diff --git a/.github/workflows/cve-scan.yaml b/.github/workflows/cve-scan.yaml index 91cee707752..63bb103aa71 100644 --- a/.github/workflows/cve-scan.yaml +++ b/.github/workflows/cve-scan.yaml @@ -42,7 +42,7 @@ jobs: acs-report-enable: true - name: Anchore upload scan SARIF report if: always() - uses: github/codeql-action/upload-sarif@v1 + uses: github/codeql-action/upload-sarif@v2 with: sarif_file: ${{ steps.grype-scan.outputs.sarif }} - name: Trivy Scanner diff --git a/.schema/openapi/patches/nulls.yaml b/.schema/openapi/patches/nulls.yaml new file mode 100644 index 00000000000..30bf028772f --- /dev/null +++ b/.schema/openapi/patches/nulls.yaml @@ -0,0 +1,43 @@ +- op: replace + path: "#/components/schemas/NullUUID" + value: + type: string + format: uuid4 + nullable: true +- op: replace + path: "#/components/schemas/NullTime" + value: + format: date-time + type: string + nullable: true +- op: replace + path: "#/components/schemas/Time" + value: + format: date-time + type: string +- op: replace + path: "#/components/schemas/NullString" + value: + type: string + nullable: true +- op: replace + path: "#/components/schemas/NullBool" + value: + type: boolean + nullable: true +- op: replace + path: "#/components/schemas/NullInt" + value: + type: integer + nullable: true +- op: replace + path: "#/components/schemas/nullInt64" + value: + type: integer + nullable: true +- op: replace + path: "#/components/schemas/nullDuration" + value: + type: string + nullable: true + pattern: ^[0-9]+(ns|us|ms|s|m|h)$ diff --git a/Makefile b/Makefile index 5fc2f9f86ae..5ebd191226d 100644 --- a/Makefile +++ b/Makefile @@ -105,6 +105,7 @@ sdk: .bin/swagger .bin/ory node_modules -p file://.schema/openapi/patches/identity.yaml \ -p file://.schema/openapi/patches/courier.yaml \ -p file://.schema/openapi/patches/generic_error.yaml \ + -p file://.schema/openapi/patches/nulls.yaml \ -p file://.schema/openapi/patches/common.yaml \ spec/swagger.json spec/api.json diff --git a/driver/config/config.go b/driver/config/config.go index 3e6b52ae3e0..d70ec3113d2 100644 --- a/driver/config/config.go +++ b/driver/config/config.go @@ -179,6 +179,8 @@ const ( ViperKeyWebAuthnRPOrigin = "selfservice.methods.webauthn.config.rp.origin" ViperKeyWebAuthnRPIcon = "selfservice.methods.webauthn.config.rp.issuer" ViperKeyWebAuthnPasswordless = "selfservice.methods.webauthn.config.passwordless" + ViperKeyOAuth2ProviderURL = "oauth2_provider.url" + ViperKeyOAuth2ProviderHeader = "oauth2_provider.headers" ViperKeyClientHTTPNoPrivateIPRanges = "clients.http.disallow_private_ip_ranges" ViperKeyClientHTTPPrivateIPExceptionURLs = "clients.http.private_ip_exception_urls" ViperKeyVersion = "version" @@ -848,6 +850,37 @@ func (p *Config) CourierSMTPURL(ctx context.Context) *url.URL { return p.ParseURIOrFail(ctx, ViperKeyCourierSMTPURL) } +func (p *Config) OAuth2ProviderHeader(ctx context.Context) http.Header { + hh := map[string]string{} + if err := p.GetProvider(ctx).Unmarshal(ViperKeyOAuth2ProviderHeader, &hh); err != nil { + p.l.WithError(errors.WithStack(err)). + Errorf("Configuration value from key %s could not be decoded.", ViperKeyOAuth2ProviderHeader) + return nil + } + + h := make(http.Header) + for k, v := range hh { + h.Set(k, v) + } + + return h +} + +func (p *Config) OAuth2ProviderURL(ctx context.Context) *url.URL { + k := ViperKeyOAuth2ProviderURL + v := p.GetProvider(ctx).String(k) + if v == "" { + return nil + } + parsed, err := p.ParseAbsoluteOrRelativeURI(v) + if err != nil { + p.l.WithError(errors.WithStack(err)). + Errorf("Configuration value from key %s is not a valid URL: %s", k, v) + return nil + } + return parsed +} + func (p *Config) SelfServiceFlowLoginUI(ctx context.Context) *url.URL { return p.ParseAbsoluteOrRelativeURIOrFail(ctx, ViperKeySelfServiceLoginUI) } @@ -868,7 +901,7 @@ func (p *Config) SelfServiceFlowRecoveryUI(ctx context.Context) *url.URL { return p.ParseAbsoluteOrRelativeURIOrFail(ctx, ViperKeySelfServiceRecoveryUI) } -// SessionLifespan returns nil when the value is not set. +// SessionLifespan returns time.Hour*24 when the value is not set. func (p *Config) SessionLifespan(ctx context.Context) time.Duration { return p.GetProvider(ctx).DurationF(ViperKeySessionLifespan, time.Hour*24) } diff --git a/driver/config/config_test.go b/driver/config/config_test.go index b1fbd3d8a84..89e904f39f9 100644 --- a/driver/config/config_test.go +++ b/driver/config/config_test.go @@ -1119,6 +1119,23 @@ func TestCourierMessageTTL(t *testing.T) { }) } +func TestOAuth2Provider(t *testing.T) { + ctx := context.Background() + + t.Run("case=configs set", func(t *testing.T) { + conf, _ := config.New(ctx, logrusx.New("", ""), os.Stderr, + configx.WithConfigFiles("stub/.kratos.oauth2_provider.yaml"), configx.SkipValidation()) + assert.Equal(t, "https://oauth2_provider/", conf.OAuth2ProviderURL(ctx).String()) + assert.Equal(t, http.Header{"Authorization": {"Basic"}}, conf.OAuth2ProviderHeader(ctx)) + }) + + t.Run("case=defaults", func(t *testing.T) { + conf, _ := config.New(ctx, logrusx.New("", ""), os.Stderr, configx.SkipValidation()) + assert.Empty(t, conf.OAuth2ProviderURL(ctx)) + assert.Empty(t, conf.OAuth2ProviderHeader(ctx)) + }) +} + func TestCourierTemplatesConfig(t *testing.T) { ctx := context.Background() diff --git a/driver/config/stub/.kratos.oauth2_provider.yaml b/driver/config/stub/.kratos.oauth2_provider.yaml new file mode 100644 index 00000000000..e7548822aba --- /dev/null +++ b/driver/config/stub/.kratos.oauth2_provider.yaml @@ -0,0 +1,4 @@ +oauth2_provider: + url: https://oauth2_provider/ + headers: + Authorization: Basic diff --git a/driver/registry_default.go b/driver/registry_default.go index 691854a0e3b..2f0a7006c19 100644 --- a/driver/registry_default.go +++ b/driver/registry_default.go @@ -22,6 +22,7 @@ import ( "github.com/ory/nosurf" + "github.com/ory/kratos/hydra" "github.com/ory/kratos/selfservice/strategy/code" "github.com/ory/kratos/selfservice/strategy/webauthn" @@ -146,6 +147,8 @@ type RegistryDefault struct { selfserviceStrategies []interface{} + hydra hydra.Hydra + buildVersion string buildHash string buildDate string @@ -517,6 +520,18 @@ func (m *RegistryDefault) SessionManager() session.Manager { return m.sessionManager } +func (m *RegistryDefault) Hydra() hydra.Hydra { + if m.hydra == nil { + m.hydra = hydra.NewDefaultHydra(m) + } + return m.hydra +} + +func (m *RegistryDefault) WithHydra(h hydra.Hydra) Registry { + m.hydra = h + return m +} + func (m *RegistryDefault) SelfServiceErrorManager() *errorx.Manager { if m.errorManager == nil { m.errorManager = errorx.NewManager(m) diff --git a/embedx/config.schema.json b/embedx/config.schema.json index 60b4e876894..35df9b500d0 100644 --- a/embedx/config.schema.json +++ b/embedx/config.schema.json @@ -230,8 +230,7 @@ }, "anyOf": [ { - "not": - { + "not": { "properties": { "response": { "properties": { @@ -241,10 +240,14 @@ ] } }, - "required": ["ignore"] + "required": [ + "ignore" + ] } }, - "required": ["response"] + "required": [ + "response" + ] } }, { @@ -255,7 +258,9 @@ ] } }, - "require": ["can_interrupt"] + "require": [ + "can_interrupt" + ] } ], "additionalProperties": false, @@ -1223,7 +1228,7 @@ }, "use": { "title": "Recovery Strategy", - "description":"The strategy to use for recovery requests", + "description": "The strategy to use for recovery requests", "type": "string", "enum": [ "link", @@ -1545,7 +1550,7 @@ } } }, - "database": { + "database": { "type": "object", "title": "Database related configuration", "description": "Miscellaneous settings used in database related tasks (cleanup, etc.)", @@ -1555,7 +1560,7 @@ "title": "Database cleanup settings", "description": "Settings that controls how the database cleanup process is configured (delays, batch size, etc.)", "properties": { - "batch_size" : { + "batch_size": { "type": "integer", "title": "Number of records to clean in one iteration", "description": "Controls how many records should be purged from one table during database cleanup task", @@ -1687,6 +1692,9 @@ "title": "SMTP Headers", "description": "These headers will be passed in the SMTP conversation -- e.g. when using the AWS SES SMTP interface for cross-account sending.", "type": "object", + "additionalProperties": { + "type": "string" + }, "examples": [ { "X-SES-SOURCE-ARN": "arn:aws:ses:us-west-2:123456789012:identity/example.com", @@ -1739,7 +1747,7 @@ "type": "string", "description": "The HTTP method to use (GET, POST, etc)." }, - "header": { + "headers": { "type": "object", "description": "The HTTP headers that must be applied to request", "additionalProperties": { @@ -1788,6 +1796,36 @@ ], "additionalProperties": false }, + "oauth2_provider": { + "title": "OAuth2 Provider Configuration", + "type": "object", + "properties": { + "url": { + "title": "OAuth 2.0 Provider URL.", + "description": "If set, the login and registration flows will handle the Ory OAuth 2.0 & OpenID `login_challenge` query parameter to serve as an OpenID Connect Provider. This URL should point to Ory Hydra when you are not running on the Ory Network and be left untouched otherwise.", + "type": "string", + "format": "uri", + "examples": [ + "https://some-slug.projects.oryapis.com", + "https://domain-of-ory-hydra:4445" + ] + }, + "headers": { + "title": "HTTP Request Headers", + "description": "These headers will be passed in HTTP request to the OAuth2 Provider.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "examples": [ + { + "Authorization": "Bearer some-token" + } + ] + } + }, + "additionalProperties": false + }, "serve": { "type": "object", "properties": { @@ -2318,7 +2356,7 @@ }, "persistent": { "title": "Make Session Cookie Persistent", - "description": "If set to true will persist the cookie in the end-user's browser using the `max-age` parameter which is set to the `session.lifespan` value. Persistent cookies are not deleted when the browser is closed (e.g. on reboot or alt+f4).", + "description": "If set to true will persist the cookie in the end-user's browser using the `max-age` parameter which is set to the `session.lifespan` value. Persistent cookies are not deleted when the browser is closed (e.g. on reboot or alt+f4). This option affects the Ory OAuth2 and OpenID Provider's remember feature as well.", "type": "boolean", "default": true }, diff --git a/go.mod b/go.mod index 78d7d9e640c..617fc514144 100644 --- a/go.mod +++ b/go.mod @@ -72,11 +72,12 @@ require ( github.com/ory/go-convenience v0.1.0 github.com/ory/graceful v0.1.3 github.com/ory/herodot v0.9.13 + github.com/ory/hydra-client-go v1.11.8 github.com/ory/jsonschema/v3 v3.0.7 github.com/ory/kratos-client-go v0.6.3-alpha.1 github.com/ory/mail/v3 v3.0.0 github.com/ory/nosurf v1.2.7 - github.com/ory/x v0.0.480 + github.com/ory/x v0.0.488 github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 github.com/pkg/errors v0.9.1 github.com/pquerna/otp v1.3.0 diff --git a/go.sum b/go.sum index d7737cc3771..30e8196a74a 100644 --- a/go.sum +++ b/go.sum @@ -1370,6 +1370,8 @@ github.com/ory/graceful v0.1.3 h1:FaeXcHZh168WzS+bqruqWEw/HgXWLdNv2nJ+fbhxbhc= github.com/ory/graceful v0.1.3/go.mod h1:4zFz687IAF7oNHHiB586U4iL+/4aV09o/PYLE34t2bA= github.com/ory/herodot v0.9.13 h1:cN/Z4eOkErl/9W7hDIDLb79IO/bfsH+8yscBjRpB4IU= github.com/ory/herodot v0.9.13/go.mod h1:IWDs9kSvFQqw/cQ8zi5ksyYvITiUU4dI7glUrhZcJYo= +github.com/ory/hydra-client-go v1.11.8 h1:GwJjvH/DBcfYzoST4vUpi4pIRzDGH5oODKpIVuhwVyc= +github.com/ory/hydra-client-go v1.11.8/go.mod h1:4YuBuwUEC4yiyDrnKjGYc1tB3gUXan4ZiUYMjXJbfxA= github.com/ory/jsonschema/v3 v3.0.7 h1:GQ9qfZDiJqs4l2d3p56dozCChvejQFZyLKGHYzDzOSo= github.com/ory/jsonschema/v3 v3.0.7/go.mod h1:g8c8YOtN4TrR2wYeMdT02GDmzJDI0fEW2nI26BECafY= github.com/ory/mail v2.3.1+incompatible/go.mod h1:87D9/1gB6ewElQoN0lXJ0ayfqcj3cW3qCTXh+5E9mfU= @@ -1381,8 +1383,8 @@ github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2 h1:zm6sDvHy/U9XrGpi github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/ory/viper v1.7.5 h1:+xVdq7SU3e1vNaCsk/ixsfxE4zylk1TJUiJrY647jUE= github.com/ory/viper v1.7.5/go.mod h1:ypOuyJmEUb3oENywQZRgeAMwqgOyDqwboO1tj3DjTaM= -github.com/ory/x v0.0.480 h1:IAflszUfmpy/bVnd8gxIgKuL9pL1oLjytxqCmAMC14o= -github.com/ory/x v0.0.480/go.mod h1:w2gwqgw3XqKTxW8wURVxUFI2NuDyIC2rGxvEsnBJqjs= +github.com/ory/x v0.0.488 h1:EQLqYLPwNfs9OW9GFrxDEO11oEmKpvveN1wuUfU8yOU= +github.com/ory/x v0.0.488/go.mod h1:dJ800rWC2/eNECWhXMyI9kSd7lO2LTOu6R8oS0lQZ38= github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= @@ -2011,6 +2013,7 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= diff --git a/hydra/fake.go b/hydra/fake.go new file mode 100644 index 00000000000..be9b19958eb --- /dev/null +++ b/hydra/fake.go @@ -0,0 +1,45 @@ +package hydra + +import ( + "context" + "errors" + + "github.com/gofrs/uuid" + + hydraclientgo "github.com/ory/hydra-client-go" + "github.com/ory/kratos/session" +) + +const ( + FAKE_GET_LOGIN_REQUEST_RETURN_NIL_NIL = "b805f2d9-2f6d-4745-9d68-a17f48e25774" + FAKE_ACCEPT_REQUEST_FAIL = "2e98454e-031b-4870-9ad6-8517df1ce604" + FAKE_SUCCESS = "5ff59a39-ecc5-467e-bb10-26644c0700ee" +) + +type FakeHydra struct{} + +var _ Hydra = &FakeHydra{} + +func NewFakeHydra() *FakeHydra { + return &FakeHydra{} +} + +func (h *FakeHydra) AcceptLoginRequest(ctx context.Context, hlc uuid.UUID, sub string, amr session.AuthenticationMethods) (string, error) { + switch hlc.String() { + case FAKE_ACCEPT_REQUEST_FAIL: + return "", errors.New("failed to accept login request") + default: + panic("unknown fake login_challenge " + hlc.String()) + } +} + +func (h *FakeHydra) GetLoginRequest(ctx context.Context, hlc uuid.NullUUID) (*hydraclientgo.LoginRequest, error) { + switch hlc.UUID.String() { + case FAKE_ACCEPT_REQUEST_FAIL: + return &hydraclientgo.LoginRequest{}, nil + case FAKE_SUCCESS: + return &hydraclientgo.LoginRequest{}, nil + default: + panic("unknown fake login_challenge " + hlc.UUID.String()) + } +} diff --git a/hydra/hydra.go b/hydra/hydra.go new file mode 100644 index 00000000000..cf367fb9804 --- /dev/null +++ b/hydra/hydra.go @@ -0,0 +1,138 @@ +package hydra + +import ( + "context" + "fmt" + "net/http" + "time" + + "github.com/ory/x/httpx" + + "github.com/gofrs/uuid" + "github.com/pkg/errors" + + "github.com/ory/herodot" + hydraclientgo "github.com/ory/hydra-client-go" + "github.com/ory/kratos/driver/config" + "github.com/ory/kratos/session" + "github.com/ory/kratos/x" +) + +type ( + hydraDependencies interface { + config.Provider + x.HTTPClientProvider + } + HydraProvider interface { + Hydra() Hydra + } + Hydra interface { + AcceptLoginRequest(ctx context.Context, hlc uuid.UUID, sub string, amr session.AuthenticationMethods) (string, error) + GetLoginRequest(ctx context.Context, hlc uuid.NullUUID) (*hydraclientgo.LoginRequest, error) + } + DefaultHydra struct { + d hydraDependencies + } +) + +func NewDefaultHydra(d hydraDependencies) *DefaultHydra { + return &DefaultHydra{ + d: d, + } +} + +func GetLoginChallengeID(conf *config.Config, r *http.Request) (uuid.NullUUID, error) { + if !r.URL.Query().Has("login_challenge") { + return uuid.NullUUID{}, nil + } else if conf.OAuth2ProviderURL(r.Context()) == nil { + return uuid.NullUUID{}, errors.WithStack(herodot.ErrInternalServerError.WithReason("refusing to parse login_challenge query parameter because " + config.ViperKeyOAuth2ProviderURL + " is invalid or unset")) + } + + hlc, err := uuid.FromString(r.URL.Query().Get("login_challenge")) + if err != nil || hlc.IsNil() { + return uuid.NullUUID{}, errors.WithStack(herodot.ErrBadRequest.WithReason("the login_challenge parameter is present but invalid or zero UUID")) + } else { + return uuid.NullUUID{UUID: hlc, Valid: true}, nil + } +} + +func (h *DefaultHydra) getAdminURL(ctx context.Context) (string, error) { + u := h.d.Config().OAuth2ProviderURL(ctx) + if u == nil { + return "", errors.WithStack(herodot.ErrInternalServerError.WithReason(config.ViperKeyOAuth2ProviderURL + " is not configured")) + } + return u.String(), nil +} + +func (h *DefaultHydra) getAdminAPIClient(ctx context.Context) (hydraclientgo.AdminApi, error) { + url, err := h.getAdminURL(ctx) + if err != nil { + return nil, err + } + + configuration := hydraclientgo.NewConfiguration() + configuration.Servers = hydraclientgo.ServerConfigurations{{URL: url}} + + client := h.d.HTTPClient(ctx).StandardClient() + if header := h.d.Config().OAuth2ProviderHeader(ctx); header != nil { + client.Transport = httpx.WrapTransportWithHeader(client.Transport, header) + } + + configuration.HTTPClient = client + return hydraclientgo.NewAPIClient(configuration).AdminApi, nil +} + +func (h *DefaultHydra) AcceptLoginRequest(ctx context.Context, hlc uuid.UUID, sub string, amr session.AuthenticationMethods) (string, error) { + remember := h.d.Config().SessionPersistentCookie(ctx) + rememberFor := int64(h.d.Config().SessionLifespan(ctx) / time.Second) + + alr := hydraclientgo.NewAcceptLoginRequest(sub) + alr.Remember = &remember + alr.RememberFor = &rememberFor + alr.Amr = []string{} + for _, r := range amr { + alr.Amr = append(alr.Amr, string(r.Method)) + } + + aa, err := h.getAdminAPIClient(ctx) + if err != nil { + return "", err + } + + resp, r, err := aa.AcceptLoginRequest(ctx).LoginChallenge(fmt.Sprintf("%x", hlc)).AcceptLoginRequest(*alr).Execute() + if err != nil { + innerErr := herodot.ErrInternalServerError.WithWrap(err).WithReasonf("Unable to accept OAuth 2.0 Login Challenge.") + if r != nil { + innerErr = innerErr. + WithDetail("status_code", r.StatusCode). + WithDebugf("error", err.Error()) + } + return "", errors.WithStack(innerErr) + } + + return resp.RedirectTo, nil +} + +func (h *DefaultHydra) GetLoginRequest(ctx context.Context, hlc uuid.NullUUID) (*hydraclientgo.LoginRequest, error) { + if !hlc.Valid { + return nil, errors.WithStack(herodot.ErrBadRequest.WithReason("invalid login_challenge")) + } + + aa, err := h.getAdminAPIClient(ctx) + if err != nil { + return nil, err + } + + hlr, r, err := aa.GetLoginRequest(ctx).LoginChallenge(fmt.Sprintf("%x", hlc.UUID)).Execute() + if err != nil { + innerErr := herodot.ErrInternalServerError.WithWrap(err).WithReasonf("Unable to get OAuth 2.0 Login Challenge.") + if r != nil { + innerErr = innerErr. + WithDetail("status_code", r.StatusCode). + WithDebugf("error", err.Error()) + } + return nil, errors.WithStack(innerErr) + } + + return hlr, nil +} diff --git a/hydra/hydra_test.go b/hydra/hydra_test.go new file mode 100644 index 00000000000..9fccdc9adf5 --- /dev/null +++ b/hydra/hydra_test.go @@ -0,0 +1,100 @@ +package hydra_test + +import ( + "net/http" + "os" + "reflect" + "testing" + + "github.com/gofrs/uuid" + + "github.com/ory/kratos/driver/config" + "github.com/ory/kratos/hydra" + "github.com/ory/x/configx" + "github.com/ory/x/logrusx" + "github.com/ory/x/urlx" +) + +func TestGetLoginChallengeID(t *testing.T) { + validChallenge := "https://hydra?login_challenge=b346a452-e8fb-4828-8ef8-a4dbc98dc23a" + invalidChallenge := "https://hydra?login_challenge=invalid" + defaultConfig := config.MustNew(t, logrusx.New("", ""), os.Stderr, configx.SkipValidation()) + configWithHydra := config.MustNew( + t, + logrusx.New("", ""), + os.Stderr, + configx.SkipValidation(), + configx.WithValues(map[string]interface{}{ + config.ViperKeyOAuth2ProviderURL: "https://hydra", + }), + ) + + type args struct { + conf *config.Config + r *http.Request + } + tests := []struct { + name string + args args + want uuid.NullUUID + wantErr bool + }{ + { + name: "no login challenge; hydra is not configured", + args: args{ + conf: defaultConfig, + r: &http.Request{URL: urlx.ParseOrPanic("https://hydra")}, + }, + want: uuid.NullUUID{Valid: false}, + wantErr: false, + }, + { + name: "no login challenge; hydra is configured", + args: args{ + conf: configWithHydra, + r: &http.Request{URL: urlx.ParseOrPanic("https://hydra")}, + }, + want: uuid.NullUUID{Valid: false}, + wantErr: false, + }, + { + name: "login_challenge is present; Hydra is not configured", + args: args{ + conf: defaultConfig, + r: &http.Request{URL: urlx.ParseOrPanic(validChallenge)}, + }, + want: uuid.NullUUID{Valid: false}, + wantErr: true, + }, + { + name: "login_challenge is present; hydra is configured", + args: args{ + conf: configWithHydra, + r: &http.Request{URL: urlx.ParseOrPanic(validChallenge)}, + }, + want: uuid.NullUUID{Valid: true, UUID: uuid.FromStringOrNil("b346a452-e8fb-4828-8ef8-a4dbc98dc23a")}, + wantErr: false, + }, + { + name: "login_challenge is invalid; hydra is configured", + args: args{ + conf: configWithHydra, + r: &http.Request{URL: urlx.ParseOrPanic(invalidChallenge)}, + }, + want: uuid.NullUUID{Valid: false}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := hydra.GetLoginChallengeID(tt.args.conf, tt.args.r) + if (err != nil) != tt.wantErr { + t.Errorf("GetLoginChallengeID() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("GetLoginChallengeID() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/internal/httpclient/.openapi-generator/FILES b/internal/httpclient/.openapi-generator/FILES index 000360e64ec..c277bccbc12 100644 --- a/internal/httpclient/.openapi-generator/FILES +++ b/internal/httpclient/.openapi-generator/FILES @@ -37,9 +37,12 @@ docs/InlineResponse2001.md docs/InlineResponse503.md docs/JsonError.md docs/JsonPatch.md +docs/LoginRequest.md docs/Message.md docs/MetadataApi.md docs/NeedsPrivilegedSessionError.md +docs/OAuth2Client.md +docs/OpenIDConnectContext.md docs/Pagination.md docs/RecoveryIdentityAddress.md docs/RevokedSessions.md @@ -135,8 +138,11 @@ model_inline_response_200_1.go model_inline_response_503.go model_json_error.go model_json_patch.go +model_login_request.go model_message.go model_needs_privileged_session_error.go +model_o_auth2_client.go +model_open_id_connect_context.go model_pagination.go model_recovery_identity_address.go model_revoked_sessions.go diff --git a/internal/httpclient/README.md b/internal/httpclient/README.md index d1c42716e9d..f5b358e7fbf 100644 --- a/internal/httpclient/README.md +++ b/internal/httpclient/README.md @@ -163,8 +163,11 @@ Class | Method | HTTP request | Description - [InlineResponse503](docs/InlineResponse503.md) - [JsonError](docs/JsonError.md) - [JsonPatch](docs/JsonPatch.md) + - [LoginRequest](docs/LoginRequest.md) - [Message](docs/Message.md) - [NeedsPrivilegedSessionError](docs/NeedsPrivilegedSessionError.md) + - [OAuth2Client](docs/OAuth2Client.md) + - [OpenIDConnectContext](docs/OpenIDConnectContext.md) - [Pagination](docs/Pagination.md) - [RecoveryIdentityAddress](docs/RecoveryIdentityAddress.md) - [RevokedSessions](docs/RevokedSessions.md) diff --git a/internal/httpclient/api/openapi.yaml b/internal/httpclient/api/openapi.yaml index 1f83d9cb56d..7395a9740ee 100644 --- a/internal/httpclient/api/openapi.yaml +++ b/internal/httpclient/api/openapi.yaml @@ -1100,11 +1100,28 @@ paths: `security_csrf_violation`: Unable to fetch the flow because a CSRF violation occurred. `security_identity_mismatch`: The requested `?return_to` address is not allowed to be used. Adjust this in the configuration! + The optional query parameter login_challenge is set when using Kratos with + Hydra in an OAuth2 flow. See the oauth2_provider.url configuration + option. + This endpoint is NOT INTENDED for clients that do not have a browser (Chrome, Firefox, ...) as cookies are needed. More information can be found at [Ory Kratos User Login](https://www.ory.sh/docs/kratos/self-service/flows/user-login) and [User Registration Documentation](https://www.ory.sh/docs/kratos/self-service/flows/user-registration). operationId: initializeSelfServiceLoginFlowForBrowsers parameters: + - description: |- + An optional Hydra login challenge. If present, Kratos will cooperate with + Ory Hydra to act as an OAuth2 identity provider. + + The value for this parameter comes from `login_challenge` URL Query parameter sent to your + application (e.g. `/login?login_challenge=abcde`). + explode: true + in: query + name: login_challenge + required: false + schema: + type: string + style: form - description: |- Refresh a login session @@ -1851,6 +1868,19 @@ paths: More information can be found at [Ory Kratos User Login](https://www.ory.sh/docs/kratos/self-service/flows/user-login) and [User Registration Documentation](https://www.ory.sh/docs/kratos/self-service/flows/user-registration). operationId: initializeSelfServiceRegistrationFlowForBrowsers parameters: + - description: |- + An optional Hydra login challenge. If present, Kratos will cooperate with + Ory Hydra to act as an OAuth2 identity provider. + + The value for this parameter comes from `login_challenge` URL Query parameter sent to your + application (e.g. `/registration?login_challenge=abcde`). + explode: true + in: query + name: login_challenge + required: false + schema: + type: string + style: form - description: The URL to return the browser to after the flow was completed. explode: true in: query @@ -3006,12 +3036,457 @@ components: title: JSONRawMessage represents a json.RawMessage that works well with JSON, SQL, and Swagger. type: object + LoginRequest: + description: LoginRequest struct for LoginRequest + example: + requested_access_token_audience: + - requested_access_token_audience + - requested_access_token_audience + subject: subject + oidc_context: + login_hint: login_hint + ui_locales: + - ui_locales + - ui_locales + id_token_hint_claims: + key: '{}' + acr_values: + - acr_values + - acr_values + display: display + challenge: challenge + client: + metadata: + key: "" + token_endpoint_auth_signing_alg: token_endpoint_auth_signing_alg + client_uri: client_uri + jwks: + key: "" + logo_uri: logo_uri + created_at: 2000-01-23T04:56:07.000+00:00 + registration_client_uri: registration_client_uri + allowed_cors_origins: + - allowed_cors_origins + - allowed_cors_origins + registration_access_token: registration_access_token + client_id: client_id + token_endpoint_auth_method: token_endpoint_auth_method + userinfo_signed_response_alg: userinfo_signed_response_alg + updated_at: 2000-01-23T04:56:07.000+00:00 + scope: scope + request_uris: + - request_uris + - request_uris + client_secret: client_secret + backchannel_logout_session_required: true + backchannel_logout_uri: backchannel_logout_uri + client_name: client_name + policy_uri: policy_uri + owner: owner + audience: + - audience + - audience + post_logout_redirect_uris: + - post_logout_redirect_uris + - post_logout_redirect_uris + grant_types: + - grant_types + - grant_types + subject_type: subject_type + redirect_uris: + - redirect_uris + - redirect_uris + sector_identifier_uri: sector_identifier_uri + frontchannel_logout_session_required: true + frontchannel_logout_uri: frontchannel_logout_uri + client_secret_expires_at: 0 + jwks_uri: jwks_uri + request_object_signing_alg: request_object_signing_alg + tos_uri: tos_uri + contacts: + - contacts + - contacts + response_types: + - response_types + - response_types + session_id: session_id + skip: true + request_url: request_url + requested_scope: + - requested_scope + - requested_scope + properties: + challenge: + description: ID is the identifier (\"login challenge\") of the login request. + It is used to identify the session. + type: string + client: + $ref: '#/components/schemas/OAuth2Client' + oidc_context: + $ref: '#/components/schemas/OpenIDConnectContext' + request_url: + description: RequestURL is the original OAuth 2.0 Authorization URL requested + by the OAuth 2.0 client. It is the URL which initiates the OAuth 2.0 Authorization + Code or OAuth 2.0 Implicit flow. This URL is typically not needed, but + might come in handy if you want to deal with additional request parameters. + type: string + requested_access_token_audience: + items: + type: string + type: array + requested_scope: + items: + type: string + type: array + session_id: + description: SessionID is the login session ID. If the user-agent reuses + a login session (via cookie / remember flag) this ID will remain the same. + If the user-agent did not have an existing authentication session (e.g. + remember is false) this will be a new random value. This value is used + as the \"sid\" parameter in the ID Token and in OIDC Front-/Back- channel + logout. It's value can generally be used to associate consecutive login + requests by a certain user. + type: string + skip: + description: Skip, if true, implies that the client has requested the same + scopes from the same user previously. If true, you can skip asking the + user to grant the requested scopes, and simply forward the user to the + redirect URL. This feature allows you to update / set session information. + type: boolean + subject: + description: Subject is the user ID of the end-user that authenticated. + Now, that end user needs to grant or deny the scope requested by the OAuth + 2.0 client. If this value is set and `skip` is true, you MUST include + this subject type when accepting the login request, or the request will + fail. + type: string + type: object + NullBool: + nullable: true + type: boolean + NullInt: + nullable: true + type: integer + NullString: + nullable: true + type: string + NullTime: + format: date-time + nullable: true + type: string + NullUUID: + format: uuid4 + nullable: true + type: string + OAuth2Client: + description: OAuth2Client struct for OAuth2Client + example: + metadata: + key: "" + token_endpoint_auth_signing_alg: token_endpoint_auth_signing_alg + client_uri: client_uri + jwks: + key: "" + logo_uri: logo_uri + created_at: 2000-01-23T04:56:07.000+00:00 + registration_client_uri: registration_client_uri + allowed_cors_origins: + - allowed_cors_origins + - allowed_cors_origins + registration_access_token: registration_access_token + client_id: client_id + token_endpoint_auth_method: token_endpoint_auth_method + userinfo_signed_response_alg: userinfo_signed_response_alg + updated_at: 2000-01-23T04:56:07.000+00:00 + scope: scope + request_uris: + - request_uris + - request_uris + client_secret: client_secret + backchannel_logout_session_required: true + backchannel_logout_uri: backchannel_logout_uri + client_name: client_name + policy_uri: policy_uri + owner: owner + audience: + - audience + - audience + post_logout_redirect_uris: + - post_logout_redirect_uris + - post_logout_redirect_uris + grant_types: + - grant_types + - grant_types + subject_type: subject_type + redirect_uris: + - redirect_uris + - redirect_uris + sector_identifier_uri: sector_identifier_uri + frontchannel_logout_session_required: true + frontchannel_logout_uri: frontchannel_logout_uri + client_secret_expires_at: 0 + jwks_uri: jwks_uri + request_object_signing_alg: request_object_signing_alg + tos_uri: tos_uri + contacts: + - contacts + - contacts + response_types: + - response_types + - response_types + properties: + allowed_cors_origins: + items: + type: string + type: array + audience: + items: + type: string + type: array + backchannel_logout_session_required: + description: Boolean value specifying whether the RP requires that a sid + (session ID) Claim be included in the Logout Token to identify the RP + session with the OP when the backchannel_logout_uri is used. If omitted, + the default value is false. + type: boolean + backchannel_logout_uri: + description: RP URL that will cause the RP to log itself out when sent a + Logout Token by the OP. + type: string + client_id: + description: ID is the id for this client. + type: string + client_name: + description: Name is the human-readable string name of the client to be + presented to the end-user during authorization. + type: string + client_secret: + description: Secret is the client's secret. The secret will be included + in the create request as cleartext, and then never again. The secret is + stored using BCrypt so it is impossible to recover it. Tell your users + that they need to write the secret down as it will not be made available + again. + type: string + client_secret_expires_at: + description: SecretExpiresAt is an integer holding the time at which the + client secret will expire or 0 if it will not expire. The time is represented + as the number of seconds from 1970-01-01T00:00:00Z as measured in UTC + until the date/time of expiration. This feature is currently not supported + and it's value will always be set to 0. + format: int64 + type: integer + client_uri: + description: ClientURI is an URL string of a web page providing information + about the client. If present, the server SHOULD display this URL to the + end-user in a clickable fashion. + type: string + contacts: + items: + type: string + type: array + created_at: + description: CreatedAt returns the timestamp of the client's creation. + format: date-time + type: string + frontchannel_logout_session_required: + description: Boolean value specifying whether the RP requires that iss (issuer) + and sid (session ID) query parameters be included to identify the RP session + with the OP when the frontchannel_logout_uri is used. If omitted, the + default value is false. + type: boolean + frontchannel_logout_uri: + description: RP URL that will cause the RP to log itself out when rendered + in an iframe by the OP. An iss (issuer) query parameter and a sid (session + ID) query parameter MAY be included by the OP to enable the RP to validate + the request and to determine which of the potentially multiple sessions + is to be logged out; if either is included, both MUST be. + type: string + grant_types: + items: + type: string + type: array + jwks: + additionalProperties: {} + type: object + jwks_uri: + description: URL for the Client's JSON Web Key Set [JWK] document. If the + Client signs requests to the Server, it contains the signing key(s) the + Server uses to validate signatures from the Client. The JWK Set MAY also + contain the Client's encryption keys(s), which are used by the Server + to encrypt responses to the Client. When both signing and encryption keys + are made available, a use (Key Use) parameter value is REQUIRED for all + keys in the referenced JWK Set to indicate each key's intended usage. + Although some algorithms allow the same key to be used for both signatures + and encryption, doing so is NOT RECOMMENDED, as it is less secure. The + JWK x5c parameter MAY be used to provide X.509 representations of keys + provided. When used, the bare key values MUST still be present and MUST + match those in the certificate. + type: string + logo_uri: + description: LogoURI is an URL string that references a logo for the client. + type: string + metadata: + additionalProperties: {} + type: object + owner: + description: Owner is a string identifying the owner of the OAuth 2.0 Client. + type: string + policy_uri: + description: PolicyURI is a URL string that points to a human-readable privacy + policy document that describes how the deployment organization collects, + uses, retains, and discloses personal data. + type: string + post_logout_redirect_uris: + items: + type: string + type: array + redirect_uris: + items: + type: string + type: array + registration_access_token: + description: RegistrationAccessToken can be used to update, get, or delete + the OAuth2 Client. + type: string + registration_client_uri: + description: RegistrationClientURI is the URL used to update, get, or delete + the OAuth2 Client. + type: string + request_object_signing_alg: + description: JWS [JWS] alg algorithm [JWA] that MUST be used for signing + Request Objects sent to the OP. All Request Objects from this Client MUST + be rejected, if not signed with this algorithm. + type: string + request_uris: + items: + type: string + type: array + response_types: + items: + type: string + type: array + scope: + description: Scope is a string containing a space-separated list of scope + values (as described in Section 3.3 of OAuth 2.0 [RFC6749]) that the client + can use when requesting access tokens. + type: string + sector_identifier_uri: + description: URL using the https scheme to be used in calculating Pseudonymous + Identifiers by the OP. The URL references a file with a single JSON array + of redirect_uri values. + type: string + subject_type: + description: SubjectType requested for responses to this Client. The subject_types_supported + Discovery parameter contains a list of the supported subject_type values + for this server. Valid types include `pairwise` and `public`. + type: string + token_endpoint_auth_method: + description: Requested Client Authentication method for the Token Endpoint. + The options are client_secret_post, client_secret_basic, private_key_jwt, + and none. + type: string + token_endpoint_auth_signing_alg: + description: Requested Client Authentication signing algorithm for the Token + Endpoint. + type: string + tos_uri: + description: TermsOfServiceURI is a URL string that points to a human-readable + terms of service document for the client that describes a contractual + relationship between the end-user and the client that the end-user accepts + when authorizing the client. + type: string + updated_at: + description: UpdatedAt returns the timestamp of the last update. + format: date-time + type: string + userinfo_signed_response_alg: + description: JWS alg algorithm [JWA] REQUIRED for signing UserInfo Responses. + If this is specified, the response will be JWT [JWT] serialized, and signed + using JWS. The default, if omitted, is for the UserInfo Response to return + the Claims as a UTF-8 encoded JSON object using the application/json content-type. + type: string + type: object + OpenIDConnectContext: + description: OpenIDConnectContext struct for OpenIDConnectContext + example: + login_hint: login_hint + ui_locales: + - ui_locales + - ui_locales + id_token_hint_claims: + key: '{}' + acr_values: + - acr_values + - acr_values + display: display + properties: + acr_values: + description: 'ACRValues is the Authentication AuthorizationContext Class + Reference requested in the OAuth 2.0 Authorization request. It is a parameter + defined by OpenID Connect and expresses which level of authentication + (e.g. 2FA) is required. OpenID Connect defines it as follows: > Requested + Authentication AuthorizationContext Class Reference values. Space-separated + string that specifies the acr values that the Authorization Server is + being requested to use for processing this Authentication Request, with + the values appearing in order of preference. The Authentication AuthorizationContext + Class satisfied by the authentication performed is returned as the acr + Claim Value, as specified in Section 2. The acr Claim is requested as + a Voluntary Claim by this parameter.' + items: + type: string + type: array + display: + description: 'Display is a string value that specifies how the Authorization + Server displays the authentication and consent user interface pages to + the End-User. The defined values are: page: The Authorization Server SHOULD + display the authentication and consent UI consistent with a full User + Agent page view. If the display parameter is not specified, this is the + default display mode. popup: The Authorization Server SHOULD display the + authentication and consent UI consistent with a popup User Agent window. + The popup User Agent window should be of an appropriate size for a login-focused + dialog and should not obscure the entire window that it is popping up + over. touch: The Authorization Server SHOULD display the authentication + and consent UI consistent with a device that leverages a touch interface. + wap: The Authorization Server SHOULD display the authentication and consent + UI consistent with a \"feature phone\" type display. The Authorization + Server MAY also attempt to detect the capabilities of the User Agent and + present an appropriate display.' + type: string + id_token_hint_claims: + additionalProperties: true + description: IDTokenHintClaims are the claims of the ID Token previously + issued by the Authorization Server being passed as a hint about the End-User's + current or past authenticated session with the Client. + type: object + login_hint: + description: LoginHint hints about the login identifier the End-User might + use to log in (if necessary). This hint can be used by an RP if it first + asks the End-User for their e-mail address (or other identifier) and then + wants to pass that value as a hint to the discovered authorization service. + This value MAY also be a phone number in the format specified for the + phone_number Claim. The use of this parameter is optional. + type: string + ui_locales: + description: UILocales is the End-User'id preferred languages and scripts + for the user interface, represented as a space-separated list of BCP47 + [RFC5646] language tag values, ordered by preference. For instance, the + value \"fr-CA fr en\" represents a preference for French as spoken in + Canada, then French (without a region designation), followed by English + (without a region designation). An error SHOULD NOT result if some or + all of the requested locales are not supported by the OpenID Provider. + items: + type: string + type: array + type: object RecoveryAddressType: title: RecoveryAddressType must not exceed 16 characters as that is the limitation in the SQL Schema. type: string TemplateType: type: string + Time: + format: date-time + type: string UUID: format: uuid4 type: string @@ -3741,6 +4216,13 @@ components: title: Is sent when a privileged session is required to perform the settings update. type: object + nullDuration: + nullable: true + pattern: ^[0-9]+(ns|us|ms|s|m|h)$ + type: string + nullInt64: + nullable: true + type: integer nullJsonRawMessage: description: NullJSONRawMessage represents a json.RawMessage that works well with JSON, SQL, and Swagger and is NULLable- @@ -3970,22 +4452,105 @@ components: Once a login flow is completed successfully, a session cookie or session token will be issued. example: + created_at: 2000-01-23T04:56:07.000+00:00 + refresh: true + return_to: return_to + type: type + issued_at: 2000-01-23T04:56:07.000+00:00 + request_url: request_url expires_at: 2000-01-23T04:56:07.000+00:00 + oauth2_login_request: + requested_access_token_audience: + - requested_access_token_audience + - requested_access_token_audience + subject: subject + oidc_context: + login_hint: login_hint + ui_locales: + - ui_locales + - ui_locales + id_token_hint_claims: + key: '{}' + acr_values: + - acr_values + - acr_values + display: display + challenge: challenge + client: + metadata: + key: "" + token_endpoint_auth_signing_alg: token_endpoint_auth_signing_alg + client_uri: client_uri + jwks: + key: "" + logo_uri: logo_uri + created_at: 2000-01-23T04:56:07.000+00:00 + registration_client_uri: registration_client_uri + allowed_cors_origins: + - allowed_cors_origins + - allowed_cors_origins + registration_access_token: registration_access_token + client_id: client_id + token_endpoint_auth_method: token_endpoint_auth_method + userinfo_signed_response_alg: userinfo_signed_response_alg + updated_at: 2000-01-23T04:56:07.000+00:00 + scope: scope + request_uris: + - request_uris + - request_uris + client_secret: client_secret + backchannel_logout_session_required: true + backchannel_logout_uri: backchannel_logout_uri + client_name: client_name + policy_uri: policy_uri + owner: owner + audience: + - audience + - audience + post_logout_redirect_uris: + - post_logout_redirect_uris + - post_logout_redirect_uris + grant_types: + - grant_types + - grant_types + subject_type: subject_type + redirect_uris: + - redirect_uris + - redirect_uris + sector_identifier_uri: sector_identifier_uri + frontchannel_logout_session_required: true + frontchannel_logout_uri: frontchannel_logout_uri + client_secret_expires_at: 0 + jwks_uri: jwks_uri + request_object_signing_alg: request_object_signing_alg + tos_uri: tos_uri + contacts: + - contacts + - contacts + response_types: + - response_types + - response_types + session_id: session_id + skip: true + request_url: request_url + requested_scope: + - requested_scope + - requested_scope ui: nodes: - meta: label: context: '{}' - id: 0 + id: 6 text: text type: type messages: - context: '{}' - id: 0 + id: 6 text: text type: type - context: '{}' - id: 0 + id: 6 text: text type: type type: text @@ -3993,16 +4558,16 @@ components: - meta: label: context: '{}' - id: 0 + id: 6 text: text type: type messages: - context: '{}' - id: 0 + id: 6 text: text type: type - context: '{}' - id: 0 + id: 6 text: text type: type type: text @@ -4011,21 +4576,16 @@ components: action: action messages: - context: '{}' - id: 0 + id: 6 text: text type: type - context: '{}' - id: 0 + id: 6 text: text type: type updated_at: 2000-01-23T04:56:07.000+00:00 - created_at: 2000-01-23T04:56:07.000+00:00 - refresh: true - return_to: return_to + oauth2_login_challenge: oauth2_login_challenge id: 046b6c7f-0b8a-43b9-b35d-6489e6daee91 - type: type - issued_at: 2000-01-23T04:56:07.000+00:00 - request_url: request_url properties: active: $ref: '#/components/schemas/identityCredentialsType' @@ -4049,6 +4609,12 @@ components: description: IssuedAt is the time (UTC) when the flow started. format: date-time type: string + oauth2_login_challenge: + format: uuid4 + nullable: true + type: string + oauth2_login_request: + $ref: '#/components/schemas/LoginRequest' refresh: description: Refresh stores whether this login flow should enforce re-authentication. type: boolean @@ -4137,16 +4703,16 @@ components: - meta: label: context: '{}' - id: 0 + id: 6 text: text type: type messages: - context: '{}' - id: 0 + id: 6 text: text type: type - context: '{}' - id: 0 + id: 6 text: text type: type type: text @@ -4154,16 +4720,16 @@ components: - meta: label: context: '{}' - id: 0 + id: 6 text: text type: type messages: - context: '{}' - id: 0 + id: 6 text: text type: type - context: '{}' - id: 0 + id: 6 text: text type: type type: text @@ -4172,11 +4738,11 @@ components: action: action messages: - context: '{}' - id: 0 + id: 6 text: text type: type - context: '{}' - id: 0 + id: 6 text: text type: type active: active @@ -4270,21 +4836,98 @@ components: selfServiceRegistrationFlow: example: expires_at: 2000-01-23T04:56:07.000+00:00 + oauth2_login_request: + requested_access_token_audience: + - requested_access_token_audience + - requested_access_token_audience + subject: subject + oidc_context: + login_hint: login_hint + ui_locales: + - ui_locales + - ui_locales + id_token_hint_claims: + key: '{}' + acr_values: + - acr_values + - acr_values + display: display + challenge: challenge + client: + metadata: + key: "" + token_endpoint_auth_signing_alg: token_endpoint_auth_signing_alg + client_uri: client_uri + jwks: + key: "" + logo_uri: logo_uri + created_at: 2000-01-23T04:56:07.000+00:00 + registration_client_uri: registration_client_uri + allowed_cors_origins: + - allowed_cors_origins + - allowed_cors_origins + registration_access_token: registration_access_token + client_id: client_id + token_endpoint_auth_method: token_endpoint_auth_method + userinfo_signed_response_alg: userinfo_signed_response_alg + updated_at: 2000-01-23T04:56:07.000+00:00 + scope: scope + request_uris: + - request_uris + - request_uris + client_secret: client_secret + backchannel_logout_session_required: true + backchannel_logout_uri: backchannel_logout_uri + client_name: client_name + policy_uri: policy_uri + owner: owner + audience: + - audience + - audience + post_logout_redirect_uris: + - post_logout_redirect_uris + - post_logout_redirect_uris + grant_types: + - grant_types + - grant_types + subject_type: subject_type + redirect_uris: + - redirect_uris + - redirect_uris + sector_identifier_uri: sector_identifier_uri + frontchannel_logout_session_required: true + frontchannel_logout_uri: frontchannel_logout_uri + client_secret_expires_at: 0 + jwks_uri: jwks_uri + request_object_signing_alg: request_object_signing_alg + tos_uri: tos_uri + contacts: + - contacts + - contacts + response_types: + - response_types + - response_types + session_id: session_id + skip: true + request_url: request_url + requested_scope: + - requested_scope + - requested_scope ui: nodes: - meta: label: context: '{}' - id: 0 + id: 6 text: text type: type messages: - context: '{}' - id: 0 + id: 6 text: text type: type - context: '{}' - id: 0 + id: 6 text: text type: type type: text @@ -4292,16 +4935,16 @@ components: - meta: label: context: '{}' - id: 0 + id: 6 text: text type: type messages: - context: '{}' - id: 0 + id: 6 text: text type: type - context: '{}' - id: 0 + id: 6 text: text type: type type: text @@ -4310,13 +4953,14 @@ components: action: action messages: - context: '{}' - id: 0 + id: 6 text: text type: type - context: '{}' - id: 0 + id: 6 text: text type: type + oauth2_login_challenge: oauth2_login_challenge return_to: return_to id: 046b6c7f-0b8a-43b9-b35d-6489e6daee91 type: type @@ -4341,6 +4985,12 @@ components: description: IssuedAt is the time (UTC) when the flow occurred. format: date-time type: string + oauth2_login_challenge: + format: uuid4 + nullable: true + type: string + oauth2_login_request: + $ref: '#/components/schemas/LoginRequest' request_url: description: |- RequestURL is the initial URL that was requested from Ory Kratos. It can be used @@ -4376,16 +5026,16 @@ components: - meta: label: context: '{}' - id: 0 + id: 6 text: text type: type messages: - context: '{}' - id: 0 + id: 6 text: text type: type - context: '{}' - id: 0 + id: 6 text: text type: type type: text @@ -4393,16 +5043,16 @@ components: - meta: label: context: '{}' - id: 0 + id: 6 text: text type: type messages: - context: '{}' - id: 0 + id: 6 text: text type: type - context: '{}' - id: 0 + id: 6 text: text type: type type: text @@ -4411,11 +5061,11 @@ components: action: action messages: - context: '{}' - id: 0 + id: 6 text: text type: type - context: '{}' - id: 0 + id: 6 text: text type: type identity: @@ -4546,16 +5196,16 @@ components: - meta: label: context: '{}' - id: 0 + id: 6 text: text type: type messages: - context: '{}' - id: 0 + id: 6 text: text type: type - context: '{}' - id: 0 + id: 6 text: text type: type type: text @@ -4563,16 +5213,16 @@ components: - meta: label: context: '{}' - id: 0 + id: 6 text: text type: type messages: - context: '{}' - id: 0 + id: 6 text: text type: type - context: '{}' - id: 0 + id: 6 text: text type: type type: text @@ -4581,11 +5231,11 @@ components: action: action messages: - context: '{}' - id: 0 + id: 6 text: text type: type - context: '{}' - id: 0 + id: 6 text: text type: type active: active @@ -5658,16 +6308,16 @@ components: - meta: label: context: '{}' - id: 0 + id: 6 text: text type: type messages: - context: '{}' - id: 0 + id: 6 text: text type: type - context: '{}' - id: 0 + id: 6 text: text type: type type: text @@ -5675,16 +6325,16 @@ components: - meta: label: context: '{}' - id: 0 + id: 6 text: text type: type messages: - context: '{}' - id: 0 + id: 6 text: text type: type - context: '{}' - id: 0 + id: 6 text: text type: type type: text @@ -5693,11 +6343,11 @@ components: action: action messages: - context: '{}' - id: 0 + id: 6 text: text type: type - context: '{}' - id: 0 + id: 6 text: text type: type properties: @@ -5729,16 +6379,16 @@ components: meta: label: context: '{}' - id: 0 + id: 6 text: text type: type messages: - context: '{}' - id: 0 + id: 6 text: text type: type - context: '{}' - id: 0 + id: 6 text: text type: type type: text @@ -5996,7 +6646,7 @@ components: example: label: context: '{}' - id: 0 + id: 6 text: text type: type properties: @@ -6077,7 +6727,7 @@ components: uiText: example: context: '{}' - id: 0 + id: 6 text: text type: type properties: diff --git a/internal/httpclient/api_v0alpha2.go b/internal/httpclient/api_v0alpha2.go index 9069c26ad04..0955abec27f 100644 --- a/internal/httpclient/api_v0alpha2.go +++ b/internal/httpclient/api_v0alpha2.go @@ -489,6 +489,10 @@ type V0alpha2Api interface { `security_csrf_violation`: Unable to fetch the flow because a CSRF violation occurred. `security_identity_mismatch`: The requested `?return_to` address is not allowed to be used. Adjust this in the configuration! + The optional query parameter login_challenge is set when using Kratos with + Hydra in an OAuth2 flow. See the oauth2_provider.url configuration + option. + This endpoint is NOT INTENDED for clients that do not have a browser (Chrome, Firefox, ...) as cookies are needed. More information can be found at [Ory Kratos User Login](https://www.ory.sh/docs/kratos/self-service/flows/user-login) and [User Registration Documentation](https://www.ory.sh/docs/kratos/self-service/flows/user-registration). @@ -4402,14 +4406,19 @@ func (a *V0alpha2ApiService) GetWebAuthnJavaScriptExecute(r V0alpha2ApiApiGetWeb } type V0alpha2ApiApiInitializeSelfServiceLoginFlowForBrowsersRequest struct { - ctx context.Context - ApiService V0alpha2Api - refresh *bool - aal *string - returnTo *string - cookie *string + ctx context.Context + ApiService V0alpha2Api + loginChallenge *string + refresh *bool + aal *string + returnTo *string + cookie *string } +func (r V0alpha2ApiApiInitializeSelfServiceLoginFlowForBrowsersRequest) LoginChallenge(loginChallenge string) V0alpha2ApiApiInitializeSelfServiceLoginFlowForBrowsersRequest { + r.loginChallenge = &loginChallenge + return r +} func (r V0alpha2ApiApiInitializeSelfServiceLoginFlowForBrowsersRequest) Refresh(refresh bool) V0alpha2ApiApiInitializeSelfServiceLoginFlowForBrowsersRequest { r.refresh = &refresh return r @@ -4450,6 +4459,10 @@ case of an error, the `error.id` of the JSON response body can be one of: `security_csrf_violation`: Unable to fetch the flow because a CSRF violation occurred. `security_identity_mismatch`: The requested `?return_to` address is not allowed to be used. Adjust this in the configuration! +The optional query parameter login_challenge is set when using Kratos with +Hydra in an OAuth2 flow. See the oauth2_provider.url configuration +option. + This endpoint is NOT INTENDED for clients that do not have a browser (Chrome, Firefox, ...) as cookies are needed. More information can be found at [Ory Kratos User Login](https://www.ory.sh/docs/kratos/self-service/flows/user-login) and [User Registration Documentation](https://www.ory.sh/docs/kratos/self-service/flows/user-registration). @@ -4488,6 +4501,9 @@ func (a *V0alpha2ApiService) InitializeSelfServiceLoginFlowForBrowsersExecute(r localVarQueryParams := url.Values{} localVarFormParams := url.Values{} + if r.loginChallenge != nil { + localVarQueryParams.Add("login_challenge", parameterToString(*r.loginChallenge, "")) + } if r.refresh != nil { localVarQueryParams.Add("refresh", parameterToString(*r.refresh, "")) } @@ -5009,11 +5025,16 @@ func (a *V0alpha2ApiService) InitializeSelfServiceRecoveryFlowWithoutBrowserExec } type V0alpha2ApiApiInitializeSelfServiceRegistrationFlowForBrowsersRequest struct { - ctx context.Context - ApiService V0alpha2Api - returnTo *string + ctx context.Context + ApiService V0alpha2Api + loginChallenge *string + returnTo *string } +func (r V0alpha2ApiApiInitializeSelfServiceRegistrationFlowForBrowsersRequest) LoginChallenge(loginChallenge string) V0alpha2ApiApiInitializeSelfServiceRegistrationFlowForBrowsersRequest { + r.loginChallenge = &loginChallenge + return r +} func (r V0alpha2ApiApiInitializeSelfServiceRegistrationFlowForBrowsersRequest) ReturnTo(returnTo string) V0alpha2ApiApiInitializeSelfServiceRegistrationFlowForBrowsersRequest { r.returnTo = &returnTo return r @@ -5086,6 +5107,9 @@ func (a *V0alpha2ApiService) InitializeSelfServiceRegistrationFlowForBrowsersExe localVarQueryParams := url.Values{} localVarFormParams := url.Values{} + if r.loginChallenge != nil { + localVarQueryParams.Add("login_challenge", parameterToString(*r.loginChallenge, "")) + } if r.returnTo != nil { localVarQueryParams.Add("return_to", parameterToString(*r.returnTo, "")) } diff --git a/internal/httpclient/docs/LoginRequest.md b/internal/httpclient/docs/LoginRequest.md new file mode 100644 index 00000000000..6ca2ab9a787 --- /dev/null +++ b/internal/httpclient/docs/LoginRequest.md @@ -0,0 +1,264 @@ +# LoginRequest + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Challenge** | Pointer to **string** | ID is the identifier (\\\"login challenge\\\") of the login request. It is used to identify the session. | [optional] +**Client** | Pointer to [**OAuth2Client**](OAuth2Client.md) | | [optional] +**OidcContext** | Pointer to [**OpenIDConnectContext**](OpenIDConnectContext.md) | | [optional] +**RequestUrl** | Pointer to **string** | RequestURL is the original OAuth 2.0 Authorization URL requested by the OAuth 2.0 client. It is the URL which initiates the OAuth 2.0 Authorization Code or OAuth 2.0 Implicit flow. This URL is typically not needed, but might come in handy if you want to deal with additional request parameters. | [optional] +**RequestedAccessTokenAudience** | Pointer to **[]string** | | [optional] +**RequestedScope** | Pointer to **[]string** | | [optional] +**SessionId** | Pointer to **string** | SessionID is the login session ID. If the user-agent reuses a login session (via cookie / remember flag) this ID will remain the same. If the user-agent did not have an existing authentication session (e.g. remember is false) this will be a new random value. This value is used as the \\\"sid\\\" parameter in the ID Token and in OIDC Front-/Back- channel logout. It's value can generally be used to associate consecutive login requests by a certain user. | [optional] +**Skip** | Pointer to **bool** | Skip, if true, implies that the client has requested the same scopes from the same user previously. If true, you can skip asking the user to grant the requested scopes, and simply forward the user to the redirect URL. This feature allows you to update / set session information. | [optional] +**Subject** | Pointer to **string** | Subject is the user ID of the end-user that authenticated. Now, that end user needs to grant or deny the scope requested by the OAuth 2.0 client. If this value is set and `skip` is true, you MUST include this subject type when accepting the login request, or the request will fail. | [optional] + +## Methods + +### NewLoginRequest + +`func NewLoginRequest() *LoginRequest` + +NewLoginRequest instantiates a new LoginRequest object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewLoginRequestWithDefaults + +`func NewLoginRequestWithDefaults() *LoginRequest` + +NewLoginRequestWithDefaults instantiates a new LoginRequest object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetChallenge + +`func (o *LoginRequest) GetChallenge() string` + +GetChallenge returns the Challenge field if non-nil, zero value otherwise. + +### GetChallengeOk + +`func (o *LoginRequest) GetChallengeOk() (*string, bool)` + +GetChallengeOk returns a tuple with the Challenge field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetChallenge + +`func (o *LoginRequest) SetChallenge(v string)` + +SetChallenge sets Challenge field to given value. + +### HasChallenge + +`func (o *LoginRequest) HasChallenge() bool` + +HasChallenge returns a boolean if a field has been set. + +### GetClient + +`func (o *LoginRequest) GetClient() OAuth2Client` + +GetClient returns the Client field if non-nil, zero value otherwise. + +### GetClientOk + +`func (o *LoginRequest) GetClientOk() (*OAuth2Client, bool)` + +GetClientOk returns a tuple with the Client field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetClient + +`func (o *LoginRequest) SetClient(v OAuth2Client)` + +SetClient sets Client field to given value. + +### HasClient + +`func (o *LoginRequest) HasClient() bool` + +HasClient returns a boolean if a field has been set. + +### GetOidcContext + +`func (o *LoginRequest) GetOidcContext() OpenIDConnectContext` + +GetOidcContext returns the OidcContext field if non-nil, zero value otherwise. + +### GetOidcContextOk + +`func (o *LoginRequest) GetOidcContextOk() (*OpenIDConnectContext, bool)` + +GetOidcContextOk returns a tuple with the OidcContext field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetOidcContext + +`func (o *LoginRequest) SetOidcContext(v OpenIDConnectContext)` + +SetOidcContext sets OidcContext field to given value. + +### HasOidcContext + +`func (o *LoginRequest) HasOidcContext() bool` + +HasOidcContext returns a boolean if a field has been set. + +### GetRequestUrl + +`func (o *LoginRequest) GetRequestUrl() string` + +GetRequestUrl returns the RequestUrl field if non-nil, zero value otherwise. + +### GetRequestUrlOk + +`func (o *LoginRequest) GetRequestUrlOk() (*string, bool)` + +GetRequestUrlOk returns a tuple with the RequestUrl field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetRequestUrl + +`func (o *LoginRequest) SetRequestUrl(v string)` + +SetRequestUrl sets RequestUrl field to given value. + +### HasRequestUrl + +`func (o *LoginRequest) HasRequestUrl() bool` + +HasRequestUrl returns a boolean if a field has been set. + +### GetRequestedAccessTokenAudience + +`func (o *LoginRequest) GetRequestedAccessTokenAudience() []string` + +GetRequestedAccessTokenAudience returns the RequestedAccessTokenAudience field if non-nil, zero value otherwise. + +### GetRequestedAccessTokenAudienceOk + +`func (o *LoginRequest) GetRequestedAccessTokenAudienceOk() (*[]string, bool)` + +GetRequestedAccessTokenAudienceOk returns a tuple with the RequestedAccessTokenAudience field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetRequestedAccessTokenAudience + +`func (o *LoginRequest) SetRequestedAccessTokenAudience(v []string)` + +SetRequestedAccessTokenAudience sets RequestedAccessTokenAudience field to given value. + +### HasRequestedAccessTokenAudience + +`func (o *LoginRequest) HasRequestedAccessTokenAudience() bool` + +HasRequestedAccessTokenAudience returns a boolean if a field has been set. + +### GetRequestedScope + +`func (o *LoginRequest) GetRequestedScope() []string` + +GetRequestedScope returns the RequestedScope field if non-nil, zero value otherwise. + +### GetRequestedScopeOk + +`func (o *LoginRequest) GetRequestedScopeOk() (*[]string, bool)` + +GetRequestedScopeOk returns a tuple with the RequestedScope field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetRequestedScope + +`func (o *LoginRequest) SetRequestedScope(v []string)` + +SetRequestedScope sets RequestedScope field to given value. + +### HasRequestedScope + +`func (o *LoginRequest) HasRequestedScope() bool` + +HasRequestedScope returns a boolean if a field has been set. + +### GetSessionId + +`func (o *LoginRequest) GetSessionId() string` + +GetSessionId returns the SessionId field if non-nil, zero value otherwise. + +### GetSessionIdOk + +`func (o *LoginRequest) GetSessionIdOk() (*string, bool)` + +GetSessionIdOk returns a tuple with the SessionId field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetSessionId + +`func (o *LoginRequest) SetSessionId(v string)` + +SetSessionId sets SessionId field to given value. + +### HasSessionId + +`func (o *LoginRequest) HasSessionId() bool` + +HasSessionId returns a boolean if a field has been set. + +### GetSkip + +`func (o *LoginRequest) GetSkip() bool` + +GetSkip returns the Skip field if non-nil, zero value otherwise. + +### GetSkipOk + +`func (o *LoginRequest) GetSkipOk() (*bool, bool)` + +GetSkipOk returns a tuple with the Skip field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetSkip + +`func (o *LoginRequest) SetSkip(v bool)` + +SetSkip sets Skip field to given value. + +### HasSkip + +`func (o *LoginRequest) HasSkip() bool` + +HasSkip returns a boolean if a field has been set. + +### GetSubject + +`func (o *LoginRequest) GetSubject() string` + +GetSubject returns the Subject field if non-nil, zero value otherwise. + +### GetSubjectOk + +`func (o *LoginRequest) GetSubjectOk() (*string, bool)` + +GetSubjectOk returns a tuple with the Subject field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetSubject + +`func (o *LoginRequest) SetSubject(v string)` + +SetSubject sets Subject field to given value. + +### HasSubject + +`func (o *LoginRequest) HasSubject() bool` + +HasSubject returns a boolean if a field has been set. + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/internal/httpclient/docs/OAuth2Client.md b/internal/httpclient/docs/OAuth2Client.md new file mode 100644 index 00000000000..030c3af4ed4 --- /dev/null +++ b/internal/httpclient/docs/OAuth2Client.md @@ -0,0 +1,940 @@ +# OAuth2Client + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**AllowedCorsOrigins** | Pointer to **[]string** | | [optional] +**Audience** | Pointer to **[]string** | | [optional] +**BackchannelLogoutSessionRequired** | Pointer to **bool** | Boolean value specifying whether the RP requires that a sid (session ID) Claim be included in the Logout Token to identify the RP session with the OP when the backchannel_logout_uri is used. If omitted, the default value is false. | [optional] +**BackchannelLogoutUri** | Pointer to **string** | RP URL that will cause the RP to log itself out when sent a Logout Token by the OP. | [optional] +**ClientId** | Pointer to **string** | ID is the id for this client. | [optional] +**ClientName** | Pointer to **string** | Name is the human-readable string name of the client to be presented to the end-user during authorization. | [optional] +**ClientSecret** | Pointer to **string** | Secret is the client's secret. The secret will be included in the create request as cleartext, and then never again. The secret is stored using BCrypt so it is impossible to recover it. Tell your users that they need to write the secret down as it will not be made available again. | [optional] +**ClientSecretExpiresAt** | Pointer to **int64** | SecretExpiresAt is an integer holding the time at which the client secret will expire or 0 if it will not expire. The time is represented as the number of seconds from 1970-01-01T00:00:00Z as measured in UTC until the date/time of expiration. This feature is currently not supported and it's value will always be set to 0. | [optional] +**ClientUri** | Pointer to **string** | ClientURI is an URL string of a web page providing information about the client. If present, the server SHOULD display this URL to the end-user in a clickable fashion. | [optional] +**Contacts** | Pointer to **[]string** | | [optional] +**CreatedAt** | Pointer to **time.Time** | CreatedAt returns the timestamp of the client's creation. | [optional] +**FrontchannelLogoutSessionRequired** | Pointer to **bool** | Boolean value specifying whether the RP requires that iss (issuer) and sid (session ID) query parameters be included to identify the RP session with the OP when the frontchannel_logout_uri is used. If omitted, the default value is false. | [optional] +**FrontchannelLogoutUri** | Pointer to **string** | RP URL that will cause the RP to log itself out when rendered in an iframe by the OP. An iss (issuer) query parameter and a sid (session ID) query parameter MAY be included by the OP to enable the RP to validate the request and to determine which of the potentially multiple sessions is to be logged out; if either is included, both MUST be. | [optional] +**GrantTypes** | Pointer to **[]string** | | [optional] +**Jwks** | Pointer to **map[string]interface{}** | | [optional] +**JwksUri** | Pointer to **string** | URL for the Client's JSON Web Key Set [JWK] document. If the Client signs requests to the Server, it contains the signing key(s) the Server uses to validate signatures from the Client. The JWK Set MAY also contain the Client's encryption keys(s), which are used by the Server to encrypt responses to the Client. When both signing and encryption keys are made available, a use (Key Use) parameter value is REQUIRED for all keys in the referenced JWK Set to indicate each key's intended usage. Although some algorithms allow the same key to be used for both signatures and encryption, doing so is NOT RECOMMENDED, as it is less secure. The JWK x5c parameter MAY be used to provide X.509 representations of keys provided. When used, the bare key values MUST still be present and MUST match those in the certificate. | [optional] +**LogoUri** | Pointer to **string** | LogoURI is an URL string that references a logo for the client. | [optional] +**Metadata** | Pointer to **map[string]interface{}** | | [optional] +**Owner** | Pointer to **string** | Owner is a string identifying the owner of the OAuth 2.0 Client. | [optional] +**PolicyUri** | Pointer to **string** | PolicyURI is a URL string that points to a human-readable privacy policy document that describes how the deployment organization collects, uses, retains, and discloses personal data. | [optional] +**PostLogoutRedirectUris** | Pointer to **[]string** | | [optional] +**RedirectUris** | Pointer to **[]string** | | [optional] +**RegistrationAccessToken** | Pointer to **string** | RegistrationAccessToken can be used to update, get, or delete the OAuth2 Client. | [optional] +**RegistrationClientUri** | Pointer to **string** | RegistrationClientURI is the URL used to update, get, or delete the OAuth2 Client. | [optional] +**RequestObjectSigningAlg** | Pointer to **string** | JWS [JWS] alg algorithm [JWA] that MUST be used for signing Request Objects sent to the OP. All Request Objects from this Client MUST be rejected, if not signed with this algorithm. | [optional] +**RequestUris** | Pointer to **[]string** | | [optional] +**ResponseTypes** | Pointer to **[]string** | | [optional] +**Scope** | Pointer to **string** | Scope is a string containing a space-separated list of scope values (as described in Section 3.3 of OAuth 2.0 [RFC6749]) that the client can use when requesting access tokens. | [optional] +**SectorIdentifierUri** | Pointer to **string** | URL using the https scheme to be used in calculating Pseudonymous Identifiers by the OP. The URL references a file with a single JSON array of redirect_uri values. | [optional] +**SubjectType** | Pointer to **string** | SubjectType requested for responses to this Client. The subject_types_supported Discovery parameter contains a list of the supported subject_type values for this server. Valid types include `pairwise` and `public`. | [optional] +**TokenEndpointAuthMethod** | Pointer to **string** | Requested Client Authentication method for the Token Endpoint. The options are client_secret_post, client_secret_basic, private_key_jwt, and none. | [optional] +**TokenEndpointAuthSigningAlg** | Pointer to **string** | Requested Client Authentication signing algorithm for the Token Endpoint. | [optional] +**TosUri** | Pointer to **string** | TermsOfServiceURI is a URL string that points to a human-readable terms of service document for the client that describes a contractual relationship between the end-user and the client that the end-user accepts when authorizing the client. | [optional] +**UpdatedAt** | Pointer to **time.Time** | UpdatedAt returns the timestamp of the last update. | [optional] +**UserinfoSignedResponseAlg** | Pointer to **string** | JWS alg algorithm [JWA] REQUIRED for signing UserInfo Responses. If this is specified, the response will be JWT [JWT] serialized, and signed using JWS. The default, if omitted, is for the UserInfo Response to return the Claims as a UTF-8 encoded JSON object using the application/json content-type. | [optional] + +## Methods + +### NewOAuth2Client + +`func NewOAuth2Client() *OAuth2Client` + +NewOAuth2Client instantiates a new OAuth2Client object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewOAuth2ClientWithDefaults + +`func NewOAuth2ClientWithDefaults() *OAuth2Client` + +NewOAuth2ClientWithDefaults instantiates a new OAuth2Client object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetAllowedCorsOrigins + +`func (o *OAuth2Client) GetAllowedCorsOrigins() []string` + +GetAllowedCorsOrigins returns the AllowedCorsOrigins field if non-nil, zero value otherwise. + +### GetAllowedCorsOriginsOk + +`func (o *OAuth2Client) GetAllowedCorsOriginsOk() (*[]string, bool)` + +GetAllowedCorsOriginsOk returns a tuple with the AllowedCorsOrigins field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetAllowedCorsOrigins + +`func (o *OAuth2Client) SetAllowedCorsOrigins(v []string)` + +SetAllowedCorsOrigins sets AllowedCorsOrigins field to given value. + +### HasAllowedCorsOrigins + +`func (o *OAuth2Client) HasAllowedCorsOrigins() bool` + +HasAllowedCorsOrigins returns a boolean if a field has been set. + +### GetAudience + +`func (o *OAuth2Client) GetAudience() []string` + +GetAudience returns the Audience field if non-nil, zero value otherwise. + +### GetAudienceOk + +`func (o *OAuth2Client) GetAudienceOk() (*[]string, bool)` + +GetAudienceOk returns a tuple with the Audience field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetAudience + +`func (o *OAuth2Client) SetAudience(v []string)` + +SetAudience sets Audience field to given value. + +### HasAudience + +`func (o *OAuth2Client) HasAudience() bool` + +HasAudience returns a boolean if a field has been set. + +### GetBackchannelLogoutSessionRequired + +`func (o *OAuth2Client) GetBackchannelLogoutSessionRequired() bool` + +GetBackchannelLogoutSessionRequired returns the BackchannelLogoutSessionRequired field if non-nil, zero value otherwise. + +### GetBackchannelLogoutSessionRequiredOk + +`func (o *OAuth2Client) GetBackchannelLogoutSessionRequiredOk() (*bool, bool)` + +GetBackchannelLogoutSessionRequiredOk returns a tuple with the BackchannelLogoutSessionRequired field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetBackchannelLogoutSessionRequired + +`func (o *OAuth2Client) SetBackchannelLogoutSessionRequired(v bool)` + +SetBackchannelLogoutSessionRequired sets BackchannelLogoutSessionRequired field to given value. + +### HasBackchannelLogoutSessionRequired + +`func (o *OAuth2Client) HasBackchannelLogoutSessionRequired() bool` + +HasBackchannelLogoutSessionRequired returns a boolean if a field has been set. + +### GetBackchannelLogoutUri + +`func (o *OAuth2Client) GetBackchannelLogoutUri() string` + +GetBackchannelLogoutUri returns the BackchannelLogoutUri field if non-nil, zero value otherwise. + +### GetBackchannelLogoutUriOk + +`func (o *OAuth2Client) GetBackchannelLogoutUriOk() (*string, bool)` + +GetBackchannelLogoutUriOk returns a tuple with the BackchannelLogoutUri field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetBackchannelLogoutUri + +`func (o *OAuth2Client) SetBackchannelLogoutUri(v string)` + +SetBackchannelLogoutUri sets BackchannelLogoutUri field to given value. + +### HasBackchannelLogoutUri + +`func (o *OAuth2Client) HasBackchannelLogoutUri() bool` + +HasBackchannelLogoutUri returns a boolean if a field has been set. + +### GetClientId + +`func (o *OAuth2Client) GetClientId() string` + +GetClientId returns the ClientId field if non-nil, zero value otherwise. + +### GetClientIdOk + +`func (o *OAuth2Client) GetClientIdOk() (*string, bool)` + +GetClientIdOk returns a tuple with the ClientId field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetClientId + +`func (o *OAuth2Client) SetClientId(v string)` + +SetClientId sets ClientId field to given value. + +### HasClientId + +`func (o *OAuth2Client) HasClientId() bool` + +HasClientId returns a boolean if a field has been set. + +### GetClientName + +`func (o *OAuth2Client) GetClientName() string` + +GetClientName returns the ClientName field if non-nil, zero value otherwise. + +### GetClientNameOk + +`func (o *OAuth2Client) GetClientNameOk() (*string, bool)` + +GetClientNameOk returns a tuple with the ClientName field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetClientName + +`func (o *OAuth2Client) SetClientName(v string)` + +SetClientName sets ClientName field to given value. + +### HasClientName + +`func (o *OAuth2Client) HasClientName() bool` + +HasClientName returns a boolean if a field has been set. + +### GetClientSecret + +`func (o *OAuth2Client) GetClientSecret() string` + +GetClientSecret returns the ClientSecret field if non-nil, zero value otherwise. + +### GetClientSecretOk + +`func (o *OAuth2Client) GetClientSecretOk() (*string, bool)` + +GetClientSecretOk returns a tuple with the ClientSecret field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetClientSecret + +`func (o *OAuth2Client) SetClientSecret(v string)` + +SetClientSecret sets ClientSecret field to given value. + +### HasClientSecret + +`func (o *OAuth2Client) HasClientSecret() bool` + +HasClientSecret returns a boolean if a field has been set. + +### GetClientSecretExpiresAt + +`func (o *OAuth2Client) GetClientSecretExpiresAt() int64` + +GetClientSecretExpiresAt returns the ClientSecretExpiresAt field if non-nil, zero value otherwise. + +### GetClientSecretExpiresAtOk + +`func (o *OAuth2Client) GetClientSecretExpiresAtOk() (*int64, bool)` + +GetClientSecretExpiresAtOk returns a tuple with the ClientSecretExpiresAt field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetClientSecretExpiresAt + +`func (o *OAuth2Client) SetClientSecretExpiresAt(v int64)` + +SetClientSecretExpiresAt sets ClientSecretExpiresAt field to given value. + +### HasClientSecretExpiresAt + +`func (o *OAuth2Client) HasClientSecretExpiresAt() bool` + +HasClientSecretExpiresAt returns a boolean if a field has been set. + +### GetClientUri + +`func (o *OAuth2Client) GetClientUri() string` + +GetClientUri returns the ClientUri field if non-nil, zero value otherwise. + +### GetClientUriOk + +`func (o *OAuth2Client) GetClientUriOk() (*string, bool)` + +GetClientUriOk returns a tuple with the ClientUri field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetClientUri + +`func (o *OAuth2Client) SetClientUri(v string)` + +SetClientUri sets ClientUri field to given value. + +### HasClientUri + +`func (o *OAuth2Client) HasClientUri() bool` + +HasClientUri returns a boolean if a field has been set. + +### GetContacts + +`func (o *OAuth2Client) GetContacts() []string` + +GetContacts returns the Contacts field if non-nil, zero value otherwise. + +### GetContactsOk + +`func (o *OAuth2Client) GetContactsOk() (*[]string, bool)` + +GetContactsOk returns a tuple with the Contacts field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetContacts + +`func (o *OAuth2Client) SetContacts(v []string)` + +SetContacts sets Contacts field to given value. + +### HasContacts + +`func (o *OAuth2Client) HasContacts() bool` + +HasContacts returns a boolean if a field has been set. + +### GetCreatedAt + +`func (o *OAuth2Client) GetCreatedAt() time.Time` + +GetCreatedAt returns the CreatedAt field if non-nil, zero value otherwise. + +### GetCreatedAtOk + +`func (o *OAuth2Client) GetCreatedAtOk() (*time.Time, bool)` + +GetCreatedAtOk returns a tuple with the CreatedAt field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetCreatedAt + +`func (o *OAuth2Client) SetCreatedAt(v time.Time)` + +SetCreatedAt sets CreatedAt field to given value. + +### HasCreatedAt + +`func (o *OAuth2Client) HasCreatedAt() bool` + +HasCreatedAt returns a boolean if a field has been set. + +### GetFrontchannelLogoutSessionRequired + +`func (o *OAuth2Client) GetFrontchannelLogoutSessionRequired() bool` + +GetFrontchannelLogoutSessionRequired returns the FrontchannelLogoutSessionRequired field if non-nil, zero value otherwise. + +### GetFrontchannelLogoutSessionRequiredOk + +`func (o *OAuth2Client) GetFrontchannelLogoutSessionRequiredOk() (*bool, bool)` + +GetFrontchannelLogoutSessionRequiredOk returns a tuple with the FrontchannelLogoutSessionRequired field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetFrontchannelLogoutSessionRequired + +`func (o *OAuth2Client) SetFrontchannelLogoutSessionRequired(v bool)` + +SetFrontchannelLogoutSessionRequired sets FrontchannelLogoutSessionRequired field to given value. + +### HasFrontchannelLogoutSessionRequired + +`func (o *OAuth2Client) HasFrontchannelLogoutSessionRequired() bool` + +HasFrontchannelLogoutSessionRequired returns a boolean if a field has been set. + +### GetFrontchannelLogoutUri + +`func (o *OAuth2Client) GetFrontchannelLogoutUri() string` + +GetFrontchannelLogoutUri returns the FrontchannelLogoutUri field if non-nil, zero value otherwise. + +### GetFrontchannelLogoutUriOk + +`func (o *OAuth2Client) GetFrontchannelLogoutUriOk() (*string, bool)` + +GetFrontchannelLogoutUriOk returns a tuple with the FrontchannelLogoutUri field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetFrontchannelLogoutUri + +`func (o *OAuth2Client) SetFrontchannelLogoutUri(v string)` + +SetFrontchannelLogoutUri sets FrontchannelLogoutUri field to given value. + +### HasFrontchannelLogoutUri + +`func (o *OAuth2Client) HasFrontchannelLogoutUri() bool` + +HasFrontchannelLogoutUri returns a boolean if a field has been set. + +### GetGrantTypes + +`func (o *OAuth2Client) GetGrantTypes() []string` + +GetGrantTypes returns the GrantTypes field if non-nil, zero value otherwise. + +### GetGrantTypesOk + +`func (o *OAuth2Client) GetGrantTypesOk() (*[]string, bool)` + +GetGrantTypesOk returns a tuple with the GrantTypes field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetGrantTypes + +`func (o *OAuth2Client) SetGrantTypes(v []string)` + +SetGrantTypes sets GrantTypes field to given value. + +### HasGrantTypes + +`func (o *OAuth2Client) HasGrantTypes() bool` + +HasGrantTypes returns a boolean if a field has been set. + +### GetJwks + +`func (o *OAuth2Client) GetJwks() map[string]interface{}` + +GetJwks returns the Jwks field if non-nil, zero value otherwise. + +### GetJwksOk + +`func (o *OAuth2Client) GetJwksOk() (*map[string]interface{}, bool)` + +GetJwksOk returns a tuple with the Jwks field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetJwks + +`func (o *OAuth2Client) SetJwks(v map[string]interface{})` + +SetJwks sets Jwks field to given value. + +### HasJwks + +`func (o *OAuth2Client) HasJwks() bool` + +HasJwks returns a boolean if a field has been set. + +### GetJwksUri + +`func (o *OAuth2Client) GetJwksUri() string` + +GetJwksUri returns the JwksUri field if non-nil, zero value otherwise. + +### GetJwksUriOk + +`func (o *OAuth2Client) GetJwksUriOk() (*string, bool)` + +GetJwksUriOk returns a tuple with the JwksUri field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetJwksUri + +`func (o *OAuth2Client) SetJwksUri(v string)` + +SetJwksUri sets JwksUri field to given value. + +### HasJwksUri + +`func (o *OAuth2Client) HasJwksUri() bool` + +HasJwksUri returns a boolean if a field has been set. + +### GetLogoUri + +`func (o *OAuth2Client) GetLogoUri() string` + +GetLogoUri returns the LogoUri field if non-nil, zero value otherwise. + +### GetLogoUriOk + +`func (o *OAuth2Client) GetLogoUriOk() (*string, bool)` + +GetLogoUriOk returns a tuple with the LogoUri field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetLogoUri + +`func (o *OAuth2Client) SetLogoUri(v string)` + +SetLogoUri sets LogoUri field to given value. + +### HasLogoUri + +`func (o *OAuth2Client) HasLogoUri() bool` + +HasLogoUri returns a boolean if a field has been set. + +### GetMetadata + +`func (o *OAuth2Client) GetMetadata() map[string]interface{}` + +GetMetadata returns the Metadata field if non-nil, zero value otherwise. + +### GetMetadataOk + +`func (o *OAuth2Client) GetMetadataOk() (*map[string]interface{}, bool)` + +GetMetadataOk returns a tuple with the Metadata field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetMetadata + +`func (o *OAuth2Client) SetMetadata(v map[string]interface{})` + +SetMetadata sets Metadata field to given value. + +### HasMetadata + +`func (o *OAuth2Client) HasMetadata() bool` + +HasMetadata returns a boolean if a field has been set. + +### GetOwner + +`func (o *OAuth2Client) GetOwner() string` + +GetOwner returns the Owner field if non-nil, zero value otherwise. + +### GetOwnerOk + +`func (o *OAuth2Client) GetOwnerOk() (*string, bool)` + +GetOwnerOk returns a tuple with the Owner field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetOwner + +`func (o *OAuth2Client) SetOwner(v string)` + +SetOwner sets Owner field to given value. + +### HasOwner + +`func (o *OAuth2Client) HasOwner() bool` + +HasOwner returns a boolean if a field has been set. + +### GetPolicyUri + +`func (o *OAuth2Client) GetPolicyUri() string` + +GetPolicyUri returns the PolicyUri field if non-nil, zero value otherwise. + +### GetPolicyUriOk + +`func (o *OAuth2Client) GetPolicyUriOk() (*string, bool)` + +GetPolicyUriOk returns a tuple with the PolicyUri field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetPolicyUri + +`func (o *OAuth2Client) SetPolicyUri(v string)` + +SetPolicyUri sets PolicyUri field to given value. + +### HasPolicyUri + +`func (o *OAuth2Client) HasPolicyUri() bool` + +HasPolicyUri returns a boolean if a field has been set. + +### GetPostLogoutRedirectUris + +`func (o *OAuth2Client) GetPostLogoutRedirectUris() []string` + +GetPostLogoutRedirectUris returns the PostLogoutRedirectUris field if non-nil, zero value otherwise. + +### GetPostLogoutRedirectUrisOk + +`func (o *OAuth2Client) GetPostLogoutRedirectUrisOk() (*[]string, bool)` + +GetPostLogoutRedirectUrisOk returns a tuple with the PostLogoutRedirectUris field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetPostLogoutRedirectUris + +`func (o *OAuth2Client) SetPostLogoutRedirectUris(v []string)` + +SetPostLogoutRedirectUris sets PostLogoutRedirectUris field to given value. + +### HasPostLogoutRedirectUris + +`func (o *OAuth2Client) HasPostLogoutRedirectUris() bool` + +HasPostLogoutRedirectUris returns a boolean if a field has been set. + +### GetRedirectUris + +`func (o *OAuth2Client) GetRedirectUris() []string` + +GetRedirectUris returns the RedirectUris field if non-nil, zero value otherwise. + +### GetRedirectUrisOk + +`func (o *OAuth2Client) GetRedirectUrisOk() (*[]string, bool)` + +GetRedirectUrisOk returns a tuple with the RedirectUris field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetRedirectUris + +`func (o *OAuth2Client) SetRedirectUris(v []string)` + +SetRedirectUris sets RedirectUris field to given value. + +### HasRedirectUris + +`func (o *OAuth2Client) HasRedirectUris() bool` + +HasRedirectUris returns a boolean if a field has been set. + +### GetRegistrationAccessToken + +`func (o *OAuth2Client) GetRegistrationAccessToken() string` + +GetRegistrationAccessToken returns the RegistrationAccessToken field if non-nil, zero value otherwise. + +### GetRegistrationAccessTokenOk + +`func (o *OAuth2Client) GetRegistrationAccessTokenOk() (*string, bool)` + +GetRegistrationAccessTokenOk returns a tuple with the RegistrationAccessToken field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetRegistrationAccessToken + +`func (o *OAuth2Client) SetRegistrationAccessToken(v string)` + +SetRegistrationAccessToken sets RegistrationAccessToken field to given value. + +### HasRegistrationAccessToken + +`func (o *OAuth2Client) HasRegistrationAccessToken() bool` + +HasRegistrationAccessToken returns a boolean if a field has been set. + +### GetRegistrationClientUri + +`func (o *OAuth2Client) GetRegistrationClientUri() string` + +GetRegistrationClientUri returns the RegistrationClientUri field if non-nil, zero value otherwise. + +### GetRegistrationClientUriOk + +`func (o *OAuth2Client) GetRegistrationClientUriOk() (*string, bool)` + +GetRegistrationClientUriOk returns a tuple with the RegistrationClientUri field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetRegistrationClientUri + +`func (o *OAuth2Client) SetRegistrationClientUri(v string)` + +SetRegistrationClientUri sets RegistrationClientUri field to given value. + +### HasRegistrationClientUri + +`func (o *OAuth2Client) HasRegistrationClientUri() bool` + +HasRegistrationClientUri returns a boolean if a field has been set. + +### GetRequestObjectSigningAlg + +`func (o *OAuth2Client) GetRequestObjectSigningAlg() string` + +GetRequestObjectSigningAlg returns the RequestObjectSigningAlg field if non-nil, zero value otherwise. + +### GetRequestObjectSigningAlgOk + +`func (o *OAuth2Client) GetRequestObjectSigningAlgOk() (*string, bool)` + +GetRequestObjectSigningAlgOk returns a tuple with the RequestObjectSigningAlg field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetRequestObjectSigningAlg + +`func (o *OAuth2Client) SetRequestObjectSigningAlg(v string)` + +SetRequestObjectSigningAlg sets RequestObjectSigningAlg field to given value. + +### HasRequestObjectSigningAlg + +`func (o *OAuth2Client) HasRequestObjectSigningAlg() bool` + +HasRequestObjectSigningAlg returns a boolean if a field has been set. + +### GetRequestUris + +`func (o *OAuth2Client) GetRequestUris() []string` + +GetRequestUris returns the RequestUris field if non-nil, zero value otherwise. + +### GetRequestUrisOk + +`func (o *OAuth2Client) GetRequestUrisOk() (*[]string, bool)` + +GetRequestUrisOk returns a tuple with the RequestUris field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetRequestUris + +`func (o *OAuth2Client) SetRequestUris(v []string)` + +SetRequestUris sets RequestUris field to given value. + +### HasRequestUris + +`func (o *OAuth2Client) HasRequestUris() bool` + +HasRequestUris returns a boolean if a field has been set. + +### GetResponseTypes + +`func (o *OAuth2Client) GetResponseTypes() []string` + +GetResponseTypes returns the ResponseTypes field if non-nil, zero value otherwise. + +### GetResponseTypesOk + +`func (o *OAuth2Client) GetResponseTypesOk() (*[]string, bool)` + +GetResponseTypesOk returns a tuple with the ResponseTypes field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetResponseTypes + +`func (o *OAuth2Client) SetResponseTypes(v []string)` + +SetResponseTypes sets ResponseTypes field to given value. + +### HasResponseTypes + +`func (o *OAuth2Client) HasResponseTypes() bool` + +HasResponseTypes returns a boolean if a field has been set. + +### GetScope + +`func (o *OAuth2Client) GetScope() string` + +GetScope returns the Scope field if non-nil, zero value otherwise. + +### GetScopeOk + +`func (o *OAuth2Client) GetScopeOk() (*string, bool)` + +GetScopeOk returns a tuple with the Scope field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetScope + +`func (o *OAuth2Client) SetScope(v string)` + +SetScope sets Scope field to given value. + +### HasScope + +`func (o *OAuth2Client) HasScope() bool` + +HasScope returns a boolean if a field has been set. + +### GetSectorIdentifierUri + +`func (o *OAuth2Client) GetSectorIdentifierUri() string` + +GetSectorIdentifierUri returns the SectorIdentifierUri field if non-nil, zero value otherwise. + +### GetSectorIdentifierUriOk + +`func (o *OAuth2Client) GetSectorIdentifierUriOk() (*string, bool)` + +GetSectorIdentifierUriOk returns a tuple with the SectorIdentifierUri field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetSectorIdentifierUri + +`func (o *OAuth2Client) SetSectorIdentifierUri(v string)` + +SetSectorIdentifierUri sets SectorIdentifierUri field to given value. + +### HasSectorIdentifierUri + +`func (o *OAuth2Client) HasSectorIdentifierUri() bool` + +HasSectorIdentifierUri returns a boolean if a field has been set. + +### GetSubjectType + +`func (o *OAuth2Client) GetSubjectType() string` + +GetSubjectType returns the SubjectType field if non-nil, zero value otherwise. + +### GetSubjectTypeOk + +`func (o *OAuth2Client) GetSubjectTypeOk() (*string, bool)` + +GetSubjectTypeOk returns a tuple with the SubjectType field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetSubjectType + +`func (o *OAuth2Client) SetSubjectType(v string)` + +SetSubjectType sets SubjectType field to given value. + +### HasSubjectType + +`func (o *OAuth2Client) HasSubjectType() bool` + +HasSubjectType returns a boolean if a field has been set. + +### GetTokenEndpointAuthMethod + +`func (o *OAuth2Client) GetTokenEndpointAuthMethod() string` + +GetTokenEndpointAuthMethod returns the TokenEndpointAuthMethod field if non-nil, zero value otherwise. + +### GetTokenEndpointAuthMethodOk + +`func (o *OAuth2Client) GetTokenEndpointAuthMethodOk() (*string, bool)` + +GetTokenEndpointAuthMethodOk returns a tuple with the TokenEndpointAuthMethod field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetTokenEndpointAuthMethod + +`func (o *OAuth2Client) SetTokenEndpointAuthMethod(v string)` + +SetTokenEndpointAuthMethod sets TokenEndpointAuthMethod field to given value. + +### HasTokenEndpointAuthMethod + +`func (o *OAuth2Client) HasTokenEndpointAuthMethod() bool` + +HasTokenEndpointAuthMethod returns a boolean if a field has been set. + +### GetTokenEndpointAuthSigningAlg + +`func (o *OAuth2Client) GetTokenEndpointAuthSigningAlg() string` + +GetTokenEndpointAuthSigningAlg returns the TokenEndpointAuthSigningAlg field if non-nil, zero value otherwise. + +### GetTokenEndpointAuthSigningAlgOk + +`func (o *OAuth2Client) GetTokenEndpointAuthSigningAlgOk() (*string, bool)` + +GetTokenEndpointAuthSigningAlgOk returns a tuple with the TokenEndpointAuthSigningAlg field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetTokenEndpointAuthSigningAlg + +`func (o *OAuth2Client) SetTokenEndpointAuthSigningAlg(v string)` + +SetTokenEndpointAuthSigningAlg sets TokenEndpointAuthSigningAlg field to given value. + +### HasTokenEndpointAuthSigningAlg + +`func (o *OAuth2Client) HasTokenEndpointAuthSigningAlg() bool` + +HasTokenEndpointAuthSigningAlg returns a boolean if a field has been set. + +### GetTosUri + +`func (o *OAuth2Client) GetTosUri() string` + +GetTosUri returns the TosUri field if non-nil, zero value otherwise. + +### GetTosUriOk + +`func (o *OAuth2Client) GetTosUriOk() (*string, bool)` + +GetTosUriOk returns a tuple with the TosUri field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetTosUri + +`func (o *OAuth2Client) SetTosUri(v string)` + +SetTosUri sets TosUri field to given value. + +### HasTosUri + +`func (o *OAuth2Client) HasTosUri() bool` + +HasTosUri returns a boolean if a field has been set. + +### GetUpdatedAt + +`func (o *OAuth2Client) GetUpdatedAt() time.Time` + +GetUpdatedAt returns the UpdatedAt field if non-nil, zero value otherwise. + +### GetUpdatedAtOk + +`func (o *OAuth2Client) GetUpdatedAtOk() (*time.Time, bool)` + +GetUpdatedAtOk returns a tuple with the UpdatedAt field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetUpdatedAt + +`func (o *OAuth2Client) SetUpdatedAt(v time.Time)` + +SetUpdatedAt sets UpdatedAt field to given value. + +### HasUpdatedAt + +`func (o *OAuth2Client) HasUpdatedAt() bool` + +HasUpdatedAt returns a boolean if a field has been set. + +### GetUserinfoSignedResponseAlg + +`func (o *OAuth2Client) GetUserinfoSignedResponseAlg() string` + +GetUserinfoSignedResponseAlg returns the UserinfoSignedResponseAlg field if non-nil, zero value otherwise. + +### GetUserinfoSignedResponseAlgOk + +`func (o *OAuth2Client) GetUserinfoSignedResponseAlgOk() (*string, bool)` + +GetUserinfoSignedResponseAlgOk returns a tuple with the UserinfoSignedResponseAlg field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetUserinfoSignedResponseAlg + +`func (o *OAuth2Client) SetUserinfoSignedResponseAlg(v string)` + +SetUserinfoSignedResponseAlg sets UserinfoSignedResponseAlg field to given value. + +### HasUserinfoSignedResponseAlg + +`func (o *OAuth2Client) HasUserinfoSignedResponseAlg() bool` + +HasUserinfoSignedResponseAlg returns a boolean if a field has been set. + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/internal/httpclient/docs/OpenIDConnectContext.md b/internal/httpclient/docs/OpenIDConnectContext.md new file mode 100644 index 00000000000..9c36a97a776 --- /dev/null +++ b/internal/httpclient/docs/OpenIDConnectContext.md @@ -0,0 +1,160 @@ +# OpenIDConnectContext + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**AcrValues** | Pointer to **[]string** | ACRValues is the Authentication AuthorizationContext Class Reference requested in the OAuth 2.0 Authorization request. It is a parameter defined by OpenID Connect and expresses which level of authentication (e.g. 2FA) is required. OpenID Connect defines it as follows: > Requested Authentication AuthorizationContext Class Reference values. Space-separated string that specifies the acr values that the Authorization Server is being requested to use for processing this Authentication Request, with the values appearing in order of preference. The Authentication AuthorizationContext Class satisfied by the authentication performed is returned as the acr Claim Value, as specified in Section 2. The acr Claim is requested as a Voluntary Claim by this parameter. | [optional] +**Display** | Pointer to **string** | Display is a string value that specifies how the Authorization Server displays the authentication and consent user interface pages to the End-User. The defined values are: page: The Authorization Server SHOULD display the authentication and consent UI consistent with a full User Agent page view. If the display parameter is not specified, this is the default display mode. popup: The Authorization Server SHOULD display the authentication and consent UI consistent with a popup User Agent window. The popup User Agent window should be of an appropriate size for a login-focused dialog and should not obscure the entire window that it is popping up over. touch: The Authorization Server SHOULD display the authentication and consent UI consistent with a device that leverages a touch interface. wap: The Authorization Server SHOULD display the authentication and consent UI consistent with a \\\"feature phone\\\" type display. The Authorization Server MAY also attempt to detect the capabilities of the User Agent and present an appropriate display. | [optional] +**IdTokenHintClaims** | Pointer to **map[string]map[string]interface{}** | IDTokenHintClaims are the claims of the ID Token previously issued by the Authorization Server being passed as a hint about the End-User's current or past authenticated session with the Client. | [optional] +**LoginHint** | Pointer to **string** | LoginHint hints about the login identifier the End-User might use to log in (if necessary). This hint can be used by an RP if it first asks the End-User for their e-mail address (or other identifier) and then wants to pass that value as a hint to the discovered authorization service. This value MAY also be a phone number in the format specified for the phone_number Claim. The use of this parameter is optional. | [optional] +**UiLocales** | Pointer to **[]string** | UILocales is the End-User'id preferred languages and scripts for the user interface, represented as a space-separated list of BCP47 [RFC5646] language tag values, ordered by preference. For instance, the value \\\"fr-CA fr en\\\" represents a preference for French as spoken in Canada, then French (without a region designation), followed by English (without a region designation). An error SHOULD NOT result if some or all of the requested locales are not supported by the OpenID Provider. | [optional] + +## Methods + +### NewOpenIDConnectContext + +`func NewOpenIDConnectContext() *OpenIDConnectContext` + +NewOpenIDConnectContext instantiates a new OpenIDConnectContext object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewOpenIDConnectContextWithDefaults + +`func NewOpenIDConnectContextWithDefaults() *OpenIDConnectContext` + +NewOpenIDConnectContextWithDefaults instantiates a new OpenIDConnectContext object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetAcrValues + +`func (o *OpenIDConnectContext) GetAcrValues() []string` + +GetAcrValues returns the AcrValues field if non-nil, zero value otherwise. + +### GetAcrValuesOk + +`func (o *OpenIDConnectContext) GetAcrValuesOk() (*[]string, bool)` + +GetAcrValuesOk returns a tuple with the AcrValues field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetAcrValues + +`func (o *OpenIDConnectContext) SetAcrValues(v []string)` + +SetAcrValues sets AcrValues field to given value. + +### HasAcrValues + +`func (o *OpenIDConnectContext) HasAcrValues() bool` + +HasAcrValues returns a boolean if a field has been set. + +### GetDisplay + +`func (o *OpenIDConnectContext) GetDisplay() string` + +GetDisplay returns the Display field if non-nil, zero value otherwise. + +### GetDisplayOk + +`func (o *OpenIDConnectContext) GetDisplayOk() (*string, bool)` + +GetDisplayOk returns a tuple with the Display field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetDisplay + +`func (o *OpenIDConnectContext) SetDisplay(v string)` + +SetDisplay sets Display field to given value. + +### HasDisplay + +`func (o *OpenIDConnectContext) HasDisplay() bool` + +HasDisplay returns a boolean if a field has been set. + +### GetIdTokenHintClaims + +`func (o *OpenIDConnectContext) GetIdTokenHintClaims() map[string]map[string]interface{}` + +GetIdTokenHintClaims returns the IdTokenHintClaims field if non-nil, zero value otherwise. + +### GetIdTokenHintClaimsOk + +`func (o *OpenIDConnectContext) GetIdTokenHintClaimsOk() (*map[string]map[string]interface{}, bool)` + +GetIdTokenHintClaimsOk returns a tuple with the IdTokenHintClaims field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetIdTokenHintClaims + +`func (o *OpenIDConnectContext) SetIdTokenHintClaims(v map[string]map[string]interface{})` + +SetIdTokenHintClaims sets IdTokenHintClaims field to given value. + +### HasIdTokenHintClaims + +`func (o *OpenIDConnectContext) HasIdTokenHintClaims() bool` + +HasIdTokenHintClaims returns a boolean if a field has been set. + +### GetLoginHint + +`func (o *OpenIDConnectContext) GetLoginHint() string` + +GetLoginHint returns the LoginHint field if non-nil, zero value otherwise. + +### GetLoginHintOk + +`func (o *OpenIDConnectContext) GetLoginHintOk() (*string, bool)` + +GetLoginHintOk returns a tuple with the LoginHint field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetLoginHint + +`func (o *OpenIDConnectContext) SetLoginHint(v string)` + +SetLoginHint sets LoginHint field to given value. + +### HasLoginHint + +`func (o *OpenIDConnectContext) HasLoginHint() bool` + +HasLoginHint returns a boolean if a field has been set. + +### GetUiLocales + +`func (o *OpenIDConnectContext) GetUiLocales() []string` + +GetUiLocales returns the UiLocales field if non-nil, zero value otherwise. + +### GetUiLocalesOk + +`func (o *OpenIDConnectContext) GetUiLocalesOk() (*[]string, bool)` + +GetUiLocalesOk returns a tuple with the UiLocales field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetUiLocales + +`func (o *OpenIDConnectContext) SetUiLocales(v []string)` + +SetUiLocales sets UiLocales field to given value. + +### HasUiLocales + +`func (o *OpenIDConnectContext) HasUiLocales() bool` + +HasUiLocales returns a boolean if a field has been set. + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/internal/httpclient/docs/SelfServiceLoginFlow.md b/internal/httpclient/docs/SelfServiceLoginFlow.md index 3cb8c233610..70d0259d3e0 100644 --- a/internal/httpclient/docs/SelfServiceLoginFlow.md +++ b/internal/httpclient/docs/SelfServiceLoginFlow.md @@ -9,6 +9,8 @@ Name | Type | Description | Notes **ExpiresAt** | **time.Time** | ExpiresAt is the time (UTC) when the flow expires. If the user still wishes to log in, a new flow has to be initiated. | **Id** | **string** | ID represents the flow's unique ID. When performing the login flow, this represents the id in the login UI's query parameter: http://<selfservice.flows.login.ui_url>/?flow=<flow_id> | **IssuedAt** | **time.Time** | IssuedAt is the time (UTC) when the flow started. | +**Oauth2LoginChallenge** | Pointer to **NullableString** | | [optional] +**Oauth2LoginRequest** | Pointer to [**LoginRequest**](LoginRequest.md) | | [optional] **Refresh** | Pointer to **bool** | Refresh stores whether this login flow should enforce re-authentication. | [optional] **RequestUrl** | **string** | RequestURL is the initial URL that was requested from Ory Kratos. It can be used to forward information contained in the URL's path or query for example. | **RequestedAal** | Pointer to [**AuthenticatorAssuranceLevel**](AuthenticatorAssuranceLevel.md) | | [optional] @@ -146,6 +148,66 @@ and a boolean to check if the value has been set. SetIssuedAt sets IssuedAt field to given value. +### GetOauth2LoginChallenge + +`func (o *SelfServiceLoginFlow) GetOauth2LoginChallenge() string` + +GetOauth2LoginChallenge returns the Oauth2LoginChallenge field if non-nil, zero value otherwise. + +### GetOauth2LoginChallengeOk + +`func (o *SelfServiceLoginFlow) GetOauth2LoginChallengeOk() (*string, bool)` + +GetOauth2LoginChallengeOk returns a tuple with the Oauth2LoginChallenge field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetOauth2LoginChallenge + +`func (o *SelfServiceLoginFlow) SetOauth2LoginChallenge(v string)` + +SetOauth2LoginChallenge sets Oauth2LoginChallenge field to given value. + +### HasOauth2LoginChallenge + +`func (o *SelfServiceLoginFlow) HasOauth2LoginChallenge() bool` + +HasOauth2LoginChallenge returns a boolean if a field has been set. + +### SetOauth2LoginChallengeNil + +`func (o *SelfServiceLoginFlow) SetOauth2LoginChallengeNil(b bool)` + + SetOauth2LoginChallengeNil sets the value for Oauth2LoginChallenge to be an explicit nil + +### UnsetOauth2LoginChallenge +`func (o *SelfServiceLoginFlow) UnsetOauth2LoginChallenge()` + +UnsetOauth2LoginChallenge ensures that no value is present for Oauth2LoginChallenge, not even an explicit nil +### GetOauth2LoginRequest + +`func (o *SelfServiceLoginFlow) GetOauth2LoginRequest() LoginRequest` + +GetOauth2LoginRequest returns the Oauth2LoginRequest field if non-nil, zero value otherwise. + +### GetOauth2LoginRequestOk + +`func (o *SelfServiceLoginFlow) GetOauth2LoginRequestOk() (*LoginRequest, bool)` + +GetOauth2LoginRequestOk returns a tuple with the Oauth2LoginRequest field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetOauth2LoginRequest + +`func (o *SelfServiceLoginFlow) SetOauth2LoginRequest(v LoginRequest)` + +SetOauth2LoginRequest sets Oauth2LoginRequest field to given value. + +### HasOauth2LoginRequest + +`func (o *SelfServiceLoginFlow) HasOauth2LoginRequest() bool` + +HasOauth2LoginRequest returns a boolean if a field has been set. + ### GetRefresh `func (o *SelfServiceLoginFlow) GetRefresh() bool` diff --git a/internal/httpclient/docs/SelfServiceRegistrationFlow.md b/internal/httpclient/docs/SelfServiceRegistrationFlow.md index 7f7f424a0db..53668d515eb 100644 --- a/internal/httpclient/docs/SelfServiceRegistrationFlow.md +++ b/internal/httpclient/docs/SelfServiceRegistrationFlow.md @@ -8,6 +8,8 @@ Name | Type | Description | Notes **ExpiresAt** | **time.Time** | ExpiresAt is the time (UTC) when the flow expires. If the user still wishes to log in, a new flow has to be initiated. | **Id** | **string** | ID represents the flow's unique ID. When performing the registration flow, this represents the id in the registration ui's query parameter: http://<selfservice.flows.registration.ui_url>/?flow=<id> | **IssuedAt** | **time.Time** | IssuedAt is the time (UTC) when the flow occurred. | +**Oauth2LoginChallenge** | Pointer to **NullableString** | | [optional] +**Oauth2LoginRequest** | Pointer to [**LoginRequest**](LoginRequest.md) | | [optional] **RequestUrl** | **string** | RequestURL is the initial URL that was requested from Ory Kratos. It can be used to forward information contained in the URL's path or query for example. | **ReturnTo** | Pointer to **string** | ReturnTo contains the requested return_to URL. | [optional] **Type** | **string** | The flow type can either be `api` or `browser`. | @@ -117,6 +119,66 @@ and a boolean to check if the value has been set. SetIssuedAt sets IssuedAt field to given value. +### GetOauth2LoginChallenge + +`func (o *SelfServiceRegistrationFlow) GetOauth2LoginChallenge() string` + +GetOauth2LoginChallenge returns the Oauth2LoginChallenge field if non-nil, zero value otherwise. + +### GetOauth2LoginChallengeOk + +`func (o *SelfServiceRegistrationFlow) GetOauth2LoginChallengeOk() (*string, bool)` + +GetOauth2LoginChallengeOk returns a tuple with the Oauth2LoginChallenge field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetOauth2LoginChallenge + +`func (o *SelfServiceRegistrationFlow) SetOauth2LoginChallenge(v string)` + +SetOauth2LoginChallenge sets Oauth2LoginChallenge field to given value. + +### HasOauth2LoginChallenge + +`func (o *SelfServiceRegistrationFlow) HasOauth2LoginChallenge() bool` + +HasOauth2LoginChallenge returns a boolean if a field has been set. + +### SetOauth2LoginChallengeNil + +`func (o *SelfServiceRegistrationFlow) SetOauth2LoginChallengeNil(b bool)` + + SetOauth2LoginChallengeNil sets the value for Oauth2LoginChallenge to be an explicit nil + +### UnsetOauth2LoginChallenge +`func (o *SelfServiceRegistrationFlow) UnsetOauth2LoginChallenge()` + +UnsetOauth2LoginChallenge ensures that no value is present for Oauth2LoginChallenge, not even an explicit nil +### GetOauth2LoginRequest + +`func (o *SelfServiceRegistrationFlow) GetOauth2LoginRequest() LoginRequest` + +GetOauth2LoginRequest returns the Oauth2LoginRequest field if non-nil, zero value otherwise. + +### GetOauth2LoginRequestOk + +`func (o *SelfServiceRegistrationFlow) GetOauth2LoginRequestOk() (*LoginRequest, bool)` + +GetOauth2LoginRequestOk returns a tuple with the Oauth2LoginRequest field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetOauth2LoginRequest + +`func (o *SelfServiceRegistrationFlow) SetOauth2LoginRequest(v LoginRequest)` + +SetOauth2LoginRequest sets Oauth2LoginRequest field to given value. + +### HasOauth2LoginRequest + +`func (o *SelfServiceRegistrationFlow) HasOauth2LoginRequest() bool` + +HasOauth2LoginRequest returns a boolean if a field has been set. + ### GetRequestUrl `func (o *SelfServiceRegistrationFlow) GetRequestUrl() string` diff --git a/internal/httpclient/docs/V0alpha2Api.md b/internal/httpclient/docs/V0alpha2Api.md index a9146b4f6ff..4cc994fd84c 100644 --- a/internal/httpclient/docs/V0alpha2Api.md +++ b/internal/httpclient/docs/V0alpha2Api.md @@ -1493,7 +1493,7 @@ No authorization required ## InitializeSelfServiceLoginFlowForBrowsers -> SelfServiceLoginFlow InitializeSelfServiceLoginFlowForBrowsers(ctx).Refresh(refresh).Aal(aal).ReturnTo(returnTo).Cookie(cookie).Execute() +> SelfServiceLoginFlow InitializeSelfServiceLoginFlowForBrowsers(ctx).LoginChallenge(loginChallenge).Refresh(refresh).Aal(aal).ReturnTo(returnTo).Cookie(cookie).Execute() Initialize Login Flow for Browsers @@ -1512,6 +1512,7 @@ import ( ) func main() { + loginChallenge := "loginChallenge_example" // string | An optional Hydra login challenge. If present, Kratos will cooperate with Ory Hydra to act as an OAuth2 identity provider. The value for this parameter comes from `login_challenge` URL Query parameter sent to your application (e.g. `/login?login_challenge=abcde`). (optional) refresh := true // bool | Refresh a login session If set to true, this will refresh an existing login session by asking the user to sign in again. This will reset the authenticated_at time of the session. (optional) aal := "aal_example" // string | Request a Specific AuthenticationMethod Assurance Level Use this parameter to upgrade an existing session's authenticator assurance level (AAL). This allows you to ask for multi-factor authentication. When an identity sign in using e.g. username+password, the AAL is 1. If you wish to \"upgrade\" the session's security by asking the user to perform TOTP / WebAuth/ ... you would set this to \"aal2\". (optional) returnTo := "returnTo_example" // string | The URL to return the browser to after the flow was completed. (optional) @@ -1519,7 +1520,7 @@ func main() { configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.V0alpha2Api.InitializeSelfServiceLoginFlowForBrowsers(context.Background()).Refresh(refresh).Aal(aal).ReturnTo(returnTo).Cookie(cookie).Execute() + resp, r, err := apiClient.V0alpha2Api.InitializeSelfServiceLoginFlowForBrowsers(context.Background()).LoginChallenge(loginChallenge).Refresh(refresh).Aal(aal).ReturnTo(returnTo).Cookie(cookie).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `V0alpha2Api.InitializeSelfServiceLoginFlowForBrowsers``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -1540,6 +1541,7 @@ Other parameters are passed through a pointer to a apiInitializeSelfServiceLogin Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- + **loginChallenge** | **string** | An optional Hydra login challenge. If present, Kratos will cooperate with Ory Hydra to act as an OAuth2 identity provider. The value for this parameter comes from `login_challenge` URL Query parameter sent to your application (e.g. `/login?login_challenge=abcde`). | **refresh** | **bool** | Refresh a login session If set to true, this will refresh an existing login session by asking the user to sign in again. This will reset the authenticated_at time of the session. | **aal** | **string** | Request a Specific AuthenticationMethod Assurance Level Use this parameter to upgrade an existing session's authenticator assurance level (AAL). This allows you to ask for multi-factor authentication. When an identity sign in using e.g. username+password, the AAL is 1. If you wish to \"upgrade\" the session's security by asking the user to perform TOTP / WebAuth/ ... you would set this to \"aal2\". | **returnTo** | **string** | The URL to return the browser to after the flow was completed. | @@ -1762,7 +1764,7 @@ No authorization required ## InitializeSelfServiceRegistrationFlowForBrowsers -> SelfServiceRegistrationFlow InitializeSelfServiceRegistrationFlowForBrowsers(ctx).ReturnTo(returnTo).Execute() +> SelfServiceRegistrationFlow InitializeSelfServiceRegistrationFlowForBrowsers(ctx).LoginChallenge(loginChallenge).ReturnTo(returnTo).Execute() Initialize Registration Flow for Browsers @@ -1781,11 +1783,12 @@ import ( ) func main() { + loginChallenge := "loginChallenge_example" // string | An optional Hydra login challenge. If present, Kratos will cooperate with Ory Hydra to act as an OAuth2 identity provider. The value for this parameter comes from `login_challenge` URL Query parameter sent to your application (e.g. `/registration?login_challenge=abcde`). (optional) returnTo := "returnTo_example" // string | The URL to return the browser to after the flow was completed. (optional) configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.V0alpha2Api.InitializeSelfServiceRegistrationFlowForBrowsers(context.Background()).ReturnTo(returnTo).Execute() + resp, r, err := apiClient.V0alpha2Api.InitializeSelfServiceRegistrationFlowForBrowsers(context.Background()).LoginChallenge(loginChallenge).ReturnTo(returnTo).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `V0alpha2Api.InitializeSelfServiceRegistrationFlowForBrowsers``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -1806,6 +1809,7 @@ Other parameters are passed through a pointer to a apiInitializeSelfServiceRegis Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- + **loginChallenge** | **string** | An optional Hydra login challenge. If present, Kratos will cooperate with Ory Hydra to act as an OAuth2 identity provider. The value for this parameter comes from `login_challenge` URL Query parameter sent to your application (e.g. `/registration?login_challenge=abcde`). | **returnTo** | **string** | The URL to return the browser to after the flow was completed. | ### Return type diff --git a/internal/httpclient/model_login_request.go b/internal/httpclient/model_login_request.go new file mode 100644 index 00000000000..5ac0ab85ec0 --- /dev/null +++ b/internal/httpclient/model_login_request.go @@ -0,0 +1,407 @@ +/* + * Ory Kratos API + * + * Documentation for all public and administrative Ory Kratos APIs. Public and administrative APIs are exposed on different ports. Public APIs can face the public internet without any protection while administrative APIs should never be exposed without prior authorization. To protect the administative API port you should use something like Nginx, Ory Oathkeeper, or any other technology capable of authorizing incoming requests. + * + * API version: 1.0.0 + * Contact: hi@ory.sh + */ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +import ( + "encoding/json" +) + +// LoginRequest LoginRequest struct for LoginRequest +type LoginRequest struct { + // ID is the identifier (\\\"login challenge\\\") of the login request. It is used to identify the session. + Challenge *string `json:"challenge,omitempty"` + Client *OAuth2Client `json:"client,omitempty"` + OidcContext *OpenIDConnectContext `json:"oidc_context,omitempty"` + // RequestURL is the original OAuth 2.0 Authorization URL requested by the OAuth 2.0 client. It is the URL which initiates the OAuth 2.0 Authorization Code or OAuth 2.0 Implicit flow. This URL is typically not needed, but might come in handy if you want to deal with additional request parameters. + RequestUrl *string `json:"request_url,omitempty"` + RequestedAccessTokenAudience []string `json:"requested_access_token_audience,omitempty"` + RequestedScope []string `json:"requested_scope,omitempty"` + // SessionID is the login session ID. If the user-agent reuses a login session (via cookie / remember flag) this ID will remain the same. If the user-agent did not have an existing authentication session (e.g. remember is false) this will be a new random value. This value is used as the \\\"sid\\\" parameter in the ID Token and in OIDC Front-/Back- channel logout. It's value can generally be used to associate consecutive login requests by a certain user. + SessionId *string `json:"session_id,omitempty"` + // Skip, if true, implies that the client has requested the same scopes from the same user previously. If true, you can skip asking the user to grant the requested scopes, and simply forward the user to the redirect URL. This feature allows you to update / set session information. + Skip *bool `json:"skip,omitempty"` + // Subject is the user ID of the end-user that authenticated. Now, that end user needs to grant or deny the scope requested by the OAuth 2.0 client. If this value is set and `skip` is true, you MUST include this subject type when accepting the login request, or the request will fail. + Subject *string `json:"subject,omitempty"` +} + +// NewLoginRequest instantiates a new LoginRequest object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewLoginRequest() *LoginRequest { + this := LoginRequest{} + return &this +} + +// NewLoginRequestWithDefaults instantiates a new LoginRequest object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewLoginRequestWithDefaults() *LoginRequest { + this := LoginRequest{} + return &this +} + +// GetChallenge returns the Challenge field value if set, zero value otherwise. +func (o *LoginRequest) GetChallenge() string { + if o == nil || o.Challenge == nil { + var ret string + return ret + } + return *o.Challenge +} + +// GetChallengeOk returns a tuple with the Challenge field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *LoginRequest) GetChallengeOk() (*string, bool) { + if o == nil || o.Challenge == nil { + return nil, false + } + return o.Challenge, true +} + +// HasChallenge returns a boolean if a field has been set. +func (o *LoginRequest) HasChallenge() bool { + if o != nil && o.Challenge != nil { + return true + } + + return false +} + +// SetChallenge gets a reference to the given string and assigns it to the Challenge field. +func (o *LoginRequest) SetChallenge(v string) { + o.Challenge = &v +} + +// GetClient returns the Client field value if set, zero value otherwise. +func (o *LoginRequest) GetClient() OAuth2Client { + if o == nil || o.Client == nil { + var ret OAuth2Client + return ret + } + return *o.Client +} + +// GetClientOk returns a tuple with the Client field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *LoginRequest) GetClientOk() (*OAuth2Client, bool) { + if o == nil || o.Client == nil { + return nil, false + } + return o.Client, true +} + +// HasClient returns a boolean if a field has been set. +func (o *LoginRequest) HasClient() bool { + if o != nil && o.Client != nil { + return true + } + + return false +} + +// SetClient gets a reference to the given OAuth2Client and assigns it to the Client field. +func (o *LoginRequest) SetClient(v OAuth2Client) { + o.Client = &v +} + +// GetOidcContext returns the OidcContext field value if set, zero value otherwise. +func (o *LoginRequest) GetOidcContext() OpenIDConnectContext { + if o == nil || o.OidcContext == nil { + var ret OpenIDConnectContext + return ret + } + return *o.OidcContext +} + +// GetOidcContextOk returns a tuple with the OidcContext field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *LoginRequest) GetOidcContextOk() (*OpenIDConnectContext, bool) { + if o == nil || o.OidcContext == nil { + return nil, false + } + return o.OidcContext, true +} + +// HasOidcContext returns a boolean if a field has been set. +func (o *LoginRequest) HasOidcContext() bool { + if o != nil && o.OidcContext != nil { + return true + } + + return false +} + +// SetOidcContext gets a reference to the given OpenIDConnectContext and assigns it to the OidcContext field. +func (o *LoginRequest) SetOidcContext(v OpenIDConnectContext) { + o.OidcContext = &v +} + +// GetRequestUrl returns the RequestUrl field value if set, zero value otherwise. +func (o *LoginRequest) GetRequestUrl() string { + if o == nil || o.RequestUrl == nil { + var ret string + return ret + } + return *o.RequestUrl +} + +// GetRequestUrlOk returns a tuple with the RequestUrl field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *LoginRequest) GetRequestUrlOk() (*string, bool) { + if o == nil || o.RequestUrl == nil { + return nil, false + } + return o.RequestUrl, true +} + +// HasRequestUrl returns a boolean if a field has been set. +func (o *LoginRequest) HasRequestUrl() bool { + if o != nil && o.RequestUrl != nil { + return true + } + + return false +} + +// SetRequestUrl gets a reference to the given string and assigns it to the RequestUrl field. +func (o *LoginRequest) SetRequestUrl(v string) { + o.RequestUrl = &v +} + +// GetRequestedAccessTokenAudience returns the RequestedAccessTokenAudience field value if set, zero value otherwise. +func (o *LoginRequest) GetRequestedAccessTokenAudience() []string { + if o == nil || o.RequestedAccessTokenAudience == nil { + var ret []string + return ret + } + return o.RequestedAccessTokenAudience +} + +// GetRequestedAccessTokenAudienceOk returns a tuple with the RequestedAccessTokenAudience field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *LoginRequest) GetRequestedAccessTokenAudienceOk() ([]string, bool) { + if o == nil || o.RequestedAccessTokenAudience == nil { + return nil, false + } + return o.RequestedAccessTokenAudience, true +} + +// HasRequestedAccessTokenAudience returns a boolean if a field has been set. +func (o *LoginRequest) HasRequestedAccessTokenAudience() bool { + if o != nil && o.RequestedAccessTokenAudience != nil { + return true + } + + return false +} + +// SetRequestedAccessTokenAudience gets a reference to the given []string and assigns it to the RequestedAccessTokenAudience field. +func (o *LoginRequest) SetRequestedAccessTokenAudience(v []string) { + o.RequestedAccessTokenAudience = v +} + +// GetRequestedScope returns the RequestedScope field value if set, zero value otherwise. +func (o *LoginRequest) GetRequestedScope() []string { + if o == nil || o.RequestedScope == nil { + var ret []string + return ret + } + return o.RequestedScope +} + +// GetRequestedScopeOk returns a tuple with the RequestedScope field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *LoginRequest) GetRequestedScopeOk() ([]string, bool) { + if o == nil || o.RequestedScope == nil { + return nil, false + } + return o.RequestedScope, true +} + +// HasRequestedScope returns a boolean if a field has been set. +func (o *LoginRequest) HasRequestedScope() bool { + if o != nil && o.RequestedScope != nil { + return true + } + + return false +} + +// SetRequestedScope gets a reference to the given []string and assigns it to the RequestedScope field. +func (o *LoginRequest) SetRequestedScope(v []string) { + o.RequestedScope = v +} + +// GetSessionId returns the SessionId field value if set, zero value otherwise. +func (o *LoginRequest) GetSessionId() string { + if o == nil || o.SessionId == nil { + var ret string + return ret + } + return *o.SessionId +} + +// GetSessionIdOk returns a tuple with the SessionId field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *LoginRequest) GetSessionIdOk() (*string, bool) { + if o == nil || o.SessionId == nil { + return nil, false + } + return o.SessionId, true +} + +// HasSessionId returns a boolean if a field has been set. +func (o *LoginRequest) HasSessionId() bool { + if o != nil && o.SessionId != nil { + return true + } + + return false +} + +// SetSessionId gets a reference to the given string and assigns it to the SessionId field. +func (o *LoginRequest) SetSessionId(v string) { + o.SessionId = &v +} + +// GetSkip returns the Skip field value if set, zero value otherwise. +func (o *LoginRequest) GetSkip() bool { + if o == nil || o.Skip == nil { + var ret bool + return ret + } + return *o.Skip +} + +// GetSkipOk returns a tuple with the Skip field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *LoginRequest) GetSkipOk() (*bool, bool) { + if o == nil || o.Skip == nil { + return nil, false + } + return o.Skip, true +} + +// HasSkip returns a boolean if a field has been set. +func (o *LoginRequest) HasSkip() bool { + if o != nil && o.Skip != nil { + return true + } + + return false +} + +// SetSkip gets a reference to the given bool and assigns it to the Skip field. +func (o *LoginRequest) SetSkip(v bool) { + o.Skip = &v +} + +// GetSubject returns the Subject field value if set, zero value otherwise. +func (o *LoginRequest) GetSubject() string { + if o == nil || o.Subject == nil { + var ret string + return ret + } + return *o.Subject +} + +// GetSubjectOk returns a tuple with the Subject field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *LoginRequest) GetSubjectOk() (*string, bool) { + if o == nil || o.Subject == nil { + return nil, false + } + return o.Subject, true +} + +// HasSubject returns a boolean if a field has been set. +func (o *LoginRequest) HasSubject() bool { + if o != nil && o.Subject != nil { + return true + } + + return false +} + +// SetSubject gets a reference to the given string and assigns it to the Subject field. +func (o *LoginRequest) SetSubject(v string) { + o.Subject = &v +} + +func (o LoginRequest) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if o.Challenge != nil { + toSerialize["challenge"] = o.Challenge + } + if o.Client != nil { + toSerialize["client"] = o.Client + } + if o.OidcContext != nil { + toSerialize["oidc_context"] = o.OidcContext + } + if o.RequestUrl != nil { + toSerialize["request_url"] = o.RequestUrl + } + if o.RequestedAccessTokenAudience != nil { + toSerialize["requested_access_token_audience"] = o.RequestedAccessTokenAudience + } + if o.RequestedScope != nil { + toSerialize["requested_scope"] = o.RequestedScope + } + if o.SessionId != nil { + toSerialize["session_id"] = o.SessionId + } + if o.Skip != nil { + toSerialize["skip"] = o.Skip + } + if o.Subject != nil { + toSerialize["subject"] = o.Subject + } + return json.Marshal(toSerialize) +} + +type NullableLoginRequest struct { + value *LoginRequest + isSet bool +} + +func (v NullableLoginRequest) Get() *LoginRequest { + return v.value +} + +func (v *NullableLoginRequest) Set(val *LoginRequest) { + v.value = val + v.isSet = true +} + +func (v NullableLoginRequest) IsSet() bool { + return v.isSet +} + +func (v *NullableLoginRequest) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableLoginRequest(val *LoginRequest) *NullableLoginRequest { + return &NullableLoginRequest{value: val, isSet: true} +} + +func (v NullableLoginRequest) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableLoginRequest) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/httpclient/model_o_auth2_client.go b/internal/httpclient/model_o_auth2_client.go new file mode 100644 index 00000000000..6b7ec84ccb9 --- /dev/null +++ b/internal/httpclient/model_o_auth2_client.go @@ -0,0 +1,1364 @@ +/* + * Ory Kratos API + * + * Documentation for all public and administrative Ory Kratos APIs. Public and administrative APIs are exposed on different ports. Public APIs can face the public internet without any protection while administrative APIs should never be exposed without prior authorization. To protect the administative API port you should use something like Nginx, Ory Oathkeeper, or any other technology capable of authorizing incoming requests. + * + * API version: 1.0.0 + * Contact: hi@ory.sh + */ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +import ( + "encoding/json" + "time" +) + +// OAuth2Client OAuth2Client struct for OAuth2Client +type OAuth2Client struct { + AllowedCorsOrigins []string `json:"allowed_cors_origins,omitempty"` + Audience []string `json:"audience,omitempty"` + // Boolean value specifying whether the RP requires that a sid (session ID) Claim be included in the Logout Token to identify the RP session with the OP when the backchannel_logout_uri is used. If omitted, the default value is false. + BackchannelLogoutSessionRequired *bool `json:"backchannel_logout_session_required,omitempty"` + // RP URL that will cause the RP to log itself out when sent a Logout Token by the OP. + BackchannelLogoutUri *string `json:"backchannel_logout_uri,omitempty"` + // ID is the id for this client. + ClientId *string `json:"client_id,omitempty"` + // Name is the human-readable string name of the client to be presented to the end-user during authorization. + ClientName *string `json:"client_name,omitempty"` + // Secret is the client's secret. The secret will be included in the create request as cleartext, and then never again. The secret is stored using BCrypt so it is impossible to recover it. Tell your users that they need to write the secret down as it will not be made available again. + ClientSecret *string `json:"client_secret,omitempty"` + // SecretExpiresAt is an integer holding the time at which the client secret will expire or 0 if it will not expire. The time is represented as the number of seconds from 1970-01-01T00:00:00Z as measured in UTC until the date/time of expiration. This feature is currently not supported and it's value will always be set to 0. + ClientSecretExpiresAt *int64 `json:"client_secret_expires_at,omitempty"` + // ClientURI is an URL string of a web page providing information about the client. If present, the server SHOULD display this URL to the end-user in a clickable fashion. + ClientUri *string `json:"client_uri,omitempty"` + Contacts []string `json:"contacts,omitempty"` + // CreatedAt returns the timestamp of the client's creation. + CreatedAt *time.Time `json:"created_at,omitempty"` + // Boolean value specifying whether the RP requires that iss (issuer) and sid (session ID) query parameters be included to identify the RP session with the OP when the frontchannel_logout_uri is used. If omitted, the default value is false. + FrontchannelLogoutSessionRequired *bool `json:"frontchannel_logout_session_required,omitempty"` + // RP URL that will cause the RP to log itself out when rendered in an iframe by the OP. An iss (issuer) query parameter and a sid (session ID) query parameter MAY be included by the OP to enable the RP to validate the request and to determine which of the potentially multiple sessions is to be logged out; if either is included, both MUST be. + FrontchannelLogoutUri *string `json:"frontchannel_logout_uri,omitempty"` + GrantTypes []string `json:"grant_types,omitempty"` + Jwks map[string]interface{} `json:"jwks,omitempty"` + // URL for the Client's JSON Web Key Set [JWK] document. If the Client signs requests to the Server, it contains the signing key(s) the Server uses to validate signatures from the Client. The JWK Set MAY also contain the Client's encryption keys(s), which are used by the Server to encrypt responses to the Client. When both signing and encryption keys are made available, a use (Key Use) parameter value is REQUIRED for all keys in the referenced JWK Set to indicate each key's intended usage. Although some algorithms allow the same key to be used for both signatures and encryption, doing so is NOT RECOMMENDED, as it is less secure. The JWK x5c parameter MAY be used to provide X.509 representations of keys provided. When used, the bare key values MUST still be present and MUST match those in the certificate. + JwksUri *string `json:"jwks_uri,omitempty"` + // LogoURI is an URL string that references a logo for the client. + LogoUri *string `json:"logo_uri,omitempty"` + Metadata map[string]interface{} `json:"metadata,omitempty"` + // Owner is a string identifying the owner of the OAuth 2.0 Client. + Owner *string `json:"owner,omitempty"` + // PolicyURI is a URL string that points to a human-readable privacy policy document that describes how the deployment organization collects, uses, retains, and discloses personal data. + PolicyUri *string `json:"policy_uri,omitempty"` + PostLogoutRedirectUris []string `json:"post_logout_redirect_uris,omitempty"` + RedirectUris []string `json:"redirect_uris,omitempty"` + // RegistrationAccessToken can be used to update, get, or delete the OAuth2 Client. + RegistrationAccessToken *string `json:"registration_access_token,omitempty"` + // RegistrationClientURI is the URL used to update, get, or delete the OAuth2 Client. + RegistrationClientUri *string `json:"registration_client_uri,omitempty"` + // JWS [JWS] alg algorithm [JWA] that MUST be used for signing Request Objects sent to the OP. All Request Objects from this Client MUST be rejected, if not signed with this algorithm. + RequestObjectSigningAlg *string `json:"request_object_signing_alg,omitempty"` + RequestUris []string `json:"request_uris,omitempty"` + ResponseTypes []string `json:"response_types,omitempty"` + // Scope is a string containing a space-separated list of scope values (as described in Section 3.3 of OAuth 2.0 [RFC6749]) that the client can use when requesting access tokens. + Scope *string `json:"scope,omitempty"` + // URL using the https scheme to be used in calculating Pseudonymous Identifiers by the OP. The URL references a file with a single JSON array of redirect_uri values. + SectorIdentifierUri *string `json:"sector_identifier_uri,omitempty"` + // SubjectType requested for responses to this Client. The subject_types_supported Discovery parameter contains a list of the supported subject_type values for this server. Valid types include `pairwise` and `public`. + SubjectType *string `json:"subject_type,omitempty"` + // Requested Client Authentication method for the Token Endpoint. The options are client_secret_post, client_secret_basic, private_key_jwt, and none. + TokenEndpointAuthMethod *string `json:"token_endpoint_auth_method,omitempty"` + // Requested Client Authentication signing algorithm for the Token Endpoint. + TokenEndpointAuthSigningAlg *string `json:"token_endpoint_auth_signing_alg,omitempty"` + // TermsOfServiceURI is a URL string that points to a human-readable terms of service document for the client that describes a contractual relationship between the end-user and the client that the end-user accepts when authorizing the client. + TosUri *string `json:"tos_uri,omitempty"` + // UpdatedAt returns the timestamp of the last update. + UpdatedAt *time.Time `json:"updated_at,omitempty"` + // JWS alg algorithm [JWA] REQUIRED for signing UserInfo Responses. If this is specified, the response will be JWT [JWT] serialized, and signed using JWS. The default, if omitted, is for the UserInfo Response to return the Claims as a UTF-8 encoded JSON object using the application/json content-type. + UserinfoSignedResponseAlg *string `json:"userinfo_signed_response_alg,omitempty"` +} + +// NewOAuth2Client instantiates a new OAuth2Client object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewOAuth2Client() *OAuth2Client { + this := OAuth2Client{} + return &this +} + +// NewOAuth2ClientWithDefaults instantiates a new OAuth2Client object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewOAuth2ClientWithDefaults() *OAuth2Client { + this := OAuth2Client{} + return &this +} + +// GetAllowedCorsOrigins returns the AllowedCorsOrigins field value if set, zero value otherwise. +func (o *OAuth2Client) GetAllowedCorsOrigins() []string { + if o == nil || o.AllowedCorsOrigins == nil { + var ret []string + return ret + } + return o.AllowedCorsOrigins +} + +// GetAllowedCorsOriginsOk returns a tuple with the AllowedCorsOrigins field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetAllowedCorsOriginsOk() ([]string, bool) { + if o == nil || o.AllowedCorsOrigins == nil { + return nil, false + } + return o.AllowedCorsOrigins, true +} + +// HasAllowedCorsOrigins returns a boolean if a field has been set. +func (o *OAuth2Client) HasAllowedCorsOrigins() bool { + if o != nil && o.AllowedCorsOrigins != nil { + return true + } + + return false +} + +// SetAllowedCorsOrigins gets a reference to the given []string and assigns it to the AllowedCorsOrigins field. +func (o *OAuth2Client) SetAllowedCorsOrigins(v []string) { + o.AllowedCorsOrigins = v +} + +// GetAudience returns the Audience field value if set, zero value otherwise. +func (o *OAuth2Client) GetAudience() []string { + if o == nil || o.Audience == nil { + var ret []string + return ret + } + return o.Audience +} + +// GetAudienceOk returns a tuple with the Audience field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetAudienceOk() ([]string, bool) { + if o == nil || o.Audience == nil { + return nil, false + } + return o.Audience, true +} + +// HasAudience returns a boolean if a field has been set. +func (o *OAuth2Client) HasAudience() bool { + if o != nil && o.Audience != nil { + return true + } + + return false +} + +// SetAudience gets a reference to the given []string and assigns it to the Audience field. +func (o *OAuth2Client) SetAudience(v []string) { + o.Audience = v +} + +// GetBackchannelLogoutSessionRequired returns the BackchannelLogoutSessionRequired field value if set, zero value otherwise. +func (o *OAuth2Client) GetBackchannelLogoutSessionRequired() bool { + if o == nil || o.BackchannelLogoutSessionRequired == nil { + var ret bool + return ret + } + return *o.BackchannelLogoutSessionRequired +} + +// GetBackchannelLogoutSessionRequiredOk returns a tuple with the BackchannelLogoutSessionRequired field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetBackchannelLogoutSessionRequiredOk() (*bool, bool) { + if o == nil || o.BackchannelLogoutSessionRequired == nil { + return nil, false + } + return o.BackchannelLogoutSessionRequired, true +} + +// HasBackchannelLogoutSessionRequired returns a boolean if a field has been set. +func (o *OAuth2Client) HasBackchannelLogoutSessionRequired() bool { + if o != nil && o.BackchannelLogoutSessionRequired != nil { + return true + } + + return false +} + +// SetBackchannelLogoutSessionRequired gets a reference to the given bool and assigns it to the BackchannelLogoutSessionRequired field. +func (o *OAuth2Client) SetBackchannelLogoutSessionRequired(v bool) { + o.BackchannelLogoutSessionRequired = &v +} + +// GetBackchannelLogoutUri returns the BackchannelLogoutUri field value if set, zero value otherwise. +func (o *OAuth2Client) GetBackchannelLogoutUri() string { + if o == nil || o.BackchannelLogoutUri == nil { + var ret string + return ret + } + return *o.BackchannelLogoutUri +} + +// GetBackchannelLogoutUriOk returns a tuple with the BackchannelLogoutUri field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetBackchannelLogoutUriOk() (*string, bool) { + if o == nil || o.BackchannelLogoutUri == nil { + return nil, false + } + return o.BackchannelLogoutUri, true +} + +// HasBackchannelLogoutUri returns a boolean if a field has been set. +func (o *OAuth2Client) HasBackchannelLogoutUri() bool { + if o != nil && o.BackchannelLogoutUri != nil { + return true + } + + return false +} + +// SetBackchannelLogoutUri gets a reference to the given string and assigns it to the BackchannelLogoutUri field. +func (o *OAuth2Client) SetBackchannelLogoutUri(v string) { + o.BackchannelLogoutUri = &v +} + +// GetClientId returns the ClientId field value if set, zero value otherwise. +func (o *OAuth2Client) GetClientId() string { + if o == nil || o.ClientId == nil { + var ret string + return ret + } + return *o.ClientId +} + +// GetClientIdOk returns a tuple with the ClientId field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetClientIdOk() (*string, bool) { + if o == nil || o.ClientId == nil { + return nil, false + } + return o.ClientId, true +} + +// HasClientId returns a boolean if a field has been set. +func (o *OAuth2Client) HasClientId() bool { + if o != nil && o.ClientId != nil { + return true + } + + return false +} + +// SetClientId gets a reference to the given string and assigns it to the ClientId field. +func (o *OAuth2Client) SetClientId(v string) { + o.ClientId = &v +} + +// GetClientName returns the ClientName field value if set, zero value otherwise. +func (o *OAuth2Client) GetClientName() string { + if o == nil || o.ClientName == nil { + var ret string + return ret + } + return *o.ClientName +} + +// GetClientNameOk returns a tuple with the ClientName field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetClientNameOk() (*string, bool) { + if o == nil || o.ClientName == nil { + return nil, false + } + return o.ClientName, true +} + +// HasClientName returns a boolean if a field has been set. +func (o *OAuth2Client) HasClientName() bool { + if o != nil && o.ClientName != nil { + return true + } + + return false +} + +// SetClientName gets a reference to the given string and assigns it to the ClientName field. +func (o *OAuth2Client) SetClientName(v string) { + o.ClientName = &v +} + +// GetClientSecret returns the ClientSecret field value if set, zero value otherwise. +func (o *OAuth2Client) GetClientSecret() string { + if o == nil || o.ClientSecret == nil { + var ret string + return ret + } + return *o.ClientSecret +} + +// GetClientSecretOk returns a tuple with the ClientSecret field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetClientSecretOk() (*string, bool) { + if o == nil || o.ClientSecret == nil { + return nil, false + } + return o.ClientSecret, true +} + +// HasClientSecret returns a boolean if a field has been set. +func (o *OAuth2Client) HasClientSecret() bool { + if o != nil && o.ClientSecret != nil { + return true + } + + return false +} + +// SetClientSecret gets a reference to the given string and assigns it to the ClientSecret field. +func (o *OAuth2Client) SetClientSecret(v string) { + o.ClientSecret = &v +} + +// GetClientSecretExpiresAt returns the ClientSecretExpiresAt field value if set, zero value otherwise. +func (o *OAuth2Client) GetClientSecretExpiresAt() int64 { + if o == nil || o.ClientSecretExpiresAt == nil { + var ret int64 + return ret + } + return *o.ClientSecretExpiresAt +} + +// GetClientSecretExpiresAtOk returns a tuple with the ClientSecretExpiresAt field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetClientSecretExpiresAtOk() (*int64, bool) { + if o == nil || o.ClientSecretExpiresAt == nil { + return nil, false + } + return o.ClientSecretExpiresAt, true +} + +// HasClientSecretExpiresAt returns a boolean if a field has been set. +func (o *OAuth2Client) HasClientSecretExpiresAt() bool { + if o != nil && o.ClientSecretExpiresAt != nil { + return true + } + + return false +} + +// SetClientSecretExpiresAt gets a reference to the given int64 and assigns it to the ClientSecretExpiresAt field. +func (o *OAuth2Client) SetClientSecretExpiresAt(v int64) { + o.ClientSecretExpiresAt = &v +} + +// GetClientUri returns the ClientUri field value if set, zero value otherwise. +func (o *OAuth2Client) GetClientUri() string { + if o == nil || o.ClientUri == nil { + var ret string + return ret + } + return *o.ClientUri +} + +// GetClientUriOk returns a tuple with the ClientUri field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetClientUriOk() (*string, bool) { + if o == nil || o.ClientUri == nil { + return nil, false + } + return o.ClientUri, true +} + +// HasClientUri returns a boolean if a field has been set. +func (o *OAuth2Client) HasClientUri() bool { + if o != nil && o.ClientUri != nil { + return true + } + + return false +} + +// SetClientUri gets a reference to the given string and assigns it to the ClientUri field. +func (o *OAuth2Client) SetClientUri(v string) { + o.ClientUri = &v +} + +// GetContacts returns the Contacts field value if set, zero value otherwise. +func (o *OAuth2Client) GetContacts() []string { + if o == nil || o.Contacts == nil { + var ret []string + return ret + } + return o.Contacts +} + +// GetContactsOk returns a tuple with the Contacts field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetContactsOk() ([]string, bool) { + if o == nil || o.Contacts == nil { + return nil, false + } + return o.Contacts, true +} + +// HasContacts returns a boolean if a field has been set. +func (o *OAuth2Client) HasContacts() bool { + if o != nil && o.Contacts != nil { + return true + } + + return false +} + +// SetContacts gets a reference to the given []string and assigns it to the Contacts field. +func (o *OAuth2Client) SetContacts(v []string) { + o.Contacts = v +} + +// GetCreatedAt returns the CreatedAt field value if set, zero value otherwise. +func (o *OAuth2Client) GetCreatedAt() time.Time { + if o == nil || o.CreatedAt == nil { + var ret time.Time + return ret + } + return *o.CreatedAt +} + +// GetCreatedAtOk returns a tuple with the CreatedAt field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetCreatedAtOk() (*time.Time, bool) { + if o == nil || o.CreatedAt == nil { + return nil, false + } + return o.CreatedAt, true +} + +// HasCreatedAt returns a boolean if a field has been set. +func (o *OAuth2Client) HasCreatedAt() bool { + if o != nil && o.CreatedAt != nil { + return true + } + + return false +} + +// SetCreatedAt gets a reference to the given time.Time and assigns it to the CreatedAt field. +func (o *OAuth2Client) SetCreatedAt(v time.Time) { + o.CreatedAt = &v +} + +// GetFrontchannelLogoutSessionRequired returns the FrontchannelLogoutSessionRequired field value if set, zero value otherwise. +func (o *OAuth2Client) GetFrontchannelLogoutSessionRequired() bool { + if o == nil || o.FrontchannelLogoutSessionRequired == nil { + var ret bool + return ret + } + return *o.FrontchannelLogoutSessionRequired +} + +// GetFrontchannelLogoutSessionRequiredOk returns a tuple with the FrontchannelLogoutSessionRequired field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetFrontchannelLogoutSessionRequiredOk() (*bool, bool) { + if o == nil || o.FrontchannelLogoutSessionRequired == nil { + return nil, false + } + return o.FrontchannelLogoutSessionRequired, true +} + +// HasFrontchannelLogoutSessionRequired returns a boolean if a field has been set. +func (o *OAuth2Client) HasFrontchannelLogoutSessionRequired() bool { + if o != nil && o.FrontchannelLogoutSessionRequired != nil { + return true + } + + return false +} + +// SetFrontchannelLogoutSessionRequired gets a reference to the given bool and assigns it to the FrontchannelLogoutSessionRequired field. +func (o *OAuth2Client) SetFrontchannelLogoutSessionRequired(v bool) { + o.FrontchannelLogoutSessionRequired = &v +} + +// GetFrontchannelLogoutUri returns the FrontchannelLogoutUri field value if set, zero value otherwise. +func (o *OAuth2Client) GetFrontchannelLogoutUri() string { + if o == nil || o.FrontchannelLogoutUri == nil { + var ret string + return ret + } + return *o.FrontchannelLogoutUri +} + +// GetFrontchannelLogoutUriOk returns a tuple with the FrontchannelLogoutUri field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetFrontchannelLogoutUriOk() (*string, bool) { + if o == nil || o.FrontchannelLogoutUri == nil { + return nil, false + } + return o.FrontchannelLogoutUri, true +} + +// HasFrontchannelLogoutUri returns a boolean if a field has been set. +func (o *OAuth2Client) HasFrontchannelLogoutUri() bool { + if o != nil && o.FrontchannelLogoutUri != nil { + return true + } + + return false +} + +// SetFrontchannelLogoutUri gets a reference to the given string and assigns it to the FrontchannelLogoutUri field. +func (o *OAuth2Client) SetFrontchannelLogoutUri(v string) { + o.FrontchannelLogoutUri = &v +} + +// GetGrantTypes returns the GrantTypes field value if set, zero value otherwise. +func (o *OAuth2Client) GetGrantTypes() []string { + if o == nil || o.GrantTypes == nil { + var ret []string + return ret + } + return o.GrantTypes +} + +// GetGrantTypesOk returns a tuple with the GrantTypes field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetGrantTypesOk() ([]string, bool) { + if o == nil || o.GrantTypes == nil { + return nil, false + } + return o.GrantTypes, true +} + +// HasGrantTypes returns a boolean if a field has been set. +func (o *OAuth2Client) HasGrantTypes() bool { + if o != nil && o.GrantTypes != nil { + return true + } + + return false +} + +// SetGrantTypes gets a reference to the given []string and assigns it to the GrantTypes field. +func (o *OAuth2Client) SetGrantTypes(v []string) { + o.GrantTypes = v +} + +// GetJwks returns the Jwks field value if set, zero value otherwise. +func (o *OAuth2Client) GetJwks() map[string]interface{} { + if o == nil || o.Jwks == nil { + var ret map[string]interface{} + return ret + } + return o.Jwks +} + +// GetJwksOk returns a tuple with the Jwks field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetJwksOk() (map[string]interface{}, bool) { + if o == nil || o.Jwks == nil { + return nil, false + } + return o.Jwks, true +} + +// HasJwks returns a boolean if a field has been set. +func (o *OAuth2Client) HasJwks() bool { + if o != nil && o.Jwks != nil { + return true + } + + return false +} + +// SetJwks gets a reference to the given map[string]interface{} and assigns it to the Jwks field. +func (o *OAuth2Client) SetJwks(v map[string]interface{}) { + o.Jwks = v +} + +// GetJwksUri returns the JwksUri field value if set, zero value otherwise. +func (o *OAuth2Client) GetJwksUri() string { + if o == nil || o.JwksUri == nil { + var ret string + return ret + } + return *o.JwksUri +} + +// GetJwksUriOk returns a tuple with the JwksUri field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetJwksUriOk() (*string, bool) { + if o == nil || o.JwksUri == nil { + return nil, false + } + return o.JwksUri, true +} + +// HasJwksUri returns a boolean if a field has been set. +func (o *OAuth2Client) HasJwksUri() bool { + if o != nil && o.JwksUri != nil { + return true + } + + return false +} + +// SetJwksUri gets a reference to the given string and assigns it to the JwksUri field. +func (o *OAuth2Client) SetJwksUri(v string) { + o.JwksUri = &v +} + +// GetLogoUri returns the LogoUri field value if set, zero value otherwise. +func (o *OAuth2Client) GetLogoUri() string { + if o == nil || o.LogoUri == nil { + var ret string + return ret + } + return *o.LogoUri +} + +// GetLogoUriOk returns a tuple with the LogoUri field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetLogoUriOk() (*string, bool) { + if o == nil || o.LogoUri == nil { + return nil, false + } + return o.LogoUri, true +} + +// HasLogoUri returns a boolean if a field has been set. +func (o *OAuth2Client) HasLogoUri() bool { + if o != nil && o.LogoUri != nil { + return true + } + + return false +} + +// SetLogoUri gets a reference to the given string and assigns it to the LogoUri field. +func (o *OAuth2Client) SetLogoUri(v string) { + o.LogoUri = &v +} + +// GetMetadata returns the Metadata field value if set, zero value otherwise. +func (o *OAuth2Client) GetMetadata() map[string]interface{} { + if o == nil || o.Metadata == nil { + var ret map[string]interface{} + return ret + } + return o.Metadata +} + +// GetMetadataOk returns a tuple with the Metadata field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetMetadataOk() (map[string]interface{}, bool) { + if o == nil || o.Metadata == nil { + return nil, false + } + return o.Metadata, true +} + +// HasMetadata returns a boolean if a field has been set. +func (o *OAuth2Client) HasMetadata() bool { + if o != nil && o.Metadata != nil { + return true + } + + return false +} + +// SetMetadata gets a reference to the given map[string]interface{} and assigns it to the Metadata field. +func (o *OAuth2Client) SetMetadata(v map[string]interface{}) { + o.Metadata = v +} + +// GetOwner returns the Owner field value if set, zero value otherwise. +func (o *OAuth2Client) GetOwner() string { + if o == nil || o.Owner == nil { + var ret string + return ret + } + return *o.Owner +} + +// GetOwnerOk returns a tuple with the Owner field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetOwnerOk() (*string, bool) { + if o == nil || o.Owner == nil { + return nil, false + } + return o.Owner, true +} + +// HasOwner returns a boolean if a field has been set. +func (o *OAuth2Client) HasOwner() bool { + if o != nil && o.Owner != nil { + return true + } + + return false +} + +// SetOwner gets a reference to the given string and assigns it to the Owner field. +func (o *OAuth2Client) SetOwner(v string) { + o.Owner = &v +} + +// GetPolicyUri returns the PolicyUri field value if set, zero value otherwise. +func (o *OAuth2Client) GetPolicyUri() string { + if o == nil || o.PolicyUri == nil { + var ret string + return ret + } + return *o.PolicyUri +} + +// GetPolicyUriOk returns a tuple with the PolicyUri field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetPolicyUriOk() (*string, bool) { + if o == nil || o.PolicyUri == nil { + return nil, false + } + return o.PolicyUri, true +} + +// HasPolicyUri returns a boolean if a field has been set. +func (o *OAuth2Client) HasPolicyUri() bool { + if o != nil && o.PolicyUri != nil { + return true + } + + return false +} + +// SetPolicyUri gets a reference to the given string and assigns it to the PolicyUri field. +func (o *OAuth2Client) SetPolicyUri(v string) { + o.PolicyUri = &v +} + +// GetPostLogoutRedirectUris returns the PostLogoutRedirectUris field value if set, zero value otherwise. +func (o *OAuth2Client) GetPostLogoutRedirectUris() []string { + if o == nil || o.PostLogoutRedirectUris == nil { + var ret []string + return ret + } + return o.PostLogoutRedirectUris +} + +// GetPostLogoutRedirectUrisOk returns a tuple with the PostLogoutRedirectUris field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetPostLogoutRedirectUrisOk() ([]string, bool) { + if o == nil || o.PostLogoutRedirectUris == nil { + return nil, false + } + return o.PostLogoutRedirectUris, true +} + +// HasPostLogoutRedirectUris returns a boolean if a field has been set. +func (o *OAuth2Client) HasPostLogoutRedirectUris() bool { + if o != nil && o.PostLogoutRedirectUris != nil { + return true + } + + return false +} + +// SetPostLogoutRedirectUris gets a reference to the given []string and assigns it to the PostLogoutRedirectUris field. +func (o *OAuth2Client) SetPostLogoutRedirectUris(v []string) { + o.PostLogoutRedirectUris = v +} + +// GetRedirectUris returns the RedirectUris field value if set, zero value otherwise. +func (o *OAuth2Client) GetRedirectUris() []string { + if o == nil || o.RedirectUris == nil { + var ret []string + return ret + } + return o.RedirectUris +} + +// GetRedirectUrisOk returns a tuple with the RedirectUris field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetRedirectUrisOk() ([]string, bool) { + if o == nil || o.RedirectUris == nil { + return nil, false + } + return o.RedirectUris, true +} + +// HasRedirectUris returns a boolean if a field has been set. +func (o *OAuth2Client) HasRedirectUris() bool { + if o != nil && o.RedirectUris != nil { + return true + } + + return false +} + +// SetRedirectUris gets a reference to the given []string and assigns it to the RedirectUris field. +func (o *OAuth2Client) SetRedirectUris(v []string) { + o.RedirectUris = v +} + +// GetRegistrationAccessToken returns the RegistrationAccessToken field value if set, zero value otherwise. +func (o *OAuth2Client) GetRegistrationAccessToken() string { + if o == nil || o.RegistrationAccessToken == nil { + var ret string + return ret + } + return *o.RegistrationAccessToken +} + +// GetRegistrationAccessTokenOk returns a tuple with the RegistrationAccessToken field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetRegistrationAccessTokenOk() (*string, bool) { + if o == nil || o.RegistrationAccessToken == nil { + return nil, false + } + return o.RegistrationAccessToken, true +} + +// HasRegistrationAccessToken returns a boolean if a field has been set. +func (o *OAuth2Client) HasRegistrationAccessToken() bool { + if o != nil && o.RegistrationAccessToken != nil { + return true + } + + return false +} + +// SetRegistrationAccessToken gets a reference to the given string and assigns it to the RegistrationAccessToken field. +func (o *OAuth2Client) SetRegistrationAccessToken(v string) { + o.RegistrationAccessToken = &v +} + +// GetRegistrationClientUri returns the RegistrationClientUri field value if set, zero value otherwise. +func (o *OAuth2Client) GetRegistrationClientUri() string { + if o == nil || o.RegistrationClientUri == nil { + var ret string + return ret + } + return *o.RegistrationClientUri +} + +// GetRegistrationClientUriOk returns a tuple with the RegistrationClientUri field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetRegistrationClientUriOk() (*string, bool) { + if o == nil || o.RegistrationClientUri == nil { + return nil, false + } + return o.RegistrationClientUri, true +} + +// HasRegistrationClientUri returns a boolean if a field has been set. +func (o *OAuth2Client) HasRegistrationClientUri() bool { + if o != nil && o.RegistrationClientUri != nil { + return true + } + + return false +} + +// SetRegistrationClientUri gets a reference to the given string and assigns it to the RegistrationClientUri field. +func (o *OAuth2Client) SetRegistrationClientUri(v string) { + o.RegistrationClientUri = &v +} + +// GetRequestObjectSigningAlg returns the RequestObjectSigningAlg field value if set, zero value otherwise. +func (o *OAuth2Client) GetRequestObjectSigningAlg() string { + if o == nil || o.RequestObjectSigningAlg == nil { + var ret string + return ret + } + return *o.RequestObjectSigningAlg +} + +// GetRequestObjectSigningAlgOk returns a tuple with the RequestObjectSigningAlg field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetRequestObjectSigningAlgOk() (*string, bool) { + if o == nil || o.RequestObjectSigningAlg == nil { + return nil, false + } + return o.RequestObjectSigningAlg, true +} + +// HasRequestObjectSigningAlg returns a boolean if a field has been set. +func (o *OAuth2Client) HasRequestObjectSigningAlg() bool { + if o != nil && o.RequestObjectSigningAlg != nil { + return true + } + + return false +} + +// SetRequestObjectSigningAlg gets a reference to the given string and assigns it to the RequestObjectSigningAlg field. +func (o *OAuth2Client) SetRequestObjectSigningAlg(v string) { + o.RequestObjectSigningAlg = &v +} + +// GetRequestUris returns the RequestUris field value if set, zero value otherwise. +func (o *OAuth2Client) GetRequestUris() []string { + if o == nil || o.RequestUris == nil { + var ret []string + return ret + } + return o.RequestUris +} + +// GetRequestUrisOk returns a tuple with the RequestUris field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetRequestUrisOk() ([]string, bool) { + if o == nil || o.RequestUris == nil { + return nil, false + } + return o.RequestUris, true +} + +// HasRequestUris returns a boolean if a field has been set. +func (o *OAuth2Client) HasRequestUris() bool { + if o != nil && o.RequestUris != nil { + return true + } + + return false +} + +// SetRequestUris gets a reference to the given []string and assigns it to the RequestUris field. +func (o *OAuth2Client) SetRequestUris(v []string) { + o.RequestUris = v +} + +// GetResponseTypes returns the ResponseTypes field value if set, zero value otherwise. +func (o *OAuth2Client) GetResponseTypes() []string { + if o == nil || o.ResponseTypes == nil { + var ret []string + return ret + } + return o.ResponseTypes +} + +// GetResponseTypesOk returns a tuple with the ResponseTypes field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetResponseTypesOk() ([]string, bool) { + if o == nil || o.ResponseTypes == nil { + return nil, false + } + return o.ResponseTypes, true +} + +// HasResponseTypes returns a boolean if a field has been set. +func (o *OAuth2Client) HasResponseTypes() bool { + if o != nil && o.ResponseTypes != nil { + return true + } + + return false +} + +// SetResponseTypes gets a reference to the given []string and assigns it to the ResponseTypes field. +func (o *OAuth2Client) SetResponseTypes(v []string) { + o.ResponseTypes = v +} + +// GetScope returns the Scope field value if set, zero value otherwise. +func (o *OAuth2Client) GetScope() string { + if o == nil || o.Scope == nil { + var ret string + return ret + } + return *o.Scope +} + +// GetScopeOk returns a tuple with the Scope field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetScopeOk() (*string, bool) { + if o == nil || o.Scope == nil { + return nil, false + } + return o.Scope, true +} + +// HasScope returns a boolean if a field has been set. +func (o *OAuth2Client) HasScope() bool { + if o != nil && o.Scope != nil { + return true + } + + return false +} + +// SetScope gets a reference to the given string and assigns it to the Scope field. +func (o *OAuth2Client) SetScope(v string) { + o.Scope = &v +} + +// GetSectorIdentifierUri returns the SectorIdentifierUri field value if set, zero value otherwise. +func (o *OAuth2Client) GetSectorIdentifierUri() string { + if o == nil || o.SectorIdentifierUri == nil { + var ret string + return ret + } + return *o.SectorIdentifierUri +} + +// GetSectorIdentifierUriOk returns a tuple with the SectorIdentifierUri field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetSectorIdentifierUriOk() (*string, bool) { + if o == nil || o.SectorIdentifierUri == nil { + return nil, false + } + return o.SectorIdentifierUri, true +} + +// HasSectorIdentifierUri returns a boolean if a field has been set. +func (o *OAuth2Client) HasSectorIdentifierUri() bool { + if o != nil && o.SectorIdentifierUri != nil { + return true + } + + return false +} + +// SetSectorIdentifierUri gets a reference to the given string and assigns it to the SectorIdentifierUri field. +func (o *OAuth2Client) SetSectorIdentifierUri(v string) { + o.SectorIdentifierUri = &v +} + +// GetSubjectType returns the SubjectType field value if set, zero value otherwise. +func (o *OAuth2Client) GetSubjectType() string { + if o == nil || o.SubjectType == nil { + var ret string + return ret + } + return *o.SubjectType +} + +// GetSubjectTypeOk returns a tuple with the SubjectType field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetSubjectTypeOk() (*string, bool) { + if o == nil || o.SubjectType == nil { + return nil, false + } + return o.SubjectType, true +} + +// HasSubjectType returns a boolean if a field has been set. +func (o *OAuth2Client) HasSubjectType() bool { + if o != nil && o.SubjectType != nil { + return true + } + + return false +} + +// SetSubjectType gets a reference to the given string and assigns it to the SubjectType field. +func (o *OAuth2Client) SetSubjectType(v string) { + o.SubjectType = &v +} + +// GetTokenEndpointAuthMethod returns the TokenEndpointAuthMethod field value if set, zero value otherwise. +func (o *OAuth2Client) GetTokenEndpointAuthMethod() string { + if o == nil || o.TokenEndpointAuthMethod == nil { + var ret string + return ret + } + return *o.TokenEndpointAuthMethod +} + +// GetTokenEndpointAuthMethodOk returns a tuple with the TokenEndpointAuthMethod field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetTokenEndpointAuthMethodOk() (*string, bool) { + if o == nil || o.TokenEndpointAuthMethod == nil { + return nil, false + } + return o.TokenEndpointAuthMethod, true +} + +// HasTokenEndpointAuthMethod returns a boolean if a field has been set. +func (o *OAuth2Client) HasTokenEndpointAuthMethod() bool { + if o != nil && o.TokenEndpointAuthMethod != nil { + return true + } + + return false +} + +// SetTokenEndpointAuthMethod gets a reference to the given string and assigns it to the TokenEndpointAuthMethod field. +func (o *OAuth2Client) SetTokenEndpointAuthMethod(v string) { + o.TokenEndpointAuthMethod = &v +} + +// GetTokenEndpointAuthSigningAlg returns the TokenEndpointAuthSigningAlg field value if set, zero value otherwise. +func (o *OAuth2Client) GetTokenEndpointAuthSigningAlg() string { + if o == nil || o.TokenEndpointAuthSigningAlg == nil { + var ret string + return ret + } + return *o.TokenEndpointAuthSigningAlg +} + +// GetTokenEndpointAuthSigningAlgOk returns a tuple with the TokenEndpointAuthSigningAlg field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetTokenEndpointAuthSigningAlgOk() (*string, bool) { + if o == nil || o.TokenEndpointAuthSigningAlg == nil { + return nil, false + } + return o.TokenEndpointAuthSigningAlg, true +} + +// HasTokenEndpointAuthSigningAlg returns a boolean if a field has been set. +func (o *OAuth2Client) HasTokenEndpointAuthSigningAlg() bool { + if o != nil && o.TokenEndpointAuthSigningAlg != nil { + return true + } + + return false +} + +// SetTokenEndpointAuthSigningAlg gets a reference to the given string and assigns it to the TokenEndpointAuthSigningAlg field. +func (o *OAuth2Client) SetTokenEndpointAuthSigningAlg(v string) { + o.TokenEndpointAuthSigningAlg = &v +} + +// GetTosUri returns the TosUri field value if set, zero value otherwise. +func (o *OAuth2Client) GetTosUri() string { + if o == nil || o.TosUri == nil { + var ret string + return ret + } + return *o.TosUri +} + +// GetTosUriOk returns a tuple with the TosUri field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetTosUriOk() (*string, bool) { + if o == nil || o.TosUri == nil { + return nil, false + } + return o.TosUri, true +} + +// HasTosUri returns a boolean if a field has been set. +func (o *OAuth2Client) HasTosUri() bool { + if o != nil && o.TosUri != nil { + return true + } + + return false +} + +// SetTosUri gets a reference to the given string and assigns it to the TosUri field. +func (o *OAuth2Client) SetTosUri(v string) { + o.TosUri = &v +} + +// GetUpdatedAt returns the UpdatedAt field value if set, zero value otherwise. +func (o *OAuth2Client) GetUpdatedAt() time.Time { + if o == nil || o.UpdatedAt == nil { + var ret time.Time + return ret + } + return *o.UpdatedAt +} + +// GetUpdatedAtOk returns a tuple with the UpdatedAt field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetUpdatedAtOk() (*time.Time, bool) { + if o == nil || o.UpdatedAt == nil { + return nil, false + } + return o.UpdatedAt, true +} + +// HasUpdatedAt returns a boolean if a field has been set. +func (o *OAuth2Client) HasUpdatedAt() bool { + if o != nil && o.UpdatedAt != nil { + return true + } + + return false +} + +// SetUpdatedAt gets a reference to the given time.Time and assigns it to the UpdatedAt field. +func (o *OAuth2Client) SetUpdatedAt(v time.Time) { + o.UpdatedAt = &v +} + +// GetUserinfoSignedResponseAlg returns the UserinfoSignedResponseAlg field value if set, zero value otherwise. +func (o *OAuth2Client) GetUserinfoSignedResponseAlg() string { + if o == nil || o.UserinfoSignedResponseAlg == nil { + var ret string + return ret + } + return *o.UserinfoSignedResponseAlg +} + +// GetUserinfoSignedResponseAlgOk returns a tuple with the UserinfoSignedResponseAlg field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetUserinfoSignedResponseAlgOk() (*string, bool) { + if o == nil || o.UserinfoSignedResponseAlg == nil { + return nil, false + } + return o.UserinfoSignedResponseAlg, true +} + +// HasUserinfoSignedResponseAlg returns a boolean if a field has been set. +func (o *OAuth2Client) HasUserinfoSignedResponseAlg() bool { + if o != nil && o.UserinfoSignedResponseAlg != nil { + return true + } + + return false +} + +// SetUserinfoSignedResponseAlg gets a reference to the given string and assigns it to the UserinfoSignedResponseAlg field. +func (o *OAuth2Client) SetUserinfoSignedResponseAlg(v string) { + o.UserinfoSignedResponseAlg = &v +} + +func (o OAuth2Client) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if o.AllowedCorsOrigins != nil { + toSerialize["allowed_cors_origins"] = o.AllowedCorsOrigins + } + if o.Audience != nil { + toSerialize["audience"] = o.Audience + } + if o.BackchannelLogoutSessionRequired != nil { + toSerialize["backchannel_logout_session_required"] = o.BackchannelLogoutSessionRequired + } + if o.BackchannelLogoutUri != nil { + toSerialize["backchannel_logout_uri"] = o.BackchannelLogoutUri + } + if o.ClientId != nil { + toSerialize["client_id"] = o.ClientId + } + if o.ClientName != nil { + toSerialize["client_name"] = o.ClientName + } + if o.ClientSecret != nil { + toSerialize["client_secret"] = o.ClientSecret + } + if o.ClientSecretExpiresAt != nil { + toSerialize["client_secret_expires_at"] = o.ClientSecretExpiresAt + } + if o.ClientUri != nil { + toSerialize["client_uri"] = o.ClientUri + } + if o.Contacts != nil { + toSerialize["contacts"] = o.Contacts + } + if o.CreatedAt != nil { + toSerialize["created_at"] = o.CreatedAt + } + if o.FrontchannelLogoutSessionRequired != nil { + toSerialize["frontchannel_logout_session_required"] = o.FrontchannelLogoutSessionRequired + } + if o.FrontchannelLogoutUri != nil { + toSerialize["frontchannel_logout_uri"] = o.FrontchannelLogoutUri + } + if o.GrantTypes != nil { + toSerialize["grant_types"] = o.GrantTypes + } + if o.Jwks != nil { + toSerialize["jwks"] = o.Jwks + } + if o.JwksUri != nil { + toSerialize["jwks_uri"] = o.JwksUri + } + if o.LogoUri != nil { + toSerialize["logo_uri"] = o.LogoUri + } + if o.Metadata != nil { + toSerialize["metadata"] = o.Metadata + } + if o.Owner != nil { + toSerialize["owner"] = o.Owner + } + if o.PolicyUri != nil { + toSerialize["policy_uri"] = o.PolicyUri + } + if o.PostLogoutRedirectUris != nil { + toSerialize["post_logout_redirect_uris"] = o.PostLogoutRedirectUris + } + if o.RedirectUris != nil { + toSerialize["redirect_uris"] = o.RedirectUris + } + if o.RegistrationAccessToken != nil { + toSerialize["registration_access_token"] = o.RegistrationAccessToken + } + if o.RegistrationClientUri != nil { + toSerialize["registration_client_uri"] = o.RegistrationClientUri + } + if o.RequestObjectSigningAlg != nil { + toSerialize["request_object_signing_alg"] = o.RequestObjectSigningAlg + } + if o.RequestUris != nil { + toSerialize["request_uris"] = o.RequestUris + } + if o.ResponseTypes != nil { + toSerialize["response_types"] = o.ResponseTypes + } + if o.Scope != nil { + toSerialize["scope"] = o.Scope + } + if o.SectorIdentifierUri != nil { + toSerialize["sector_identifier_uri"] = o.SectorIdentifierUri + } + if o.SubjectType != nil { + toSerialize["subject_type"] = o.SubjectType + } + if o.TokenEndpointAuthMethod != nil { + toSerialize["token_endpoint_auth_method"] = o.TokenEndpointAuthMethod + } + if o.TokenEndpointAuthSigningAlg != nil { + toSerialize["token_endpoint_auth_signing_alg"] = o.TokenEndpointAuthSigningAlg + } + if o.TosUri != nil { + toSerialize["tos_uri"] = o.TosUri + } + if o.UpdatedAt != nil { + toSerialize["updated_at"] = o.UpdatedAt + } + if o.UserinfoSignedResponseAlg != nil { + toSerialize["userinfo_signed_response_alg"] = o.UserinfoSignedResponseAlg + } + return json.Marshal(toSerialize) +} + +type NullableOAuth2Client struct { + value *OAuth2Client + isSet bool +} + +func (v NullableOAuth2Client) Get() *OAuth2Client { + return v.value +} + +func (v *NullableOAuth2Client) Set(val *OAuth2Client) { + v.value = val + v.isSet = true +} + +func (v NullableOAuth2Client) IsSet() bool { + return v.isSet +} + +func (v *NullableOAuth2Client) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableOAuth2Client(val *OAuth2Client) *NullableOAuth2Client { + return &NullableOAuth2Client{value: val, isSet: true} +} + +func (v NullableOAuth2Client) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableOAuth2Client) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/httpclient/model_open_id_connect_context.go b/internal/httpclient/model_open_id_connect_context.go new file mode 100644 index 00000000000..7df9c7ddab9 --- /dev/null +++ b/internal/httpclient/model_open_id_connect_context.go @@ -0,0 +1,263 @@ +/* + * Ory Kratos API + * + * Documentation for all public and administrative Ory Kratos APIs. Public and administrative APIs are exposed on different ports. Public APIs can face the public internet without any protection while administrative APIs should never be exposed without prior authorization. To protect the administative API port you should use something like Nginx, Ory Oathkeeper, or any other technology capable of authorizing incoming requests. + * + * API version: 1.0.0 + * Contact: hi@ory.sh + */ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +import ( + "encoding/json" +) + +// OpenIDConnectContext OpenIDConnectContext struct for OpenIDConnectContext +type OpenIDConnectContext struct { + // ACRValues is the Authentication AuthorizationContext Class Reference requested in the OAuth 2.0 Authorization request. It is a parameter defined by OpenID Connect and expresses which level of authentication (e.g. 2FA) is required. OpenID Connect defines it as follows: > Requested Authentication AuthorizationContext Class Reference values. Space-separated string that specifies the acr values that the Authorization Server is being requested to use for processing this Authentication Request, with the values appearing in order of preference. The Authentication AuthorizationContext Class satisfied by the authentication performed is returned as the acr Claim Value, as specified in Section 2. The acr Claim is requested as a Voluntary Claim by this parameter. + AcrValues []string `json:"acr_values,omitempty"` + // Display is a string value that specifies how the Authorization Server displays the authentication and consent user interface pages to the End-User. The defined values are: page: The Authorization Server SHOULD display the authentication and consent UI consistent with a full User Agent page view. If the display parameter is not specified, this is the default display mode. popup: The Authorization Server SHOULD display the authentication and consent UI consistent with a popup User Agent window. The popup User Agent window should be of an appropriate size for a login-focused dialog and should not obscure the entire window that it is popping up over. touch: The Authorization Server SHOULD display the authentication and consent UI consistent with a device that leverages a touch interface. wap: The Authorization Server SHOULD display the authentication and consent UI consistent with a \\\"feature phone\\\" type display. The Authorization Server MAY also attempt to detect the capabilities of the User Agent and present an appropriate display. + Display *string `json:"display,omitempty"` + // IDTokenHintClaims are the claims of the ID Token previously issued by the Authorization Server being passed as a hint about the End-User's current or past authenticated session with the Client. + IdTokenHintClaims map[string]map[string]interface{} `json:"id_token_hint_claims,omitempty"` + // LoginHint hints about the login identifier the End-User might use to log in (if necessary). This hint can be used by an RP if it first asks the End-User for their e-mail address (or other identifier) and then wants to pass that value as a hint to the discovered authorization service. This value MAY also be a phone number in the format specified for the phone_number Claim. The use of this parameter is optional. + LoginHint *string `json:"login_hint,omitempty"` + // UILocales is the End-User'id preferred languages and scripts for the user interface, represented as a space-separated list of BCP47 [RFC5646] language tag values, ordered by preference. For instance, the value \\\"fr-CA fr en\\\" represents a preference for French as spoken in Canada, then French (without a region designation), followed by English (without a region designation). An error SHOULD NOT result if some or all of the requested locales are not supported by the OpenID Provider. + UiLocales []string `json:"ui_locales,omitempty"` +} + +// NewOpenIDConnectContext instantiates a new OpenIDConnectContext object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewOpenIDConnectContext() *OpenIDConnectContext { + this := OpenIDConnectContext{} + return &this +} + +// NewOpenIDConnectContextWithDefaults instantiates a new OpenIDConnectContext object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewOpenIDConnectContextWithDefaults() *OpenIDConnectContext { + this := OpenIDConnectContext{} + return &this +} + +// GetAcrValues returns the AcrValues field value if set, zero value otherwise. +func (o *OpenIDConnectContext) GetAcrValues() []string { + if o == nil || o.AcrValues == nil { + var ret []string + return ret + } + return o.AcrValues +} + +// GetAcrValuesOk returns a tuple with the AcrValues field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OpenIDConnectContext) GetAcrValuesOk() ([]string, bool) { + if o == nil || o.AcrValues == nil { + return nil, false + } + return o.AcrValues, true +} + +// HasAcrValues returns a boolean if a field has been set. +func (o *OpenIDConnectContext) HasAcrValues() bool { + if o != nil && o.AcrValues != nil { + return true + } + + return false +} + +// SetAcrValues gets a reference to the given []string and assigns it to the AcrValues field. +func (o *OpenIDConnectContext) SetAcrValues(v []string) { + o.AcrValues = v +} + +// GetDisplay returns the Display field value if set, zero value otherwise. +func (o *OpenIDConnectContext) GetDisplay() string { + if o == nil || o.Display == nil { + var ret string + return ret + } + return *o.Display +} + +// GetDisplayOk returns a tuple with the Display field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OpenIDConnectContext) GetDisplayOk() (*string, bool) { + if o == nil || o.Display == nil { + return nil, false + } + return o.Display, true +} + +// HasDisplay returns a boolean if a field has been set. +func (o *OpenIDConnectContext) HasDisplay() bool { + if o != nil && o.Display != nil { + return true + } + + return false +} + +// SetDisplay gets a reference to the given string and assigns it to the Display field. +func (o *OpenIDConnectContext) SetDisplay(v string) { + o.Display = &v +} + +// GetIdTokenHintClaims returns the IdTokenHintClaims field value if set, zero value otherwise. +func (o *OpenIDConnectContext) GetIdTokenHintClaims() map[string]map[string]interface{} { + if o == nil || o.IdTokenHintClaims == nil { + var ret map[string]map[string]interface{} + return ret + } + return o.IdTokenHintClaims +} + +// GetIdTokenHintClaimsOk returns a tuple with the IdTokenHintClaims field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OpenIDConnectContext) GetIdTokenHintClaimsOk() (map[string]map[string]interface{}, bool) { + if o == nil || o.IdTokenHintClaims == nil { + return nil, false + } + return o.IdTokenHintClaims, true +} + +// HasIdTokenHintClaims returns a boolean if a field has been set. +func (o *OpenIDConnectContext) HasIdTokenHintClaims() bool { + if o != nil && o.IdTokenHintClaims != nil { + return true + } + + return false +} + +// SetIdTokenHintClaims gets a reference to the given map[string]map[string]interface{} and assigns it to the IdTokenHintClaims field. +func (o *OpenIDConnectContext) SetIdTokenHintClaims(v map[string]map[string]interface{}) { + o.IdTokenHintClaims = v +} + +// GetLoginHint returns the LoginHint field value if set, zero value otherwise. +func (o *OpenIDConnectContext) GetLoginHint() string { + if o == nil || o.LoginHint == nil { + var ret string + return ret + } + return *o.LoginHint +} + +// GetLoginHintOk returns a tuple with the LoginHint field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OpenIDConnectContext) GetLoginHintOk() (*string, bool) { + if o == nil || o.LoginHint == nil { + return nil, false + } + return o.LoginHint, true +} + +// HasLoginHint returns a boolean if a field has been set. +func (o *OpenIDConnectContext) HasLoginHint() bool { + if o != nil && o.LoginHint != nil { + return true + } + + return false +} + +// SetLoginHint gets a reference to the given string and assigns it to the LoginHint field. +func (o *OpenIDConnectContext) SetLoginHint(v string) { + o.LoginHint = &v +} + +// GetUiLocales returns the UiLocales field value if set, zero value otherwise. +func (o *OpenIDConnectContext) GetUiLocales() []string { + if o == nil || o.UiLocales == nil { + var ret []string + return ret + } + return o.UiLocales +} + +// GetUiLocalesOk returns a tuple with the UiLocales field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OpenIDConnectContext) GetUiLocalesOk() ([]string, bool) { + if o == nil || o.UiLocales == nil { + return nil, false + } + return o.UiLocales, true +} + +// HasUiLocales returns a boolean if a field has been set. +func (o *OpenIDConnectContext) HasUiLocales() bool { + if o != nil && o.UiLocales != nil { + return true + } + + return false +} + +// SetUiLocales gets a reference to the given []string and assigns it to the UiLocales field. +func (o *OpenIDConnectContext) SetUiLocales(v []string) { + o.UiLocales = v +} + +func (o OpenIDConnectContext) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if o.AcrValues != nil { + toSerialize["acr_values"] = o.AcrValues + } + if o.Display != nil { + toSerialize["display"] = o.Display + } + if o.IdTokenHintClaims != nil { + toSerialize["id_token_hint_claims"] = o.IdTokenHintClaims + } + if o.LoginHint != nil { + toSerialize["login_hint"] = o.LoginHint + } + if o.UiLocales != nil { + toSerialize["ui_locales"] = o.UiLocales + } + return json.Marshal(toSerialize) +} + +type NullableOpenIDConnectContext struct { + value *OpenIDConnectContext + isSet bool +} + +func (v NullableOpenIDConnectContext) Get() *OpenIDConnectContext { + return v.value +} + +func (v *NullableOpenIDConnectContext) Set(val *OpenIDConnectContext) { + v.value = val + v.isSet = true +} + +func (v NullableOpenIDConnectContext) IsSet() bool { + return v.isSet +} + +func (v *NullableOpenIDConnectContext) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableOpenIDConnectContext(val *OpenIDConnectContext) *NullableOpenIDConnectContext { + return &NullableOpenIDConnectContext{value: val, isSet: true} +} + +func (v NullableOpenIDConnectContext) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableOpenIDConnectContext) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/httpclient/model_self_service_login_flow.go b/internal/httpclient/model_self_service_login_flow.go index dbdf326f690..e766a45c7c9 100644 --- a/internal/httpclient/model_self_service_login_flow.go +++ b/internal/httpclient/model_self_service_login_flow.go @@ -26,7 +26,9 @@ type SelfServiceLoginFlow struct { // ID represents the flow's unique ID. When performing the login flow, this represents the id in the login UI's query parameter: http:///?flow= Id string `json:"id"` // IssuedAt is the time (UTC) when the flow started. - IssuedAt time.Time `json:"issued_at"` + IssuedAt time.Time `json:"issued_at"` + Oauth2LoginChallenge NullableString `json:"oauth2_login_challenge,omitempty"` + Oauth2LoginRequest *LoginRequest `json:"oauth2_login_request,omitempty"` // Refresh stores whether this login flow should enforce re-authentication. Refresh *bool `json:"refresh,omitempty"` // RequestURL is the initial URL that was requested from Ory Kratos. It can be used to forward information contained in the URL's path or query for example. @@ -200,6 +202,81 @@ func (o *SelfServiceLoginFlow) SetIssuedAt(v time.Time) { o.IssuedAt = v } +// GetOauth2LoginChallenge returns the Oauth2LoginChallenge field value if set, zero value otherwise (both if not set or set to explicit null). +func (o *SelfServiceLoginFlow) GetOauth2LoginChallenge() string { + if o == nil || o.Oauth2LoginChallenge.Get() == nil { + var ret string + return ret + } + return *o.Oauth2LoginChallenge.Get() +} + +// GetOauth2LoginChallengeOk returns a tuple with the Oauth2LoginChallenge field value if set, nil otherwise +// and a boolean to check if the value has been set. +// NOTE: If the value is an explicit nil, `nil, true` will be returned +func (o *SelfServiceLoginFlow) GetOauth2LoginChallengeOk() (*string, bool) { + if o == nil { + return nil, false + } + return o.Oauth2LoginChallenge.Get(), o.Oauth2LoginChallenge.IsSet() +} + +// HasOauth2LoginChallenge returns a boolean if a field has been set. +func (o *SelfServiceLoginFlow) HasOauth2LoginChallenge() bool { + if o != nil && o.Oauth2LoginChallenge.IsSet() { + return true + } + + return false +} + +// SetOauth2LoginChallenge gets a reference to the given NullableString and assigns it to the Oauth2LoginChallenge field. +func (o *SelfServiceLoginFlow) SetOauth2LoginChallenge(v string) { + o.Oauth2LoginChallenge.Set(&v) +} + +// SetOauth2LoginChallengeNil sets the value for Oauth2LoginChallenge to be an explicit nil +func (o *SelfServiceLoginFlow) SetOauth2LoginChallengeNil() { + o.Oauth2LoginChallenge.Set(nil) +} + +// UnsetOauth2LoginChallenge ensures that no value is present for Oauth2LoginChallenge, not even an explicit nil +func (o *SelfServiceLoginFlow) UnsetOauth2LoginChallenge() { + o.Oauth2LoginChallenge.Unset() +} + +// GetOauth2LoginRequest returns the Oauth2LoginRequest field value if set, zero value otherwise. +func (o *SelfServiceLoginFlow) GetOauth2LoginRequest() LoginRequest { + if o == nil || o.Oauth2LoginRequest == nil { + var ret LoginRequest + return ret + } + return *o.Oauth2LoginRequest +} + +// GetOauth2LoginRequestOk returns a tuple with the Oauth2LoginRequest field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *SelfServiceLoginFlow) GetOauth2LoginRequestOk() (*LoginRequest, bool) { + if o == nil || o.Oauth2LoginRequest == nil { + return nil, false + } + return o.Oauth2LoginRequest, true +} + +// HasOauth2LoginRequest returns a boolean if a field has been set. +func (o *SelfServiceLoginFlow) HasOauth2LoginRequest() bool { + if o != nil && o.Oauth2LoginRequest != nil { + return true + } + + return false +} + +// SetOauth2LoginRequest gets a reference to the given LoginRequest and assigns it to the Oauth2LoginRequest field. +func (o *SelfServiceLoginFlow) SetOauth2LoginRequest(v LoginRequest) { + o.Oauth2LoginRequest = &v +} + // GetRefresh returns the Refresh field value if set, zero value otherwise. func (o *SelfServiceLoginFlow) GetRefresh() bool { if o == nil || o.Refresh == nil { @@ -417,6 +494,12 @@ func (o SelfServiceLoginFlow) MarshalJSON() ([]byte, error) { if true { toSerialize["issued_at"] = o.IssuedAt } + if o.Oauth2LoginChallenge.IsSet() { + toSerialize["oauth2_login_challenge"] = o.Oauth2LoginChallenge.Get() + } + if o.Oauth2LoginRequest != nil { + toSerialize["oauth2_login_request"] = o.Oauth2LoginRequest + } if o.Refresh != nil { toSerialize["refresh"] = o.Refresh } diff --git a/internal/httpclient/model_self_service_registration_flow.go b/internal/httpclient/model_self_service_registration_flow.go index ab11281c3d6..6ac174b259d 100644 --- a/internal/httpclient/model_self_service_registration_flow.go +++ b/internal/httpclient/model_self_service_registration_flow.go @@ -24,7 +24,9 @@ type SelfServiceRegistrationFlow struct { // ID represents the flow's unique ID. When performing the registration flow, this represents the id in the registration ui's query parameter: http:///?flow= Id string `json:"id"` // IssuedAt is the time (UTC) when the flow occurred. - IssuedAt time.Time `json:"issued_at"` + IssuedAt time.Time `json:"issued_at"` + Oauth2LoginChallenge NullableString `json:"oauth2_login_challenge,omitempty"` + Oauth2LoginRequest *LoginRequest `json:"oauth2_login_request,omitempty"` // RequestURL is the initial URL that was requested from Ory Kratos. It can be used to forward information contained in the URL's path or query for example. RequestUrl string `json:"request_url"` // ReturnTo contains the requested return_to URL. @@ -161,6 +163,81 @@ func (o *SelfServiceRegistrationFlow) SetIssuedAt(v time.Time) { o.IssuedAt = v } +// GetOauth2LoginChallenge returns the Oauth2LoginChallenge field value if set, zero value otherwise (both if not set or set to explicit null). +func (o *SelfServiceRegistrationFlow) GetOauth2LoginChallenge() string { + if o == nil || o.Oauth2LoginChallenge.Get() == nil { + var ret string + return ret + } + return *o.Oauth2LoginChallenge.Get() +} + +// GetOauth2LoginChallengeOk returns a tuple with the Oauth2LoginChallenge field value if set, nil otherwise +// and a boolean to check if the value has been set. +// NOTE: If the value is an explicit nil, `nil, true` will be returned +func (o *SelfServiceRegistrationFlow) GetOauth2LoginChallengeOk() (*string, bool) { + if o == nil { + return nil, false + } + return o.Oauth2LoginChallenge.Get(), o.Oauth2LoginChallenge.IsSet() +} + +// HasOauth2LoginChallenge returns a boolean if a field has been set. +func (o *SelfServiceRegistrationFlow) HasOauth2LoginChallenge() bool { + if o != nil && o.Oauth2LoginChallenge.IsSet() { + return true + } + + return false +} + +// SetOauth2LoginChallenge gets a reference to the given NullableString and assigns it to the Oauth2LoginChallenge field. +func (o *SelfServiceRegistrationFlow) SetOauth2LoginChallenge(v string) { + o.Oauth2LoginChallenge.Set(&v) +} + +// SetOauth2LoginChallengeNil sets the value for Oauth2LoginChallenge to be an explicit nil +func (o *SelfServiceRegistrationFlow) SetOauth2LoginChallengeNil() { + o.Oauth2LoginChallenge.Set(nil) +} + +// UnsetOauth2LoginChallenge ensures that no value is present for Oauth2LoginChallenge, not even an explicit nil +func (o *SelfServiceRegistrationFlow) UnsetOauth2LoginChallenge() { + o.Oauth2LoginChallenge.Unset() +} + +// GetOauth2LoginRequest returns the Oauth2LoginRequest field value if set, zero value otherwise. +func (o *SelfServiceRegistrationFlow) GetOauth2LoginRequest() LoginRequest { + if o == nil || o.Oauth2LoginRequest == nil { + var ret LoginRequest + return ret + } + return *o.Oauth2LoginRequest +} + +// GetOauth2LoginRequestOk returns a tuple with the Oauth2LoginRequest field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *SelfServiceRegistrationFlow) GetOauth2LoginRequestOk() (*LoginRequest, bool) { + if o == nil || o.Oauth2LoginRequest == nil { + return nil, false + } + return o.Oauth2LoginRequest, true +} + +// HasOauth2LoginRequest returns a boolean if a field has been set. +func (o *SelfServiceRegistrationFlow) HasOauth2LoginRequest() bool { + if o != nil && o.Oauth2LoginRequest != nil { + return true + } + + return false +} + +// SetOauth2LoginRequest gets a reference to the given LoginRequest and assigns it to the Oauth2LoginRequest field. +func (o *SelfServiceRegistrationFlow) SetOauth2LoginRequest(v LoginRequest) { + o.Oauth2LoginRequest = &v +} + // GetRequestUrl returns the RequestUrl field value func (o *SelfServiceRegistrationFlow) GetRequestUrl() string { if o == nil { @@ -279,6 +356,12 @@ func (o SelfServiceRegistrationFlow) MarshalJSON() ([]byte, error) { if true { toSerialize["issued_at"] = o.IssuedAt } + if o.Oauth2LoginChallenge.IsSet() { + toSerialize["oauth2_login_challenge"] = o.Oauth2LoginChallenge.Get() + } + if o.Oauth2LoginRequest != nil { + toSerialize["oauth2_login_request"] = o.Oauth2LoginRequest + } if true { toSerialize["request_url"] = o.RequestUrl } diff --git a/internal/registrationhelpers/helpers.go b/internal/registrationhelpers/helpers.go index c6e16d249f2..a5d284089d5 100644 --- a/internal/registrationhelpers/helpers.go +++ b/internal/registrationhelpers/helpers.go @@ -130,7 +130,7 @@ func AssertSchemDoesNotExist(t *testing.T, reg *driver.RegistryDefault, flows [] t.Run("type=spa", func(t *testing.T) { skipIfNotEnabled(t, flows, "spa") browserClient := testhelpers.NewClientWithCookies(t) - f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, true) + f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, true, false, false) testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/i-do-not-exist.schema.json") t.Cleanup(reset) @@ -142,7 +142,7 @@ func AssertSchemDoesNotExist(t *testing.T, reg *driver.RegistryDefault, flows [] t.Run("type=browser", func(t *testing.T) { skipIfNotEnabled(t, flows, "browser") browserClient := testhelpers.NewClientWithCookies(t) - f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, false) + f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, false, false, false) testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/i-do-not-exist.schema.json") t.Cleanup(reset) @@ -173,7 +173,7 @@ func AssertCSRFFailures(t *testing.T, reg *driver.RegistryDefault, flows []strin skipIfNotEnabled(t, flows, "browser") browserClient := testhelpers.NewClientWithCookies(t) - f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, false) + f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, false, false, false) actual, res := testhelpers.RegistrationMakeRequest(t, false, false, f, browserClient, values.Encode()) assert.EqualValues(t, http.StatusOK, res.StatusCode) @@ -185,7 +185,7 @@ func AssertCSRFFailures(t *testing.T, reg *driver.RegistryDefault, flows []strin skipIfNotEnabled(t, flows, "spa") browserClient := testhelpers.NewClientWithCookies(t) - f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, true) + f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, true, false, false) actual, res := testhelpers.RegistrationMakeRequest(t, false, true, f, browserClient, values.Encode()) assert.EqualValues(t, http.StatusForbidden, res.StatusCode) @@ -312,7 +312,7 @@ func AssertCommonErrorCases(t *testing.T, reg *driver.RegistryDefault, flows []s }) t.Run("type=spa", func(t *testing.T) { - f := testhelpers.InitializeRegistrationFlowViaBrowser(t, apiClient, publicTS, true) + f := testhelpers.InitializeRegistrationFlowViaBrowser(t, apiClient, publicTS, true, false, false) body, res := testhelpers.RegistrationMakeRequest(t, true, false, f, apiClient, "14=)=!(%)$/ZP()GHIÖ") assert.Contains(t, res.Request.URL.String(), publicTS.URL+registration.RouteSubmitFlow) assert.NotEmpty(t, gjson.Get(body, "id").String(), "%s", body) @@ -321,7 +321,7 @@ func AssertCommonErrorCases(t *testing.T, reg *driver.RegistryDefault, flows []s t.Run("type=browser", func(t *testing.T) { browserClient := testhelpers.NewClientWithCookies(t) - f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, false) + f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, false, false, false) body, res := testhelpers.RegistrationMakeRequest(t, false, false, f, browserClient, "14=)=!(%)$/ZP()GHIÖ") assert.Contains(t, res.Request.URL.String(), uiTS.URL+"/registration-ts") assert.NotEmpty(t, gjson.Get(body, "id").String(), "%s", body) @@ -361,7 +361,7 @@ func AssertCommonErrorCases(t *testing.T, reg *driver.RegistryDefault, flows []s }) t.Run("type=spa", func(t *testing.T) { - f := testhelpers.InitializeRegistrationFlowViaBrowser(t, apiClient, publicTS, true) + f := testhelpers.InitializeRegistrationFlowViaBrowser(t, apiClient, publicTS, true, false, false) body, res := testhelpers.RegistrationMakeRequest(t, true, false, f, apiClient, "14=)=!(%)$/ZP()GHIÖ") assert.Contains(t, res.Request.URL.String(), publicTS.URL+registration.RouteSubmitFlow) assert.NotEmpty(t, gjson.Get(body, "id").String(), "%s", body) @@ -370,7 +370,7 @@ func AssertCommonErrorCases(t *testing.T, reg *driver.RegistryDefault, flows []s t.Run("type=browser", func(t *testing.T) { browserClient := testhelpers.NewClientWithCookies(t) - f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, false) + f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, false, false, false) body, res := testhelpers.RegistrationMakeRequest(t, false, false, f, browserClient, "14=)=!(%)$/ZP()GHIÖ") assert.Contains(t, res.Request.URL.String(), uiTS.URL+"/registration-ts") assert.NotEmpty(t, gjson.Get(body, "id").String(), "%s", body) @@ -390,7 +390,7 @@ func AssertCommonErrorCases(t *testing.T, reg *driver.RegistryDefault, flows []s t.Run("type=spa", func(t *testing.T) { browserClient := testhelpers.NewClientWithCookies(t) - f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, true) + f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, true, false, false) body, res := testhelpers.RegistrationMakeRequest(t, false, true, f, browserClient, "{}}") assert.Contains(t, res.Request.URL.String(), publicTS.URL+registration.RouteSubmitFlow) assert.NotEmpty(t, gjson.Get(body, "id").String(), "%s", body) @@ -399,7 +399,7 @@ func AssertCommonErrorCases(t *testing.T, reg *driver.RegistryDefault, flows []s t.Run("type=browser", func(t *testing.T) { browserClient := testhelpers.NewClientWithCookies(t) - f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, false) + f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, false, false, false) body, res := testhelpers.RegistrationMakeRequest(t, false, false, f, browserClient, "foo=bar") assert.Contains(t, res.Request.URL.String(), uiTS.URL+"/registration-ts") assert.NotEmpty(t, gjson.Get(body, "id").String(), "%s", body) @@ -457,7 +457,7 @@ func AssertCommonErrorCases(t *testing.T, reg *driver.RegistryDefault, flows []s t.Run("type=spa", func(t *testing.T) { browserClient := testhelpers.NewClientWithCookies(t) - f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, true) + f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, true, false, false) time.Sleep(time.Millisecond * 600) actual, res := testhelpers.RegistrationMakeRequest(t, false, true, f, browserClient, "{}") @@ -468,7 +468,7 @@ func AssertCommonErrorCases(t *testing.T, reg *driver.RegistryDefault, flows []s t.Run("type=browser", func(t *testing.T) { browserClient := testhelpers.NewClientWithCookies(t) - f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, false) + f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, false, false, false) time.Sleep(time.Millisecond * 600) actual, res := testhelpers.RegistrationMakeRequest(t, false, false, f, browserClient, "") diff --git a/internal/testhelpers/http.go b/internal/testhelpers/http.go index 7e993fb0b14..6907fe0d7f0 100644 --- a/internal/testhelpers/http.go +++ b/internal/testhelpers/http.go @@ -3,8 +3,10 @@ package testhelpers import ( "bytes" "encoding/json" + "errors" "io" "net/http" + "net/http/cookiejar" "net/url" "testing" @@ -15,6 +17,29 @@ func NewDebugClient(t *testing.T) *http.Client { return &http.Client{Transport: NewTransportWithLogger(http.DefaultTransport, t)} } +func NewClientWithCookieJar(t *testing.T, jar *cookiejar.Jar, debugRedirects bool) *http.Client { + if jar == nil { + j, err := cookiejar.New(nil) + jar = j + require.NoError(t, err) + } + return &http.Client{ + Jar: jar, + CheckRedirect: func(req *http.Request, via []*http.Request) error { + if debugRedirects { + t.Logf("Redirect: %s", req.URL.String()) + } + if len(via) >= 20 { + for k, v := range via { + t.Logf("Failed with redirect (%d): %s", k, v.URL.String()) + } + return errors.New("stopped after 20 redirects") + } + return nil + }, + } +} + func NewRequest(t *testing.T, isAPI bool, method string, url string, payload io.Reader) *http.Request { req, err := http.NewRequest("POST", url, payload) require.NoError(t, err) diff --git a/internal/testhelpers/selfservice_login.go b/internal/testhelpers/selfservice_login.go index e4b16e63a23..d91bcf7dd6a 100644 --- a/internal/testhelpers/selfservice_login.go +++ b/internal/testhelpers/selfservice_login.go @@ -51,9 +51,10 @@ func NewLoginUIWith401Response(t *testing.T, c *config.Config) *httptest.Server } type initFlowOptions struct { - aal identity.AuthenticatorAssuranceLevel - returnTo string - refresh bool + aal identity.AuthenticatorAssuranceLevel + returnTo string + refresh bool + oauth2LoginChallenge string } func (o *initFlowOptions) apply(opts []InitFlowWithOption) *initFlowOptions { @@ -79,6 +80,10 @@ func getURLFromInitOptions(ts *httptest.Server, path string, forced bool, opts . q.Set("return_to", string(o.returnTo)) } + if o.oauth2LoginChallenge != "" { + q.Set("login_challenge", o.oauth2LoginChallenge) + } + u := urlx.ParseOrPanic(ts.URL + path) u.RawQuery = q.Encode() return u.String() @@ -104,7 +109,13 @@ func InitFlowWithRefresh() InitFlowWithOption { } } -func InitializeLoginFlowViaBrowser(t *testing.T, client *http.Client, ts *httptest.Server, forced bool, isSPA bool, opts ...InitFlowWithOption) *kratos.SelfServiceLoginFlow { +func InitFlowWithOAuth2LoginChallenge(hlc string) InitFlowWithOption { + return func(o *initFlowOptions) { + o.oauth2LoginChallenge = hlc + } +} + +func InitializeLoginFlowViaBrowser(t *testing.T, client *http.Client, ts *httptest.Server, forced bool, isSPA bool, expectInitError bool, expectGetError bool, opts ...InitFlowWithOption) *kratos.SelfServiceLoginFlow { publicClient := NewSDKCustomClient(ts, client) req, err := http.NewRequest("GET", getURLFromInitOptions(ts, login.RouteInitBrowserFlow, forced, opts...), nil) @@ -118,6 +129,11 @@ func InitializeLoginFlowViaBrowser(t *testing.T, client *http.Client, ts *httpte require.NoError(t, err) body := x.MustReadAll(res.Body) require.NoError(t, res.Body.Close()) + if expectInitError { + require.Equal(t, 200, res.StatusCode) + require.NotNil(t, res.Request.URL) + require.Contains(t, res.Request.URL.String(), "error-ts") + } flowID := res.Request.URL.Query().Get("flow") if isSPA { @@ -125,8 +141,13 @@ func InitializeLoginFlowViaBrowser(t *testing.T, client *http.Client, ts *httpte } rs, _, err := publicClient.V0alpha2Api.GetSelfServiceLoginFlow(context.Background()).Id(flowID).Execute() - require.NoError(t, err) - assert.Empty(t, rs.Active) + if expectGetError { + require.Error(t, err) + require.Nil(t, rs) + } else { + require.NoError(t, err) + assert.Empty(t, rs.Active) + } return rs } @@ -195,7 +216,7 @@ func SubmitLoginForm( if isAPI { f = InitializeLoginFlowViaAPI(t, hc, publicTS, forced) } else { - f = InitializeLoginFlowViaBrowser(t, hc, publicTS, forced, isSPA) + f = InitializeLoginFlowViaBrowser(t, hc, publicTS, forced, isSPA, false, false) } time.Sleep(time.Millisecond) // add a bit of delay to allow `1ns` to time out. diff --git a/internal/testhelpers/selfservice_registration.go b/internal/testhelpers/selfservice_registration.go index 1e7379e6383..1c04a522b6c 100644 --- a/internal/testhelpers/selfservice_registration.go +++ b/internal/testhelpers/selfservice_registration.go @@ -39,7 +39,7 @@ func NewRegistrationUIFlowEchoServer(t *testing.T, reg driver.Registry) *httptes return ts } -func InitializeRegistrationFlowViaBrowser(t *testing.T, client *http.Client, ts *httptest.Server, isSPA bool, opts ...InitFlowWithOption) *kratos.SelfServiceRegistrationFlow { +func InitializeRegistrationFlowViaBrowser(t *testing.T, client *http.Client, ts *httptest.Server, isSPA bool, expectInitError bool, expectGetError bool, opts ...InitFlowWithOption) *kratos.SelfServiceRegistrationFlow { req, err := http.NewRequest("GET", getURLFromInitOptions(ts, registration.RouteInitBrowserFlow, false, opts...), nil) require.NoError(t, err) @@ -51,6 +51,11 @@ func InitializeRegistrationFlowViaBrowser(t *testing.T, client *http.Client, ts require.NoError(t, err) body := x.MustReadAll(res.Body) require.NoError(t, res.Body.Close()) + if expectInitError { + require.Equal(t, 200, res.StatusCode) + require.NotNil(t, res.Request.URL) + require.Contains(t, res.Request.URL.String(), "error-ts") + } flowID := res.Request.URL.Query().Get("flow") if isSPA { @@ -58,8 +63,13 @@ func InitializeRegistrationFlowViaBrowser(t *testing.T, client *http.Client, ts } rs, _, err := NewSDKCustomClient(ts, client).V0alpha2Api.GetSelfServiceRegistrationFlow(context.Background()).Id(flowID).Execute() - require.NoError(t, err) - assert.Empty(t, rs.Active) + if expectGetError { + require.Error(t, err) + require.Nil(t, rs) + } else { + require.NoError(t, err) + assert.Empty(t, rs.Active) + } return rs } @@ -114,7 +124,7 @@ func SubmitRegistrationForm( if isAPI { payload = InitializeRegistrationFlowViaAPI(t, hc, publicTS) } else { - payload = InitializeRegistrationFlowViaBrowser(t, hc, publicTS, isSPA) + payload = InitializeRegistrationFlowViaBrowser(t, hc, publicTS, isSPA, false, false) } time.Sleep(time.Millisecond) // add a bit of delay to allow `1ns` to time out. diff --git a/package-lock.json b/package-lock.json index 9895f8a50f4..27f1f71a24c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,9 +11,10 @@ "devDependencies": { "@ory/kratos-client": "0.0.0-next.8d3b018594f7", "@types/node": "^16.9.6", + "@types/uuid": "^8.3.4", "@types/yamljs": "^0.2.31", "chrome-remote-interface": "^0.31.0", - "cypress": "^9.5.1", + "cypress": "^9.6.0", "dayjs": "^1.10.4", "got": "^11.8.2", "ory-prettier-styles": "1.3.0", @@ -24,6 +25,16 @@ "wait-on": "5.3.0" } }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, "node_modules/@cypress/request": { "version": "2.88.10", "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.10.tgz", @@ -73,9 +84,9 @@ } }, "node_modules/@hapi/hoek": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz", - "integrity": "sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", "dev": true }, "node_modules/@hapi/topo": { @@ -88,11 +99,11 @@ } }, "node_modules/@nestjs/common": { - "version": "8.2.6", - "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-8.2.6.tgz", - "integrity": "sha512-flLYSXunxcKyjbYddrhwbc49uE705MxBt85rS3mHyhDbAIPSGGeZEqME44YyAzCg1NTfJSNe7ztmOce5kNkb9A==", + "version": "8.4.4", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-8.4.4.tgz", + "integrity": "sha512-QHi7QcgH/5Jinz+SCfIZJkFHc6Cch1YsAEGFEhi6wSp6MILb0sJMQ1CX06e9tCOAjSlBwaJj4PH0eFCVau5v9Q==", "dependencies": { - "axios": "0.24.0", + "axios": "0.26.1", "iterare": "1.2.1", "tslib": "2.3.1", "uuid": "8.3.2" @@ -126,15 +137,15 @@ "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" }, "node_modules/@nestjs/core": { - "version": "8.2.6", - "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-8.2.6.tgz", - "integrity": "sha512-NwPcEIMmCsucs3QaDlQvkoU1FlFM2wm/WjaqLQhkSoIEmAR1gNtBo88f5io5cpMwCo1k5xYhqGlaSl6TfngwWQ==", + "version": "8.4.4", + "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-8.4.4.tgz", + "integrity": "sha512-Ef3yJPuzAttpNfehnGqIV5kHIL9SHptB5F4ERxoU7pT61H3xiYpZw6hSjx68cJO7cc6rm7/N+b4zeuJvFHtvBg==", "hasInstallScript": true, "dependencies": { "@nuxtjs/opencollective": "0.3.2", "fast-safe-stringify": "2.1.1", "iterare": "1.2.1", - "object-hash": "2.2.0", + "object-hash": "3.0.0", "path-to-regexp": "3.2.0", "tslib": "2.3.1", "uuid": "8.3.2" @@ -221,25 +232,25 @@ } }, "node_modules/@openapitools/openapi-generator-cli": { - "version": "2.4.26", - "resolved": "https://registry.npmjs.org/@openapitools/openapi-generator-cli/-/openapi-generator-cli-2.4.26.tgz", - "integrity": "sha512-O42H9q1HWGoIpcpMaUu318b6bmOgcjP3MieHwOrFdoG3KyttceBGlbLf9Kbf7WM91WSNCDXum7cnEKASuoGjAg==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@openapitools/openapi-generator-cli/-/openapi-generator-cli-2.5.1.tgz", + "integrity": "sha512-WSRQBU0dCSVD+0Qv8iCsv0C4iMaZe/NpJ/CT4SmrEYLH3txoKTE8wEfbdj/kqShS8Or0YEGDPUzhSIKY151L0w==", "hasInstallScript": true, "dependencies": { - "@nestjs/common": "8.2.6", - "@nestjs/core": "8.2.6", + "@nestjs/common": "8.4.4", + "@nestjs/core": "8.4.4", "@nuxtjs/opencollective": "0.3.2", "chalk": "4.1.2", "commander": "8.3.0", - "compare-versions": "3.6.0", + "compare-versions": "4.1.3", "concurrently": "6.5.1", "console.table": "0.10.0", - "fs-extra": "10.0.0", + "fs-extra": "10.0.1", "glob": "7.1.6", - "inquirer": "8.2.0", + "inquirer": "8.2.2", "lodash": "4.17.21", "reflect-metadata": "0.1.13", - "rxjs": "7.5.2", + "rxjs": "7.5.5", "tslib": "2.0.3" }, "bin": { @@ -319,9 +330,9 @@ } }, "node_modules/@sideway/address": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.3.tgz", - "integrity": "sha512-8ncEUtmnTsMmL7z1YPB47kPUq7LpKWJNFPsRzHiIajGC5uXlWGn+AmkYPcHNl8S4tcEGx+cnORnNYaw2wvL+LQ==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", + "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", "dev": true, "dependencies": { "@hapi/hoek": "^9.0.0" @@ -340,9 +351,9 @@ "dev": true }, "node_modules/@sindresorhus/is": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.4.0.tgz", - "integrity": "sha512-QppPM/8l3Mawvh4rn9CNEYIU9bxpXUCRMaX9yUpvBk1nMKusLKpfXGDEKExKaPhLzcn3lzil7pR6rnJ11HgeRQ==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", "dev": true, "engines": { "node": ">=10" @@ -391,10 +402,16 @@ "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", "dev": true }, + "node_modules/@types/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha512-3YP80IxxFJB4b5tYC2SUPwkg0XQLiu0nWvhRgEatgjf+29IcWO9X1k8xRv5DGssJ/lCrjYTjQPcobJr2yWIVuQ==", + "dev": true + }, "node_modules/@types/keyv": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.3.tgz", - "integrity": "sha512-FXCJgyyN3ivVgRoml4h94G/p3kY+u/B86La+QptcqJaWtBWtmc6TtkNfS40n9bIvyLteHh7zXOtgbobORKPbDg==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", "dev": true, "dependencies": { "@types/node": "*" @@ -407,9 +424,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "16.11.24", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.24.tgz", - "integrity": "sha512-Ezv33Rl4mIi6YdSHfIRNBd4Q9kUe5okiaw/ikvJiJDmuQZNW5kfdg7+oQPF8NO6sTcr3woIpj3jANzTXdvEZXA==", + "version": "16.11.41", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.41.tgz", + "integrity": "sha512-mqoYK2TnVjdkGk8qXAVGc/x9nSaTpSrFaGFm43BUH3IdoBV0nta6hYaGmdOvIMlbHJbUEVen3gvwpwovAZKNdQ==", "dev": true }, "node_modules/@types/responselike": { @@ -433,6 +450,12 @@ "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==", "dev": true }, + "node_modules/@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "dev": true + }, "node_modules/@types/yamljs": { "version": "0.2.31", "resolved": "https://registry.npmjs.org/@types/yamljs/-/yamljs-0.2.31.tgz", @@ -440,9 +463,9 @@ "dev": true }, "node_modules/@types/yauzl": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.2.tgz", - "integrity": "sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", "dev": true, "optional": true, "dependencies": { @@ -463,9 +486,9 @@ } }, "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true, "engines": { "node": ">=6" @@ -556,7 +579,7 @@ "node_modules/assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "dev": true, "engines": { "node": ">=0.8" @@ -572,15 +595,15 @@ } }, "node_modules/async": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", - "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", "dev": true }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, "node_modules/at-least-node": { @@ -595,7 +618,7 @@ "node_modules/aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", "dev": true, "engines": { "node": "*" @@ -608,11 +631,11 @@ "dev": true }, "node_modules/axios": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz", - "integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==", + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", + "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", "dependencies": { - "follow-redirects": "^1.14.4" + "follow-redirects": "^1.14.8" } }, "node_modules/balanced-match": { @@ -642,7 +665,7 @@ "node_modules/bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", "dev": true, "dependencies": { "tweetnacl": "^0.14.3" @@ -717,7 +740,7 @@ "node_modules/buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true, "engines": { "node": "*" @@ -762,7 +785,7 @@ "node_modules/caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", "dev": true }, "node_modules/chalk": { @@ -788,7 +811,7 @@ "node_modules/check-more-types": { "version": "2.24.0", "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", - "integrity": "sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA=", + "integrity": "sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==", "dev": true, "engines": { "node": ">= 0.8.0" @@ -814,9 +837,9 @@ "dev": true }, "node_modules/ci-info": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", - "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.2.tgz", + "integrity": "sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg==", "dev": true }, "node_modules/clean-stack": { @@ -851,9 +874,9 @@ } }, "node_modules/cli-table3": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.1.tgz", - "integrity": "sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==", + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.2.tgz", + "integrity": "sha512-QyavHCaIC80cMivimWu4aWHilIpiDpfm3hGmqAmXVL1UsnbLuBSMd21hTX6VY4ZSDSM73ESLeF8TOYId3rBTbw==", "dev": true, "dependencies": { "string-width": "^4.2.0" @@ -862,7 +885,7 @@ "node": "10.* || >= 12.*" }, "optionalDependencies": { - "colors": "1.4.0" + "@colors/colors": "1.5.0" } }, "node_modules/cli-truncate": { @@ -902,7 +925,7 @@ "node_modules/clone": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "engines": { "node": ">=0.8" } @@ -910,7 +933,7 @@ "node_modules/clone-response": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "integrity": "sha512-yjLXh88P599UOyPTFX0POsd7WxnbsVsGohcwzHOLspIhhpalPw1BcqED8NblyZLKcGrL8dTgMlcaZxV2jAD41Q==", "dev": true, "dependencies": { "mimic-response": "^1.0.0" @@ -933,21 +956,11 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/colorette": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", - "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", "dev": true }, - "node_modules/colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.1.90" - } - }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -978,14 +991,27 @@ } }, "node_modules/compare-versions": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", - "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==" + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-4.1.3.tgz", + "integrity": "sha512-WQfnbDcrYnGr55UwbxKiQKASnTtNnaAWVi8jZyy8NTpVAXWACSne8lMD1iaIo9AiU6mnuLvSVshCzewVuWxHUg==" + }, + "node_modules/compress-brotli": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/compress-brotli/-/compress-brotli-1.3.8.tgz", + "integrity": "sha512-lVcQsjhxhIXsuupfy9fmZUFtAIdBmXA7EGY6GBdgZ++qkM9zG4YFT8iU7FoBxzryNDMOpD1HIFHUSX4D87oqhQ==", + "dev": true, + "dependencies": { + "@types/json-buffer": "~3.0.0", + "json-buffer": "~3.0.1" + }, + "engines": { + "node": ">= 12" + } }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "node_modules/concurrently": { "version": "6.5.1", @@ -1046,7 +1072,7 @@ "node_modules/console.table": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/console.table/-/console.table-0.10.0.tgz", - "integrity": "sha1-CRcCVYiHW+/XDPLv9L7yxuLXXQQ=", + "integrity": "sha512-dPyZofqggxuvSf7WXvNjuRfnsOk1YazkVP8FdxH4tcH2c37wc79/Yl6Bhr7Lsu00KMgy2ql/qCMuNu8xctZM8g==", "dependencies": { "easy-table": "1.1.0" }, @@ -1057,7 +1083,7 @@ "node_modules/core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", "dev": true }, "node_modules/cross-spawn": { @@ -1075,9 +1101,9 @@ } }, "node_modules/cypress": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-9.5.1.tgz", - "integrity": "sha512-H7lUWB3Svr44gz1rNnj941xmdsCljXoJa2cDneAltjI9leKLMQLm30x6jLlpQ730tiVtIbW5HdUmBzPzwzfUQg==", + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-9.7.0.tgz", + "integrity": "sha512-+1EE1nuuuwIt/N1KXRR2iWHU+OiIt7H28jJDyyI4tiUftId/DrXYEwoDa5+kH2pki1zxnA0r6HrUGHV5eLbF5Q==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -1113,7 +1139,7 @@ "listr2": "^3.8.3", "lodash": "^4.17.21", "log-symbols": "^4.0.0", - "minimist": "^1.2.5", + "minimist": "^1.2.6", "ospath": "^1.2.2", "pretty-bytes": "^5.6.0", "proxy-from-env": "1.0.0", @@ -1132,9 +1158,9 @@ } }, "node_modules/cypress/node_modules/@types/node": { - "version": "14.18.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.11.tgz", - "integrity": "sha512-zCoCEMA+IPpsRkyCFBqew5vGb7r8RSiB3uwdu/map7uwLAfu1MTazW26/pUDWoNnF88vJz4W3U56i5gtXNqxGg==", + "version": "14.18.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.21.tgz", + "integrity": "sha512-x5W9s+8P4XteaxT/jKF0PSb7XEvo5VmqEWgsMlyeY4ZlLK8I6aH6g5TPPyDlLAep+GYf4kefb7HFyc7PAO3m+Q==", "dev": true }, "node_modules/cypress/node_modules/commander": { @@ -1179,7 +1205,7 @@ "node_modules/dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", "dev": true, "dependencies": { "assert-plus": "^1.0.0" @@ -1201,15 +1227,15 @@ } }, "node_modules/dayjs": { - "version": "1.10.7", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz", - "integrity": "sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig==", + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.3.tgz", + "integrity": "sha512-xxwlswWOlGhzgQ4TKzASQkUhqERI3egRNqgV4ScR8wlANA/A9tZ7miXa44vTTKEq5l7vWoL5G57bG3zA+Kow0A==", "dev": true }, "node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -1253,7 +1279,7 @@ "node_modules/defaults": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "integrity": "sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA==", "dependencies": { "clone": "^1.0.2" } @@ -1270,7 +1296,7 @@ "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, "engines": { "node": ">=0.4.0" @@ -1309,7 +1335,7 @@ "node_modules/easy-table": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/easy-table/-/easy-table-1.1.0.tgz", - "integrity": "sha1-hvmrTBAvA3G3KXuSplHVgkvIy3M=", + "integrity": "sha512-oq33hWOSSnl2Hoh00tZWaIPi1ievrD9aFG82/IgjlycAnW9hHx5PkJiXpxPsgEE+H7BsbVQXFVFST8TEXS6/pA==", "optionalDependencies": { "wcwidth": ">=1.0.1" } @@ -1317,7 +1343,7 @@ "node_modules/ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", "dev": true, "dependencies": { "jsbn": "~0.1.0", @@ -1361,7 +1387,7 @@ "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "engines": { "node": ">=0.8.0" } @@ -1460,7 +1486,7 @@ "node_modules/extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", "dev": true, "engines": [ "node >=0.6.0" @@ -1499,7 +1525,7 @@ "node_modules/fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", "dev": true, "dependencies": { "pend": "~1.2.0" @@ -1532,9 +1558,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.14.8", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", - "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", "funding": [ { "type": "individual", @@ -1553,7 +1579,7 @@ "node_modules/forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", "dev": true, "engines": { "node": "*" @@ -1574,9 +1600,9 @@ } }, "node_modules/fs-extra": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", - "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", + "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -1589,7 +1615,7 @@ "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "node_modules/get-caller-file": { "version": "2.0.5", @@ -1626,7 +1652,7 @@ "node_modules/getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", "dev": true, "dependencies": { "assert-plus": "^1.0.0" @@ -1707,9 +1733,9 @@ } }, "node_modules/got": { - "version": "11.8.3", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.3.tgz", - "integrity": "sha512-7gtQ5KiPh1RtGS9/Jbv1ofDpBFuq42gyfEib+ejaRBJuj/3tQFeR5+gw57e4ipaU8c/rCjvX6fkQz2lyDlGAOg==", + "version": "11.8.5", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.5.tgz", + "integrity": "sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==", "dev": true, "dependencies": { "@sindresorhus/is": "^4.0.0", @@ -1732,9 +1758,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" }, "node_modules/has-flag": { "version": "4.0.0", @@ -1837,7 +1863,7 @@ "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -1858,9 +1884,9 @@ } }, "node_modules/inquirer": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.0.tgz", - "integrity": "sha512-0crLweprevJ02tTuA6ThpoAERAGyVILC4sS74uib58Xf/zSr1/ZWtmm7D5CI+bSQEaA04f0K7idaHpQbSWgiVQ==", + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.2.tgz", + "integrity": "sha512-pG7I/si6K/0X7p1qU+rfWnpTE1UIkTONN1wxtzh0d+dHXtT/JG6qBgLxoyHVsQa8cFABxAPh0pD6uUUHiAoaow==", "dependencies": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", @@ -1872,13 +1898,13 @@ "mute-stream": "0.0.8", "ora": "^5.4.1", "run-async": "^2.4.0", - "rxjs": "^7.2.0", + "rxjs": "^7.5.5", "string-width": "^4.1.0", "strip-ansi": "^6.0.0", "through": "^2.3.6" }, "engines": { - "node": ">=8.0.0" + "node": ">=12.0.0" } }, "node_modules/is-ci": { @@ -1988,7 +2014,7 @@ "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", "dev": true }, "node_modules/is-unicode-supported": { @@ -2005,13 +2031,13 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", "dev": true }, "node_modules/iterare": { @@ -2038,7 +2064,7 @@ "node_modules/jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", "dev": true }, "node_modules/json-buffer": { @@ -2056,7 +2082,7 @@ "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", "dev": true }, "node_modules/jsonfile": { @@ -2086,18 +2112,19 @@ } }, "node_modules/keyv": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.1.1.tgz", - "integrity": "sha512-tGv1yP6snQVDSM4X6yxrv2zzq/EvpW+oYiUz6aueW1u9CtS8RzUQYxxmFwgZlO2jSgCxQbchhxaqXXp2hnKGpQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.3.2.tgz", + "integrity": "sha512-kn8WmodVBe12lmHpA6W8OY7SNh6wVR+Z+wZESF4iF5FCazaVXGWOtnbnvX0tMQ1bO+/TmOD9LziuYMvrIIs0xw==", "dev": true, "dependencies": { + "compress-brotli": "^1.3.8", "json-buffer": "3.0.1" } }, "node_modules/lazy-ass": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", - "integrity": "sha1-eZllXoZGwX8In90YfRUNMyTVRRM=", + "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==", "dev": true, "engines": { "node": "> 0.8" @@ -2138,7 +2165,7 @@ "node_modules/lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", "dev": true }, "node_modules/log-symbols": { @@ -2255,21 +2282,21 @@ } }, "node_modules/mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "dependencies": { - "mime-db": "1.51.0" + "mime-db": "1.52.0" }, "engines": { "node": ">= 0.6" @@ -2293,9 +2320,9 @@ } }, "node_modules/minimatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.1.tgz", - "integrity": "sha512-reLxBcKUPNBnc/sVtAbxgRVFSegoGeLaSjmphNhcwcolhYLRgtJscn5mRl6YRZNQv40Y7P6JM2YhSIsbL9OB5A==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -2364,9 +2391,9 @@ } }, "node_modules/object-hash": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", - "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", "engines": { "node": ">= 6" } @@ -2374,7 +2401,7 @@ "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dependencies": { "wrappy": "1" } @@ -2424,7 +2451,7 @@ "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "engines": { "node": ">=0.10.0" } @@ -2432,7 +2459,7 @@ "node_modules/ospath": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", - "integrity": "sha1-EnZjl3Sj+O8lcvf+QoDg6kVQwHs=", + "integrity": "sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==", "dev": true }, "node_modules/otplib": { @@ -2473,7 +2500,7 @@ "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "engines": { "node": ">=0.10.0" } @@ -2504,13 +2531,13 @@ "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", "dev": true }, "node_modules/performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", "dev": true }, "node_modules/picomatch": { @@ -2528,7 +2555,7 @@ "node_modules/pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true, "engines": { "node": ">=0.10.0" @@ -2576,7 +2603,7 @@ "node_modules/proxy-from-env": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", - "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=", + "integrity": "sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==", "dev": true }, "node_modules/psl": { @@ -2666,7 +2693,7 @@ "node_modules/request-progress": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", - "integrity": "sha1-TKdUCBx/7GP1BeT6qCWqBs1mnb4=", + "integrity": "sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==", "dev": true, "dependencies": { "throttleit": "^1.0.0" @@ -2675,7 +2702,7 @@ "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "engines": { "node": ">=0.10.0" } @@ -2770,17 +2797,17 @@ } }, "node_modules/rxjs": { - "version": "7.5.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.2.tgz", - "integrity": "sha512-PwDt186XaL3QN5qXj/H9DGyHhP3/RYYgZZwqBv9Tv8rsAaiwFH1IsJJlcgD37J7UW5a6O67qX0KWKS3/pu0m4w==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", + "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/rxjs/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" }, "node_modules/safe-buffer": { "version": "5.2.1", @@ -2807,9 +2834,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -2896,12 +2923,12 @@ "node_modules/spawn-command": { "version": "0.0.2-1", "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", - "integrity": "sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A=" + "integrity": "sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==" }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, "node_modules/sshpk": { "version": "1.17.0", @@ -2983,7 +3010,7 @@ "node_modules/thirty-two": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/thirty-two/-/thirty-two-1.0.2.tgz", - "integrity": "sha1-TKL//AKlEpDSdEueP1V2k8prYno=", + "integrity": "sha512-OEI0IWCe+Dw46019YLl6V10Us5bi574EvlJEOcAkB29IzQ/mYD1A6RyNHLjZPiHCmuodxvgF6U+vZO1L15lxVA==", "dev": true, "engines": { "node": ">=0.2.6" @@ -2992,13 +3019,13 @@ "node_modules/throttleit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", - "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=", + "integrity": "sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g==", "dev": true }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" }, "node_modules/tmp": { "version": "0.2.1", @@ -3040,7 +3067,7 @@ "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/tree-kill": { "version": "1.2.2", @@ -3058,7 +3085,7 @@ "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, "dependencies": { "safe-buffer": "^5.0.1" @@ -3070,7 +3097,7 @@ "node_modules/tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", "dev": true }, "node_modules/type-fest": { @@ -3085,9 +3112,9 @@ } }, "node_modules/typescript": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", - "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -3117,7 +3144,7 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/uuid": { "version": "8.3.2", @@ -3130,7 +3157,7 @@ "node_modules/verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", "dev": true, "engines": [ "node >=0.6.0" @@ -3190,7 +3217,7 @@ "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "dependencies": { "defaults": "^1.0.3" } @@ -3198,12 +3225,12 @@ "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -3243,12 +3270,12 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.8.tgz", + "integrity": "sha512-ri1Id1WinAX5Jqn9HejiGb8crfRio0Qgu8+MtL36rlTA6RLsMdWt1Az/19A2Qij6uSHUMphEFaTKa4WG+UNHNw==", "dev": true, "engines": { "node": ">=8.3.0" @@ -3321,7 +3348,7 @@ "node_modules/yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", "dev": true, "dependencies": { "buffer-crc32": "~0.2.3", @@ -3330,6 +3357,13 @@ } }, "dependencies": { + "@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "optional": true + }, "@cypress/request": { "version": "2.88.10", "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.10.tgz", @@ -3378,9 +3412,9 @@ } }, "@hapi/hoek": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz", - "integrity": "sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", "dev": true }, "@hapi/topo": { @@ -3393,11 +3427,11 @@ } }, "@nestjs/common": { - "version": "8.2.6", - "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-8.2.6.tgz", - "integrity": "sha512-flLYSXunxcKyjbYddrhwbc49uE705MxBt85rS3mHyhDbAIPSGGeZEqME44YyAzCg1NTfJSNe7ztmOce5kNkb9A==", + "version": "8.4.4", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-8.4.4.tgz", + "integrity": "sha512-QHi7QcgH/5Jinz+SCfIZJkFHc6Cch1YsAEGFEhi6wSp6MILb0sJMQ1CX06e9tCOAjSlBwaJj4PH0eFCVau5v9Q==", "requires": { - "axios": "0.24.0", + "axios": "0.26.1", "iterare": "1.2.1", "tslib": "2.3.1", "uuid": "8.3.2" @@ -3411,14 +3445,14 @@ } }, "@nestjs/core": { - "version": "8.2.6", - "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-8.2.6.tgz", - "integrity": "sha512-NwPcEIMmCsucs3QaDlQvkoU1FlFM2wm/WjaqLQhkSoIEmAR1gNtBo88f5io5cpMwCo1k5xYhqGlaSl6TfngwWQ==", + "version": "8.4.4", + "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-8.4.4.tgz", + "integrity": "sha512-Ef3yJPuzAttpNfehnGqIV5kHIL9SHptB5F4ERxoU7pT61H3xiYpZw6hSjx68cJO7cc6rm7/N+b4zeuJvFHtvBg==", "requires": { "@nuxtjs/opencollective": "0.3.2", "fast-safe-stringify": "2.1.1", "iterare": "1.2.1", - "object-hash": "2.2.0", + "object-hash": "3.0.0", "path-to-regexp": "3.2.0", "tslib": "2.3.1", "uuid": "8.3.2" @@ -3468,24 +3502,24 @@ } }, "@openapitools/openapi-generator-cli": { - "version": "2.4.26", - "resolved": "https://registry.npmjs.org/@openapitools/openapi-generator-cli/-/openapi-generator-cli-2.4.26.tgz", - "integrity": "sha512-O42H9q1HWGoIpcpMaUu318b6bmOgcjP3MieHwOrFdoG3KyttceBGlbLf9Kbf7WM91WSNCDXum7cnEKASuoGjAg==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@openapitools/openapi-generator-cli/-/openapi-generator-cli-2.5.1.tgz", + "integrity": "sha512-WSRQBU0dCSVD+0Qv8iCsv0C4iMaZe/NpJ/CT4SmrEYLH3txoKTE8wEfbdj/kqShS8Or0YEGDPUzhSIKY151L0w==", "requires": { - "@nestjs/common": "8.2.6", - "@nestjs/core": "8.2.6", + "@nestjs/common": "8.4.4", + "@nestjs/core": "8.4.4", "@nuxtjs/opencollective": "0.3.2", "chalk": "4.1.2", "commander": "8.3.0", - "compare-versions": "3.6.0", + "compare-versions": "4.1.3", "concurrently": "6.5.1", "console.table": "0.10.0", - "fs-extra": "10.0.0", + "fs-extra": "10.0.1", "glob": "7.1.6", - "inquirer": "8.2.0", + "inquirer": "8.2.2", "lodash": "4.17.21", "reflect-metadata": "0.1.13", - "rxjs": "7.5.2", + "rxjs": "7.5.5", "tslib": "2.0.3" } }, @@ -3557,9 +3591,9 @@ } }, "@sideway/address": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.3.tgz", - "integrity": "sha512-8ncEUtmnTsMmL7z1YPB47kPUq7LpKWJNFPsRzHiIajGC5uXlWGn+AmkYPcHNl8S4tcEGx+cnORnNYaw2wvL+LQ==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", + "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", "dev": true, "requires": { "@hapi/hoek": "^9.0.0" @@ -3578,9 +3612,9 @@ "dev": true }, "@sindresorhus/is": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.4.0.tgz", - "integrity": "sha512-QppPM/8l3Mawvh4rn9CNEYIU9bxpXUCRMaX9yUpvBk1nMKusLKpfXGDEKExKaPhLzcn3lzil7pR6rnJ11HgeRQ==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", "dev": true }, "@szmarczak/http-timer": { @@ -3620,10 +3654,16 @@ "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", "dev": true }, + "@types/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha512-3YP80IxxFJB4b5tYC2SUPwkg0XQLiu0nWvhRgEatgjf+29IcWO9X1k8xRv5DGssJ/lCrjYTjQPcobJr2yWIVuQ==", + "dev": true + }, "@types/keyv": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.3.tgz", - "integrity": "sha512-FXCJgyyN3ivVgRoml4h94G/p3kY+u/B86La+QptcqJaWtBWtmc6TtkNfS40n9bIvyLteHh7zXOtgbobORKPbDg==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", "dev": true, "requires": { "@types/node": "*" @@ -3636,9 +3676,9 @@ "dev": true }, "@types/node": { - "version": "16.11.24", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.24.tgz", - "integrity": "sha512-Ezv33Rl4mIi6YdSHfIRNBd4Q9kUe5okiaw/ikvJiJDmuQZNW5kfdg7+oQPF8NO6sTcr3woIpj3jANzTXdvEZXA==", + "version": "16.11.41", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.41.tgz", + "integrity": "sha512-mqoYK2TnVjdkGk8qXAVGc/x9nSaTpSrFaGFm43BUH3IdoBV0nta6hYaGmdOvIMlbHJbUEVen3gvwpwovAZKNdQ==", "dev": true }, "@types/responselike": { @@ -3662,6 +3702,12 @@ "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==", "dev": true }, + "@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "dev": true + }, "@types/yamljs": { "version": "0.2.31", "resolved": "https://registry.npmjs.org/@types/yamljs/-/yamljs-0.2.31.tgz", @@ -3669,9 +3715,9 @@ "dev": true }, "@types/yauzl": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.2.tgz", - "integrity": "sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", "dev": true, "optional": true, "requires": { @@ -3689,9 +3735,9 @@ } }, "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true }, "ansi-escapes": { @@ -3747,7 +3793,7 @@ "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "dev": true }, "astral-regex": { @@ -3757,15 +3803,15 @@ "dev": true }, "async": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", - "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", "dev": true }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, "at-least-node": { @@ -3777,7 +3823,7 @@ "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", "dev": true }, "aws4": { @@ -3787,11 +3833,11 @@ "dev": true }, "axios": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz", - "integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==", + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", + "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", "requires": { - "follow-redirects": "^1.14.4" + "follow-redirects": "^1.14.8" } }, "balanced-match": { @@ -3807,7 +3853,7 @@ "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", "dev": true, "requires": { "tweetnacl": "^0.14.3" @@ -3865,7 +3911,7 @@ "buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true }, "cacheable-lookup": { @@ -3898,7 +3944,7 @@ "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", "dev": true }, "chalk": { @@ -3918,7 +3964,7 @@ "check-more-types": { "version": "2.24.0", "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", - "integrity": "sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA=", + "integrity": "sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==", "dev": true }, "chrome-remote-interface": { @@ -3940,9 +3986,9 @@ } }, "ci-info": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", - "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.2.tgz", + "integrity": "sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg==", "dev": true }, "clean-stack": { @@ -3965,12 +4011,12 @@ "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==" }, "cli-table3": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.1.tgz", - "integrity": "sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==", + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.2.tgz", + "integrity": "sha512-QyavHCaIC80cMivimWu4aWHilIpiDpfm3hGmqAmXVL1UsnbLuBSMd21hTX6VY4ZSDSM73ESLeF8TOYId3rBTbw==", "dev": true, "requires": { - "colors": "1.4.0", + "@colors/colors": "1.5.0", "string-width": "^4.2.0" } }, @@ -4002,12 +4048,12 @@ "clone": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==" }, "clone-response": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "integrity": "sha512-yjLXh88P599UOyPTFX0POsd7WxnbsVsGohcwzHOLspIhhpalPw1BcqED8NblyZLKcGrL8dTgMlcaZxV2jAD41Q==", "dev": true, "requires": { "mimic-response": "^1.0.0" @@ -4027,18 +4073,11 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "colorette": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", - "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", "dev": true }, - "colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true, - "optional": true - }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -4060,14 +4099,24 @@ "dev": true }, "compare-versions": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", - "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==" + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-4.1.3.tgz", + "integrity": "sha512-WQfnbDcrYnGr55UwbxKiQKASnTtNnaAWVi8jZyy8NTpVAXWACSne8lMD1iaIo9AiU6mnuLvSVshCzewVuWxHUg==" + }, + "compress-brotli": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/compress-brotli/-/compress-brotli-1.3.8.tgz", + "integrity": "sha512-lVcQsjhxhIXsuupfy9fmZUFtAIdBmXA7EGY6GBdgZ++qkM9zG4YFT8iU7FoBxzryNDMOpD1HIFHUSX4D87oqhQ==", + "dev": true, + "requires": { + "@types/json-buffer": "~3.0.0", + "json-buffer": "~3.0.1" + } }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "concurrently": { "version": "6.5.1", @@ -4115,7 +4164,7 @@ "console.table": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/console.table/-/console.table-0.10.0.tgz", - "integrity": "sha1-CRcCVYiHW+/XDPLv9L7yxuLXXQQ=", + "integrity": "sha512-dPyZofqggxuvSf7WXvNjuRfnsOk1YazkVP8FdxH4tcH2c37wc79/Yl6Bhr7Lsu00KMgy2ql/qCMuNu8xctZM8g==", "requires": { "easy-table": "1.1.0" } @@ -4123,7 +4172,7 @@ "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", "dev": true }, "cross-spawn": { @@ -4138,9 +4187,9 @@ } }, "cypress": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-9.5.1.tgz", - "integrity": "sha512-H7lUWB3Svr44gz1rNnj941xmdsCljXoJa2cDneAltjI9leKLMQLm30x6jLlpQ730tiVtIbW5HdUmBzPzwzfUQg==", + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-9.7.0.tgz", + "integrity": "sha512-+1EE1nuuuwIt/N1KXRR2iWHU+OiIt7H28jJDyyI4tiUftId/DrXYEwoDa5+kH2pki1zxnA0r6HrUGHV5eLbF5Q==", "dev": true, "requires": { "@cypress/request": "^2.88.10", @@ -4175,7 +4224,7 @@ "listr2": "^3.8.3", "lodash": "^4.17.21", "log-symbols": "^4.0.0", - "minimist": "^1.2.5", + "minimist": "^1.2.6", "ospath": "^1.2.2", "pretty-bytes": "^5.6.0", "proxy-from-env": "1.0.0", @@ -4188,9 +4237,9 @@ }, "dependencies": { "@types/node": { - "version": "14.18.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.11.tgz", - "integrity": "sha512-zCoCEMA+IPpsRkyCFBqew5vGb7r8RSiB3uwdu/map7uwLAfu1MTazW26/pUDWoNnF88vJz4W3U56i5gtXNqxGg==", + "version": "14.18.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.21.tgz", + "integrity": "sha512-x5W9s+8P4XteaxT/jKF0PSb7XEvo5VmqEWgsMlyeY4ZlLK8I6aH6g5TPPyDlLAep+GYf4kefb7HFyc7PAO3m+Q==", "dev": true }, "commander": { @@ -4225,7 +4274,7 @@ "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", "dev": true, "requires": { "assert-plus": "^1.0.0" @@ -4237,15 +4286,15 @@ "integrity": "sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==" }, "dayjs": { - "version": "1.10.7", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz", - "integrity": "sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig==", + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.3.tgz", + "integrity": "sha512-xxwlswWOlGhzgQ4TKzASQkUhqERI3egRNqgV4ScR8wlANA/A9tZ7miXa44vTTKEq5l7vWoL5G57bG3zA+Kow0A==", "dev": true }, "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "requires": { "ms": "2.1.2" @@ -4271,7 +4320,7 @@ "defaults": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "integrity": "sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA==", "requires": { "clone": "^1.0.2" } @@ -4285,7 +4334,7 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true }, "detect-indent": { @@ -4312,7 +4361,7 @@ "easy-table": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/easy-table/-/easy-table-1.1.0.tgz", - "integrity": "sha1-hvmrTBAvA3G3KXuSplHVgkvIy3M=", + "integrity": "sha512-oq33hWOSSnl2Hoh00tZWaIPi1ievrD9aFG82/IgjlycAnW9hHx5PkJiXpxPsgEE+H7BsbVQXFVFST8TEXS6/pA==", "requires": { "wcwidth": ">=1.0.1" } @@ -4320,7 +4369,7 @@ "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", "dev": true, "requires": { "jsbn": "~0.1.0", @@ -4358,7 +4407,7 @@ "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" }, "eventemitter2": { "version": "6.4.5", @@ -4433,7 +4482,7 @@ "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", "dev": true }, "fast-glob": { @@ -4466,7 +4515,7 @@ "fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", "dev": true, "requires": { "pend": "~1.2.0" @@ -4490,14 +4539,14 @@ } }, "follow-redirects": { - "version": "1.14.8", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", - "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==" + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==" }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", "dev": true }, "form-data": { @@ -4512,9 +4561,9 @@ } }, "fs-extra": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", - "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", + "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", "requires": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -4524,7 +4573,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "get-caller-file": { "version": "2.0.5", @@ -4552,7 +4601,7 @@ "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", "dev": true, "requires": { "assert-plus": "^1.0.0" @@ -4612,9 +4661,9 @@ } }, "got": { - "version": "11.8.3", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.3.tgz", - "integrity": "sha512-7gtQ5KiPh1RtGS9/Jbv1ofDpBFuq42gyfEib+ejaRBJuj/3tQFeR5+gw57e4ipaU8c/rCjvX6fkQz2lyDlGAOg==", + "version": "11.8.5", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.5.tgz", + "integrity": "sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==", "dev": true, "requires": { "@sindresorhus/is": "^4.0.0", @@ -4631,9 +4680,9 @@ } }, "graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" }, "has-flag": { "version": "4.0.0", @@ -4701,7 +4750,7 @@ "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "requires": { "once": "^1.3.0", "wrappy": "1" @@ -4719,9 +4768,9 @@ "dev": true }, "inquirer": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.0.tgz", - "integrity": "sha512-0crLweprevJ02tTuA6ThpoAERAGyVILC4sS74uib58Xf/zSr1/ZWtmm7D5CI+bSQEaA04f0K7idaHpQbSWgiVQ==", + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.2.tgz", + "integrity": "sha512-pG7I/si6K/0X7p1qU+rfWnpTE1UIkTONN1wxtzh0d+dHXtT/JG6qBgLxoyHVsQa8cFABxAPh0pD6uUUHiAoaow==", "requires": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", @@ -4733,7 +4782,7 @@ "mute-stream": "0.0.8", "ora": "^5.4.1", "run-async": "^2.4.0", - "rxjs": "^7.2.0", + "rxjs": "^7.5.5", "string-width": "^4.1.0", "strip-ansi": "^6.0.0", "through": "^2.3.6" @@ -4810,7 +4859,7 @@ "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", "dev": true }, "is-unicode-supported": { @@ -4821,13 +4870,13 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", "dev": true }, "iterare": { @@ -4851,7 +4900,7 @@ "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", "dev": true }, "json-buffer": { @@ -4869,7 +4918,7 @@ "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", "dev": true }, "jsonfile": { @@ -4894,18 +4943,19 @@ } }, "keyv": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.1.1.tgz", - "integrity": "sha512-tGv1yP6snQVDSM4X6yxrv2zzq/EvpW+oYiUz6aueW1u9CtS8RzUQYxxmFwgZlO2jSgCxQbchhxaqXXp2hnKGpQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.3.2.tgz", + "integrity": "sha512-kn8WmodVBe12lmHpA6W8OY7SNh6wVR+Z+wZESF4iF5FCazaVXGWOtnbnvX0tMQ1bO+/TmOD9LziuYMvrIIs0xw==", "dev": true, "requires": { + "compress-brotli": "^1.3.8", "json-buffer": "3.0.1" } }, "lazy-ass": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", - "integrity": "sha1-eZllXoZGwX8In90YfRUNMyTVRRM=", + "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==", "dev": true }, "listr2": { @@ -4932,7 +4982,7 @@ "lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", "dev": true }, "log-symbols": { @@ -5018,18 +5068,18 @@ } }, "mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true }, "mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "requires": { - "mime-db": "1.51.0" + "mime-db": "1.52.0" } }, "mimic-fn": { @@ -5044,9 +5094,9 @@ "dev": true }, "minimatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.1.tgz", - "integrity": "sha512-reLxBcKUPNBnc/sVtAbxgRVFSegoGeLaSjmphNhcwcolhYLRgtJscn5mRl6YRZNQv40Y7P6JM2YhSIsbL9OB5A==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "requires": { "brace-expansion": "^1.1.7" } @@ -5092,14 +5142,14 @@ } }, "object-hash": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", - "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==" }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "requires": { "wrappy": "1" } @@ -5137,12 +5187,12 @@ "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==" }, "ospath": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", - "integrity": "sha1-EnZjl3Sj+O8lcvf+QoDg6kVQwHs=", + "integrity": "sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==", "dev": true }, "otplib": { @@ -5174,7 +5224,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" }, "path-key": { "version": "3.1.1", @@ -5196,13 +5246,13 @@ "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", "dev": true }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", "dev": true }, "picomatch": { @@ -5214,7 +5264,7 @@ "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true }, "prettier": { @@ -5241,7 +5291,7 @@ "proxy-from-env": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", - "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=", + "integrity": "sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==", "dev": true }, "psl": { @@ -5302,7 +5352,7 @@ "request-progress": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", - "integrity": "sha1-TKdUCBx/7GP1BeT6qCWqBs1mnb4=", + "integrity": "sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==", "dev": true, "requires": { "throttleit": "^1.0.0" @@ -5311,7 +5361,7 @@ "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" }, "resolve-alpn": { "version": "1.2.1", @@ -5373,17 +5423,17 @@ } }, "rxjs": { - "version": "7.5.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.2.tgz", - "integrity": "sha512-PwDt186XaL3QN5qXj/H9DGyHhP3/RYYgZZwqBv9Tv8rsAaiwFH1IsJJlcgD37J7UW5a6O67qX0KWKS3/pu0m4w==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", + "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", "requires": { "tslib": "^2.1.0" }, "dependencies": { "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" } } }, @@ -5398,9 +5448,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -5466,12 +5516,12 @@ "spawn-command": { "version": "0.0.2-1", "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", - "integrity": "sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A=" + "integrity": "sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==" }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, "sshpk": { "version": "1.17.0", @@ -5533,19 +5583,19 @@ "thirty-two": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/thirty-two/-/thirty-two-1.0.2.tgz", - "integrity": "sha1-TKL//AKlEpDSdEueP1V2k8prYno=", + "integrity": "sha512-OEI0IWCe+Dw46019YLl6V10Us5bi574EvlJEOcAkB29IzQ/mYD1A6RyNHLjZPiHCmuodxvgF6U+vZO1L15lxVA==", "dev": true }, "throttleit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", - "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=", + "integrity": "sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g==", "dev": true }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" }, "tmp": { "version": "0.2.1", @@ -5578,7 +5628,7 @@ "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "tree-kill": { "version": "1.2.2", @@ -5593,7 +5643,7 @@ "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, "requires": { "safe-buffer": "^5.0.1" @@ -5602,7 +5652,7 @@ "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", "dev": true }, "type-fest": { @@ -5611,9 +5661,9 @@ "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" }, "typescript": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", - "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", "dev": true }, "universalify": { @@ -5630,7 +5680,7 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "uuid": { "version": "8.3.2", @@ -5640,7 +5690,7 @@ "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", "dev": true, "requires": { "assert-plus": "^1.0.0", @@ -5690,7 +5740,7 @@ "wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "requires": { "defaults": "^1.0.3" } @@ -5698,12 +5748,12 @@ "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "requires": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -5731,13 +5781,14 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", - "dev": true + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.8.tgz", + "integrity": "sha512-ri1Id1WinAX5Jqn9HejiGb8crfRio0Qgu8+MtL36rlTA6RLsMdWt1Az/19A2Qij6uSHUMphEFaTKa4WG+UNHNw==", + "dev": true, + "requires": {} }, "y18n": { "version": "5.0.8", @@ -5781,7 +5832,7 @@ "yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", "dev": true, "requires": { "buffer-crc32": "~0.2.3", diff --git a/package.json b/package.json index 81f8e1fef44..1fcc80b0a22 100644 --- a/package.json +++ b/package.json @@ -15,9 +15,10 @@ "devDependencies": { "@ory/kratos-client": "0.0.0-next.8d3b018594f7", "@types/node": "^16.9.6", + "@types/uuid": "^8.3.4", "@types/yamljs": "^0.2.31", "chrome-remote-interface": "^0.31.0", - "cypress": "^9.5.1", + "cypress": "^9.6.0", "dayjs": "^1.10.4", "got": "^11.8.2", "ory-prettier-styles": "1.3.0", diff --git a/persistence/sql/migratest/fixtures/login_flow/0bc96cc9-dda4-4700-9e42-35731f2af91e.json b/persistence/sql/migratest/fixtures/login_flow/0bc96cc9-dda4-4700-9e42-35731f2af91e.json index e48e54d97a6..ab5b570fb78 100644 --- a/persistence/sql/migratest/fixtures/login_flow/0bc96cc9-dda4-4700-9e42-35731f2af91e.json +++ b/persistence/sql/migratest/fixtures/login_flow/0bc96cc9-dda4-4700-9e42-35731f2af91e.json @@ -1,5 +1,6 @@ { "id": "0bc96cc9-dda4-4700-9e42-35731f2af91e", + "oauth2_login_challenge": null, "type": "api", "expires_at": "2013-10-07T08:23:19Z", "issued_at": "2013-10-07T08:23:19Z", diff --git a/persistence/sql/migratest/fixtures/login_flow/1fb23c75-b809-42cc-8984-6ca2d0a1192f.json b/persistence/sql/migratest/fixtures/login_flow/1fb23c75-b809-42cc-8984-6ca2d0a1192f.json index 5f63a7ec006..d955b7c462e 100644 --- a/persistence/sql/migratest/fixtures/login_flow/1fb23c75-b809-42cc-8984-6ca2d0a1192f.json +++ b/persistence/sql/migratest/fixtures/login_flow/1fb23c75-b809-42cc-8984-6ca2d0a1192f.json @@ -1,5 +1,6 @@ { "id": "1fb23c75-b809-42cc-8984-6ca2d0a1192f", + "oauth2_login_challenge": null, "type": "api", "expires_at": "2013-10-07T08:23:19Z", "issued_at": "2013-10-07T08:23:19Z", diff --git a/persistence/sql/migratest/fixtures/login_flow/202c1981-1e25-47f0-8764-75ad506c2bec.json b/persistence/sql/migratest/fixtures/login_flow/202c1981-1e25-47f0-8764-75ad506c2bec.json index efbd0740cdf..3241be100fe 100644 --- a/persistence/sql/migratest/fixtures/login_flow/202c1981-1e25-47f0-8764-75ad506c2bec.json +++ b/persistence/sql/migratest/fixtures/login_flow/202c1981-1e25-47f0-8764-75ad506c2bec.json @@ -1,5 +1,6 @@ { "id": "202c1981-1e25-47f0-8764-75ad506c2bec", + "oauth2_login_challenge": null, "type": "browser", "expires_at": "2013-10-07T08:23:19Z", "issued_at": "2013-10-07T08:23:19Z", diff --git a/persistence/sql/migratest/fixtures/login_flow/349c945a-60f8-436a-a301-7a42c92604f9.json b/persistence/sql/migratest/fixtures/login_flow/349c945a-60f8-436a-a301-7a42c92604f9.json new file mode 100644 index 00000000000..58c5df35b67 --- /dev/null +++ b/persistence/sql/migratest/fixtures/login_flow/349c945a-60f8-436a-a301-7a42c92604f9.json @@ -0,0 +1,17 @@ +{ + "id": "349c945a-60f8-436a-a301-7a42c92604f9", + "oauth2_login_challenge": "3caddfd5-9903-4bce-83ff-cae36f42dff7", + "type": "browser", + "expires_at": "2013-10-07T08:23:19Z", + "issued_at": "2013-10-07T08:23:19Z", + "request_url": "http://kratos:4433/self-service/browser/flows/login?login_challenge=3caddfd599034bce83ffcae36f42dff7", + "ui": { + "action": "", + "method": "", + "nodes": null + }, + "created_at": "2013-10-07T08:23:19Z", + "updated_at": "2013-10-07T08:23:19Z", + "refresh": false, + "requested_aal": "aal2" +} diff --git a/persistence/sql/migratest/fixtures/login_flow/38caf592-b042-4551-b92f-8d5223c2a4e2.json b/persistence/sql/migratest/fixtures/login_flow/38caf592-b042-4551-b92f-8d5223c2a4e2.json index 084b36a0c0b..aebfc35ddcb 100644 --- a/persistence/sql/migratest/fixtures/login_flow/38caf592-b042-4551-b92f-8d5223c2a4e2.json +++ b/persistence/sql/migratest/fixtures/login_flow/38caf592-b042-4551-b92f-8d5223c2a4e2.json @@ -1,5 +1,6 @@ { "id": "38caf592-b042-4551-b92f-8d5223c2a4e2", + "oauth2_login_challenge": null, "type": "api", "expires_at": "2013-10-07T08:23:19Z", "issued_at": "2013-10-07T08:23:19Z", diff --git a/persistence/sql/migratest/fixtures/login_flow/3a9ea34f-0f12-469b-9417-3ae5795a7baa.json b/persistence/sql/migratest/fixtures/login_flow/3a9ea34f-0f12-469b-9417-3ae5795a7baa.json index 13dff119fce..87ac8cbc577 100644 --- a/persistence/sql/migratest/fixtures/login_flow/3a9ea34f-0f12-469b-9417-3ae5795a7baa.json +++ b/persistence/sql/migratest/fixtures/login_flow/3a9ea34f-0f12-469b-9417-3ae5795a7baa.json @@ -1,5 +1,6 @@ { "id": "3a9ea34f-0f12-469b-9417-3ae5795a7baa", + "oauth2_login_challenge": null, "type": "browser", "expires_at": "2013-10-07T08:23:19Z", "issued_at": "2013-10-07T08:23:19Z", diff --git a/persistence/sql/migratest/fixtures/login_flow/43c99182-bb67-47e1-b564-bb23bd8d4393.json b/persistence/sql/migratest/fixtures/login_flow/43c99182-bb67-47e1-b564-bb23bd8d4393.json index 5f1529c393b..cee695fcfea 100644 --- a/persistence/sql/migratest/fixtures/login_flow/43c99182-bb67-47e1-b564-bb23bd8d4393.json +++ b/persistence/sql/migratest/fixtures/login_flow/43c99182-bb67-47e1-b564-bb23bd8d4393.json @@ -1,5 +1,6 @@ { "id": "43c99182-bb67-47e1-b564-bb23bd8d4393", + "oauth2_login_challenge": null, "type": "browser", "expires_at": "2013-10-07T08:23:19Z", "issued_at": "2013-10-07T08:23:19Z", diff --git a/persistence/sql/migratest/fixtures/login_flow/47edd3a8-0998-4779-9469-f4b8ee4430df.json b/persistence/sql/migratest/fixtures/login_flow/47edd3a8-0998-4779-9469-f4b8ee4430df.json index fe46265a6d2..698d637c458 100644 --- a/persistence/sql/migratest/fixtures/login_flow/47edd3a8-0998-4779-9469-f4b8ee4430df.json +++ b/persistence/sql/migratest/fixtures/login_flow/47edd3a8-0998-4779-9469-f4b8ee4430df.json @@ -1,5 +1,6 @@ { "id": "47edd3a8-0998-4779-9469-f4b8ee4430df", + "oauth2_login_challenge": null, "type": "api", "expires_at": "2013-10-07T08:23:19Z", "issued_at": "2013-10-07T08:23:19Z", diff --git a/persistence/sql/migratest/fixtures/login_flow/56d94e8b-8a5d-4b7f-8a6e-3259d2b2903e.json b/persistence/sql/migratest/fixtures/login_flow/56d94e8b-8a5d-4b7f-8a6e-3259d2b2903e.json index 85156c189e4..cca989cf7d1 100644 --- a/persistence/sql/migratest/fixtures/login_flow/56d94e8b-8a5d-4b7f-8a6e-3259d2b2903e.json +++ b/persistence/sql/migratest/fixtures/login_flow/56d94e8b-8a5d-4b7f-8a6e-3259d2b2903e.json @@ -1,5 +1,6 @@ { "id": "56d94e8b-8a5d-4b7f-8a6e-3259d2b2903e", + "oauth2_login_challenge": null, "type": "browser", "expires_at": "2013-10-07T08:23:19Z", "issued_at": "2013-10-07T08:23:19Z", diff --git a/persistence/sql/migratest/fixtures/login_flow/6d387820-f2f4-4f9f-9980-a90d89e7811f.json b/persistence/sql/migratest/fixtures/login_flow/6d387820-f2f4-4f9f-9980-a90d89e7811f.json index c38727386af..87ce37ad796 100644 --- a/persistence/sql/migratest/fixtures/login_flow/6d387820-f2f4-4f9f-9980-a90d89e7811f.json +++ b/persistence/sql/migratest/fixtures/login_flow/6d387820-f2f4-4f9f-9980-a90d89e7811f.json @@ -1,5 +1,6 @@ { "id": "6d387820-f2f4-4f9f-9980-a90d89e7811f", + "oauth2_login_challenge": null, "type": "browser", "expires_at": "2013-10-07T08:23:19Z", "issued_at": "2013-10-07T08:23:19Z", diff --git a/persistence/sql/migratest/fixtures/login_flow/916ded11-aa64-4a27-b06e-96e221a509d7.json b/persistence/sql/migratest/fixtures/login_flow/916ded11-aa64-4a27-b06e-96e221a509d7.json index eb8ec21e0e3..715afad1312 100644 --- a/persistence/sql/migratest/fixtures/login_flow/916ded11-aa64-4a27-b06e-96e221a509d7.json +++ b/persistence/sql/migratest/fixtures/login_flow/916ded11-aa64-4a27-b06e-96e221a509d7.json @@ -1,5 +1,6 @@ { "id": "916ded11-aa64-4a27-b06e-96e221a509d7", + "oauth2_login_challenge": null, "type": "browser", "expires_at": "2013-10-07T08:23:19Z", "issued_at": "2013-10-07T08:23:19Z", diff --git a/persistence/sql/migratest/fixtures/login_flow/99974ce6-388c-4669-a95a-7757ee724020.json b/persistence/sql/migratest/fixtures/login_flow/99974ce6-388c-4669-a95a-7757ee724020.json index 418e16ebe69..18ea717cf9c 100644 --- a/persistence/sql/migratest/fixtures/login_flow/99974ce6-388c-4669-a95a-7757ee724020.json +++ b/persistence/sql/migratest/fixtures/login_flow/99974ce6-388c-4669-a95a-7757ee724020.json @@ -1,5 +1,6 @@ { "id": "99974ce6-388c-4669-a95a-7757ee724020", + "oauth2_login_challenge": null, "type": "browser", "expires_at": "2013-10-07T08:23:19Z", "issued_at": "2013-10-07T08:23:19Z", diff --git a/persistence/sql/migratest/fixtures/login_flow/b1fac7fb-d016-4a06-a7fe-e4eab2a0429f.json b/persistence/sql/migratest/fixtures/login_flow/b1fac7fb-d016-4a06-a7fe-e4eab2a0429f.json index 84eda2f9661..6909c4aa650 100644 --- a/persistence/sql/migratest/fixtures/login_flow/b1fac7fb-d016-4a06-a7fe-e4eab2a0429f.json +++ b/persistence/sql/migratest/fixtures/login_flow/b1fac7fb-d016-4a06-a7fe-e4eab2a0429f.json @@ -1,5 +1,6 @@ { "id": "b1fac7fb-d016-4a06-a7fe-e4eab2a0429f", + "oauth2_login_challenge": null, "type": "api", "expires_at": "2013-10-07T08:23:19Z", "issued_at": "2013-10-07T08:23:19Z", diff --git a/persistence/sql/migratest/fixtures/login_flow/d6aa1f23-88c9-4b9b-a850-392f48c7f9e8.json b/persistence/sql/migratest/fixtures/login_flow/d6aa1f23-88c9-4b9b-a850-392f48c7f9e8.json index 87ccb1d1dcd..d5dfa1ed143 100644 --- a/persistence/sql/migratest/fixtures/login_flow/d6aa1f23-88c9-4b9b-a850-392f48c7f9e8.json +++ b/persistence/sql/migratest/fixtures/login_flow/d6aa1f23-88c9-4b9b-a850-392f48c7f9e8.json @@ -1,5 +1,6 @@ { "id": "d6aa1f23-88c9-4b9b-a850-392f48c7f9e8", + "oauth2_login_challenge": null, "type": "api", "expires_at": "2013-10-07T08:23:19Z", "issued_at": "2013-10-07T08:23:19Z", diff --git a/persistence/sql/migratest/fixtures/registration_flow/05a7f09d-4ef3-41fb-958a-6ad74584b36a.json b/persistence/sql/migratest/fixtures/registration_flow/05a7f09d-4ef3-41fb-958a-6ad74584b36a.json index 1e649d64ad5..2434aecce32 100644 --- a/persistence/sql/migratest/fixtures/registration_flow/05a7f09d-4ef3-41fb-958a-6ad74584b36a.json +++ b/persistence/sql/migratest/fixtures/registration_flow/05a7f09d-4ef3-41fb-958a-6ad74584b36a.json @@ -1,5 +1,6 @@ { "id": "05a7f09d-4ef3-41fb-958a-6ad74584b36a", + "oauth2_login_challenge": null, "type": "browser", "expires_at": "2013-10-07T08:23:19Z", "issued_at": "2013-10-07T08:23:19Z", diff --git a/persistence/sql/migratest/fixtures/registration_flow/22d58184-b97d-44a5-bbaf-0aa8b4000d81.json b/persistence/sql/migratest/fixtures/registration_flow/22d58184-b97d-44a5-bbaf-0aa8b4000d81.json index 7f90a694387..46272806091 100644 --- a/persistence/sql/migratest/fixtures/registration_flow/22d58184-b97d-44a5-bbaf-0aa8b4000d81.json +++ b/persistence/sql/migratest/fixtures/registration_flow/22d58184-b97d-44a5-bbaf-0aa8b4000d81.json @@ -1,5 +1,6 @@ { "id": "22d58184-b97d-44a5-bbaf-0aa8b4000d81", + "oauth2_login_challenge": null, "type": "browser", "expires_at": "2013-10-07T08:23:19Z", "issued_at": "2013-10-07T08:23:19Z", diff --git a/persistence/sql/migratest/fixtures/registration_flow/2bf132e0-5d40-4df9-9a11-9106e5333735.json b/persistence/sql/migratest/fixtures/registration_flow/2bf132e0-5d40-4df9-9a11-9106e5333735.json index dbc832d2aa7..ac6f789af89 100644 --- a/persistence/sql/migratest/fixtures/registration_flow/2bf132e0-5d40-4df9-9a11-9106e5333735.json +++ b/persistence/sql/migratest/fixtures/registration_flow/2bf132e0-5d40-4df9-9a11-9106e5333735.json @@ -1,5 +1,6 @@ { "id": "2bf132e0-5d40-4df9-9a11-9106e5333735", + "oauth2_login_challenge": null, "type": "browser", "expires_at": "2013-10-07T08:23:19Z", "issued_at": "2013-10-07T08:23:19Z", diff --git a/persistence/sql/migratest/fixtures/registration_flow/696e7022-c466-44f6-89c6-8cf93c06a62a.json b/persistence/sql/migratest/fixtures/registration_flow/696e7022-c466-44f6-89c6-8cf93c06a62a.json index 6b627d7541f..76048be0f17 100644 --- a/persistence/sql/migratest/fixtures/registration_flow/696e7022-c466-44f6-89c6-8cf93c06a62a.json +++ b/persistence/sql/migratest/fixtures/registration_flow/696e7022-c466-44f6-89c6-8cf93c06a62a.json @@ -1,5 +1,6 @@ { "id": "696e7022-c466-44f6-89c6-8cf93c06a62a", + "oauth2_login_challenge": null, "type": "api", "expires_at": "2013-10-07T08:23:19Z", "issued_at": "2013-10-07T08:23:19Z", diff --git a/persistence/sql/migratest/fixtures/registration_flow/87fa3f43-5155-42b4-a1ad-174c2595fdaf.json b/persistence/sql/migratest/fixtures/registration_flow/87fa3f43-5155-42b4-a1ad-174c2595fdaf.json index 6a1dcdac29d..1a41a4488ca 100644 --- a/persistence/sql/migratest/fixtures/registration_flow/87fa3f43-5155-42b4-a1ad-174c2595fdaf.json +++ b/persistence/sql/migratest/fixtures/registration_flow/87fa3f43-5155-42b4-a1ad-174c2595fdaf.json @@ -1,5 +1,6 @@ { "id": "87fa3f43-5155-42b4-a1ad-174c2595fdaf", + "oauth2_login_challenge": null, "type": "browser", "expires_at": "2013-10-07T08:23:19Z", "issued_at": "2013-10-07T08:23:19Z", diff --git a/persistence/sql/migratest/fixtures/registration_flow/8ef215a9-e8d5-43b3-9aa3-cb4333562e36.json b/persistence/sql/migratest/fixtures/registration_flow/8ef215a9-e8d5-43b3-9aa3-cb4333562e36.json index ed2e8512fde..91fffa409ba 100644 --- a/persistence/sql/migratest/fixtures/registration_flow/8ef215a9-e8d5-43b3-9aa3-cb4333562e36.json +++ b/persistence/sql/migratest/fixtures/registration_flow/8ef215a9-e8d5-43b3-9aa3-cb4333562e36.json @@ -1,5 +1,6 @@ { "id": "8ef215a9-e8d5-43b3-9aa3-cb4333562e36", + "oauth2_login_challenge": null, "type": "api", "expires_at": "2013-10-07T08:23:19Z", "issued_at": "2013-10-07T08:23:19Z", diff --git a/persistence/sql/migratest/fixtures/registration_flow/8f32efdc-f6fc-4c27-a3c2-579d109eff60.json b/persistence/sql/migratest/fixtures/registration_flow/8f32efdc-f6fc-4c27-a3c2-579d109eff60.json index df3f9c39299..e6333958d0d 100644 --- a/persistence/sql/migratest/fixtures/registration_flow/8f32efdc-f6fc-4c27-a3c2-579d109eff60.json +++ b/persistence/sql/migratest/fixtures/registration_flow/8f32efdc-f6fc-4c27-a3c2-579d109eff60.json @@ -1,5 +1,6 @@ { "id": "8f32efdc-f6fc-4c27-a3c2-579d109eff60", + "oauth2_login_challenge": null, "type": "api", "expires_at": "2013-10-07T08:23:19Z", "issued_at": "2013-10-07T08:23:19Z", diff --git a/persistence/sql/migratest/fixtures/registration_flow/9edcf051-1cd0-44cc-bd2f-6ac21f0c24dd.json b/persistence/sql/migratest/fixtures/registration_flow/9edcf051-1cd0-44cc-bd2f-6ac21f0c24dd.json index 2195263f157..fb0dcdcb872 100644 --- a/persistence/sql/migratest/fixtures/registration_flow/9edcf051-1cd0-44cc-bd2f-6ac21f0c24dd.json +++ b/persistence/sql/migratest/fixtures/registration_flow/9edcf051-1cd0-44cc-bd2f-6ac21f0c24dd.json @@ -1,5 +1,6 @@ { "id": "9edcf051-1cd0-44cc-bd2f-6ac21f0c24dd", + "oauth2_login_challenge": null, "type": "browser", "expires_at": "2013-10-07T08:23:19Z", "issued_at": "2013-10-07T08:23:19Z", diff --git a/persistence/sql/migratest/fixtures/registration_flow/e2150cdc-23ac-4940-a240-6c79c27ab029.json b/persistence/sql/migratest/fixtures/registration_flow/e2150cdc-23ac-4940-a240-6c79c27ab029.json index 497f88de81b..20aad653405 100644 --- a/persistence/sql/migratest/fixtures/registration_flow/e2150cdc-23ac-4940-a240-6c79c27ab029.json +++ b/persistence/sql/migratest/fixtures/registration_flow/e2150cdc-23ac-4940-a240-6c79c27ab029.json @@ -1,5 +1,6 @@ { "id": "e2150cdc-23ac-4940-a240-6c79c27ab029", + "oauth2_login_challenge": null, "type": "api", "expires_at": "2013-10-07T08:23:19Z", "issued_at": "2013-10-07T08:23:19Z", diff --git a/persistence/sql/migratest/fixtures/registration_flow/ef18b06e-4700-4021-9949-ef783cd86be8.json b/persistence/sql/migratest/fixtures/registration_flow/ef18b06e-4700-4021-9949-ef783cd86be8.json new file mode 100644 index 00000000000..350b0c9fcd2 --- /dev/null +++ b/persistence/sql/migratest/fixtures/registration_flow/ef18b06e-4700-4021-9949-ef783cd86be8.json @@ -0,0 +1,14 @@ +{ + "id": "ef18b06e-4700-4021-9949-ef783cd86be8", + "oauth2_login_challenge": "3caddfd5-9903-4bce-83ff-cae36f42dff7", + "type": "browser", + "expires_at": "2013-10-07T08:23:19Z", + "issued_at": "2013-10-07T08:23:19Z", + "request_url": "http://kratos:4433/self-service/browser/flows/registration?login_challenge=", + "active": "password", + "ui": { + "action": "", + "method": "", + "nodes": null + } +} diff --git a/persistence/sql/migratest/fixtures/registration_flow/f1b5ed18-113a-4a98-aae7-d4eba007199c.json b/persistence/sql/migratest/fixtures/registration_flow/f1b5ed18-113a-4a98-aae7-d4eba007199c.json index d894073c546..440430b3f82 100644 --- a/persistence/sql/migratest/fixtures/registration_flow/f1b5ed18-113a-4a98-aae7-d4eba007199c.json +++ b/persistence/sql/migratest/fixtures/registration_flow/f1b5ed18-113a-4a98-aae7-d4eba007199c.json @@ -1,5 +1,6 @@ { "id": "f1b5ed18-113a-4a98-aae7-d4eba007199c", + "oauth2_login_challenge": null, "type": "api", "expires_at": "2013-10-07T08:23:19Z", "issued_at": "2013-10-07T08:23:19Z", diff --git a/persistence/sql/migratest/testdata/20220607000001_testdata.sql b/persistence/sql/migratest/testdata/20220607000001_testdata.sql new file mode 100644 index 00000000000..7093698f4bb --- /dev/null +++ b/persistence/sql/migratest/testdata/20220607000001_testdata.sql @@ -0,0 +1,11 @@ +INSERT INTO selfservice_login_flows (id, nid, request_url, issued_at, expires_at, active_method, csrf_token, created_at, updated_at, forced, type, ui, requested_aal, internal_context, oauth2_login_challenge) +VALUES ('349c945a-60f8-436a-a301-7a42c92604f9', '884f556e-eb3a-4b9f-bee3-11345642c6c0', + 'http://kratos:4433/self-service/browser/flows/login?login_challenge=3caddfd599034bce83ffcae36f42dff7', '2013-10-07 08:23:19', '2013-10-07 08:23:19', '', + 'fpeVSZ9ZH7YvUkhXsOVEIssxbfauh5lcoQSYxTcN0XkMneg1L42h+HtvisjlNjBF4ElcD2jApCHoJYq2u9sVWg==', + '2013-10-07 08:23:19', '2013-10-07 08:23:19', false, 'browser', '{}', 'aal2', '{"foo":"bar"}', '3caddfd5-9903-4bce-83ff-cae36f42dff7'); + +INSERT INTO selfservice_registration_flows (id, nid, request_url, issued_at, expires_at, active_method, csrf_token, created_at, updated_at, type, ui, internal_context, oauth2_login_challenge) +VALUES ('ef18b06e-4700-4021-9949-ef783cd86be8', '884f556e-eb3a-4b9f-bee3-11345642c6c0', + 'http://kratos:4433/self-service/browser/flows/registration?login_challenge=', '2013-10-07 08:23:19', '2013-10-07 08:23:19', + 'password', 'vYYuhWXBfXKzBC+BlnbDmXfBKsUWY6SU/v04gHF9GYzPjFP51RXDPOc57R7Dpbf+XLkbPNAkmem33Crz/avdrw==', + '2013-10-07 08:23:19', '2013-10-07 08:23:19', 'browser', '{}', '{"foo":"bar"}', '3caddfd5-9903-4bce-83ff-cae36f42dff7'); diff --git a/persistence/sql/migrations/sql/20220607000001000000_hydra_login_challenge.cockroach.down.sql b/persistence/sql/migrations/sql/20220607000001000000_hydra_login_challenge.cockroach.down.sql new file mode 100644 index 00000000000..0bf9f82d296 --- /dev/null +++ b/persistence/sql/migrations/sql/20220607000001000000_hydra_login_challenge.cockroach.down.sql @@ -0,0 +1,2 @@ +ALTER TABLE "selfservice_login_flows" DROP COLUMN "oauth2_login_challenge"; +ALTER TABLE "selfservice_registration_flows" DROP COLUMN "oauth2_login_challenge"; diff --git a/persistence/sql/migrations/sql/20220607000001000000_hydra_login_challenge.cockroach.up.sql b/persistence/sql/migrations/sql/20220607000001000000_hydra_login_challenge.cockroach.up.sql new file mode 100644 index 00000000000..8a61077cbd1 --- /dev/null +++ b/persistence/sql/migrations/sql/20220607000001000000_hydra_login_challenge.cockroach.up.sql @@ -0,0 +1,2 @@ +ALTER TABLE "selfservice_login_flows" ADD COLUMN "oauth2_login_challenge" UUID NULL; +ALTER TABLE "selfservice_registration_flows" ADD COLUMN "oauth2_login_challenge" UUID NULL; diff --git a/persistence/sql/migrations/sql/20220607000001000000_hydra_login_challenge.mysql.down.sql b/persistence/sql/migrations/sql/20220607000001000000_hydra_login_challenge.mysql.down.sql new file mode 100644 index 00000000000..c537f4631d4 --- /dev/null +++ b/persistence/sql/migrations/sql/20220607000001000000_hydra_login_challenge.mysql.down.sql @@ -0,0 +1,2 @@ +ALTER TABLE `selfservice_login_flows` DROP COLUMN `oauth2_login_challenge`; +ALTER TABLE `selfservice_registration_flows` DROP COLUMN `oauth2_login_challenge`; diff --git a/persistence/sql/migrations/sql/20220607000001000000_hydra_login_challenge.mysql.up.sql b/persistence/sql/migrations/sql/20220607000001000000_hydra_login_challenge.mysql.up.sql new file mode 100644 index 00000000000..e4e79074649 --- /dev/null +++ b/persistence/sql/migrations/sql/20220607000001000000_hydra_login_challenge.mysql.up.sql @@ -0,0 +1,2 @@ +ALTER TABLE `selfservice_login_flows` ADD COLUMN `oauth2_login_challenge` CHAR(36) NULL; +ALTER TABLE `selfservice_registration_flows` ADD COLUMN `oauth2_login_challenge` CHAR(36) NULL; diff --git a/persistence/sql/migrations/sql/20220607000001000000_hydra_login_challenge.postgres.down.sql b/persistence/sql/migrations/sql/20220607000001000000_hydra_login_challenge.postgres.down.sql new file mode 100644 index 00000000000..0bf9f82d296 --- /dev/null +++ b/persistence/sql/migrations/sql/20220607000001000000_hydra_login_challenge.postgres.down.sql @@ -0,0 +1,2 @@ +ALTER TABLE "selfservice_login_flows" DROP COLUMN "oauth2_login_challenge"; +ALTER TABLE "selfservice_registration_flows" DROP COLUMN "oauth2_login_challenge"; diff --git a/persistence/sql/migrations/sql/20220607000001000000_hydra_login_challenge.postgres.up.sql b/persistence/sql/migrations/sql/20220607000001000000_hydra_login_challenge.postgres.up.sql new file mode 100644 index 00000000000..8a61077cbd1 --- /dev/null +++ b/persistence/sql/migrations/sql/20220607000001000000_hydra_login_challenge.postgres.up.sql @@ -0,0 +1,2 @@ +ALTER TABLE "selfservice_login_flows" ADD COLUMN "oauth2_login_challenge" UUID NULL; +ALTER TABLE "selfservice_registration_flows" ADD COLUMN "oauth2_login_challenge" UUID NULL; diff --git a/persistence/sql/migrations/sql/20220607000001000000_hydra_login_challenge.sqlite3.down.sql b/persistence/sql/migrations/sql/20220607000001000000_hydra_login_challenge.sqlite3.down.sql new file mode 100644 index 00000000000..0bf9f82d296 --- /dev/null +++ b/persistence/sql/migrations/sql/20220607000001000000_hydra_login_challenge.sqlite3.down.sql @@ -0,0 +1,2 @@ +ALTER TABLE "selfservice_login_flows" DROP COLUMN "oauth2_login_challenge"; +ALTER TABLE "selfservice_registration_flows" DROP COLUMN "oauth2_login_challenge"; diff --git a/persistence/sql/migrations/sql/20220607000001000000_hydra_login_challenge.sqlite3.up.sql b/persistence/sql/migrations/sql/20220607000001000000_hydra_login_challenge.sqlite3.up.sql new file mode 100644 index 00000000000..be22767a2fd --- /dev/null +++ b/persistence/sql/migrations/sql/20220607000001000000_hydra_login_challenge.sqlite3.up.sql @@ -0,0 +1,2 @@ +ALTER TABLE "selfservice_login_flows" ADD COLUMN "oauth2_login_challenge" CHAR(36) NULL; +ALTER TABLE "selfservice_registration_flows" ADD COLUMN "oauth2_login_challenge" CHAR(36) NULL; diff --git a/request/builder_test.go b/request/builder_test.go index 10a3dd0f882..5b993f1f3b1 100644 --- a/request/builder_test.go +++ b/request/builder_test.go @@ -103,7 +103,7 @@ func TestBuildRequest(t *testing.T) { rawConfig: `{ "url": "https://test.kratos.ory.sh/my_endpoint2", "method": "POST", - "header": { + "headers": { "Custom-Header": "test" }, "body": "file://./stub/test_body.jsonnet" @@ -194,7 +194,7 @@ func TestBuildRequest(t *testing.T) { "url": "https://test.kratos.ory.sh/my_endpoint6", "method": "POST", "body": "file://./stub/test_body.jsonnet", - "header": { + "headers": { "Content-Type": "application/x-www-form-urlencoded" }, "auth": { diff --git a/request/config.go b/request/config.go index caf5061bf32..085b18a76a7 100644 --- a/request/config.go +++ b/request/config.go @@ -17,7 +17,7 @@ type ( Method string `json:"method"` URL string `json:"url"` TemplateURI string `json:"body"` - Header http.Header `json:"header"` + Header http.Header `json:"headers"` Auth Auth `json:"auth,omitempty"` } ) @@ -27,7 +27,7 @@ func parseConfig(r json.RawMessage) (*Config, error) { Method string `json:"method"` URL string `json:"url"` TemplateURI string `json:"body"` - Header json.RawMessage `json:"header"` + Header json.RawMessage `json:"headers"` Auth Auth `json:"auth,omitempty"` } diff --git a/selfservice/flow/login/export_test.go b/selfservice/flow/login/export_test.go new file mode 100644 index 00000000000..e3566e815eb --- /dev/null +++ b/selfservice/flow/login/export_test.go @@ -0,0 +1,11 @@ +package login + +import ( + "net/http" + + "github.com/ory/kratos/session" +) + +func RequiresAAL2ForTest(e HookExecutor, r *http.Request, s *session.Session) (bool, error) { + return e.requiresAAL2(r, s, nil) // *login.Flow is nil to avoid an import cycle +} diff --git a/selfservice/flow/login/flow.go b/selfservice/flow/login/flow.go index b25e16e9fc7..b8cfedbb830 100644 --- a/selfservice/flow/login/flow.go +++ b/selfservice/flow/login/flow.go @@ -17,7 +17,10 @@ import ( "github.com/ory/x/stringsx" + hydraclientgo "github.com/ory/hydra-client-go" + "github.com/ory/kratos/driver/config" + "github.com/ory/kratos/hydra" "github.com/ory/kratos/ui/container" @@ -47,6 +50,18 @@ type Flow struct { ID uuid.UUID `json:"id" faker:"-" db:"id" rw:"r"` NID uuid.UUID `json:"-" faker:"-" db:"nid"` + // Ory OAuth 2.0 Login Challenge. + // + // This value is set using the `login_challenge` query parameter of the registration and login endpoints. + // If set will cooperate with Ory OAuth2 and OpenID to act as an OAuth2 server / OpenID Provider. + OAuth2LoginChallenge uuid.NullUUID `json:"oauth2_login_challenge,omitempty" faker:"-" db:"oauth2_login_challenge"` + + // HydraLoginRequest is an optional field whose presence indicates that Kratos + // is being used as an identity provider in a Hydra OAuth2 flow. Kratos + // populates this field by retrieving its value from Hydra and it is used by + // the login and consent UIs. + HydraLoginRequest *hydraclientgo.LoginRequest `json:"oauth2_login_request,omitempty" faker:"-" db:"-"` + // Type represents the flow's type which can be either "api" or "browser", depending on the flow interaction. // // required: true @@ -119,10 +134,16 @@ func NewFlow(conf *config.Config, exp time.Duration, csrf string, r *http.Reques return nil, err } + hlc, err := hydra.GetLoginChallengeID(conf, r) + if err != nil { + return nil, err + } + return &Flow{ - ID: id, - ExpiresAt: now.Add(exp), - IssuedAt: now, + ID: id, + OAuth2LoginChallenge: hlc, + ExpiresAt: now.Add(exp), + IssuedAt: now, UI: &container.Container{ Method: "POST", Action: flow.AppendFlowTo(urlx.AppendPaths(conf.SelfPublicURL(r.Context()), RouteSubmitFlow), id).String(), diff --git a/selfservice/flow/login/flow_test.go b/selfservice/flow/login/flow_test.go index 5a47a2167a1..7dcee257386 100644 --- a/selfservice/flow/login/flow_test.go +++ b/selfservice/flow/login/flow_test.go @@ -15,6 +15,7 @@ import ( "github.com/ory/x/jsonx" + "github.com/ory/kratos/driver/config" "github.com/ory/kratos/identity" "github.com/ory/kratos/internal" @@ -111,6 +112,18 @@ func TestNewFlow(t *testing.T) { assert.Equal(t, "http://ory.sh/", r.RequestURL) }) }) + + t.Run("should parse login_challenge when Hydra is configured", func(t *testing.T) { + _, err := login.NewFlow(conf, 0, "csrf", &http.Request{URL: urlx.ParseOrPanic("https://ory.sh/?login_challenge=badee1"), Host: "ory.sh"}, flow.TypeBrowser) + require.Error(t, err) + + conf.MustSet(ctx, config.ViperKeyOAuth2ProviderURL, "https://hydra") + + r, err := login.NewFlow(conf, 0, "csrf", &http.Request{URL: urlx.ParseOrPanic("https://ory.sh/?login_challenge=8aadcb8fc1334186a84c4da9813356d9"), Host: "ory.sh"}, flow.TypeBrowser) + require.NoError(t, err) + assert.Equal(t, "8aadcb8f-c133-4186-a84c-4da9813356d9", r.OAuth2LoginChallenge.UUID.String()) + }) + } func TestFlow(t *testing.T) { diff --git a/selfservice/flow/login/handler.go b/selfservice/flow/login/handler.go index 1612a30ef9c..ae3adbe01ac 100644 --- a/selfservice/flow/login/handler.go +++ b/selfservice/flow/login/handler.go @@ -2,11 +2,15 @@ package login import ( "net/http" + "net/url" "time" "github.com/gofrs/uuid" "github.com/ory/herodot" + hydraclientgo "github.com/ory/hydra-client-go" + + "github.com/ory/kratos/hydra" "github.com/ory/kratos/text" "github.com/ory/x/stringsx" @@ -43,6 +47,7 @@ type ( HookExecutorProvider FlowPersistenceProvider errorx.ManagementProvider + hydra.HydraProvider StrategyProvider session.HandlerProvider session.ManagementProvider @@ -94,11 +99,11 @@ func WithFlowReturnTo(returnTo string) FlowOption { } } -func (h *Handler) NewLoginFlow(w http.ResponseWriter, r *http.Request, ft flow.Type, opts ...FlowOption) (*Flow, error) { +func (h *Handler) NewLoginFlow(w http.ResponseWriter, r *http.Request, ft flow.Type, opts ...FlowOption) (*Flow, *session.Session, error) { conf := h.d.Config() f, err := NewFlow(conf, conf.SelfServiceFlowLoginRequestLifespan(r.Context()), h.d.GenerateCSRFToken(r), r, ft) if err != nil { - return nil, err + return nil, nil, err } for _, o := range opts { o(f) @@ -114,7 +119,7 @@ func (h *Handler) NewLoginFlow(w http.ResponseWriter, r *http.Request, ft flow.T case cs.AddCase(string(identity.AuthenticatorAssuranceLevel2)): f.RequestedAAL = identity.AuthenticatorAssuranceLevel2 default: - return nil, errors.WithStack(herodot.ErrBadRequest.WithReasonf("Unable to parse AuthenticationMethod Assurance Level (AAL): %s", cs.ToUnknownCaseErr())) + return nil, nil, errors.WithStack(herodot.ErrBadRequest.WithReasonf("Unable to parse AuthenticationMethod Assurance Level (AAL): %s", cs.ToUnknownCaseErr())) } // We assume an error means the user has no session @@ -124,7 +129,7 @@ func (h *Handler) NewLoginFlow(w http.ResponseWriter, r *http.Request, ft flow.T // We can not request an AAL > 1 because we must first verify the first factor. if f.RequestedAAL > identity.AuthenticatorAssuranceLevel1 { - return nil, errors.WithStack(ErrSessionRequiredForHigherAAL) + return nil, nil, errors.WithStack(ErrSessionRequiredForHigherAAL) } // We are setting refresh to false if no session exists. @@ -133,7 +138,7 @@ func (h *Handler) NewLoginFlow(w http.ResponseWriter, r *http.Request, ft flow.T goto preLoginHook } else if err != nil { // Some other error happened - return that one. - return nil, err + return nil, nil, err } else { // A session exists already if f.Refresh { @@ -145,13 +150,13 @@ func (h *Handler) NewLoginFlow(w http.ResponseWriter, r *http.Request, ft flow.T // If level is 1 we are not requesting AAL -> we are logged in already. if f.RequestedAAL == identity.AuthenticatorAssuranceLevel1 { - return nil, errors.WithStack(ErrAlreadyLoggedIn) + return nil, sess, errors.WithStack(ErrAlreadyLoggedIn) } // We are requesting an assurance level which the session already has. So we are not upgrading the session // in which case we want to return an error. if f.RequestedAAL <= sess.AuthenticatorAssuranceLevel { - return nil, errors.WithStack(ErrAlreadyLoggedIn) + return nil, sess, errors.WithStack(ErrAlreadyLoggedIn) } // Looks like we are requesting an AAL which is higher than what the session has. @@ -170,12 +175,12 @@ preLoginHook: var s Strategy for _, s = range h.d.LoginStrategies(r.Context()) { if err := s.PopulateLoginMethod(r, f.RequestedAAL, f); err != nil { - return nil, err + return nil, nil, err } } if err := sortNodes(r.Context(), f.UI.Nodes); err != nil { - return nil, err + return nil, nil, err } if f.Type == flow.TypeBrowser { @@ -184,18 +189,18 @@ preLoginHook: if err := h.d.LoginHookExecutor().PreLoginHook(w, r, f); err != nil { h.d.LoginFlowErrorHandler().WriteFlowError(w, r, f, node.DefaultGroup, err) - return f, nil + return f, sess, nil } if err := h.d.LoginFlowPersister().CreateLoginFlow(r.Context(), f); err != nil { - return nil, err + return nil, nil, err } - return f, nil + return f, nil, nil } func (h *Handler) FromOldFlow(w http.ResponseWriter, r *http.Request, of Flow) (*Flow, error) { - nf, err := h.NewLoginFlow(w, r, of.Type) + nf, _, err := h.NewLoginFlow(w, r, of.Type) if err != nil { return nil, err } @@ -267,7 +272,7 @@ type initializeSelfServiceLoginFlowWithoutBrowser struct { // 400: jsonError // 500: jsonError func (h *Handler) initAPIFlow(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { - f, err := h.NewLoginFlow(w, r, flow.TypeAPI) + f, _, err := h.NewLoginFlow(w, r, flow.TypeAPI) if err != nil { h.d.Writer().WriteError(w, r, err) return @@ -279,6 +284,16 @@ func (h *Handler) initAPIFlow(w http.ResponseWriter, r *http.Request, _ httprout // nolint:deadcode,unused // swagger:parameters initializeSelfServiceLoginFlowForBrowsers type initializeSelfServiceLoginFlowForBrowsers struct { + // An optional Hydra login challenge. If present, Kratos will cooperate with + // Ory Hydra to act as an OAuth2 identity provider. + // + // The value for this parameter comes from `login_challenge` URL Query parameter sent to your + // application (e.g. `/login?login_challenge=abcde`). + // + // required: false + // in: query + HydraLoginChallenge string `json:"login_challenge"` + // Refresh a login session // // If set to true, this will refresh an existing login session by @@ -333,6 +348,10 @@ type initializeSelfServiceLoginFlowForBrowsers struct { // - `security_csrf_violation`: Unable to fetch the flow because a CSRF violation occurred. // - `security_identity_mismatch`: The requested `?return_to` address is not allowed to be used. Adjust this in the configuration! // +// The optional query parameter login_challenge is set when using Kratos with +// Hydra in an OAuth2 flow. See the oauth2_provider.url configuration +// option. +// // This endpoint is NOT INTENDED for clients that do not have a browser (Chrome, Firefox, ...) as cookies are needed. // // More information can be found at [Ory Kratos User Login](https://www.ory.sh/docs/kratos/self-service/flows/user-login) and [User Registration Documentation](https://www.ory.sh/docs/kratos/self-service/flows/user-registration). @@ -348,8 +367,52 @@ type initializeSelfServiceLoginFlowForBrowsers struct { // 400: jsonError // 500: jsonError func (h *Handler) initBrowserFlow(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - a, err := h.NewLoginFlow(w, r, flow.TypeBrowser) + var hlr *hydraclientgo.LoginRequest + var hlc uuid.NullUUID + if r.URL.Query().Has("login_challenge") { + var err error + hlc, err = hydra.GetLoginChallengeID(h.d.Config(), r) + if err != nil { + h.d.SelfServiceErrorManager().Forward(r.Context(), w, r, err) + return + } + + hlr, err = h.d.Hydra().GetLoginRequest(r.Context(), hlc) + if err != nil { + h.d.SelfServiceErrorManager().Forward(r.Context(), w, r, errors.WithStack(herodot.ErrInternalServerError.WithReason("Failed to retrieve OAuth 2.0 login request."))) + return + } + + if !hlr.GetSkip() { + q := r.URL.Query() + q.Set("refresh", "true") + r.URL.RawQuery = q.Encode() + } + } + + a, sess, err := h.NewLoginFlow(w, r, flow.TypeBrowser) if errors.Is(err, ErrAlreadyLoggedIn) { + if hlr != nil { + if !hlr.GetSkip() { + h.d.SelfServiceErrorManager().Forward(r.Context(), w, r, errors.WithStack(herodot.ErrInternalServerError.WithReason("ErrAlreadyLoggedIn indicated we can skip login, but Hydra asked us to refresh"))) + return + } + + rt, err := h.d.Hydra().AcceptLoginRequest(r.Context(), hlc.UUID, sess.IdentityID.String(), sess.AMR) + + if err != nil { + h.d.SelfServiceErrorManager().Forward(r.Context(), w, r, err) + return + } + returnTo, err := url.Parse(rt) + if err != nil { + h.d.SelfServiceErrorManager().Forward(r.Context(), w, r, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Unable to parse URL: %s", rt))) + return + } + x.AcceptToRedirectOrJSON(w, r, h.d.Writer(), err, returnTo.String()) + return + } + returnTo, redirErr := x.SecureRedirectTo(r, h.d.Config().SelfServiceBrowserDefaultReturnTo(r.Context()), x.SecureRedirectAllowSelfServiceURLs(h.d.Config().SelfPublicURL(r.Context())), x.SecureRedirectAllowURLs(h.d.Config().SelfServiceBrowserAllowedReturnToDomains(r.Context())), @@ -461,6 +524,17 @@ func (h *Handler) fetchFlow(w http.ResponseWriter, r *http.Request, _ httprouter return } + if ar.OAuth2LoginChallenge.Valid { + hlr, err := h.d.Hydra().GetLoginRequest(r.Context(), ar.OAuth2LoginChallenge) + if err != nil { + // We don't redirect back to the third party on errors because Hydra doesn't + // give us the 3rd party return_uri when it redirects to the login UI. + h.d.SelfServiceErrorManager().Forward(r.Context(), w, r, err) + return + } + ar.HydraLoginRequest = hlr + } + h.d.Writer().Write(w, r, ar) } diff --git a/selfservice/flow/login/handler_test.go b/selfservice/flow/login/handler_test.go index b6c07ed858c..2508061bbf2 100644 --- a/selfservice/flow/login/handler_test.go +++ b/selfservice/flow/login/handler_test.go @@ -15,6 +15,7 @@ import ( "github.com/ory/x/sqlxx" + "github.com/ory/kratos/hydra" "github.com/ory/kratos/selfservice/flow" "github.com/ory/kratos/ui/container" @@ -46,6 +47,7 @@ func init() { func TestFlowLifecycle(t *testing.T) { ctx := context.Background() conf, reg := internal.NewFastRegistryWithMocks(t) + reg.WithHydra(hydra.NewFakeHydra()) router := x.NewRouterPublic() ts, _ := testhelpers.NewKratosServerWithRouters(t, reg, router, x.NewRouterAdmin()) loginTS := testhelpers.NewLoginUIFlowEchoServer(t, reg) @@ -551,6 +553,19 @@ func TestFlowLifecycle(t *testing.T) { require.Equal(t, http.StatusSeeOther, res.StatusCode) defer res.Body.Close() }) + + t.Run("case=refuses to parse oauth2 login challenge when Hydra is not configured", func(t *testing.T) { + res, body := initAuthenticatedFlow(t, url.Values{"login_challenge": {hydra.FAKE_GET_LOGIN_REQUEST_RETURN_NIL_NIL}}, false) + require.Contains(t, res.Request.URL.String(), errorTS.URL) + require.Contains(t, string(body), "refusing to parse") + }) + + conf.MustSet(ctx, config.ViperKeyOAuth2ProviderURL, "https://fake-hydra") + + t.Run("case=oauth2 flow init succeeds", func(t *testing.T) { + res, _ := initAuthenticatedFlow(t, url.Values{"login_challenge": {hydra.FAKE_SUCCESS}}, false) + require.Contains(t, res.Request.URL.String(), loginTS.URL) + }) }) t.Run("case=relative redirect when self-service login ui is a relative URL", func(t *testing.T) { diff --git a/selfservice/flow/login/hook.go b/selfservice/flow/login/hook.go index ff1f98d9b63..eddafe0b803 100644 --- a/selfservice/flow/login/hook.go +++ b/selfservice/flow/login/hook.go @@ -9,6 +9,7 @@ import ( "github.com/pkg/errors" "github.com/ory/kratos/driver/config" + "github.com/ory/kratos/hydra" "github.com/ory/kratos/identity" "github.com/ory/kratos/selfservice/flow" "github.com/ory/kratos/session" @@ -35,6 +36,7 @@ type ( type ( executorDependencies interface { config.Provider + hydra.HydraProvider session.ManagementProvider session.PersistenceProvider x.CSRFTokenGeneratorProvider @@ -63,18 +65,19 @@ func NewHookExecutor(d executorDependencies) *HookExecutor { return &HookExecutor{d: d} } -func (e *HookExecutor) requiresAAL2(r *http.Request, s *session.Session, a *Flow) (*session.ErrAALNotSatisfied, bool) { - var aalErr *session.ErrAALNotSatisfied +func (e *HookExecutor) requiresAAL2(r *http.Request, s *session.Session, a *Flow) (bool, error) { err := e.d.SessionManager().DoesSessionSatisfy(r, s, e.d.Config().SessionWhoAmIAAL(r.Context())) - if ok := errors.As(err, &aalErr); !ok { - return nil, false - } - if err := aalErr.PassReturnToParameter(a.RequestURL); err != nil { - return nil, false + if aalErr := new(session.ErrAALNotSatisfied); errors.As(err, &aalErr) { + if aalErr.PassReturnToAndLoginChallengeParameters(a.RequestURL) != nil { + _ = aalErr.WithDetail("pass_request_params_error", "failed to pass request parameters to aalErr.RedirectTo") + } + return true, aalErr + } else if err != nil { + return true, errors.WithStack(err) } - return aalErr, true + return false, nil } func (e *HookExecutor) handleLoginError(_ http.ResponseWriter, r *http.Request, g node.UiNodeGroup, f *Flow, i *identity.Identity, flowError error) error { @@ -162,7 +165,7 @@ func (e *HookExecutor) PostLoginHook(w http.ResponseWriter, r *http.Request, g n Info("Identity authenticated successfully and was issued an Ory Kratos Session Token.") response := &APIFlowResponse{Session: s, Token: s.Token} - if _, required := e.requiresAAL2(r, s, a); required { + if required, _ := e.requiresAAL2(r, s, a); required { // If AAL is not satisfied, we omit the identity to preserve the user's privacy in case of a phishing attack. response.Session.Identity = nil } @@ -186,7 +189,7 @@ func (e *HookExecutor) PostLoginHook(w http.ResponseWriter, r *http.Request, g n s.Token = "" response := &APIFlowResponse{Session: s} - if _, required := e.requiresAAL2(r, s, a); required { + if required, _ := e.requiresAAL2(r, s, a); required { // If AAL is not satisfied, we omit the identity to preserve the user's privacy in case of a phishing attack. response.Session.Identity = nil } @@ -195,12 +198,24 @@ func (e *HookExecutor) PostLoginHook(w http.ResponseWriter, r *http.Request, g n } // If we detect that whoami would require a higher AAL, we redirect! - if aalErr, required := e.requiresAAL2(r, s, a); required { - http.Redirect(w, r, aalErr.RedirectTo, http.StatusSeeOther) - return nil + if _, err := e.requiresAAL2(r, s, a); err != nil { + if aalErr := new(session.ErrAALNotSatisfied); errors.As(err, &aalErr) { + http.Redirect(w, r, aalErr.RedirectTo, http.StatusSeeOther) + return nil + } + return errors.WithStack(err) + } + + finalReturnTo := returnTo.String() + if a.OAuth2LoginChallenge.Valid { + rt, err := e.d.Hydra().AcceptLoginRequest(r.Context(), a.OAuth2LoginChallenge.UUID, i.ID.String(), s.AMR) + if err != nil { + return err + } + finalReturnTo = rt } - x.ContentNegotiationRedirection(w, r, s.Declassify(), e.d.Writer(), returnTo.String()) + x.ContentNegotiationRedirection(w, r, s.Declassify(), e.d.Writer(), finalReturnTo) return nil } diff --git a/selfservice/flow/login/hook_test.go b/selfservice/flow/login/hook_test.go index 3f2cf7a237a..1821a7f29dd 100644 --- a/selfservice/flow/login/hook_test.go +++ b/selfservice/flow/login/hook_test.go @@ -247,6 +247,12 @@ func TestLoginExecutor(t *testing.T) { conf, )) }) + + t.Run("requiresAAL2 should return true if there's an error", func(t *testing.T) { + requiresAAL2, err := login.RequiresAAL2ForTest(*reg.LoginHookExecutor(), &http.Request{}, &session.Session{}) + require.NotNil(t, err) + require.True(t, requiresAAL2) + }) }) } } diff --git a/selfservice/flow/registration/flow.go b/selfservice/flow/registration/flow.go index eac408c4519..cf3f3ba7e79 100644 --- a/selfservice/flow/registration/flow.go +++ b/selfservice/flow/registration/flow.go @@ -13,7 +13,10 @@ import ( "github.com/ory/x/sqlxx" + hydraclientgo "github.com/ory/hydra-client-go" + "github.com/ory/kratos/driver/config" + "github.com/ory/kratos/hydra" "github.com/ory/kratos/ui/container" "github.com/gofrs/uuid" @@ -34,6 +37,18 @@ type Flow struct { // required: true ID uuid.UUID `json:"id" faker:"-" db:"id"` + // Ory OAuth 2.0 Login Challenge. + // + // This value is set using the `login_challenge` query parameter of the registration and login endpoints. + // If set will cooperate with Ory OAuth2 and OpenID to act as an OAuth2 server / OpenID Provider. + OAuth2LoginChallenge uuid.NullUUID `json:"oauth2_login_challenge,omitempty" faker:"-" db:"oauth2_login_challenge"` + + // HydraLoginRequest is an optional field whose presence indicates that Kratos + // is being used as an identity provider in a Hydra OAuth2 flow. Kratos + // populates this field by retrieving its value from Hydra and it is used by + // the login and consent UIs. + HydraLoginRequest *hydraclientgo.LoginRequest `json:"oauth2_login_request,omitempty" faker:"-" db:"-"` + // Type represents the flow's type which can be either "api" or "browser", depending on the flow interaction. // // required: true @@ -98,11 +113,17 @@ func NewFlow(conf *config.Config, exp time.Duration, csrf string, r *http.Reques return nil, err } + hlc, err := hydra.GetLoginChallengeID(conf, r) + if err != nil { + return nil, err + } + return &Flow{ - ID: id, - ExpiresAt: now.Add(exp), - IssuedAt: now, - RequestURL: requestURL, + ID: id, + OAuth2LoginChallenge: hlc, + ExpiresAt: now.Add(exp), + IssuedAt: now, + RequestURL: requestURL, UI: &container.Container{ Method: "POST", Action: flow.AppendFlowTo(urlx.AppendPaths(conf.SelfPublicURL(r.Context()), RouteSubmitFlow), id).String(), diff --git a/selfservice/flow/registration/flow_test.go b/selfservice/flow/registration/flow_test.go index bb36c851628..938c995d49d 100644 --- a/selfservice/flow/registration/flow_test.go +++ b/selfservice/flow/registration/flow_test.go @@ -15,6 +15,7 @@ import ( "github.com/ory/x/jsonx" + "github.com/ory/kratos/driver/config" "github.com/ory/kratos/internal" "github.com/bxcodec/faker/v3" @@ -78,6 +79,17 @@ func TestNewFlow(t *testing.T) { require.NoError(t, err) assert.Equal(t, "https://ory.sh/", r.RequestURL) }) + + t.Run("should parse login_challenge when Hydra is configured", func(t *testing.T) { + _, err := registration.NewFlow(conf, 0, "csrf", &http.Request{URL: urlx.ParseOrPanic("https://ory.sh/?login_challenge=badee1"), Host: "ory.sh"}, flow.TypeBrowser) + require.Error(t, err) + + conf.MustSet(ctx, config.ViperKeyOAuth2ProviderURL, "https://hydra") + + r, err := registration.NewFlow(conf, 0, "csrf", &http.Request{URL: urlx.ParseOrPanic("https://ory.sh/?login_challenge=8aadcb8fc1334186a84c4da9813356d9"), Host: "ory.sh"}, flow.TypeBrowser) + require.NoError(t, err) + assert.Equal(t, "8aadcb8f-c133-4186-a84c-4da9813356d9", r.OAuth2LoginChallenge.UUID.String()) + }) } func TestFlow(t *testing.T) { diff --git a/selfservice/flow/registration/handler.go b/selfservice/flow/registration/handler.go index de36b755e9c..e3199dc3429 100644 --- a/selfservice/flow/registration/handler.go +++ b/selfservice/flow/registration/handler.go @@ -2,8 +2,10 @@ package registration import ( "net/http" + "net/url" "time" + "github.com/ory/kratos/hydra" "github.com/ory/kratos/text" "github.com/ory/nosurf" @@ -21,6 +23,7 @@ import ( "github.com/ory/kratos/driver/config" "github.com/ory/kratos/selfservice/errorx" "github.com/ory/kratos/selfservice/flow" + "github.com/ory/kratos/selfservice/flow/logout" "github.com/ory/kratos/session" "github.com/ory/kratos/x" ) @@ -38,6 +41,7 @@ type ( handlerDependencies interface { config.Provider errorx.ManagementProvider + hydra.HydraProvider session.HandlerProvider session.ManagementProvider x.WriterProvider @@ -191,6 +195,19 @@ func (h *Handler) initApiFlow(w http.ResponseWriter, r *http.Request, _ httprout // nolint:deadcode,unused // swagger:parameters initializeSelfServiceRegistrationFlowForBrowsers type initializeSelfServiceRegistrationFlowForBrowsers struct { + // Ory OAuth 2.0 Login Challenge. + // + // If set will cooperate with Ory OAuth2 and OpenID to act as an OAuth2 server / OpenID Provider. + // + // The value for this parameter comes from `login_challenge` URL Query parameter sent to your + // application (e.g. `/registration?login_challenge=abcde`). + // + // This feature is compatible with Ory Hydra when not running on the Ory Network. + // + // required: false + // in: query + LoginChallenge string `json:"login_challenge"` + // The URL to return the browser to after the flow was completed. // // in: query @@ -243,7 +260,26 @@ func (h *Handler) initBrowserFlow(w http.ResponseWriter, r *http.Request, ps htt return } - if _, err := h.d.SessionManager().FetchFromRequest(r.Context(), r); err == nil { + if sess, err := h.d.SessionManager().FetchFromRequest(r.Context(), r); err == nil { + if r.URL.Query().Has("login_challenge") { + logoutUrl := urlx.AppendPaths(h.d.Config().SelfPublicURL(r.Context()), logout.RouteSubmitFlow) + self := urlx.CopyWithQuery( + urlx.AppendPaths(h.d.Config().SelfPublicURL(r.Context()), RouteInitBrowserFlow), + r.URL.Query(), + ).String() + + http.Redirect( + w, + r, + urlx.CopyWithQuery(logoutUrl, url.Values{ + "token": {sess.LogoutToken}, + "return_to": {self}, + }).String(), + http.StatusFound, + ) + return + } + if x.IsJSONRequest(r) { h.d.Writer().WriteError(w, r, errors.WithStack(ErrAlreadyLoggedIn)) return @@ -354,6 +390,17 @@ func (h *Handler) fetchFlow(w http.ResponseWriter, r *http.Request, ps httproute return } + if ar.OAuth2LoginChallenge.Valid { + hlr, err := h.d.Hydra().GetLoginRequest(r.Context(), ar.OAuth2LoginChallenge) + if err != nil { + // We don't redirect back to the third party on errors because Hydra doesn't + // give us the 3rd party return_uri when it redirects to the login UI. + h.d.SelfServiceErrorManager().Forward(r.Context(), w, r, err) + return + } + ar.HydraLoginRequest = hlr + } + h.d.Writer().Write(w, r, ar) } diff --git a/selfservice/flow/registration/hook.go b/selfservice/flow/registration/hook.go index 3fe483a72b8..d2120480ccb 100644 --- a/selfservice/flow/registration/hook.go +++ b/selfservice/flow/registration/hook.go @@ -11,6 +11,7 @@ import ( "github.com/ory/x/sqlcon" "github.com/ory/kratos/driver/config" + "github.com/ory/kratos/hydra" "github.com/ory/kratos/identity" "github.com/ory/kratos/schema" "github.com/ory/kratos/selfservice/flow" @@ -69,7 +70,9 @@ type ( session.PersistenceProvider session.ManagementProvider HooksProvider + hydra.HydraProvider x.CSRFTokenGeneratorProvider + x.HTTPClientProvider x.LoggingProvider x.WriterProvider } @@ -202,7 +205,16 @@ func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Reque return nil } - x.ContentNegotiationRedirection(w, r, s.Declassify(), e.d.Writer(), returnTo.String()) + finalReturnTo := returnTo.String() + if a.OAuth2LoginChallenge.Valid { + cr, err := e.d.Hydra().AcceptLoginRequest(r.Context(), a.OAuth2LoginChallenge.UUID, i.ID.String(), s.AMR) + if err != nil { + return err + } + finalReturnTo = cr + } + + x.ContentNegotiationRedirection(w, r, s.Declassify(), e.d.Writer(), finalReturnTo) return nil } diff --git a/selfservice/strategy/lookup/login_test.go b/selfservice/strategy/lookup/login_test.go index 8964bc8098e..34fa084620d 100644 --- a/selfservice/strategy/lookup/login_test.go +++ b/selfservice/strategy/lookup/login_test.go @@ -89,7 +89,7 @@ func TestCompleteLogin(t *testing.T) { } doBrowserFlowWithClient := func(t *testing.T, spa bool, v func(url.Values), id *identity.Identity, browserClient *http.Client, forced bool) (string, *http.Response) { - f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, forced, spa, testhelpers.InitFlowWithAAL(identity.AuthenticatorAssuranceLevel2)) + f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, forced, spa, false, false, testhelpers.InitFlowWithAAL(identity.AuthenticatorAssuranceLevel2)) values := testhelpers.SDKFormFieldsToURLValues(f.Ui.Nodes) values.Set("method", identity.CredentialsTypeLookup.String()) v(values) diff --git a/selfservice/strategy/oidc/strategy_helper_test.go b/selfservice/strategy/oidc/strategy_helper_test.go index 2f072cd96d6..3d735d7ed16 100644 --- a/selfservice/strategy/oidc/strategy_helper_test.go +++ b/selfservice/strategy/oidc/strategy_helper_test.go @@ -7,7 +7,6 @@ import ( "fmt" "io" "net/http" - "net/http/cookiejar" "net/http/httptest" "net/url" "os" @@ -302,29 +301,6 @@ func viperSetProviderConfig(t *testing.T, conf *config.Config, providers ...oidc conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+"."+string(identity.CredentialsTypeOIDC)+".enabled", true) } -func newClient(t *testing.T, jar *cookiejar.Jar) *http.Client { - if jar == nil { - j, err := cookiejar.New(nil) - jar = j - require.NoError(t, err) - } - return &http.Client{ - Jar: jar, - CheckRedirect: func(req *http.Request, via []*http.Request) error { - if debugRedirects { - t.Logf("Redirect: %s", req.URL.String()) - } - if len(via) >= 20 { - for k, v := range via { - t.Logf("Failed with redirect (%d): %s", k, v.URL.String()) - } - return errors.New("stopped after 20 redirects") - } - return nil - }, - } -} - // AssertSystemError asserts an error ui response func AssertSystemError(t *testing.T, errTS *httptest.Server, res *http.Response, body []byte, code int, reason string) { require.Contains(t, res.Request.URL.String(), errTS.URL, "%s", body) diff --git a/selfservice/strategy/oidc/strategy_registration.go b/selfservice/strategy/oidc/strategy_registration.go index 05c9f624c7d..a8c6b6ed783 100644 --- a/selfservice/strategy/oidc/strategy_registration.go +++ b/selfservice/strategy/oidc/strategy_registration.go @@ -184,7 +184,7 @@ func (s *Strategy) processRegistration(w http.ResponseWriter, r *http.Request, a } // This endpoint only handles browser flow at the moment. - ar, err := s.d.LoginHandler().NewLoginFlow(w, r, flow.TypeBrowser, opts...) + ar, _, err := s.d.LoginHandler().NewLoginFlow(w, r, flow.TypeBrowser, opts...) if err != nil { return nil, s.handleError(w, r, a, provider.Config().ID, nil, err) } diff --git a/selfservice/strategy/oidc/strategy_test.go b/selfservice/strategy/oidc/strategy_test.go index 91a08f00a42..2f46b61bf62 100644 --- a/selfservice/strategy/oidc/strategy_test.go +++ b/selfservice/strategy/oidc/strategy_test.go @@ -45,8 +45,6 @@ import ( "github.com/ory/kratos/x" ) -const debugRedirects = false - func TestStrategy(t *testing.T) { ctx := context.Background() if testing.Short() { @@ -138,7 +136,7 @@ func TestStrategy(t *testing.T) { var makeRequestWithCookieJar = func(t *testing.T, provider string, action string, fv url.Values, jar *cookiejar.Jar) (*http.Response, []byte) { fv.Set("provider", provider) - res, err := newClient(t, jar).PostForm(action, fv) + res, err := testhelpers.NewClientWithCookieJar(t, jar, false).PostForm(action, fv) require.NoError(t, err, action) body, err := io.ReadAll(res.Body) @@ -185,7 +183,7 @@ func TestStrategy(t *testing.T) { var newLoginFlow = func(t *testing.T, redirectTo string, exp time.Duration) (req *login.Flow) { // Use NewLoginFlow to instantiate the request but change the things we need to control a copy of it. - req, err := reg.LoginHandler().NewLoginFlow(httptest.NewRecorder(), + req, _, err := reg.LoginHandler().NewLoginFlow(httptest.NewRecorder(), &http.Request{URL: urlx.ParseOrPanic(redirectTo)}, flow.TypeBrowser) require.NoError(t, err) req.RequestURL = redirectTo diff --git a/selfservice/strategy/password/login_test.go b/selfservice/strategy/password/login_test.go index 746df44733f..0fb66528d7e 100644 --- a/selfservice/strategy/password/login_test.go +++ b/selfservice/strategy/password/login_test.go @@ -13,6 +13,7 @@ import ( "testing" "time" + "github.com/ory/kratos/driver" "github.com/ory/kratos/internal/registrationhelpers" "github.com/ory/kratos/selfservice/flow" @@ -45,6 +46,31 @@ import ( //go:embed stub/login.schema.json var loginSchema []byte +func createIdentity(ctx context.Context, reg *driver.RegistryDefault, t *testing.T, identifier, password string) { + p, _ := reg.Hasher(ctx).Generate(context.Background(), []byte(password)) + iId := x.NewUUID() + require.NoError(t, reg.PrivilegedIdentityPool().CreateIdentity(context.Background(), &identity.Identity{ + ID: iId, + Traits: identity.Traits(fmt.Sprintf(`{"subject":"%s"}`, identifier)), + Credentials: map[identity.CredentialsType]identity.Credentials{ + identity.CredentialsTypePassword: { + Type: identity.CredentialsTypePassword, + Identifiers: []string{identifier}, + Config: sqlxx.JSONRawMessage(`{"hashed_password":"` + string(p) + `"}`), + }, + }, + VerifiableAddresses: []identity.VerifiableAddress{ + { + ID: x.NewUUID(), + Value: identifier, + Verified: false, + CreatedAt: time.Now(), + IdentityID: iId, + }, + }, + })) +} + func TestCompleteLogin(t *testing.T) { ctx := context.Background() conf, reg := internal.NewFastRegistryWithMocks(t) @@ -70,31 +96,6 @@ func TestCompleteLogin(t *testing.T) { "csrf_token") } - createIdentity := func(identifier, password string) { - p, _ := reg.Hasher(ctx).Generate(context.Background(), []byte(password)) - iId := x.NewUUID() - require.NoError(t, reg.PrivilegedIdentityPool().CreateIdentity(context.Background(), &identity.Identity{ - ID: iId, - Traits: identity.Traits(fmt.Sprintf(`{"subject":"%s"}`, identifier)), - Credentials: map[identity.CredentialsType]identity.Credentials{ - identity.CredentialsTypePassword: { - Type: identity.CredentialsTypePassword, - Identifiers: []string{identifier}, - Config: sqlxx.JSONRawMessage(`{"hashed_password":"` + string(p) + `"}`), - }, - }, - VerifiableAddresses: []identity.VerifiableAddress{ - { - ID: x.NewUUID(), - Value: identifier, - Verified: false, - CreatedAt: time.Now(), - IdentityID: iId, - }, - }, - })) - } - apiClient := testhelpers.NewDebugClient(t) t.Run("case=should show the error ui because the request payload is malformed", func(t *testing.T) { @@ -109,7 +110,7 @@ func TestCompleteLogin(t *testing.T) { t.Run("type=browser", func(t *testing.T) { browserClient := testhelpers.NewClientWithCookies(t) - f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, false) + f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, false, false, false) body, res := testhelpers.LoginMakeRequest(t, false, false, f, browserClient, "14=)=!(%)$/ZP()GHIÖ") assert.Contains(t, res.Request.URL.String(), uiTS.URL+"/login-ts") @@ -119,7 +120,7 @@ func TestCompleteLogin(t *testing.T) { t.Run("type=spa", func(t *testing.T) { browserClient := testhelpers.NewClientWithCookies(t) - f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, true) + f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, true, false, false) body, res := testhelpers.LoginMakeRequest(t, false, true, f, browserClient, "14=)=!(%)$/ZP()GHIÖ") assert.Contains(t, res.Request.URL.String(), publicTS.URL+login.RouteSubmitFlow) @@ -203,7 +204,7 @@ func TestCompleteLogin(t *testing.T) { t.Run("type=browser", func(t *testing.T) { browserClient := testhelpers.NewClientWithCookies(t) - f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, false) + f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, false, false, false) time.Sleep(time.Millisecond * 60) actual, res := testhelpers.LoginMakeRequest(t, false, false, f, browserClient, values.Encode()) @@ -214,7 +215,7 @@ func TestCompleteLogin(t *testing.T) { t.Run("type=SPA", func(t *testing.T) { browserClient := testhelpers.NewClientWithCookies(t) - f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, true) + f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, true, false, false) time.Sleep(time.Millisecond * 60) actual, res := testhelpers.LoginMakeRequest(t, false, true, f, apiClient, testhelpers.EncodeFormAsJSON(t, true, values)) @@ -234,7 +235,7 @@ func TestCompleteLogin(t *testing.T) { t.Run("case=should fail because of missing CSRF token/type=browser", func(t *testing.T) { browserClient := testhelpers.NewClientWithCookies(t) - f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, false) + f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, false, false, false) actual, res := testhelpers.LoginMakeRequest(t, false, false, f, browserClient, values.Encode()) assert.EqualValues(t, http.StatusOK, res.StatusCode) @@ -244,7 +245,7 @@ func TestCompleteLogin(t *testing.T) { t.Run("case=should fail because of missing CSRF token/type=spa", func(t *testing.T) { browserClient := testhelpers.NewClientWithCookies(t) - f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, true) + f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, true, false, false) actual, res := testhelpers.LoginMakeRequest(t, false, true, f, browserClient, values.Encode()) assert.EqualValues(t, http.StatusForbidden, res.StatusCode) @@ -443,7 +444,7 @@ func TestCompleteLogin(t *testing.T) { } identifier, pwd := x.NewUUID().String(), "password" - createIdentity(identifier, pwd) + createIdentity(ctx, reg, t, identifier, pwd) var values = func(v url.Values) { v.Set("identifier", identifier) @@ -464,7 +465,7 @@ func TestCompleteLogin(t *testing.T) { t.Run("should pass with real request", func(t *testing.T) { identifier, pwd := x.NewUUID().String(), "password" - createIdentity(identifier, pwd) + createIdentity(ctx, reg, t, identifier, pwd) var values = func(v url.Values) { v.Set("identifier", identifier) @@ -689,7 +690,7 @@ func TestCompleteLogin(t *testing.T) { t.Run("type=browser", func(t *testing.T) { browserClient := testhelpers.NewClientWithCookies(t) - f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, false) + f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, false, false, false) actual, _ := testhelpers.LoginMakeRequest(t, false, false, f, browserClient, valuesFirst(testhelpers.SDKFormFieldsToURLValues(f.Ui.Nodes)).Encode()) checkFirst(t, actual) @@ -700,10 +701,10 @@ func TestCompleteLogin(t *testing.T) { t.Run("should be a new session with refresh flag", func(t *testing.T) { identifier, pwd := x.NewUUID().String(), "password" - createIdentity(identifier, pwd) + createIdentity(ctx, reg, t, identifier, pwd) browserClient := testhelpers.NewClientWithCookies(t) - f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, false) + f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, false, false, false) values := url.Values{"method": {"password"}, "identifier": {identifier}, "password": {pwd}, "csrf_token": {x.FakeCSRFToken}}.Encode() @@ -711,7 +712,7 @@ func TestCompleteLogin(t *testing.T) { body1, res := testhelpers.LoginMakeRequest(t, false, false, f, browserClient, values) assert.EqualValues(t, http.StatusOK, res.StatusCode) - f = testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, true, false) + f = testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, true, false, false, false) body2, res := testhelpers.LoginMakeRequest(t, false, false, f, browserClient, values) require.Contains(t, res.Request.URL.Path, "return-ts", "%s", res.Request.URL.String()) @@ -721,10 +722,10 @@ func TestCompleteLogin(t *testing.T) { t.Run("should login same identity regardless of identifier capitalization", func(t *testing.T) { identifier, pwd := x.NewUUID().String(), "password" - createIdentity(identifier, pwd) + createIdentity(ctx, reg, t, identifier, pwd) browserClient := testhelpers.NewClientWithCookies(t) - f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, false) + f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, false, false, false) values := url.Values{"method": {"password"}, "identifier": {strings.ToUpper(identifier)}, "password": {pwd}, "csrf_token": {x.FakeCSRFToken}}.Encode() @@ -736,10 +737,10 @@ func TestCompleteLogin(t *testing.T) { t.Run("should login even if old form field name is used", func(t *testing.T) { identifier, pwd := x.NewUUID().String(), "password" - createIdentity(identifier, pwd) + createIdentity(ctx, reg, t, identifier, pwd) browserClient := testhelpers.NewClientWithCookies(t) - f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, false) + f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, false, false, false) values := url.Values{"method": {"password"}, "password_identifier": {strings.ToUpper(identifier)}, "password": {pwd}, "csrf_token": {x.FakeCSRFToken}}.Encode() @@ -751,10 +752,10 @@ func TestCompleteLogin(t *testing.T) { t.Run("should login same identity regardless of leading or trailing whitespace", func(t *testing.T) { identifier, pwd := x.NewUUID().String(), "password" - createIdentity(identifier, pwd) + createIdentity(ctx, reg, t, identifier, pwd) browserClient := testhelpers.NewClientWithCookies(t) - f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, false) + f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, false, false, false) values := url.Values{"method": {"password"}, "identifier": {" " + identifier + " "}, "password": {pwd}, "csrf_token": {x.FakeCSRFToken}}.Encode() @@ -770,7 +771,7 @@ func TestCompleteLogin(t *testing.T) { }) identifier, pwd := x.NewUUID().String(), "password" - createIdentity(identifier, pwd) + createIdentity(ctx, reg, t, identifier, pwd) var values = func(v url.Values) { v.Set("method", "password") diff --git a/selfservice/strategy/password/op_login_test.go b/selfservice/strategy/password/op_login_test.go new file mode 100644 index 00000000000..9d5b360d973 --- /dev/null +++ b/selfservice/strategy/password/op_login_test.go @@ -0,0 +1,338 @@ +package password_test + +import ( + "context" + _ "embed" + "fmt" + "io" + "net/http" + "net/url" + "testing" + "time" + + "github.com/phayes/freeport" + "github.com/pkg/errors" + "github.com/tidwall/gjson" + "golang.org/x/oauth2" + + "github.com/ory/dockertest/v3" + "github.com/ory/dockertest/v3/docker" + + "github.com/gofrs/uuid" + + "github.com/ory/x/logrusx" + "github.com/ory/x/resilience" + "github.com/ory/x/urlx" + + hydraclientgo "github.com/ory/hydra-client-go" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/ory/kratos/driver/config" + "github.com/ory/kratos/hydra" + "github.com/ory/kratos/identity" + "github.com/ory/kratos/internal" + "github.com/ory/kratos/internal/testhelpers" + "github.com/ory/kratos/session" + "github.com/ory/kratos/x" +) + +func createHydraAdminApiClient(url string) hydraclientgo.AdminApi { + configuration := hydraclientgo.NewConfiguration() + configuration.Host = urlx.ParseOrPanic(url).Host + configuration.Servers = hydraclientgo.ServerConfigurations{{URL: url}} + + return hydraclientgo.NewAPIClient(configuration).AdminApi +} + +func createOAuth2Client(t *testing.T, ctx context.Context, hydraAdmin hydraclientgo.AdminApi, redirectURIs []string, scope string) string { + clientName := "kratos-hydra-integration-test-client-1" + tokenEndpointAuthMethod := "client_secret_post" + clientSecret := "client-secret" + + c, r, err := hydraAdmin.CreateOAuth2Client(ctx).OAuth2Client( + hydraclientgo.OAuth2Client{ + ClientName: &clientName, + RedirectUris: redirectURIs, + Scope: &scope, + TokenEndpointAuthMethod: &tokenEndpointAuthMethod, + ClientSecret: &clientSecret, + }, + ).Execute() + require.NoError(t, err) + require.Equal(t, r.StatusCode, http.StatusCreated) + return *c.ClientId +} + +func makeAuthCodeURL(t *testing.T, c *oauth2.Config, requestedClaims string, isForced bool) string { + var options []oauth2.AuthCodeOption + + if isForced { + options = append(options, oauth2.SetAuthURLParam("prompt", "login")) + } + if requestedClaims != "" { + options = append(options, oauth2.SetAuthURLParam("claims", requestedClaims)) + } + + state := fmt.Sprintf("%x", uuid.Must(uuid.NewV4())) + return c.AuthCodeURL(state, options...) +} + +func newHydra(t *testing.T, loginUI string, consentUI string) (hydraAdmin string, hydraPublic string) { + publicPort, err := freeport.GetFreePort() + require.NoError(t, err) + adminPort, err := freeport.GetFreePort() + require.NoError(t, err) + + pool, err := dockertest.NewPool("") + require.NoError(t, err) + + hydra, err := pool.RunWithOptions(&dockertest.RunOptions{ + Repository: "oryd/hydra", + Tag: "v2.0.0", + Env: []string{ + "DSN=memory", + fmt.Sprintf("URLS_SELF_ISSUER=http://127.0.0.1:%d/", publicPort), + "URLS_LOGIN=" + loginUI, + "URLS_CONSENT=" + consentUI, + "LOG_LEAK_SENSITIVE_VALUES=true", + }, + Cmd: []string{"serve", "all", "--dev"}, + ExposedPorts: []string{"4444/tcp", "4445/tcp"}, + PortBindings: map[docker.Port][]docker.PortBinding{ + "4444/tcp": {{HostPort: fmt.Sprintf("%d/tcp", publicPort)}}, + "4445/tcp": {{HostPort: fmt.Sprintf("%d/tcp", adminPort)}}, + }, + }) + require.NoError(t, err) + t.Cleanup(func() { + require.NoError(t, hydra.Close()) + }) + + require.NoError(t, hydra.Expire(uint(60*5))) + + require.NotEmpty(t, hydra.GetPort("4444/tcp"), "%+v", hydra.Container.NetworkSettings.Ports) + require.NotEmpty(t, hydra.GetPort("4445/tcp"), "%+v", hydra.Container) + + hydraPublic = "http://127.0.0.1:" + hydra.GetPort("4444/tcp") + hydraAdmin = "http://127.0.0.1:" + hydra.GetPort("4445/tcp") + + go pool.Client.Logs(docker.LogsOptions{ErrorStream: TestLogWriter{T: t, streamName: "hydra-stderr"}, OutputStream: TestLogWriter{T: t, streamName: "hydra-stdout"}, Stdout: true, Stderr: true, Follow: true, Container: hydra.Container.ID}) + hl := logrusx.New("hydra-ready-check", "hydra-ready-check") + err = resilience.Retry(hl, time.Second*1, time.Second*5, func() error { + pr := hydraPublic + "/health/ready" + res, err := http.DefaultClient.Get(pr) + if err != nil || res.StatusCode != 200 { + return errors.Errorf("Hydra public is not ready at " + pr) + } + + ar := hydraAdmin + "/health/ready" + res, err = http.DefaultClient.Get(ar) + if err != nil && res.StatusCode != 200 { + return errors.Errorf("Hydra admin is not ready at " + ar) + } else { + return nil + } + }) + require.NoError(t, err) + + t.Logf("Ory Hydra running at: %s %s", hydraPublic, hydraAdmin) + + return hydraAdmin, hydraPublic +} + +type TestLogWriter struct { + streamName string + *testing.T +} + +func (t TestLogWriter) Write(p []byte) (int, error) { + t.Logf("[%d bytes @ %s]:\n\n%s\n", len(p), t.streamName, string(p)) + return len(p), nil +} + +func TestOAuth2Provider(t *testing.T) { + ctx := context.Background() + conf, reg := internal.NewFastRegistryWithMocks(t) + conf.MustSet( + ctx, + config.ViperKeySelfServiceStrategyConfig+"."+string(identity.CredentialsTypePassword), + map[string]interface{}{"enabled": true}, + ) + router := x.NewRouterPublic() + kratosPublicTS, _ := testhelpers.NewKratosServerWithRouters(t, reg, router, x.NewRouterAdmin()) + + browserClient := testhelpers.NewClientWithCookieJar(t, nil, true) + + errTS := testhelpers.NewErrorTestServer(t, reg) + + redirTS := testhelpers.NewRedirSessionEchoTS(t, reg) + + oAuthSuccess := false + var hydraAdminClient hydraclientgo.AdminApi + var clientAppOAuth2Config *oauth2.Config + + clientAppTS := testhelpers.NewHTTPTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + t.Logf("[clientAppTS] handling a callback at client app %s", r.URL.String()) + if r.URL.Query().Has("code") { + token, err := clientAppOAuth2Config.Exchange(r.Context(), r.URL.Query().Get("code")) + require.NoError(t, err) + require.NotNil(t, token) + require.NotEqual(t, "", token.AccessToken) + oAuthSuccess = true + t.Log("[clientAppTS] successfully exchanged code for token") + } else { + t.Error("[clientAppTS] code query parameter is missing") + } + })) + + identifier, pwd := x.NewUUID().String(), "password" + + testRequireLogin := true + + uiTS := testhelpers.NewHTTPTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + t.Logf("[uiTS] handling %s", r.URL) + q := r.URL.Query() + + if len(q) == 1 && !q.Has("flow") && q.Has("login_challenge") { + t.Log("[uiTS] initializing a new OpenID Provider flow") + hlc := r.URL.Query().Get("login_challenge") + f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, kratosPublicTS, false, false, false, !testRequireLogin, testhelpers.InitFlowWithOAuth2LoginChallenge(hlc)) + if testRequireLogin { + require.NotNil(t, f) + + values := url.Values{"method": {"password"}, "identifier": {identifier}, "password": {pwd}, "csrf_token": {x.FakeCSRFToken}}.Encode() + _, res := testhelpers.LoginMakeRequest(t, false, false, f, browserClient, values) + + assert.EqualValues(t, http.StatusOK, res.StatusCode) + } else { + require.Nil(t, f, "login flow should have been skipped and invalidated, but we successfully retrieved it") + } + return + } + + if q.Has("consent_challenge") { + kratosUIHandleConsent(t, r, browserClient, hydraAdminClient, clientAppTS.URL) + return + } + + if q.Has("flow") { + t.Log("[uiTS] no operaton; the flow should be completed by the handler that initialized it") + return + } + + t.Errorf("[uiTS] unexpected query %#v", q) + })) + + conf.MustSet(ctx, config.ViperKeySecretsDefault, []string{"not-a-secure-session-key"}) + conf.MustSet(ctx, config.ViperKeySelfServiceErrorUI, errTS.URL+"/error-ts") + conf.MustSet(ctx, config.ViperKeySelfServiceLoginUI, uiTS.URL+"/login-ts") + conf.MustSet(ctx, config.ViperKeySelfServiceBrowserDefaultReturnTo, redirTS.URL+"/return-ts") + + testhelpers.SetDefaultIdentitySchemaFromRaw(conf, loginSchema) + createIdentity(ctx, reg, t, identifier, pwd) + + hydraAdmin, hydraPublic := newHydra(t, uiTS.URL, uiTS.URL) + conf.MustSet(ctx, config.ViperKeyOAuth2ProviderURL, hydraAdmin+"/admin") + hydraAdminClient = createHydraAdminApiClient(hydraAdmin + "/admin") + clientID := createOAuth2Client(t, ctx, hydraAdminClient, []string{clientAppTS.URL}, "profile email") + + t.Run("should sign in the user without OAuth2", func(t *testing.T) { + f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, kratosPublicTS, false, false, false, false) + + values := url.Values{"method": {"password"}, "identifier": {identifier}, "password": {pwd}, "csrf_token": {x.FakeCSRFToken}}.Encode() + + body, res := testhelpers.LoginMakeRequest(t, false, false, f, browserClient, values) + + assert.EqualValues(t, http.StatusOK, res.StatusCode) + assert.Equal(t, identifier, gjson.Get(body, "identity.traits.subject").String(), "%s", body) + }) + + clientAppOAuth2Config = &oauth2.Config{ + ClientID: clientID, + ClientSecret: "client-secret", + Endpoint: oauth2.Endpoint{ + AuthURL: hydraPublic + "/oauth2/auth", + TokenURL: hydraPublic + "/oauth2/token", + AuthStyle: oauth2.AuthStyleInParams, + }, + Scopes: []string{"profile", "email"}, + RedirectURL: clientAppTS.URL, + } + + conf.MustSet(ctx, config.ViperKeySessionPersistentCookie, false) + t.Run("should prompt the user for login and consent", func(t *testing.T) { + authCodeURL := makeAuthCodeURL(t, clientAppOAuth2Config, "", false) + res, err := browserClient.Get(authCodeURL) + + require.NoError(t, err, authCodeURL) + body, err := io.ReadAll(res.Body) + require.NoError(t, res.Body.Close()) + require.NoError(t, err) + require.Equal(t, "", string(body)) + require.Equal(t, http.StatusOK, res.StatusCode) + require.True(t, oAuthSuccess) + oAuthSuccess = false + }) + + conf.MustSet(ctx, config.ViperKeySessionPersistentCookie, true) + t.Run("should prompt the user for login and consent again", func(t *testing.T) { + authCodeURL := makeAuthCodeURL(t, clientAppOAuth2Config, "", false) + res, err := browserClient.Get(authCodeURL) + + require.NoError(t, err, authCodeURL) + body, err := io.ReadAll(res.Body) + require.NoError(t, res.Body.Close()) + require.NoError(t, err) + require.Equal(t, "", string(body)) + require.Equal(t, http.StatusOK, res.StatusCode) + require.True(t, oAuthSuccess) + oAuthSuccess = false + }) + + testRequireLogin = false + t.Run("should prompt the user for consent, but not for login", func(t *testing.T) { + authCodeURL := makeAuthCodeURL(t, clientAppOAuth2Config, "", false) + res, err := browserClient.Get(authCodeURL) + + require.NoError(t, err, authCodeURL) + body, err := io.ReadAll(res.Body) + require.NoError(t, res.Body.Close()) + require.NoError(t, err) + require.Equal(t, "", string(body)) + require.Equal(t, http.StatusOK, res.StatusCode) + require.True(t, oAuthSuccess) + oAuthSuccess = false + }) + + reg.WithHydra(&AcceptWrongSubject{h: reg.Hydra().(*hydra.DefaultHydra)}) + t.Run("should fail when Hydra session subject doesn't match the subject authenticated by Kratos", func(t *testing.T) { + authCodeURL := makeAuthCodeURL(t, clientAppOAuth2Config, "", false) + res, err := browserClient.Get(authCodeURL) + + require.NoError(t, err, authCodeURL) + body, err := io.ReadAll(res.Body) + require.NoError(t, res.Body.Close()) + require.NoError(t, err) + require.Equal(t, "", string(body)) + require.Equal(t, http.StatusOK, res.StatusCode) + require.False(t, oAuthSuccess) + oAuthSuccess = false + }) +} + +var _ hydra.Hydra = &AcceptWrongSubject{} + +type AcceptWrongSubject struct { + h *hydra.DefaultHydra +} + +func (h *AcceptWrongSubject) AcceptLoginRequest(ctx context.Context, hlc uuid.UUID, sub string, amr session.AuthenticationMethods) (string, error) { + hackerman := uuid.Must(uuid.NewV4()) + return h.h.AcceptLoginRequest(ctx, hlc, hackerman.String(), amr) +} + +func (h *AcceptWrongSubject) GetLoginRequest(ctx context.Context, hlc uuid.NullUUID) (*hydraclientgo.LoginRequest, error) { + return h.h.GetLoginRequest(ctx, hlc) +} diff --git a/selfservice/strategy/password/op_registration_test.go b/selfservice/strategy/password/op_registration_test.go new file mode 100644 index 00000000000..8868c6df18a --- /dev/null +++ b/selfservice/strategy/password/op_registration_test.go @@ -0,0 +1,276 @@ +package password_test + +import ( + "context" + _ "embed" + "fmt" + "io" + "net/http" + "net/http/httptest" + "testing" + + "golang.org/x/oauth2" + + hydraclientgo "github.com/ory/hydra-client-go" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/ory/kratos/driver/config" + "github.com/ory/kratos/identity" + "github.com/ory/kratos/internal" + "github.com/ory/kratos/internal/testhelpers" + "github.com/ory/kratos/x" +) + +type clientAppConfig struct { + client *oauth2.Config + expectToken bool + state clientAppState +} + +type clientAppState struct { + visits int64 + tokens int64 +} + +type kratosUIConfig struct { + expectLoginScreen bool + identifier string + password string + browserClient *http.Client + kratosPublicTS *httptest.Server + clientAppTS *httptest.Server + hydraAdminClient hydraclientgo.AdminApi +} + +func newClientAppTS(t *testing.T, c *clientAppConfig) *httptest.Server { + return testhelpers.NewHTTPTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + c.state.visits += 1 + t.Logf("[clientAppTS] handling a callback at client app %s", r.URL.String()) + if r.URL.Query().Has("code") { + token, err := c.client.Exchange(r.Context(), r.URL.Query().Get("code")) + require.NoError(t, err) + require.NotNil(t, token) + require.NotEqual(t, "", token.AccessToken) + require.True(t, c.expectToken) + c.state.tokens += 1 + t.Log("[clientAppTS] successfully exchanged code for token") + } else { + t.Error("[clientAppTS] code query parameter is missing") + require.False(t, c.expectToken) + } + })) +} + +func kratosUIHandleConsent(t *testing.T, req *http.Request, client *http.Client, haa hydraclientgo.AdminApi, clientAppURL string) { + q := req.URL.Query() + cr, resp, err := haa.GetConsentRequest(req.Context()).ConsentChallenge(q.Get("consent_challenge")).Execute() + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode) + require.ElementsMatch(t, cr.RequestedScope, []string{"profile", "email"}) + + remember := true + completedAcceptRequest, resp, err := haa.AcceptConsentRequest(context.Background()).AcceptConsentRequest(hydraclientgo.AcceptConsentRequest{ + Remember: &remember, + }).ConsentChallenge(q.Get("consent_challenge")).Execute() + + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode) + require.NotNil(t, completedAcceptRequest) + + t.Logf("[uiTS] navigating to %s", completedAcceptRequest.RedirectTo) + resp, err = client.Get(completedAcceptRequest.RedirectTo) + require.NoError(t, err) + require.Equal(t, clientAppURL, fmt.Sprintf("%s://%s", resp.Request.URL.Scheme, resp.Request.URL.Host)) + require.True(t, resp.Request.URL.Query().Has("code")) +} + +func newKratosUITS(t *testing.T, c *kratosUIConfig) *httptest.Server { + return testhelpers.NewHTTPTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + t.Logf("[uiTS] handling %s", r.URL) + q := r.URL.Query() + + if len(q) == 1 && !q.Has("flow") && q.Has("login_challenge") { + t.Log("[uiTS] initializing a new OpenID Provider flow") + hlc := r.URL.Query().Get("login_challenge") + f := testhelpers.InitializeRegistrationFlowViaBrowser(t, c.browserClient, c.kratosPublicTS, false, false, !c.expectLoginScreen, testhelpers.InitFlowWithOAuth2LoginChallenge(hlc)) + if c.expectLoginScreen { + require.NotNil(t, f) + + values := testhelpers.SDKFormFieldsToURLValues(f.Ui.Nodes) + values.Set("traits.foobar", c.identifier) + values.Set("traits.username", c.identifier) + values.Set("password", c.password) + + _, res := testhelpers.RegistrationMakeRequest(t, false, false, f, c.browserClient, values.Encode()) + + assert.EqualValues(t, http.StatusOK, res.StatusCode) + } else { + require.Nil(t, f, "registration flow should have been skipped and invalidated, but we successfully retrieved it") + } + return + } + + if q.Has("consent_challenge") { + kratosUIHandleConsent(t, r, c.browserClient, c.hydraAdminClient, c.clientAppTS.URL) + return + } + + if q.Has("flow") { + t.Log("[uiTS] no operaton; the flow should be completed by the handler that initialized it") + return + } + + t.Errorf("[uiTS] unexpected query %#v", q) + })) +} + +func TestOAuth2ProviderRegistration(t *testing.T) { + ctx := context.Background() + conf, reg := internal.NewFastRegistryWithMocks(t) + kratosPublicTS, _ := testhelpers.NewKratosServerWithRouters(t, reg, x.NewRouterPublic(), x.NewRouterAdmin()) + errTS := testhelpers.NewErrorTestServer(t, reg) + redirTS := testhelpers.NewRedirSessionEchoTS(t, reg) + + var hydraAdminClient hydraclientgo.AdminApi + + cac := &clientAppConfig{} + clientAppTS := newClientAppTS(t, cac) + + kuc := &kratosUIConfig{} + kratosUITS := newKratosUITS(t, kuc) + + hydraAdmin, hydraPublic := newHydra(t, kratosUITS.URL, kratosUITS.URL) + + hydraAdminClient = createHydraAdminApiClient(hydraAdmin + "/admin") + clientID := createOAuth2Client(t, ctx, hydraAdminClient, []string{clientAppTS.URL}, "profile email") + + defaultClient := &oauth2.Config{ + ClientID: clientID, + ClientSecret: "client-secret", + Endpoint: oauth2.Endpoint{ + AuthURL: hydraPublic + "/oauth2/auth", + TokenURL: hydraPublic + "/oauth2/token", + AuthStyle: oauth2.AuthStyleInParams, + }, + Scopes: []string{"profile", "email"}, + RedirectURL: clientAppTS.URL, + } + + conf.MustSet(ctx, config.ViperKeyOAuth2ProviderURL, hydraAdmin+"/admin") + conf.MustSet(ctx, config.ViperKeySelfServiceErrorUI, errTS.URL+"/error-ts") + conf.MustSet(ctx, config.ViperKeySelfServiceLoginUI, kratosUITS.URL+"/login-ts") + conf.MustSet(ctx, config.ViperKeySelfServiceRegistrationUI, kratosUITS.URL+"/login-ts") + conf.MustSet(ctx, config.ViperKeySelfServiceBrowserDefaultReturnTo, redirTS.URL+"/return-ts") + conf.MustSet(ctx, config.ViperKeySelfServiceRegistrationAfter+"."+config.DefaultBrowserReturnURL, redirTS.URL+"/registration-return-ts") + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+"."+string(identity.CredentialsTypePassword), map[string]interface{}{"enabled": true}) + conf.MustSet(ctx, config.ViperKeySecretsDefault, []string{"not-a-secure-session-key"}) + conf.MustSet(ctx, config.HookStrategyKey(config.ViperKeySelfServiceRegistrationAfter, identity.CredentialsTypePassword.String()), []config.SelfServiceHook{{Name: "session"}}) + testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/registration.schema.json") + + sharedBrowserClient := testhelpers.NewClientWithCookieJar(t, nil, true) + + type state struct { + cas clientAppState + } + for _, tc := range []struct { + name string + configure func(c *config.Config) + cac clientAppConfig + kuc kratosUIConfig + expected state + }{ + { + name: "should prompt the user for login and consent", + configure: func(c *config.Config) { + c.MustSet(ctx, config.ViperKeySessionPersistentCookie, false) + }, + cac: clientAppConfig{ + client: defaultClient, + expectToken: true, + }, + kuc: kratosUIConfig{ + expectLoginScreen: true, + identifier: x.NewUUID().String(), + password: x.NewUUID().String(), + browserClient: sharedBrowserClient, + kratosPublicTS: kratosPublicTS, + clientAppTS: clientAppTS, + hydraAdminClient: hydraAdminClient, + }, + expected: state{ + cas: clientAppState{ + visits: 1, + tokens: 1, + }, + }, + }, + { + name: "should prompt the user for login and consent again", + configure: func(c *config.Config) { + c.MustSet(ctx, config.ViperKeySessionPersistentCookie, true) + }, + cac: clientAppConfig{ + client: defaultClient, + expectToken: true, + }, + kuc: kratosUIConfig{ + expectLoginScreen: true, + identifier: x.NewUUID().String(), + password: x.NewUUID().String(), + browserClient: sharedBrowserClient, + kratosPublicTS: kratosPublicTS, + clientAppTS: clientAppTS, + hydraAdminClient: hydraAdminClient, + }, + expected: state{ + cas: clientAppState{ + visits: 1, + tokens: 1, + }, + }, + }, + { + name: "should fail because the persistent Hydra session doesn't match the new Kratos session subject", + configure: func(c *config.Config) { + }, + cac: clientAppConfig{ + client: defaultClient, + expectToken: false, + }, + kuc: kratosUIConfig{ + expectLoginScreen: true, + identifier: x.NewUUID().String(), + password: x.NewUUID().String(), + browserClient: sharedBrowserClient, + kratosPublicTS: kratosPublicTS, + clientAppTS: clientAppTS, + hydraAdminClient: hydraAdminClient, + }, + expected: state{ + cas: clientAppState{ + visits: 0, + tokens: 0, + }, + }, + }, + } { + t.Run(tc.name, func(t *testing.T) { + *cac = tc.cac + *kuc = tc.kuc + tc.configure(conf) + + authCodeURL := makeAuthCodeURL(t, cac.client, "", false) + res, err := tc.kuc.browserClient.Get(authCodeURL) + + require.NoError(t, err) + body, err := io.ReadAll(res.Body) + require.NoError(t, res.Body.Close()) + require.NoError(t, err) + require.Equal(t, "", string(body)) + require.Equal(t, http.StatusOK, res.StatusCode) + require.EqualValues(t, tc.expected.cas, cac.state) + }) + } +} diff --git a/selfservice/strategy/password/registration_test.go b/selfservice/strategy/password/registration_test.go index 2a4060a0285..50e11e6a6cf 100644 --- a/selfservice/strategy/password/registration_test.go +++ b/selfservice/strategy/password/registration_test.go @@ -333,7 +333,7 @@ func TestRegistration(t *testing.T) { t.Run("type=spa", func(t *testing.T) { browserClient := testhelpers.NewClientWithCookies(t) - f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, true) + f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, true, false, false) c := f.Ui actual, _ := testhelpers.RegistrationMakeRequest(t, false, true, f, browserClient, testhelpers.EncodeFormAsJSON(t, false, valuesFirst(testhelpers.SDKFormFieldsToURLValues(c.Nodes)))) @@ -344,7 +344,7 @@ func TestRegistration(t *testing.T) { t.Run("type=browser", func(t *testing.T) { browserClient := testhelpers.NewClientWithCookies(t) - f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, false) + f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, false, false, false) c := f.Ui actual, _ := testhelpers.RegistrationMakeRequest(t, false, false, f, browserClient, valuesFirst(testhelpers.SDKFormFieldsToURLValues(c.Nodes)).Encode()) @@ -413,7 +413,7 @@ func TestRegistration(t *testing.T) { hc := testhelpers.NewClientWithCookies(t) hc.Transport = testhelpers.NewTransportWithLogger(hc.Transport, t) - payload := testhelpers.InitializeRegistrationFlowViaBrowser(t, hc, publicTS, false) + payload := testhelpers.InitializeRegistrationFlowViaBrowser(t, hc, publicTS, false, false, false) values := testhelpers.SDKFormFieldsToURLValues(payload.Ui.Nodes) time.Sleep(time.Millisecond) // add a bit of delay to allow `1ns` to time out. @@ -481,7 +481,7 @@ func TestRegistration(t *testing.T) { _ = testhelpers.NewRegistrationUIFlowEchoServer(t, reg) browserClient := testhelpers.NewClientWithCookies(t) - f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, false) + f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, publicTS, false, false, false) assertx.EqualAsJSON(t, container.Container{ Action: conf.SelfPublicURL(ctx).String() + registration.RouteSubmitFlow + "?flow=" + f.Id, diff --git a/selfservice/strategy/totp/login_test.go b/selfservice/strategy/totp/login_test.go index ab3310cc255..d180d92b39c 100644 --- a/selfservice/strategy/totp/login_test.go +++ b/selfservice/strategy/totp/login_test.go @@ -133,7 +133,7 @@ func TestCompleteLogin(t *testing.T) { t.Run("type=browser", func(t *testing.T) { browserClient := testhelpers.NewHTTPClientWithIdentitySessionCookie(t, reg, id) - f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, false, testhelpers.InitFlowWithAAL(identity.AuthenticatorAssuranceLevel2)) + f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, false, false, false, testhelpers.InitFlowWithAAL(identity.AuthenticatorAssuranceLevel2)) body, res := testhelpers.LoginMakeRequest(t, false, false, f, browserClient, "14=)=!(%)$/ZP()GHIÖ") assert.Contains(t, res.Request.URL.String(), uiTS.URL+"/login-ts") @@ -143,7 +143,7 @@ func TestCompleteLogin(t *testing.T) { t.Run("type=spa", func(t *testing.T) { browserClient := testhelpers.NewHTTPClientWithIdentitySessionCookie(t, reg, id) - f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, true, testhelpers.InitFlowWithAAL(identity.AuthenticatorAssuranceLevel2)) + f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, true, false, false, testhelpers.InitFlowWithAAL(identity.AuthenticatorAssuranceLevel2)) body, res := testhelpers.LoginMakeRequest(t, false, true, f, browserClient, "14=)=!(%)$/ZP()GHIÖ") assert.Contains(t, res.Request.URL.String(), publicTS.URL+login.RouteSubmitFlow) @@ -170,7 +170,7 @@ func TestCompleteLogin(t *testing.T) { opts = append(opts, testhelpers.InitFlowWithReturnTo(returnTo)) } - f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, spa, opts...) + f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, spa, false, false, opts...) values := testhelpers.SDKFormFieldsToURLValues(f.Ui.Nodes) values.Set("method", "totp") v(values) @@ -411,7 +411,7 @@ func TestCompleteLogin(t *testing.T) { t.Run("type=browser", func(t *testing.T) { returnTo := "https://www.ory.sh" browserClient := testhelpers.NewClientWithCookies(t) - f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, false, testhelpers.InitFlowWithReturnTo(returnTo)) + f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, false, false, false, testhelpers.InitFlowWithReturnTo(returnTo)) cred, ok := id.GetCredentials(identity.CredentialsTypePassword) require.True(t, ok) diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=passwordless-case=should_fail_if_webauthn_login_is_invalid-type=browser.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=passwordless-case=should_fail_if_webauthn_login_is_invalid-type=browser.json index 4ec85e234b8..025c09e3c50 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=passwordless-case=should_fail_if_webauthn_login_is_invalid-type=browser.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=passwordless-case=should_fail_if_webauthn_login_is_invalid-type=browser.json @@ -1,4 +1,5 @@ { + "oauth2_login_challenge": null, "type": "browser", "ui": { "method": "POST", diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=passwordless-case=should_fail_if_webauthn_login_is_invalid-type=spa.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=passwordless-case=should_fail_if_webauthn_login_is_invalid-type=spa.json index 4ec85e234b8..025c09e3c50 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=passwordless-case=should_fail_if_webauthn_login_is_invalid-type=spa.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=passwordless-case=should_fail_if_webauthn_login_is_invalid-type=spa.json @@ -1,4 +1,5 @@ { + "oauth2_login_challenge": null, "type": "browser", "ui": { "method": "POST", diff --git a/selfservice/strategy/webauthn/login_test.go b/selfservice/strategy/webauthn/login_test.go index 016e861226d..736d0692af7 100644 --- a/selfservice/strategy/webauthn/login_test.go +++ b/selfservice/strategy/webauthn/login_test.go @@ -105,7 +105,7 @@ func TestCompleteLogin(t *testing.T) { } doBrowserFlow := func(t *testing.T, spa bool, v func(url.Values), browserClient *http.Client, opts ...testhelpers.InitFlowWithOption) (string, *http.Response) { - f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, spa, opts...) + f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, spa, false, false, opts...) values := testhelpers.SDKFormFieldsToURLValues(f.Ui.Nodes) v(values) return testhelpers.LoginMakeRequest(t, false, spa, f, browserClient, values.Encode()) @@ -145,7 +145,7 @@ func TestCompleteLogin(t *testing.T) { } submitWebAuthnLoginWithClient := func(t *testing.T, isSPA bool, id *identity.Identity, contextFixture []byte, client *http.Client, cb func(values url.Values), opts ...testhelpers.InitFlowWithOption) (string, *http.Response, *kratos.SelfServiceLoginFlow) { - f := testhelpers.InitializeLoginFlowViaBrowser(t, client, publicTS, false, isSPA, opts...) + f := testhelpers.InitializeLoginFlowViaBrowser(t, client, publicTS, false, isSPA, false, false, opts...) return submitWebAuthnLoginFlowWithClient(t, isSPA, f, contextFixture, client, cb) } @@ -263,7 +263,7 @@ func TestCompleteLogin(t *testing.T) { id := identity.NewIdentity("") client := testhelpers.NewHTTPClientWithIdentitySessionCookie(t, reg, id) - f := testhelpers.InitializeLoginFlowViaBrowser(t, client, publicTS, true, f == "spa") + f := testhelpers.InitializeLoginFlowViaBrowser(t, client, publicTS, true, f == "spa", false, false) snapshotx.SnapshotTExcept(t, f.Ui.Nodes, []string{ "0.attributes.value", }) @@ -286,7 +286,7 @@ func TestCompleteLogin(t *testing.T) { t.Run("case=webauthn button exists", func(t *testing.T) { client := testhelpers.NewClientWithCookies(t) - f := testhelpers.InitializeLoginFlowViaBrowser(t, client, publicTS, false, true) + f := testhelpers.InitializeLoginFlowViaBrowser(t, client, publicTS, false, true, false, false) testhelpers.SnapshotTExcept(t, f.Ui.Nodes, []string{"0.attributes.value"}) }) @@ -369,7 +369,7 @@ func TestCompleteLogin(t *testing.T) { _, subject := createIdentityAndReturnIdentifier(t, reg, []byte(`{"credentials":[{"id":"Zm9vZm9v","display_name":"foo","is_passwordless":true}]}`)) doBrowserFlow := func(t *testing.T, spa bool, browserClient *http.Client, opts ...testhelpers.InitFlowWithOption) { - f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, spa, opts...) + f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, spa, false, false, opts...) values := testhelpers.SDKFormFieldsToURLValues(f.Ui.Nodes) values.Set("method", identity.CredentialsTypeWebAuthn.String()) @@ -414,6 +414,7 @@ func TestCompleteLogin(t *testing.T) { t.Run("case=succeeds with passwordless login", func(t *testing.T) { run := func(t *testing.T, spa bool) { + conf.MustSet(ctx, config.ViperKeySessionWhoAmIAAL, "aal1") // We load our identity which we will use to replay the webauth session id := createIdentityWithWebAuthn(t, identity.Credentials{ Config: loginFixtureSuccessV1PasswordlessCredentials, @@ -459,7 +460,7 @@ func TestCompleteLogin(t *testing.T) { id := createIdentity(t, reg) apiClient := testhelpers.NewHTTPClientWithIdentitySessionToken(t, reg, id) - f := testhelpers.InitializeLoginFlowViaBrowser(t, apiClient, publicTS, false, true, testhelpers.InitFlowWithAAL(identity.AuthenticatorAssuranceLevel2)) + f := testhelpers.InitializeLoginFlowViaBrowser(t, apiClient, publicTS, false, true, false, false, testhelpers.InitFlowWithAAL(identity.AuthenticatorAssuranceLevel2)) assert.Equal(t, gjson.GetBytes(id.Traits, "subject").String(), f.Ui.Nodes[1].Attributes.UiNodeInputAttributes.Value, jsonx.TestMarshalJSONString(t, f.Ui)) testhelpers.SnapshotTExcept(t, f.Ui.Nodes, []string{ "0.attributes.value", @@ -475,7 +476,7 @@ func TestCompleteLogin(t *testing.T) { t.Run("case=webauthn payload is not set when identity has no webauthn", func(t *testing.T) { id := createIdentityWithoutWebAuthn(t, reg) apiClient := testhelpers.NewHTTPClientWithIdentitySessionCookie(t, reg, id) - f := testhelpers.InitializeLoginFlowViaBrowser(t, apiClient, publicTS, false, true, testhelpers.InitFlowWithAAL(identity.AuthenticatorAssuranceLevel2)) + f := testhelpers.InitializeLoginFlowViaBrowser(t, apiClient, publicTS, false, true, false, false, testhelpers.InitFlowWithAAL(identity.AuthenticatorAssuranceLevel2)) testhelpers.SnapshotTExcept(t, f.Ui.Nodes, []string{ "0.attributes.value", diff --git a/selfservice/strategy/webauthn/registration_test.go b/selfservice/strategy/webauthn/registration_test.go index 6a675cad041..701ac3bf74b 100644 --- a/selfservice/strategy/webauthn/registration_test.go +++ b/selfservice/strategy/webauthn/registration_test.go @@ -122,7 +122,7 @@ func TestRegistration(t *testing.T) { for _, f := range flows { t.Run(f, func(t *testing.T) { client := testhelpers.NewClientWithCookies(t) - f := testhelpers.InitializeRegistrationFlowViaBrowser(t, client, publicTS, flowToIsSPA(f)) + f := testhelpers.InitializeRegistrationFlowViaBrowser(t, client, publicTS, flowToIsSPA(f), false, false) testhelpers.SnapshotTExcept(t, f.Ui.Nodes, []string{ "0.attributes.value", }) @@ -134,7 +134,7 @@ func TestRegistration(t *testing.T) { for _, f := range flows { t.Run(f, func(t *testing.T) { client := testhelpers.NewClientWithCookies(t) - f := testhelpers.InitializeRegistrationFlowViaBrowser(t, client, publicTS, flowToIsSPA(f)) + f := testhelpers.InitializeRegistrationFlowViaBrowser(t, client, publicTS, flowToIsSPA(f), false, false) testhelpers.SnapshotTExcept(t, f.Ui.Nodes, []string{ "2.attributes.value", "5.attributes.onclick", @@ -192,7 +192,7 @@ func TestRegistration(t *testing.T) { submitWebAuthnRegistrationWithClient := func(t *testing.T, flow string, contextFixture []byte, client *http.Client, cb func(values url.Values), opts ...testhelpers.InitFlowWithOption) (string, *http.Response, *kratos.SelfServiceRegistrationFlow) { isSPA := flow == "spa" - f := testhelpers.InitializeRegistrationFlowViaBrowser(t, client, publicTS, isSPA, opts...) + f := testhelpers.InitializeRegistrationFlowViaBrowser(t, client, publicTS, isSPA, false, false, opts...) // We inject the session to replay interim, err := reg.RegistrationFlowPersister().GetRegistrationFlow(context.Background(), uuid.FromStringOrNil(f.Id)) diff --git a/session/manager.go b/session/manager.go index 9efe12b2ffb..52df844618d 100644 --- a/session/manager.go +++ b/session/manager.go @@ -50,22 +50,28 @@ func (e *ErrAALNotSatisfied) EnhanceJSONError() interface{} { return e } -func (e *ErrAALNotSatisfied) PassReturnToParameter(requestURL string) error { +func (e *ErrAALNotSatisfied) PassReturnToAndLoginChallengeParameters(requestURL string) error { req, err := url.Parse(requestURL) if err != nil { return err } - returnTo := req.Query().Get("return_to") - if len(returnTo) == 0 { - return nil - } u, err := url.Parse(e.RedirectTo) if err != nil { return err } q := u.Query() - q.Set("return_to", returnTo) + + hlc := req.Query().Get("login_challenge") + if len(hlc) != 0 { + q.Set("login_challenge", hlc) + } + + returnTo := req.Query().Get("return_to") + if len(returnTo) != 0 { + q.Set("return_to", returnTo) + } + u.RawQuery = q.Encode() e.RedirectTo = u.String() diff --git a/session/manager_test.go b/session/manager_test.go index 8aeb89a2fbb..be14131a313 100644 --- a/session/manager_test.go +++ b/session/manager_test.go @@ -11,7 +11,7 @@ import ( "github.com/ory/kratos/session" ) -func TestErrAALNotSatisfied_PassReturnToParameter(t *testing.T) { +func TestErrAALNotSatisfied_PassReturnToAndLoginChallengeParameters(t *testing.T) { cases := []struct { name string instance *session.ErrAALNotSatisfied @@ -39,6 +39,26 @@ func TestErrAALNotSatisfied_PassReturnToParameter(t *testing.T) { wantErr: assert.NoError, expected: "https://localhost/?foo=bar&return_to=https%3A%2F%2Fory.sh", }, + { + name: "pass login_challenge parameter", + instance: &session.ErrAALNotSatisfied{ + DefaultError: &herodot.DefaultError{}, + RedirectTo: "https://localhost/?foo=bar", + }, + requestURL: "https://localhost:1234/?login_challenge=badee1", + wantErr: assert.NoError, + expected: "https://localhost/?foo=bar&login_challenge=badee1", + }, + { + name: "pass login_challenge and return_to parameters", + instance: &session.ErrAALNotSatisfied{ + DefaultError: &herodot.DefaultError{}, + RedirectTo: "https://localhost/?foo=bar", + }, + requestURL: "https://localhost:1234/?return_to=https%3A%2F%2Fory.sh&login_challenge=badee1", + wantErr: assert.NoError, + expected: "https://localhost/?foo=bar&login_challenge=badee1&return_to=https%3A%2F%2Fory.sh", + }, { name: "invalid RedirectTo URL", instance: &session.ErrAALNotSatisfied{ @@ -60,7 +80,7 @@ func TestErrAALNotSatisfied_PassReturnToParameter(t *testing.T) { } for _, tc := range cases { t.Run(fmt.Sprintf("case=%s", tc.name), func(t *testing.T) { - err := tc.instance.PassReturnToParameter(tc.requestURL) + err := tc.instance.PassReturnToAndLoginChallengeParameters(tc.requestURL) tc.wantErr(t, err) if err == nil { diff --git a/spec/api.json b/spec/api.json index ced7ae67776..779e1c75412 100755 --- a/spec/api.json +++ b/spec/api.json @@ -49,6 +49,270 @@ "title": "JSONRawMessage represents a json.RawMessage that works well with JSON, SQL, and Swagger.", "type": "object" }, + "LoginRequest": { + "description": "LoginRequest struct for LoginRequest", + "properties": { + "challenge": { + "description": "ID is the identifier (\\\"login challenge\\\") of the login request. It is used to identify the session.", + "type": "string" + }, + "client": { + "$ref": "#/components/schemas/OAuth2Client" + }, + "oidc_context": { + "$ref": "#/components/schemas/OpenIDConnectContext" + }, + "request_url": { + "description": "RequestURL is the original OAuth 2.0 Authorization URL requested by the OAuth 2.0 client. It is the URL which initiates the OAuth 2.0 Authorization Code or OAuth 2.0 Implicit flow. This URL is typically not needed, but might come in handy if you want to deal with additional request parameters.", + "type": "string" + }, + "requested_access_token_audience": { + "items": { + "type": "string" + }, + "type": "array" + }, + "requested_scope": { + "items": { + "type": "string" + }, + "type": "array" + }, + "session_id": { + "description": "SessionID is the login session ID. If the user-agent reuses a login session (via cookie / remember flag) this ID will remain the same. If the user-agent did not have an existing authentication session (e.g. remember is false) this will be a new random value. This value is used as the \\\"sid\\\" parameter in the ID Token and in OIDC Front-/Back- channel logout. It's value can generally be used to associate consecutive login requests by a certain user.", + "type": "string" + }, + "skip": { + "description": "Skip, if true, implies that the client has requested the same scopes from the same user previously. If true, you can skip asking the user to grant the requested scopes, and simply forward the user to the redirect URL. This feature allows you to update / set session information.", + "type": "boolean" + }, + "subject": { + "description": "Subject is the user ID of the end-user that authenticated. Now, that end user needs to grant or deny the scope requested by the OAuth 2.0 client. If this value is set and `skip` is true, you MUST include this subject type when accepting the login request, or the request will fail.", + "type": "string" + } + }, + "type": "object" + }, + "NullBool": { + "nullable": true, + "type": "boolean" + }, + "NullInt": { + "nullable": true, + "type": "integer" + }, + "NullString": { + "nullable": true, + "type": "string" + }, + "NullTime": { + "format": "date-time", + "nullable": true, + "type": "string" + }, + "NullUUID": { + "format": "uuid4", + "nullable": true, + "type": "string" + }, + "OAuth2Client": { + "description": "OAuth2Client struct for OAuth2Client", + "properties": { + "allowed_cors_origins": { + "items": { + "type": "string" + }, + "type": "array" + }, + "audience": { + "items": { + "type": "string" + }, + "type": "array" + }, + "backchannel_logout_session_required": { + "description": "Boolean value specifying whether the RP requires that a sid (session ID) Claim be included in the Logout Token to identify the RP session with the OP when the backchannel_logout_uri is used. If omitted, the default value is false.", + "type": "boolean" + }, + "backchannel_logout_uri": { + "description": "RP URL that will cause the RP to log itself out when sent a Logout Token by the OP.", + "type": "string" + }, + "client_id": { + "description": "ID is the id for this client.", + "type": "string" + }, + "client_name": { + "description": "Name is the human-readable string name of the client to be presented to the end-user during authorization.", + "type": "string" + }, + "client_secret": { + "description": "Secret is the client's secret. The secret will be included in the create request as cleartext, and then never again. The secret is stored using BCrypt so it is impossible to recover it. Tell your users that they need to write the secret down as it will not be made available again.", + "type": "string" + }, + "client_secret_expires_at": { + "description": "SecretExpiresAt is an integer holding the time at which the client secret will expire or 0 if it will not expire. The time is represented as the number of seconds from 1970-01-01T00:00:00Z as measured in UTC until the date/time of expiration. This feature is currently not supported and it's value will always be set to 0.", + "format": "int64", + "type": "integer" + }, + "client_uri": { + "description": "ClientURI is an URL string of a web page providing information about the client. If present, the server SHOULD display this URL to the end-user in a clickable fashion.", + "type": "string" + }, + "contacts": { + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "CreatedAt returns the timestamp of the client's creation.", + "format": "date-time", + "type": "string" + }, + "frontchannel_logout_session_required": { + "description": "Boolean value specifying whether the RP requires that iss (issuer) and sid (session ID) query parameters be included to identify the RP session with the OP when the frontchannel_logout_uri is used. If omitted, the default value is false.", + "type": "boolean" + }, + "frontchannel_logout_uri": { + "description": "RP URL that will cause the RP to log itself out when rendered in an iframe by the OP. An iss (issuer) query parameter and a sid (session ID) query parameter MAY be included by the OP to enable the RP to validate the request and to determine which of the potentially multiple sessions is to be logged out; if either is included, both MUST be.", + "type": "string" + }, + "grant_types": { + "items": { + "type": "string" + }, + "type": "array" + }, + "jwks": { + "additionalProperties": {}, + "type": "object" + }, + "jwks_uri": { + "description": "URL for the Client's JSON Web Key Set [JWK] document. If the Client signs requests to the Server, it contains the signing key(s) the Server uses to validate signatures from the Client. The JWK Set MAY also contain the Client's encryption keys(s), which are used by the Server to encrypt responses to the Client. When both signing and encryption keys are made available, a use (Key Use) parameter value is REQUIRED for all keys in the referenced JWK Set to indicate each key's intended usage. Although some algorithms allow the same key to be used for both signatures and encryption, doing so is NOT RECOMMENDED, as it is less secure. The JWK x5c parameter MAY be used to provide X.509 representations of keys provided. When used, the bare key values MUST still be present and MUST match those in the certificate.", + "type": "string" + }, + "logo_uri": { + "description": "LogoURI is an URL string that references a logo for the client.", + "type": "string" + }, + "metadata": { + "additionalProperties": {}, + "type": "object" + }, + "owner": { + "description": "Owner is a string identifying the owner of the OAuth 2.0 Client.", + "type": "string" + }, + "policy_uri": { + "description": "PolicyURI is a URL string that points to a human-readable privacy policy document that describes how the deployment organization collects, uses, retains, and discloses personal data.", + "type": "string" + }, + "post_logout_redirect_uris": { + "items": { + "type": "string" + }, + "type": "array" + }, + "redirect_uris": { + "items": { + "type": "string" + }, + "type": "array" + }, + "registration_access_token": { + "description": "RegistrationAccessToken can be used to update, get, or delete the OAuth2 Client.", + "type": "string" + }, + "registration_client_uri": { + "description": "RegistrationClientURI is the URL used to update, get, or delete the OAuth2 Client.", + "type": "string" + }, + "request_object_signing_alg": { + "description": "JWS [JWS] alg algorithm [JWA] that MUST be used for signing Request Objects sent to the OP. All Request Objects from this Client MUST be rejected, if not signed with this algorithm.", + "type": "string" + }, + "request_uris": { + "items": { + "type": "string" + }, + "type": "array" + }, + "response_types": { + "items": { + "type": "string" + }, + "type": "array" + }, + "scope": { + "description": "Scope is a string containing a space-separated list of scope values (as described in Section 3.3 of OAuth 2.0 [RFC6749]) that the client can use when requesting access tokens.", + "type": "string" + }, + "sector_identifier_uri": { + "description": "URL using the https scheme to be used in calculating Pseudonymous Identifiers by the OP. The URL references a file with a single JSON array of redirect_uri values.", + "type": "string" + }, + "subject_type": { + "description": "SubjectType requested for responses to this Client. The subject_types_supported Discovery parameter contains a list of the supported subject_type values for this server. Valid types include `pairwise` and `public`.", + "type": "string" + }, + "token_endpoint_auth_method": { + "description": "Requested Client Authentication method for the Token Endpoint. The options are client_secret_post, client_secret_basic, private_key_jwt, and none.", + "type": "string" + }, + "token_endpoint_auth_signing_alg": { + "description": "Requested Client Authentication signing algorithm for the Token Endpoint.", + "type": "string" + }, + "tos_uri": { + "description": "TermsOfServiceURI is a URL string that points to a human-readable terms of service document for the client that describes a contractual relationship between the end-user and the client that the end-user accepts when authorizing the client.", + "type": "string" + }, + "updated_at": { + "description": "UpdatedAt returns the timestamp of the last update.", + "format": "date-time", + "type": "string" + }, + "userinfo_signed_response_alg": { + "description": "JWS alg algorithm [JWA] REQUIRED for signing UserInfo Responses. If this is specified, the response will be JWT [JWT] serialized, and signed using JWS. The default, if omitted, is for the UserInfo Response to return the Claims as a UTF-8 encoded JSON object using the application/json content-type.", + "type": "string" + } + }, + "type": "object" + }, + "OpenIDConnectContext": { + "description": "OpenIDConnectContext struct for OpenIDConnectContext", + "properties": { + "acr_values": { + "description": "ACRValues is the Authentication AuthorizationContext Class Reference requested in the OAuth 2.0 Authorization request. It is a parameter defined by OpenID Connect and expresses which level of authentication (e.g. 2FA) is required. OpenID Connect defines it as follows: \u003e Requested Authentication AuthorizationContext Class Reference values. Space-separated string that specifies the acr values that the Authorization Server is being requested to use for processing this Authentication Request, with the values appearing in order of preference. The Authentication AuthorizationContext Class satisfied by the authentication performed is returned as the acr Claim Value, as specified in Section 2. The acr Claim is requested as a Voluntary Claim by this parameter.", + "items": { + "type": "string" + }, + "type": "array" + }, + "display": { + "description": "Display is a string value that specifies how the Authorization Server displays the authentication and consent user interface pages to the End-User. The defined values are: page: The Authorization Server SHOULD display the authentication and consent UI consistent with a full User Agent page view. If the display parameter is not specified, this is the default display mode. popup: The Authorization Server SHOULD display the authentication and consent UI consistent with a popup User Agent window. The popup User Agent window should be of an appropriate size for a login-focused dialog and should not obscure the entire window that it is popping up over. touch: The Authorization Server SHOULD display the authentication and consent UI consistent with a device that leverages a touch interface. wap: The Authorization Server SHOULD display the authentication and consent UI consistent with a \\\"feature phone\\\" type display. The Authorization Server MAY also attempt to detect the capabilities of the User Agent and present an appropriate display.", + "type": "string" + }, + "id_token_hint_claims": { + "additionalProperties": true, + "description": "IDTokenHintClaims are the claims of the ID Token previously issued by the Authorization Server being passed as a hint about the End-User's current or past authenticated session with the Client.", + "type": "object" + }, + "login_hint": { + "description": "LoginHint hints about the login identifier the End-User might use to log in (if necessary). This hint can be used by an RP if it first asks the End-User for their e-mail address (or other identifier) and then wants to pass that value as a hint to the discovered authorization service. This value MAY also be a phone number in the format specified for the phone_number Claim. The use of this parameter is optional.", + "type": "string" + }, + "ui_locales": { + "description": "UILocales is the End-User'id preferred languages and scripts for the user interface, represented as a space-separated list of BCP47 [RFC5646] language tag values, ordered by preference. For instance, the value \\\"fr-CA fr en\\\" represents a preference for French as spoken in Canada, then French (without a region designation), followed by English (without a region designation). An error SHOULD NOT result if some or all of the requested locales are not supported by the OpenID Provider.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, "RecoveryAddressType": { "title": "RecoveryAddressType must not exceed 16 characters as that is the limitation in the SQL Schema.", "type": "string" @@ -56,6 +320,10 @@ "TemplateType": { "type": "string" }, + "Time": { + "format": "date-time", + "type": "string" + }, "UUID": { "format": "uuid4", "type": "string" @@ -726,6 +994,15 @@ "title": "Is sent when a privileged session is required to perform the settings update.", "type": "object" }, + "nullDuration": { + "nullable": true, + "pattern": "^[0-9]+(ns|us|ms|s|m|h)$", + "type": "string" + }, + "nullInt64": { + "nullable": true, + "type": "integer" + }, "nullJsonRawMessage": { "description": "NullJSONRawMessage represents a json.RawMessage that works well with JSON, SQL, and Swagger and is NULLable-" }, @@ -966,6 +1243,12 @@ "format": "date-time", "type": "string" }, + "oauth2_login_challenge": { + "$ref": "#/components/schemas/NullUUID" + }, + "oauth2_login_request": { + "$ref": "#/components/schemas/LoginRequest" + }, "refresh": { "description": "Refresh stores whether this login flow should enforce re-authentication.", "type": "boolean" @@ -1142,6 +1425,12 @@ "format": "date-time", "type": "string" }, + "oauth2_login_challenge": { + "$ref": "#/components/schemas/NullUUID" + }, + "oauth2_login_request": { + "$ref": "#/components/schemas/LoginRequest" + }, "request_url": { "description": "RequestURL is the initial URL that was requested from Ory Kratos. It can be used\nto forward information contained in the URL's path or query for example.", "type": "string" @@ -3858,9 +4147,17 @@ }, "/self-service/login/browser": { "get": { - "description": "This endpoint initializes a browser-based user login flow. This endpoint will set the appropriate\ncookies and anti-CSRF measures required for browser-based flows.\n\nIf this endpoint is opened as a link in the browser, it will be redirected to\n`selfservice.flows.login.ui_url` with the flow ID set as the query parameter `?flow=`. If a valid user session\nexists already, the browser will be redirected to `urls.default_redirect_url` unless the query parameter\n`?refresh=true` was set.\n\nIf this endpoint is called via an AJAX request, the response contains the flow without a redirect. In the\ncase of an error, the `error.id` of the JSON response body can be one of:\n\n`session_already_available`: The user is already signed in.\n`session_aal1_required`: Multi-factor auth (e.g. 2fa) was requested but the user has no session yet.\n`security_csrf_violation`: Unable to fetch the flow because a CSRF violation occurred.\n`security_identity_mismatch`: The requested `?return_to` address is not allowed to be used. Adjust this in the configuration!\n\nThis endpoint is NOT INTENDED for clients that do not have a browser (Chrome, Firefox, ...) as cookies are needed.\n\nMore information can be found at [Ory Kratos User Login](https://www.ory.sh/docs/kratos/self-service/flows/user-login) and [User Registration Documentation](https://www.ory.sh/docs/kratos/self-service/flows/user-registration).", + "description": "This endpoint initializes a browser-based user login flow. This endpoint will set the appropriate\ncookies and anti-CSRF measures required for browser-based flows.\n\nIf this endpoint is opened as a link in the browser, it will be redirected to\n`selfservice.flows.login.ui_url` with the flow ID set as the query parameter `?flow=`. If a valid user session\nexists already, the browser will be redirected to `urls.default_redirect_url` unless the query parameter\n`?refresh=true` was set.\n\nIf this endpoint is called via an AJAX request, the response contains the flow without a redirect. In the\ncase of an error, the `error.id` of the JSON response body can be one of:\n\n`session_already_available`: The user is already signed in.\n`session_aal1_required`: Multi-factor auth (e.g. 2fa) was requested but the user has no session yet.\n`security_csrf_violation`: Unable to fetch the flow because a CSRF violation occurred.\n`security_identity_mismatch`: The requested `?return_to` address is not allowed to be used. Adjust this in the configuration!\n\nThe optional query parameter `login_challenge` is set when using an Ory OAuth 2.0 OAuth2 & OpenID. See the `oauth2_provider.url` configuration\noption.\n\nThis endpoint is NOT INTENDED for clients that do not have a browser (Chrome, Firefox, ...) as cookies are needed.\n\nMore information can be found at [Ory Kratos User Login](https://www.ory.sh/docs/kratos/self-service/flows/user-login) and [User Registration Documentation](https://www.ory.sh/docs/kratos/self-service/flows/user-registration).", "operationId": "initializeSelfServiceLoginFlowForBrowsers", "parameters": [ + { + "description": "An optional Hydra login challenge. If present, Kratos will cooperate with\nOry Hydra to act as an OAuth2 identity provider.\n\nThe value for this parameter comes from `login_challenge` URL Query parameter sent to your\napplication (e.g. `/login?login_challenge=abcde`).", + "in": "query", + "name": "login_challenge", + "schema": { + "type": "string" + } + }, { "description": "Refresh a login session\n\nIf set to true, this will refresh an existing login session by\nasking the user to sign in again. This will reset the\nauthenticated_at time of the session.", "in": "query", @@ -4583,6 +4880,14 @@ "description": "This endpoint initializes a browser-based user registration flow. This endpoint will set the appropriate\ncookies and anti-CSRF measures required for browser-based flows.\n\n:::info\n\nThis endpoint is EXPERIMENTAL and subject to potential breaking changes in the future.\n\n:::\n\nIf this endpoint is opened as a link in the browser, it will be redirected to\n`selfservice.flows.registration.ui_url` with the flow ID set as the query parameter `?flow=`. If a valid user session\nexists already, the browser will be redirected to `urls.default_redirect_url`.\n\nIf this endpoint is called via an AJAX request, the response contains the flow without a redirect. In the\ncase of an error, the `error.id` of the JSON response body can be one of:\n\n`session_already_available`: The user is already signed in.\n`security_csrf_violation`: Unable to fetch the flow because a CSRF violation occurred.\n`security_identity_mismatch`: The requested `?return_to` address is not allowed to be used. Adjust this in the configuration!\n\nIf this endpoint is called via an AJAX request, the response contains the registration flow without a redirect.\n\nThis endpoint is NOT INTENDED for clients that do not have a browser (Chrome, Firefox, ...) as cookies are needed.\n\nMore information can be found at [Ory Kratos User Login](https://www.ory.sh/docs/kratos/self-service/flows/user-login) and [User Registration Documentation](https://www.ory.sh/docs/kratos/self-service/flows/user-registration).", "operationId": "initializeSelfServiceRegistrationFlowForBrowsers", "parameters": [ + { + "description": "An optional Hydra login challenge. If present, Kratos will cooperate with\nOry Hydra to act as an OAuth2 identity provider.\n\nThe value for this parameter comes from `login_challenge` URL Query parameter sent to your\napplication (e.g. `/registration?login_challenge=abcde`).", + "in": "query", + "name": "login_challenge", + "schema": { + "type": "string" + } + }, { "description": "The URL to return the browser to after the flow was completed.", "in": "query", @@ -5670,4 +5975,4 @@ }, "x-forwarded-proto": "string", "x-request-id": "string" -} \ No newline at end of file +} diff --git a/spec/swagger.json b/spec/swagger.json index 5395823b09f..6cc035a6313 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -1132,7 +1132,7 @@ }, "/self-service/login/browser": { "get": { - "description": "This endpoint initializes a browser-based user login flow. This endpoint will set the appropriate\ncookies and anti-CSRF measures required for browser-based flows.\n\nIf this endpoint is opened as a link in the browser, it will be redirected to\n`selfservice.flows.login.ui_url` with the flow ID set as the query parameter `?flow=`. If a valid user session\nexists already, the browser will be redirected to `urls.default_redirect_url` unless the query parameter\n`?refresh=true` was set.\n\nIf this endpoint is called via an AJAX request, the response contains the flow without a redirect. In the\ncase of an error, the `error.id` of the JSON response body can be one of:\n\n`session_already_available`: The user is already signed in.\n`session_aal1_required`: Multi-factor auth (e.g. 2fa) was requested but the user has no session yet.\n`security_csrf_violation`: Unable to fetch the flow because a CSRF violation occurred.\n`security_identity_mismatch`: The requested `?return_to` address is not allowed to be used. Adjust this in the configuration!\n\nThis endpoint is NOT INTENDED for clients that do not have a browser (Chrome, Firefox, ...) as cookies are needed.\n\nMore information can be found at [Ory Kratos User Login](https://www.ory.sh/docs/kratos/self-service/flows/user-login) and [User Registration Documentation](https://www.ory.sh/docs/kratos/self-service/flows/user-registration).", + "description": "This endpoint initializes a browser-based user login flow. This endpoint will set the appropriate\ncookies and anti-CSRF measures required for browser-based flows.\n\nIf this endpoint is opened as a link in the browser, it will be redirected to\n`selfservice.flows.login.ui_url` with the flow ID set as the query parameter `?flow=`. If a valid user session\nexists already, the browser will be redirected to `urls.default_redirect_url` unless the query parameter\n`?refresh=true` was set.\n\nIf this endpoint is called via an AJAX request, the response contains the flow without a redirect. In the\ncase of an error, the `error.id` of the JSON response body can be one of:\n\n`session_already_available`: The user is already signed in.\n`session_aal1_required`: Multi-factor auth (e.g. 2fa) was requested but the user has no session yet.\n`security_csrf_violation`: Unable to fetch the flow because a CSRF violation occurred.\n`security_identity_mismatch`: The requested `?return_to` address is not allowed to be used. Adjust this in the configuration!\n\nThe optional query parameter login_challenge is set when using Kratos with\nHydra in an OAuth2 flow. See the oauth2_provider.url configuration\noption.\n\nThis endpoint is NOT INTENDED for clients that do not have a browser (Chrome, Firefox, ...) as cookies are needed.\n\nMore information can be found at [Ory Kratos User Login](https://www.ory.sh/docs/kratos/self-service/flows/user-login) and [User Registration Documentation](https://www.ory.sh/docs/kratos/self-service/flows/user-registration).", "produces": [ "application/json" ], @@ -1146,6 +1146,12 @@ "summary": "Initialize Login Flow for Browsers", "operationId": "initializeSelfServiceLoginFlowForBrowsers", "parameters": [ + { + "type": "string", + "description": "An optional Hydra login challenge. If present, Kratos will cooperate with\nOry Hydra to act as an OAuth2 identity provider.\n\nThe value for this parameter comes from `login_challenge` URL Query parameter sent to your\napplication (e.g. `/login?login_challenge=abcde`).", + "name": "login_challenge", + "in": "query" + }, { "type": "boolean", "description": "Refresh a login session\n\nIf set to true, this will refresh an existing login session by\nasking the user to sign in again. This will reset the\nauthenticated_at time of the session.", @@ -1748,6 +1754,12 @@ "summary": "Initialize Registration Flow for Browsers", "operationId": "initializeSelfServiceRegistrationFlowForBrowsers", "parameters": [ + { + "type": "string", + "description": "An optional Hydra login challenge. If present, Kratos will cooperate with\nOry Hydra to act as an OAuth2 identity provider.\n\nThe value for this parameter comes from `login_challenge` URL Query parameter sent to your\napplication (e.g. `/registration?login_challenge=abcde`).", + "name": "login_challenge", + "in": "query" + }, { "type": "string", "description": "The URL to return the browser to after the flow was completed.", @@ -2639,6 +2651,261 @@ "type": "object", "title": "JSONRawMessage represents a json.RawMessage that works well with JSON, SQL, and Swagger." }, + "LoginRequest": { + "description": "LoginRequest struct for LoginRequest", + "type": "object", + "properties": { + "challenge": { + "description": "ID is the identifier (\\\"login challenge\\\") of the login request. It is used to identify the session.", + "type": "string" + }, + "client": { + "$ref": "#/definitions/OAuth2Client" + }, + "oidc_context": { + "$ref": "#/definitions/OpenIDConnectContext" + }, + "request_url": { + "description": "RequestURL is the original OAuth 2.0 Authorization URL requested by the OAuth 2.0 client. It is the URL which initiates the OAuth 2.0 Authorization Code or OAuth 2.0 Implicit flow. This URL is typically not needed, but might come in handy if you want to deal with additional request parameters.", + "type": "string" + }, + "requested_access_token_audience": { + "type": "array", + "items": { + "type": "string" + } + }, + "requested_scope": { + "type": "array", + "items": { + "type": "string" + } + }, + "session_id": { + "description": "SessionID is the login session ID. If the user-agent reuses a login session (via cookie / remember flag) this ID will remain the same. If the user-agent did not have an existing authentication session (e.g. remember is false) this will be a new random value. This value is used as the \\\"sid\\\" parameter in the ID Token and in OIDC Front-/Back- channel logout. It's value can generally be used to associate consecutive login requests by a certain user.", + "type": "string" + }, + "skip": { + "description": "Skip, if true, implies that the client has requested the same scopes from the same user previously. If true, you can skip asking the user to grant the requested scopes, and simply forward the user to the redirect URL. This feature allows you to update / set session information.", + "type": "boolean" + }, + "subject": { + "description": "Subject is the user ID of the end-user that authenticated. Now, that end user needs to grant or deny the scope requested by the OAuth 2.0 client. If this value is set and `skip` is true, you MUST include this subject type when accepting the login request, or the request will fail.", + "type": "string" + } + } + }, + "NullUUID": { + "description": "NullUUID can be used with the standard sql package to represent a\nUUID value that can be NULL in the database.", + "type": "object", + "properties": { + "UUID": { + "type": "string", + "format": "uuid" + }, + "Valid": { + "type": "boolean" + } + } + }, + "OAuth2Client": { + "description": "OAuth2Client struct for OAuth2Client", + "type": "object", + "properties": { + "allowed_cors_origins": { + "type": "array", + "items": { + "type": "string" + } + }, + "audience": { + "type": "array", + "items": { + "type": "string" + } + }, + "backchannel_logout_session_required": { + "description": "Boolean value specifying whether the RP requires that a sid (session ID) Claim be included in the Logout Token to identify the RP session with the OP when the backchannel_logout_uri is used. If omitted, the default value is false.", + "type": "boolean" + }, + "backchannel_logout_uri": { + "description": "RP URL that will cause the RP to log itself out when sent a Logout Token by the OP.", + "type": "string" + }, + "client_id": { + "description": "ID is the id for this client.", + "type": "string" + }, + "client_name": { + "description": "Name is the human-readable string name of the client to be presented to the end-user during authorization.", + "type": "string" + }, + "client_secret": { + "description": "Secret is the client's secret. The secret will be included in the create request as cleartext, and then never again. The secret is stored using BCrypt so it is impossible to recover it. Tell your users that they need to write the secret down as it will not be made available again.", + "type": "string" + }, + "client_secret_expires_at": { + "description": "SecretExpiresAt is an integer holding the time at which the client secret will expire or 0 if it will not expire. The time is represented as the number of seconds from 1970-01-01T00:00:00Z as measured in UTC until the date/time of expiration. This feature is currently not supported and it's value will always be set to 0.", + "type": "integer", + "format": "int64" + }, + "client_uri": { + "description": "ClientURI is an URL string of a web page providing information about the client. If present, the server SHOULD display this URL to the end-user in a clickable fashion.", + "type": "string" + }, + "contacts": { + "type": "array", + "items": { + "type": "string" + } + }, + "created_at": { + "description": "CreatedAt returns the timestamp of the client's creation.", + "type": "string", + "format": "date-time" + }, + "frontchannel_logout_session_required": { + "description": "Boolean value specifying whether the RP requires that iss (issuer) and sid (session ID) query parameters be included to identify the RP session with the OP when the frontchannel_logout_uri is used. If omitted, the default value is false.", + "type": "boolean" + }, + "frontchannel_logout_uri": { + "description": "RP URL that will cause the RP to log itself out when rendered in an iframe by the OP. An iss (issuer) query parameter and a sid (session ID) query parameter MAY be included by the OP to enable the RP to validate the request and to determine which of the potentially multiple sessions is to be logged out; if either is included, both MUST be.", + "type": "string" + }, + "grant_types": { + "type": "array", + "items": { + "type": "string" + } + }, + "jwks": { + "type": "object", + "additionalProperties": {} + }, + "jwks_uri": { + "description": "URL for the Client's JSON Web Key Set [JWK] document. If the Client signs requests to the Server, it contains the signing key(s) the Server uses to validate signatures from the Client. The JWK Set MAY also contain the Client's encryption keys(s), which are used by the Server to encrypt responses to the Client. When both signing and encryption keys are made available, a use (Key Use) parameter value is REQUIRED for all keys in the referenced JWK Set to indicate each key's intended usage. Although some algorithms allow the same key to be used for both signatures and encryption, doing so is NOT RECOMMENDED, as it is less secure. The JWK x5c parameter MAY be used to provide X.509 representations of keys provided. When used, the bare key values MUST still be present and MUST match those in the certificate.", + "type": "string" + }, + "logo_uri": { + "description": "LogoURI is an URL string that references a logo for the client.", + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "owner": { + "description": "Owner is a string identifying the owner of the OAuth 2.0 Client.", + "type": "string" + }, + "policy_uri": { + "description": "PolicyURI is a URL string that points to a human-readable privacy policy document that describes how the deployment organization collects, uses, retains, and discloses personal data.", + "type": "string" + }, + "post_logout_redirect_uris": { + "type": "array", + "items": { + "type": "string" + } + }, + "redirect_uris": { + "type": "array", + "items": { + "type": "string" + } + }, + "registration_access_token": { + "description": "RegistrationAccessToken can be used to update, get, or delete the OAuth2 Client.", + "type": "string" + }, + "registration_client_uri": { + "description": "RegistrationClientURI is the URL used to update, get, or delete the OAuth2 Client.", + "type": "string" + }, + "request_object_signing_alg": { + "description": "JWS [JWS] alg algorithm [JWA] that MUST be used for signing Request Objects sent to the OP. All Request Objects from this Client MUST be rejected, if not signed with this algorithm.", + "type": "string" + }, + "request_uris": { + "type": "array", + "items": { + "type": "string" + } + }, + "response_types": { + "type": "array", + "items": { + "type": "string" + } + }, + "scope": { + "description": "Scope is a string containing a space-separated list of scope values (as described in Section 3.3 of OAuth 2.0 [RFC6749]) that the client can use when requesting access tokens.", + "type": "string" + }, + "sector_identifier_uri": { + "description": "URL using the https scheme to be used in calculating Pseudonymous Identifiers by the OP. The URL references a file with a single JSON array of redirect_uri values.", + "type": "string" + }, + "subject_type": { + "description": "SubjectType requested for responses to this Client. The subject_types_supported Discovery parameter contains a list of the supported subject_type values for this server. Valid types include `pairwise` and `public`.", + "type": "string" + }, + "token_endpoint_auth_method": { + "description": "Requested Client Authentication method for the Token Endpoint. The options are client_secret_post, client_secret_basic, private_key_jwt, and none.", + "type": "string" + }, + "token_endpoint_auth_signing_alg": { + "description": "Requested Client Authentication signing algorithm for the Token Endpoint.", + "type": "string" + }, + "tos_uri": { + "description": "TermsOfServiceURI is a URL string that points to a human-readable terms of service document for the client that describes a contractual relationship between the end-user and the client that the end-user accepts when authorizing the client.", + "type": "string" + }, + "updated_at": { + "description": "UpdatedAt returns the timestamp of the last update.", + "type": "string", + "format": "date-time" + }, + "userinfo_signed_response_alg": { + "description": "JWS alg algorithm [JWA] REQUIRED for signing UserInfo Responses. If this is specified, the response will be JWT [JWT] serialized, and signed using JWS. The default, if omitted, is for the UserInfo Response to return the Claims as a UTF-8 encoded JSON object using the application/json content-type.", + "type": "string" + } + } + }, + "OpenIDConnectContext": { + "description": "OpenIDConnectContext struct for OpenIDConnectContext", + "type": "object", + "properties": { + "acr_values": { + "description": "ACRValues is the Authentication AuthorizationContext Class Reference requested in the OAuth 2.0 Authorization request. It is a parameter defined by OpenID Connect and expresses which level of authentication (e.g. 2FA) is required. OpenID Connect defines it as follows: \u003e Requested Authentication AuthorizationContext Class Reference values. Space-separated string that specifies the acr values that the Authorization Server is being requested to use for processing this Authentication Request, with the values appearing in order of preference. The Authentication AuthorizationContext Class satisfied by the authentication performed is returned as the acr Claim Value, as specified in Section 2. The acr Claim is requested as a Voluntary Claim by this parameter.", + "type": "array", + "items": { + "type": "string" + } + }, + "display": { + "description": "Display is a string value that specifies how the Authorization Server displays the authentication and consent user interface pages to the End-User. The defined values are: page: The Authorization Server SHOULD display the authentication and consent UI consistent with a full User Agent page view. If the display parameter is not specified, this is the default display mode. popup: The Authorization Server SHOULD display the authentication and consent UI consistent with a popup User Agent window. The popup User Agent window should be of an appropriate size for a login-focused dialog and should not obscure the entire window that it is popping up over. touch: The Authorization Server SHOULD display the authentication and consent UI consistent with a device that leverages a touch interface. wap: The Authorization Server SHOULD display the authentication and consent UI consistent with a \\\"feature phone\\\" type display. The Authorization Server MAY also attempt to detect the capabilities of the User Agent and present an appropriate display.", + "type": "string" + }, + "id_token_hint_claims": { + "description": "IDTokenHintClaims are the claims of the ID Token previously issued by the Authorization Server being passed as a hint about the End-User's current or past authenticated session with the Client.", + "type": "object", + "additionalProperties": true + }, + "login_hint": { + "description": "LoginHint hints about the login identifier the End-User might use to log in (if necessary). This hint can be used by an RP if it first asks the End-User for their e-mail address (or other identifier) and then wants to pass that value as a hint to the discovered authorization service. This value MAY also be a phone number in the format specified for the phone_number Claim. The use of this parameter is optional.", + "type": "string" + }, + "ui_locales": { + "description": "UILocales is the End-User'id preferred languages and scripts for the user interface, represented as a space-separated list of BCP47 [RFC5646] language tag values, ordered by preference. For instance, the value \\\"fr-CA fr en\\\" represents a preference for French as spoken in Canada, then French (without a region designation), followed by English (without a region designation). An error SHOULD NOT result if some or all of the requested locales are not supported by the OpenID Provider.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, "RecoveryAddressType": { "type": "string", "title": "RecoveryAddressType must not exceed 16 characters as that is the limitation in the SQL Schema." @@ -3543,6 +3810,12 @@ "type": "string", "format": "date-time" }, + "oauth2_login_challenge": { + "$ref": "#/definitions/NullUUID" + }, + "oauth2_login_request": { + "$ref": "#/definitions/LoginRequest" + }, "refresh": { "description": "Refresh stores whether this login flow should enforce re-authentication.", "type": "boolean" @@ -3713,6 +3986,12 @@ "type": "string", "format": "date-time" }, + "oauth2_login_challenge": { + "$ref": "#/definitions/NullUUID" + }, + "oauth2_login_request": { + "$ref": "#/definitions/LoginRequest" + }, "request_url": { "description": "RequestURL is the initial URL that was requested from Ory Kratos. It can be used\nto forward information contained in the URL's path or query for example.", "type": "string" @@ -4930,4 +5209,4 @@ }, "x-forwarded-proto": "string", "x-request-id": "string" -} \ No newline at end of file +} diff --git a/test/e2e/cypress/helpers/httpbin.ts b/test/e2e/cypress/helpers/httpbin.ts new file mode 100644 index 00000000000..3e5ed407be2 --- /dev/null +++ b/test/e2e/cypress/helpers/httpbin.ts @@ -0,0 +1,36 @@ +import * as oauth2 from "./oauth2" + +export function checkToken( + client: oauth2.oAuth2Client, + scope: string[], + check: (token: any) => void, +) { + cy.location("href") + .should("match", new RegExp("https://httpbin.org/anything[?]code=.*")) + .then((body) => { + cy.get("body") + .invoke("text") + .then((text) => { + const result = JSON.parse(text) + const tokenParams = { + code: result.args.code, + redirect_uri: "https://httpbin.org/anything", + scope: scope.join(" "), + } + oauth2 + .getToken( + client.token_endpoint, + client.id, + client.secret, + "authorization_code", + tokenParams.code, + tokenParams.redirect_uri, + tokenParams.scope, + ) + .then((res) => { + const token = res.body + check(token) + }) + }) + }) +} diff --git a/test/e2e/cypress/helpers/oauth2.ts b/test/e2e/cypress/helpers/oauth2.ts new file mode 100644 index 00000000000..5ad3d6680f0 --- /dev/null +++ b/test/e2e/cypress/helpers/oauth2.ts @@ -0,0 +1,101 @@ +import * as uuid from "uuid" + +export type oAuth2Client = { + auth_endpoint: string + token_endpoint: string + id: string + secret: string + token_endpoint_auth_method: string + grant_types: string[] + response_types: string[] + scopes: string[] + callbacks: string[] +} + +export function getDefaultAuthorizeURL(client: oAuth2Client) { + const state = uuid.v4() + const nonce = uuid.v4() + return getAuthorizeURL( + client.auth_endpoint, + "", + client.id, + "0", + nonce, + "https://httpbin.org/anything", + "code", + ["offline", "openid"], + state, + undefined, + ) +} + +export function getAuthorizeURL( + auth_endpoint: string, + audience: string, + client_id: string, + max_age: string, + nonce: string, + redirect_uri: string, + response_type: + | "code" + | "id_token" + | "id_token token" + | "code id_token" + | "code token" + | "code id_token token", + scopes: string[], + state: string, + code_challenge?: string, +): string { + const r = new URL(auth_endpoint) + r.searchParams.append("audience", audience) + r.searchParams.append("client_id", client_id) + r.searchParams.append("max_age", max_age) + r.searchParams.append("nonce", nonce) + r.searchParams.append("prompt", "") + r.searchParams.append("redirect_uri", redirect_uri) + r.searchParams.append("response_type", response_type) + r.searchParams.append("scope", scopes.join(" ")) + r.searchParams.append("state", state) + + code_challenge && r.searchParams.append("code_challenge", code_challenge) + return r.toString() +} + +export function getToken( + token_endpoint: string, + client_id: string, + client_secret: string, + grant_type: "authorization_code", + code: string, + redirect_uri: string, + scope: string, +) { + let urlEncodedData = "" + const urlEncodedDataPairs = [] + urlEncodedDataPairs.push( + encodeURIComponent("grant_type") + "=" + encodeURIComponent(grant_type), + ) + urlEncodedDataPairs.push( + encodeURIComponent("code") + "=" + encodeURIComponent(code), + ) + urlEncodedDataPairs.push( + encodeURIComponent("redirect_uri") + "=" + encodeURIComponent(redirect_uri), + ) + urlEncodedDataPairs.push( + encodeURIComponent("scope") + "=" + encodeURIComponent(scope), + ) + + urlEncodedData = urlEncodedDataPairs.join("&").replace(/%20/g, "+") + + return cy.request({ + method: "POST", + url: token_endpoint, + form: true, + body: urlEncodedData, + headers: { + Accept: "application/json", + Authorization: "Basic " + btoa(client_id + ":" + client_secret), + }, + }) +} diff --git a/test/e2e/cypress/integration/profiles/oidc-provider/error.spec.ts b/test/e2e/cypress/integration/profiles/oidc-provider/error.spec.ts new file mode 100644 index 00000000000..b7bf1b8a6bc --- /dev/null +++ b/test/e2e/cypress/integration/profiles/oidc-provider/error.spec.ts @@ -0,0 +1,34 @@ +import { routes as express } from "../../../helpers/express" + +context("OpenID Provider", () => { + before(() => { + cy.useConfigProfile("oidc-provider") + cy.proxy("express") + }) + it("should fail with invalid login_challenge", () => { + cy.visit(express.login + "?login_challenge=not-a-uuid", { + failOnStatusCode: false, + }).then((d) => { + cy.get(`[data-testid="ui/error/message"]`).then((c) => { + cy.wrap(c[0].textContent).should( + "contain", + "the login_challenge parameter is present but invalid or zero UUID", + ) + }) + }) + }) + + it("should fail with zero login_challenge", () => { + cy.visit( + express.login + "?login_challenge=00000000-0000-0000-0000-000000000000", + { failOnStatusCode: false }, + ).then((d) => { + cy.get(`[data-testid="ui/error/message"]`).then((c) => { + cy.wrap(c[0].textContent).should( + "contain", + "the login_challenge parameter is present but invalid or zero UUID", + ) + }) + }) + }) +}) diff --git a/test/e2e/cypress/integration/profiles/oidc-provider/login.spec.ts b/test/e2e/cypress/integration/profiles/oidc-provider/login.spec.ts new file mode 100644 index 00000000000..649b2b21563 --- /dev/null +++ b/test/e2e/cypress/integration/profiles/oidc-provider/login.spec.ts @@ -0,0 +1,144 @@ +import { gen } from "../../../helpers" +import * as oauth2 from "../../../helpers/oauth2" +import * as httpbin from "../../../helpers/httpbin" + +context("OpenID Provider", () => { + before(() => { + cy.useConfigProfile("oidc-provider") + cy.proxy("express") + }) + const client = { + auth_endpoint: "http://localhost:4744/oauth2/auth", + token_endpoint: "http://localhost:4744/oauth2/token", + id: "dummy-client", + secret: "secret", + token_endpoint_auth_method: "client_secret_basic", + grant_types: ["authorization_code", "refresh_token"], + response_types: ["code", "id_token"], + scopes: ["openid", "offline", "email", "website"], + callbacks: [ + "http://localhost:5555/callback", + "https://httpbin.org/anything", + ], + } + + it("login", () => { + const email = gen.email() + const password = gen.password() + cy.registerApi({ + email: email, + password: password, + fields: { "traits.website": "http://t1.local" }, + }) + + const url = oauth2.getDefaultAuthorizeURL(client) + + cy.visit(url) + + // kratos login ui + cy.get("[name=identifier]").type(email) + cy.get("[name=password]").type(password) + cy.get("[type=submit]").click() + + // consent ui + cy.get("#openid").click() + cy.get("#offline").click() + cy.get("#accept").click() + + const scope = ["offline", "openid"] + httpbin.checkToken(client, scope, (token: any) => { + expect(token).to.have.property("access_token") + expect(token).to.have.property("id_token") + expect(token).to.have.property("refresh_token") + expect(token).to.have.property("token_type") + expect(token).to.have.property("expires_in") + expect(token.scope).to.equal("offline openid") + let idToken = JSON.parse( + decodeURIComponent(escape(window.atob(token.id_token.split(".")[1]))), + ) + expect(idToken).to.have.property("amr") + expect(idToken.amr).to.deep.equal(["password"]) + }) + }) + + it("login-without-scopes", () => { + const email = gen.email() + const password = gen.password() + cy.registerApi({ + email: email, + password: password, + fields: { "traits.website": "http://t1.local" }, + }) + + const url = oauth2.getDefaultAuthorizeURL(client) + cy.visit(url) + + // kratos login ui + cy.get("[name=identifier]").type(email) + cy.get("[name=password]").type(password) + cy.get("[type=submit]").click() + + // consent ui + cy.get("#accept").click() + + const scope = ["offline", "openid"] + httpbin.checkToken(client, scope, (token: any) => { + expect(token).to.have.property("access_token") + expect(token).not.to.have.property("id_token") + expect(token).not.to.have.property("refresh_token") + expect(token).to.have.property("token_type") + expect(token).to.have.property("expires_in") + expect(token.scope).to.equal("") + }) + }) + + it("respects-login-remember-config", () => { + let odicLogin = () => { + const email = gen.email() + const password = gen.password() + cy.registerApi({ + email: email, + password: password, + fields: { "traits.website": "http://t1.local" }, + }) + + let url = oauth2.getDefaultAuthorizeURL(client) + cy.visit(url) + + // kratos login ui + cy.get("[name=identifier]").type(email) + cy.get("[name=password]").type(password) + cy.get("[type=submit]").click() + + // consent ui + cy.get("#accept").click() + } + + cy.clearAllCookies() + cy.updateConfigFile((config) => { + config.session.cookie = config.session.cookie || {} + config.session.cookie.persistent = true + config.session.lifespan = "1234s" + return config + }) + + odicLogin() + cy.getCookie("oauth2_authentication_session_insecure").should("not.be.null") + cy.getCookie("oauth2_authentication_session_insecure").then((cookie) => { + let expected = Date.now() / 1000 + 1234 + let precision = 10 + expect(cookie.expiry).to.be.lessThan(expected + precision) + expect(cookie.expiry).to.be.greaterThan(expected - precision) + }) + + cy.clearAllCookies() + cy.updateConfigFile((config) => { + config.session.cookie = config.session.cookie || {} + config.session.cookie.persistent = false + return config + }) + + odicLogin() + cy.getCookie("oauth2_authentication_session_insecure").should("be.null") + }) +}) diff --git a/test/e2e/cypress/integration/profiles/oidc-provider/mfa.spec.ts b/test/e2e/cypress/integration/profiles/oidc-provider/mfa.spec.ts new file mode 100644 index 00000000000..5e7076d9327 --- /dev/null +++ b/test/e2e/cypress/integration/profiles/oidc-provider/mfa.spec.ts @@ -0,0 +1,155 @@ +import { authenticator } from "otplib" +import { gen } from "../../../helpers" +import { routes as express } from "../../../helpers/express" +import * as oauth2 from "../../../helpers/oauth2" +import * as httpbin from "../../../helpers/httpbin" + +context("OIDC Provider 2FA", () => { + const client = { + auth_endpoint: "http://localhost:4744/oauth2/auth", + token_endpoint: "http://localhost:4744/oauth2/token", + id: "dummy-client", + secret: "secret", + token_endpoint_auth_method: "client_secret_basic", + grant_types: ["authorization_code", "refresh_token"], + response_types: ["code", "id_token"], + scopes: ["openid", "offline", "email", "website"], + callbacks: [ + "http://localhost:5555/callback", + "https://httpbin.org/anything", + ], + } + + ;[ + { + login: express.login, + settings: express.settings, + base: express.base, + profile: "oidc-provider-mfa", + app: "express" as "express", + }, + ].forEach(({ settings, login, profile, app, base }) => { + describe(`for app ${app}`, () => { + let email = gen.email() + let password = gen.password() + let secret + + before(() => { + cy.useConfigProfile(profile) + cy.proxy(app) + + email = gen.email() + password = gen.password() + + cy.register({ + email, + password, + fields: { "traits.website": "http://t1.local" }, + }) + cy.visit(settings) + + cy.get('[data-testid="node/text/totp_secret_key/text"]').then(($e) => { + secret = $e.text().trim() + }) + cy.get('input[name="totp_code"]').then(($e) => { + cy.wrap($e).type(authenticator.generate(secret)) + }) + cy.get('*[name="method"][value="totp"]').click() + cy.expectSettingsSaved() + cy.getSession({ + expectAal: "aal2", + expectMethods: ["password", "totp"], + }) + + cy.clearAllCookies() + }) + + it("should be be asked to sign in with 2fa if set up", () => { + let url = oauth2.getDefaultAuthorizeURL(client) + + cy.get("body") + .then((body$) => { + // Credits https://github.com/suchipi, https://github.com/cypress-io/cypress/issues/944#issuecomment-444312914 + const appWindow = body$[0].ownerDocument.defaultView + const appIframe = appWindow.parent.document.querySelector("iframe") + + return new Promise((resolve) => { + appIframe.onload = () => resolve(undefined) + appWindow.location.href = url + }) + }) + .then(() => { + // kratos login ui + cy.get("[name=identifier]").type(email) + cy.get("[name=password]").type(password) + cy.get("[type=submit]").click() + + cy.get('input[name="totp_code"]').then(($e) => { + cy.wrap($e).type(authenticator.generate(secret)) + }) + cy.get('*[name="method"][value="totp"]').click() + + // consent ui + cy.get("#openid").click() + cy.get("#offline").click() + cy.get("#accept").click() + + let scope = ["offline", "openid"] + httpbin.checkToken(client, scope, (token: any) => { + expect(token).to.have.property("access_token") + expect(token).to.have.property("id_token") + expect(token).to.have.property("refresh_token") + expect(token).to.have.property("token_type") + expect(token).to.have.property("expires_in") + expect(token.scope).to.equal("offline openid") + let idToken = JSON.parse( + decodeURIComponent( + escape(window.atob(token.id_token.split(".")[1])), + ), + ) + expect(idToken).to.have.property("amr") + expect(idToken.amr).to.deep.equal(["password", "totp"]) + }) + + // We shouldn't need to authenticate again + url = oauth2.getDefaultAuthorizeURL(client) + + cy.get("body") + .then((body$) => { + // Credits https://github.com/suchipi, https://github.com/cypress-io/cypress/issues/944#issuecomment-444312914 + const appWindow = body$[0].ownerDocument.defaultView + const appIframe = + appWindow.parent.document.querySelector("iframe") + + return new Promise((resolve) => { + appIframe.onload = () => resolve(undefined) + appWindow.location.href = url + }) + }) + .then(() => { + // We get the consent screen instead of login + cy.get("#openid").click() + cy.get("#offline").click() + cy.get("#accept").click() + + httpbin.checkToken(client, scope, (token: any) => { + expect(token).to.have.property("access_token") + expect(token).to.have.property("id_token") + expect(token).to.have.property("refresh_token") + expect(token).to.have.property("token_type") + expect(token).to.have.property("expires_in") + expect(token.scope).to.equal("offline openid") + let idToken = JSON.parse( + decodeURIComponent( + escape(window.atob(token.id_token.split(".")[1])), + ), + ) + expect(idToken).to.have.property("amr") + expect(idToken.amr).to.deep.equal(["password", "totp"]) + }) + }) + }) + }) + }) + }) +}) diff --git a/test/e2e/cypress/integration/profiles/oidc-provider/registration.spec.ts b/test/e2e/cypress/integration/profiles/oidc-provider/registration.spec.ts new file mode 100644 index 00000000000..2b33b23f4a9 --- /dev/null +++ b/test/e2e/cypress/integration/profiles/oidc-provider/registration.spec.ts @@ -0,0 +1,65 @@ +import { gen } from "../../../helpers" +import * as uuid from "uuid" +import * as oauth2 from "../../../helpers/oauth2" +import * as httpbin from "../../../helpers/httpbin" + +context("OpenID Provider", () => { + before(() => { + cy.useConfigProfile("oidc-provider") + cy.proxy("express") + }) + const client = { + auth_endpoint: "http://localhost:4744/oauth2/auth", + token_endpoint: "http://localhost:4744/oauth2/token", + id: "dummy-client", + secret: "secret", + token_endpoint_auth_method: "client_secret_basic", + grant_types: ["authorization_code", "refresh_token"], + response_types: ["code", "id_token"], + scopes: ["openid", "offline", "email", "website"], + callbacks: [ + "http://localhost:5555/callback", + "https://httpbin.org/anything", + ], + } + + it("registration", () => { + const url = oauth2.getDefaultAuthorizeURL(client) + + cy.visit(url) + cy.get("[data-testid=signup-link]").click() + + const email = gen.email() + const password = gen.password() + + cy.get('[name="traits.email"]').type(email) + cy.get("[name=password]").type(password) + cy.get('[name="traits.website"]').type("http://example.com") + cy.get('input[type=checkbox][name="traits.tos"]').click({ force: true }) + cy.get('[name="traits.age"]').type("199") + cy.get('input[type=checkbox][name="traits.consent"]').click({ force: true }) + cy.get('input[type=checkbox][name="traits.newsletter"]').click({ + force: true, + }) + cy.get("[type=submit]").click() + + cy.get("#openid").click() + cy.get("#offline").click() + cy.get("#accept").click() + + const scope = ["offline", "openid"] + httpbin.checkToken(client, scope, (token: any) => { + expect(token).to.have.property("access_token") + expect(token).to.have.property("id_token") + expect(token).to.have.property("refresh_token") + expect(token).to.have.property("token_type") + expect(token).to.have.property("expires_in") + expect(token.scope).to.equal("offline openid") + let idToken = JSON.parse( + decodeURIComponent(escape(window.atob(token.id_token.split(".")[1]))), + ) + expect(idToken).to.have.property("amr") + expect(idToken.amr).to.deep.equal(["password"]) + }) + }) +}) diff --git a/test/e2e/hydra-kratos-login-consent/.gitignore b/test/e2e/hydra-kratos-login-consent/.gitignore new file mode 100644 index 00000000000..5176eab7c30 --- /dev/null +++ b/test/e2e/hydra-kratos-login-consent/.gitignore @@ -0,0 +1 @@ +hydra-kratos-login-consent diff --git a/test/e2e/hydra-kratos-login-consent/go.mod b/test/e2e/hydra-kratos-login-consent/go.mod new file mode 100644 index 00000000000..6c589972795 --- /dev/null +++ b/test/e2e/hydra-kratos-login-consent/go.mod @@ -0,0 +1,14 @@ +module github.com/ory/kratos/test/e2e/hydra-kratos-login-consent + +go 1.16 + +replace github.com/oleiade/reflections => github.com/oleiade/reflections v1.0.1 + +replace golang.org/x/sys => golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 + +require ( + github.com/julienschmidt/httprouter v1.3.0 + github.com/ory/hydra-client-go v1.7.4 + github.com/ory/kratos-client-go v0.10.1 + github.com/ory/x v0.0.116 +) diff --git a/test/e2e/hydra-kratos-login-consent/go.sum b/test/e2e/hydra-kratos-login-consent/go.sum new file mode 100644 index 00000000000..c241b3ef328 --- /dev/null +++ b/test/e2e/hydra-kratos-login-consent/go.sum @@ -0,0 +1,1249 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.41.0/go.mod h1:OauMR7DV8fzvZIl2qg6rkaIhD/vmgk4iwEw/h6ercmg= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +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/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +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/ajg/form v0.0.0-20160822230020-523a5da1a92f/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= +github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY= +github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= +github.com/aws/aws-sdk-go v1.23.19/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-xray-sdk-go v0.9.4/go.mod h1:XtMKdBQfpVut+tJEwI7+dJFRxxRdxHDyVNp2tHXRq04= +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/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +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/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cihub/seelog v0.0.0-20170130134532-f561c5e57575/go.mod h1:9d6lWj8KzO/fd/NrVaLscBKmPigpZpn5YawRPw+e3Yo= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/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/cockroachdb/cockroach-go v0.0.0-20190925194419-606b3d062051/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk= +github.com/cockroachdb/cockroach-go v0.0.0-20200312223839-f565e4789405/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-20190827140505-75bee3e2ccb6/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20200107194136-26c1120b8d41/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+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-systemd v0.0.0-20190321100706-95778dfbb74e/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/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgraph-io/ristretto v0.0.1/go.mod h1:T40EBc7CJke8TkpiYfGGKAeFjSaxuFXhuXRyumBd6RE= +github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +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/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/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/elazarl/goproxy v0.0.0-20181003060214-f58a169a71a5/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/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/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/go-bindata/go-bindata v3.1.1+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-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.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= +github.com/go-openapi/analysis v0.19.4/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= +github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= +github.com/go-openapi/analysis v0.19.10 h1:5BHISBAXOc/aJK25irLZnx2D3s6WyYaY9D4gmuz9fdE= +github.com/go-openapi/analysis v0.19.10/go.mod h1:qmhS3VNFxBlquFJ0RGoDtylO9y4pgTAUNE9AEEMdlJQ= +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.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= +github.com/go-openapi/errors v0.19.3/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= +github.com/go-openapi/errors v0.19.6 h1:xZMThgv5SQ7SMbWtKFkCf9bBdvR2iEyw9k3zGZONuys= +github.com/go-openapi/errors v0.19.6/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +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/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= +github.com/go-openapi/loads v0.19.3/go.mod h1:YVfqhUCdahYwR3f3iiwQLhicVRvLlU/WO5WPaZvcvSI= +github.com/go-openapi/loads v0.19.5 h1:jZVYWawIQiA1NBnHla28ktg6hrcfTHsCE+3QLVRBIls= +github.com/go-openapi/loads v0.19.5/go.mod h1:dswLCAdonkRufe/gSUC3gN8nTSaB9uaS2es0x5/IbjY= +github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= +github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= +github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= +github.com/go-openapi/runtime v0.19.15/go.mod h1:dhGWCTKRXlAfGnQG0ONViOZpjfg0m2gUt9nTQPQZuoo= +github.com/go-openapi/runtime v0.19.21 h1:81PiYus9l6fwwS4EwhJD+tQb3EPZBeWfgdAVTfFD25Q= +github.com/go-openapi/runtime v0.19.21/go.mod h1:Lm9YGCeecBnUUkFTxPC4s1+lwrkJ0pthx8YvyjCfkgk= +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.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/spec v0.19.6/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= +github.com/go-openapi/spec v0.19.8 h1:qAdZLh1r6QF/hI/gTq+TJTvsQUodZsM7KLqkAJdiJNg= +github.com/go-openapi/spec v0.19.8/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= +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/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= +github.com/go-openapi/strfmt v0.19.2/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= +github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= +github.com/go-openapi/strfmt v0.19.4/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= +github.com/go-openapi/strfmt v0.19.5 h1:0utjKrw+BAh8s57XE9Xz8DUBsVvPmRUB6styvl9wWIM= +github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= +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.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.7/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY= +github.com/go-openapi/swag v0.19.9 h1:1IxuqvBUU3S2Bi4YC7tlP9SJF1gVpCvqN0T2Qof4azE= +github.com/go-openapi/swag v0.19.9/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY= +github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= +github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= +github.com/go-openapi/validate v0.19.3/go.mod h1:90Vh6jjkTn+OT1Eefm0ZixWNFjhtOH7vS9k0lo6zwJo= +github.com/go-openapi/validate v0.19.10 h1:tG3SZ5DC5KF4cyt7nqLVcQXGj5A7mpaYkAcNPlDK+Yk= +github.com/go-openapi/validate v0.19.10/go.mod h1:RKEZTUWDkxKQxN2jDT7ZnZi2bhZlbNMAuKvKB+IaGx8= +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-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= +github.com/gobuffalo/attrs v0.1.0/go.mod h1:fmNpaWyHM0tRm8gCZWKx8yY9fvaNLo2PyzBNSrBZ5Hw= +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= +github.com/gobuffalo/buffalo-plugins v1.0.4/go.mod h1:pWS1vjtQ6uD17MVFWf7i3zfThrEKWlI5+PYLw/NaDB4= +github.com/gobuffalo/buffalo-plugins v1.4.3/go.mod h1:uCzTY0woez4nDMdQjkcOYKanngeUVRO2HZi7ezmAjWY= +github.com/gobuffalo/buffalo-plugins v1.5.1/go.mod h1:jbmwSZK5+PiAP9cC09VQOrGMZFCa/P0UMlIS3O12r5w= +github.com/gobuffalo/buffalo-plugins v1.6.4/go.mod h1:/+N1aophkA2jZ1ifB2O3Y9yGwu6gKOVMtUmJnbg+OZI= +github.com/gobuffalo/buffalo-plugins v1.6.5/go.mod h1:0HVkbgrVs/MnPZ/FOseDMVanCTm2RNcdM0PuXcL1NNI= +github.com/gobuffalo/buffalo-plugins v1.6.7/go.mod h1:ZGZRkzz2PiKWHs0z7QsPBOTo2EpcGRArMEym6ghKYgk= +github.com/gobuffalo/buffalo-plugins v1.6.9/go.mod h1:yYlYTrPdMCz+6/+UaXg5Jm4gN3xhsvsQ2ygVatZV5vw= +github.com/gobuffalo/buffalo-plugins v1.6.11/go.mod h1:eAA6xJIL8OuynJZ8amXjRmHND6YiusVAaJdHDN1Lu8Q= +github.com/gobuffalo/buffalo-plugins v1.8.2/go.mod h1:9te6/VjEQ7pKp7lXlDIMqzxgGpjlKoAcAANdCgoR960= +github.com/gobuffalo/buffalo-plugins v1.8.3/go.mod h1:IAWq6vjZJVXebIq2qGTLOdlXzmpyTZ5iJG5b59fza5U= +github.com/gobuffalo/buffalo-plugins v1.9.4/go.mod h1:grCV6DGsQlVzQwk6XdgcL3ZPgLm9BVxlBmXPMF8oBHI= +github.com/gobuffalo/buffalo-plugins v1.10.0/go.mod h1:4osg8d9s60txLuGwXnqH+RCjPHj9K466cDFRl3PErHI= +github.com/gobuffalo/buffalo-plugins v1.11.0/go.mod h1:rtIvAYRjYibgmWhnjKmo7OadtnxuMG5ZQLr25ozAzjg= +github.com/gobuffalo/buffalo-plugins v1.15.0/go.mod h1:BqSx01nwgKUQr/MArXzFkSD0QvdJidiky1OKgyfgrK8= +github.com/gobuffalo/buffalo-pop v1.0.5/go.mod h1:Fw/LfFDnSmB/vvQXPvcXEjzP98Tc+AudyNWUBWKCwQ8= +github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= +github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= +github.com/gobuffalo/envy v1.6.4/go.mod h1:Abh+Jfw475/NWtYMEt+hnJWRiC8INKWibIMyNt1w2Mc= +github.com/gobuffalo/envy v1.6.5/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= +github.com/gobuffalo/envy v1.6.6/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= +github.com/gobuffalo/envy v1.6.7/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= +github.com/gobuffalo/envy v1.6.8/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= +github.com/gobuffalo/envy v1.6.9/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= +github.com/gobuffalo/envy v1.6.10/go.mod h1:X0CFllQjTV5ogsnUrg+Oks2yTI+PU2dGYBJOEI2D1Uo= +github.com/gobuffalo/envy v1.6.11/go.mod h1:Fiq52W7nrHGDggFPhn2ZCcHw4u/rqXkqo+i7FB6EAcg= +github.com/gobuffalo/envy v1.6.12/go.mod h1:qJNrJhKkZpEW0glh5xP2syQHH5kgdmgsKss2Kk8PTP0= +github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.7.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w= +github.com/gobuffalo/envy v1.8.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w= +github.com/gobuffalo/envy v1.9.0/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w= +github.com/gobuffalo/events v1.0.3/go.mod h1:Txo8WmqScapa7zimEQIwgiJBvMECMe9gJjsKNPN3uZw= +github.com/gobuffalo/events v1.0.7/go.mod h1:z8txf6H9jWhQ5Scr7YPLWg/cgXBRj8Q4uYI+rsVCCSQ= +github.com/gobuffalo/events v1.0.8/go.mod h1:A5KyqT1sA+3GJiBE4QKZibse9mtOcI9nw8gGrDdqYGs= +github.com/gobuffalo/events v1.1.3/go.mod h1:9yPGWYv11GENtzrIRApwQRMYSbUgCsZ1w6R503fCfrk= +github.com/gobuffalo/events v1.1.4/go.mod h1:09/YRRgZHEOts5Isov+g9X2xajxdvOAcUuAHIX/O//A= +github.com/gobuffalo/events v1.1.5/go.mod h1:3YUSzgHfYctSjEjLCWbkXP6djH2M+MLaVRzb4ymbAK0= +github.com/gobuffalo/events v1.1.7/go.mod h1:6fGqxH2ing5XMb3EYRq9LEkVlyPGs4oO/eLzh+S8CxY= +github.com/gobuffalo/events v1.1.8/go.mod h1:UFy+W6X6VbCWS8k2iT81HYX65dMtiuVycMy04cplt/8= +github.com/gobuffalo/events v1.1.9/go.mod h1:/0nf8lMtP5TkgNbzYxR6Bl4GzBy5s5TebgNTdRfRbPM= +github.com/gobuffalo/events v1.3.1/go.mod h1:9JOkQVoyRtailYVE/JJ2ZQ/6i4gTjM5t2HsZK4C1cSA= +github.com/gobuffalo/events v1.4.1/go.mod h1:SjXgWKpeSuvQDvGhgMz5IXx3Czu+IbL+XPLR41NvVQY= +github.com/gobuffalo/fizz v1.0.12/go.mod h1:C0sltPxpYK8Ftvf64kbsQa2yiCZY4RZviurNxXdAKwc= +github.com/gobuffalo/fizz v1.9.8/go.mod h1:w1FEn1yKNVCc49KnADGyYGRPH7jFON3ak4Bj1yUudHo= +github.com/gobuffalo/flect v0.0.0-20180907193754-dc14d8acaf9f/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= +github.com/gobuffalo/flect v0.0.0-20181002182613-4571df4b1daf/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= +github.com/gobuffalo/flect v0.0.0-20181007231023-ae7ed6bfe683/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= +github.com/gobuffalo/flect v0.0.0-20181018182602-fd24a256709f/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= +github.com/gobuffalo/flect v0.0.0-20181019110701-3d6f0b585514/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= +github.com/gobuffalo/flect v0.0.0-20181024204909-8f6be1a8c6c2/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= +github.com/gobuffalo/flect v0.0.0-20181104133451-1f6e9779237a/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= +github.com/gobuffalo/flect v0.0.0-20181114183036-47375f6d8328/go.mod h1:0HvNbHdfh+WOvDSIASqJOSxTOWSxCCUF++k/Y53v9rI= +github.com/gobuffalo/flect v0.0.0-20181210151238-24a2b68e0316/go.mod h1:en58vff74S9b99Eg42Dr+/9yPu437QjlNsO/hBYPuOk= +github.com/gobuffalo/flect v0.0.0-20190104192022-4af577e09bf2/go.mod h1:en58vff74S9b99Eg42Dr+/9yPu437QjlNsO/hBYPuOk= +github.com/gobuffalo/flect v0.0.0-20190117212819-a62e61d96794/go.mod h1:397QT6v05LkZkn07oJXXT6y9FCfwC8Pug0WA2/2mE9k= +github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= +github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/flect v0.1.5/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80= +github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80= +github.com/gobuffalo/flect v0.2.1/go.mod h1:vmkQwuZYhN5Pc4ljYQZzP+1sq+NEkK+lh20jmEmX3jc= +github.com/gobuffalo/genny v0.0.0-20180924032338-7af3a40f2252/go.mod h1:tUTQOogrr7tAQnhajMSH6rv1BVev34H2sa1xNHMy94g= +github.com/gobuffalo/genny v0.0.0-20181003150629-3786a0744c5d/go.mod h1:WAd8HmjMVrnkAZbmfgH5dLBUchsZfqzp/WS5sQz+uTM= +github.com/gobuffalo/genny v0.0.0-20181005145118-318a41a134cc/go.mod h1:WAd8HmjMVrnkAZbmfgH5dLBUchsZfqzp/WS5sQz+uTM= +github.com/gobuffalo/genny v0.0.0-20181007153042-b8de7d566757/go.mod h1:+oG5Ljrw04czAHbPXREwaFojJbpUvcIy4DiOnbEJFTA= +github.com/gobuffalo/genny v0.0.0-20181012161047-33e5f43d83a6/go.mod h1:+oG5Ljrw04czAHbPXREwaFojJbpUvcIy4DiOnbEJFTA= +github.com/gobuffalo/genny v0.0.0-20181017160347-90a774534246/go.mod h1:+oG5Ljrw04czAHbPXREwaFojJbpUvcIy4DiOnbEJFTA= +github.com/gobuffalo/genny v0.0.0-20181024195656-51392254bf53/go.mod h1:o9GEH5gn5sCKLVB5rHFC4tq40rQ3VRUzmx6WwmaqISE= +github.com/gobuffalo/genny v0.0.0-20181025145300-af3f81d526b8/go.mod h1:uZ1fFYvdcP8mu0B/Ynarf6dsGvp7QFIpk/QACUuFUVI= +github.com/gobuffalo/genny v0.0.0-20181027191429-94d6cfb5c7fc/go.mod h1:x7SkrQQBx204Y+O9EwRXeszLJDTaWN0GnEasxgLrQTA= +github.com/gobuffalo/genny v0.0.0-20181027195209-3887b7171c4f/go.mod h1:JbKx8HSWICu5zyqWOa0dVV1pbbXOHusrSzQUprW6g+w= +github.com/gobuffalo/genny v0.0.0-20181106193839-7dcb0924caf1/go.mod h1:x61yHxvbDCgQ/7cOAbJCacZQuHgB0KMSzoYcw5debjU= +github.com/gobuffalo/genny v0.0.0-20181107223128-f18346459dbe/go.mod h1:utQD3aKKEsdb03oR+Vi/6ztQb1j7pO10N3OBoowRcSU= +github.com/gobuffalo/genny v0.0.0-20181114215459-0a4decd77f5d/go.mod h1:kN2KZ8VgXF9VIIOj/GM0Eo7YK+un4Q3tTreKOf0q1ng= +github.com/gobuffalo/genny v0.0.0-20181119162812-e8ff4adce8bb/go.mod h1:BA9htSe4bZwBDJLe8CUkoqkypq3hn3+CkoHqVOW718E= +github.com/gobuffalo/genny v0.0.0-20181127225641-2d959acc795b/go.mod h1:l54xLXNkteX/PdZ+HlgPk1qtcrgeOr3XUBBPDbH+7CQ= +github.com/gobuffalo/genny v0.0.0-20181128191930-77e34f71ba2a/go.mod h1:FW/D9p7cEEOqxYA71/hnrkOWm62JZ5ZNxcNIVJEaWBU= +github.com/gobuffalo/genny v0.0.0-20181203165245-fda8bcce96b1/go.mod h1:wpNSANu9UErftfiaAlz1pDZclrYzLtO5lALifODyjuM= +github.com/gobuffalo/genny v0.0.0-20181203201232-849d2c9534ea/go.mod h1:wpNSANu9UErftfiaAlz1pDZclrYzLtO5lALifODyjuM= +github.com/gobuffalo/genny v0.0.0-20181206121324-d6fb8a0dbe36/go.mod h1:wpNSANu9UErftfiaAlz1pDZclrYzLtO5lALifODyjuM= +github.com/gobuffalo/genny v0.0.0-20181207164119-84844398a37d/go.mod h1:y0ysCHGGQf2T3vOhCrGHheYN54Y/REj0ayd0Suf4C/8= +github.com/gobuffalo/genny v0.0.0-20181211165820-e26c8466f14d/go.mod h1:sHnK+ZSU4e2feXP3PA29ouij6PUEiN+RCwECjCTB3yM= +github.com/gobuffalo/genny v0.0.0-20190104222617-a71664fc38e7/go.mod h1:QPsQ1FnhEsiU8f+O0qKWXz2RE4TiDqLVChWkBuh1WaY= +github.com/gobuffalo/genny v0.0.0-20190112155932-f31a84fcacf5/go.mod h1:CIaHCrSIuJ4il6ka3Hub4DR4adDrGoXGEEt2FbBxoIo= +github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= +github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= +github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= +github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= +github.com/gobuffalo/genny v0.2.0/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= +github.com/gobuffalo/genny v0.3.0/go.mod h1:ywJ2CoXrTZj7rbS8HTbzv7uybnLKlsNSBhEQ+yFI3E8= +github.com/gobuffalo/genny v0.6.0/go.mod h1:Vigx9VDiNscYpa/LwrURqGXLSIbzTfapt9+K6gF1kTA= +github.com/gobuffalo/genny/v2 v2.0.5/go.mod h1:kRkJuAw9mdI37AiEYjV4Dl+TgkBDYf8HZVjLkqe5eBg= +github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= +github.com/gobuffalo/github_flavored_markdown v1.0.4/go.mod h1:uRowCdK+q8d/RF0Kt3/DSalaIXbb0De/dmTqMQdkQ4I= +github.com/gobuffalo/github_flavored_markdown v1.0.5/go.mod h1:U0643QShPF+OF2tJvYNiYDLDGDuQmJZXsf/bHOJPsMY= +github.com/gobuffalo/github_flavored_markdown v1.0.7/go.mod h1:w93Pd9Lz6LvyQXEG6DktTPHkOtCbr+arAD5mkwMzXLI= +github.com/gobuffalo/github_flavored_markdown v1.1.0/go.mod h1:TSpTKWcRTI0+v7W3x8dkSKMLJSUpuVitlptCkpeY8ic= +github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= +github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= +github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= +github.com/gobuffalo/gogen v0.2.0/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= +github.com/gobuffalo/helpers v0.2.2/go.mod h1:xYbzUdCUpVzLwLnqV8HIjT6hmG0Cs7YIBCJkNM597jw= +github.com/gobuffalo/helpers v0.2.4/go.mod h1:NX7v27yxPDOPTgUFYmJ5ow37EbxdoLraucOGvMNawyk= +github.com/gobuffalo/helpers v0.5.0/go.mod h1:stpgxJ2C7T99NLyAxGUnYMM2zAtBk5NKQR0SIbd05j4= +github.com/gobuffalo/helpers v0.6.0/go.mod h1:pncVrer7x/KRvnL5aJABLAuT/RhKRR9klL6dkUOhyv8= +github.com/gobuffalo/helpers v0.6.1/go.mod h1:wInbDi0vTJKZBviURTLRMFLE4+nF2uRuuL2fnlYo7w4= +github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM= +github.com/gobuffalo/httptest v1.0.2/go.mod h1:7T1IbSrg60ankme0aDLVnEY0h056g9M1/ZvpVThtB7E= +github.com/gobuffalo/licenser v0.0.0-20180924033006-eae28e638a42/go.mod h1:Ubo90Np8gpsSZqNScZZkVXXAo5DGhTb+WYFIjlnog8w= +github.com/gobuffalo/licenser v0.0.0-20181025145548-437d89de4f75/go.mod h1:x3lEpYxkRG/XtGCUNkio+6RZ/dlOvLzTI9M1auIwFcw= +github.com/gobuffalo/licenser v0.0.0-20181027200154-58051a75da95/go.mod h1:BzhaaxGd1tq1+OLKObzgdCV9kqVhbTulxOpYbvMQWS0= +github.com/gobuffalo/licenser v0.0.0-20181109171355-91a2a7aac9a7/go.mod h1:m+Ygox92pi9bdg+gVaycvqE8RVSjZp7mWw75+K5NPHk= +github.com/gobuffalo/licenser v0.0.0-20181128165715-cc7305f8abed/go.mod h1:oU9F9UCE+AzI/MueCKZamsezGOOHfSirltllOVeRTAE= +github.com/gobuffalo/licenser v0.0.0-20181203160806-fe900bbede07/go.mod h1:ph6VDNvOzt1CdfaWC+9XwcBnlSTBz2j49PBwum6RFaU= +github.com/gobuffalo/licenser v0.0.0-20181211173111-f8a311c51159/go.mod h1:ve/Ue99DRuvnTaLq2zKa6F4KtHiYf7W046tDjuGYPfM= +github.com/gobuffalo/licenser v1.1.0/go.mod h1:ZVWE6uKUE3rGf7sedUHWVjNWrEgxaUQLVFL+pQiWpfY= +github.com/gobuffalo/logger v0.0.0-20181022175615-46cfb361fc27/go.mod h1:8sQkgyhWipz1mIctHF4jTxmJh1Vxhp7mP8IqbljgJZo= +github.com/gobuffalo/logger v0.0.0-20181027144941-73d08d2bb969/go.mod h1:7uGg2duHKpWnN4+YmyKBdLXfhopkAdVM6H3nKbyFbz8= +github.com/gobuffalo/logger v0.0.0-20181027193913-9cf4dd0efe46/go.mod h1:7uGg2duHKpWnN4+YmyKBdLXfhopkAdVM6H3nKbyFbz8= +github.com/gobuffalo/logger v0.0.0-20181109185836-3feeab578c17/go.mod h1:oNErH0xLe+utO+OW8ptXMSA5DkiSEDW1u3zGIt8F9Ew= +github.com/gobuffalo/logger v0.0.0-20181117211126-8e9b89b7c264/go.mod h1:5etB91IE0uBlw9k756fVKZJdS+7M7ejVhmpXXiSFj0I= +github.com/gobuffalo/logger v0.0.0-20181127160119-5b956e21995c/go.mod h1:+HxKANrR9VGw9yN3aOAppJKvhO05ctDi63w4mDnKv2U= +github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= +github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= +github.com/gobuffalo/logger v1.0.1/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= +github.com/gobuffalo/logger v1.0.3/go.mod h1:SoeejUwldiS7ZsyCBphOGURmWdwUFXs0J7TCjEhjKxM= +github.com/gobuffalo/makr v1.1.5/go.mod h1:Y+o0btAH1kYAMDJW/TX3+oAXEu0bmSLLoC9mIFxtzOw= +github.com/gobuffalo/mapi v1.0.0/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/mapi v1.1.0/go.mod h1:pqQ1XAqvpy/JYtRwoieNps2yU8MFiMxBUpAm2FBtQ50= +github.com/gobuffalo/mapi v1.2.1/go.mod h1:giGJ2AUESRepOFYAzWpq8Gf/s/QDryxoEHisQtFN3cY= +github.com/gobuffalo/meta v0.0.0-20181018155829-df62557efcd3/go.mod h1:XTTOhwMNryif3x9LkTTBO/Llrveezd71u3quLd0u7CM= +github.com/gobuffalo/meta v0.0.0-20181018192820-8c6cef77dab3/go.mod h1:E94EPzx9NERGCY69UWlcj6Hipf2uK/vnfrF4QD0plVE= +github.com/gobuffalo/meta v0.0.0-20181025145500-3a985a084b0a/go.mod h1:YDAKBud2FP7NZdruCSlmTmDOZbVSa6bpK7LJ/A/nlKg= +github.com/gobuffalo/meta v0.0.0-20181114191255-b130ebedd2f7/go.mod h1:K6cRZ29ozr4Btvsqkjvg5nDFTLOgTqf03KA70Ks0ypE= +github.com/gobuffalo/meta v0.0.0-20181127070345-0d7e59dd540b/go.mod h1:RLO7tMvE0IAKAM8wny1aN12pvEKn7EtkBLkUZR00Qf8= +github.com/gobuffalo/meta v0.0.0-20190120163247-50bbb1fa260d/go.mod h1:KKsH44nIK2gA8p0PJmRT9GvWJUdphkDUA8AJEvFWiqM= +github.com/gobuffalo/meta v0.0.0-20190329152330-e161e8a93e3b/go.mod h1:mCRSy5F47tjK8yaIDcJad4oe9fXxY5gLrx3Xx2spK+0= +github.com/gobuffalo/meta v0.3.0/go.mod h1:cpr6mrUX5H/B4wEP86Gdq568TK4+dKUD8oRPl698RUw= +github.com/gobuffalo/mw-basicauth v1.0.3/go.mod h1:dg7+ilMZOKnQFHDefUzUHufNyTswVUviCBgF244C1+0= +github.com/gobuffalo/mw-contenttype v0.0.0-20180802152300-74f5a47f4d56/go.mod h1:7EvcmzBbeCvFtQm5GqF9ys6QnCxz2UM1x0moiWLq1No= +github.com/gobuffalo/mw-csrf v0.0.0-20180802151833-446ff26e108b/go.mod h1:sbGtb8DmDZuDUQoxjr8hG1ZbLtZboD9xsn6p77ppcHo= +github.com/gobuffalo/mw-forcessl v0.0.0-20180802152810-73921ae7a130/go.mod h1:JvNHRj7bYNAMUr/5XMkZaDcw3jZhUZpsmzhd//FFWmQ= +github.com/gobuffalo/mw-i18n v0.0.0-20180802152014-e3060b7e13d6/go.mod h1:91AQfukc52A6hdfIfkxzyr+kpVYDodgAeT5cjX1UIj4= +github.com/gobuffalo/mw-paramlogger v0.0.0-20181005191442-d6ee392ec72e/go.mod h1:6OJr6VwSzgJMqWMj7TYmRUqzNe2LXu/W1rRW4MAz/ME= +github.com/gobuffalo/mw-tokenauth v0.0.0-20181001105134-8545f626c189/go.mod h1:UqBF00IfKvd39ni5+yI5MLMjAf4gX7cDKN/26zDOD6c= +github.com/gobuffalo/nulls v0.2.0/go.mod h1:w4q8RoSCEt87Q0K0sRIZWYeIxkxog5mh3eN3C/n+dUc= +github.com/gobuffalo/nulls v0.3.0/go.mod h1:UP49vd/k+bcaz6m0cHMyuk8oQ7XgLnkfxeiVoPAvBSs= +github.com/gobuffalo/packd v0.0.0-20181027182251-01ad393492c8/go.mod h1:SmdBdhj6uhOsg1Ui4SFAyrhuc7U4VCildosO5IDJ3lc= +github.com/gobuffalo/packd v0.0.0-20181027190505-aafc0d02c411/go.mod h1:SmdBdhj6uhOsg1Ui4SFAyrhuc7U4VCildosO5IDJ3lc= +github.com/gobuffalo/packd v0.0.0-20181027194105-7ae579e6d213/go.mod h1:SmdBdhj6uhOsg1Ui4SFAyrhuc7U4VCildosO5IDJ3lc= +github.com/gobuffalo/packd v0.0.0-20181031195726-c82734870264/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI= +github.com/gobuffalo/packd v0.0.0-20181104210303-d376b15f8e96/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI= +github.com/gobuffalo/packd v0.0.0-20181111195323-b2e760a5f0ff/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI= +github.com/gobuffalo/packd v0.0.0-20181114190715-f25c5d2471d7/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI= +github.com/gobuffalo/packd v0.0.0-20181124090624-311c6248e5fb/go.mod h1:Foenia9ZvITEvG05ab6XpiD5EfBHPL8A6hush8SJ0o8= +github.com/gobuffalo/packd v0.0.0-20181207120301-c49825f8f6f4/go.mod h1:LYc0TGKFBBFTRC9dg2pcRcMqGCTMD7T2BIMP7OBuQAA= +github.com/gobuffalo/packd v0.0.0-20181212173646-eca3b8fd6687/go.mod h1:LYc0TGKFBBFTRC9dg2pcRcMqGCTMD7T2BIMP7OBuQAA= +github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packd v0.2.0/go.mod h1:k2CkHP3bjbqL2GwxwhxUy1DgnlbW644hkLC9iIUvZwY= +github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= +github.com/gobuffalo/packd v1.0.0/go.mod h1:6VTc4htmJRFB7u1m/4LeMTWjFoYrUiBkU9Fdec9hrhI= +github.com/gobuffalo/packr v1.13.7/go.mod h1:KkinLIn/n6+3tVXMwg6KkNvWwVsrRAz4ph+jgpk3Z24= +github.com/gobuffalo/packr v1.15.0/go.mod h1:t5gXzEhIviQwVlNx/+3SfS07GS+cZ2hn76WLzPp6MGI= +github.com/gobuffalo/packr v1.15.1/go.mod h1:IeqicJ7jm8182yrVmNbM6PR4g79SjN9tZLH8KduZZwE= +github.com/gobuffalo/packr v1.19.0/go.mod h1:MstrNkfCQhd5o+Ct4IJ0skWlxN8emOq8DsoT1G98VIU= +github.com/gobuffalo/packr v1.20.0/go.mod h1:JDytk1t2gP+my1ig7iI4NcVaXr886+N0ecUga6884zw= +github.com/gobuffalo/packr v1.21.0/go.mod h1:H00jGfj1qFKxscFJSw8wcL4hpQtPe1PfU2wa6sg/SR0= +github.com/gobuffalo/packr v1.22.0/go.mod h1:Qr3Wtxr3+HuQEwWqlLnNW4t1oTvK+7Gc/Rnoi/lDFvA= +github.com/gobuffalo/packr/v2 v2.0.0-rc.8/go.mod h1:y60QCdzwuMwO2R49fdQhsjCPv7tLQFR0ayzxxla9zes= +github.com/gobuffalo/packr/v2 v2.0.0-rc.9/go.mod h1:fQqADRfZpEsgkc7c/K7aMew3n4aF1Kji7+lIZeR98Fc= +github.com/gobuffalo/packr/v2 v2.0.0-rc.10/go.mod h1:4CWWn4I5T3v4c1OsJ55HbHlUEKNWMITG5iIkdr4Px4w= +github.com/gobuffalo/packr/v2 v2.0.0-rc.11/go.mod h1:JoieH/3h3U4UmatmV93QmqyPUdf4wVM9HELaHEu+3fk= +github.com/gobuffalo/packr/v2 v2.0.0-rc.12/go.mod h1:FV1zZTsVFi1DSCboO36Xgs4pzCZBjB/tDV9Cz/lSaR8= +github.com/gobuffalo/packr/v2 v2.0.0-rc.13/go.mod h1:2Mp7GhBFMdJlOK8vGfl7SYtfMP3+5roE39ejlfjw0rA= +github.com/gobuffalo/packr/v2 v2.0.0-rc.14/go.mod h1:06otbrNvDKO1eNQ3b8hst+1010UooI2MFg+B2Ze4MV8= +github.com/gobuffalo/packr/v2 v2.0.0-rc.15/go.mod h1:IMe7H2nJvcKXSF90y4X1rjYIRlNMJYCxEhssBXNZwWs= +github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= +github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= +github.com/gobuffalo/packr/v2 v2.4.0/go.mod h1:ra341gygw9/61nSjAbfwcwh8IrYL4WmR4IsPkPBhQiY= +github.com/gobuffalo/packr/v2 v2.5.2/go.mod h1:sgEE1xNZ6G0FNN5xn9pevVu4nywaxHvgup67xisti08= +github.com/gobuffalo/packr/v2 v2.7.1/go.mod h1:qYEvAazPaVxy7Y7KR0W8qYEE+RymX74kETFqjFoFlOc= +github.com/gobuffalo/plush v3.7.16+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= +github.com/gobuffalo/plush v3.7.20+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= +github.com/gobuffalo/plush v3.7.21+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= +github.com/gobuffalo/plush v3.7.22+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= +github.com/gobuffalo/plush v3.7.23+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= +github.com/gobuffalo/plush v3.7.30+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= +github.com/gobuffalo/plush v3.7.31+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= +github.com/gobuffalo/plush v3.7.32+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= +github.com/gobuffalo/plush v3.8.2+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= +github.com/gobuffalo/plush v3.8.3+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= +github.com/gobuffalo/plush/v4 v4.0.0/go.mod h1:ErFS3UxKqEb8fpFJT7lYErfN/Nw6vHGiDMTjxpk5bQ0= +github.com/gobuffalo/plushgen v0.0.0-20181128164830-d29dcb966cb2/go.mod h1:r9QwptTFnuvSaSRjpSp4S2/4e2D3tJhARYbvEBcKSb4= +github.com/gobuffalo/plushgen v0.0.0-20181203163832-9fc4964505c2/go.mod h1:opEdT33AA2HdrIwK1aibqnTJDVVKXC02Bar/GT1YRVs= +github.com/gobuffalo/plushgen v0.0.0-20181207152837-eedb135bd51b/go.mod h1:Lcw7HQbEVm09sAQrCLzIxuhFbB3nAgp4c55E+UlynR0= +github.com/gobuffalo/plushgen v0.0.0-20190104222512-177cd2b872b3/go.mod h1:tYxCozi8X62bpZyKXYHw1ncx2ZtT2nFvG42kuLwYjoc= +github.com/gobuffalo/plushgen v0.1.2/go.mod h1:3U71v6HWZpVER1nInTXeAwdoRNsRd4W8aeIa1Lyp+Bk= +github.com/gobuffalo/pop v4.8.2+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVDpJWGsxjVjMPnkiThWg= +github.com/gobuffalo/pop v4.8.3+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVDpJWGsxjVjMPnkiThWg= +github.com/gobuffalo/pop v4.8.4+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVDpJWGsxjVjMPnkiThWg= +github.com/gobuffalo/pop v4.13.1+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVDpJWGsxjVjMPnkiThWg= +github.com/gobuffalo/pop/v5 v5.0.11/go.mod h1:mZJHJbA3cy2V18abXYuVop2ldEJ8UZ2DK6qOekC5u5g= +github.com/gobuffalo/release v1.0.35/go.mod h1:VtHFAKs61vO3wboCec5xr9JPTjYyWYcvaM3lclkc4x4= +github.com/gobuffalo/release v1.0.38/go.mod h1:VtHFAKs61vO3wboCec5xr9JPTjYyWYcvaM3lclkc4x4= +github.com/gobuffalo/release v1.0.42/go.mod h1:RPs7EtafH4oylgetOJpGP0yCZZUiO4vqHfTHJjSdpug= +github.com/gobuffalo/release v1.0.52/go.mod h1:RPs7EtafH4oylgetOJpGP0yCZZUiO4vqHfTHJjSdpug= +github.com/gobuffalo/release v1.0.53/go.mod h1:FdF257nd8rqhNaqtDWFGhxdJ/Ig4J7VcS3KL7n/a+aA= +github.com/gobuffalo/release v1.0.54/go.mod h1:Pe5/RxRa/BE8whDpGfRqSI7D1a0evGK1T4JDm339tJc= +github.com/gobuffalo/release v1.0.61/go.mod h1:mfIO38ujUNVDlBziIYqXquYfBF+8FDHUjKZgYC1Hj24= +github.com/gobuffalo/release v1.0.72/go.mod h1:NP5NXgg/IX3M5XmHmWR99D687/3Dt9qZtTK/Lbwc1hU= +github.com/gobuffalo/release v1.1.1/go.mod h1:Sluak1Xd6kcp6snkluR1jeXAogdJZpFFRzTYRs/2uwg= +github.com/gobuffalo/release v1.1.3/go.mod h1:CuXc5/m+4zuq8idoDt1l4va0AXAn/OSs08uHOfMVr8E= +github.com/gobuffalo/release v1.1.6/go.mod h1:18naWa3kBsqO0cItXZNJuefCKOENpbbUIqRL1g+p6z0= +github.com/gobuffalo/release v1.7.0/go.mod h1:xH2NjAueVSY89XgC4qx24ojEQ4zQ9XCGVs5eXwJTkEs= +github.com/gobuffalo/shoulders v1.0.1/go.mod h1:V33CcVmaQ4gRUmHKwq1fiTXuf8Gp/qjQBUL5tHPmvbA= +github.com/gobuffalo/shoulders v1.0.4/go.mod h1:LqMcHhKRuBPMAYElqOe3POHiZ1x7Ry0BE8ZZ84Bx+k4= +github.com/gobuffalo/syncx v0.0.0-20181120191700-98333ab04150/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= +github.com/gobuffalo/syncx v0.0.0-20181120194010-558ac7de985f/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= +github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= +github.com/gobuffalo/syncx v0.1.0/go.mod h1:Mg/s+5pv7IgxEp6sA+NFpqS4o2x+R9dQNwbwT0iuOGQ= +github.com/gobuffalo/tags v2.0.11+incompatible/go.mod h1:9XmhOkyaB7UzvuY4UoZO4s67q8/xRMVJEaakauVQYeY= +github.com/gobuffalo/tags v2.0.14+incompatible/go.mod h1:9XmhOkyaB7UzvuY4UoZO4s67q8/xRMVJEaakauVQYeY= +github.com/gobuffalo/tags v2.0.15+incompatible/go.mod h1:9XmhOkyaB7UzvuY4UoZO4s67q8/xRMVJEaakauVQYeY= +github.com/gobuffalo/tags v2.1.0+incompatible/go.mod h1:9XmhOkyaB7UzvuY4UoZO4s67q8/xRMVJEaakauVQYeY= +github.com/gobuffalo/tags v2.1.7+incompatible/go.mod h1:9XmhOkyaB7UzvuY4UoZO4s67q8/xRMVJEaakauVQYeY= +github.com/gobuffalo/tags/v3 v3.0.2/go.mod h1:ZQeN6TCTiwAFnS0dNcbDtSgZDwNKSpqajvVtt6mlYpA= +github.com/gobuffalo/tags/v3 v3.1.0/go.mod h1:ZQeN6TCTiwAFnS0dNcbDtSgZDwNKSpqajvVtt6mlYpA= +github.com/gobuffalo/uuid v2.0.3+incompatible/go.mod h1:ErhIzkRhm0FtRuiE/PeORqcw4cVi1RtSpnwYrxuvkfE= +github.com/gobuffalo/uuid v2.0.4+incompatible/go.mod h1:ErhIzkRhm0FtRuiE/PeORqcw4cVi1RtSpnwYrxuvkfE= +github.com/gobuffalo/uuid v2.0.5+incompatible/go.mod h1:ErhIzkRhm0FtRuiE/PeORqcw4cVi1RtSpnwYrxuvkfE= +github.com/gobuffalo/validate v2.0.3+incompatible/go.mod h1:N+EtDe0J8252BgfzQUChBgfd6L93m9weay53EWFVsMM= +github.com/gobuffalo/validate v2.0.4+incompatible/go.mod h1:N+EtDe0J8252BgfzQUChBgfd6L93m9weay53EWFVsMM= +github.com/gobuffalo/validate/v3 v3.0.0/go.mod h1:HFpjq+AIiA2RHoQnQVTFKF/ZpUPXwyw82LgyDPxQ9r0= +github.com/gobuffalo/validate/v3 v3.1.0/go.mod h1:HFpjq+AIiA2RHoQnQVTFKF/ZpUPXwyw82LgyDPxQ9r0= +github.com/gobuffalo/validate/v3 v3.2.0/go.mod h1:PrhDOdDHxtN8KUgMvF3TDL0r1YZXV4sQnyFX/EmeETY= +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/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/gofrs/uuid/v3 v3.1.2/go.mod h1:xPwMqoocQ1L5G6pXX5BcE7N5jlzn2o19oqAKxwZW/kI= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/gddo v0.0.0-20180828051604-96d2a289f41e/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4= +github.com/golang/gddo v0.0.0-20190904175337-72a348e765d2/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-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.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/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +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 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-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/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +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/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.1.2/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= +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 v1.3.0/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= +github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +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/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= +github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= +github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= +github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= +github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= +github.com/jackc/pgconn v1.3.2/go.mod h1:LvCquS3HbBKwgl7KbX9KyqEIumJAbm1UMcTvGaIf3bM= +github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= +github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= +github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= +github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= +github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= +github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= +github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= +github.com/jackc/pgtype v1.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0= +github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= +github.com/jackc/pgx v3.6.2+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= +github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= +github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= +github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= +github.com/jackc/pgx/v4 v4.4.1/go.mod h1:6iSW+JznC0YT+SgBn7rNxoEBsBgSmnC5FwyCekOGUiE= +github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +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/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.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/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/karrick/godirwalk v1.7.5/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34= +github.com/karrick/godirwalk v1.7.7/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34= +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/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +github.com/karrick/godirwalk v1.10.9/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +github.com/karrick/godirwalk v1.15.5/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +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/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +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 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= +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/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +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.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +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/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lib/pq v0.0.0-20180327071824-d34b9ff171c2/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.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/luna-duclos/instrumentedsql v0.0.0-20181127104832-b7d587d28109/go.mod h1:PWUIzhtavmOR965zfawVsHXbEuU1G29BPZ/CB3C7jXk= +github.com/luna-duclos/instrumentedsql v1.1.2/go.mod h1:4LGbEqDnopzNAiyxPPDXhLspyunZxgPTMJBKtC6U0BQ= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1/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/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.1 h1:mdxE1MF9o53iCb2Ghj1VfWvh7ZOwHpnVG/xwXrV90U8= +github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/markbates/deplist v1.0.4/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM= +github.com/markbates/deplist v1.0.5/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM= +github.com/markbates/deplist v1.1.3/go.mod h1:BF7ioVzAJYEtzQN/os4rt8H8Ti3h0T7EoN+7eyALktE= +github.com/markbates/going v1.0.2/go.mod h1:UWCk3zm0UKefHZ7l8BNqi26UyiEMniznk8naLdTcy6c= +github.com/markbates/grift v1.0.4/go.mod h1:wbmtW74veyx+cgfwFhlnnMWqhoz55rnHR47oMXzsyVs= +github.com/markbates/hmax v1.0.0/go.mod h1:cOkR9dktiESxIMu+65oc/r/bdY4bE8zZw3OLhLx0X2c= +github.com/markbates/inflect v1.0.0/go.mod h1:oTeZL2KHA7CUX6X+fovmK9OvIOFuqu0TwdQrZjLTh88= +github.com/markbates/inflect v1.0.1/go.mod h1:uv3UVNBe5qBIfCm8O8Q+DW+S1EopeyINj+Ikhc7rnCk= +github.com/markbates/inflect v1.0.3/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs= +github.com/markbates/inflect v1.0.4/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs= +github.com/markbates/oncer v0.0.0-20180924031910-e862a676800b/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= +github.com/markbates/oncer v0.0.0-20180924034138-723ad0170a46/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= +github.com/markbates/oncer v0.0.0-20181014194634-05fccaae8fc4/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= +github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= +github.com/markbates/oncer v1.0.0/go.mod h1:Z59JA581E9GP6w96jai+TGqafHPW+cPfRxz2aSZ0mcI= +github.com/markbates/refresh v1.4.10/go.mod h1:NDPHvotuZmTmesXxr95C9bjlw1/0frJwtME2dzcVKhc= +github.com/markbates/safe v1.0.0/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= +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/mattn/go-colorable v0.0.9/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/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-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.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +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/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +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/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/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg= +github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +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/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/moul/http2curl v0.0.0-20170919181001-9ac6cf4d929b/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nicksnyder/go-i18n v1.10.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/oleiade/reflections v1.0.1/go.mod h1:rdFxbxq4QXVZWj0F+e9jqjDkc7dbp97vkRixKo2JR60= +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/ginkgo v1.9.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +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/onsi/gomega v1.6.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +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= +github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/ory/analytics-go/v4 v4.0.0/go.mod h1:FMx9cLRD9xN+XevPvZ5FDMfignpmcqPP6FUKnJ9/MmE= +github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= +github.com/ory/dockertest/v3 v3.5.4/go.mod h1:J8ZUbNB2FOhm1cFZW9xBpDsODqsSWcyYgtJYVPcnF70= +github.com/ory/fosite v0.29.0/go.mod h1:0atSZmXO7CAcs6NPMI/Qtot8tmZYj04Nddoold4S2h0= +github.com/ory/go-acc v0.0.0-20181118080137-ddc355013f90/go.mod h1:sxnvPCxChFuSmTJGj8FdMupeq1BezCiEpDjTUXQ4hf4= +github.com/ory/go-convenience v0.1.0/go.mod h1:uEY/a60PL5c12nYz4V5cHY03IBmwIAEm8TWB0yn9KNs= +github.com/ory/gojsonreference v0.0.0-20190720135523-6b606c2d8ee8/go.mod h1:wsH1C4nIeeQClDtD5AH7kF1uTS6zWyqfjVDTmB0Em7A= +github.com/ory/gojsonschema v1.1.1-0.20190919112458-f254ca73d5e9/go.mod h1:BNZpdJgB74KOLSsWFvzw6roXg1I6O51WO8roMmW+T7Y= +github.com/ory/herodot v0.6.2/go.mod h1:3BOneqcyBsVybCPAJoi92KN2BpJHcmDqAMcAAaJiJow= +github.com/ory/herodot v0.7.0/go.mod h1:YXKOfAXYdQojDP5sD8m0ajowq3+QXNdtxA+QiUXBwn0= +github.com/ory/hydra-client-go v1.7.4 h1:xazbWaXCsAjRazT8EWStU6qjkT0I0EC6WtXZOGtNau4= +github.com/ory/hydra-client-go v1.7.4/go.mod h1:g1By+kj32wbTmbtBWnFV0NWDif3YBxPvse882PU912I= +github.com/ory/jsonschema/v3 v3.0.1/go.mod h1:jgLHekkFk0uiGdEWGleC+tOm6JSSP8cbf17PnBuGXlw= +github.com/ory/kratos-client-go v0.10.1 h1:kSRk+0leCJ1nPMS+FPho8b9WMzrKNpgszvta0Xo32QU= +github.com/ory/kratos-client-go v0.10.1/go.mod h1:dOQIsar76K07wMPJD/6aMhrWyY+sFGEagLDLso1CpsA= +github.com/ory/viper v1.5.6/go.mod h1:TYmpFpKLxjQwvT4f0QPpkOn4sDXU1kDgAwJpgLYiQ28= +github.com/ory/viper v1.7.4/go.mod h1:T6sodNZKNGPpashUOk7EtXz2isovz8oCd57GNVkkNmE= +github.com/ory/x v0.0.84/go.mod h1:RXLPBG7B+hAViONVg0sHwK+U/ie1Y/NeXrq1JcARfoE= +github.com/ory/x v0.0.93/go.mod h1:lfcTaGXpTZs7IEQAW00r9EtTCOxD//SiP5uWtNiz31g= +github.com/ory/x v0.0.110/go.mod h1:DJfkE3GdakhshNhw4zlKoRaL/ozg/lcTahA9OCih2BE= +github.com/ory/x v0.0.116 h1:gq47UBzFe9l8n4CToLFMAkjNwqTR+oq1JZYxhA0T5dM= +github.com/ory/x v0.0.116/go.mod h1:ImFneVZHXPCeI1EYXLzRylIkOUMQnWT9Xwuasd8QHxw= +github.com/parnurzeal/gorequest v0.2.15/go.mod h1:3Kh2QUMJoqw3icWAecsyzkpY7UzRfDhbRdTjtNwNiUE= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= +github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +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/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +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/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.4.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= +github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= +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/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHiuO9LYd+cIxzgEHCQI4= +github.com/santhosh-tekuri/jsonschema/v2 v2.1.0/go.mod h1:yzJzKUGV4RbWqWIBBP4wSOBqavX5saE02yirLS0OTyg= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/segmentio/analytics-go v3.0.1+incompatible/go.mod h1:C7CYBtQWk4vRk2RyLu0qOcbHJ18E3F1HV2C/8JvKN48= +github.com/segmentio/analytics-go v3.1.0+incompatible/go.mod h1:C7CYBtQWk4vRk2RyLu0qOcbHJ18E3F1HV2C/8JvKN48= +github.com/segmentio/backo-go v0.0.0-20160424052352-204274ad699c/go.mod h1:kJ9mm9YmoWSkk+oQ+5Cj8DEoRCX2JT6As4kEtIIOp1M= +github.com/segmentio/backo-go v0.0.0-20200129164019-23eae7c10bd3/go.mod h1:9/Rh6yILuLysoQnZ2oNooD2g7aBnvM7r/fNVxRNWfBc= +github.com/segmentio/conf v1.2.0/go.mod h1:Y3B9O/PqqWqjyxyWWseyj/quPEtMu1zDp/kVbSWWaB0= +github.com/segmentio/go-snakecase v1.1.0/go.mod h1:jk1miR5MS7Na32PZUykG89Arm+1BUSYhuGR6b7+hJto= +github.com/segmentio/objconv v1.0.1/go.mod h1:auayaH5k3137Cl4SoXTgrzQcuQDmvuVtZgS0fb1Ahys= +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/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= +github.com/shurcooL/highlight_go v0.0.0-20170515013102-78fb10f4a5f8/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= +github.com/shurcooL/octicon v0.0.0-20180602230221-c42b0e3b24d9/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= +github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.1.0/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A= +github.com/sirupsen/logrus v1.1.1/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A= +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/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q= +github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/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/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.0/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/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v0.0.7 h1:FfTH+vuMXOas8jmfb5/M7dzEYx7LpcLb7a0LPe34uOU= +github.com/spf13/cobra v0.0.7/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +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.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.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/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/sqs/goreturns v0.0.0-20181028201513-538ac6014518/go.mod h1:CKI4AZ4XmGV240rTHfO0hfE83S6/a3/Q1siZJ/vXf7A= +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 v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/subosito/gotenv v1.1.1/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tidwall/gjson v1.3.2/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= +github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= +github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/sjson v1.0.4/go.mod h1:bURseu1nuBkFpIES5cz6zBtjmYeOQmEESshn7VpF15Y= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/uber-go/atomic v1.3.2/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.22.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= +github.com/uber/jaeger-lib v1.5.0/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= +github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +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/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +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/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= +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.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.3.0/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE= +go.mongodb.org/mongo-driver v1.3.4 h1:zs/dKNwX0gYUtzwrN9lLiR15hCO0nDwQj5xXx+vjCdE= +go.mongodb.org/mongo-driver v1.3.4/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/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= +golang.org/x/crypto v0.0.0-20181001203147-e3636079e1a4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181015023909-0c41d7ab0a0e/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181024171144-74cb1d3d52f4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181025113841-85e1b3f9139a/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181106171534-e4dc69e5b2fd/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190102171810-8d7daa0c54b3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +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-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200320181102-891825fb96df/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/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-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/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= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180921000356-2f5d2388922f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180926154720-4dfa2610cdf3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181017193950-04a2e542c03f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181102091132-c10e9556a7bc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181207154023-610586996380/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200219183655-46282727080f/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +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-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558 h1:D7nTwh4J0i+5mW4Zjzn5omvlr6YBcWywE6KOcatyNxY= +golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-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-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-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= +golang.org/x/tools v0.0.0-20181119130350-139d099f6620/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181127195227-b4e97c0ed882/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181127232545-e782529d0ddd/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181203210056-e5f3ab76ea4b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181205224935-3576414c54a4/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181206194817-bcd4e47d0288/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181207183836-8bc39b988060/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181212172921-837e80568c09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190102213336-ca9055ed7d04/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190104182027-498d95493402/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190111214448-fc1d57b08d7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190118193359-16909d206f00/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/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-20190531172133-b3315ee88b7d/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-20190613204242-ed0dc450797f/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190617190820-da514acc4774/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-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191224055732-dd894d0a8a40/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200203215610-ab391d50b528/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.6.2/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/netlib v0.0.0-20191229114700-bbb4dff026f8/go.mod h1:2IgXn/sJaRbePPBA1wRj8OE+QLvVaH0q8SK6TSTKlnk= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +gonum.org/v1/plot v0.0.0-20200111075622-4abb28f724d5/go.mod h1:+HbaZVpsa73UwN7kXGCECULRHovLRJjH+t5cFPgxErs= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/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.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-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-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.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.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +gopkg.in/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/check.v1 v0.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/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/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/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/mold.v2 v2.2.0/go.mod h1:XMyyRsGtakkDPbxXbrA5VODo6bUXyvoDjLd5l3T0XoA= +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/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/mail.v2 v2.0.0-20180731213649-a0242b2233b4/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= +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/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/validator.v2 v2.0.0-20180514200540-135c24b11c19/go.mod h1:o4V0GXN9/CAmCsvJ0oXYZvrZOe7syiDZSN1GWGZTGzc= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= +modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= +modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= +modernc.org/strutil v1.1.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= +modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/test/e2e/hydra-kratos-login-consent/main.go b/test/e2e/hydra-kratos-login-consent/main.go new file mode 100644 index 00000000000..f63e47ef07a --- /dev/null +++ b/test/e2e/hydra-kratos-login-consent/main.go @@ -0,0 +1,183 @@ +package main + +import ( + "fmt" + "net/http" + + "github.com/julienschmidt/httprouter" + + "github.com/ory/hydra-client-go/client" + "github.com/ory/hydra-client-go/client/admin" + "github.com/ory/hydra-client-go/models" + kratos "github.com/ory/kratos-client-go" + "github.com/ory/x/osx" + "github.com/ory/x/pointerx" + "github.com/ory/x/urlx" +) + +func check(err error) { + if err != nil { + panic(err) + } +} + +func checkReq(w http.ResponseWriter, err error) bool { + if err != nil { + http.Error(w, fmt.Sprintf("%+v", err), 500) + return false + } + return true +} + +func main() { + router := httprouter.New() + + kratosPublicURL := urlx.ParseOrPanic(osx.GetenvDefault("KRATOS_PUBLIC_URL", "http://localhost:4433")) + adminURL := urlx.ParseOrPanic(osx.GetenvDefault("HYDRA_ADMIN_URL", "http://localhost:4445")) + hc := client.NewHTTPClientWithConfig(nil, &client.TransportConfig{Schemes: []string{adminURL.Scheme}, Host: adminURL.Host, BasePath: adminURL.Path}) + + router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + w.Write([]byte(`ok`)) + }) + router.GET("/login", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + res, err := hc.Admin.GetLoginRequest(admin.NewGetLoginRequestParams(). + WithLoginChallenge(r.URL.Query().Get("login_challenge"))) + if !checkReq(w, err) { + return + } + if *res.Payload.Skip { + res, err := hc.Admin.AcceptLoginRequest(admin.NewAcceptLoginRequestParams(). + WithLoginChallenge(r.URL.Query().Get("login_challenge")). + WithBody(&models.AcceptLoginRequest{Remember: true, RememberFor: 3600, + Subject: res.Payload.Subject})) + if !checkReq(w, err) { + return + } + http.Redirect(w, r, *res.Payload.RedirectTo, http.StatusFound) + return + } + + challenge := r.URL.Query().Get("login_challenge") + _, _ = fmt.Fprintf(w, ` + +
+ + Remember me + + +
+ +`, challenge) + }) + + router.POST("/login", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + if !checkReq(w, r.ParseForm()) { + return + } + if r.Form.Get("action") == "accept" { + res, err := hc.Admin.AcceptLoginRequest(admin.NewAcceptLoginRequestParams(). + WithLoginChallenge(r.URL.Query().Get("login_challenge")). + WithBody(&models.AcceptLoginRequest{ + RememberFor: 3600, Remember: r.Form.Get("remember") == "true", + Subject: pointerx.String(r.Form.Get("username"))})) + if !checkReq(w, err) { + return + } + http.Redirect(w, r, *res.Payload.RedirectTo, http.StatusFound) + return + } + res, err := hc.Admin.RejectLoginRequest(admin.NewRejectLoginRequestParams(). + WithLoginChallenge(r.URL.Query().Get("login_challenge")). + WithBody(&models.RejectRequest{Error: "login rejected request"})) + if !checkReq(w, err) { + return + } + http.Redirect(w, r, *res.Payload.RedirectTo, http.StatusFound) + }) + + router.GET("/consent", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + res, err := hc.Admin.GetConsentRequest(admin.NewGetConsentRequestParams(). + WithConsentChallenge(r.URL.Query().Get("consent_challenge"))) + if !checkReq(w, err) { + return + } + if res.Payload.Skip { + res, err := hc.Admin.AcceptConsentRequest(admin.NewAcceptConsentRequestParams(). + WithConsentChallenge(r.URL.Query().Get("consent_challenge")). + WithBody(&models.AcceptConsentRequest{GrantScope: res.Payload.RequestedScope})) + if !checkReq(w, err) { + return + } + http.Redirect(w, r, *res.Payload.RedirectTo, http.StatusFound) + return + } + + checkoxes := "" + for _, s := range res.Payload.RequestedScope { + checkoxes += fmt.Sprintf(`
  • %s
  • `, s, s, s) + } + + challenge := r.URL.Query().Get("consent_challenge") + _, _ = fmt.Fprintf(w, ` + +
    +
      + %s +
    + + Remember me + + +
    + +`, challenge, checkoxes) + }) + + router.POST("/consent", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + _ = r.ParseForm() + if r.Form.Get("action") == "accept" { + kratosConfig := kratos.NewConfiguration() + kratosConfig.Servers = kratos.ServerConfigurations{{URL: kratosPublicURL.String()}} + kratosClient := kratos.NewAPIClient(kratosConfig) + session, _, err := kratosClient.V0alpha2Api.ToSession(r.Context()).Cookie(r.Header.Get("Cookie")).Execute() + if err != nil { + panic(err) + } + traitMap, ok := session.Identity.Traits.(map[string]interface{}) + if !ok { + panic("type assertion failed") + } + idToken := map[string]interface{}{} + // Populate ID token claims with values found in the session's traits + for _, scope := range r.Form["scope"] { + if v, ok := traitMap[scope]; ok { + idToken[scope] = v + } + } + + res, err := hc.Admin.AcceptConsentRequest(admin.NewAcceptConsentRequestParams(). + WithConsentChallenge(r.URL.Query().Get("consent_challenge")). + WithBody(&models.AcceptConsentRequest{ + Session: &models.ConsentRequestSession{IDToken: idToken}, + Remember: r.Form.Get("remember") == "true", RememberFor: 3600, + GrantScope: r.Form["scope"]})) + if !checkReq(w, err) { + return + } + http.Redirect(w, r, *res.Payload.RedirectTo, http.StatusFound) + return + } + res, err := hc.Admin.RejectConsentRequest(admin.NewRejectConsentRequestParams(). + WithConsentChallenge(r.URL.Query().Get("consent_challenge")). + WithBody(&models.RejectRequest{Error: "consent rejected request"})) + if !checkReq(w, err) { + return + } + http.Redirect(w, r, *res.Payload.RedirectTo, http.StatusFound) + }) + + addr := ":" + osx.GetenvDefault("PORT", "4746") + server := &http.Server{Addr: addr, Handler: router} + fmt.Printf("Starting web server at %s\n", addr) + check(server.ListenAndServe()) +} diff --git a/test/e2e/mock/webhook/go.mod b/test/e2e/mock/webhook/go.mod index 9da3332be88..a12d10e7a51 100644 --- a/test/e2e/mock/webhook/go.mod +++ b/test/e2e/mock/webhook/go.mod @@ -4,4 +4,4 @@ go 1.17 require github.com/sirupsen/logrus v1.8.1 -require golang.org/x/sys v0.0.0-20220818161305-2296e01440c6 // indirect +require golang.org/x/sys v0.0.0-20221006211917-84dc82d7e875 // indirect diff --git a/test/e2e/mock/webhook/go.sum b/test/e2e/mock/webhook/go.sum index 684141838b1..f5ce7ae859e 100644 --- a/test/e2e/mock/webhook/go.sum +++ b/test/e2e/mock/webhook/go.sum @@ -8,5 +8,5 @@ github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20220818161305-2296e01440c6 h1:Sx/u41w+OwrInGdEckYmEuU5gHoGSL4QbDz3S9s6j4U= -golang.org/x/sys v0.0.0-20220818161305-2296e01440c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20221006211917-84dc82d7e875 h1:AzgQNqF+FKwyQ5LbVrVqOcuuFB67N47F9+htZYH0wFM= +golang.org/x/sys v0.0.0-20221006211917-84dc82d7e875/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/test/e2e/package-lock.json b/test/e2e/package-lock.json index 94d57292225..46dce874278 100644 --- a/test/e2e/package-lock.json +++ b/test/e2e/package-lock.json @@ -7,6 +7,9 @@ "": { "name": "@ory/kratos-e2e-suite", "version": "0.0.1", + "dependencies": { + "simple-oauth2": "^2.5.2" + }, "devDependencies": { "@ory/kratos-client": "0.0.0-next.8d3b018594f7", "@types/node": "^16.9.6", @@ -69,12 +72,51 @@ "ms": "^2.1.1" } }, + "node_modules/@hapi/address": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz", + "integrity": "sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ==", + "deprecated": "Moved to 'npm install @sideway/address'" + }, + "node_modules/@hapi/bourne": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-1.3.2.tgz", + "integrity": "sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA==", + "deprecated": "This version has been deprecated and is no longer supported or maintained" + }, "node_modules/@hapi/hoek": { "version": "9.2.1", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz", "integrity": "sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw==", "dev": true }, + "node_modules/@hapi/joi": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-15.1.1.tgz", + "integrity": "sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ==", + "deprecated": "Switch to 'npm install joi'", + "dependencies": { + "@hapi/address": "2.x.x", + "@hapi/bourne": "1.x.x", + "@hapi/hoek": "8.x.x", + "@hapi/topo": "3.x.x" + } + }, + "node_modules/@hapi/joi/node_modules/@hapi/hoek": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.5.1.tgz", + "integrity": "sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow==", + "deprecated": "This version has been deprecated and is no longer supported or maintained" + }, + "node_modules/@hapi/joi/node_modules/@hapi/topo": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-3.1.6.tgz", + "integrity": "sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ==", + "deprecated": "This version has been deprecated and is no longer supported or maintained", + "dependencies": { + "@hapi/hoek": "^8.3.0" + } + }, "node_modules/@hapi/topo": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", @@ -464,6 +506,21 @@ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "dev": true }, + "node_modules/boom": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-7.3.0.tgz", + "integrity": "sha512-Swpoyi2t5+GhOEGw8rEsKvTxFLIDiiKoUc2gsoV6Lyr43LHBIzch3k2MvYUs8RTROrIkVJ3Al0TkaOGjnb+B6A==", + "deprecated": "This module has moved and is now available at @hapi/boom. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues.", + "dependencies": { + "hoek": "6.x.x" + } + }, + "node_modules/bourne": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/bourne/-/bourne-1.1.2.tgz", + "integrity": "sha512-b2dgVkTZhkQirNMohgC00rWfpVqEi9y5tKM1k3JvoNx05ODtfQoPPd4js9CYFQoY0IM8LAmnJulEuWv74zjUOg==", + "deprecated": "This module has moved and is now available at @hapi/bourne. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues." + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -837,6 +894,18 @@ "node": ">=0.10" } }, + "node_modules/date-fns": { + "version": "2.28.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz", + "integrity": "sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==", + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, "node_modules/dayjs": { "version": "1.10.8", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.8.tgz", @@ -847,7 +916,6 @@ "version": "4.3.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -1223,6 +1291,12 @@ "node": ">=8" } }, + "node_modules/hoek": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz", + "integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==", + "deprecated": "This module has moved and is now available at @hapi/hoek. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues." + }, "node_modules/http-cache-semantics": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", @@ -1680,8 +1754,7 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/normalize-url": { "version": "6.1.0", @@ -2010,6 +2083,18 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/simple-oauth2": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/simple-oauth2/-/simple-oauth2-2.5.2.tgz", + "integrity": "sha512-8qjf+nHRdSUllFjjfpnonrU1oF/HNVbDle5HIbvXRYiy38C7KUvYe6w0ZZ//g4AFB6VNWuiZ80HmnycR8ZFDyQ==", + "deprecated": "simple-oauth2 v2 is no longer supported. Please upgrade to v3 for further support", + "dependencies": { + "@hapi/joi": "^15.1.1", + "date-fns": "^2.2.1", + "debug": "^4.1.1", + "wreck": "^14.0.2" + } + }, "node_modules/slice-ansi": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", @@ -2316,6 +2401,17 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, + "node_modules/wreck": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/wreck/-/wreck-14.2.0.tgz", + "integrity": "sha512-NFFft3SMgqrJbXEVfYifh+QDWFxni+98/I7ut7rLbz3F0XOypluHsdo3mdEYssGSirMobM3fGlqhyikbWKDn2Q==", + "deprecated": "This module has moved and is now available at @hapi/wreck. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues.", + "dependencies": { + "boom": "7.x.x", + "bourne": "1.x.x", + "hoek": "6.x.x" + } + }, "node_modules/ws": { "version": "7.5.7", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", @@ -2416,12 +2512,48 @@ } } }, + "@hapi/address": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz", + "integrity": "sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ==" + }, + "@hapi/bourne": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-1.3.2.tgz", + "integrity": "sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA==" + }, "@hapi/hoek": { "version": "9.2.1", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz", "integrity": "sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw==", "dev": true }, + "@hapi/joi": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-15.1.1.tgz", + "integrity": "sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ==", + "requires": { + "@hapi/address": "2.x.x", + "@hapi/bourne": "1.x.x", + "@hapi/hoek": "8.x.x", + "@hapi/topo": "3.x.x" + }, + "dependencies": { + "@hapi/hoek": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.5.1.tgz", + "integrity": "sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow==" + }, + "@hapi/topo": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-3.1.6.tgz", + "integrity": "sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ==", + "requires": { + "@hapi/hoek": "^8.3.0" + } + } + } + }, "@hapi/topo": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", @@ -2741,6 +2873,19 @@ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "dev": true }, + "boom": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-7.3.0.tgz", + "integrity": "sha512-Swpoyi2t5+GhOEGw8rEsKvTxFLIDiiKoUc2gsoV6Lyr43LHBIzch3k2MvYUs8RTROrIkVJ3Al0TkaOGjnb+B6A==", + "requires": { + "hoek": "6.x.x" + } + }, + "bourne": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/bourne/-/bourne-1.1.2.tgz", + "integrity": "sha512-b2dgVkTZhkQirNMohgC00rWfpVqEi9y5tKM1k3JvoNx05ODtfQoPPd4js9CYFQoY0IM8LAmnJulEuWv74zjUOg==" + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -3032,6 +3177,11 @@ "assert-plus": "^1.0.0" } }, + "date-fns": { + "version": "2.28.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz", + "integrity": "sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==" + }, "dayjs": { "version": "1.10.8", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.8.tgz", @@ -3042,7 +3192,6 @@ "version": "4.3.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, "requires": { "ms": "2.1.2" } @@ -3312,6 +3461,11 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "hoek": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz", + "integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==" + }, "http-cache-semantics": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", @@ -3654,8 +3808,7 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "normalize-url": { "version": "6.1.0", @@ -3898,6 +4051,17 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "simple-oauth2": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/simple-oauth2/-/simple-oauth2-2.5.2.tgz", + "integrity": "sha512-8qjf+nHRdSUllFjjfpnonrU1oF/HNVbDle5HIbvXRYiy38C7KUvYe6w0ZZ//g4AFB6VNWuiZ80HmnycR8ZFDyQ==", + "requires": { + "@hapi/joi": "^15.1.1", + "date-fns": "^2.2.1", + "debug": "^4.1.1", + "wreck": "^14.0.2" + } + }, "slice-ansi": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", @@ -4122,6 +4286,16 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, + "wreck": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/wreck/-/wreck-14.2.0.tgz", + "integrity": "sha512-NFFft3SMgqrJbXEVfYifh+QDWFxni+98/I7ut7rLbz3F0XOypluHsdo3mdEYssGSirMobM3fGlqhyikbWKDn2Q==", + "requires": { + "boom": "7.x.x", + "bourne": "1.x.x", + "hoek": "6.x.x" + } + }, "ws": { "version": "7.5.7", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", diff --git a/test/e2e/package.json b/test/e2e/package.json index 556a716ace8..a2d09d3863c 100644 --- a/test/e2e/package.json +++ b/test/e2e/package.json @@ -2,7 +2,7 @@ "name": "@ory/kratos-e2e-suite", "version": "0.0.1", "scripts": { - "test": "cypress run --browser chrome --e2e", + "test": "cypress run --browser chrome", "test:watch": "cypress open --browser chrome", "openapi-generator-cli": "openapi-generator-cli", "wait-on": "wait-on", diff --git a/test/e2e/profiles/oidc-provider-mfa/.kratos.yml b/test/e2e/profiles/oidc-provider-mfa/.kratos.yml new file mode 100644 index 00000000000..ac577ce4572 --- /dev/null +++ b/test/e2e/profiles/oidc-provider-mfa/.kratos.yml @@ -0,0 +1,54 @@ +clients: + http: + disallow_private_ip_ranges: false +selfservice: + flows: + settings: + ui_url: http://localhost:4455/settings + privileged_session_max_age: 5m + required_aal: highest_available + + logout: + after: + default_browser_return_url: http://localhost:4455/login + + registration: + ui_url: http://localhost:4455/registration + after: + password: + hooks: + - hook: session + + login: + ui_url: http://localhost:4455/login + error: + ui_url: http://localhost:4455/error + verification: + ui_url: http://localhost:4455/verify + recovery: + ui_url: http://localhost:4455/recovery + + methods: + totp: + enabled: true + config: + issuer: issuer.ory.sh + webauthn: + enabled: true + config: + rp: + id: localhost + origin: http://localhost:4455 + display_name: Ory + +oauth2_provider: + url: "http://localhost:4745" + +identity: + schemas: + - id: default + url: file://test/e2e/profiles/oidc-provider-mfa/identity.traits.schema.json + +session: + whoami: + required_aal: highest_available diff --git a/test/e2e/profiles/oidc-provider-mfa/identity.traits.schema.json b/test/e2e/profiles/oidc-provider-mfa/identity.traits.schema.json new file mode 100644 index 00000000000..e88020fa60a --- /dev/null +++ b/test/e2e/profiles/oidc-provider-mfa/identity.traits.schema.json @@ -0,0 +1,57 @@ +{ + "$id": "https://schemas.ory.sh/presets/kratos/quickstart/email-password/identity.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Person", + "type": "object", + "properties": { + "traits": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "title": "E-Mail", + "minLength": 3, + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + }, + "webauthn": { + "identifier": true + } + } + } + }, + "website": { + "title": "Website", + "type": "string", + "format": "uri", + "minLength": 10 + }, + "tos": { + "title": "Accept Terms of Service", + "type": "boolean" + }, + "age": { + "title": "Age", + "type": "number", + "maximum": 300 + }, + "consent": { + "title": "Consent", + "type": "boolean" + }, + "newsletter": { + "title": "Newsletter", + "type": "boolean" + } + }, + "required": [ + "email", + "website" + ], + "additionalProperties": false + } + } +} diff --git a/test/e2e/profiles/oidc-provider/.kratos.yml b/test/e2e/profiles/oidc-provider/.kratos.yml new file mode 100644 index 00000000000..43d3700a1da --- /dev/null +++ b/test/e2e/profiles/oidc-provider/.kratos.yml @@ -0,0 +1,41 @@ +clients: + http: + disallow_private_ip_ranges: false +oauth2_provider: + url: "http://localhost:4745" +selfservice: + flows: + settings: + privileged_session_max_age: 5m + ui_url: http://localhost:4455/settings + + logout: + after: + default_browser_return_url: http://localhost:4455/login + + registration: + ui_url: http://localhost:4455/registration + after: + oidc: + hooks: + - hook: session + password: + hooks: + - hook: session + login: + ui_url: http://localhost:4455/login + error: + ui_url: http://localhost:4455/error + verification: + ui_url: http://localhost:4455/verify + recovery: + ui_url: http://localhost:4455/recovery + +identity: + schemas: + - id: default + url: file://test/e2e/profiles/oidc-provider/identity.traits.schema.json + +secrets: + cipher: + - secret-thirty-two-character-long diff --git a/test/e2e/profiles/oidc-provider/identity.traits.schema.json b/test/e2e/profiles/oidc-provider/identity.traits.schema.json new file mode 100644 index 00000000000..e88020fa60a --- /dev/null +++ b/test/e2e/profiles/oidc-provider/identity.traits.schema.json @@ -0,0 +1,57 @@ +{ + "$id": "https://schemas.ory.sh/presets/kratos/quickstart/email-password/identity.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Person", + "type": "object", + "properties": { + "traits": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "title": "E-Mail", + "minLength": 3, + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + }, + "webauthn": { + "identifier": true + } + } + } + }, + "website": { + "title": "Website", + "type": "string", + "format": "uri", + "minLength": 10 + }, + "tos": { + "title": "Accept Terms of Service", + "type": "boolean" + }, + "age": { + "title": "Age", + "type": "number", + "maximum": 300 + }, + "consent": { + "title": "Consent", + "type": "boolean" + }, + "newsletter": { + "title": "Newsletter", + "type": "boolean" + } + }, + "required": [ + "email", + "website" + ], + "additionalProperties": false + } + } +} diff --git a/test/e2e/run.sh b/test/e2e/run.sh index 364a3587921..9514a8309fd 100755 --- a/test/e2e/run.sh +++ b/test/e2e/run.sh @@ -68,8 +68,11 @@ prepare() { if [[ "${nokill}" == "no" ]]; then killall node || true killall modd || true + killall webhook || true killall hydra || true killall hydra-login-consent || true + killall hydra-kratos-login-consent || true + docker kill kratos_test_hydra || true fi if [ -z ${TEST_DATABASE_POSTGRESQL+x} ]; then @@ -120,11 +123,15 @@ prepare() { fi # Check if any ports that we need are open already - ! nc -zv localhost 4446 - ! nc -zv localhost 4455 - ! nc -zv localhost 4456 - ! nc -zv localhost 4457 - ! nc -zv localhost 4458 + nc -zv localhost 4444 && exit 1 + nc -zv localhost 4445 && exit 1 + nc -zv localhost 4446 && exit 1 + nc -zv localhost 4455 && exit 1 + nc -zv localhost 4456 && exit 1 + nc -zv localhost 4457 && exit 1 + nc -zv localhost 4458 && exit 1 + nc -zv localhost 4744 && exit 1 + nc -zv localhost 4745 && exit 1 ( cd "$rn_ui_dir" @@ -168,6 +175,39 @@ prepare() { --scope openid,offline \ --callbacks http://localhost:4455/self-service/methods/oidc/callback/github + ( + cd test/e2e/hydra-login-consent + go build . + PORT=4446 HYDRA_ADMIN_URL=http://localhost:4445 ./hydra-login-consent >"${base}/test/e2e/hydra-ui.e2e.log" 2>&1 & + ) + + # Spin up another Hydra instance with the express node app used as the login UI for kratos-hydra OIDC provider tests + DSN=memory SERVE_PUBLIC_PORT=4744 \ + SERVE_ADMIN_PORT=4745 \ + URLS_SELF_ISSUER=http://localhost:4744 \ + LOG_LEVEL=trace \ + URLS_LOGIN=http://localhost:4455/login \ + URLS_CONSENT=http://localhost:4746/consent \ + hydra serve all --dangerous-force-http >"${base}/test/e2e/hydra-kratos.e2e.log" 2>&1 & + + (cd test/e2e; npm run wait-on -- -l -t 300000 http-get://127.0.0.1:4745/health/alive) + + hydra clients create \ + --endpoint http://localhost:4745 \ + --id dummy-client \ + --secret secret \ + --token-endpoint-auth-method client_secret_basic \ + --grant-types authorization_code,refresh_token \ + --response-types code,id_token \ + --scope openid,offline,email,website \ + --callbacks http://localhost:5555/callback,https://httpbin.org/anything + + ( + cd test/e2e/hydra-kratos-login-consent + go build . + PORT=4746 HYDRA_ADMIN_URL=http://localhost:4745 ./hydra-kratos-login-consent >"${base}/test/e2e/hydra-kratos-ui.e2e.log" 2>&1 & + ) + if [ -z ${NODE_UI_PATH+x} ]; then ( cd "$node_ui_dir" @@ -202,12 +242,6 @@ prepare() { PORT=4455 npm run start \ >"${base}/test/e2e/proxy.e2e.log" 2>&1 & ) - - ( - cd test/e2e/hydra-login-consent - go build . - PORT=4446 HYDRA_ADMIN_URL=http://localhost:4445 ./hydra-login-consent >"${base}/test/e2e/hydra-ui.e2e.log" 2>&1 & - ) } run() { @@ -216,14 +250,14 @@ run() { export DSN=${1} - ! nc -zv localhost 4434 - ! nc -zv localhost 4433 + nc -zv localhost 4434 && exit 1 + nc -zv localhost 4433 && exit 1 ls -la . - for profile in email mobile oidc recovery verification mfa spa network passwordless webhooks; do + for profile in email mobile oidc recovery verification mfa spa network passwordless webhooks oidc-provider oidc-provider-mfa; do yq ea '. as $item ireduce ({}; . * $item )' test/e2e/profiles/kratos.base.yml "test/e2e/profiles/${profile}/.kratos.yml" > test/e2e/kratos.${profile}.yml - cp test/e2e/kratos.email.yml test/e2e/kratos.generated.yml done + cp test/e2e/kratos.email.yml test/e2e/kratos.generated.yml (modd -f test/e2e/modd.conf >"${base}/test/e2e/kratos.e2e.log" 2>&1 &) diff --git a/test/schema/fixtures/config.schema.test.success/root.courierSMS.yaml b/test/schema/fixtures/config.schema.test.success/root.courierSMS.yaml index 0a131356ee0..b9b73bcb10a 100644 --- a/test/schema/fixtures/config.schema.test.success/root.courierSMS.yaml +++ b/test/schema/fixtures/config.schema.test.success/root.courierSMS.yaml @@ -20,5 +20,5 @@ courier: url: https://sms.example.com method: POST body: file://request.config.twilio.jsonnet - header: + headers: 'Content-Type': "application/x-www-form-urlencoded"