From e0327b00a0cc5f79307975ff9f2dbef25e33710e Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Wed, 12 Jul 2023 20:25:37 +0000 Subject: [PATCH 001/282] autogen(docs): generate and bump docs [skip ci] --- quickstart.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/quickstart.yml b/quickstart.yml index 4d9a2f6ea5d7..1af5775bdd4c 100644 --- a/quickstart.yml +++ b/quickstart.yml @@ -1,7 +1,7 @@ version: '3.7' services: kratos-migrate: - image: oryd/kratos:v0.13.0 + image: oryd/kratos:v1.0.0 environment: - DSN=sqlite:///var/lib/sqlite/db.sqlite?_fk=true&mode=rwc volumes: @@ -17,7 +17,7 @@ services: networks: - intranet kratos-selfservice-ui-node: - image: oryd/kratos-selfservice-ui-node:v0.13.0 + image: oryd/kratos-selfservice-ui-node:v1.0.0 environment: - KRATOS_PUBLIC_URL=http://kratos:4433/ - KRATOS_BROWSER_URL=http://127.0.0.1:4433/ @@ -27,7 +27,7 @@ services: kratos: depends_on: - kratos-migrate - image: oryd/kratos:v0.13.0 + image: oryd/kratos:v1.0.0 ports: - '4433:4433' # public - '4434:4434' # admin From 86ad5e1c3012bc5292420ba7811ffd2547d79ffa Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Wed, 12 Jul 2023 20:26:04 +0000 Subject: [PATCH 002/282] autogen: add v1.0.0 to version.schema.json [skip ci] --- .schema/version.schema.json | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.schema/version.schema.json b/.schema/version.schema.json index 8d397a60fa09..e04013ff2587 100644 --- a/.schema/version.schema.json +++ b/.schema/version.schema.json @@ -2,6 +2,23 @@ "$id": "https://github.com/ory/kratos/.schema/versions.config.schema.json", "$schema": "http://json-schema.org/draft-07/schema#", "oneOf": [ + { + "allOf": [ + { + "properties": { + "version": { + "const": "v1.0.0" + } + }, + "required": [ + "version" + ] + }, + { + "$ref": "https://raw.githubusercontent.com/ory/kratos/v1.0.0/.schemastore/config.schema.json" + } + ] + }, { "allOf": [ { From d814a4864d5c25c4f320daca733873577d517331 Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Thu, 13 Jul 2023 10:13:26 +0200 Subject: [PATCH 003/282] fix: reduce db lookups in whoami for aal check (#3372) Significantly improves performance by reducing the amount of queries we need to do when checking for the different AAL levels. --- Makefile | 2 +- identity/credentials.go | 39 +++++ identity/identity.go | 25 ++++ identity/manager.go | 12 ++ identity/manager_test.go | 135 +++++++++++++++++- identity/test/pool.go | 12 ++ internal/testhelpers/session.go | 3 +- ..._buildInsertQueryArgs-case=Identities.json | 5 +- .../0149ce5f-76a8-4efe-b2e3-431b8c6cceb6.json | 17 +++ .../0149ce5f-76a8-4efe-b2e3-431b8c6cceb7.json | 17 +++ .../testdata/20230706000000_testdata.sql | 11 ++ ...0230706000000000001_available_aal.down.sql | 1 + .../20230706000000000001_available_aal.up.sql | 1 + selfservice/flow/login/handler_test.go | 7 +- .../strategy/code/strategy_recovery_test.go | 4 +- selfservice/strategy/totp/login_test.go | 1 + session/handler.go | 5 +- session/manager_http.go | 63 ++++---- session/manager_http_test.go | 71 ++++++--- 19 files changed, 371 insertions(+), 60 deletions(-) create mode 100644 persistence/sql/migratest/fixtures/identity/0149ce5f-76a8-4efe-b2e3-431b8c6cceb6.json create mode 100644 persistence/sql/migratest/fixtures/identity/0149ce5f-76a8-4efe-b2e3-431b8c6cceb7.json create mode 100644 persistence/sql/migratest/testdata/20230706000000_testdata.sql create mode 100644 persistence/sql/migrations/sql/20230706000000000001_available_aal.down.sql create mode 100644 persistence/sql/migrations/sql/20230706000000000001_available_aal.up.sql diff --git a/Makefile b/Makefile index cbc64548403d..1656375c5a31 100644 --- a/Makefile +++ b/Makefile @@ -191,7 +191,7 @@ migrations-sync: .bin/ory .PHONY: test-update-snapshots test-update-snapshots: - UPDATE_SNAPSHOTS=true go test -p 4 -tags sqlite -short ./... + UPDATE_SNAPSHOTS=true go test -tags sqlite,json1,refresh -short ./... .PHONY: post-release post-release: .bin/yq diff --git a/identity/credentials.go b/identity/credentials.go index 74b6857ef124..99b04db3031b 100644 --- a/identity/credentials.go +++ b/identity/credentials.go @@ -5,6 +5,7 @@ package identity import ( "context" + "database/sql" "reflect" "time" @@ -33,6 +34,44 @@ const ( AuthenticatorAssuranceLevel2 AuthenticatorAssuranceLevel = "aal2" ) +type NullableAuthenticatorAssuranceLevel struct { + sql.NullString +} + +// NewNullableAuthenticatorAssuranceLevel returns a new NullableAuthenticatorAssuranceLevel +func NewNullableAuthenticatorAssuranceLevel(aal AuthenticatorAssuranceLevel) NullableAuthenticatorAssuranceLevel { + switch aal { + case NoAuthenticatorAssuranceLevel: + fallthrough + case AuthenticatorAssuranceLevel1: + fallthrough + case AuthenticatorAssuranceLevel2: + return NullableAuthenticatorAssuranceLevel{sql.NullString{ + String: string(aal), + Valid: true, + }} + default: + return NullableAuthenticatorAssuranceLevel{sql.NullString{}} + } +} + +// ToAAL returns the AuthenticatorAssuranceLevel value of the given NullableAuthenticatorAssuranceLevel. +func (n NullableAuthenticatorAssuranceLevel) ToAAL() (AuthenticatorAssuranceLevel, bool) { + if !n.Valid { + return "", false + } + switch n.String { + case string(NoAuthenticatorAssuranceLevel): + return NoAuthenticatorAssuranceLevel, true + case string(AuthenticatorAssuranceLevel1): + return AuthenticatorAssuranceLevel1, true + case string(AuthenticatorAssuranceLevel2): + return AuthenticatorAssuranceLevel2, true + default: + return "", false + } +} + // CredentialsType represents several different credential types, like password credentials, passwordless credentials, // and so on. // diff --git a/identity/identity.go b/identity/identity.go index 59ce0daedab5..070ec30a666d 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -67,6 +67,10 @@ type Identity struct { // Credentials represents all credentials that can be used for authenticating this identity. Credentials map[CredentialsType]Credentials `json:"credentials,omitempty" faker:"-" db:"-"` + // AvailableAAL defines the maximum available AAL for this identity. If the user has only a password + // configured, the AAL will be 1. If the user has a password and a TOTP configured, the AAL will be 2. + AvailableAAL NullableAuthenticatorAssuranceLevel `json:"-" faker:"-" db:"available_aal"` + // // IdentifierCredentials contains the access and refresh token for oidc identifier // IdentifierCredentials []IdentifierCredential `json:"identifier_credentials,omitempty" faker:"-" db:"-"` @@ -317,6 +321,27 @@ func (i *Identity) UnmarshalJSON(b []byte) error { return err } +func (i *Identity) SetAvailableAAL(ctx context.Context, m *Manager) (err error) { + i.AvailableAAL = NewNullableAuthenticatorAssuranceLevel(NoAuthenticatorAssuranceLevel) + if c, err := m.CountActiveFirstFactorCredentials(ctx, i); err != nil { + return err + } else if c == 0 { + // No first factor set up - AAL is 0 + return nil + } + + i.AvailableAAL = NewNullableAuthenticatorAssuranceLevel(AuthenticatorAssuranceLevel1) + if c, err := m.CountActiveMultiFactorCredentials(ctx, i); err != nil { + return err + } else if c == 0 { + // No second factor set up - AAL is 1 + return nil + } + + i.AvailableAAL = NewNullableAuthenticatorAssuranceLevel(AuthenticatorAssuranceLevel2) + return nil +} + type WithAdminMetadataInJSON Identity func (i WithAdminMetadataInJSON) MarshalJSON() ([]byte, error) { diff --git a/identity/manager.go b/identity/manager.go index f5b7a7959a8a..a63f3e1b7d91 100644 --- a/identity/manager.go +++ b/identity/manager.go @@ -90,6 +90,10 @@ func (m *Manager) Create(ctx context.Context, i *Identity, opts ...ManagerOption return err } + if err := i.SetAvailableAAL(ctx, m); err != nil { + return err + } + if err := m.r.PrivilegedIdentityPool().CreateIdentity(ctx, i); err != nil { return err } @@ -107,6 +111,10 @@ func (m *Manager) CreateIdentities(ctx context.Context, identities []*Identity, i.SchemaID = m.r.Config().DefaultIdentityTraitsSchemaID(ctx) } + if err := i.SetAvailableAAL(ctx, m); err != nil { + return err + } + o := newManagerOptions(opts) if err := m.ValidateIdentity(ctx, i, o); err != nil { return err @@ -164,6 +172,10 @@ func (m *Manager) Update(ctx context.Context, updated *Identity, opts ...Manager return err } + if err := updated.SetAvailableAAL(ctx, m); err != nil { + return err + } + return m.r.PrivilegedIdentityPool().UpdateIdentity(ctx, updated) } diff --git a/identity/manager_test.go b/identity/manager_test.go index 16768ad60acf..294eff89b95e 100644 --- a/identity/manager_test.go +++ b/identity/manager_test.go @@ -9,6 +9,8 @@ import ( "testing" "time" + "github.com/gofrs/uuid" + "github.com/ory/x/sqlxx" "github.com/ory/kratos/internal/testhelpers" @@ -65,10 +67,82 @@ func TestManager(t *testing.T) { t.Run("method=Create", func(t *testing.T) { t.Run("case=should create identity and track extension fields", func(t *testing.T) { + email := uuid.Must(uuid.NewV4()).String() + "@ory.sh" original := identity.NewIdentity(config.DefaultIdentityTraitsSchemaID) - original.Traits = newTraits("foo@ory.sh", "") + original.Traits = newTraits(email, "") require.NoError(t, reg.IdentityManager().Create(context.Background(), original)) - checkExtensionFieldsForIdentities(t, "foo@ory.sh", original) + checkExtensionFieldsForIdentities(t, email, original) + got, ok := original.AvailableAAL.ToAAL() + require.True(t, ok) + assert.Equal(t, identity.NoAuthenticatorAssuranceLevel, got) + }) + + t.Run("case=correctly set AAL", func(t *testing.T) { + t.Run("case=should set AAL to 0 if no credentials are available", func(t *testing.T) { + email := uuid.Must(uuid.NewV4()).String() + "@ory.sh" + original := identity.NewIdentity(config.DefaultIdentityTraitsSchemaID) + original.Traits = newTraits(email, "") + require.NoError(t, reg.IdentityManager().Create(context.Background(), original)) + got, ok := original.AvailableAAL.ToAAL() + require.True(t, ok) + assert.Equal(t, identity.NoAuthenticatorAssuranceLevel, got) + }) + + t.Run("case=should set AAL to 1 if password is set", func(t *testing.T) { + email := uuid.Must(uuid.NewV4()).String() + "@ory.sh" + original := identity.NewIdentity(config.DefaultIdentityTraitsSchemaID) + original.Traits = newTraits(email, "") + original.Credentials = map[identity.CredentialsType]identity.Credentials{ + identity.CredentialsTypePassword: { + Type: identity.CredentialsTypePassword, + Identifiers: []string{email}, + Config: sqlxx.JSONRawMessage(`{"hashed_password":"$2a$08$.cOYmAd.vCpDOoiVJrO5B.hjTLKQQ6cAK40u8uB.FnZDyPvVvQ9Q."}`), + }, + } + require.NoError(t, reg.IdentityManager().Create(context.Background(), original)) + got, ok := original.AvailableAAL.ToAAL() + require.True(t, ok) + assert.Equal(t, identity.AuthenticatorAssuranceLevel1, got) + }) + + t.Run("case=should set AAL to 2 if password and TOTP is set", func(t *testing.T) { + email := uuid.Must(uuid.NewV4()).String() + "@ory.sh" + original := identity.NewIdentity(config.DefaultIdentityTraitsSchemaID) + original.Traits = newTraits(email, "") + original.Credentials = map[identity.CredentialsType]identity.Credentials{ + identity.CredentialsTypePassword: { + Type: identity.CredentialsTypePassword, + Identifiers: []string{email}, + Config: sqlxx.JSONRawMessage(`{"hashed_password":"$2a$08$.cOYmAd.vCpDOoiVJrO5B.hjTLKQQ6cAK40u8uB.FnZDyPvVvQ9Q."}`), + }, + identity.CredentialsTypeTOTP: { + Type: identity.CredentialsTypeTOTP, + Identifiers: []string{email}, + Config: sqlxx.JSONRawMessage(`{"totp_url":"otpauth://totp/test"}`), + }, + } + require.NoError(t, reg.IdentityManager().Create(context.Background(), original)) + got, ok := original.AvailableAAL.ToAAL() + require.True(t, ok) + assert.Equal(t, identity.AuthenticatorAssuranceLevel2, got) + }) + + t.Run("case=should set AAL to 0 if only TOTP is set", func(t *testing.T) { + email := uuid.Must(uuid.NewV4()).String() + "@ory.sh" + original := identity.NewIdentity(config.DefaultIdentityTraitsSchemaID) + original.Traits = newTraits(email, "") + original.Credentials = map[identity.CredentialsType]identity.Credentials{ + identity.CredentialsTypeTOTP: { + Type: identity.CredentialsTypeTOTP, + Identifiers: []string{email}, + Config: sqlxx.JSONRawMessage(`{"totp_url":"otpauth://totp/test"}`), + }, + } + require.NoError(t, reg.IdentityManager().Create(context.Background(), original)) + got, ok := original.AvailableAAL.ToAAL() + require.True(t, ok) + assert.Equal(t, identity.NoAuthenticatorAssuranceLevel, got) + }) }) t.Run("case=should expose validation errors with option", func(t *testing.T) { @@ -100,6 +174,63 @@ func TestManager(t *testing.T) { checkExtensionFieldsForIdentities(t, "bar@ory.sh", original) }) + t.Run("case=should set AAL to 1 if password is set", func(t *testing.T) { + email := uuid.Must(uuid.NewV4()).String() + "@ory.sh" + original := identity.NewIdentity(config.DefaultIdentityTraitsSchemaID) + original.Traits = newTraits(email, "") + require.NoError(t, reg.IdentityManager().Create(context.Background(), original)) + original.Credentials = map[identity.CredentialsType]identity.Credentials{ + identity.CredentialsTypePassword: { + Type: identity.CredentialsTypePassword, + Identifiers: []string{email}, + Config: sqlxx.JSONRawMessage(`{"hashed_password":"$2a$08$.cOYmAd.vCpDOoiVJrO5B.hjTLKQQ6cAK40u8uB.FnZDyPvVvQ9Q."}`), + }, + } + require.NoError(t, reg.IdentityManager().Update(context.Background(), original, identity.ManagerAllowWriteProtectedTraits)) + assert.EqualValues(t, identity.AuthenticatorAssuranceLevel1, original.AvailableAAL.String) + }) + + t.Run("case=should set AAL to 2 if password and TOTP is set", func(t *testing.T) { + email := uuid.Must(uuid.NewV4()).String() + "@ory.sh" + original := identity.NewIdentity(config.DefaultIdentityTraitsSchemaID) + original.Traits = newTraits(email, "") + original.Credentials = map[identity.CredentialsType]identity.Credentials{ + identity.CredentialsTypePassword: { + Type: identity.CredentialsTypePassword, + Identifiers: []string{email}, + Config: sqlxx.JSONRawMessage(`{"hashed_password":"$2a$08$.cOYmAd.vCpDOoiVJrO5B.hjTLKQQ6cAK40u8uB.FnZDyPvVvQ9Q."}`), + }, + } + require.NoError(t, reg.IdentityManager().Create(context.Background(), original)) + assert.EqualValues(t, identity.AuthenticatorAssuranceLevel1, original.AvailableAAL.String) + require.NoError(t, reg.IdentityManager().Update(context.Background(), original, identity.ManagerAllowWriteProtectedTraits)) + assert.EqualValues(t, identity.AuthenticatorAssuranceLevel1, original.AvailableAAL.String, "Updating without changes should not change AAL") + original.Credentials[identity.CredentialsTypeTOTP] = identity.Credentials{ + Type: identity.CredentialsTypeTOTP, + Identifiers: []string{email}, + Config: sqlxx.JSONRawMessage(`{"totp_url":"otpauth://totp/test"}`), + } + require.NoError(t, reg.IdentityManager().Update(context.Background(), original, identity.ManagerAllowWriteProtectedTraits)) + assert.EqualValues(t, identity.AuthenticatorAssuranceLevel2, original.AvailableAAL.String) + }) + + t.Run("case=should set AAL to 0 if only TOTP is set", func(t *testing.T) { + email := uuid.Must(uuid.NewV4()).String() + "@ory.sh" + original := identity.NewIdentity(config.DefaultIdentityTraitsSchemaID) + original.Traits = newTraits(email, "") + require.NoError(t, reg.IdentityManager().Create(context.Background(), original)) + original.Credentials = map[identity.CredentialsType]identity.Credentials{ + identity.CredentialsTypeTOTP: { + Type: identity.CredentialsTypeTOTP, + Identifiers: []string{email}, + Config: sqlxx.JSONRawMessage(`{"totp_url":"otpauth://totp/test"}`), + }, + } + require.NoError(t, reg.IdentityManager().Update(context.Background(), original, identity.ManagerAllowWriteProtectedTraits)) + assert.True(t, original.AvailableAAL.Valid) + assert.EqualValues(t, identity.NoAuthenticatorAssuranceLevel, original.AvailableAAL.String) + }) + t.Run("case=should not update protected traits without option", func(t *testing.T) { original := identity.NewIdentity(config.DefaultIdentityTraitsSchemaID) original.Traits = newTraits("email-update-1@ory.sh", "") diff --git a/identity/test/pool.go b/identity/test/pool.go index 0a84e66f60b0..f695c6dda35d 100644 --- a/identity/test/pool.go +++ b/identity/test/pool.go @@ -320,6 +320,18 @@ func TestPool(ctx context.Context, conf *config.Config, p persistence.Persister, }) }) + t.Run("case=create with null AAL", func(t *testing.T) { + expected := passwordIdentity("", "id-"+uuid.Must(uuid.NewV4()).String()) + expected.AvailableAAL.Valid = false + require.NoError(t, p.CreateIdentity(ctx, expected)) + createdIDs = append(createdIDs, expected.ID) + + actual, err := p.GetIdentity(ctx, expected.ID, identity.ExpandDefault) + require.NoError(t, err) + + assert.False(t, actual.AvailableAAL.Valid) + }) + t.Run("suite=create multiple identities", func(t *testing.T) { t.Run("create multiple identities", func(t *testing.T) { identities := make([]*identity.Identity, 100) diff --git a/internal/testhelpers/session.go b/internal/testhelpers/session.go index 635a5902f3ad..b96c5ef47f00 100644 --- a/internal/testhelpers/session.go +++ b/internal/testhelpers/session.go @@ -45,6 +45,7 @@ func NewSessionClient(t *testing.T, u string) *http.Client { func maybePersistSession(t *testing.T, reg *driver.RegistryDefault, sess *session.Session) { id, err := reg.PrivilegedIdentityPool().GetIdentityConfidential(context.Background(), sess.Identity.ID) if err != nil { + require.NoError(t, sess.Identity.SetAvailableAAL(context.Background(), reg.IdentityManager())) require.NoError(t, reg.PrivilegedIdentityPool().CreateIdentity(context.Background(), sess.Identity)) id, err = reg.PrivilegedIdentityPool().GetIdentityConfidential(context.Background(), sess.Identity.ID) require.NoError(t, err) @@ -156,7 +157,7 @@ func NewHTTPClientWithArbitrarySessionToken(t *testing.T, reg *driver.RegistryDe func NewHTTPClientWithArbitrarySessionCookie(t *testing.T, reg *driver.RegistryDefault) *http.Client { req := x.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) s, err := session.NewActiveSession(req, - &identity.Identity{ID: x.NewUUID(), State: identity.StateActive}, + &identity.Identity{ID: x.NewUUID(), State: identity.StateActive, Traits: []byte("{}")}, NewSessionLifespanProvider(time.Hour), time.Now(), identity.CredentialsTypePassword, diff --git a/persistence/sql/batch/.snapshots/Test_buildInsertQueryArgs-case=Identities.json b/persistence/sql/batch/.snapshots/Test_buildInsertQueryArgs-case=Identities.json index 7659c7d88165..af21f20a0c1a 100644 --- a/persistence/sql/batch/.snapshots/Test_buildInsertQueryArgs-case=Identities.json +++ b/persistence/sql/batch/.snapshots/Test_buildInsertQueryArgs-case=Identities.json @@ -1,7 +1,8 @@ { "TableName": "\"identities\"", - "ColumnsDecl": "\"created_at\", \"id\", \"metadata_admin\", \"metadata_public\", \"nid\", \"schema_id\", \"state\", \"state_changed_at\", \"traits\", \"updated_at\"", + "ColumnsDecl": "\"available_aal\", \"created_at\", \"id\", \"metadata_admin\", \"metadata_public\", \"nid\", \"schema_id\", \"state\", \"state_changed_at\", \"traits\", \"updated_at\"", "Columns": [ + "available_aal", "created_at", "id", "metadata_admin", @@ -13,5 +14,5 @@ "traits", "updated_at" ], - "Placeholders": "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + "Placeholders": "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" } diff --git a/persistence/sql/migratest/fixtures/identity/0149ce5f-76a8-4efe-b2e3-431b8c6cceb6.json b/persistence/sql/migratest/fixtures/identity/0149ce5f-76a8-4efe-b2e3-431b8c6cceb6.json new file mode 100644 index 000000000000..89f3c2dae2e3 --- /dev/null +++ b/persistence/sql/migratest/fixtures/identity/0149ce5f-76a8-4efe-b2e3-431b8c6cceb6.json @@ -0,0 +1,17 @@ +{ + "id": "0149ce5f-76a8-4efe-b2e3-431b8c6cceb6", + "schema_id": "default", + "schema_url": "https://www.ory.sh/schemas/ZGVmYXVsdA", + "state": "active", + "traits": { + "email": "bazbar@ory.sh" + }, + "metadata_public": { + "foo": "bar" + }, + "metadata_admin": { + "baz": "bar" + }, + "created_at": "2013-10-07T08:23:19Z", + "updated_at": "2013-10-07T08:23:19Z" +} diff --git a/persistence/sql/migratest/fixtures/identity/0149ce5f-76a8-4efe-b2e3-431b8c6cceb7.json b/persistence/sql/migratest/fixtures/identity/0149ce5f-76a8-4efe-b2e3-431b8c6cceb7.json new file mode 100644 index 000000000000..634a2313a48e --- /dev/null +++ b/persistence/sql/migratest/fixtures/identity/0149ce5f-76a8-4efe-b2e3-431b8c6cceb7.json @@ -0,0 +1,17 @@ +{ + "id": "0149ce5f-76a8-4efe-b2e3-431b8c6cceb7", + "schema_id": "default", + "schema_url": "https://www.ory.sh/schemas/ZGVmYXVsdA", + "state": "active", + "traits": { + "email": "bazbarbar@ory.sh" + }, + "metadata_public": { + "foo": "bar" + }, + "metadata_admin": { + "baz": "bar" + }, + "created_at": "2013-10-07T08:23:19Z", + "updated_at": "2013-10-07T08:23:19Z" +} diff --git a/persistence/sql/migratest/testdata/20230706000000_testdata.sql b/persistence/sql/migratest/testdata/20230706000000_testdata.sql new file mode 100644 index 000000000000..162cba6a6247 --- /dev/null +++ b/persistence/sql/migratest/testdata/20230706000000_testdata.sql @@ -0,0 +1,11 @@ +INSERT INTO identities (id, nid, schema_id, traits, created_at, updated_at, metadata_public, metadata_admin, + available_aal) +VALUES ('0149ce5f-76a8-4efe-b2e3-431b8c6cceb6', '884f556e-eb3a-4b9f-bee3-11345642c6c0', 'default', + '{"email":"bazbar@ory.sh"}', '2013-10-07 08:23:19', '2013-10-07 08:23:19', '{"foo":"bar"}', '{"baz":"bar"}', + 'aal1'); + +INSERT INTO identities (id, nid, schema_id, traits, created_at, updated_at, metadata_public, metadata_admin, + available_aal) +VALUES ('0149ce5f-76a8-4efe-b2e3-431b8c6cceb7', '884f556e-eb3a-4b9f-bee3-11345642c6c0', 'default', + '{"email":"bazbarbar@ory.sh"}', '2013-10-07 08:23:19', '2013-10-07 08:23:19', '{"foo":"bar"}', '{"baz":"bar"}', + NULL); diff --git a/persistence/sql/migrations/sql/20230706000000000001_available_aal.down.sql b/persistence/sql/migrations/sql/20230706000000000001_available_aal.down.sql new file mode 100644 index 000000000000..8de33750f332 --- /dev/null +++ b/persistence/sql/migrations/sql/20230706000000000001_available_aal.down.sql @@ -0,0 +1 @@ +ALTER TABLE identities DROP COLUMN available_aal; diff --git a/persistence/sql/migrations/sql/20230706000000000001_available_aal.up.sql b/persistence/sql/migrations/sql/20230706000000000001_available_aal.up.sql new file mode 100644 index 000000000000..1eb506ec068c --- /dev/null +++ b/persistence/sql/migrations/sql/20230706000000000001_available_aal.up.sql @@ -0,0 +1 @@ +ALTER TABLE identities ADD COLUMN available_aal VARCHAR(4) NULL; diff --git a/selfservice/flow/login/handler_test.go b/selfservice/flow/login/handler_test.go index 76a2457a217f..eb1b7e3d6a4a 100644 --- a/selfservice/flow/login/handler_test.go +++ b/selfservice/flow/login/handler_test.go @@ -433,21 +433,21 @@ func TestFlowLifecycle(t *testing.T) { "password": { Type: "password", Identifiers: []string{email}, - Config: sqlxx.JSONRawMessage(`{"hashed_password":"foo"}`), + Config: sqlxx.JSONRawMessage(`{"hashed_password": "$argon2id$v=19$m=32,t=2,p=4$cm94YnRVOW5jZzFzcVE4bQ$MNzk5BtR2vUhrp6qQEjRNw"}`), }, }, Traits: identity.Traits(fmt.Sprintf(`{"email":"%s"}`, email)), SchemaID: config.DefaultIdentityTraitsSchemaID, } - require.NoError(t, reg.PrivilegedIdentityPool().CreateIdentities(context.Background(), id)) + require.NoError(t, reg.IdentityManager().CreateIdentities(context.Background(), []*identity.Identity{id}, identity.ManagerAllowWriteProtectedTraits)) id.SetCredentials(identity.CredentialsTypeTOTP, identity.Credentials{ Type: identity.CredentialsTypeTOTP, Identifiers: []string{id.ID.String()}, Config: sqlxx.JSONRawMessage(`{"totp_url":"` + string(key.URL()) + `"}`), }) - require.NoError(t, reg.PrivilegedIdentityPool().UpdateIdentity(context.Background(), id)) + require.NoError(t, reg.IdentityManager().Update(context.Background(), id, identity.ManagerAllowWriteProtectedTraits)) h := func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { sess, err := session.NewActiveSession(r, id, reg.Config(), time.Now().UTC(), identity.CredentialsTypePassword, identity.AuthenticatorAssuranceLevel1) @@ -456,7 +456,6 @@ func TestFlowLifecycle(t *testing.T) { require.NoError(t, reg.SessionPersister().UpsertSession(context.Background(), sess)) require.NoError(t, reg.SessionManager().IssueCookie(context.Background(), w, r, sess)) require.Equal(t, identity.AuthenticatorAssuranceLevel1, sess.AuthenticatorAssuranceLevel) - } router.GET("/mock-session", h) diff --git a/selfservice/strategy/code/strategy_recovery_test.go b/selfservice/strategy/code/strategy_recovery_test.go index c88e662268a0..db6af2c126b1 100644 --- a/selfservice/strategy/code/strategy_recovery_test.go +++ b/selfservice/strategy/code/strategy_recovery_test.go @@ -295,7 +295,7 @@ func createIdentityToRecover(t *testing.T, reg *driver.RegistryDefault, email st "password": { Type: "password", Identifiers: []string{email}, - Config: sqlxx.JSONRawMessage(`{"hashed_password":"foo"}`), + Config: sqlxx.JSONRawMessage(`{"hashed_password":"$2a$08$.cOYmAd.vCpDOoiVJrO5B.hjTLKQQ6cAK40u8uB.FnZDyPvVvQ9Q."}`), }, }, Traits: identity.Traits(fmt.Sprintf(`{"email":"%s"}`, email)), @@ -521,7 +521,7 @@ func TestRecovery(t *testing.T) { Identifiers: []string{testhelpers.RandomEmail()}, }) - require.NoError(t, reg.PrivilegedIdentityPool().UpdateIdentity(ctx, id)) + require.NoError(t, reg.IdentityManager().Update(ctx, id, identity.ManagerAllowWriteProtectedTraits)) return testhelpers.InitializeRecoveryFlowViaBrowser(t, client, false, public, url.Values{"return_to": []string{returnTo}}) }, expectedAAL: "aal2", diff --git a/selfservice/strategy/totp/login_test.go b/selfservice/strategy/totp/login_test.go index c4fa51ce3241..6456ea7cc599 100644 --- a/selfservice/strategy/totp/login_test.go +++ b/selfservice/strategy/totp/login_test.go @@ -78,6 +78,7 @@ func createIdentity(t *testing.T, reg driver.Registry) (*identity.Identity, stri Config: sqlxx.JSONRawMessage(`{"totp_url":"` + string(key.URL()) + `"}`), }, } + require.NoError(t, i.SetAvailableAAL(context.Background(), reg.IdentityManager())) require.NoError(t, reg.PrivilegedIdentityPool().UpdateIdentity(context.Background(), i)) return i, password, key } diff --git a/session/handler.go b/session/handler.go index 601f3e3c1c6a..2c71e33c2738 100644 --- a/session/handler.go +++ b/session/handler.go @@ -205,7 +205,10 @@ func (h *Handler) whoami(w http.ResponseWriter, r *http.Request, ps httprouter.P } var aalErr *ErrAALNotSatisfied - if err := h.r.SessionManager().DoesSessionSatisfy(r, s, c.SessionWhoAmIAAL(r.Context())); errors.As(err, &aalErr) { + if err := h.r.SessionManager().DoesSessionSatisfy(r, s, c.SessionWhoAmIAAL(r.Context()), + // For the time being we want to update the AAL in the database if it is unset. + UpsertAAL, + ); errors.As(err, &aalErr) { h.r.Audit().WithRequest(r).WithError(err).Info("Session was found but AAL is not satisfied for calling this endpoint.") h.r.Writer().WriteError(w, r, err) return diff --git a/session/manager_http.go b/session/manager_http.go index 22f23e8f98aa..b4577e4c9035 100644 --- a/session/manager_http.go +++ b/session/manager_http.go @@ -63,6 +63,7 @@ func NewManagerHTTP(r managerHTTPDependencies) *ManagerHTTP { type options struct { requestURL string + upsertAAL bool } type ManagerOptions func(*options) @@ -74,6 +75,12 @@ func WithRequestURL(requestURL string) ManagerOptions { } } +// UpsertAAL will update the available AAL of the identity if it was previoulsy unset. This is used to migrate +// identities from older versions of Ory Kratos. +func UpsertAAL(opts *options) { + opts.upsertAAL = true +} + func (s *ManagerHTTP) UpsertAndIssueCookie(ctx context.Context, w http.ResponseWriter, r *http.Request, ss *Session) (err error) { ctx, span := s.r.Tracer(ctx).Tracer().Start(ctx, "sessions.ManagerHTTP.UpsertAndIssueCookie") defer otelx.End(span, &err) @@ -225,15 +232,7 @@ func (s *ManagerHTTP) FetchFromRequest(ctx context.Context, r *http.Request) (_ return nil, errors.WithStack(NewErrNoCredentialsForSession()) } - expand := identity.ExpandDefault - if s.r.Config().SessionWhoAmIAAL(r.Context()) == config.HighestAvailableAAL { - // When the session endpoint requires the highest AAL, we fetch all credentials immediately to save a - // query later in "DoesSessionSatisfy". This is a SQL optimization, because the identity manager fetches - // the data in parallel, which is a bit faster than fetching it in sequence. - expand = identity.ExpandEverything - } - - se, err := s.r.SessionPersister().GetSessionByToken(ctx, token, ExpandEverything, expand) + se, err := s.r.SessionPersister().GetSessionByToken(ctx, token, ExpandEverything, identity.ExpandDefault) if err != nil { if errors.Is(err, herodot.ErrNotFound) || errors.Is(err, sqlcon.ErrNoRows) { return nil, errors.WithStack(NewErrNoActiveSessionFound()) @@ -295,31 +294,41 @@ func (s *ManagerHTTP) DoesSessionSatisfy(r *http.Request, sess *Session, request return nil } case config.HighestAvailableAAL: - i := sess.Identity - if i == nil { - i, err = s.r.IdentityPool().GetIdentity(ctx, sess.IdentityID, identity.ExpandCredentials) + if sess.Identity == nil { + sess.Identity, err = s.r.IdentityPool().GetIdentity(ctx, sess.IdentityID, identity.ExpandNothing) if err != nil { return err } - sess.Identity = i - } else if len(i.Credentials) == 0 { - // If credentials are not expanded, we load them here. - if err := s.r.PrivilegedIdentityPool().HydrateIdentityAssociations(ctx, i, identity.ExpandCredentials); err != nil { + } + + i := sess.Identity + available, valid := i.AvailableAAL.ToAAL() + if !valid { + // Available is 0 if the identity was created before the AAL feature was introduced, or if the identity + // was directly created in the persister and not the identity manager. + // + // aal0 indicates that the AAL state of the identity is probably unknown. + // + // In either case, we need to fetch the credentials from the database to determine the AAL. + if len(i.Credentials) == 0 { + // The identity was apparently fetched without credentials. Let's hydrate them. + if err := s.r.PrivilegedIdentityPool().HydrateIdentityAssociations(ctx, i, identity.ExpandCredentials); err != nil { + return err + } + } + + if err := i.SetAvailableAAL(ctx, s.r.IdentityManager()); err != nil { return err } - } - available := identity.NoAuthenticatorAssuranceLevel - if firstCount, err := s.r.IdentityManager().CountActiveFirstFactorCredentials(ctx, i); err != nil { - return err - } else if firstCount > 0 { - available = identity.AuthenticatorAssuranceLevel1 - } + available, _ = i.AvailableAAL.ToAAL() - if secondCount, err := s.r.IdentityManager().CountActiveMultiFactorCredentials(ctx, i); err != nil { - return err - } else if secondCount > 0 { - available = identity.AuthenticatorAssuranceLevel2 + // This is the migration strategy for identities that already exist. + if managerOpts.upsertAAL { + if _, err := s.r.SessionPersister().GetConnection(ctx).Where("id = ? AND nid = ?", i.ID, i.NID).UpdateQuery(i, "available_aal"); err != nil { + return err + } + } } if sess.AuthenticatorAssuranceLevel >= available { diff --git a/session/manager_http_test.go b/session/manager_http_test.go index 791081e52d65..c3b93b2d3c10 100644 --- a/session/manager_http_test.go +++ b/session/manager_http_test.go @@ -366,11 +366,6 @@ func TestManagerHTTP(t *testing.T) { t.Run("required_aal=aal2", func(t *testing.T) { req := x.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) - idAAL2 := createAAL2Identity(t, reg) - idAAL1 := createAAL1Identity(t, reg) - require.NoError(t, reg.PrivilegedIdentityPool().CreateIdentity(context.Background(), idAAL1)) - require.NoError(t, reg.PrivilegedIdentityPool().CreateIdentity(context.Background(), idAAL2)) - run := func(t *testing.T, complete []identity.CredentialsType, requested string, i *identity.Identity, expectedError error) { s := session.NewInactiveSession() for _, m := range complete { @@ -385,24 +380,62 @@ func TestManagerHTTP(t *testing.T) { } } - t.Run("fulfilled for aal2 if identity has aal2", func(t *testing.T) { - run(t, []identity.CredentialsType{identity.CredentialsTypePassword, identity.CredentialsTypeWebAuthn}, config.HighestAvailableAAL, idAAL2, nil) - }) + test := func(t *testing.T, idAAL1, idAAL2 *identity.Identity) { + t.Run("fulfilled for aal2 if identity has aal2", func(t *testing.T) { + run(t, []identity.CredentialsType{identity.CredentialsTypePassword, identity.CredentialsTypeWebAuthn}, config.HighestAvailableAAL, idAAL2, nil) + }) - t.Run("rejected for aal1 if identity has aal2", func(t *testing.T) { - run(t, []identity.CredentialsType{identity.CredentialsTypePassword}, config.HighestAvailableAAL, idAAL2, session.NewErrAALNotSatisfied("")) - }) + t.Run("rejected for aal1 if identity has aal2", func(t *testing.T) { + run(t, []identity.CredentialsType{identity.CredentialsTypePassword}, config.HighestAvailableAAL, idAAL2, session.NewErrAALNotSatisfied("")) + }) + + t.Run("fulfilled for aal1 if identity has aal2 but config is aal1", func(t *testing.T) { + run(t, []identity.CredentialsType{identity.CredentialsTypePassword}, "aal1", idAAL2, nil) + }) + + t.Run("fulfilled for aal2 if identity has aal1", func(t *testing.T) { + run(t, []identity.CredentialsType{identity.CredentialsTypePassword}, "aal1", idAAL2, nil) + }) + + t.Run("fulfilled for aal1 if identity has aal1", func(t *testing.T) { + run(t, []identity.CredentialsType{identity.CredentialsTypePassword}, "aal1", idAAL1, nil) + }) + } - t.Run("fulfilled for aal1 if identity has aal2 but config is aal1", func(t *testing.T) { - run(t, []identity.CredentialsType{identity.CredentialsTypePassword}, "aal1", idAAL2, nil) + t.Run("identity available AAL is not hydrated", func(t *testing.T) { + idAAL2 := createAAL2Identity(t, reg) + idAAL1 := createAAL1Identity(t, reg) + require.NoError(t, reg.PrivilegedIdentityPool().CreateIdentity(context.Background(), idAAL1)) + require.NoError(t, reg.PrivilegedIdentityPool().CreateIdentity(context.Background(), idAAL2)) + test(t, idAAL1, idAAL2) }) - t.Run("fulfilled for aal2 if identity has aal1", func(t *testing.T) { - run(t, []identity.CredentialsType{identity.CredentialsTypePassword}, "aal1", idAAL2, nil) + t.Run("identity available AAL is hydrated and updated in the DB", func(t *testing.T) { + // We do not create the identity in the database, proving that we do not need + // to do any DB roundtrips in this case. + idAAL1 := createAAL2Identity(t, reg) + require.NoError(t, reg.PrivilegedIdentityPool().CreateIdentity(context.Background(), idAAL1)) + + s := session.NewInactiveSession() + s.CompletedLoginFor(identity.CredentialsTypePassword, "") + require.NoError(t, s.Activate(req, idAAL1, conf, time.Now().UTC())) + require.Error(t, reg.SessionManager().DoesSessionSatisfy((&http.Request{}).WithContext(context.Background()), s, config.HighestAvailableAAL, session.UpsertAAL)) + + result, err := reg.IdentityPool().GetIdentity(context.Background(), idAAL1.ID, identity.ExpandNothing) + require.NoError(t, err) + assert.EqualValues(t, identity.AuthenticatorAssuranceLevel2, result.AvailableAAL.String) }) - t.Run("fulfilled for aal1 if identity has aal1", func(t *testing.T) { - run(t, []identity.CredentialsType{identity.CredentialsTypePassword}, "aal1", idAAL1, nil) + t.Run("identity available AAL is hydrated without DB", func(t *testing.T) { + // We do not create the identity in the database, proving that we do not need + // to do any DB roundtrips in this case. + idAAL2 := createAAL2Identity(t, reg) + idAAL2.AvailableAAL = identity.NewNullableAuthenticatorAssuranceLevel(identity.AuthenticatorAssuranceLevel2) + + idAAL1 := createAAL1Identity(t, reg) + idAAL1.AvailableAAL = identity.NewNullableAuthenticatorAssuranceLevel(identity.AuthenticatorAssuranceLevel1) + + test(t, idAAL1, idAAL2) }) }) }) @@ -556,7 +589,7 @@ func TestDoesSessionSatisfy(t *testing.T) { for _, c := range tc.creds { id.SetCredentials(c.Type, c) } - require.NoError(t, reg.PrivilegedIdentityPool().CreateIdentity(context.Background(), id)) + require.NoError(t, reg.IdentityManager().Create(context.Background(), id, identity.ManagerAllowWriteProtectedTraits)) t.Cleanup(func() { require.NoError(t, reg.PrivilegedIdentityPool().DeleteIdentity(context.Background(), id.ID)) }) @@ -573,9 +606,7 @@ func TestDoesSessionSatisfy(t *testing.T) { if tc.expectedFunc != nil { tc.expectedFunc(t, err, tc.err) } - require.ErrorAs(t, err, &tc.err) - } else { require.NoError(t, err) } From 0d37eb356eb7fd51fc60bad4f625266cc3b6de73 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Thu, 13 Jul 2023 09:49:19 +0000 Subject: [PATCH 004/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 150 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 131 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5be0bfc03d1d..9bfd53936b23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,9 +5,9 @@ **Table of Contents** -- [ (2023-07-11)](#2023-07-11) +- [ (2023-07-13)](#2023-07-13) - [Bug Fixes](#bug-fixes) -- [0.14.0-pre.0 (2023-07-06)](#0140-pre0-2023-07-06) +- [1.0.0 (2023-07-12)](#100-2023-07-12) - [Bug Fixes](#bug-fixes-1) - [Code Generation](#code-generation) - [Documentation](#documentation) @@ -306,24 +306,125 @@ -# [](https://github.com/ory/kratos/compare/v0.14.0-pre.0...v) (2023-07-11) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-07-13) ### Bug Fixes -- Incorrect override in identity hydrate - ([#3368](https://github.com/ory/kratos/issues/3368)) - ([eaa3f3c](https://github.com/ory/kratos/commit/eaa3f3c19feaf9048e800cc5a5f1e28d3708c624)) -- Reintroduce ExpandAll ([#3369](https://github.com/ory/kratos/issues/3369)) - ([8f9bff5](https://github.com/ory/kratos/commit/8f9bff527528780b623bf8e4801f7f3c37a5a6f3)) -- Update correct typo ([#3281](https://github.com/ory/kratos/issues/3281)) - ([0fea75c](https://github.com/ory/kratos/commit/0fea75c4093d2c7edc84c14f0ab5bebf33a58970)): - - The text for verification code input should be `Verification code` not - `Verify code`. - -# [0.14.0-pre.0](https://github.com/ory/kratos/compare/v0.13.0...v0.14.0-pre.0) (2023-07-06) - -autogen: pin v0.14.0-pre.0 release commit +- Reduce db lookups in whoami for aal check + ([#3372](https://github.com/ory/kratos/issues/3372)) + ([d814a48](https://github.com/ory/kratos/commit/d814a4864d5c25c4f320daca733873577d517331)): + + Significantly improves performance by reducing the amount of queries we need + to do when checking for the different AAL levels. + +# [1.0.0](https://github.com/ory/kratos/compare/v0.13.0...v1.0.0) (2023-07-12) + +We are thrilled to announce Ory Kratos v1.0, the powerful Identity, User +Management, and Authentication system! With this major update, Ory Kratos brings +a host of enhancements and fixes that greatly improve the user experience and +overall performance. + +Several compelling reasons led to label Ory Kratos as a major release, like +successfully processing over 100 million API requests daily and having about 100 +million Docker Pulls. We have maintained stability within the Ory Kratos APIs +for nearly two years, demonstrating their robustness and reliability. No +breaking changes mean that developers can trust the stability of Ory Kratos in +production. + +Ory Kratos 1.0 introduces a variety of new features while focusing on stability, +robustness, and improved performance. Major enhancements include support for +social login and single-sign-on via OpenID connect in native apps, emails sent +through HTTP rather than SMTP, and full compatibility with Ory Hydra v2.2.0. +Users will also find multi-region support in the Ory Network for broader +geographic reach, improved export functionality for all credential types, and +enhanced session management with the introduction of the "provider ID" +parameter. Other additions comprise distroless images for leaner resource +utilization and faster deployment and support for the Lark OIDC provider. + +Significant improvements and fixes accompany these new features. Enhanced OIDC +flows now include the ability to forward prompt upstream parameters, offering +developers increased flexibility and customization options. The logout flow also +supports the `return_to` parameter, facilitating more flexible redirection +post-user logout. Performance has been a key focus, with Ory Kratos 1.0 now +capable of handling hundreds of millions of active users monthly. Critical bug +fixes have been applied to prevent users from being redirected to incorrect +destinations, ensuring smoother authentication and authorization. Additionally, +there's more support for legacy systems via implemented crypt(3) hashers and a +fix for metadata patching has been deployed to ensure consistent user metadata +management. For a detailed view of all changes, refer to the +[changelog on GitHub](https://github.com/ory/kratos/blob/master/CHANGELOG.md). +Feedback and support are, as always, greatly appreciated. + +Ory Kratos 1.0 is a major release that marks a significant milestone in our +journey. + +We sincerely hope that you find these new features and improvements in Ory +Kratos 1.0 valuable for your projects. To experience the power of the latest +release, we encourage you to get the latest version of Ory +Kratos [here](https://github.com/ory/kratos) or leverage Kratos +in [Ory Network](https://www.ory.sh/network/) — the easiest, simplest, and most +cost-effective way to run Ory. + +For organizations seeking to upgrade their self-hosted solution, **Ory offers +dedicated support services to ensure a smooth transition**. Our team is ready to +assist you throughout the migration process, ensuring uninterrupted access to +the latest features and improvements. Additionally, we provide +various [support plans](https://www.ory.sh/support/) specifically tailored for +self-hosting organizations. These plans offer comprehensive assistance and +guidance to optimize your Ory deployments and meet your unique requirements. + +We extend our heartfelt gratitude to the vibrant and supportive Ory Community. +Without your constant support, feedback, and contributions, reaching this +significant milestone would not have been possible. As we continue on this +journey, your feedback and suggestions are invaluable to us. Together, we are +shaping the future of identity management and authentication in the digital +landscape. + +Contributors to this release in alphabetical order: +[borisroman](https://github.com/ory/kratos/commits?author=borisroman), +[ci42](https://github.com/ory/kratos/commits?author=ci42), +[CNLHC](https://github.com/ory/kratos/commits?author=CNLHC), +[David-Wobrock](https://github.com/ory/kratos/commits?author=David-Wobrock), +[giautm](https://github.com/ory/kratos/commits?author=giautm), +[IchordeDionysos](https://github.com/ory/kratos/commits?author=IchordeDionysos), +[indietyp](https://github.com/ory/kratos/commits?author=indietyp), +[jossbnd](https://github.com/ory/kratos/commits?author=jossbnd), +[kralicky](https://github.com/ory/kratos/commits?author=kralicky), +[PhakornKiong](https://github.com/ory/kratos/commits?author=PhakornKiong), +[sunakan](https://github.com/ory/kratos/commits?author=sunakan), +[steverusso](https://github.com/ory/kratos/commits?author=steverusso) + +Are you passionate about security and want to make a meaningful impact in one of +the biggest open-source communities? Join the +[Ory community](https://slack.ory.sh) and become a part of the new ID stack. +Together, we are building the next generation of IAM solutions that empower +organizations and individuals to secure their identities effectively. + +Want to check out Ory Kratos yourself? Use these commands to get your Ory Kratos +project running on the Ory Network: + +```shell +brew install ory/tap/cli + +scoop bucket add ory https://github.com/ory/scoop.git +scoop install ory + +bash <(curl ) -b . ory +sudo mv ./ory /usr/local/bin/ + +ory auth + +ory create project --name "My first Kratos project" + +ory open account-experience registration + +ory patch identity-config \\ + --replace '/identity/default_schema_id="preset://username"' \\ + --replace '/identity/schemas=[{"id":"preset://username","url":"preset://username"}]' \\ + --format yaml + +ory open account-experience registration +``` ### Bug Fixes @@ -375,6 +476,9 @@ autogen: pin v0.14.0-pre.0 release commit - IdentityCreated event ([#3314](https://github.com/ory/kratos/issues/3314)) ([78e31cb](https://github.com/ory/kratos/commit/78e31cb82a28e240a6176c8d3d9ef3bc64559e75)) +- Incorrect override in identity hydrate + ([#3368](https://github.com/ory/kratos/issues/3368)) + ([eaa3f3c](https://github.com/ory/kratos/commit/eaa3f3c19feaf9048e800cc5a5f1e28d3708c624)) - Increase size for request url ([#3366](https://github.com/ory/kratos/issues/3366)) ([10713cc](https://github.com/ory/kratos/commit/10713cc703457cb6f4a1b38482c836e54a0cb224)) @@ -403,6 +507,8 @@ autogen: pin v0.14.0-pre.0 release commit - Reduce lookups in whoami call ([#3364](https://github.com/ory/kratos/issues/3364)) ([5bb7b0c](https://github.com/ory/kratos/commit/5bb7b0c83b330ee893bdeb4e636655179bd29e39)) +- Reintroduce ExpandAll ([#3369](https://github.com/ory/kratos/issues/3369)) + ([8f9bff5](https://github.com/ory/kratos/commit/8f9bff527528780b623bf8e4801f7f3c37a5a6f3)) - Remove codeball ([aa29606](https://github.com/ory/kratos/commit/aa296067e2736cad329814f7acffd816ce0d74a3)) - Remove duplicate SessionIssued event @@ -467,6 +573,12 @@ autogen: pin v0.14.0-pre.0 release commit ([#3279](https://github.com/ory/kratos/issues/3279)) ([34ff1d2](https://github.com/ory/kratos/commit/34ff1d2912e7f7aefb35dae759dce2eb37ecb790)), closes [#2943](https://github.com/ory/kratos/issues/2943) +- Update correct typo ([#3281](https://github.com/ory/kratos/issues/3281)) + ([0fea75c](https://github.com/ory/kratos/commit/0fea75c4093d2c7edc84c14f0ab5bebf33a58970)): + + The text for verification code input should be `Verification code` not + `Verify code`. + - Update README ([#3363](https://github.com/ory/kratos/issues/3363)) ([c426014](https://github.com/ory/kratos/commit/c4260140966489a05169a0197e209ff98181bc2e)) - Use RETURNING clause for batch create @@ -481,8 +593,8 @@ autogen: pin v0.14.0-pre.0 release commit ### Code Generation -- Pin v0.14.0-pre.0 release commit - ([b75313e](https://github.com/ory/kratos/commit/b75313e15d7071a77ac49a8425c1fac1be1f5bb3)) +- Pin v1.0.0 release commit + ([41b7c51](https://github.com/ory/kratos/commit/41b7c51c1c6b3bdff9e9ea8bb5e455e3c15c5256)) ### Documentation From ea1f72195985914037a186c9f74f4ce65085dfde Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Jul 2023 08:59:17 +0200 Subject: [PATCH 005/282] chore(deps): bump semver from 5.7.1 to 5.7.2 in /test/e2e/proxy (#3377) Bumps [semver](https://github.com/npm/node-semver) from 5.7.1 to 5.7.2. - [Release notes](https://github.com/npm/node-semver/releases) - [Changelog](https://github.com/npm/node-semver/blob/v5.7.2/CHANGELOG.md) - [Commits](https://github.com/npm/node-semver/compare/v5.7.1...v5.7.2) --- updated-dependencies: - dependency-name: semver dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- test/e2e/proxy/package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/e2e/proxy/package-lock.json b/test/e2e/proxy/package-lock.json index bf78903f68cf..0796984a900e 100644 --- a/test/e2e/proxy/package-lock.json +++ b/test/e2e/proxy/package-lock.json @@ -1039,9 +1039,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "bin": { "semver": "bin/semver" } @@ -2083,9 +2083,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" }, "send": { "version": "0.18.0", From 3d6927ced9b6b6dcf338f0e1998a36203197c0a4 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Mon, 17 Jul 2023 08:29:52 +0000 Subject: [PATCH 006/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bfd53936b23..9afaed33d199 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-07-13)](#2023-07-13) +- [ (2023-07-17)](#2023-07-17) - [Bug Fixes](#bug-fixes) - [1.0.0 (2023-07-12)](#100-2023-07-12) - [Bug Fixes](#bug-fixes-1) @@ -306,7 +306,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-07-13) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-07-17) ### Bug Fixes From ffda1a0dab661c5f11ad849b9287094313561b79 Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Mon, 17 Jul 2023 15:02:04 +0200 Subject: [PATCH 007/282] fix: type-assert all interfaces that WebHook implements --- selfservice/hook/web_hook.go | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/selfservice/hook/web_hook.go b/selfservice/hook/web_hook.go index 97f77ea8be22..474a18343c61 100644 --- a/selfservice/hook/web_hook.go +++ b/selfservice/hook/web_hook.go @@ -38,17 +38,24 @@ import ( "github.com/ory/kratos/x" ) -var ( - _ registration.PostHookPostPersistExecutor = new(WebHook) - _ registration.PostHookPrePersistExecutor = new(WebHook) +var _ interface { + login.PreHookExecutor + login.PostHookExecutor - _ verification.PostHookExecutor = new(WebHook) + registration.PostHookPostPersistExecutor + registration.PostHookPrePersistExecutor + registration.PreHookExecutor - _ recovery.PostHookExecutor = new(WebHook) + verification.PreHookExecutor + verification.PostHookExecutor - _ settings.PostHookPostPersistExecutor = new(WebHook) - _ settings.PostHookPrePersistExecutor = new(WebHook) -) + recovery.PreHookExecutor + recovery.PostHookExecutor + + settings.PreHookExecutor + settings.PostHookPrePersistExecutor + settings.PostHookPostPersistExecutor +} = (*WebHook)(nil) type ( webHookDependencies interface { From 96c1ff7747ea38e23a3892f74b75ee555ed49c88 Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Wed, 19 Jul 2023 12:33:58 +0200 Subject: [PATCH 008/282] feat: allow extra migrations in NewPersister --- driver/registry.go | 14 +++++++++++--- driver/registry_default.go | 2 +- persistence/sql/persister.go | 5 +++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/driver/registry.go b/driver/registry.go index 6bf98a101c75..38c87baf5c9b 100644 --- a/driver/registry.go +++ b/driver/registry.go @@ -5,6 +5,7 @@ package driver import ( "context" + "io/fs" "github.com/ory/kratos/selfservice/sessiontokenexchange" "github.com/ory/x/contextx" @@ -182,6 +183,7 @@ type options struct { config *config.Config replaceTracer func(*otelx.Tracer) *otelx.Tracer inspect func(Registry) error + extraMigrations []fs.FS } type RegistryOption func(*options) @@ -190,24 +192,30 @@ func SkipNetworkInit(o *options) { o.skipNetworkInit = true } -func WithConfig(config *config.Config) func(o *options) { +func WithConfig(config *config.Config) RegistryOption { return func(o *options) { o.config = config } } -func ReplaceTracer(f func(*otelx.Tracer) *otelx.Tracer) func(o *options) { +func ReplaceTracer(f func(*otelx.Tracer) *otelx.Tracer) RegistryOption { return func(o *options) { o.replaceTracer = f } } -func Inspect(f func(reg Registry) error) func(o *options) { +func Inspect(f func(reg Registry) error) RegistryOption { return func(o *options) { o.inspect = f } } +func WithExtraMigrations(m ...fs.FS) RegistryOption { + return func(o *options) { + o.extraMigrations = append(o.extraMigrations, m...) + } +} + func newOptions(os []RegistryOption) *options { o := new(options) for _, f := range os { diff --git a/driver/registry_default.go b/driver/registry_default.go index f4e9ba3fb040..f1307e310902 100644 --- a/driver/registry_default.go +++ b/driver/registry_default.go @@ -615,7 +615,7 @@ func (m *RegistryDefault) Init(ctx context.Context, ctxer contextx.Contextualize m.Logger().WithError(err).Warnf("Unable to open database, retrying.") return errors.WithStack(err) } - p, err := sql.NewPersister(ctx, m, c) + p, err := sql.NewPersister(ctx, m, c, o.extraMigrations...) if err != nil { m.Logger().WithError(err).Warnf("Unable to initialize persister, retrying.") return err diff --git a/persistence/sql/persister.go b/persistence/sql/persister.go index 9762823b1056..c7c98188dc78 100644 --- a/persistence/sql/persister.go +++ b/persistence/sql/persister.go @@ -6,6 +6,7 @@ package sql import ( "context" "embed" + "io/fs" "time" "github.com/gobuffalo/pop/v6" @@ -53,8 +54,8 @@ type ( } ) -func NewPersister(ctx context.Context, r persisterDependencies, c *pop.Connection) (*Persister, error) { - m, err := popx.NewMigrationBox(mergefs.Merge(migrations, networkx.Migrations), popx.NewMigrator(c, r.Logger(), r.Tracer(ctx), 0)) +func NewPersister(ctx context.Context, r persisterDependencies, c *pop.Connection, extraMigrations ...fs.FS) (*Persister, error) { + m, err := popx.NewMigrationBox(mergefs.Merge(append([]fs.FS{migrations, networkx.Migrations}, extraMigrations...)...), popx.NewMigrator(c, r.Logger(), r.Tracer(ctx), 0)) if err != nil { return nil, err } From 04bca63dc05ff9f30e9ac1f49b60c53eed22c77e Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Wed, 19 Jul 2023 14:23:58 +0000 Subject: [PATCH 009/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 67 +++++++++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9afaed33d199..4bc49f92a3a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,13 +5,14 @@ **Table of Contents** -- [ (2023-07-17)](#2023-07-17) +- [ (2023-07-19)](#2023-07-19) - [Bug Fixes](#bug-fixes) + - [Features](#features) - [1.0.0 (2023-07-12)](#100-2023-07-12) - [Bug Fixes](#bug-fixes-1) - [Code Generation](#code-generation) - [Documentation](#documentation) - - [Features](#features) + - [Features](#features-1) - [Tests](#tests) - [Unclassified](#unclassified) - [0.13.0 (2023-04-18)](#0130-2023-04-18) @@ -20,7 +21,7 @@ - [Code Generation](#code-generation-1) - [Code Refactoring](#code-refactoring) - [Documentation](#documentation-1) - - [Features](#features-1) + - [Features](#features-2) - [Tests](#tests-1) - [Unclassified](#unclassified-1) - [0.11.1 (2023-01-14)](#0111-2023-01-14) @@ -28,7 +29,7 @@ - [Bug Fixes](#bug-fixes-3) - [Code Generation](#code-generation-2) - [Documentation](#documentation-2) - - [Features](#features-2) + - [Features](#features-3) - [Tests](#tests-2) - [0.11.0 (2022-12-02)](#0110-2022-12-02) - [Breaking Changes](#breaking-changes-2) @@ -36,7 +37,7 @@ - [Code Generation](#code-generation-3) - [Code Refactoring](#code-refactoring-1) - [Documentation](#documentation-3) - - [Features](#features-3) + - [Features](#features-4) - [Reverts](#reverts) - [Tests](#tests-3) - [Unclassified](#unclassified-2) @@ -49,7 +50,7 @@ - [Code Generation](#code-generation-5) - [Code Refactoring](#code-refactoring-2) - [Documentation](#documentation-4) - - [Features](#features-4) + - [Features](#features-5) - [Tests](#tests-4) - [Unclassified](#unclassified-3) - [0.9.0-alpha.3 (2022-03-25)](#090-alpha3-2022-03-25) @@ -66,7 +67,7 @@ - [Code Generation](#code-generation-8) - [Code Refactoring](#code-refactoring-3) - [Documentation](#documentation-6) - - [Features](#features-5) + - [Features](#features-6) - [Tests](#tests-5) - [Unclassified](#unclassified-4) - [0.8.3-alpha.1.pre.0 (2022-01-21)](#083-alpha1pre0-2022-01-21) @@ -75,7 +76,7 @@ - [Code Generation](#code-generation-9) - [Code Refactoring](#code-refactoring-4) - [Documentation](#documentation-7) - - [Features](#features-6) + - [Features](#features-7) - [Tests](#tests-6) - [0.8.2-alpha.1 (2021-12-17)](#082-alpha1-2021-12-17) - [Bug Fixes](#bug-fixes-11) @@ -85,14 +86,14 @@ - [Bug Fixes](#bug-fixes-12) - [Code Generation](#code-generation-11) - [Documentation](#documentation-9) - - [Features](#features-7) + - [Features](#features-8) - [Tests](#tests-7) - [0.8.0-alpha.4.pre.0 (2021-11-09)](#080-alpha4pre0-2021-11-09) - [Breaking Changes](#breaking-changes-7) - [Bug Fixes](#bug-fixes-13) - [Code Generation](#code-generation-12) - [Documentation](#documentation-10) - - [Features](#features-8) + - [Features](#features-9) - [Tests](#tests-8) - [0.8.0-alpha.3 (2021-10-28)](#080-alpha3-2021-10-28) - [Bug Fixes](#bug-fixes-14) @@ -105,7 +106,7 @@ - [Code Generation](#code-generation-15) - [Code Refactoring](#code-refactoring-5) - [Documentation](#documentation-11) - - [Features](#features-9) + - [Features](#features-10) - [Reverts](#reverts-1) - [Tests](#tests-9) - [Unclassified](#unclassified-5) @@ -117,13 +118,13 @@ - [Bug Fixes](#bug-fixes-16) - [Code Generation](#code-generation-18) - [Documentation](#documentation-12) - - [Features](#features-10) + - [Features](#features-11) - [Tests](#tests-10) - [0.7.3-alpha.1 (2021-08-28)](#073-alpha1-2021-08-28) - [Bug Fixes](#bug-fixes-17) - [Code Generation](#code-generation-19) - [Documentation](#documentation-13) - - [Features](#features-11) + - [Features](#features-12) - [0.7.1-alpha.1 (2021-07-22)](#071-alpha1-2021-07-22) - [Bug Fixes](#bug-fixes-18) - [Code Generation](#code-generation-20) @@ -135,7 +136,7 @@ - [Code Generation](#code-generation-21) - [Code Refactoring](#code-refactoring-6) - [Documentation](#documentation-15) - - [Features](#features-12) + - [Features](#features-13) - [Tests](#tests-12) - [Unclassified](#unclassified-6) - [0.6.3-alpha.1 (2021-05-17)](#063-alpha1-2021-05-17) @@ -148,25 +149,25 @@ - [Documentation](#documentation-16) - [0.6.1-alpha.1 (2021-05-11)](#061-alpha1-2021-05-11) - [Code Generation](#code-generation-24) - - [Features](#features-13) + - [Features](#features-14) - [0.6.0-alpha.2 (2021-05-07)](#060-alpha2-2021-05-07) - [Bug Fixes](#bug-fixes-21) - [Code Generation](#code-generation-25) - - [Features](#features-14) + - [Features](#features-15) - [0.6.0-alpha.1 (2021-05-05)](#060-alpha1-2021-05-05) - [Breaking Changes](#breaking-changes-11) - [Bug Fixes](#bug-fixes-22) - [Code Generation](#code-generation-26) - [Code Refactoring](#code-refactoring-8) - [Documentation](#documentation-17) - - [Features](#features-15) + - [Features](#features-16) - [Tests](#tests-13) - [Unclassified](#unclassified-7) - [0.5.5-alpha.1 (2020-12-09)](#055-alpha1-2020-12-09) - [Bug Fixes](#bug-fixes-23) - [Code Generation](#code-generation-27) - [Documentation](#documentation-18) - - [Features](#features-16) + - [Features](#features-17) - [Tests](#tests-14) - [Unclassified](#unclassified-8) - [0.5.4-alpha.1 (2020-11-11)](#054-alpha1-2020-11-11) @@ -174,12 +175,12 @@ - [Code Generation](#code-generation-28) - [Code Refactoring](#code-refactoring-9) - [Documentation](#documentation-19) - - [Features](#features-17) + - [Features](#features-18) - [0.5.3-alpha.1 (2020-10-27)](#053-alpha1-2020-10-27) - [Bug Fixes](#bug-fixes-25) - [Code Generation](#code-generation-29) - [Documentation](#documentation-20) - - [Features](#features-18) + - [Features](#features-19) - [Tests](#tests-15) - [0.5.2-alpha.1 (2020-10-22)](#052-alpha1-2020-10-22) - [Bug Fixes](#bug-fixes-26) @@ -190,7 +191,7 @@ - [Bug Fixes](#bug-fixes-27) - [Code Generation](#code-generation-31) - [Documentation](#documentation-22) - - [Features](#features-19) + - [Features](#features-20) - [Tests](#tests-17) - [Unclassified](#unclassified-9) - [0.5.0-alpha.1 (2020-10-15)](#050-alpha1-2020-10-15) @@ -199,7 +200,7 @@ - [Code Generation](#code-generation-32) - [Code Refactoring](#code-refactoring-10) - [Documentation](#documentation-23) - - [Features](#features-20) + - [Features](#features-21) - [Tests](#tests-18) - [Unclassified](#unclassified-10) - [0.4.6-alpha.1 (2020-07-13)](#046-alpha1-2020-07-13) @@ -224,7 +225,7 @@ - [Code Generation](#code-generation-38) - [Code Refactoring](#code-refactoring-11) - [Documentation](#documentation-25) - - [Features](#features-21) + - [Features](#features-22) - [Unclassified](#unclassified-11) - [0.3.0-alpha.1 (2020-05-15)](#030-alpha1-2020-05-15) - [Breaking Changes](#breaking-changes-14) @@ -232,7 +233,7 @@ - [Chores](#chores) - [Code Refactoring](#code-refactoring-12) - [Documentation](#documentation-26) - - [Features](#features-22) + - [Features](#features-23) - [Unclassified](#unclassified-12) - [0.2.1-alpha.1 (2020-05-05)](#021-alpha1-2020-05-05) - [Chores](#chores-1) @@ -243,7 +244,7 @@ - [Chores](#chores-2) - [Code Refactoring](#code-refactoring-13) - [Documentation](#documentation-28) - - [Features](#features-23) + - [Features](#features-24) - [Unclassified](#unclassified-13) - [0.1.1-alpha.1 (2020-02-18)](#011-alpha1-2020-02-18) - [Bug Fixes](#bug-fixes-37) @@ -253,10 +254,10 @@ - [Bug Fixes](#bug-fixes-38) - [Code Refactoring](#code-refactoring-15) - [Documentation](#documentation-30) - - [Features](#features-24) + - [Features](#features-25) - [0.1.0-alpha.5 (2020-02-06)](#010-alpha5-2020-02-06) - [Documentation](#documentation-31) - - [Features](#features-25) + - [Features](#features-26) - [0.1.0-alpha.4 (2020-02-06)](#010-alpha4-2020-02-06) - [Continuous Integration](#continuous-integration) - [Documentation](#documentation-32) @@ -265,7 +266,7 @@ - [0.1.0-alpha.2 (2020-02-03)](#010-alpha2-2020-02-03) - [Bug Fixes](#bug-fixes-39) - [Documentation](#documentation-33) - - [Features](#features-26) + - [Features](#features-27) - [Unclassified](#unclassified-14) - [0.1.0-alpha.1 (2020-01-31)](#010-alpha1-2020-01-31) - [Documentation](#documentation-34) @@ -306,7 +307,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-07-17) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-07-19) ### Bug Fixes @@ -317,6 +318,14 @@ Significantly improves performance by reducing the amount of queries we need to do when checking for the different AAL levels. +- Type-assert all interfaces that WebHook implements + ([ffda1a0](https://github.com/ory/kratos/commit/ffda1a0dab661c5f11ad849b9287094313561b79)) + +### Features + +- Allow extra migrations in NewPersister + ([96c1ff7](https://github.com/ory/kratos/commit/96c1ff7747ea38e23a3892f74b75ee555ed49c88)) + # [1.0.0](https://github.com/ory/kratos/compare/v0.13.0...v1.0.0) (2023-07-12) We are thrilled to announce Ory Kratos v1.0, the powerful Identity, User From e3fcf0c31db9742ed61bcf783e37ee119ed19d42 Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Mon, 24 Jul 2023 09:51:43 +0200 Subject: [PATCH 010/282] feat: add OpenTelemetry span for password hash comparison (#3383) --- hash/hash_comparator.go | 18 ++++++++++++++++++ hash/hasher_argon2.go | 16 ++++++++++------ hash/hasher_bcrypt.go | 18 +++++++++--------- hash/hasher_pbkdf2.go | 7 ++++++- 4 files changed, 43 insertions(+), 16 deletions(-) diff --git a/hash/hash_comparator.go b/hash/hash_comparator.go index 0a0bcf9b9383..0200e08cad22 100644 --- a/hash/hash_comparator.go +++ b/hash/hash_comparator.go @@ -19,6 +19,8 @@ import ( "strings" "github.com/pkg/errors" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" "golang.org/x/crypto/argon2" "golang.org/x/crypto/bcrypt" "golang.org/x/crypto/pbkdf2" @@ -52,32 +54,48 @@ func NewCryptDecoder() *crypt.Decoder { var CryptDecoder = NewCryptDecoder() func Compare(ctx context.Context, password []byte, hash []byte) error { + ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "hash.Compare") + defer span.End() + switch { case IsMD5CryptHash(hash): + span.SetAttributes(attribute.String("hash.type", "md5crypt")) return CompareMD5Crypt(ctx, password, hash) case IsBcryptHash(hash): + span.SetAttributes(attribute.String("hash.type", "bcrypt")) return CompareBcrypt(ctx, password, hash) case IsSHA256CryptHash(hash): + span.SetAttributes(attribute.String("hash.type", "sha256")) return CompareSHA256Crypt(ctx, password, hash) case IsSHA512CryptHash(hash): + span.SetAttributes(attribute.String("hash.type", "sha512")) return CompareSHA512Crypt(ctx, password, hash) case IsArgon2idHash(hash): + span.SetAttributes(attribute.String("hash.type", "argon2id")) return CompareArgon2id(ctx, password, hash) case IsArgon2iHash(hash): + span.SetAttributes(attribute.String("hash.type", "argon2i")) return CompareArgon2i(ctx, password, hash) case IsPbkdf2Hash(hash): + span.SetAttributes(attribute.String("hash.type", "pbkdf2")) return ComparePbkdf2(ctx, password, hash) case IsScryptHash(hash): + span.SetAttributes(attribute.String("hash.type", "scrypt")) return CompareScrypt(ctx, password, hash) case IsSSHAHash(hash): + span.SetAttributes(attribute.String("hash.type", "ssha")) return CompareSSHA(ctx, password, hash) case IsSHAHash(hash): + span.SetAttributes(attribute.String("hash.type", "sha")) return CompareSHA(ctx, password, hash) case IsFirebaseScryptHash(hash): + span.SetAttributes(attribute.String("hash.type", "firebasescrypt")) return CompareFirebaseScrypt(ctx, password, hash) case IsMD5Hash(hash): + span.SetAttributes(attribute.String("hash.type", "md5")) return CompareMD5(ctx, password, hash) default: + span.SetAttributes(attribute.String("hash.type", "unknown")) return errors.WithStack(ErrUnknownHashAlgorithm) } } diff --git a/hash/hasher_argon2.go b/hash/hasher_argon2.go index c784f3fab6ac..6775641bb36e 100644 --- a/hash/hasher_argon2.go +++ b/hash/hasher_argon2.go @@ -14,6 +14,7 @@ import ( "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/trace" "github.com/pkg/errors" "golang.org/x/crypto/argon2" @@ -44,12 +45,15 @@ func toKB(mem bytesize.ByteSize) uint32 { } func (h *Argon2) Generate(ctx context.Context, password []byte) ([]byte, error) { - ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "hash.Argon2.Generate") + conf := h.c.Config().HasherArgon2(ctx) + + _, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "hash.Generate", trace.WithAttributes( + attribute.String("hash.type", "argon2id"), + attribute.String("hash.config", fmt.Sprintf("%#v", conf)), + )) defer span.End() - p := h.c.Config().HasherArgon2(ctx) - span.SetAttributes(attribute.String("argon2.config", fmt.Sprintf("#%v", p))) - salt := make([]byte, p.SaltLength) + salt := make([]byte, conf.SaltLength) if _, err := rand.Read(salt); err != nil { return nil, err } @@ -57,13 +61,13 @@ func (h *Argon2) Generate(ctx context.Context, password []byte) ([]byte, error) // Pass the plaintext password, salt and parameters to the argon2.IDKey // function. This will generate a hash of the password using the Argon2id // variant. - hash := argon2.IDKey(password, salt, p.Iterations, toKB(p.Memory), p.Parallelism, p.KeyLength) + hash := argon2.IDKey(password, salt, conf.Iterations, toKB(conf.Memory), conf.Parallelism, conf.KeyLength) var b bytes.Buffer if _, err := fmt.Fprintf( &b, "$argon2id$v=%d$m=%d,t=%d,p=%d$%s$%s", - argon2.Version, toKB(p.Memory), p.Iterations, p.Parallelism, + argon2.Version, toKB(conf.Memory), conf.Iterations, conf.Parallelism, base64.RawStdEncoding.EncodeToString(salt), base64.RawStdEncoding.EncodeToString(hash), ); err != nil { diff --git a/hash/hasher_bcrypt.go b/hash/hasher_bcrypt.go index 644c0ad252de..330936a44343 100644 --- a/hash/hasher_bcrypt.go +++ b/hash/hasher_bcrypt.go @@ -5,10 +5,11 @@ package hash import ( "context" + "fmt" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/trace" "github.com/ory/kratos/schema" @@ -30,21 +31,20 @@ func NewHasherBcrypt(c BcryptConfiguration) *Bcrypt { } func (h *Bcrypt) Generate(ctx context.Context, password []byte) ([]byte, error) { - ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "hash.Bcrypt.Generate") + conf := h.c.Config().HasherBcrypt(ctx) + + _, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "hash.Generate", trace.WithAttributes( + attribute.String("hash.type", "bcrypt"), + attribute.String("hash.config", fmt.Sprintf("%#v", conf)), + )) defer span.End() if err := validateBcryptPasswordLength(password); err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, err.Error()) return nil, err } - cost := int(h.c.Config().HasherBcrypt(ctx).Cost) - span.SetAttributes(attribute.Int("bcrypt.cost", cost)) - hash, err := bcrypt.GenerateFromPassword(password, cost) + hash, err := bcrypt.GenerateFromPassword(password, int(conf.Cost)) if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, err.Error()) return nil, err } diff --git a/hash/hasher_pbkdf2.go b/hash/hasher_pbkdf2.go index 38c26bba6e06..7550661d9f0a 100644 --- a/hash/hasher_pbkdf2.go +++ b/hash/hasher_pbkdf2.go @@ -16,7 +16,9 @@ import ( "github.com/pkg/errors" "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/trace" "golang.org/x/crypto/pbkdf2" "golang.org/x/crypto/sha3" ) @@ -29,7 +31,10 @@ type Pbkdf2 struct { } func (h *Pbkdf2) Generate(ctx context.Context, password []byte) ([]byte, error) { - _, span := otel.GetTracerProvider().Tracer("").Start(ctx, "hash.Pbkdf2.Generate") + _, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "hash.Generate", trace.WithAttributes( + attribute.String("hash.type", "pbkdf2"), + attribute.String("hash.config", fmt.Sprintf("%#v", h)), + )) defer span.End() salt := make([]byte, h.SaltLength) From 53080b0bd7fc3df9c85d87b119e878af7d040232 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Mon, 24 Jul 2023 09:22:08 +0000 Subject: [PATCH 011/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bc49f92a3a1..5611cb0808c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-07-19)](#2023-07-19) +- [ (2023-07-24)](#2023-07-24) - [Bug Fixes](#bug-fixes) - [Features](#features) - [1.0.0 (2023-07-12)](#100-2023-07-12) @@ -307,7 +307,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-07-19) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-07-24) ### Bug Fixes @@ -323,6 +323,9 @@ ### Features +- Add OpenTelemetry span for password hash comparison + ([#3383](https://github.com/ory/kratos/issues/3383)) + ([e3fcf0c](https://github.com/ory/kratos/commit/e3fcf0c31db9742ed61bcf783e37ee119ed19d42)) - Allow extra migrations in NewPersister ([96c1ff7](https://github.com/ory/kratos/commit/96c1ff7747ea38e23a3892f74b75ee555ed49c88)) From ca34e9b744482b41d65082f3bed52e9c4ebd7ba4 Mon Sep 17 00:00:00 2001 From: Henning Perl Date: Mon, 31 Jul 2023 13:24:53 +0200 Subject: [PATCH 012/282] fix: return 400 bad request for invalid login challenge (#3404) --- hydra/fake.go | 3 ++- hydra/hydra.go | 8 +++++++- selfservice/flow/login/handler.go | 2 +- selfservice/flow/login/handler_test.go | 7 +++++++ 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/hydra/fake.go b/hydra/fake.go index 3d1bf852c97d..90215b8b83ef 100644 --- a/hydra/fake.go +++ b/hydra/fake.go @@ -7,6 +7,7 @@ import ( "context" "errors" + "github.com/ory/herodot" hydraclientgo "github.com/ory/hydra-client-go/v2" "github.com/ory/kratos/session" ) @@ -41,7 +42,7 @@ func (h *FakeHydra) AcceptLoginRequest(_ context.Context, loginChallenge string, func (h *FakeHydra) GetLoginRequest(_ context.Context, loginChallenge string) (*hydraclientgo.OAuth2LoginRequest, error) { switch loginChallenge { case FakeInvalidLoginChallenge: - return &hydraclientgo.OAuth2LoginRequest{}, nil + return nil, herodot.ErrBadRequest.WithReasonf("Unable to get OAuth 2.0 Login Challenge.") case FakeValidLoginChallenge: return &hydraclientgo.OAuth2LoginRequest{ RequestUrl: "https://www.ory.sh", diff --git a/hydra/hydra.go b/hydra/hydra.go index 695eeed55e91..c0e94f63d5d3 100644 --- a/hydra/hydra.go +++ b/hydra/hydra.go @@ -137,7 +137,13 @@ func (h *DefaultHydra) GetLoginRequest(ctx context.Context, loginChallenge strin hlr, r, err := aa.GetOAuth2LoginRequest(ctx).LoginChallenge(loginChallenge).Execute() if err != nil { - innerErr := herodot.ErrInternalServerError.WithWrap(err).WithReasonf("Unable to get OAuth 2.0 Login Challenge.") + var innerErr *herodot.DefaultError + if r == nil || r.StatusCode >= 500 { + innerErr = &herodot.ErrInternalServerError + } else { + innerErr = &herodot.ErrBadRequest + } + innerErr = innerErr.WithReasonf("Unable to get OAuth 2.0 Login Challenge.") if r != nil { innerErr = innerErr. WithDetail("status_code", r.StatusCode). diff --git a/selfservice/flow/login/handler.go b/selfservice/flow/login/handler.go index 4493703fcbab..de545cedcd69 100644 --- a/selfservice/flow/login/handler.go +++ b/selfservice/flow/login/handler.go @@ -419,7 +419,7 @@ func (h *Handler) createBrowserLoginFlow(w http.ResponseWriter, r *http.Request, hydraLoginRequest, err = h.d.Hydra().GetLoginRequest(r.Context(), string(hydraLoginChallenge)) if err != nil { - h.d.SelfServiceErrorManager().Forward(r.Context(), w, r, errors.WithStack(herodot.ErrInternalServerError.WithReason("Failed to retrieve OAuth 2.0 login request."))) + h.d.SelfServiceErrorManager().Forward(r.Context(), w, r, err) return } diff --git a/selfservice/flow/login/handler_test.go b/selfservice/flow/login/handler_test.go index eb1b7e3d6a4a..ada0814aaf1d 100644 --- a/selfservice/flow/login/handler_test.go +++ b/selfservice/flow/login/handler_test.go @@ -751,6 +751,13 @@ func TestFlowLifecycle(t *testing.T) { assert.Equal(t, "https://www.ory.sh", gjson.GetBytes(body, "return_to").Value()) }) + t.Run("case=invalid oauth2 login challenge returns 400 Bad Request", func(t *testing.T) { + res, body := initAuthenticatedFlow(t, url.Values{"login_challenge": {hydra.FakeInvalidLoginChallenge}}, false) + assert.Contains(t, res.Request.URL.String(), errorTS.URL) + assert.Equal(t, int64(http.StatusBadRequest), gjson.GetBytes(body, "code").Int()) + assert.Contains(t, gjson.GetBytes(body, "reason").String(), "Unable to get OAuth 2.0 Login Challenge") + }) + t.Run("case=oauth2 flow init succeeds", func(t *testing.T) { res, _ := initAuthenticatedFlow(t, url.Values{"login_challenge": {hydra.FakeValidLoginChallenge}}, false) require.Contains(t, res.Request.URL.String(), loginTS.URL) From 59a3f1469b8412e49846a500493cb02fc6eb34b1 Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Mon, 31 Jul 2023 14:08:51 +0200 Subject: [PATCH 013/282] fix: remove requirement for smtp section (#3405) --- .schemastore/config.schema.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.schemastore/config.schema.json b/.schemastore/config.schema.json index 0fb880cca54b..5ab6aaa60eff 100644 --- a/.schemastore/config.schema.json +++ b/.schemastore/config.schema.json @@ -1778,7 +1778,10 @@ "title": "Delivery Strategy", "description": "Defines how emails will be sent, either through SMTP (default) or HTTP.", "type": "string", - "enum": ["smtp", "http"], + "enum": [ + "smtp", + "http" + ], "default": "smtp" }, "http": { @@ -1942,9 +1945,6 @@ "additionalProperties": false } }, - "required": [ - "smtp" - ], "additionalProperties": false }, "oauth2_provider": { @@ -1975,10 +1975,10 @@ ] }, "override_return_to": { - "title":"Persist OAuth2 request between flows", - "type":"boolean", - "default":false, - "description":"Override the return_to query parameter with the OAuth2 provider request URL when perfoming an OAuth2 login flow." + "title": "Persist OAuth2 request between flows", + "type": "boolean", + "default": false, + "description": "Override the return_to query parameter with the OAuth2 provider request URL when perfoming an OAuth2 login flow." } }, "additionalProperties": false @@ -2740,4 +2740,4 @@ "selfservice" ], "additionalProperties": false -} \ No newline at end of file +} From 013f335881831bbf90ac31b219b57118fc089fe6 Mon Sep 17 00:00:00 2001 From: Henning Perl Date: Mon, 31 Jul 2023 16:09:00 +0200 Subject: [PATCH 014/282] feat: support multiple origins for WebAuthN (#3380) Users can now supply a list of origins for webauthn in the configuration. --- driver/config/config.go | 16 +- driver/config/config_test.go | 45 ++++ .../config/stub/.kratos.webauthn.invalid.yaml | 231 ++++++++++++++++++ .../config/stub/.kratos.webauthn.origin.yaml | 227 +++++++++++++++++ .../config/stub/.kratos.webauthn.origins.yaml | 230 +++++++++++++++++ driver/config/stub/.kratos.yaml | 6 + embedx/config.schema.json | 61 ++++- go.mod | 18 +- go.sum | 24 +- identity/credentials_webauthn.go | 2 +- identity/credentials_webauthn_test.go | 2 +- .../strategy/code/strategy_recovery_test.go | 2 +- ...oad_is_set_when_identity_has_webauthn.json | 2 +- ...ebauthn_login_is_invalid-type=browser.json | 2 +- ...if_webauthn_login_is_invalid-type=spa.json | 2 +- ...passwordless_enabled=false#01-browser.json | 2 +- ...als-passwordless_enabled=false#01-spa.json | 2 +- ...passwordless_enabled=false#02-browser.json | 2 +- ...als-passwordless_enabled=false#02-spa.json | 2 +- ...ls-passwordless_enabled=false-browser.json | 2 +- ...ntials-passwordless_enabled=false-spa.json | 2 +- ...-passwordless_enabled=true#01-browser.json | 2 +- ...ials-passwordless_enabled=true#01-spa.json | 2 +- ...-passwordless_enabled=true#02-browser.json | 2 +- ...ials-passwordless_enabled=true#02-spa.json | 2 +- ...als-passwordless_enabled=true-browser.json | 2 +- ...entials-passwordless_enabled=true-spa.json | 2 +- ...device_is_shown_which_can_be_unlinked.json | 2 +- ...-case=one_activation_element_is_shown.json | 2 +- ...n-case=webauthn_button_exists-browser.json | 2 +- ...ation-case=webauthn_button_exists-spa.json | 2 +- selfservice/strategy/webauthn/js/webauthn.js | 151 +++++++----- selfservice/strategy/webauthn/login.go | 4 +- selfservice/strategy/webauthn/login_test.go | 2 +- selfservice/strategy/webauthn/registration.go | 4 +- selfservice/strategy/webauthn/settings.go | 6 +- selfservice/strategy/webauthn/user.go | 4 +- 37 files changed, 957 insertions(+), 116 deletions(-) create mode 100644 driver/config/stub/.kratos.webauthn.invalid.yaml create mode 100644 driver/config/stub/.kratos.webauthn.origin.yaml create mode 100644 driver/config/stub/.kratos.webauthn.origins.yaml diff --git a/driver/config/config.go b/driver/config/config.go index bfa08bae2a3f..35bf9f4bd1d2 100644 --- a/driver/config/config.go +++ b/driver/config/config.go @@ -18,8 +18,8 @@ import ( "testing" "time" - "github.com/duo-labs/webauthn/protocol" - "github.com/duo-labs/webauthn/webauthn" + "github.com/go-webauthn/webauthn/protocol" + "github.com/go-webauthn/webauthn/webauthn" "github.com/gofrs/uuid" "github.com/inhies/go-bytesize" kjson "github.com/knadh/koanf/parsers/json" @@ -178,7 +178,7 @@ const ( ViperKeyWebAuthnRPDisplayName = "selfservice.methods.webauthn.config.rp.display_name" ViperKeyWebAuthnRPID = "selfservice.methods.webauthn.config.rp.id" ViperKeyWebAuthnRPOrigin = "selfservice.methods.webauthn.config.rp.origin" - ViperKeyWebAuthnRPIcon = "selfservice.methods.webauthn.config.rp.issuer" + ViperKeyWebAuthnRPOrigins = "selfservice.methods.webauthn.config.rp.origins" ViperKeyWebAuthnPasswordless = "selfservice.methods.webauthn.config.passwordless" ViperKeyOAuth2ProviderURL = "oauth2_provider.url" ViperKeyOAuth2ProviderHeader = "oauth2_provider.headers" @@ -1364,14 +1364,18 @@ func (p *Config) WebAuthnForPasswordless(ctx context.Context) bool { } func (p *Config) WebAuthnConfig(ctx context.Context) *webauthn.Config { + scheme := p.SelfPublicURL(ctx).Scheme + id := p.GetProvider(ctx).String(ViperKeyWebAuthnRPID) + origin := p.GetProvider(ctx).String(ViperKeyWebAuthnRPOrigin) + origins := p.GetProvider(ctx).StringsF(ViperKeyWebAuthnRPOrigins, []string{stringsx.Coalesce(origin, scheme+"://"+id)}) return &webauthn.Config{ RPDisplayName: p.GetProvider(ctx).String(ViperKeyWebAuthnRPDisplayName), - RPID: p.GetProvider(ctx).String(ViperKeyWebAuthnRPID), - RPOrigin: p.GetProvider(ctx).String(ViperKeyWebAuthnRPOrigin), - RPIcon: p.GetProvider(ctx).String(ViperKeyWebAuthnRPIcon), + RPID: id, + RPOrigins: origins, AuthenticatorSelection: protocol.AuthenticatorSelection{ UserVerification: protocol.VerificationDiscouraged, }, + EncodeUserIDAsString: false, } } diff --git a/driver/config/config_test.go b/driver/config/config_test.go index 87271e3d0cca..95cd4e6c70bb 100644 --- a/driver/config/config_test.go +++ b/driver/config/config_test.go @@ -1194,6 +1194,51 @@ func TestOAuth2Provider(t *testing.T) { }) } +func TestWebauthn(t *testing.T) { + ctx := context.Background() + + t.Run("case=multiple origins", func(t *testing.T) { + conf, err := config.New(ctx, logrusx.New("", ""), os.Stderr, + configx.WithConfigFiles("stub/.kratos.webauthn.origins.yaml")) + require.NoError(t, err) + webAuthnConfig := conf.WebAuthnConfig(ctx) + assert.Equal(t, "https://example.com/webauthn", webAuthnConfig.RPID) + assert.EqualValues(t, []string{ + "https://origin-a.example.com", + "https://origin-b.example.com", + "https://origin-c.example.com", + }, webAuthnConfig.RPOrigins) + }) + + t.Run("case=one origin", func(t *testing.T) { + conf, err := config.New(ctx, logrusx.New("", ""), os.Stderr, + configx.WithConfigFiles("stub/.kratos.webauthn.origin.yaml")) + require.NoError(t, err) + webAuthnConfig := conf.WebAuthnConfig(ctx) + assert.Equal(t, "https://example.com/webauthn", webAuthnConfig.RPID) + assert.EqualValues(t, []string{ + "https://origin-a.example.com", + }, webAuthnConfig.RPOrigins) + }) + + t.Run("case=id as origin", func(t *testing.T) { + conf, err := config.New(ctx, logrusx.New("", ""), os.Stderr, + configx.WithConfigFiles("stub/.kratos.yaml")) + require.NoError(t, err) + webAuthnConfig := conf.WebAuthnConfig(ctx) + assert.Equal(t, "example.com", webAuthnConfig.RPID) + assert.EqualValues(t, []string{ + "http://example.com", + }, webAuthnConfig.RPOrigins) + }) + + t.Run("case=invalid", func(t *testing.T) { + _, err := config.New(ctx, logrusx.New("", ""), os.Stderr, + configx.WithConfigFiles("stub/.kratos.webauthn.invalid.yaml")) + assert.Error(t, err) + }) +} + func TestCourierTemplatesConfig(t *testing.T) { ctx := context.Background() diff --git a/driver/config/stub/.kratos.webauthn.invalid.yaml b/driver/config/stub/.kratos.webauthn.invalid.yaml new file mode 100644 index 000000000000..01fc9f5adaad --- /dev/null +++ b/driver/config/stub/.kratos.webauthn.invalid.yaml @@ -0,0 +1,231 @@ +# serve controls the configuration for the http(s) daemon +serve: + admin: + base_url: http://admin.kratos.ory.sh + port: 1234 + host: admin.kratos.ory.sh + public: + base_url: http://public.kratos.ory.sh + port: 1235 + host: public.kratos.ory.sh + +dsn: sqlite://foo.db?mode=memory&_fk=true + +log: + level: debug + +courier: + smtp: + connection_uri: smtp://foo:bar@baz/ + +identity: + default_schema_id: default + schemas: + - id: default + url: base64://ewogICIkaWQiOiAib3J5Oi8vaWRlbnRpdHktdGVzdC1zY2hlbWEiLAogICIkc2NoZW1hIjogImh0dHA6Ly9qc29uLXNjaGVtYS5vcmcvZHJhZnQtMDcvc2NoZW1hIyIsCiAgInRpdGxlIjogIklkZW50aXR5U2NoZW1hIiwKICAidHlwZSI6ICJvYmplY3QiLAogICJwcm9wZXJ0aWVzIjogewogICAgInRyYWl0cyI6IHsKICAgICAgInR5cGUiOiAib2JqZWN0IiwKICAgICAgInByb3BlcnRpZXMiOiB7CiAgICAgICAgIm5hbWUiOiB7CiAgICAgICAgICAidHlwZSI6ICJvYmplY3QiLAogICAgICAgICAgInByb3BlcnRpZXMiOiB7CiAgICAgICAgICAgICJmaXJzdCI6IHsKICAgICAgICAgICAgICAidHlwZSI6ICJzdHJpbmciCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgICJsYXN0IjogewogICAgICAgICAgICAgICJ0eXBlIjogInN0cmluZyIKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfSwKICAgICAgInJlcXVpcmVkIjogWwogICAgICAgICJuYW1lIgogICAgICBdLAogICAgICAiYWRkaXRpb25hbFByb3BlcnRpZXMiOiB0cnVlCiAgICB9CiAgfQp9 + - id: other + url: base64://ewogICIkaWQiOiAib3J5Oi8vaWRlbnRpdHktb3RoZXItc2NoZW1hIiwKICAiJHNjaGVtYSI6ICJodHRwOi8vanNvbi1zY2hlbWEub3JnL2RyYWZ0LTA3L3NjaGVtYSMiLAogICJ0aXRsZSI6ICJJZGVudGl0eU90aGVyU2NoZW1hIiwKICAidHlwZSI6ICJvYmplY3QiLAogICJwcm9wZXJ0aWVzIjogewogICAgInRyYWl0cyI6IHsKICAgICAgInR5cGUiOiAib2JqZWN0IiwKICAgICAgInByb3BlcnRpZXMiOiB7CiAgICAgICAgIm90aGVyIjogewogICAgICAgICAgInR5cGUiOiAic3RyaW5nIgogICAgICAgIH0sCiAgICAgICAgImVtYWlsIjogewogICAgICAgICAgInR5cGUiOiAic3RyaW5nIiwKICAgICAgICAgICJ0aXRsZSI6ICJlbWFpbCIsCiAgICAgICAgICAib3J5LnNoL2tyYXRvcyI6IHsKICAgICAgICAgICAgImNyZWRlbnRpYWxzIjogewogICAgICAgICAgICAgICJwYXNzd29yZCI6IHsKICAgICAgICAgICAgICAgICJpZGVudGlmaWVyIjogdHJ1ZQogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfSwKICAgICAgInJlcXVpcmVkIjogWwogICAgICAgICJvdGhlciIsCiAgICAgICAgImVtYWlsIgogICAgICBdLAogICAgICAiYWRkaXRpb25hbFByb3BlcnRpZXMiOiB0cnVlCiAgICB9CiAgfQp9 + +hashers: + argon2: + memory: 1MB + iterations: 2 + parallelism: 4 + salt_length: 16 + key_length: 32 + dedicated_memory: 1GB + expected_duration: 500ms + expected_deviation: 500ms + +secrets: + cookie: + - session-key-7f8a9b77-1 + - session-key-7f8a9b77-2 + cipher: + - secret-thirty-two-character-long + +ciphers: + algorithm: xchacha20-poly1305 + +selfservice: + default_browser_return_url: http://return-to-3-test.ory.sh/ + allowed_return_urls: + - http://return-to-1-test.ory.sh/ + - http://return-to-2-test.ory.sh/ + - http://*.wildcards.ory.sh + - http://*.sh + - http://*.com + - http://*.com.pl + - http://* + - /return-to-relative-test/ + methods: + totp: + enabled: true + config: + issuer: issuer.ory.sh + password: + enabled: true + oidc: + enabled: true + config: + providers: + - id: github + provider: github + client_id: a + client_secret: b + mapper_url: http://test.kratos.ory.sh/default-identity.schema.json + webauthn: + enabled: true + config: + rp: + id: https://example.com/webauthn + display_name: Webauthn + origin: https://origin-a.example.com + origins: + - https://origin-a.example.com + - https://origin-b.example.com + - https://origin-c.example.com + flows: + error: + ui_url: http://test.kratos.ory.sh/error + + logout: + after: + default_browser_return_url: http://test.kratos.ory.sh:4000/ + + recovery: + enabled: true + ui_url: http://test.kratos.ory.sh/recovery + lifespan: 98m + after: + default_browser_return_url: http://test.kratos.ory.sh/dashboard + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_recovery_hook + method: GET + body: /path/to/template.jsonnet + + verification: + enabled: true + lifespan: 97m + ui_url: http://test.kratos.ory.sh/verification + after: + default_browser_return_url: http://test.kratos.ory.sh/dashboard + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_verification_hook + method: GET + body: /path/to/template.jsonnet + + settings: + ui_url: http://test.kratos.ory.sh/settings + lifespan: 99m + privileged_session_max_age: 5m + after: + default_browser_return_url: https://self-service/settings/return_to + password: + default_browser_return_url: https://self-service/settings/password/return_to + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_settings_password_hook + method: POST + body: /path/to/template.jsonnet + profile: + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_settings_profile_hook + method: POST + body: /path/to/template.jsonnet + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_settings_global_hook + method: POST + body: /path/to/template.jsonnet + + login: + ui_url: http://test.kratos.ory.sh/login + lifespan: 99m + before: + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/before_login_hook + method: POST + after: + default_browser_return_url: https://self-service/login/return_to + password: + default_browser_return_url: https://self-service/login/password/return_to + hooks: + - hook: revoke_active_sessions + - hook: require_verified_address + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_login_password_hook + method: POST + body: /path/to/template.jsonnet + auth: + type: basic_auth + config: + user: test-user + password: super-secret + oidc: + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_login_oidc_hook + method: GET + body: /path/to/template.jsonnet + - hook: revoke_active_sessions + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_login_global_hook + method: POST + body: /path/to/template.jsonnet + + registration: + enabled: true + ui_url: http://test.kratos.ory.sh/register + lifespan: 98m + before: + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/before_registration_hook + method: GET + after: + default_browser_return_url: https://self-service/registration/return_to + password: + hooks: + - hook: session + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_registration_password_hook + method: POST + body: /path/to/template.jsonnet + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_registration_global_hook + method: POST + body: /path/to/template.jsonnet + auth: + type: api_key + config: + name: My-Key + value: My-Key-Value + in: header + oidc: + default_browser_return_url: https://self-service/registration/oidc/return_to + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_registration_oidc_hook + method: GET + body: /path/to/template.jsonnet + - hook: session diff --git a/driver/config/stub/.kratos.webauthn.origin.yaml b/driver/config/stub/.kratos.webauthn.origin.yaml new file mode 100644 index 000000000000..1b2ff11e9d8f --- /dev/null +++ b/driver/config/stub/.kratos.webauthn.origin.yaml @@ -0,0 +1,227 @@ +# serve controls the configuration for the http(s) daemon +serve: + admin: + base_url: http://admin.kratos.ory.sh + port: 1234 + host: admin.kratos.ory.sh + public: + base_url: http://public.kratos.ory.sh + port: 1235 + host: public.kratos.ory.sh + +dsn: sqlite://foo.db?mode=memory&_fk=true + +log: + level: debug + +courier: + smtp: + connection_uri: smtp://foo:bar@baz/ + +identity: + default_schema_id: default + schemas: + - id: default + url: base64://ewogICIkaWQiOiAib3J5Oi8vaWRlbnRpdHktdGVzdC1zY2hlbWEiLAogICIkc2NoZW1hIjogImh0dHA6Ly9qc29uLXNjaGVtYS5vcmcvZHJhZnQtMDcvc2NoZW1hIyIsCiAgInRpdGxlIjogIklkZW50aXR5U2NoZW1hIiwKICAidHlwZSI6ICJvYmplY3QiLAogICJwcm9wZXJ0aWVzIjogewogICAgInRyYWl0cyI6IHsKICAgICAgInR5cGUiOiAib2JqZWN0IiwKICAgICAgInByb3BlcnRpZXMiOiB7CiAgICAgICAgIm5hbWUiOiB7CiAgICAgICAgICAidHlwZSI6ICJvYmplY3QiLAogICAgICAgICAgInByb3BlcnRpZXMiOiB7CiAgICAgICAgICAgICJmaXJzdCI6IHsKICAgICAgICAgICAgICAidHlwZSI6ICJzdHJpbmciCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgICJsYXN0IjogewogICAgICAgICAgICAgICJ0eXBlIjogInN0cmluZyIKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfSwKICAgICAgInJlcXVpcmVkIjogWwogICAgICAgICJuYW1lIgogICAgICBdLAogICAgICAiYWRkaXRpb25hbFByb3BlcnRpZXMiOiB0cnVlCiAgICB9CiAgfQp9 + - id: other + url: base64://ewogICIkaWQiOiAib3J5Oi8vaWRlbnRpdHktb3RoZXItc2NoZW1hIiwKICAiJHNjaGVtYSI6ICJodHRwOi8vanNvbi1zY2hlbWEub3JnL2RyYWZ0LTA3L3NjaGVtYSMiLAogICJ0aXRsZSI6ICJJZGVudGl0eU90aGVyU2NoZW1hIiwKICAidHlwZSI6ICJvYmplY3QiLAogICJwcm9wZXJ0aWVzIjogewogICAgInRyYWl0cyI6IHsKICAgICAgInR5cGUiOiAib2JqZWN0IiwKICAgICAgInByb3BlcnRpZXMiOiB7CiAgICAgICAgIm90aGVyIjogewogICAgICAgICAgInR5cGUiOiAic3RyaW5nIgogICAgICAgIH0sCiAgICAgICAgImVtYWlsIjogewogICAgICAgICAgInR5cGUiOiAic3RyaW5nIiwKICAgICAgICAgICJ0aXRsZSI6ICJlbWFpbCIsCiAgICAgICAgICAib3J5LnNoL2tyYXRvcyI6IHsKICAgICAgICAgICAgImNyZWRlbnRpYWxzIjogewogICAgICAgICAgICAgICJwYXNzd29yZCI6IHsKICAgICAgICAgICAgICAgICJpZGVudGlmaWVyIjogdHJ1ZQogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfSwKICAgICAgInJlcXVpcmVkIjogWwogICAgICAgICJvdGhlciIsCiAgICAgICAgImVtYWlsIgogICAgICBdLAogICAgICAiYWRkaXRpb25hbFByb3BlcnRpZXMiOiB0cnVlCiAgICB9CiAgfQp9 + +hashers: + argon2: + memory: 1MB + iterations: 2 + parallelism: 4 + salt_length: 16 + key_length: 32 + dedicated_memory: 1GB + expected_duration: 500ms + expected_deviation: 500ms + +secrets: + cookie: + - session-key-7f8a9b77-1 + - session-key-7f8a9b77-2 + cipher: + - secret-thirty-two-character-long + +ciphers: + algorithm: xchacha20-poly1305 + +selfservice: + default_browser_return_url: http://return-to-3-test.ory.sh/ + allowed_return_urls: + - http://return-to-1-test.ory.sh/ + - http://return-to-2-test.ory.sh/ + - http://*.wildcards.ory.sh + - http://*.sh + - http://*.com + - http://*.com.pl + - http://* + - /return-to-relative-test/ + methods: + totp: + enabled: true + config: + issuer: issuer.ory.sh + password: + enabled: true + oidc: + enabled: true + config: + providers: + - id: github + provider: github + client_id: a + client_secret: b + mapper_url: http://test.kratos.ory.sh/default-identity.schema.json + webauthn: + enabled: true + config: + rp: + id: https://example.com/webauthn + display_name: Webauthn + origin: https://origin-a.example.com + flows: + error: + ui_url: http://test.kratos.ory.sh/error + + logout: + after: + default_browser_return_url: http://test.kratos.ory.sh:4000/ + + recovery: + enabled: true + ui_url: http://test.kratos.ory.sh/recovery + lifespan: 98m + after: + default_browser_return_url: http://test.kratos.ory.sh/dashboard + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_recovery_hook + method: GET + body: /path/to/template.jsonnet + + verification: + enabled: true + lifespan: 97m + ui_url: http://test.kratos.ory.sh/verification + after: + default_browser_return_url: http://test.kratos.ory.sh/dashboard + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_verification_hook + method: GET + body: /path/to/template.jsonnet + + settings: + ui_url: http://test.kratos.ory.sh/settings + lifespan: 99m + privileged_session_max_age: 5m + after: + default_browser_return_url: https://self-service/settings/return_to + password: + default_browser_return_url: https://self-service/settings/password/return_to + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_settings_password_hook + method: POST + body: /path/to/template.jsonnet + profile: + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_settings_profile_hook + method: POST + body: /path/to/template.jsonnet + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_settings_global_hook + method: POST + body: /path/to/template.jsonnet + + login: + ui_url: http://test.kratos.ory.sh/login + lifespan: 99m + before: + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/before_login_hook + method: POST + after: + default_browser_return_url: https://self-service/login/return_to + password: + default_browser_return_url: https://self-service/login/password/return_to + hooks: + - hook: revoke_active_sessions + - hook: require_verified_address + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_login_password_hook + method: POST + body: /path/to/template.jsonnet + auth: + type: basic_auth + config: + user: test-user + password: super-secret + oidc: + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_login_oidc_hook + method: GET + body: /path/to/template.jsonnet + - hook: revoke_active_sessions + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_login_global_hook + method: POST + body: /path/to/template.jsonnet + + registration: + enabled: true + ui_url: http://test.kratos.ory.sh/register + lifespan: 98m + before: + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/before_registration_hook + method: GET + after: + default_browser_return_url: https://self-service/registration/return_to + password: + hooks: + - hook: session + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_registration_password_hook + method: POST + body: /path/to/template.jsonnet + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_registration_global_hook + method: POST + body: /path/to/template.jsonnet + auth: + type: api_key + config: + name: My-Key + value: My-Key-Value + in: header + oidc: + default_browser_return_url: https://self-service/registration/oidc/return_to + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_registration_oidc_hook + method: GET + body: /path/to/template.jsonnet + - hook: session diff --git a/driver/config/stub/.kratos.webauthn.origins.yaml b/driver/config/stub/.kratos.webauthn.origins.yaml new file mode 100644 index 000000000000..f9349c670ac0 --- /dev/null +++ b/driver/config/stub/.kratos.webauthn.origins.yaml @@ -0,0 +1,230 @@ +# serve controls the configuration for the http(s) daemon +serve: + admin: + base_url: http://admin.kratos.ory.sh + port: 1234 + host: admin.kratos.ory.sh + public: + base_url: http://public.kratos.ory.sh + port: 1235 + host: public.kratos.ory.sh + +dsn: sqlite://foo.db?mode=memory&_fk=true + +log: + level: debug + +courier: + smtp: + connection_uri: smtp://foo:bar@baz/ + +identity: + default_schema_id: default + schemas: + - id: default + url: base64://ewogICIkaWQiOiAib3J5Oi8vaWRlbnRpdHktdGVzdC1zY2hlbWEiLAogICIkc2NoZW1hIjogImh0dHA6Ly9qc29uLXNjaGVtYS5vcmcvZHJhZnQtMDcvc2NoZW1hIyIsCiAgInRpdGxlIjogIklkZW50aXR5U2NoZW1hIiwKICAidHlwZSI6ICJvYmplY3QiLAogICJwcm9wZXJ0aWVzIjogewogICAgInRyYWl0cyI6IHsKICAgICAgInR5cGUiOiAib2JqZWN0IiwKICAgICAgInByb3BlcnRpZXMiOiB7CiAgICAgICAgIm5hbWUiOiB7CiAgICAgICAgICAidHlwZSI6ICJvYmplY3QiLAogICAgICAgICAgInByb3BlcnRpZXMiOiB7CiAgICAgICAgICAgICJmaXJzdCI6IHsKICAgICAgICAgICAgICAidHlwZSI6ICJzdHJpbmciCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgICJsYXN0IjogewogICAgICAgICAgICAgICJ0eXBlIjogInN0cmluZyIKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfSwKICAgICAgInJlcXVpcmVkIjogWwogICAgICAgICJuYW1lIgogICAgICBdLAogICAgICAiYWRkaXRpb25hbFByb3BlcnRpZXMiOiB0cnVlCiAgICB9CiAgfQp9 + - id: other + url: base64://ewogICIkaWQiOiAib3J5Oi8vaWRlbnRpdHktb3RoZXItc2NoZW1hIiwKICAiJHNjaGVtYSI6ICJodHRwOi8vanNvbi1zY2hlbWEub3JnL2RyYWZ0LTA3L3NjaGVtYSMiLAogICJ0aXRsZSI6ICJJZGVudGl0eU90aGVyU2NoZW1hIiwKICAidHlwZSI6ICJvYmplY3QiLAogICJwcm9wZXJ0aWVzIjogewogICAgInRyYWl0cyI6IHsKICAgICAgInR5cGUiOiAib2JqZWN0IiwKICAgICAgInByb3BlcnRpZXMiOiB7CiAgICAgICAgIm90aGVyIjogewogICAgICAgICAgInR5cGUiOiAic3RyaW5nIgogICAgICAgIH0sCiAgICAgICAgImVtYWlsIjogewogICAgICAgICAgInR5cGUiOiAic3RyaW5nIiwKICAgICAgICAgICJ0aXRsZSI6ICJlbWFpbCIsCiAgICAgICAgICAib3J5LnNoL2tyYXRvcyI6IHsKICAgICAgICAgICAgImNyZWRlbnRpYWxzIjogewogICAgICAgICAgICAgICJwYXNzd29yZCI6IHsKICAgICAgICAgICAgICAgICJpZGVudGlmaWVyIjogdHJ1ZQogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfSwKICAgICAgInJlcXVpcmVkIjogWwogICAgICAgICJvdGhlciIsCiAgICAgICAgImVtYWlsIgogICAgICBdLAogICAgICAiYWRkaXRpb25hbFByb3BlcnRpZXMiOiB0cnVlCiAgICB9CiAgfQp9 + +hashers: + argon2: + memory: 1MB + iterations: 2 + parallelism: 4 + salt_length: 16 + key_length: 32 + dedicated_memory: 1GB + expected_duration: 500ms + expected_deviation: 500ms + +secrets: + cookie: + - session-key-7f8a9b77-1 + - session-key-7f8a9b77-2 + cipher: + - secret-thirty-two-character-long + +ciphers: + algorithm: xchacha20-poly1305 + +selfservice: + default_browser_return_url: http://return-to-3-test.ory.sh/ + allowed_return_urls: + - http://return-to-1-test.ory.sh/ + - http://return-to-2-test.ory.sh/ + - http://*.wildcards.ory.sh + - http://*.sh + - http://*.com + - http://*.com.pl + - http://* + - /return-to-relative-test/ + methods: + totp: + enabled: true + config: + issuer: issuer.ory.sh + password: + enabled: true + oidc: + enabled: true + config: + providers: + - id: github + provider: github + client_id: a + client_secret: b + mapper_url: http://test.kratos.ory.sh/default-identity.schema.json + webauthn: + enabled: true + config: + rp: + id: https://example.com/webauthn + display_name: Webauthn + origins: + - https://origin-a.example.com + - https://origin-b.example.com + - https://origin-c.example.com + flows: + error: + ui_url: http://test.kratos.ory.sh/error + + logout: + after: + default_browser_return_url: http://test.kratos.ory.sh:4000/ + + recovery: + enabled: true + ui_url: http://test.kratos.ory.sh/recovery + lifespan: 98m + after: + default_browser_return_url: http://test.kratos.ory.sh/dashboard + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_recovery_hook + method: GET + body: /path/to/template.jsonnet + + verification: + enabled: true + lifespan: 97m + ui_url: http://test.kratos.ory.sh/verification + after: + default_browser_return_url: http://test.kratos.ory.sh/dashboard + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_verification_hook + method: GET + body: /path/to/template.jsonnet + + settings: + ui_url: http://test.kratos.ory.sh/settings + lifespan: 99m + privileged_session_max_age: 5m + after: + default_browser_return_url: https://self-service/settings/return_to + password: + default_browser_return_url: https://self-service/settings/password/return_to + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_settings_password_hook + method: POST + body: /path/to/template.jsonnet + profile: + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_settings_profile_hook + method: POST + body: /path/to/template.jsonnet + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_settings_global_hook + method: POST + body: /path/to/template.jsonnet + + login: + ui_url: http://test.kratos.ory.sh/login + lifespan: 99m + before: + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/before_login_hook + method: POST + after: + default_browser_return_url: https://self-service/login/return_to + password: + default_browser_return_url: https://self-service/login/password/return_to + hooks: + - hook: revoke_active_sessions + - hook: require_verified_address + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_login_password_hook + method: POST + body: /path/to/template.jsonnet + auth: + type: basic_auth + config: + user: test-user + password: super-secret + oidc: + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_login_oidc_hook + method: GET + body: /path/to/template.jsonnet + - hook: revoke_active_sessions + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_login_global_hook + method: POST + body: /path/to/template.jsonnet + + registration: + enabled: true + ui_url: http://test.kratos.ory.sh/register + lifespan: 98m + before: + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/before_registration_hook + method: GET + after: + default_browser_return_url: https://self-service/registration/return_to + password: + hooks: + - hook: session + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_registration_password_hook + method: POST + body: /path/to/template.jsonnet + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_registration_global_hook + method: POST + body: /path/to/template.jsonnet + auth: + type: api_key + config: + name: My-Key + value: My-Key-Value + in: header + oidc: + default_browser_return_url: https://self-service/registration/oidc/return_to + hooks: + - hook: web_hook + config: + url: https://test.kratos.ory.sh/after_registration_oidc_hook + method: GET + body: /path/to/template.jsonnet + - hook: session diff --git a/driver/config/stub/.kratos.yaml b/driver/config/stub/.kratos.yaml index ce4d2f3c27a5..b50341928ad8 100644 --- a/driver/config/stub/.kratos.yaml +++ b/driver/config/stub/.kratos.yaml @@ -74,6 +74,12 @@ selfservice: client_id: a client_secret: b mapper_url: http://test.kratos.ory.sh/default-identity.schema.json + webauthn: + enabled: true + config: + rp: + id: example.com + display_name: Webauthn flows: error: ui_url: http://test.kratos.ory.sh/error diff --git a/embedx/config.schema.json b/embedx/config.schema.json index ece7f175b20b..2aa5eb1e056d 100644 --- a/embedx/config.schema.json +++ b/embedx/config.schema.json @@ -1578,10 +1578,6 @@ }, "rp": { "title": "Relying Party (RP) Config", - "required": [ - "id", - "display_name" - ], "properties": { "display_name": { "type": "string", @@ -1602,23 +1598,72 @@ "origin": { "type": "string", "title": "Relying Party Origin", - "description": "An explicit RP origin. If left empty, this defaults to `id`.", + "description": "An explicit RP origin. If left empty, this defaults to `id`, prepended with the current protocol schema (HTTP or HTTPS).", "format": "uri", + "deprecationMessage": "This field is deprecated. Use `origins` instead.", "examples": [ - "https://www.ory.sh/login" + "https://www.ory.sh" ] }, + "origins": { + "type": "array", + "title": "Relying Party Origins", + "description": "A list of explicit RP origins. If left empty, this defaults to either `origin` or `id`, prepended with the current protocol schema (HTTP or HTTPS).", + "items": { + "type": "string", + "format": "uri", + "examples": [ + "https://www.ory.sh", + "https://auth.ory.sh" + ] + } + }, "icon": { "type": "string", "title": "Relying Party Icon", "description": "An icon to help the user identify this RP.", "format": "uri", + "deprecationMessage": "This field is deprecated and ignored due to security considerations.", "examples": [ "https://www.ory.sh/an-icon.png" ] } }, - "type": "object" + "type": "object", + "oneOf": [ + { + "required": [ + "id", + "display_name" + ], + "properties": { + "origin": {"not": {}}, + "origins": {"not": {}} + } + }, + { + "required": [ + "id", + "display_name", + "origin" + ], + "properties": { + "origin": {"type": "string"}, + "origins": {"not": {}} + } + }, + { + "required": [ + "id", + "display_name", + "origins" + ], + "properties": { + "origin": {"not": {}}, + "origins": {"type": "array", "items": {"type": "string"}} + } + } + ] } }, "additionalProperties": false @@ -2740,4 +2785,4 @@ "selfservice" ], "additionalProperties": false -} \ No newline at end of file +} diff --git a/go.mod b/go.mod index 9e8d579bc483..e1e44a675583 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,6 @@ require ( github.com/davecgh/go-spew v1.1.1 github.com/davidrjonas/semver-cli v0.0.0-20190116233701-ee19a9a0dda6 github.com/dgraph-io/ristretto v0.1.1 - github.com/duo-labs/webauthn v0.0.0-20220330035159-03696f3d4499 github.com/fatih/color v1.13.0 github.com/ghodss/yaml v1.0.0 github.com/go-crypt/crypt v0.2.9 @@ -37,11 +36,12 @@ require ( github.com/go-openapi/strfmt v0.21.3 github.com/go-playground/validator/v10 v10.4.1 github.com/go-swagger/go-swagger v0.30.3 + github.com/go-webauthn/webauthn v0.8.4 github.com/gobuffalo/fizz v1.14.4 github.com/gobuffalo/httptest v1.5.2 github.com/gobuffalo/pop/v6 v6.1.2-0.20230318123913-c85387acc9a0 github.com/gofrs/uuid v4.3.1+incompatible - github.com/golang-jwt/jwt/v4 v4.1.0 + github.com/golang-jwt/jwt/v4 v4.5.0 github.com/golang/gddo v0.0.0-20190904175337-72a348e765d2 github.com/golang/mock v1.6.0 github.com/google/go-github/v27 v27.0.1 @@ -87,7 +87,7 @@ require ( github.com/spf13/cobra v1.7.0 github.com/spf13/pflag v1.0.5 github.com/sqs/goreturns v0.0.0-20181028201513-538ac6014518 - github.com/stretchr/testify v1.8.2 + github.com/stretchr/testify v1.8.4 github.com/tidwall/gjson v1.14.3 github.com/tidwall/sjson v1.2.5 github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 @@ -96,8 +96,8 @@ require ( go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.4 go.opentelemetry.io/otel v1.11.1 go.opentelemetry.io/otel/trace v1.11.1 - golang.org/x/crypto v0.5.0 - golang.org/x/net v0.8.0 + golang.org/x/crypto v0.11.0 + golang.org/x/net v0.10.0 golang.org/x/oauth2 v0.6.0 golang.org/x/sync v0.1.0 golang.org/x/tools/cmd/cover v0.1.0-deprecated @@ -171,6 +171,7 @@ require ( github.com/go-playground/locales v0.13.0 // indirect github.com/go-playground/universal-translator v0.17.0 // indirect github.com/go-sql-driver/mysql v1.7.0 // indirect + github.com/go-webauthn/x v0.1.4 // indirect github.com/gobuffalo/envy v1.10.2 // indirect github.com/gobuffalo/flect v1.0.0 // indirect github.com/gobuffalo/github_flavored_markdown v1.1.3 // indirect @@ -188,6 +189,7 @@ require ( github.com/google/btree v1.0.1 // indirect github.com/google/certificate-transparency-go v1.1.2-0.20210511102531-373a877eec92 // indirect github.com/google/go-querystring v1.0.0 // indirect + github.com/google/go-tpm v0.9.0 // indirect github.com/google/pprof v0.0.0-20221010195024-131d412537ea // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.3.0 // indirect @@ -340,9 +342,9 @@ require ( go.uber.org/zap v1.21.0 // indirect golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect golang.org/x/mod v0.10.0 // indirect - golang.org/x/sys v0.8.0 // indirect - golang.org/x/term v0.6.0 // indirect - golang.org/x/text v0.8.0 // indirect + golang.org/x/sys v0.10.0 // indirect + golang.org/x/term v0.10.0 // indirect + golang.org/x/text v0.11.0 // indirect golang.org/x/time v0.1.0 // indirect golang.org/x/tools v0.7.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect diff --git a/go.sum b/go.sum index 73270b1447db..ba9c3f08b0ba 100644 --- a/go.sum +++ b/go.sum @@ -296,8 +296,6 @@ github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5Xh github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/duo-labs/webauthn v0.0.0-20220330035159-03696f3d4499 h1:jaQHuGKk9NVcfu9VbA7ygslr/7utxdYs47i4osBhZP8= -github.com/duo-labs/webauthn v0.0.0-20220330035159-03696f3d4499/go.mod h1:UMk1JMDgQDcdI2vQz+WJOIUTSjIq07qSepAVgc93rUc= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -446,6 +444,12 @@ github.com/go-swagger/go-swagger v0.30.3/go.mod h1:neDPes8r8PCz2JPvHRDj8BTULLh4V github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013 h1:l9rI6sNaZgNC0LnF3MiE+qTmyBA/tZAg1rtyrGbUMK0= github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/go-webauthn/webauthn v0.0.0-20220330035159-03696f3d4499 h1:jaQHuGKk9NVcfu9VbA7ygslr/7utxdYs47i4osBhZP8= +github.com/go-webauthn/webauthn v0.0.0-20220330035159-03696f3d4499/go.mod h1:UMk1JMDgQDcdI2vQz+WJOIUTSjIq07qSepAVgc93rUc= +github.com/go-webauthn/webauthn v0.8.4 h1:/emQ9b9Rj4flWO94Fo8KJeYvZ6VzPywXsmqyDA/WicY= +github.com/go-webauthn/webauthn v0.8.4/go.mod h1:ZqEa9OnSCdQf6CJvTWTDCsUcPRi8F3h7XCIDINwbBgI= +github.com/go-webauthn/x v0.1.4 h1:sGmIFhcY70l6k7JIDfnjVBiAAFEssga5lXIUXe0GtAs= +github.com/go-webauthn/x v0.1.4/go.mod h1:75Ug0oK6KYpANh5hDOanfDI+dvPWHk788naJVG/37H8= github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= github.com/gobuffalo/attrs v1.0.3/go.mod h1:KvDJCE0avbufqS0Bw3UV7RQynESY0jjod+572ctX4t8= github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= @@ -520,6 +524,8 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.1.0 h1:XUgk2Ex5veyVFVeLm0xhusUTQybEbexJXrvPNOKkSY0= github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/gddo v0.0.0-20190904175337-72a348e765d2 h1:xisWqjiKEff2B0KfFYGpCqc3M3zdTz+OHQHRc09FeYk= 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= @@ -598,6 +604,8 @@ github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASu github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-replayers/grpcreplay v0.1.0/go.mod h1:8Ig2Idjpr6gifRd6pNVggX6TC1Zw6Jx74AKp7QNH2QE= github.com/google/go-replayers/httpreplay v0.1.0/go.mod h1:YKZViNhiGgqdBlUbI2MwGpq4pXxNmhJLPHQ7cv2b5no= +github.com/google/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk= +github.com/google/go-tpm v0.9.0/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47QWKfU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/licenseclassifier v0.0.0-20210325184830-bb04aff29e72/go.mod h1:qsqn2hxC+vURpyBRygGUuinTO42MFRLcsmQ/P8v94+M= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= @@ -1365,6 +1373,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= @@ -1596,6 +1606,8 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= +golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1707,6 +1719,8 @@ golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfS golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1851,6 +1865,8 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20191110171634-ad39bd3f0407/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1861,6 +1877,8 @@ golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= 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= @@ -1873,6 +1891,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/identity/credentials_webauthn.go b/identity/credentials_webauthn.go index a41a15a9e70f..ecfd132ea0b1 100644 --- a/identity/credentials_webauthn.go +++ b/identity/credentials_webauthn.go @@ -6,7 +6,7 @@ package identity import ( "time" - "github.com/duo-labs/webauthn/webauthn" + "github.com/go-webauthn/webauthn/webauthn" ) // CredentialsConfig is the struct that is being used as part of the identity credentials. diff --git a/identity/credentials_webauthn_test.go b/identity/credentials_webauthn_test.go index 5386d212f559..c081c1826c41 100644 --- a/identity/credentials_webauthn_test.go +++ b/identity/credentials_webauthn_test.go @@ -6,7 +6,7 @@ package identity import ( "testing" - "github.com/duo-labs/webauthn/webauthn" + "github.com/go-webauthn/webauthn/webauthn" "github.com/stretchr/testify/assert" ) diff --git a/selfservice/strategy/code/strategy_recovery_test.go b/selfservice/strategy/code/strategy_recovery_test.go index db6af2c126b1..e07c0fb28f50 100644 --- a/selfservice/strategy/code/strategy_recovery_test.go +++ b/selfservice/strategy/code/strategy_recovery_test.go @@ -545,7 +545,7 @@ func TestRecovery(t *testing.T) { body = checkRecovery(t, client, RecoveryFlowTypeBrowser, email, body) - assert.Equal(t, text.NewRecoverySuccessful(time.Now().Add(time.Hour)).Text, + require.Equal(t, text.NewRecoverySuccessful(time.Now().Add(time.Hour)).Text, gjson.Get(body, "ui.messages.0.text").String()) settingsId := gjson.Get(body, "id").String() diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=mfa-case=webauthn_payload_is_set_when_identity_has_webauthn.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=mfa-case=webauthn_payload_is_set_when_identity_has_webauthn.json index eeddaab6c127..0e2e343e00e0 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=mfa-case=webauthn_payload_is_set_when_identity_has_webauthn.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=mfa-case=webauthn_payload_is_set_when_identity_has_webauthn.json @@ -61,7 +61,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-8GWpMHzEByiefeXeZNxg1k16eFoSoff1mQVa4vUUruBughTU/Yt4WGl7yteMa11UgygiMEbH8Xn1oKxh8PbkiA==", + "integrity": "sha512-RI23aG5lwYTo7zknGdc++eHUMimUWhkyFzrGid6HkVSdUSjdESPtM3KufXGq/lo4Ut0jI9mDiZeT8tHoSvaHvg==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" 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 0a7494871340..815e99cb456b 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 @@ -36,7 +36,7 @@ "async": true, "referrerpolicy": "no-referrer", "crossorigin": "anonymous", - "integrity": "sha512-8GWpMHzEByiefeXeZNxg1k16eFoSoff1mQVa4vUUruBughTU/Yt4WGl7yteMa11UgygiMEbH8Xn1oKxh8PbkiA==", + "integrity": "sha512-RI23aG5lwYTo7zknGdc++eHUMimUWhkyFzrGid6HkVSdUSjdESPtM3KufXGq/lo4Ut0jI9mDiZeT8tHoSvaHvg==", "type": "text/javascript", "node_type": "script" }, 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 0a7494871340..815e99cb456b 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 @@ -36,7 +36,7 @@ "async": true, "referrerpolicy": "no-referrer", "crossorigin": "anonymous", - "integrity": "sha512-8GWpMHzEByiefeXeZNxg1k16eFoSoff1mQVa4vUUruBughTU/Yt4WGl7yteMa11UgygiMEbH8Xn1oKxh8PbkiA==", + "integrity": "sha512-RI23aG5lwYTo7zknGdc++eHUMimUWhkyFzrGid6HkVSdUSjdESPtM3KufXGq/lo4Ut0jI9mDiZeT8tHoSvaHvg==", "type": "text/javascript", "node_type": "script" }, diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=false#01-browser.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=false#01-browser.json index fef5b394c157..8b27f6ca0daf 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=false#01-browser.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=false#01-browser.json @@ -62,7 +62,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-8GWpMHzEByiefeXeZNxg1k16eFoSoff1mQVa4vUUruBughTU/Yt4WGl7yteMa11UgygiMEbH8Xn1oKxh8PbkiA==", + "integrity": "sha512-RI23aG5lwYTo7zknGdc++eHUMimUWhkyFzrGid6HkVSdUSjdESPtM3KufXGq/lo4Ut0jI9mDiZeT8tHoSvaHvg==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=false#01-spa.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=false#01-spa.json index fef5b394c157..8b27f6ca0daf 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=false#01-spa.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=false#01-spa.json @@ -62,7 +62,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-8GWpMHzEByiefeXeZNxg1k16eFoSoff1mQVa4vUUruBughTU/Yt4WGl7yteMa11UgygiMEbH8Xn1oKxh8PbkiA==", + "integrity": "sha512-RI23aG5lwYTo7zknGdc++eHUMimUWhkyFzrGid6HkVSdUSjdESPtM3KufXGq/lo4Ut0jI9mDiZeT8tHoSvaHvg==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=false#02-browser.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=false#02-browser.json index fef5b394c157..8b27f6ca0daf 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=false#02-browser.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=false#02-browser.json @@ -62,7 +62,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-8GWpMHzEByiefeXeZNxg1k16eFoSoff1mQVa4vUUruBughTU/Yt4WGl7yteMa11UgygiMEbH8Xn1oKxh8PbkiA==", + "integrity": "sha512-RI23aG5lwYTo7zknGdc++eHUMimUWhkyFzrGid6HkVSdUSjdESPtM3KufXGq/lo4Ut0jI9mDiZeT8tHoSvaHvg==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=false#02-spa.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=false#02-spa.json index fef5b394c157..8b27f6ca0daf 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=false#02-spa.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=false#02-spa.json @@ -62,7 +62,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-8GWpMHzEByiefeXeZNxg1k16eFoSoff1mQVa4vUUruBughTU/Yt4WGl7yteMa11UgygiMEbH8Xn1oKxh8PbkiA==", + "integrity": "sha512-RI23aG5lwYTo7zknGdc++eHUMimUWhkyFzrGid6HkVSdUSjdESPtM3KufXGq/lo4Ut0jI9mDiZeT8tHoSvaHvg==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=false-browser.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=false-browser.json index fef5b394c157..8b27f6ca0daf 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=false-browser.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=false-browser.json @@ -62,7 +62,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-8GWpMHzEByiefeXeZNxg1k16eFoSoff1mQVa4vUUruBughTU/Yt4WGl7yteMa11UgygiMEbH8Xn1oKxh8PbkiA==", + "integrity": "sha512-RI23aG5lwYTo7zknGdc++eHUMimUWhkyFzrGid6HkVSdUSjdESPtM3KufXGq/lo4Ut0jI9mDiZeT8tHoSvaHvg==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=false-spa.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=false-spa.json index fef5b394c157..8b27f6ca0daf 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=false-spa.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=false-spa.json @@ -62,7 +62,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-8GWpMHzEByiefeXeZNxg1k16eFoSoff1mQVa4vUUruBughTU/Yt4WGl7yteMa11UgygiMEbH8Xn1oKxh8PbkiA==", + "integrity": "sha512-RI23aG5lwYTo7zknGdc++eHUMimUWhkyFzrGid6HkVSdUSjdESPtM3KufXGq/lo4Ut0jI9mDiZeT8tHoSvaHvg==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=true#01-browser.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=true#01-browser.json index fef5b394c157..8b27f6ca0daf 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=true#01-browser.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=true#01-browser.json @@ -62,7 +62,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-8GWpMHzEByiefeXeZNxg1k16eFoSoff1mQVa4vUUruBughTU/Yt4WGl7yteMa11UgygiMEbH8Xn1oKxh8PbkiA==", + "integrity": "sha512-RI23aG5lwYTo7zknGdc++eHUMimUWhkyFzrGid6HkVSdUSjdESPtM3KufXGq/lo4Ut0jI9mDiZeT8tHoSvaHvg==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=true#01-spa.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=true#01-spa.json index fef5b394c157..8b27f6ca0daf 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=true#01-spa.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=true#01-spa.json @@ -62,7 +62,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-8GWpMHzEByiefeXeZNxg1k16eFoSoff1mQVa4vUUruBughTU/Yt4WGl7yteMa11UgygiMEbH8Xn1oKxh8PbkiA==", + "integrity": "sha512-RI23aG5lwYTo7zknGdc++eHUMimUWhkyFzrGid6HkVSdUSjdESPtM3KufXGq/lo4Ut0jI9mDiZeT8tHoSvaHvg==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=true#02-browser.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=true#02-browser.json index fef5b394c157..8b27f6ca0daf 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=true#02-browser.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=true#02-browser.json @@ -62,7 +62,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-8GWpMHzEByiefeXeZNxg1k16eFoSoff1mQVa4vUUruBughTU/Yt4WGl7yteMa11UgygiMEbH8Xn1oKxh8PbkiA==", + "integrity": "sha512-RI23aG5lwYTo7zknGdc++eHUMimUWhkyFzrGid6HkVSdUSjdESPtM3KufXGq/lo4Ut0jI9mDiZeT8tHoSvaHvg==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=true#02-spa.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=true#02-spa.json index fef5b394c157..8b27f6ca0daf 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=true#02-spa.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=true#02-spa.json @@ -62,7 +62,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-8GWpMHzEByiefeXeZNxg1k16eFoSoff1mQVa4vUUruBughTU/Yt4WGl7yteMa11UgygiMEbH8Xn1oKxh8PbkiA==", + "integrity": "sha512-RI23aG5lwYTo7zknGdc++eHUMimUWhkyFzrGid6HkVSdUSjdESPtM3KufXGq/lo4Ut0jI9mDiZeT8tHoSvaHvg==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=true-browser.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=true-browser.json index fef5b394c157..8b27f6ca0daf 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=true-browser.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=true-browser.json @@ -62,7 +62,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-8GWpMHzEByiefeXeZNxg1k16eFoSoff1mQVa4vUUruBughTU/Yt4WGl7yteMa11UgygiMEbH8Xn1oKxh8PbkiA==", + "integrity": "sha512-RI23aG5lwYTo7zknGdc++eHUMimUWhkyFzrGid6HkVSdUSjdESPtM3KufXGq/lo4Ut0jI9mDiZeT8tHoSvaHvg==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=true-spa.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=true-spa.json index fef5b394c157..8b27f6ca0daf 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=true-spa.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-case=mfa_v0_credentials-passwordless_enabled=true-spa.json @@ -62,7 +62,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-8GWpMHzEByiefeXeZNxg1k16eFoSoff1mQVa4vUUruBughTU/Yt4WGl7yteMa11UgygiMEbH8Xn1oKxh8PbkiA==", + "integrity": "sha512-RI23aG5lwYTo7zknGdc++eHUMimUWhkyFzrGid6HkVSdUSjdESPtM3KufXGq/lo4Ut0jI9mDiZeT8tHoSvaHvg==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=a_device_is_shown_which_can_be_unlinked.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=a_device_is_shown_which_can_be_unlinked.json index 14c7a09cc543..43a740b43790 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=a_device_is_shown_which_can_be_unlinked.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=a_device_is_shown_which_can_be_unlinked.json @@ -114,7 +114,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-8GWpMHzEByiefeXeZNxg1k16eFoSoff1mQVa4vUUruBughTU/Yt4WGl7yteMa11UgygiMEbH8Xn1oKxh8PbkiA==", + "integrity": "sha512-RI23aG5lwYTo7zknGdc++eHUMimUWhkyFzrGid6HkVSdUSjdESPtM3KufXGq/lo4Ut0jI9mDiZeT8tHoSvaHvg==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=one_activation_element_is_shown.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=one_activation_element_is_shown.json index 94897f01f337..ab20337abc14 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=one_activation_element_is_shown.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=one_activation_element_is_shown.json @@ -68,7 +68,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-8GWpMHzEByiefeXeZNxg1k16eFoSoff1mQVa4vUUruBughTU/Yt4WGl7yteMa11UgygiMEbH8Xn1oKxh8PbkiA==", + "integrity": "sha512-RI23aG5lwYTo7zknGdc++eHUMimUWhkyFzrGid6HkVSdUSjdESPtM3KufXGq/lo4Ut0jI9mDiZeT8tHoSvaHvg==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-browser.json b/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-browser.json index d02f55750550..09b1f9ed6449 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-browser.json +++ b/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-browser.json @@ -94,7 +94,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-8GWpMHzEByiefeXeZNxg1k16eFoSoff1mQVa4vUUruBughTU/Yt4WGl7yteMa11UgygiMEbH8Xn1oKxh8PbkiA==", + "integrity": "sha512-RI23aG5lwYTo7zknGdc++eHUMimUWhkyFzrGid6HkVSdUSjdESPtM3KufXGq/lo4Ut0jI9mDiZeT8tHoSvaHvg==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-spa.json b/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-spa.json index d02f55750550..09b1f9ed6449 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-spa.json +++ b/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-spa.json @@ -94,7 +94,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-8GWpMHzEByiefeXeZNxg1k16eFoSoff1mQVa4vUUruBughTU/Yt4WGl7yteMa11UgygiMEbH8Xn1oKxh8PbkiA==", + "integrity": "sha512-RI23aG5lwYTo7zknGdc++eHUMimUWhkyFzrGid6HkVSdUSjdESPtM3KufXGq/lo4Ut0jI9mDiZeT8tHoSvaHvg==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/webauthn/js/webauthn.js b/selfservice/strategy/webauthn/js/webauthn.js index fd62c1213764..44c389d6f16b 100644 --- a/selfservice/strategy/webauthn/js/webauthn.js +++ b/selfservice/strategy/webauthn/js/webauthn.js @@ -1,13 +1,13 @@ // Copyright © 2023 Ory Corp // SPDX-License-Identifier: Apache-2.0 -(function () { +;(function () { if (!window) { return } if (!window.PublicKeyCredential) { - alert('This browser does not support WebAuthn!'); + alert("This browser does not support WebAuthn!") } if (window.__oryWebAuthnInitialized) { @@ -15,85 +15,116 @@ } function __oryWebAuthnBufferDecode(value) { - return Uint8Array.from(atob(value), function (c) { - return c.charCodeAt(0) - }); + return Uint8Array.from( + atob(value.replaceAll("-", "+").replaceAll("_", "/")), + function (c) { + return c.charCodeAt(0) + }, + ) } function __oryWebAuthnBufferEncode(value) { return btoa(String.fromCharCode.apply(null, new Uint8Array(value))) - .replace(/\+/g, '-') - .replace(/\//g, '_') - .replace(/=/g, ''); + .replaceAll("+", "-") + .replaceAll("/", "_") + .replaceAll("=", "") } - function __oryWebAuthnLogin(opt, resultQuerySelector = '*[name="webauthn_login"]', triggerQuerySelector = '*[name="webauthn_login_trigger"]') { + function __oryWebAuthnLogin( + opt, + resultQuerySelector = '*[name="webauthn_login"]', + triggerQuerySelector = '*[name="webauthn_login_trigger"]', + ) { if (!window.PublicKeyCredential) { - alert('This browser does not support WebAuthn!'); + alert("This browser does not support WebAuthn!") } - opt.publicKey.challenge = __oryWebAuthnBufferDecode(opt.publicKey.challenge); - opt.publicKey.allowCredentials = opt.publicKey.allowCredentials.map(function (value) { - return { - ...value, - id: __oryWebAuthnBufferDecode(value.id) - } - }); + opt.publicKey.challenge = __oryWebAuthnBufferDecode(opt.publicKey.challenge) + opt.publicKey.allowCredentials = opt.publicKey.allowCredentials.map( + function (value) { + return { + ...value, + id: __oryWebAuthnBufferDecode(value.id), + } + }, + ) - navigator.credentials.get(opt).then(function (credential) { - document.querySelector(resultQuerySelector).value = JSON.stringify({ - id: credential.id, - rawId: __oryWebAuthnBufferEncode(credential.rawId), - type: credential.type, - response: { - authenticatorData: __oryWebAuthnBufferEncode(credential.response.authenticatorData), - clientDataJSON: __oryWebAuthnBufferEncode(credential.response.clientDataJSON), - signature: __oryWebAuthnBufferEncode(credential.response.signature), - userHandle: __oryWebAuthnBufferEncode(credential.response.userHandle), - }, - }) + navigator.credentials + .get(opt) + .then(function (credential) { + document.querySelector(resultQuerySelector).value = JSON.stringify({ + id: credential.id, + rawId: __oryWebAuthnBufferEncode(credential.rawId), + type: credential.type, + response: { + authenticatorData: __oryWebAuthnBufferEncode( + credential.response.authenticatorData, + ), + clientDataJSON: __oryWebAuthnBufferEncode( + credential.response.clientDataJSON, + ), + signature: __oryWebAuthnBufferEncode(credential.response.signature), + userHandle: __oryWebAuthnBufferEncode( + credential.response.userHandle, + ), + }, + }) - document.querySelector(triggerQuerySelector).closest('form').submit() - }).catch((err) => { - alert(err) - }) + document.querySelector(triggerQuerySelector).closest("form").submit() + }) + .catch((err) => { + alert(err) + }) } - function __oryWebAuthnRegistration(opt, resultQuerySelector = '*[name="webauthn_register"]', triggerQuerySelector = '*[name="webauthn_register_trigger"]') { + function __oryWebAuthnRegistration( + opt, + resultQuerySelector = '*[name="webauthn_register"]', + triggerQuerySelector = '*[name="webauthn_register_trigger"]', + ) { if (!window.PublicKeyCredential) { - alert('This browser does not support WebAuthn!'); + alert("This browser does not support WebAuthn!") } - opt.publicKey.user.id = __oryWebAuthnBufferDecode(opt.publicKey.user.id); - opt.publicKey.challenge = __oryWebAuthnBufferDecode(opt.publicKey.challenge); + opt.publicKey.user.id = __oryWebAuthnBufferDecode(opt.publicKey.user.id) + opt.publicKey.challenge = __oryWebAuthnBufferDecode(opt.publicKey.challenge) if (opt.publicKey.excludeCredentials) { - opt.publicKey.excludeCredentials = opt.publicKey.excludeCredentials.map(function (value) { - return { - ...value, - id: __oryWebAuthnBufferDecode(value.id) - } - }) + opt.publicKey.excludeCredentials = opt.publicKey.excludeCredentials.map( + function (value) { + return { + ...value, + id: __oryWebAuthnBufferDecode(value.id), + } + }, + ) } - navigator.credentials.create(opt).then(function (credential) { - document.querySelector(resultQuerySelector).value = JSON.stringify({ - id: credential.id, - rawId: __oryWebAuthnBufferEncode(credential.rawId), - type: credential.type, - response: { - attestationObject: __oryWebAuthnBufferEncode(credential.response.attestationObject), - clientDataJSON: __oryWebAuthnBufferEncode(credential.response.clientDataJSON), - }, - }) + navigator.credentials + .create(opt) + .then(function (credential) { + document.querySelector(resultQuerySelector).value = JSON.stringify({ + id: credential.id, + rawId: __oryWebAuthnBufferEncode(credential.rawId), + type: credential.type, + response: { + attestationObject: __oryWebAuthnBufferEncode( + credential.response.attestationObject, + ), + clientDataJSON: __oryWebAuthnBufferEncode( + credential.response.clientDataJSON, + ), + }, + }) - document.querySelector(triggerQuerySelector).closest('form').submit() - }).catch((err) => { - alert(err) - }) + document.querySelector(triggerQuerySelector).closest("form").submit() + }) + .catch((err) => { + alert(err) + }) } - window['__oryWebAuthnLogin'] = __oryWebAuthnLogin - window['__oryWebAuthnRegistration'] = __oryWebAuthnRegistration - window['__oryWebAuthnInitialized'] = true + window["__oryWebAuthnLogin"] = __oryWebAuthnLogin + window["__oryWebAuthnRegistration"] = __oryWebAuthnRegistration + window["__oryWebAuthnInitialized"] = true })() diff --git a/selfservice/strategy/webauthn/login.go b/selfservice/strategy/webauthn/login.go index 33e2689ea315..58cf7b0f25a1 100644 --- a/selfservice/strategy/webauthn/login.go +++ b/selfservice/strategy/webauthn/login.go @@ -19,8 +19,8 @@ import ( "github.com/ory/x/urlx" - "github.com/duo-labs/webauthn/protocol" - "github.com/duo-labs/webauthn/webauthn" + "github.com/go-webauthn/webauthn/protocol" + "github.com/go-webauthn/webauthn/webauthn" "github.com/tidwall/gjson" "github.com/tidwall/sjson" diff --git a/selfservice/strategy/webauthn/login_test.go b/selfservice/strategy/webauthn/login_test.go index 6c8bfc8a27b2..f5d332182163 100644 --- a/selfservice/strategy/webauthn/login_test.go +++ b/selfservice/strategy/webauthn/login_test.go @@ -15,7 +15,7 @@ import ( "github.com/ory/x/jsonx" - "github.com/duo-labs/webauthn/protocol" + "github.com/go-webauthn/webauthn/protocol" kratos "github.com/ory/kratos/internal/httpclient" "github.com/ory/kratos/text" diff --git a/selfservice/strategy/webauthn/registration.go b/selfservice/strategy/webauthn/registration.go index 96b67244abaa..fab8e2cb77c5 100644 --- a/selfservice/strategy/webauthn/registration.go +++ b/selfservice/strategy/webauthn/registration.go @@ -9,8 +9,8 @@ import ( "strings" "time" - "github.com/duo-labs/webauthn/protocol" - "github.com/duo-labs/webauthn/webauthn" + "github.com/go-webauthn/webauthn/protocol" + "github.com/go-webauthn/webauthn/webauthn" "github.com/pkg/errors" "github.com/tidwall/gjson" "github.com/tidwall/sjson" diff --git a/selfservice/strategy/webauthn/settings.go b/selfservice/strategy/webauthn/settings.go index a6e513a20c99..ad00289c010a 100644 --- a/selfservice/strategy/webauthn/settings.go +++ b/selfservice/strategy/webauthn/settings.go @@ -14,8 +14,8 @@ import ( "github.com/ory/x/urlx" - "github.com/duo-labs/webauthn/protocol" - "github.com/duo-labs/webauthn/webauthn" + "github.com/go-webauthn/webauthn/protocol" + "github.com/go-webauthn/webauthn/webauthn" "github.com/ory/x/sqlcon" "github.com/ory/x/sqlxx" @@ -361,7 +361,7 @@ func (s *Strategy) PopulateSettingsMethod(r *http.Request, id *identity.Identity return errors.WithStack(err) } - option, sessionData, err := web.BeginRegistration(NewUser(id.ID[:], nil, web.Config)) + option, sessionData, err := web.BeginRegistration(NewUser(id.ID.Bytes(), nil, web.Config)) if err != nil { return errors.WithStack(err) } diff --git a/selfservice/strategy/webauthn/user.go b/selfservice/strategy/webauthn/user.go index 4d644afbe7fd..823ca93de106 100644 --- a/selfservice/strategy/webauthn/user.go +++ b/selfservice/strategy/webauthn/user.go @@ -3,7 +3,7 @@ package webauthn -import "github.com/duo-labs/webauthn/webauthn" +import "github.com/go-webauthn/webauthn/webauthn" var _ webauthn.User = (*User)(nil) @@ -34,7 +34,7 @@ func (u *User) WebAuthnDisplayName() string { } func (u *User) WebAuthnIcon() string { - return u.cfg.RPIcon + return "" // Icon option has been removed due to security considerations. } func (u *User) WebAuthnCredentials() []webauthn.Credential { From d4d26e6e1510c8e09346e95251f420f95ec54998 Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Tue, 1 Aug 2023 08:15:55 +0200 Subject: [PATCH 015/282] docs: remove experimental warnings (#3406) See https://github.com/ory/kratos/discussions/3388 --- selfservice/flow/login/handler.go | 6 ------ selfservice/flow/registration/handler.go | 6 ------ 2 files changed, 12 deletions(-) diff --git a/selfservice/flow/login/handler.go b/selfservice/flow/login/handler.go index de545cedcd69..de939f9e89bb 100644 --- a/selfservice/flow/login/handler.go +++ b/selfservice/flow/login/handler.go @@ -641,12 +641,6 @@ type updateLoginFlowBody struct{} // // # Submit a Login Flow // -// :::info -// -// This endpoint is EXPERIMENTAL and subject to potential breaking changes in the future. -// -// ::: -// // Use this endpoint to complete a login flow. This endpoint // behaves differently for API and browser flows. // diff --git a/selfservice/flow/registration/handler.go b/selfservice/flow/registration/handler.go index 66c3f0fe9389..179909180824 100644 --- a/selfservice/flow/registration/handler.go +++ b/selfservice/flow/registration/handler.go @@ -267,12 +267,6 @@ type createBrowserRegistrationFlow struct { // This endpoint initializes a browser-based user registration flow. This endpoint will set the appropriate // cookies and anti-CSRF measures required for browser-based flows. // -// :::info -// -// This endpoint is EXPERIMENTAL and subject to potential breaking changes in the future. -// -// ::: -// // If this endpoint is opened as a link in the browser, it will be redirected to // `selfservice.flows.registration.ui_url` with the flow ID set as the query parameter `?flow=`. If a valid user session // exists already, the browser will be redirected to `urls.default_redirect_url`. From b1dc89570cd4a02f1777d40612f5074f0e04501e Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Tue, 1 Aug 2023 06:18:09 +0000 Subject: [PATCH 016/282] autogen(openapi): regenerate swagger spec and internal client [skip ci] --- internal/client-go/api_frontend.go | 27 ++------------------------- internal/httpclient/api_frontend.go | 27 ++------------------------- spec/api.json | 4 ++-- spec/swagger.json | 4 ++-- 4 files changed, 8 insertions(+), 54 deletions(-) diff --git a/internal/client-go/api_frontend.go b/internal/client-go/api_frontend.go index 7afb4eeda28b..ac8cadd1a4b3 100644 --- a/internal/client-go/api_frontend.go +++ b/internal/client-go/api_frontend.go @@ -114,12 +114,6 @@ type FrontendApi interface { * This endpoint initializes a browser-based user registration flow. This endpoint will set the appropriate cookies and anti-CSRF measures required for browser-based flows. - :::info - - This endpoint is EXPERIMENTAL and subject to potential breaking changes in the future. - - ::: - If this endpoint is opened as a link in the browser, it will be redirected to `selfservice.flows.registration.ui_url` with the flow ID set as the query parameter `?flow=`. If a valid user session exists already, the browser will be redirected to `urls.default_redirect_url`. @@ -707,13 +701,7 @@ type FrontendApi interface { /* * UpdateLoginFlow Submit a Login Flow - * :::info - - This endpoint is EXPERIMENTAL and subject to potential breaking changes in the future. - - ::: - - Use this endpoint to complete a login flow. This endpoint + * Use this endpoint to complete a login flow. This endpoint behaves differently for API and browser flows. API flows expect `application/json` to be sent in the body and responds with @@ -1441,12 +1429,6 @@ func (r FrontendApiApiCreateBrowserRegistrationFlowRequest) Execute() (*Registra cookies and anti-CSRF measures required for browser-based flows. -:::info - -This endpoint is EXPERIMENTAL and subject to potential breaking changes in the future. - -::: - If this endpoint is opened as a link in the browser, it will be redirected to `selfservice.flows.registration.ui_url` with the flow ID set as the query parameter `?flow=`. If a valid user session exists already, the browser will be redirected to `urls.default_redirect_url`. @@ -4700,13 +4682,8 @@ func (r FrontendApiApiUpdateLoginFlowRequest) Execute() (*SuccessfulNativeLogin, /* - UpdateLoginFlow Submit a Login Flow - - :::info - -This endpoint is EXPERIMENTAL and subject to potential breaking changes in the future. - -::: + - Use this endpoint to complete a login flow. This endpoint -Use this endpoint to complete a login flow. This endpoint behaves differently for API and browser flows. API flows expect `application/json` to be sent in the body and responds with diff --git a/internal/httpclient/api_frontend.go b/internal/httpclient/api_frontend.go index 7afb4eeda28b..ac8cadd1a4b3 100644 --- a/internal/httpclient/api_frontend.go +++ b/internal/httpclient/api_frontend.go @@ -114,12 +114,6 @@ type FrontendApi interface { * This endpoint initializes a browser-based user registration flow. This endpoint will set the appropriate cookies and anti-CSRF measures required for browser-based flows. - :::info - - This endpoint is EXPERIMENTAL and subject to potential breaking changes in the future. - - ::: - If this endpoint is opened as a link in the browser, it will be redirected to `selfservice.flows.registration.ui_url` with the flow ID set as the query parameter `?flow=`. If a valid user session exists already, the browser will be redirected to `urls.default_redirect_url`. @@ -707,13 +701,7 @@ type FrontendApi interface { /* * UpdateLoginFlow Submit a Login Flow - * :::info - - This endpoint is EXPERIMENTAL and subject to potential breaking changes in the future. - - ::: - - Use this endpoint to complete a login flow. This endpoint + * Use this endpoint to complete a login flow. This endpoint behaves differently for API and browser flows. API flows expect `application/json` to be sent in the body and responds with @@ -1441,12 +1429,6 @@ func (r FrontendApiApiCreateBrowserRegistrationFlowRequest) Execute() (*Registra cookies and anti-CSRF measures required for browser-based flows. -:::info - -This endpoint is EXPERIMENTAL and subject to potential breaking changes in the future. - -::: - If this endpoint is opened as a link in the browser, it will be redirected to `selfservice.flows.registration.ui_url` with the flow ID set as the query parameter `?flow=`. If a valid user session exists already, the browser will be redirected to `urls.default_redirect_url`. @@ -4700,13 +4682,8 @@ func (r FrontendApiApiUpdateLoginFlowRequest) Execute() (*SuccessfulNativeLogin, /* - UpdateLoginFlow Submit a Login Flow - - :::info - -This endpoint is EXPERIMENTAL and subject to potential breaking changes in the future. - -::: + - Use this endpoint to complete a login flow. This endpoint -Use this endpoint to complete a login flow. This endpoint behaves differently for API and browser flows. API flows expect `application/json` to be sent in the body and responds with diff --git a/spec/api.json b/spec/api.json index ef4bf1ccd92d..b63ad4a5a91c 100755 --- a/spec/api.json +++ b/spec/api.json @@ -4668,7 +4668,7 @@ }, "/self-service/login": { "post": { - "description": ":::info\n\nThis endpoint is EXPERIMENTAL and subject to potential breaking changes in the future.\n\n:::\n\nUse this endpoint to complete a login flow. This endpoint\nbehaves differently for API and browser flows.\n\nAPI flows expect `application/json` to be sent in the body and responds with\nHTTP 200 and a application/json body with the session token on success;\nHTTP 410 if the original flow expired with the appropriate error messages set and optionally a `use_flow_id` parameter in the body;\nHTTP 400 on form validation errors.\n\nBrowser flows expect a Content-Type of `application/x-www-form-urlencoded` or `application/json` to be sent in the body and respond with\na HTTP 303 redirect to the post/after login URL or the `return_to` value if it was set and if the login succeeded;\na HTTP 303 redirect to the login UI URL with the flow ID containing the validation errors otherwise.\n\nBrowser flows with an accept header of `application/json` will not redirect but instead respond with\nHTTP 200 and a application/json body with the signed in identity and a `Set-Cookie` header on success;\nHTTP 303 redirect to a fresh login flow if the original flow expired with the appropriate error messages set;\nHTTP 400 on form validation errors.\n\nIf this endpoint is called with `Accept: application/json` in the header, 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`browser_location_change_required`: Usually sent when an AJAX request indicates that the browser needs to open a specific URL.\nMost likely used in Social Sign In flows.\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": "Use this endpoint to complete a login flow. This endpoint\nbehaves differently for API and browser flows.\n\nAPI flows expect `application/json` to be sent in the body and responds with\nHTTP 200 and a application/json body with the session token on success;\nHTTP 410 if the original flow expired with the appropriate error messages set and optionally a `use_flow_id` parameter in the body;\nHTTP 400 on form validation errors.\n\nBrowser flows expect a Content-Type of `application/x-www-form-urlencoded` or `application/json` to be sent in the body and respond with\na HTTP 303 redirect to the post/after login URL or the `return_to` value if it was set and if the login succeeded;\na HTTP 303 redirect to the login UI URL with the flow ID containing the validation errors otherwise.\n\nBrowser flows with an accept header of `application/json` will not redirect but instead respond with\nHTTP 200 and a application/json body with the signed in identity and a `Set-Cookie` header on success;\nHTTP 303 redirect to a fresh login flow if the original flow expired with the appropriate error messages set;\nHTTP 400 on form validation errors.\n\nIf this endpoint is called with `Accept: application/json` in the header, 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`browser_location_change_required`: Usually sent when an AJAX request indicates that the browser needs to open a specific URL.\nMost likely used in Social Sign In flows.\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": "updateLoginFlow", "parameters": [ { @@ -5634,7 +5634,7 @@ }, "/self-service/registration/browser": { "get": { - "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).", + "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\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": "createBrowserRegistrationFlow", "parameters": [ { diff --git a/spec/swagger.json b/spec/swagger.json index 74e4a00dc4ae..cad0b006024e 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -1353,7 +1353,7 @@ }, "/self-service/login": { "post": { - "description": ":::info\n\nThis endpoint is EXPERIMENTAL and subject to potential breaking changes in the future.\n\n:::\n\nUse this endpoint to complete a login flow. This endpoint\nbehaves differently for API and browser flows.\n\nAPI flows expect `application/json` to be sent in the body and responds with\nHTTP 200 and a application/json body with the session token on success;\nHTTP 410 if the original flow expired with the appropriate error messages set and optionally a `use_flow_id` parameter in the body;\nHTTP 400 on form validation errors.\n\nBrowser flows expect a Content-Type of `application/x-www-form-urlencoded` or `application/json` to be sent in the body and respond with\na HTTP 303 redirect to the post/after login URL or the `return_to` value if it was set and if the login succeeded;\na HTTP 303 redirect to the login UI URL with the flow ID containing the validation errors otherwise.\n\nBrowser flows with an accept header of `application/json` will not redirect but instead respond with\nHTTP 200 and a application/json body with the signed in identity and a `Set-Cookie` header on success;\nHTTP 303 redirect to a fresh login flow if the original flow expired with the appropriate error messages set;\nHTTP 400 on form validation errors.\n\nIf this endpoint is called with `Accept: application/json` in the header, 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`browser_location_change_required`: Usually sent when an AJAX request indicates that the browser needs to open a specific URL.\nMost likely used in Social Sign In flows.\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": "Use this endpoint to complete a login flow. This endpoint\nbehaves differently for API and browser flows.\n\nAPI flows expect `application/json` to be sent in the body and responds with\nHTTP 200 and a application/json body with the session token on success;\nHTTP 410 if the original flow expired with the appropriate error messages set and optionally a `use_flow_id` parameter in the body;\nHTTP 400 on form validation errors.\n\nBrowser flows expect a Content-Type of `application/x-www-form-urlencoded` or `application/json` to be sent in the body and respond with\na HTTP 303 redirect to the post/after login URL or the `return_to` value if it was set and if the login succeeded;\na HTTP 303 redirect to the login UI URL with the flow ID containing the validation errors otherwise.\n\nBrowser flows with an accept header of `application/json` will not redirect but instead respond with\nHTTP 200 and a application/json body with the signed in identity and a `Set-Cookie` header on success;\nHTTP 303 redirect to a fresh login flow if the original flow expired with the appropriate error messages set;\nHTTP 400 on form validation errors.\n\nIf this endpoint is called with `Accept: application/json` in the header, 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`browser_location_change_required`: Usually sent when an AJAX request indicates that the browser needs to open a specific URL.\nMost likely used in Social Sign In flows.\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).", "consumes": [ "application/json", "application/x-www-form-urlencoded" @@ -2149,7 +2149,7 @@ }, "/self-service/registration/browser": { "get": { - "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).", + "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\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).", "produces": [ "application/json" ], From 4eaf6c8d7b918e971dba58142bbdf316237fb9cd Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Tue, 1 Aug 2023 07:38:38 +0000 Subject: [PATCH 017/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 96 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 58 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5611cb0808c4..317a477fc06a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,13 +5,14 @@ **Table of Contents** -- [ (2023-07-24)](#2023-07-24) +- [ (2023-08-01)](#2023-08-01) - [Bug Fixes](#bug-fixes) + - [Documentation](#documentation) - [Features](#features) - [1.0.0 (2023-07-12)](#100-2023-07-12) - [Bug Fixes](#bug-fixes-1) - [Code Generation](#code-generation) - - [Documentation](#documentation) + - [Documentation](#documentation-1) - [Features](#features-1) - [Tests](#tests) - [Unclassified](#unclassified) @@ -20,7 +21,7 @@ - [Bug Fixes](#bug-fixes-2) - [Code Generation](#code-generation-1) - [Code Refactoring](#code-refactoring) - - [Documentation](#documentation-1) + - [Documentation](#documentation-2) - [Features](#features-2) - [Tests](#tests-1) - [Unclassified](#unclassified-1) @@ -28,7 +29,7 @@ - [Breaking Changes](#breaking-changes-1) - [Bug Fixes](#bug-fixes-3) - [Code Generation](#code-generation-2) - - [Documentation](#documentation-2) + - [Documentation](#documentation-3) - [Features](#features-3) - [Tests](#tests-2) - [0.11.0 (2022-12-02)](#0110-2022-12-02) @@ -36,7 +37,7 @@ - [Bug Fixes](#bug-fixes-4) - [Code Generation](#code-generation-3) - [Code Refactoring](#code-refactoring-1) - - [Documentation](#documentation-3) + - [Documentation](#documentation-4) - [Features](#features-4) - [Reverts](#reverts) - [Tests](#tests-3) @@ -49,7 +50,7 @@ - [Bug Fixes](#bug-fixes-6) - [Code Generation](#code-generation-5) - [Code Refactoring](#code-refactoring-2) - - [Documentation](#documentation-4) + - [Documentation](#documentation-5) - [Features](#features-5) - [Tests](#tests-4) - [Unclassified](#unclassified-3) @@ -57,7 +58,7 @@ - [Breaking Changes](#breaking-changes-4) - [Bug Fixes](#bug-fixes-7) - [Code Generation](#code-generation-6) - - [Documentation](#documentation-5) + - [Documentation](#documentation-6) - [0.9.0-alpha.2 (2022-03-22)](#090-alpha2-2022-03-22) - [Bug Fixes](#bug-fixes-8) - [Code Generation](#code-generation-7) @@ -66,7 +67,7 @@ - [Bug Fixes](#bug-fixes-9) - [Code Generation](#code-generation-8) - [Code Refactoring](#code-refactoring-3) - - [Documentation](#documentation-6) + - [Documentation](#documentation-7) - [Features](#features-6) - [Tests](#tests-5) - [Unclassified](#unclassified-4) @@ -75,24 +76,24 @@ - [Bug Fixes](#bug-fixes-10) - [Code Generation](#code-generation-9) - [Code Refactoring](#code-refactoring-4) - - [Documentation](#documentation-7) + - [Documentation](#documentation-8) - [Features](#features-7) - [Tests](#tests-6) - [0.8.2-alpha.1 (2021-12-17)](#082-alpha1-2021-12-17) - [Bug Fixes](#bug-fixes-11) - [Code Generation](#code-generation-10) - - [Documentation](#documentation-8) + - [Documentation](#documentation-9) - [0.8.1-alpha.1 (2021-12-13)](#081-alpha1-2021-12-13) - [Bug Fixes](#bug-fixes-12) - [Code Generation](#code-generation-11) - - [Documentation](#documentation-9) + - [Documentation](#documentation-10) - [Features](#features-8) - [Tests](#tests-7) - [0.8.0-alpha.4.pre.0 (2021-11-09)](#080-alpha4pre0-2021-11-09) - [Breaking Changes](#breaking-changes-7) - [Bug Fixes](#bug-fixes-13) - [Code Generation](#code-generation-12) - - [Documentation](#documentation-10) + - [Documentation](#documentation-11) - [Features](#features-9) - [Tests](#tests-8) - [0.8.0-alpha.3 (2021-10-28)](#080-alpha3-2021-10-28) @@ -105,7 +106,7 @@ - [Bug Fixes](#bug-fixes-15) - [Code Generation](#code-generation-15) - [Code Refactoring](#code-refactoring-5) - - [Documentation](#documentation-11) + - [Documentation](#documentation-12) - [Features](#features-10) - [Reverts](#reverts-1) - [Tests](#tests-9) @@ -117,25 +118,25 @@ - [0.7.4-alpha.1 (2021-09-09)](#074-alpha1-2021-09-09) - [Bug Fixes](#bug-fixes-16) - [Code Generation](#code-generation-18) - - [Documentation](#documentation-12) + - [Documentation](#documentation-13) - [Features](#features-11) - [Tests](#tests-10) - [0.7.3-alpha.1 (2021-08-28)](#073-alpha1-2021-08-28) - [Bug Fixes](#bug-fixes-17) - [Code Generation](#code-generation-19) - - [Documentation](#documentation-13) + - [Documentation](#documentation-14) - [Features](#features-12) - [0.7.1-alpha.1 (2021-07-22)](#071-alpha1-2021-07-22) - [Bug Fixes](#bug-fixes-18) - [Code Generation](#code-generation-20) - - [Documentation](#documentation-14) + - [Documentation](#documentation-15) - [Tests](#tests-11) - [0.7.0-alpha.1 (2021-07-13)](#070-alpha1-2021-07-13) - [Breaking Changes](#breaking-changes-9) - [Bug Fixes](#bug-fixes-19) - [Code Generation](#code-generation-21) - [Code Refactoring](#code-refactoring-6) - - [Documentation](#documentation-15) + - [Documentation](#documentation-16) - [Features](#features-13) - [Tests](#tests-12) - [Unclassified](#unclassified-6) @@ -146,7 +147,7 @@ - [Code Refactoring](#code-refactoring-7) - [0.6.2-alpha.1 (2021-05-14)](#062-alpha1-2021-05-14) - [Code Generation](#code-generation-23) - - [Documentation](#documentation-16) + - [Documentation](#documentation-17) - [0.6.1-alpha.1 (2021-05-11)](#061-alpha1-2021-05-11) - [Code Generation](#code-generation-24) - [Features](#features-14) @@ -159,14 +160,14 @@ - [Bug Fixes](#bug-fixes-22) - [Code Generation](#code-generation-26) - [Code Refactoring](#code-refactoring-8) - - [Documentation](#documentation-17) + - [Documentation](#documentation-18) - [Features](#features-16) - [Tests](#tests-13) - [Unclassified](#unclassified-7) - [0.5.5-alpha.1 (2020-12-09)](#055-alpha1-2020-12-09) - [Bug Fixes](#bug-fixes-23) - [Code Generation](#code-generation-27) - - [Documentation](#documentation-18) + - [Documentation](#documentation-19) - [Features](#features-17) - [Tests](#tests-14) - [Unclassified](#unclassified-8) @@ -174,23 +175,23 @@ - [Bug Fixes](#bug-fixes-24) - [Code Generation](#code-generation-28) - [Code Refactoring](#code-refactoring-9) - - [Documentation](#documentation-19) + - [Documentation](#documentation-20) - [Features](#features-18) - [0.5.3-alpha.1 (2020-10-27)](#053-alpha1-2020-10-27) - [Bug Fixes](#bug-fixes-25) - [Code Generation](#code-generation-29) - - [Documentation](#documentation-20) + - [Documentation](#documentation-21) - [Features](#features-19) - [Tests](#tests-15) - [0.5.2-alpha.1 (2020-10-22)](#052-alpha1-2020-10-22) - [Bug Fixes](#bug-fixes-26) - [Code Generation](#code-generation-30) - - [Documentation](#documentation-21) + - [Documentation](#documentation-22) - [Tests](#tests-16) - [0.5.1-alpha.1 (2020-10-20)](#051-alpha1-2020-10-20) - [Bug Fixes](#bug-fixes-27) - [Code Generation](#code-generation-31) - - [Documentation](#documentation-22) + - [Documentation](#documentation-23) - [Features](#features-20) - [Tests](#tests-17) - [Unclassified](#unclassified-9) @@ -199,7 +200,7 @@ - [Bug Fixes](#bug-fixes-28) - [Code Generation](#code-generation-32) - [Code Refactoring](#code-refactoring-10) - - [Documentation](#documentation-23) + - [Documentation](#documentation-24) - [Features](#features-21) - [Tests](#tests-18) - [Unclassified](#unclassified-10) @@ -212,7 +213,7 @@ - [0.4.4-alpha.1 (2020-07-10)](#044-alpha1-2020-07-10) - [Bug Fixes](#bug-fixes-31) - [Code Generation](#code-generation-35) - - [Documentation](#documentation-24) + - [Documentation](#documentation-25) - [0.4.3-alpha.1 (2020-07-08)](#043-alpha1-2020-07-08) - [Bug Fixes](#bug-fixes-32) - [Code Generation](#code-generation-36) @@ -224,7 +225,7 @@ - [Bug Fixes](#bug-fixes-34) - [Code Generation](#code-generation-38) - [Code Refactoring](#code-refactoring-11) - - [Documentation](#documentation-25) + - [Documentation](#documentation-26) - [Features](#features-22) - [Unclassified](#unclassified-11) - [0.3.0-alpha.1 (2020-05-15)](#030-alpha1-2020-05-15) @@ -232,44 +233,44 @@ - [Bug Fixes](#bug-fixes-35) - [Chores](#chores) - [Code Refactoring](#code-refactoring-12) - - [Documentation](#documentation-26) + - [Documentation](#documentation-27) - [Features](#features-23) - [Unclassified](#unclassified-12) - [0.2.1-alpha.1 (2020-05-05)](#021-alpha1-2020-05-05) - [Chores](#chores-1) - - [Documentation](#documentation-27) + - [Documentation](#documentation-28) - [0.2.0-alpha.2 (2020-05-04)](#020-alpha2-2020-05-04) - [Breaking Changes](#breaking-changes-15) - [Bug Fixes](#bug-fixes-36) - [Chores](#chores-2) - [Code Refactoring](#code-refactoring-13) - - [Documentation](#documentation-28) + - [Documentation](#documentation-29) - [Features](#features-24) - [Unclassified](#unclassified-13) - [0.1.1-alpha.1 (2020-02-18)](#011-alpha1-2020-02-18) - [Bug Fixes](#bug-fixes-37) - [Code Refactoring](#code-refactoring-14) - - [Documentation](#documentation-29) + - [Documentation](#documentation-30) - [0.1.0-alpha.6 (2020-02-16)](#010-alpha6-2020-02-16) - [Bug Fixes](#bug-fixes-38) - [Code Refactoring](#code-refactoring-15) - - [Documentation](#documentation-30) + - [Documentation](#documentation-31) - [Features](#features-25) - [0.1.0-alpha.5 (2020-02-06)](#010-alpha5-2020-02-06) - - [Documentation](#documentation-31) + - [Documentation](#documentation-32) - [Features](#features-26) - [0.1.0-alpha.4 (2020-02-06)](#010-alpha4-2020-02-06) - [Continuous Integration](#continuous-integration) - - [Documentation](#documentation-32) + - [Documentation](#documentation-33) - [0.1.0-alpha.3 (2020-02-06)](#010-alpha3-2020-02-06) - [Continuous Integration](#continuous-integration-1) - [0.1.0-alpha.2 (2020-02-03)](#010-alpha2-2020-02-03) - [Bug Fixes](#bug-fixes-39) - - [Documentation](#documentation-33) + - [Documentation](#documentation-34) - [Features](#features-27) - [Unclassified](#unclassified-14) - [0.1.0-alpha.1 (2020-01-31)](#010-alpha1-2020-01-31) - - [Documentation](#documentation-34) + - [Documentation](#documentation-35) - [0.0.3-alpha.15 (2020-01-31)](#003-alpha15-2020-01-31) - [Unclassified](#unclassified-15) - [0.0.3-alpha.14 (2020-01-31)](#003-alpha14-2020-01-31) @@ -302,12 +303,12 @@ - [Unclassified](#unclassified-26) - [0.0.1-alpha.3 (2020-01-28)](#001-alpha3-2020-01-28) - [Continuous Integration](#continuous-integration-6) - - [Documentation](#documentation-35) + - [Documentation](#documentation-36) - [Unclassified](#unclassified-27) -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-07-24) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-08-01) ### Bug Fixes @@ -318,9 +319,23 @@ Significantly improves performance by reducing the amount of queries we need to do when checking for the different AAL levels. +- Remove requirement for smtp section + ([#3405](https://github.com/ory/kratos/issues/3405)) + ([59a3f14](https://github.com/ory/kratos/commit/59a3f1469b8412e49846a500493cb02fc6eb34b1)) +- Return 400 bad request for invalid login challenge + ([#3404](https://github.com/ory/kratos/issues/3404)) + ([ca34e9b](https://github.com/ory/kratos/commit/ca34e9b744482b41d65082f3bed52e9c4ebd7ba4)) - Type-assert all interfaces that WebHook implements ([ffda1a0](https://github.com/ory/kratos/commit/ffda1a0dab661c5f11ad849b9287094313561b79)) +### Documentation + +- Remove experimental warnings + ([#3406](https://github.com/ory/kratos/issues/3406)) + ([d4d26e6](https://github.com/ory/kratos/commit/d4d26e6e1510c8e09346e95251f420f95ec54998)): + + See https://github.com/ory/kratos/discussions/3388 + ### Features - Add OpenTelemetry span for password hash comparison @@ -328,6 +343,11 @@ ([e3fcf0c](https://github.com/ory/kratos/commit/e3fcf0c31db9742ed61bcf783e37ee119ed19d42)) - Allow extra migrations in NewPersister ([96c1ff7](https://github.com/ory/kratos/commit/96c1ff7747ea38e23a3892f74b75ee555ed49c88)) +- Support multiple origins for WebAuthN + ([#3380](https://github.com/ory/kratos/issues/3380)) + ([013f335](https://github.com/ory/kratos/commit/013f335881831bbf90ac31b219b57118fc089fe6)): + + Users can now supply a list of origins for webauthn in the configuration. # [1.0.0](https://github.com/ory/kratos/compare/v0.13.0...v1.0.0) (2023-07-12) From 88237e25b080a9643f6cbf7eedbf23988ba9ba7c Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Tue, 1 Aug 2023 09:43:48 +0200 Subject: [PATCH 018/282] fix: accept all 200 responses as OK in courier (#3401) * fix: accept all 200 responses as OK in courier Closes #3399 * chore: synchronize workspaces --- courier/http.go | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/courier/http.go b/courier/http.go index 32e032c5858c..1e70803b9cff 100644 --- a/courier/http.go +++ b/courier/http.go @@ -7,7 +7,6 @@ import ( "context" "encoding/json" "fmt" - "net/http" "github.com/ory/kratos/request" "github.com/ory/x/otelx" @@ -64,30 +63,26 @@ func (c *courier) dispatchMailerEmail(ctx context.Context, msg Message) (err err defer res.Body.Close() - switch res.StatusCode { - case http.StatusOK: - case http.StatusCreated: - default: - err = fmt.Errorf( - "unable to dispatch mail delivery because upstream server replied with status code %d", - res.StatusCode, - ) + if res.StatusCode >= 200 && res.StatusCode < 300 { c.deps.Logger(). WithField("message_id", msg.ID). WithField("message_type", msg.Type). WithField("message_template_type", msg.TemplateType). WithField("message_subject", msg.Subject). - WithError(err). - Error("sending mail via HTTP failed.") - return err + Debug("Courier sent out mailer.") + return nil } + err = fmt.Errorf( + "unable to dispatch mail delivery because upstream server replied with status code %d", + res.StatusCode, + ) c.deps.Logger(). WithField("message_id", msg.ID). WithField("message_type", msg.Type). WithField("message_template_type", msg.TemplateType). WithField("message_subject", msg.Subject). - Debug("Courier sent out mailer.") - - return nil + WithError(err). + Error("sending mail via HTTP failed.") + return err } From 60e9a363c501bcf185dc7fd27e03bcffd5c601cb Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Tue, 1 Aug 2023 09:08:13 +0000 Subject: [PATCH 019/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 317a477fc06a..4baa4cab155d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -312,6 +312,13 @@ ### Bug Fixes +- Accept all 200 responses as OK in courier + ([#3401](https://github.com/ory/kratos/issues/3401)) + ([88237e2](https://github.com/ory/kratos/commit/88237e25b080a9643f6cbf7eedbf23988ba9ba7c)), + closes [#3399](https://github.com/ory/kratos/issues/3399): + + - fix: accept all 200 responses as OK in courier + - Reduce db lookups in whoami for aal check ([#3372](https://github.com/ory/kratos/issues/3372)) ([d814a48](https://github.com/ory/kratos/commit/d814a4864d5c25c4f320daca733873577d517331)): From cd9e6a0e1e4cb4957d2a50ae3d288ebb0591e42d Mon Sep 17 00:00:00 2001 From: Henning Perl Date: Wed, 2 Aug 2023 10:18:52 +0200 Subject: [PATCH 020/282] fix: redirect to verification URL even if login_challenge is set (#3412) Fixes https://github.com/ory/network/issues/320 --- identity/credentials.go | 14 +++- selfservice/flow/login/hook_test.go | 8 +-- selfservice/flow/registration/hook.go | 18 ++++- selfservice/flow/registration/hook_test.go | 80 +++++++++++++++++----- selfservice/hook/show_verification_ui.go | 8 +-- 5 files changed, 94 insertions(+), 34 deletions(-) diff --git a/identity/credentials.go b/identity/credentials.go index 99b04db3031b..1d33440389a0 100644 --- a/identity/credentials.go +++ b/identity/credentials.go @@ -108,6 +108,14 @@ const ( CredentialsTypeWebAuthn CredentialsType = "webauthn" ) +var AllCredentialTypes = []CredentialsType{ + CredentialsTypePassword, + CredentialsTypeOIDC, + CredentialsTypeTOTP, + CredentialsTypeLookup, + CredentialsTypeWebAuthn, +} + const ( // CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). // It is not used within the credentials object itself. @@ -163,7 +171,7 @@ type Credentials struct { NID uuid.UUID `json:"-" faker:"-" db:"nid"` } -func (c Credentials) TableName(ctx context.Context) string { +func (c Credentials) TableName(context.Context) string { return "identity_credentials" } @@ -202,11 +210,11 @@ type ( } ) -func (c CredentialsTypeTable) TableName(ctx context.Context) string { +func (c CredentialsTypeTable) TableName(context.Context) string { return "identity_credential_types" } -func (c CredentialIdentifier) TableName(ctx context.Context) string { +func (c CredentialIdentifier) TableName(context.Context) string { return "identity_credential_identifiers" } diff --git a/selfservice/flow/login/hook_test.go b/selfservice/flow/login/hook_test.go index cfffc34701f0..52e66a45ab62 100644 --- a/selfservice/flow/login/hook_test.go +++ b/selfservice/flow/login/hook_test.go @@ -33,13 +33,7 @@ func TestLoginExecutor(t *testing.T) { t.Parallel() ctx := context.Background() - for _, strategy := range []identity.CredentialsType{ - identity.CredentialsTypePassword, - identity.CredentialsTypeOIDC, - identity.CredentialsTypeTOTP, - identity.CredentialsTypeWebAuthn, - identity.CredentialsTypeLookup, - } { + for _, strategy := range identity.AllCredentialTypes { strategy := strategy t.Run("strategy="+strategy.String(), func(t *testing.T) { diff --git a/selfservice/flow/registration/hook.go b/selfservice/flow/registration/hook.go index 78f9eb19fb3f..8fb2604be551 100644 --- a/selfservice/flow/registration/hook.go +++ b/selfservice/flow/registration/hook.go @@ -7,6 +7,7 @@ import ( "context" "fmt" "net/http" + "net/url" "time" "go.opentelemetry.io/otel/trace" @@ -248,11 +249,24 @@ func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Reque finalReturnTo := returnTo.String() if a.OAuth2LoginChallenge != "" { - cr, err := e.d.Hydra().AcceptLoginRequest(r.Context(), string(a.OAuth2LoginChallenge), i.ID.String(), s.AMR) + callbackURL, err := e.d.Hydra().AcceptLoginRequest(r.Context(), string(a.OAuth2LoginChallenge), i.ID.String(), s.AMR) if err != nil { return err } - finalReturnTo = cr + if a.ReturnToVerification != "" { + // Special case: If Kratos is used as a login UI *and* we want to show the verification UI, + // redirect to the verification URL first and then return to Hydra. + verificationURL, err := url.Parse(a.ReturnToVerification) + if err != nil { + return err + } + q := verificationURL.Query() + q.Set("return_to", callbackURL) + verificationURL.RawQuery = q.Encode() + finalReturnTo = verificationURL.String() + } else { + finalReturnTo = callbackURL + } } else if a.ReturnToVerification != "" { finalReturnTo = a.ReturnToVerification } diff --git a/selfservice/flow/registration/hook_test.go b/selfservice/flow/registration/hook_test.go index 49719a7f10c0..a0a4bf1508b0 100644 --- a/selfservice/flow/registration/hook_test.go +++ b/selfservice/flow/registration/hook_test.go @@ -17,6 +17,7 @@ import ( "github.com/tidwall/gjson" "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" @@ -27,20 +28,23 @@ import ( ) func TestRegistrationExecutor(t *testing.T) { + t.Parallel() ctx := context.Background() - for _, strategy := range []string{ - identity.CredentialsTypePassword.String(), - identity.CredentialsTypeOIDC.String(), - identity.CredentialsTypeTOTP.String(), - identity.CredentialsTypeWebAuthn.String(), - } { + + for _, strategy := range identity.AllCredentialTypes { + strategy := strategy.String() + t.Run("strategy="+strategy, func(t *testing.T) { + t.Parallel() + conf, reg := internal.NewFastRegistryWithMocks(t) + reg.WithHydra(hydra.NewFake()) testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/registration.schema.json") conf.MustSet(ctx, config.ViperKeySelfServiceBrowserDefaultReturnTo, "https://www.ory.sh/") - newServer := func(t *testing.T, i *identity.Identity, ft flow.Type) *httptest.Server { + newServer := func(t *testing.T, i *identity.Identity, ft flow.Type, flowCallbacks ...func(*registration.Flow)) *httptest.Server { router := httprouter.New() + handleErr := testhelpers.SelfServiceHookRegistrationErrorHandler router.GET("/registration/pre", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { f, err := registration.NewFlow(conf, time.Minute, x.FakeCSRFToken, r, ft) @@ -54,10 +58,13 @@ func TestRegistrationExecutor(t *testing.T) { if i == nil { i = testhelpers.SelfServiceHookFakeIdentity(t) } - a, err := registration.NewFlow(conf, time.Minute, x.FakeCSRFToken, r, ft) + regFlow, err := registration.NewFlow(conf, time.Minute, x.FakeCSRFToken, r, ft) require.NoError(t, err) - a.RequestURL = x.RequestURL(r).String() - _ = handleErr(t, w, r, reg.RegistrationHookExecutor().PostRegistrationHook(w, r, identity.CredentialsType(strategy), "", a, i)) + regFlow.RequestURL = x.RequestURL(r).String() + for _, callback := range flowCallbacks { + callback(regFlow) + } + _ = handleErr(t, w, r, reg.RegistrationHookExecutor().PostRegistrationHook(w, r, identity.CredentialsType(strategy), "", regFlow, i)) }) ts := httptest.NewServer(router) @@ -161,11 +168,11 @@ func TestRegistrationExecutor(t *testing.T) { assert.Empty(t, gjson.Get(body, "session_token")) }) - t.Run("case=should redirect to verification ui if show_verification_ui hook is set", func(t *testing.T) { + t.Run("case=should redirect to verification UI if show_verification_ui hook is set", func(t *testing.T) { verificationTS := testhelpers.NewVerificationUIFlowEchoServer(t, reg) t.Cleanup(testhelpers.SelfServiceHookConfigReset(t, conf)) - conf.Set(ctx, config.ViperKeySelfServiceVerificationEnabled, true) - conf.Set(ctx, config.ViperKeySelfServiceRegistrationAfter+".hooks", []map[string]interface{}{ + conf.MustSet(ctx, config.ViperKeySelfServiceVerificationEnabled, true) + conf.MustSet(ctx, config.ViperKeySelfServiceRegistrationAfter+".hooks", []map[string]interface{}{ { "hook": hook.KeyVerificationUI, }, @@ -179,11 +186,48 @@ func TestRegistrationExecutor(t *testing.T) { assert.NotEmpty(t, res.Request.URL.Query().Get("flow")) }) - t.Run("case=should redirect to first verification ui if show_verification_ui hook is set and multiple verifiable addresses", func(t *testing.T) { + t.Run("case=should redirect to verification UI if there is a login_challenge", func(t *testing.T) { + verificationTS := testhelpers.NewVerificationUIFlowEchoServer(t, reg) + t.Cleanup(testhelpers.SelfServiceHookConfigReset(t, conf)) + conf.MustSet(ctx, config.ViperKeySelfServiceVerificationEnabled, true) + conf.MustSet(ctx, config.ViperKeySelfServiceRegistrationAfter+".hooks", []map[string]interface{}{{ + "hook": hook.KeyVerificationUI, + }}) + i := testhelpers.SelfServiceHookFakeIdentity(t) + i.Traits = identity.Traits(`{"email": "verifiable-valid-login_challenge@ory.sh"}`) + + withOAuthChallenge := func(f *registration.Flow) { + f.OAuth2LoginChallenge = hydra.FakeValidLoginChallenge + } + res, _ := makeRequestPost(t, newServer(t, i, flow.TypeBrowser, withOAuthChallenge), false, url.Values{}) + assert.EqualValues(t, http.StatusOK, res.StatusCode) + assert.Contains(t, res.Request.URL.String(), verificationTS.URL) + assert.NotEmpty(t, res.Request.URL.Query().Get("flow")) + assert.Equal(t, hydra.FakePostLoginURL, res.Request.URL.Query().Get("return_to")) + }) + + t.Run("case=should not redirect to verification UI if the login_challenge is invalid", func(t *testing.T) { + t.Cleanup(testhelpers.SelfServiceHookConfigReset(t, conf)) + conf.MustSet(ctx, config.ViperKeySelfServiceVerificationEnabled, true) + conf.MustSet(ctx, config.ViperKeySelfServiceRegistrationAfter+".hooks", []map[string]interface{}{{ + "hook": hook.KeyVerificationUI, + }}) + i := testhelpers.SelfServiceHookFakeIdentity(t) + i.Traits = identity.Traits(`{"email": "verifiable-invalid-login_challenge@ory.sh"}`) + + withOAuthChallenge := func(f *registration.Flow) { + f.OAuth2LoginChallenge = hydra.FakeInvalidLoginChallenge + } + res, body := makeRequestPost(t, newServer(t, i, flow.TypeBrowser, withOAuthChallenge), false, url.Values{}) + assert.EqualValues(t, http.StatusInternalServerError, res.StatusCode) + assert.Equal(t, hydra.ErrFakeAcceptLoginRequestFailed.Error(), body, "%s", body) + }) + + t.Run("case=should redirect to first verification UI if show_verification_ui hook is set and multiple verifiable addresses", func(t *testing.T) { verificationTS := testhelpers.NewVerificationUIFlowEchoServer(t, reg) t.Cleanup(testhelpers.SelfServiceHookConfigReset(t, conf)) - conf.Set(ctx, config.ViperKeySelfServiceVerificationEnabled, true) - conf.Set(ctx, config.ViperKeySelfServiceRegistrationAfter+".hooks", []map[string]interface{}{ + conf.MustSet(ctx, config.ViperKeySelfServiceVerificationEnabled, true) + conf.MustSet(ctx, config.ViperKeySelfServiceRegistrationAfter+".hooks", []map[string]interface{}{ { "hook": hook.KeyVerificationUI, }, @@ -202,8 +246,8 @@ func TestRegistrationExecutor(t *testing.T) { t.Run("case=should still sent session if show_verification_ui is set after session hook", func(t *testing.T) { verificationTS := testhelpers.NewVerificationUIFlowEchoServer(t, reg) t.Cleanup(testhelpers.SelfServiceHookConfigReset(t, conf)) - conf.Set(ctx, config.ViperKeySelfServiceVerificationEnabled, true) - conf.Set(ctx, config.ViperKeySelfServiceRegistrationAfter+".hooks", []map[string]interface{}{ + conf.MustSet(ctx, config.ViperKeySelfServiceVerificationEnabled, true) + conf.MustSet(ctx, config.ViperKeySelfServiceRegistrationAfter+".hooks", []map[string]interface{}{ { "hook": hook.KeyVerificationUI, }, diff --git a/selfservice/hook/show_verification_ui.go b/selfservice/hook/show_verification_ui.go index 28df6e012b42..d9ea9b54ee01 100644 --- a/selfservice/hook/show_verification_ui.go +++ b/selfservice/hook/show_verification_ui.go @@ -16,7 +16,7 @@ import ( ) var ( - _ registration.PostHookPostPersistExecutor = new(SessionIssuer) + _ registration.PostHookPostPersistExecutor = new(ShowVerificationUIHook) ) type ( @@ -41,13 +41,13 @@ func NewShowVerificationUIHook(d showVerificationUIDependencies) *ShowVerificati // ExecutePostRegistrationPostPersistHook adds redirect headers and status code if the request is a browser request. // If the request is not a browser request, this hook does nothing. -func (e *ShowVerificationUIHook) ExecutePostRegistrationPostPersistHook(w http.ResponseWriter, r *http.Request, f *registration.Flow, s *session.Session) error { +func (e *ShowVerificationUIHook) ExecutePostRegistrationPostPersistHook(_ http.ResponseWriter, r *http.Request, f *registration.Flow, _ *session.Session) error { return otelx.WithSpan(r.Context(), "selfservice.hook.SessionIssuer.ExecutePostRegistrationPostPersistHook", func(ctx context.Context) error { - return e.execute(w, r.WithContext(ctx), f, s) + return e.execute(r.WithContext(ctx), f) }) } -func (e *ShowVerificationUIHook) execute(w http.ResponseWriter, r *http.Request, f *registration.Flow, s *session.Session) error { +func (e *ShowVerificationUIHook) execute(r *http.Request, f *registration.Flow) error { if !x.IsBrowserRequest(r) { // this hook is only intended to be used by browsers, as it redirects to the verification ui // JSON API clients should use the `continue_with` field to continue the flow From 3a07af4d4ffd8372139bd6e1a3063088244e8bd6 Mon Sep 17 00:00:00 2001 From: aeneasr <3372410+aeneasr@users.noreply.github.com> Date: Thu, 3 Aug 2023 15:37:02 +0000 Subject: [PATCH 021/282] chore: update repository templates to https://github.com/ory/meta/commit/af28aff50b62a9eeb69de4842e0e164f82c9e066 --- .github/ISSUE_TEMPLATE/BUG-REPORT.yml | 21 +++---- .github/ISSUE_TEMPLATE/DESIGN-DOC.yml | 21 +++---- .github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml | 27 +++----- .github/ISSUE_TEMPLATE/config.yml | 6 +- CODE_OF_CONDUCT.md | 10 +++ README.md | 72 ++++++++++++++-------- 6 files changed, 80 insertions(+), 77 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/BUG-REPORT.yml b/.github/ISSUE_TEMPLATE/BUG-REPORT.yml index 1170b41b5c4a..8a1d8abef7b7 100644 --- a/.github/ISSUE_TEMPLATE/BUG-REPORT.yml +++ b/.github/ISSUE_TEMPLATE/BUG-REPORT.yml @@ -12,24 +12,18 @@ body: - attributes: label: "Preflight checklist" options: - - label: - "I could not find a solution in the existing issues, docs, nor + - label: "I could not find a solution in the existing issues, docs, nor discussions." required: true - - label: - "I agree to follow this project's [Code of + - label: "I agree to follow this project's [Code of Conduct](https://github.com/ory/kratos/blob/master/CODE_OF_CONDUCT.md)." required: true - - label: - "I have read and am following this repository's [Contribution + - label: "I have read and am following this repository's [Contribution Guidelines](https://github.com/ory/kratos/blob/master/CONTRIBUTING.md)." required: true - - label: - "This issue affects my [Ory Network](https://www.ory.sh/) project." - - label: - "I have joined the [Ory Community Slack](https://slack.ory.sh)." - - label: - "I am signed up to the [Ory Security Patch + - label: "This issue affects my [Ory Network](https://www.ory.sh/) project." + - label: "I have joined the [Ory Community Slack](https://slack.ory.sh)." + - label: "I am signed up to the [Ory Security Patch Newsletter](https://ory.us10.list-manage.com/subscribe?u=ffb1a878e4ec6c0ed312a3480&id=f605a41b53)." id: checklist type: checkboxes @@ -56,8 +50,7 @@ body: validations: required: true - attributes: - description: - "Please copy and paste any relevant log output. This will be + description: "Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. Please redact any sensitive information" label: "Relevant log output" diff --git a/.github/ISSUE_TEMPLATE/DESIGN-DOC.yml b/.github/ISSUE_TEMPLATE/DESIGN-DOC.yml index f817f4164efe..1bfbdbacdae4 100644 --- a/.github/ISSUE_TEMPLATE/DESIGN-DOC.yml +++ b/.github/ISSUE_TEMPLATE/DESIGN-DOC.yml @@ -1,8 +1,7 @@ # AUTO-GENERATED, DO NOT EDIT! # Please edit the original at https://github.com/ory/meta/blob/master/templates/repository/common/.github/ISSUE_TEMPLATE/DESIGN-DOC.yml -description: - "A design document is needed for non-trivial changes to the code base." +description: "A design document is needed for non-trivial changes to the code base." labels: - rfc name: "Design Document" @@ -23,24 +22,18 @@ body: - attributes: label: "Preflight checklist" options: - - label: - "I could not find a solution in the existing issues, docs, nor + - label: "I could not find a solution in the existing issues, docs, nor discussions." required: true - - label: - "I agree to follow this project's [Code of + - label: "I agree to follow this project's [Code of Conduct](https://github.com/ory/kratos/blob/master/CODE_OF_CONDUCT.md)." required: true - - label: - "I have read and am following this repository's [Contribution + - label: "I have read and am following this repository's [Contribution Guidelines](https://github.com/ory/kratos/blob/master/CONTRIBUTING.md)." required: true - - label: - "This issue affects my [Ory Network](https://www.ory.sh/) project." - - label: - "I have joined the [Ory Community Slack](https://slack.ory.sh)." - - label: - "I am signed up to the [Ory Security Patch + - label: "This issue affects my [Ory Network](https://www.ory.sh/) project." + - label: "I have joined the [Ory Community Slack](https://slack.ory.sh)." + - label: "I am signed up to the [Ory Security Patch Newsletter](https://ory.us10.list-manage.com/subscribe?u=ffb1a878e4ec6c0ed312a3480&id=f605a41b53)." id: checklist type: checkboxes diff --git a/.github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml b/.github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml index 0c3112cfc7d6..4f2349ab8a58 100644 --- a/.github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml +++ b/.github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml @@ -1,8 +1,7 @@ # AUTO-GENERATED, DO NOT EDIT! # Please edit the original at https://github.com/ory/meta/blob/master/templates/repository/common/.github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml -description: - "Suggest an idea for this project without a plan for implementation" +description: "Suggest an idea for this project without a plan for implementation" labels: - feat name: "Feature Request" @@ -16,30 +15,23 @@ body: - attributes: label: "Preflight checklist" options: - - label: - "I could not find a solution in the existing issues, docs, nor + - label: "I could not find a solution in the existing issues, docs, nor discussions." required: true - - label: - "I agree to follow this project's [Code of + - label: "I agree to follow this project's [Code of Conduct](https://github.com/ory/kratos/blob/master/CODE_OF_CONDUCT.md)." required: true - - label: - "I have read and am following this repository's [Contribution + - label: "I have read and am following this repository's [Contribution Guidelines](https://github.com/ory/kratos/blob/master/CONTRIBUTING.md)." required: true - - label: - "This issue affects my [Ory Network](https://www.ory.sh/) project." - - label: - "I have joined the [Ory Community Slack](https://slack.ory.sh)." - - label: - "I am signed up to the [Ory Security Patch + - label: "This issue affects my [Ory Network](https://www.ory.sh/) project." + - label: "I have joined the [Ory Community Slack](https://slack.ory.sh)." + - label: "I am signed up to the [Ory Security Patch Newsletter](https://ory.us10.list-manage.com/subscribe?u=ffb1a878e4ec6c0ed312a3480&id=f605a41b53)." id: checklist type: checkboxes - attributes: - description: - "Is your feature request related to a problem? Please describe." + description: "Is your feature request related to a problem? Please describe." label: "Describe your problem" placeholder: "A clear and concise description of what the problem is. Ex. I'm always @@ -73,8 +65,7 @@ body: validations: required: true - attributes: - description: - "Add any other context or screenshots about the feature request here." + description: "Add any other context or screenshots about the feature request here." label: Additional Context id: additional type: textarea diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index abb0b696c9d9..ef4c482ae405 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -5,10 +5,8 @@ blank_issues_enabled: false contact_links: - name: Ory Kratos Forum url: https://github.com/ory/kratos/discussions - about: - Please ask and answer questions here, show your implementations and + about: Please ask and answer questions here, show your implementations and discuss ideas. - name: Ory Chat url: https://www.ory.sh/chat - about: - Hang out with other Ory community members to ask and answer questions. + about: Hang out with other Ory community members to ask and answer questions. diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 4861c9d1844a..9cebaf358e33 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -39,6 +39,16 @@ Examples of unacceptable behavior include: - Other conduct which could reasonably be considered inappropriate in a professional setting +## Open Source Community Support + +Ory Open source software is collaborative and based on contributions by +developers in the Ory community. There is no obligation from Ory to help with +individual problems. If Ory open source software is used in production in a +for-profit company or enterprise environment, we mandate a paid support contract +where Ory is obligated under their service level agreements (SLAs) to offer a +defined level of availability and responsibility. For more information about +paid support please contact us at sales@ory.sh. + ## Enforcement Responsibilities Community leaders are responsible for clarifying and enforcing our standards of diff --git a/README.md b/README.md index 0382c90f7ff2..5245196408d2 100644 --- a/README.md +++ b/README.md @@ -58,9 +58,13 @@ today! ## Ory Network Hybrid Support Plan -Ory offers a support plan for Ory Network Hybrid, including Ory on private cloud deployments. If you have a self-hosted solution and would like help, consider a support plan! -The team at Ory has years of experience in cloud computing. Ory's offering is the only official program for qualified support from the maintainers. -For more information see the **[website](https://www.ory.sh/support/)** or **[book a meeting](https://www.ory.sh/contact/)**! +Ory offers a support plan for Ory Network Hybrid, including Ory on private cloud +deployments. If you have a self-hosted solution and would like help, consider a +support plan! +The team at Ory has years of experience in cloud computing. Ory's offering is +the only official program for qualified support from the maintainers. +For more information see the **[website](https://www.ory.sh/support/)** or +**[book a meeting](https://www.ory.sh/contact/)**! ### Quickstart @@ -152,16 +156,17 @@ products. The Ory community stands on the shoulders of individuals, companies, and -maintainers. We thank everyone involved - from submitting bug reports and -feature requests, to contributing patches, to sponsoring our work. Our community -is 1000+ strong and growing rapidly. The Ory stack protects 16.000.000.000+ API -requests every month with over 250.000+ active service nodes. We would have -never been able to achieve this without each and everyone of you! +maintainers. The Ory team thanks everyone involved - from submitting bug reports +and feature requests, to contributing patches and documentation. The Ory +community counts more than 33.000 members and is growing rapidly. The Ory stack +protects 60.000.000.000+ API requests every month with over 400.000+ active +service nodes. None of this would have been possible without each and everyone +of you! The following list represents companies that have accompanied us along the way and that have made outstanding contributions to our ecosystem. _If you think that your company deserves a spot here, reach out to -office-muc@ory.sh now_! +office@ory.sh now_! @@ -174,7 +179,7 @@ that your company deserves a spot here, reach out to - + - + - + - + - + - + - + - + + + + + + + + + + + + +
SponsorAdopter * Raspberry PI Foundation @@ -185,7 +190,7 @@ that your company deserves a spot here, reach out to raspberrypi.org
ContributorAdopter * Kyma Project @@ -196,7 +201,7 @@ that your company deserves a spot here, reach out to kyma-project.io
SponsorAdopter * Tulip @@ -207,7 +212,7 @@ that your company deserves a spot here, reach out to tulip.com
SponsorAdopter * Cashdeck / All My Funds @@ -218,7 +223,7 @@ that your company deserves a spot here, reach out to cashdeck.com.au
ContributorAdopter * Hootsuite @@ -361,7 +366,7 @@ that your company deserves a spot here, reach out to nortal.com
SponsorAdopter * OrderMyGear @@ -372,7 +377,7 @@ that your company deserves a spot here, reach out to ordermygear.com
SponsorAdopter * Spiri.bo @@ -383,7 +388,7 @@ that your company deserves a spot here, reach out to spiri.bo
SponsorAdopter * Strivacity @@ -539,22 +544,35 @@ that your company deserves a spot here, reach out to amplitude.com
Adopter *Pinniped + + + pinniped.dev + + pinniped.dev
Adopter *Pvotal + + + pvotal.tech + + pvotal.tech
-We also want to thank all individual contributors +Many thanks to all individual contributors -as well as all of our backers - - - -and past & current supporters (in alphabetical order) on -[Patreon](https://www.patreon.com/_ory): Alexander Alimovs, Billy, Chancy -Kennedy, Drozzy, Edwin Trejos, Howard Edidin, Ken Adler Oz Haven, Stefan Hans, -TheCrealm. - \* Uses one of Ory's major projects in production. From c348c12ab3c9cdb4ce8159fe774ed179ff6a4d8a Mon Sep 17 00:00:00 2001 From: Alano Terblanche <18033717+Benehiko@users.noreply.github.com> Date: Mon, 7 Aug 2023 15:10:55 +0200 Subject: [PATCH 022/282] test(e2e): logout return_to (#3418) --- test/e2e/cypress/helpers/express.ts | 1 + .../profiles/email/logout/success.spec.ts | 49 ++++++++++++++++++- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/test/e2e/cypress/helpers/express.ts b/test/e2e/cypress/helpers/express.ts index 60ead1bd13e9..138cf433fc5b 100644 --- a/test/e2e/cypress/helpers/express.ts +++ b/test/e2e/cypress/helpers/express.ts @@ -10,4 +10,5 @@ export const routes = { settings: APP_URL + "/settings", recovery: APP_URL + "/recovery", verification: APP_URL + "/verification", + welcome: APP_URL + "/welcome", } diff --git a/test/e2e/cypress/integration/profiles/email/logout/success.spec.ts b/test/e2e/cypress/integration/profiles/email/logout/success.spec.ts index ca965c2d0c25..f13358166afb 100644 --- a/test/e2e/cypress/integration/profiles/email/logout/success.spec.ts +++ b/test/e2e/cypress/integration/profiles/email/logout/success.spec.ts @@ -12,14 +12,16 @@ context("Testing logout flows", () => { app: "express" as "express", profile: "email", settings: express.settings, + welcome: express.welcome, }, { route: react.login, app: "react" as "react", profile: "spa", settings: react.settings, + welcome: "", }, - ].forEach(({ route, profile, app, settings }) => { + ].forEach(({ route, profile, app, settings, welcome }) => { describe(`for app ${app}`, () => { let email: string let password: string @@ -61,6 +63,45 @@ context("Testing logout flows", () => { cy.url().should("include", "/login") }) + it("should be able to sign out on settings page", () => { + if (app === "react") { + return + } + cy.sessionRequiresNo2fa() + cy.useLaxAal() + + cy.getSession({ expectAal: "aal1" }) + cy.getCookie("ory_kratos_session").should("not.be.null") + + cy.visit(settings, { + qs: { + return_to: "https://www.ory.sh", + }, + }) + + cy.get("a[href*='logout']").click() + cy.location("host").should("eq", "www.ory.sh") + }) + + it("should be able to sign out on welcome page", () => { + if (app === "react") { + return + } + cy.sessionRequiresNo2fa() + cy.useLaxAal() + + cy.getSession({ expectAal: "aal1" }) + + cy.visit(welcome, { + qs: { + return_to: "https://www.ory.sh", + }, + }) + + cy.get("a[href*='logout']").click() + cy.location("host").should("eq", "www.ory.sh") + }) + it("should be able to sign out at 2fa page", () => { if (app === "react") { return @@ -79,7 +120,11 @@ context("Testing logout flows", () => { cy.expectSettingsSaved() cy.logout() - cy.visit(route + "?return_to=https://www.ory.sh") + cy.visit(route, { + qs: { + return_to: "https://www.ory.sh", + }, + }) cy.get('[name="identifier"]').clear().type(email) From c749052911946ef8d811d18a3ba9fded3417d0e2 Mon Sep 17 00:00:00 2001 From: aeneasr <3372410+aeneasr@users.noreply.github.com> Date: Mon, 7 Aug 2023 14:27:57 +0000 Subject: [PATCH 023/282] chore: update repository templates to https://github.com/ory/meta/commit/ac80097fa427e7ae39820c59cac62dc6e11b9aff --- .github/ISSUE_TEMPLATE/BUG-REPORT.yml | 7 ++++++- .github/ISSUE_TEMPLATE/DESIGN-DOC.yml | 7 ++++++- .github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml | 7 ++++++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/BUG-REPORT.yml b/.github/ISSUE_TEMPLATE/BUG-REPORT.yml index 8a1d8abef7b7..b40a9c1be15d 100644 --- a/.github/ISSUE_TEMPLATE/BUG-REPORT.yml +++ b/.github/ISSUE_TEMPLATE/BUG-REPORT.yml @@ -21,12 +21,17 @@ body: - label: "I have read and am following this repository's [Contribution Guidelines](https://github.com/ory/kratos/blob/master/CONTRIBUTING.md)." required: true - - label: "This issue affects my [Ory Network](https://www.ory.sh/) project." - label: "I have joined the [Ory Community Slack](https://slack.ory.sh)." - label: "I am signed up to the [Ory Security Patch Newsletter](https://ory.us10.list-manage.com/subscribe?u=ffb1a878e4ec6c0ed312a3480&id=f605a41b53)." id: checklist type: checkboxes + - attributes: + description: "Enter the slug or API URL of the affected Ory Network project. Leave empty when you are self-hosting." + label: "Ory Network Project" + placeholder: "https://.projects.oryapis.com" + id: ory-network-project + type: input - attributes: description: "A clear and concise description of what the bug is." label: "Describe the bug" diff --git a/.github/ISSUE_TEMPLATE/DESIGN-DOC.yml b/.github/ISSUE_TEMPLATE/DESIGN-DOC.yml index 1bfbdbacdae4..36bf7935a008 100644 --- a/.github/ISSUE_TEMPLATE/DESIGN-DOC.yml +++ b/.github/ISSUE_TEMPLATE/DESIGN-DOC.yml @@ -31,12 +31,17 @@ body: - label: "I have read and am following this repository's [Contribution Guidelines](https://github.com/ory/kratos/blob/master/CONTRIBUTING.md)." required: true - - label: "This issue affects my [Ory Network](https://www.ory.sh/) project." - label: "I have joined the [Ory Community Slack](https://slack.ory.sh)." - label: "I am signed up to the [Ory Security Patch Newsletter](https://ory.us10.list-manage.com/subscribe?u=ffb1a878e4ec6c0ed312a3480&id=f605a41b53)." id: checklist type: checkboxes + - attributes: + description: "Enter the slug or API URL of the affected Ory Network project. Leave empty when you are self-hosting." + label: "Ory Network Project" + placeholder: "https://.projects.oryapis.com" + id: ory-network-project + type: input - attributes: description: | This section gives the reader a very rough overview of the landscape in which the new system is being built and what is actually being built. This isn’t a requirements doc. Keep it succinct! The goal is that readers are brought up to speed but some previous knowledge can be assumed and detailed info can be linked to. This section should be entirely focused on objective background facts. diff --git a/.github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml b/.github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml index 4f2349ab8a58..5e203aacfce9 100644 --- a/.github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml +++ b/.github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml @@ -24,12 +24,17 @@ body: - label: "I have read and am following this repository's [Contribution Guidelines](https://github.com/ory/kratos/blob/master/CONTRIBUTING.md)." required: true - - label: "This issue affects my [Ory Network](https://www.ory.sh/) project." - label: "I have joined the [Ory Community Slack](https://slack.ory.sh)." - label: "I am signed up to the [Ory Security Patch Newsletter](https://ory.us10.list-manage.com/subscribe?u=ffb1a878e4ec6c0ed312a3480&id=f605a41b53)." id: checklist type: checkboxes + - attributes: + description: "Enter the slug or API URL of the affected Ory Network project. Leave empty when you are self-hosting." + label: "Ory Network Project" + placeholder: "https://.projects.oryapis.com" + id: ory-network-project + type: input - attributes: description: "Is your feature request related to a problem? Please describe." label: "Describe your problem" From aa123f7fb92e882cd2722deb83a57131d8b3de18 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Mon, 7 Aug 2023 16:11:02 +0000 Subject: [PATCH 024/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 54 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4baa4cab155d..958705d4a87c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,16 +5,17 @@ **Table of Contents** -- [ (2023-08-01)](#2023-08-01) +- [ (2023-08-07)](#2023-08-07) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) - [Features](#features) + - [Tests](#tests) - [1.0.0 (2023-07-12)](#100-2023-07-12) - [Bug Fixes](#bug-fixes-1) - [Code Generation](#code-generation) - [Documentation](#documentation-1) - [Features](#features-1) - - [Tests](#tests) + - [Tests](#tests-1) - [Unclassified](#unclassified) - [0.13.0 (2023-04-18)](#0130-2023-04-18) - [Breaking Changes](#breaking-changes) @@ -23,7 +24,7 @@ - [Code Refactoring](#code-refactoring) - [Documentation](#documentation-2) - [Features](#features-2) - - [Tests](#tests-1) + - [Tests](#tests-2) - [Unclassified](#unclassified-1) - [0.11.1 (2023-01-14)](#0111-2023-01-14) - [Breaking Changes](#breaking-changes-1) @@ -31,7 +32,7 @@ - [Code Generation](#code-generation-2) - [Documentation](#documentation-3) - [Features](#features-3) - - [Tests](#tests-2) + - [Tests](#tests-3) - [0.11.0 (2022-12-02)](#0110-2022-12-02) - [Breaking Changes](#breaking-changes-2) - [Bug Fixes](#bug-fixes-4) @@ -40,7 +41,7 @@ - [Documentation](#documentation-4) - [Features](#features-4) - [Reverts](#reverts) - - [Tests](#tests-3) + - [Tests](#tests-4) - [Unclassified](#unclassified-2) - [0.10.1 (2022-06-01)](#0101-2022-06-01) - [Bug Fixes](#bug-fixes-5) @@ -52,7 +53,7 @@ - [Code Refactoring](#code-refactoring-2) - [Documentation](#documentation-5) - [Features](#features-5) - - [Tests](#tests-4) + - [Tests](#tests-5) - [Unclassified](#unclassified-3) - [0.9.0-alpha.3 (2022-03-25)](#090-alpha3-2022-03-25) - [Breaking Changes](#breaking-changes-4) @@ -69,7 +70,7 @@ - [Code Refactoring](#code-refactoring-3) - [Documentation](#documentation-7) - [Features](#features-6) - - [Tests](#tests-5) + - [Tests](#tests-6) - [Unclassified](#unclassified-4) - [0.8.3-alpha.1.pre.0 (2022-01-21)](#083-alpha1pre0-2022-01-21) - [Breaking Changes](#breaking-changes-6) @@ -78,7 +79,7 @@ - [Code Refactoring](#code-refactoring-4) - [Documentation](#documentation-8) - [Features](#features-7) - - [Tests](#tests-6) + - [Tests](#tests-7) - [0.8.2-alpha.1 (2021-12-17)](#082-alpha1-2021-12-17) - [Bug Fixes](#bug-fixes-11) - [Code Generation](#code-generation-10) @@ -88,14 +89,14 @@ - [Code Generation](#code-generation-11) - [Documentation](#documentation-10) - [Features](#features-8) - - [Tests](#tests-7) + - [Tests](#tests-8) - [0.8.0-alpha.4.pre.0 (2021-11-09)](#080-alpha4pre0-2021-11-09) - [Breaking Changes](#breaking-changes-7) - [Bug Fixes](#bug-fixes-13) - [Code Generation](#code-generation-12) - [Documentation](#documentation-11) - [Features](#features-9) - - [Tests](#tests-8) + - [Tests](#tests-9) - [0.8.0-alpha.3 (2021-10-28)](#080-alpha3-2021-10-28) - [Bug Fixes](#bug-fixes-14) - [Code Generation](#code-generation-13) @@ -109,7 +110,7 @@ - [Documentation](#documentation-12) - [Features](#features-10) - [Reverts](#reverts-1) - - [Tests](#tests-9) + - [Tests](#tests-10) - [Unclassified](#unclassified-5) - [0.7.6-alpha.1 (2021-09-12)](#076-alpha1-2021-09-12) - [Code Generation](#code-generation-16) @@ -120,7 +121,7 @@ - [Code Generation](#code-generation-18) - [Documentation](#documentation-13) - [Features](#features-11) - - [Tests](#tests-10) + - [Tests](#tests-11) - [0.7.3-alpha.1 (2021-08-28)](#073-alpha1-2021-08-28) - [Bug Fixes](#bug-fixes-17) - [Code Generation](#code-generation-19) @@ -130,7 +131,7 @@ - [Bug Fixes](#bug-fixes-18) - [Code Generation](#code-generation-20) - [Documentation](#documentation-15) - - [Tests](#tests-11) + - [Tests](#tests-12) - [0.7.0-alpha.1 (2021-07-13)](#070-alpha1-2021-07-13) - [Breaking Changes](#breaking-changes-9) - [Bug Fixes](#bug-fixes-19) @@ -138,7 +139,7 @@ - [Code Refactoring](#code-refactoring-6) - [Documentation](#documentation-16) - [Features](#features-13) - - [Tests](#tests-12) + - [Tests](#tests-13) - [Unclassified](#unclassified-6) - [0.6.3-alpha.1 (2021-05-17)](#063-alpha1-2021-05-17) - [Breaking Changes](#breaking-changes-10) @@ -162,14 +163,14 @@ - [Code Refactoring](#code-refactoring-8) - [Documentation](#documentation-18) - [Features](#features-16) - - [Tests](#tests-13) + - [Tests](#tests-14) - [Unclassified](#unclassified-7) - [0.5.5-alpha.1 (2020-12-09)](#055-alpha1-2020-12-09) - [Bug Fixes](#bug-fixes-23) - [Code Generation](#code-generation-27) - [Documentation](#documentation-19) - [Features](#features-17) - - [Tests](#tests-14) + - [Tests](#tests-15) - [Unclassified](#unclassified-8) - [0.5.4-alpha.1 (2020-11-11)](#054-alpha1-2020-11-11) - [Bug Fixes](#bug-fixes-24) @@ -182,18 +183,18 @@ - [Code Generation](#code-generation-29) - [Documentation](#documentation-21) - [Features](#features-19) - - [Tests](#tests-15) + - [Tests](#tests-16) - [0.5.2-alpha.1 (2020-10-22)](#052-alpha1-2020-10-22) - [Bug Fixes](#bug-fixes-26) - [Code Generation](#code-generation-30) - [Documentation](#documentation-22) - - [Tests](#tests-16) + - [Tests](#tests-17) - [0.5.1-alpha.1 (2020-10-20)](#051-alpha1-2020-10-20) - [Bug Fixes](#bug-fixes-27) - [Code Generation](#code-generation-31) - [Documentation](#documentation-23) - [Features](#features-20) - - [Tests](#tests-17) + - [Tests](#tests-18) - [Unclassified](#unclassified-9) - [0.5.0-alpha.1 (2020-10-15)](#050-alpha1-2020-10-15) - [Breaking Changes](#breaking-changes-12) @@ -202,7 +203,7 @@ - [Code Refactoring](#code-refactoring-10) - [Documentation](#documentation-24) - [Features](#features-21) - - [Tests](#tests-18) + - [Tests](#tests-19) - [Unclassified](#unclassified-10) - [0.4.6-alpha.1 (2020-07-13)](#046-alpha1-2020-07-13) - [Bug Fixes](#bug-fixes-29) @@ -308,7 +309,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-08-01) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-08-07) ### Bug Fixes @@ -319,6 +320,12 @@ - fix: accept all 200 responses as OK in courier +- Redirect to verification URL even if login_challenge is set + ([#3412](https://github.com/ory/kratos/issues/3412)) + ([cd9e6a0](https://github.com/ory/kratos/commit/cd9e6a0e1e4cb4957d2a50ae3d288ebb0591e42d)): + + Fixes https://github.com/ory/network/issues/320 + - Reduce db lookups in whoami for aal check ([#3372](https://github.com/ory/kratos/issues/3372)) ([d814a48](https://github.com/ory/kratos/commit/d814a4864d5c25c4f320daca733873577d517331)): @@ -356,6 +363,11 @@ Users can now supply a list of origins for webauthn in the configuration. +### Tests + +- **e2e:** Logout return_to ([#3418](https://github.com/ory/kratos/issues/3418)) + ([c348c12](https://github.com/ory/kratos/commit/c348c12ab3c9cdb4ce8159fe774ed179ff6a4d8a)) + # [1.0.0](https://github.com/ory/kratos/compare/v0.13.0...v1.0.0) (2023-07-12) We are thrilled to announce Ory Kratos v1.0, the powerful Identity, User From ce8139f2325a8317388cbcaaa98f3f83d626657b Mon Sep 17 00:00:00 2001 From: Patrik Date: Tue, 8 Aug 2023 09:54:57 +0200 Subject: [PATCH 025/282] fix: false-positives for requiring re-authentication on update (#3421) --- identity/credentials.go | 9 ++++++++- identity/manager_test.go | 42 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/identity/credentials.go b/identity/credentials.go index 1d33440389a0..af79ba3f2ed6 100644 --- a/identity/credentials.go +++ b/identity/credentials.go @@ -237,7 +237,14 @@ func CredentialsEqual(a, b map[CredentialsType]Credentials) bool { return false } - if !reflect.DeepEqual(expect.Identifiers, actual.Identifiers) { + expectIdentifiers, actualIdentifiers := make(map[string]struct{}, len(expect.Identifiers)), make(map[string]struct{}, len(actual.Identifiers)) + for _, i := range expect.Identifiers { + expectIdentifiers[i] = struct{}{} + } + for _, i := range actual.Identifiers { + actualIdentifiers[i] = struct{}{} + } + if !reflect.DeepEqual(expectIdentifiers, actualIdentifiers) { return false } } diff --git a/identity/manager_test.go b/identity/manager_test.go index 294eff89b95e..f5a29877bb89 100644 --- a/identity/manager_test.go +++ b/identity/manager_test.go @@ -9,6 +9,8 @@ import ( "testing" "time" + "github.com/ory/x/pointerx" + "github.com/gofrs/uuid" "github.com/ory/x/sqlxx" @@ -28,6 +30,7 @@ import ( func TestManager(t *testing.T) { conf, reg := internal.NewFastRegistryWithMocks(t) testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/manager.schema.json") + extensionSchemaID := testhelpers.UseIdentitySchema(t, conf, "file://./stub/extension.schema.json") conf.MustSet(ctx, config.ViperKeyPublicBaseURL, "https://www.ory.sh/") conf.MustSet(ctx, config.ViperKeyCourierSMTPURL, "smtp://foo@bar@dev.null/") @@ -248,6 +251,45 @@ func TestManager(t *testing.T) { checkExtensionFields(fromStore, "email-update-1@ory.sh")(t) }) + t.Run("case=should update unprotected traits with multiple credential identifiers", func(t *testing.T) { + original := identity.NewIdentity(extensionSchemaID) + original.Traits = identity.Traits(`{"email": "email-update-ewisdfuja@ory.sh", "names": ["username1", "username2"], "age": 30}`) + require.NoError(t, reg.IdentityManager().Create(ctx, original)) + assert.Len(t, original.Credentials[identity.CredentialsTypePassword].Identifiers, 3) + + original.Traits = identity.Traits(`{"email": "email-update-ewisdfuja@ory.sh", "names": ["username1", "username2"], "age": 31}`) + require.NoError(t, reg.IdentityManager().Update(ctx, original)) + + fromStore, err := reg.PrivilegedIdentityPool().GetIdentityConfidential(ctx, original.ID) + require.NoError(t, err) + assert.JSONEq(t, string(original.Traits), string(fromStore.Traits)) + }) + + t.Run("case=should update unprotected traits with verified user", func(t *testing.T) { + email := x.NewUUID().String() + "@ory.sh" + original := identity.NewIdentity(config.DefaultIdentityTraitsSchemaID) + original.Traits = newTraits(email, "initial") + require.NoError(t, reg.IdentityManager().Create(ctx, original)) + + // mock successful verification process + addr := original.VerifiableAddresses[0] + addr.Verified = true + addr.VerifiedAt = pointerx.Ptr(sqlxx.NullTime(time.Now().UTC())) + require.NoError(t, reg.PrivilegedIdentityPool().UpdateVerifiableAddress(ctx, &addr)) + + // reload to properly set the verified address + var err error + original, err = reg.PrivilegedIdentityPool().GetIdentityConfidential(ctx, original.ID) + require.NoError(t, err) + + original.Traits = newTraits(email, "updated") + require.NoError(t, reg.IdentityManager().Update(ctx, original)) + + fromStore, err := reg.PrivilegedIdentityPool().GetIdentityConfidential(ctx, original.ID) + require.NoError(t, err) + assert.JSONEq(t, string(original.Traits), string(fromStore.Traits)) + }) + t.Run("case=changing recovery address removes it from the store", func(t *testing.T) { originalEmail := x.NewUUID().String() + "@ory.sh" original := identity.NewIdentity(config.DefaultIdentityTraitsSchemaID) From a0f2420ae74af2393d855aaab1b3bbfbe5f5e732 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Tue, 8 Aug 2023 09:32:00 +0000 Subject: [PATCH 026/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 958705d4a87c..a2eb26371de7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-08-07)](#2023-08-07) +- [ (2023-08-08)](#2023-08-08) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) - [Features](#features) @@ -309,7 +309,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-08-07) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-08-08) ### Bug Fixes @@ -320,6 +320,9 @@ - fix: accept all 200 responses as OK in courier +- False-positives for requiring re-authentication on update + ([#3421](https://github.com/ory/kratos/issues/3421)) + ([ce8139f](https://github.com/ory/kratos/commit/ce8139f2325a8317388cbcaaa98f3f83d626657b)) - Redirect to verification URL even if login_challenge is set ([#3412](https://github.com/ory/kratos/issues/3412)) ([cd9e6a0](https://github.com/ory/kratos/commit/cd9e6a0e1e4cb4957d2a50ae3d288ebb0591e42d)): From 3ddff789539875ce8554ce0d9373228e475eb196 Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Wed, 9 Aug 2023 13:52:53 +0200 Subject: [PATCH 027/282] chore: use hosted httpbin in e2e tests (#3422) --- test/e2e/cypress/helpers/httpbin.ts | 12 +++++++++--- test/e2e/cypress/helpers/oauth2.ts | 2 +- .../integration/profiles/oidc-provider/login.spec.ts | 4 ++-- .../integration/profiles/oidc-provider/mfa.spec.ts | 2 +- .../profiles/oidc-provider/registration.spec.ts | 2 +- test/e2e/run.sh | 2 +- 6 files changed, 15 insertions(+), 9 deletions(-) diff --git a/test/e2e/cypress/helpers/httpbin.ts b/test/e2e/cypress/helpers/httpbin.ts index b8c37d9027d9..ebd89ecaea3a 100644 --- a/test/e2e/cypress/helpers/httpbin.ts +++ b/test/e2e/cypress/helpers/httpbin.ts @@ -9,15 +9,21 @@ export function checkToken( check: (token: any) => void, ) { cy.location("href") - .should("match", new RegExp("https://httpbin.org/anything[?]code=.*")) - .then((body) => { + .should( + "match", + new RegExp( + "https://ory-network-httpbin-ijakee5waq-ez.a.run.app/anything[?]code=.*", + ), + ) + .then(() => { cy.get("body") .invoke("text") .then((text) => { const result = JSON.parse(text) const tokenParams = { code: result.args.code, - redirect_uri: "https://httpbin.org/anything", + redirect_uri: + "https://ory-network-httpbin-ijakee5waq-ez.a.run.app/anything", scope: scope.join(" "), } oauth2 diff --git a/test/e2e/cypress/helpers/oauth2.ts b/test/e2e/cypress/helpers/oauth2.ts index ad6cf0505d99..8fde8c70304b 100644 --- a/test/e2e/cypress/helpers/oauth2.ts +++ b/test/e2e/cypress/helpers/oauth2.ts @@ -24,7 +24,7 @@ export function getDefaultAuthorizeURL(client: oAuth2Client) { client.id, undefined, nonce, - "https://httpbin.org/anything", + "https://ory-network-httpbin-ijakee5waq-ez.a.run.app/anything", "code", ["offline", "openid"], state, diff --git a/test/e2e/cypress/integration/profiles/oidc-provider/login.spec.ts b/test/e2e/cypress/integration/profiles/oidc-provider/login.spec.ts index 66a4a91f17b9..8264047a8f44 100644 --- a/test/e2e/cypress/integration/profiles/oidc-provider/login.spec.ts +++ b/test/e2e/cypress/integration/profiles/oidc-provider/login.spec.ts @@ -17,7 +17,7 @@ context("OpenID Provider", () => { scopes: ["openid", "offline", "email", "website"], callbacks: [ "http://localhost:5555/callback", - "https://httpbin.org/anything", + "https://ory-network-httpbin-ijakee5waq-ez.a.run.app/anything", ], } @@ -160,7 +160,7 @@ context("OpenID Provider - change between flows", () => { scopes: ["openid", "offline", "email", "website"], callbacks: [ "http://localhost:5555/callback", - "https://httpbin.org/anything", + "https://ory-network-httpbin-ijakee5waq-ez.a.run.app/anything", ], } diff --git a/test/e2e/cypress/integration/profiles/oidc-provider/mfa.spec.ts b/test/e2e/cypress/integration/profiles/oidc-provider/mfa.spec.ts index c9151e54e307..1c2395dc9491 100644 --- a/test/e2e/cypress/integration/profiles/oidc-provider/mfa.spec.ts +++ b/test/e2e/cypress/integration/profiles/oidc-provider/mfa.spec.ts @@ -19,7 +19,7 @@ context("OIDC Provider 2FA", () => { scopes: ["openid", "offline", "email", "website"], callbacks: [ "http://localhost:5555/callback", - "https://httpbin.org/anything", + "https://ory-network-httpbin-ijakee5waq-ez.a.run.app/anything", ], } diff --git a/test/e2e/cypress/integration/profiles/oidc-provider/registration.spec.ts b/test/e2e/cypress/integration/profiles/oidc-provider/registration.spec.ts index 6c13f1588938..1452844f3c18 100644 --- a/test/e2e/cypress/integration/profiles/oidc-provider/registration.spec.ts +++ b/test/e2e/cypress/integration/profiles/oidc-provider/registration.spec.ts @@ -22,7 +22,7 @@ context("OpenID Provider", () => { scopes: ["openid", "offline", "email", "website"], callbacks: [ "http://localhost:5555/callback", - "https://httpbin.org/anything", + "https://ory-network-httpbin-ijakee5waq-ez.a.run.app/anything", ], } diff --git a/test/e2e/run.sh b/test/e2e/run.sh index 94c84296f951..fdb7b623b25f 100755 --- a/test/e2e/run.sh +++ b/test/e2e/run.sh @@ -207,7 +207,7 @@ prepare() { --response-type code --response-type id_token \ --scope openid --scope offline --scope email --scope website \ --redirect-uri http://localhost:5555/callback \ - --redirect-uri https://httpbin.org/anything \ + --redirect-uri https://ory-network-httpbin-ijakee5waq-ez.a.run.app/anything \ --format json) export CYPRESS_OIDC_DUMMY_CLIENT_ID=$(jq -r '.client_id' <<< "$dummy_client" ) export CYPRESS_OIDC_DUMMY_CLIENT_SECRET=$(jq -r '.client_secret' <<< "$dummy_client" ) From 76241bee3dc7fec4690346ee85bc4b9f897fdd34 Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Fri, 11 Aug 2023 10:36:49 +0200 Subject: [PATCH 028/282] fix: carry `oauth2_login_challenge` over to registration flow (#3419) Fixes https://github.com/ory/kratos/issues/3321 --- selfservice/flow/registration/handler.go | 7 +++ .../strategy/oidc/strategy_helper_test.go | 4 +- selfservice/strategy/oidc/strategy_login.go | 48 +++++++++++-------- selfservice/strategy/oidc/strategy_test.go | 29 ++++++++--- 4 files changed, 60 insertions(+), 28 deletions(-) diff --git a/selfservice/flow/registration/handler.go b/selfservice/flow/registration/handler.go index 179909180824..91242f6bf26b 100644 --- a/selfservice/flow/registration/handler.go +++ b/selfservice/flow/registration/handler.go @@ -22,6 +22,7 @@ import ( "github.com/julienschmidt/httprouter" "github.com/pkg/errors" + "github.com/ory/x/sqlxx" "github.com/ory/x/urlx" "github.com/ory/kratos/driver/config" @@ -108,6 +109,12 @@ func WithFlowReturnTo(returnTo string) FlowOption { } } +func WithFlowOAuth2LoginChallenge(loginChallenge string) FlowOption { + return func(f *Flow) { + f.OAuth2LoginChallenge = sqlxx.NullString(loginChallenge) + } +} + func (h *Handler) NewRegistrationFlow(w http.ResponseWriter, r *http.Request, ft flow.Type, opts ...FlowOption) (*Flow, error) { if !h.d.Config().SelfServiceFlowRegistrationEnabled(r.Context()) { return nil, errors.WithStack(ErrRegistrationDisabled) diff --git a/selfservice/strategy/oidc/strategy_helper_test.go b/selfservice/strategy/oidc/strategy_helper_test.go index 31fc70987e48..db3904d0221f 100644 --- a/selfservice/strategy/oidc/strategy_helper_test.go +++ b/selfservice/strategy/oidc/strategy_helper_test.go @@ -94,11 +94,11 @@ func createClient(t *testing.T, remote string, redir string) (id, secret string) } defer res.Body.Close() + body := ioutilx.MustReadAll(res.Body) if http.StatusCreated != res.StatusCode { - return errors.Errorf("got status code: %d", res.StatusCode) + return errors.Errorf("got status code: %d\n%s", res.StatusCode, body) } - body := ioutilx.MustReadAll(res.Body) id = gjson.GetBytes(body, "client_id").String() secret = gjson.GetBytes(body, "client_secret").String() return nil diff --git a/selfservice/strategy/oidc/strategy_login.go b/selfservice/strategy/oidc/strategy_login.go index edf3faeb80ae..23f4ff60514a 100644 --- a/selfservice/strategy/oidc/strategy_login.go +++ b/selfservice/strategy/oidc/strategy_login.go @@ -83,7 +83,7 @@ type UpdateLoginFlowWithOidcMethod struct { UpstreamParameters json.RawMessage `json:"upstream_parameters"` } -func (s *Strategy) processLogin(w http.ResponseWriter, r *http.Request, a *login.Flow, token *oauth2.Token, claims *Claims, provider Provider, container *authCodeContainer) (*registration.Flow, error) { +func (s *Strategy) processLogin(w http.ResponseWriter, r *http.Request, loginFlow *login.Flow, token *oauth2.Token, claims *Claims, provider Provider, container *authCodeContainer) (*registration.Flow, error) { i, c, err := s.d.PrivilegedIdentityPool().FindByCredentialsIdentifier(r.Context(), identity.CredentialsTypeOIDC, identity.OIDCUniqueID(provider.Config().ID, claims.Subject)) if err != nil { if errors.Is(err, sqlcon.ErrNoRows) { @@ -97,56 +97,64 @@ func (s *Strategy) processLogin(w http.ResponseWriter, r *http.Request, a *login // not need additional consent/login. // This is kinda hacky but the only way to ensure seamless login/registration flows when using OIDC. - s.d.Logger().WithField("provider", provider.Config().ID).WithField("subject", claims.Subject).Debug("Received successful OpenID Connect callback but user is not registered. Re-initializing registration flow now.") + s.d. + Logger(). + WithField("provider", provider.Config().ID). + WithField("subject", claims.Subject). + Debug("Received successful OpenID Connect callback but user is not registered. Re-initializing registration flow now.") // If return_to was set before, we need to preserve it. var opts []registration.FlowOption - if len(a.ReturnTo) > 0 { - opts = append(opts, registration.WithFlowReturnTo(a.ReturnTo)) + if len(loginFlow.ReturnTo) > 0 { + opts = append(opts, registration.WithFlowReturnTo(loginFlow.ReturnTo)) } - aa, err := s.d.RegistrationHandler().NewRegistrationFlow(w, r, a.Type, opts...) + if loginFlow.OAuth2LoginChallenge.String() != "" { + opts = append(opts, registration.WithFlowOAuth2LoginChallenge(loginFlow.OAuth2LoginChallenge.String())) + } + + registrationFlow, err := s.d.RegistrationHandler().NewRegistrationFlow(w, r, loginFlow.Type, opts...) if err != nil { - return nil, s.handleError(w, r, a, provider.Config().ID, nil, err) + return nil, s.handleError(w, r, loginFlow, provider.Config().ID, nil, err) } - err = s.d.SessionTokenExchangePersister().MoveToNewFlow(r.Context(), a.ID, aa.ID) + err = s.d.SessionTokenExchangePersister().MoveToNewFlow(r.Context(), loginFlow.ID, registrationFlow.ID) if err != nil { - return nil, s.handleError(w, r, a, provider.Config().ID, nil, err) + return nil, s.handleError(w, r, loginFlow, provider.Config().ID, nil, err) } - aa.RequestURL, err = x.TakeOverReturnToParameter(a.RequestURL, aa.RequestURL) + registrationFlow.RequestURL, err = x.TakeOverReturnToParameter(loginFlow.RequestURL, registrationFlow.RequestURL) if err != nil { - return nil, s.handleError(w, r, a, provider.Config().ID, nil, err) + return nil, s.handleError(w, r, loginFlow, provider.Config().ID, nil, err) } - if _, err := s.processRegistration(w, r, aa, token, claims, provider, container); err != nil { - return aa, err + if _, err := s.processRegistration(w, r, registrationFlow, token, claims, provider, container); err != nil { + return registrationFlow, err } return nil, nil } - return nil, s.handleError(w, r, a, provider.Config().ID, nil, err) + return nil, s.handleError(w, r, loginFlow, provider.Config().ID, nil, err) } - var o identity.CredentialsOIDC - if err := json.NewDecoder(bytes.NewBuffer(c.Config)).Decode(&o); err != nil { - return nil, s.handleError(w, r, a, provider.Config().ID, nil, errors.WithStack(herodot.ErrInternalServerError.WithReason("The password credentials could not be decoded properly").WithDebug(err.Error()))) + var oidcCredentials identity.CredentialsOIDC + if err := json.NewDecoder(bytes.NewBuffer(c.Config)).Decode(&oidcCredentials); err != nil { + return nil, s.handleError(w, r, loginFlow, provider.Config().ID, nil, errors.WithStack(herodot.ErrInternalServerError.WithReason("The password credentials could not be decoded properly").WithDebug(err.Error()))) } sess := session.NewInactiveSession() sess.CompletedLoginForWithProvider(s.ID(), identity.AuthenticatorAssuranceLevel1, provider.Config().ID) - for _, c := range o.Providers { + for _, c := range oidcCredentials.Providers { if c.Subject == claims.Subject && c.Provider == provider.Config().ID { - if err = s.d.LoginHookExecutor().PostLoginHook(w, r, node.OpenIDConnectGroup, a, i, sess, provider.Config().ID); err != nil { - return nil, s.handleError(w, r, a, provider.Config().ID, nil, err) + if err = s.d.LoginHookExecutor().PostLoginHook(w, r, node.OpenIDConnectGroup, loginFlow, i, sess, provider.Config().ID); err != nil { + return nil, s.handleError(w, r, loginFlow, provider.Config().ID, nil, err) } return nil, nil } } - return nil, s.handleError(w, r, a, provider.Config().ID, nil, errors.WithStack(herodot.ErrInternalServerError.WithReason("Unable to find matching OpenID Connect Credentials.").WithDebugf(`Unable to find credentials that match the given provider "%s" and subject "%s".`, provider.Config().ID, claims.Subject))) + return nil, s.handleError(w, r, loginFlow, provider.Config().ID, nil, errors.WithStack(herodot.ErrInternalServerError.WithReason("Unable to find matching OpenID Connect Credentials.").WithDebugf(`Unable to find credentials that match the given provider "%s" and subject "%s".`, provider.Config().ID, claims.Subject))) } func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, _ uuid.UUID) (i *identity.Identity, err error) { diff --git a/selfservice/strategy/oidc/strategy_test.go b/selfservice/strategy/oidc/strategy_test.go index 181678033459..4c6284ac5c4c 100644 --- a/selfservice/strategy/oidc/strategy_test.go +++ b/selfservice/strategy/oidc/strategy_test.go @@ -17,6 +17,7 @@ import ( "testing" "time" + "github.com/ory/kratos/hydra" "github.com/ory/kratos/selfservice/sessiontokenexchange" "github.com/ory/kratos/session" "github.com/ory/x/snapshotx" @@ -241,12 +242,12 @@ func TestStrategy(t *testing.T) { assert.Equal(t, claims.metadataPublic.picture, gjson.GetBytes(body, "identity.metadata_public.picture").String(), "%s", body) } - var newLoginFlow = func(t *testing.T, redirectTo string, exp time.Duration, flowType flow.Type) (req *login.Flow) { + var newLoginFlow = func(t *testing.T, requestURL string, exp time.Duration, flowType flow.Type) (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(), - &http.Request{URL: urlx.ParseOrPanic(redirectTo)}, flowType) + &http.Request{URL: urlx.ParseOrPanic(requestURL)}, flowType) require.NoError(t, err) - req.RequestURL = redirectTo + req.RequestURL = requestURL req.ExpiresAt = time.Now().Add(exp) require.NoError(t, reg.LoginFlowPersister().UpdateLoginFlow(context.Background(), req)) @@ -552,17 +553,33 @@ func TestStrategy(t *testing.T) { }) t.Run("case=login without registered account with return_to", func(t *testing.T) { - subject = "login-without-register-return-to@ory.sh" - scope = []string{"openid"} - returnTo := "/foo" t.Run("case=should pass login", func(t *testing.T) { + subject = "login-without-register-return-to@ory.sh" + scope = []string{"openid"} + returnTo := "/foo" r := newBrowserLoginFlow(t, fmt.Sprintf("%s?return_to=%s", returnTS.URL, returnTo), time.Minute) action := assertFormValues(t, r.ID, "valid") res, body := makeRequest(t, "valid", action, url.Values{}) assert.True(t, strings.HasSuffix(res.Request.URL.String(), returnTo)) assertIdentity(t, res, body) }) + + t.Run("case=should pass login and carry over login_challenge to registration", func(t *testing.T) { + subject = "login_challenge_carry_over@ory.sh" + scope = []string{"openid"} + conf.MustSet(ctx, config.ViperKeyOAuth2ProviderURL, "http://fake-hydra") + + reg.WithHydra(hydra.NewFake()) + r := newBrowserLoginFlow(t, fmt.Sprintf("%s?login_challenge=%s", returnTS.URL, hydra.FakeValidLoginChallenge), time.Minute) + action := assertFormValues(t, r.ID, "valid") + fv := url.Values{} + fv.Set("provider", "valid") + res, err := testhelpers.NewClientWithCookieJar(t, nil, false).PostForm(action, fv) + require.NoError(t, err) + // Expect to be returned to the hydra instance, that instantiated the request + assert.Equal(t, hydra.FakePostLoginURL, res.Request.URL.String()) + }) }) t.Run("case=register and register again but login", func(t *testing.T) { From 57e2195837f424d361ed80412052e04832a12afa Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Fri, 11 Aug 2023 10:02:12 +0000 Subject: [PATCH 029/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2eb26371de7..c8975ff0de52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-08-08)](#2023-08-08) +- [ (2023-08-11)](#2023-08-11) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) - [Features](#features) @@ -309,7 +309,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-08-08) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-08-11) ### Bug Fixes @@ -320,6 +320,12 @@ - fix: accept all 200 responses as OK in courier +- Carry `oauth2_login_challenge` over to registration flow + ([#3419](https://github.com/ory/kratos/issues/3419)) + ([76241be](https://github.com/ory/kratos/commit/76241bee3dc7fec4690346ee85bc4b9f897fdd34)): + + Fixes https://github.com/ory/kratos/issues/3321 + - False-positives for requiring re-authentication on update ([#3421](https://github.com/ory/kratos/issues/3421)) ([ce8139f](https://github.com/ory/kratos/commit/ce8139f2325a8317388cbcaaa98f3f83d626657b)) From 6b02350c21aa65decd1bb16e559e1cc7dae42d55 Mon Sep 17 00:00:00 2001 From: Henning Perl Date: Sun, 13 Aug 2023 18:08:17 +0200 Subject: [PATCH 030/282] fix: accept login_challenge after verification (#3427) Part of https://github.com/ory/network/issues/320 --- ...cation_add_oauth2_login_challenge.down.sql | 1 + ...fication_add_oauth2_login_challenge.up.sql | 1 + selfservice/flow/flow.go | 5 ++++ selfservice/flow/registration/flow.go | 4 +++ selfservice/flow/registration/hook.go | 14 +++------- selfservice/flow/registration/hook_test.go | 25 +++++------------ selfservice/flow/verification/flow.go | 2 ++ selfservice/flow/verification/handler.go | 27 +++++++++++++++++-- selfservice/hook/verification.go | 4 +++ session/handler.go | 2 +- 10 files changed, 52 insertions(+), 33 deletions(-) create mode 100644 persistence/sql/migrations/sql/20230811000000000001_verification_add_oauth2_login_challenge.down.sql create mode 100644 persistence/sql/migrations/sql/20230811000000000001_verification_add_oauth2_login_challenge.up.sql diff --git a/persistence/sql/migrations/sql/20230811000000000001_verification_add_oauth2_login_challenge.down.sql b/persistence/sql/migrations/sql/20230811000000000001_verification_add_oauth2_login_challenge.down.sql new file mode 100644 index 000000000000..3aa1dba47a09 --- /dev/null +++ b/persistence/sql/migrations/sql/20230811000000000001_verification_add_oauth2_login_challenge.down.sql @@ -0,0 +1 @@ +ALTER TABLE selfservice_verification_flows DROP COLUMN oauth2_login_challenge; diff --git a/persistence/sql/migrations/sql/20230811000000000001_verification_add_oauth2_login_challenge.up.sql b/persistence/sql/migrations/sql/20230811000000000001_verification_add_oauth2_login_challenge.up.sql new file mode 100644 index 000000000000..70209b68d4f2 --- /dev/null +++ b/persistence/sql/migrations/sql/20230811000000000001_verification_add_oauth2_login_challenge.up.sql @@ -0,0 +1 @@ +ALTER TABLE selfservice_verification_flows ADD COLUMN oauth2_login_challenge TEXT NULL; diff --git a/selfservice/flow/flow.go b/selfservice/flow/flow.go index 6759ee3dfda7..912cb72fa715 100644 --- a/selfservice/flow/flow.go +++ b/selfservice/flow/flow.go @@ -12,6 +12,7 @@ import ( "github.com/ory/kratos/driver/config" "github.com/ory/kratos/ui/container" + "github.com/ory/x/sqlxx" "github.com/ory/herodot" "github.com/ory/kratos/x" @@ -41,6 +42,10 @@ type Flow interface { GetUI() *container.Container } +type Challenger interface { + GetOAuth2LoginChallenge() sqlxx.NullString +} + type FlowWithRedirect interface { SecureRedirectToOpts(ctx context.Context, cfg config.Provider) (opts []x.SecureRedirectOption) } diff --git a/selfservice/flow/registration/flow.go b/selfservice/flow/registration/flow.go index 26c748760ce2..0b1c49c69080 100644 --- a/selfservice/flow/registration/flow.go +++ b/selfservice/flow/registration/flow.go @@ -229,6 +229,10 @@ func (f *Flow) ContinueWith() []flow.ContinueWith { return f.ContinueWithItems } +func (f Flow) GetOAuth2LoginChallenge() sqlxx.NullString { + return f.OAuth2LoginChallenge +} + func (f *Flow) SecureRedirectToOpts(ctx context.Context, cfg config.Provider) (opts []x.SecureRedirectOption) { return []x.SecureRedirectOption{ x.SecureRedirectReturnTo(f.ReturnTo), diff --git a/selfservice/flow/registration/hook.go b/selfservice/flow/registration/hook.go index 8fb2604be551..6a7d7d0f75bf 100644 --- a/selfservice/flow/registration/hook.go +++ b/selfservice/flow/registration/hook.go @@ -7,7 +7,6 @@ import ( "context" "fmt" "net/http" - "net/url" "time" "go.opentelemetry.io/otel/trace" @@ -249,22 +248,15 @@ func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Reque finalReturnTo := returnTo.String() if a.OAuth2LoginChallenge != "" { - callbackURL, err := e.d.Hydra().AcceptLoginRequest(r.Context(), string(a.OAuth2LoginChallenge), i.ID.String(), s.AMR) - if err != nil { - return err - } if a.ReturnToVerification != "" { // Special case: If Kratos is used as a login UI *and* we want to show the verification UI, // redirect to the verification URL first and then return to Hydra. - verificationURL, err := url.Parse(a.ReturnToVerification) + finalReturnTo = a.ReturnToVerification + } else { + callbackURL, err := e.d.Hydra().AcceptLoginRequest(r.Context(), string(a.OAuth2LoginChallenge), i.ID.String(), s.AMR) if err != nil { return err } - q := verificationURL.Query() - q.Set("return_to", callbackURL) - verificationURL.RawQuery = q.Encode() - finalReturnTo = verificationURL.String() - } else { finalReturnTo = callbackURL } } else if a.ReturnToVerification != "" { diff --git a/selfservice/flow/registration/hook_test.go b/selfservice/flow/registration/hook_test.go index a0a4bf1508b0..c6f396b64514 100644 --- a/selfservice/flow/registration/hook_test.go +++ b/selfservice/flow/registration/hook_test.go @@ -11,6 +11,7 @@ import ( "time" "github.com/gobuffalo/httptest" + "github.com/gofrs/uuid" "github.com/julienschmidt/httprouter" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -202,25 +203,11 @@ func TestRegistrationExecutor(t *testing.T) { res, _ := makeRequestPost(t, newServer(t, i, flow.TypeBrowser, withOAuthChallenge), false, url.Values{}) assert.EqualValues(t, http.StatusOK, res.StatusCode) assert.Contains(t, res.Request.URL.String(), verificationTS.URL) - assert.NotEmpty(t, res.Request.URL.Query().Get("flow")) - assert.Equal(t, hydra.FakePostLoginURL, res.Request.URL.Query().Get("return_to")) - }) - - t.Run("case=should not redirect to verification UI if the login_challenge is invalid", func(t *testing.T) { - t.Cleanup(testhelpers.SelfServiceHookConfigReset(t, conf)) - conf.MustSet(ctx, config.ViperKeySelfServiceVerificationEnabled, true) - conf.MustSet(ctx, config.ViperKeySelfServiceRegistrationAfter+".hooks", []map[string]interface{}{{ - "hook": hook.KeyVerificationUI, - }}) - i := testhelpers.SelfServiceHookFakeIdentity(t) - i.Traits = identity.Traits(`{"email": "verifiable-invalid-login_challenge@ory.sh"}`) - - withOAuthChallenge := func(f *registration.Flow) { - f.OAuth2LoginChallenge = hydra.FakeInvalidLoginChallenge - } - res, body := makeRequestPost(t, newServer(t, i, flow.TypeBrowser, withOAuthChallenge), false, url.Values{}) - assert.EqualValues(t, http.StatusInternalServerError, res.StatusCode) - assert.Equal(t, hydra.ErrFakeAcceptLoginRequestFailed.Error(), body, "%s", body) + flowID := res.Request.URL.Query().Get("flow") + require.NotEmpty(t, flowID) + flow, err := reg.VerificationFlowPersister().GetVerificationFlow(ctx, uuid.Must(uuid.FromString(flowID))) + require.NoError(t, err) + assert.Equal(t, hydra.FakeValidLoginChallenge, flow.OAuth2LoginChallenge.String()) }) t.Run("case=should redirect to first verification UI if show_verification_ui hook is set and multiple verifiable addresses", func(t *testing.T) { diff --git a/selfservice/flow/verification/flow.go b/selfservice/flow/verification/flow.go index c43ef74bb342..88f6600161e3 100644 --- a/selfservice/flow/verification/flow.go +++ b/selfservice/flow/verification/flow.go @@ -79,6 +79,8 @@ type Flow struct { // required: true State State `json:"state" faker:"-" db:"state"` + OAuth2LoginChallenge sqlxx.NullString `json:"-" db:"oauth2_login_challenge"` + // CSRFToken contains the anti-csrf token associated with this request. CSRFToken string `json:"-" db:"csrf_token"` diff --git a/selfservice/flow/verification/handler.go b/selfservice/flow/verification/handler.go index dd21a7db1135..f47d13167dcf 100644 --- a/selfservice/flow/verification/handler.go +++ b/selfservice/flow/verification/handler.go @@ -7,6 +7,8 @@ import ( "net/http" "time" + "github.com/ory/kratos/hydra" + "github.com/ory/kratos/session" "github.com/ory/nosurf" "github.com/ory/kratos/schema" @@ -44,6 +46,8 @@ type ( identity.ManagementProvider identity.PrivilegedPoolProvider config.Provider + hydra.Provider + session.ManagementProvider x.CSRFTokenGeneratorProvider x.WriterProvider @@ -186,7 +190,7 @@ type createBrowserVerificationFlow struct { // 200: verificationFlow // 303: emptyResponse // default: errorGeneric -func (h *Handler) createBrowserVerificationFlow(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { +func (h *Handler) createBrowserVerificationFlow(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { if !h.d.Config().SelfServiceFlowVerificationEnabled(r.Context()) { h.d.SelfServiceErrorManager().Forward(r.Context(), w, r, errors.WithStack(herodot.ErrBadRequest.WithReasonf("Verification is not allowed because it was disabled."))) return @@ -385,7 +389,7 @@ type updateVerificationFlowBody struct{} // 400: verificationFlow // 410: errorGeneric // default: errorGeneric -func (h *Handler) updateVerificationFlow(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { +func (h *Handler) updateVerificationFlow(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { rid, err := flow.GetFlowID(r) if err != nil { h.d.VerificationFlowErrorHandler().WriteFlowError(w, r, nil, node.DefaultGroup, err) @@ -435,6 +439,25 @@ func (h *Handler) updateVerificationFlow(w http.ResponseWriter, r *http.Request, } if x.IsBrowserRequest(r) { + // Special case: If we ended up here through a OAuth2 login challenge, we need to accept the login request + // and redirect back to the OAuth2 provider. + if found && f.OAuth2LoginChallenge.String() != "" { + s, err := h.d.SessionManager().FetchFromRequest(r.Context(), r) + if err != nil { + h.d.VerificationFlowErrorHandler().WriteFlowError(w, r, f, node.DefaultGroup, err) + return + } + + callbackURL, err := h.d.Hydra().AcceptLoginRequest(r.Context(), string(f.OAuth2LoginChallenge), s.IdentityID.String(), s.AMR) + if err != nil { + h.d.VerificationFlowErrorHandler().WriteFlowError(w, r, f, node.DefaultGroup, err) + return + } + + http.Redirect(w, r, callbackURL, http.StatusSeeOther) + return + } + http.Redirect(w, r, f.AppendTo(h.d.Config().SelfServiceFlowVerificationUI(r.Context())).String(), http.StatusSeeOther) return } diff --git a/selfservice/hook/verification.go b/selfservice/hook/verification.go index acae298a6f33..8f8deea73eb9 100644 --- a/selfservice/hook/verification.go +++ b/selfservice/hook/verification.go @@ -83,6 +83,10 @@ func (e *Verifier) do(w http.ResponseWriter, r *http.Request, i *identity.Identi return err } + if f, ok := f.(flow.Challenger); ok { + verificationFlow.OAuth2LoginChallenge = f.GetOAuth2LoginChallenge() + } + verificationFlow.State = verification.StateEmailSent if err := strategy.PopulateVerificationMethod(r, verificationFlow); err != nil { diff --git a/session/handler.go b/session/handler.go index 2c71e33c2738..a3f706859c22 100644 --- a/session/handler.go +++ b/session/handler.go @@ -190,7 +190,7 @@ type toSession struct { // 401: errorGeneric // 403: errorGeneric // default: errorGeneric -func (h *Handler) whoami(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { +func (h *Handler) whoami(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { s, err := h.r.SessionManager().FetchFromRequest(r.Context(), r) c := h.r.Config() if err != nil { From 6fe86577a8a0e3dc6db36e8a5c0fdd571b48a521 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Sun, 13 Aug 2023 17:38:37 +0000 Subject: [PATCH 031/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8975ff0de52..6f161dac81c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-08-11)](#2023-08-11) +- [ (2023-08-13)](#2023-08-13) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) - [Features](#features) @@ -309,7 +309,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-08-11) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-08-13) ### Bug Fixes @@ -320,6 +320,12 @@ - fix: accept all 200 responses as OK in courier +- Accept login_challenge after verification + ([#3427](https://github.com/ory/kratos/issues/3427)) + ([6b02350](https://github.com/ory/kratos/commit/6b02350c21aa65decd1bb16e559e1cc7dae42d55)): + + Part of https://github.com/ory/network/issues/320 + - Carry `oauth2_login_challenge` over to registration flow ([#3419](https://github.com/ory/kratos/issues/3419)) ([76241be](https://github.com/ory/kratos/commit/76241bee3dc7fec4690346ee85bc4b9f897fdd34)): From f323b3d77a1f0d1495f81b381920fcf53178c40e Mon Sep 17 00:00:00 2001 From: Henning Perl Date: Tue, 15 Aug 2023 12:11:16 +0200 Subject: [PATCH 032/282] chore: add hperl as codeowner (#3433) --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 65f23948d74b..d142185008ff 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,3 +1,3 @@ -* @aeneasr @zepatrik +* @aeneasr @zepatrik @hperl /docs/ @ory/documenters From 9f5982bf5fa887fe1cd29bec236da9f87fa446c5 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Tue, 15 Aug 2023 11:36:30 +0000 Subject: [PATCH 033/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f161dac81c9..62c4746e8466 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-08-13)](#2023-08-13) +- [ (2023-08-15)](#2023-08-15) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) - [Features](#features) @@ -309,7 +309,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-08-13) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-08-15) ### Bug Fixes From 8b284697e4a26fb01ad57d2e9ebd8f714be49f33 Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Tue, 15 Aug 2023 16:59:49 +0200 Subject: [PATCH 034/282] feat: provide login hints when registration fails due to duplicate credentials/addresses (#3430) * feat: provide login hints when registration fails due to duplicate credentials or identifiers * feat: identify edge cases and write tests * chore: synchronize workspaces * feat: make login hints configurable * chore: synchronize workspaces * chore: synchronize workspaces * chore: synchronize workspaces * chore: synchronize workspaces --------- Co-authored-by: aeneasr <3372410+aeneasr@users.noreply.github.com> --- cmd/clidoc/main.go | 1 + driver/config/config.go | 5 + embedx/config.schema.json | 6 + identity/handler_test.go | 3 +- identity/manager.go | 171 ++++++++++++++++++ identity/manager_test.go | 129 ++++++++++++- identity/stub/manager.schema.json | 12 +- schema/errors.go | 67 ++++++- selfservice/flow/registration/error.go | 13 +- selfservice/flow/registration/hook.go | 8 - selfservice/flow/settings/hook.go | 2 +- selfservice/strategy/oidc/strategy.go | 2 +- .../strategy/password/registration_test.go | 8 +- .../strategy/webauthn/registration_test.go | 3 +- spec/api.json | 4 +- .../email/registration/errors.spec.ts | 29 ++- test/e2e/cypress/support/config.d.ts | 1 + text/id.go | 1 + text/message_validation.go | 13 ++ 19 files changed, 449 insertions(+), 29 deletions(-) diff --git a/cmd/clidoc/main.go b/cmd/clidoc/main.go index 7ec745a05964..6b4bbd7840af 100644 --- a/cmd/clidoc/main.go +++ b/cmd/clidoc/main.go @@ -97,6 +97,7 @@ func init() { "NewErrorValidationPasswordPolicyViolation": text.NewErrorValidationPasswordPolicyViolation("{reason}"), "NewErrorValidationInvalidCredentials": text.NewErrorValidationInvalidCredentials(), "NewErrorValidationDuplicateCredentials": text.NewErrorValidationDuplicateCredentials(), + "NewErrorValidationDuplicateCredentialsWithHints": text.NewErrorValidationDuplicateCredentialsWithHints("{reason}", nil, nil, ""), "NewErrorValidationDuplicateCredentialsOnOIDCLink": text.NewErrorValidationDuplicateCredentialsOnOIDCLink(), "NewErrorValidationTOTPVerifierWrong": text.NewErrorValidationTOTPVerifierWrong(), "NewErrorValidationLookupAlreadyUsed": text.NewErrorValidationLookupAlreadyUsed(), diff --git a/driver/config/config.go b/driver/config/config.go index 35bf9f4bd1d2..cc3c997ab493 100644 --- a/driver/config/config.go +++ b/driver/config/config.go @@ -117,6 +117,7 @@ const ( ViperKeySelfServiceBrowserDefaultReturnTo = "selfservice." + DefaultBrowserReturnURL ViperKeyURLsAllowedReturnToDomains = "selfservice.allowed_return_urls" ViperKeySelfServiceRegistrationEnabled = "selfservice.flows.registration.enabled" + ViperKeySelfServiceRegistrationLoginHints = "selfservice.flows.registration.login_hints" ViperKeySelfServiceRegistrationUI = "selfservice.flows.registration.ui_url" ViperKeySelfServiceRegistrationRequestLifespan = "selfservice.flows.registration.lifespan" ViperKeySelfServiceRegistrationAfter = "selfservice.flows.registration.after" @@ -628,6 +629,10 @@ func (p *Config) SelfServiceFlowRegistrationEnabled(ctx context.Context) bool { return p.GetProvider(ctx).Bool(ViperKeySelfServiceRegistrationEnabled) } +func (p *Config) SelfServiceFlowRegistrationLoginHints(ctx context.Context) bool { + return p.GetProvider(ctx).Bool(ViperKeySelfServiceRegistrationLoginHints) +} + func (p *Config) SelfServiceFlowVerificationEnabled(ctx context.Context) bool { return p.GetProvider(ctx).Bool(ViperKeySelfServiceVerificationEnabled) } diff --git a/embedx/config.schema.json b/embedx/config.schema.json index 2aa5eb1e056d..61ba37c6708f 100644 --- a/embedx/config.schema.json +++ b/embedx/config.schema.json @@ -1194,6 +1194,12 @@ "description": "If set to true will enable [User Registration](https://www.ory.sh/kratos/docs/self-service/flows/user-registration/).", "default": true }, + "login_hints": { + "type": "boolean", + "title": "Provide Login Hints on Failed Registration", + "description": "When registration fails because an account with the given credentials or addresses previously signed up, provide login hints about available methods to sign in to the user.", + "default": false + }, "ui_url": { "title": "Registration UI URL", "description": "URL where the Registration UI is hosted. Check the [reference implementation](https://github.com/ory/kratos-selfservice-ui-node).", diff --git a/identity/handler_test.go b/identity/handler_test.go index 8a7e5a48ab91..399b6f0cb1ff 100644 --- a/identity/handler_test.go +++ b/identity/handler_test.go @@ -1469,6 +1469,7 @@ func TestHandler(t *testing.T) { require.NoError(t, reg.PrivilegedIdentityPool().CreateIdentities(context.Background(), toCreate...)) for _, perPage := range []int{10, 50, 100, 500} { + perPage := perPage t.Run(fmt.Sprintf("perPage=%d", perPage), func(t *testing.T) { t.Parallel() body, res := getFull(t, ts, fmt.Sprintf("/identities?per_page=%d", perPage), http.StatusOK) @@ -1524,7 +1525,7 @@ func TestHandler(t *testing.T) { assert.Equal(t, count/perPage, pages) }) - t.Run("using üage pagination", func(t *testing.T) { + t.Run("using page pagination", func(t *testing.T) { knownIDs := make(map[string]struct{}) var isLast bool var pages int diff --git a/identity/manager.go b/identity/manager.go index a63f3e1b7d91..ee62c5d7caed 100644 --- a/identity/manager.go +++ b/identity/manager.go @@ -5,11 +5,15 @@ package identity import ( "context" + "encoding/json" "reflect" + "sort" "go.opentelemetry.io/otel/trace" + "github.com/ory/kratos/schema" "github.com/ory/kratos/x/events" + "github.com/ory/x/sqlcon" "github.com/ory/x/otelx" @@ -41,6 +45,7 @@ type ( courier.Provider ValidationProvider ActiveCredentialsCounterStrategyProvider + x.LoggingProvider } ManagementProvider interface { IdentityManager() *Manager @@ -95,6 +100,9 @@ func (m *Manager) Create(ctx context.Context, i *Identity, opts ...ManagerOption } if err := m.r.PrivilegedIdentityPool().CreateIdentity(ctx, i); err != nil { + if errors.Is(err, sqlcon.ErrUniqueViolation) { + return m.findExistingAuthMethod(ctx, err, i) + } return err } @@ -102,6 +110,169 @@ func (m *Manager) Create(ctx context.Context, i *Identity, opts ...ManagerOption return nil } +func (m *Manager) findExistingAuthMethod(ctx context.Context, e error, i *Identity) (err error) { + if !m.r.Config().SelfServiceFlowRegistrationLoginHints(ctx) { + return &ErrDuplicateCredentials{error: e} + } + // First we try to find the conflict in the identifiers table. This is most likely to have a conflict. + var found *Identity + for ct, cred := range i.Credentials { + for _, id := range cred.Identifiers { + found, _, err = m.r.PrivilegedIdentityPool().FindByCredentialsIdentifier(ctx, ct, id) + if err != nil { + continue + } + + // FindByCredentialsIdentifier does not expand identity credentials. + if err = m.r.PrivilegedIdentityPool().HydrateIdentityAssociations(ctx, found, ExpandCredentials); err != nil { + return err + } + } + } + + // If the conflict is not in the identifiers table, it is coming from the verifiable or recovery address. + var foundConflictAddress string + if found == nil { + for _, va := range i.VerifiableAddresses { + conflictingAddress, err := m.r.PrivilegedIdentityPool().FindVerifiableAddressByValue(ctx, va.Via, va.Value) + if errors.Is(err, sqlcon.ErrNoRows) { + continue + } else if err != nil { + return err + } + + foundConflictAddress = conflictingAddress.Value + found, err = m.r.PrivilegedIdentityPool().GetIdentity(ctx, conflictingAddress.IdentityID, ExpandCredentials) + if err != nil { + return err + } + } + } + + // Last option: check the recovery address + if found == nil { + for _, va := range i.RecoveryAddresses { + conflictingAddress, err := m.r.PrivilegedIdentityPool().FindRecoveryAddressByValue(ctx, va.Via, va.Value) + if errors.Is(err, sqlcon.ErrNoRows) { + continue + } else if err != nil { + return err + } + + foundConflictAddress = conflictingAddress.Value + found, err = m.r.PrivilegedIdentityPool().GetIdentity(ctx, conflictingAddress.IdentityID, ExpandCredentials) + if err != nil { + return err + } + } + } + + // Still not found? Return generic error. + if found == nil { + return &ErrDuplicateCredentials{error: e} + } + + // We need to sort the credentials for the error message to be deterministic. + var creds []Credentials + for _, cred := range found.Credentials { + creds = append(creds, cred) + } + sort.Slice(creds, func(i, j int) bool { + return creds[i].Type < creds[j].Type + }) + + for _, cred := range creds { + if cred.Config == nil { + continue + } + + // Basically, we only have password, oidc, and webauthn as first factor credentials. + // We don't care about second factor, because they don't help the user understand how to sign + // in to the first factor (obviously). + switch cred.Type { + case CredentialsTypePassword: + identifierHint := foundConflictAddress + if len(cred.Identifiers) > 0 { + identifierHint = cred.Identifiers[0] + } + return &ErrDuplicateCredentials{ + error: e, + availableCredentials: []CredentialsType{cred.Type}, + identifierHint: identifierHint, + } + case CredentialsTypeOIDC: + var cfg CredentialsOIDC + if err := json.Unmarshal(cred.Config, &cfg); err != nil { + return errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Unable to JSON decode identity credentials %s for identity %s.", cred.Type, found.ID)) + } + + available := make([]string, 0, len(cfg.Providers)) + for _, provider := range cfg.Providers { + available = append(available, provider.Provider) + } + + return &ErrDuplicateCredentials{ + error: e, + availableCredentials: []CredentialsType{cred.Type}, + availableOIDCProviders: available, + identifierHint: foundConflictAddress, + } + case CredentialsTypeWebAuthn: + var cfg CredentialsWebAuthnConfig + if err := json.Unmarshal(cred.Config, &cfg); err != nil { + return errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Unable to JSON decode identity credentials %s for identity %s.", cred.Type, found.ID)) + } + + identifierHint := foundConflictAddress + if len(cred.Identifiers) > 0 { + identifierHint = cred.Identifiers[0] + } + + for _, webauthn := range cfg.Credentials { + if webauthn.IsPasswordless { + return &ErrDuplicateCredentials{ + error: e, + availableCredentials: []CredentialsType{cred.Type}, + identifierHint: identifierHint, + } + } + } + } + } + + // Still not found? Return generic error. + return &ErrDuplicateCredentials{error: e} +} + +type ErrDuplicateCredentials struct { + error + + availableCredentials []CredentialsType + availableOIDCProviders []string + identifierHint string +} + +var _ schema.DuplicateCredentialsHinter = (*ErrDuplicateCredentials)(nil) + +func (e ErrDuplicateCredentials) AvailableCredentials() []string { + res := make([]string, len(e.availableCredentials)) + for k, v := range e.availableCredentials { + res[k] = string(v) + } + return res +} + +func (e ErrDuplicateCredentials) AvailableOIDCProviders() []string { + return e.availableOIDCProviders +} + +func (e ErrDuplicateCredentials) IdentifierHint() string { + return e.identifierHint +} +func (e ErrDuplicateCredentials) HasHints() bool { + return len(e.availableCredentials) > 0 || len(e.availableOIDCProviders) > 0 || len(e.identifierHint) > 0 +} + func (m *Manager) CreateIdentities(ctx context.Context, identities []*Identity, opts ...ManagerOption) (err error) { ctx, span := m.r.Tracer(ctx).Tracer().Start(ctx, "identity.Manager.CreateIdentities") defer otelx.End(span, &err) diff --git a/identity/manager_test.go b/identity/manager_test.go index f5a29877bb89..800d84590470 100644 --- a/identity/manager_test.go +++ b/identity/manager_test.go @@ -33,10 +33,11 @@ func TestManager(t *testing.T) { extensionSchemaID := testhelpers.UseIdentitySchema(t, conf, "file://./stub/extension.schema.json") conf.MustSet(ctx, config.ViperKeyPublicBaseURL, "https://www.ory.sh/") conf.MustSet(ctx, config.ViperKeyCourierSMTPURL, "smtp://foo@bar@dev.null/") + conf.MustSet(ctx, config.ViperKeySelfServiceRegistrationLoginHints, true) t.Run("case=should fail to create because validation fails", func(t *testing.T) { i := identity.NewIdentity(config.DefaultIdentityTraitsSchemaID) - i.Traits = identity.Traits("{}") + i.Traits = identity.Traits(`{"email":"not an email"}`) require.Error(t, reg.IdentityManager().Create(context.Background(), i)) }) @@ -163,6 +164,132 @@ func TestManager(t *testing.T) { require.Error(t, err) assert.NotContains(t, err.Error(), "\"not an email\" is not valid \"email\"") }) + + t.Run("case=should correctly hint at the duplicate credential", func(t *testing.T) { + createIdentity := func(email string, field string, creds map[identity.CredentialsType]identity.Credentials) *identity.Identity { + i := identity.NewIdentity(config.DefaultIdentityTraitsSchemaID) + i.Traits = identity.Traits(fmt.Sprintf(`{"%s":"%s"}`, field, email)) + i.Credentials = creds + return i + } + + t.Run("case=credential identifier duplicate", func(t *testing.T) { + t.Run("type=password", func(t *testing.T) { + email := uuid.Must(uuid.NewV4()).String() + "@ory.sh" + creds := map[identity.CredentialsType]identity.Credentials{ + identity.CredentialsTypePassword: { + Type: identity.CredentialsTypePassword, + Identifiers: []string{email}, + Config: sqlxx.JSONRawMessage(`{"hashed_password":"$2a$08$.cOYmAd.vCpDOoiVJrO5B.hjTLKQQ6cAK40u8uB.FnZDyPvVvQ9Q."}`), + }, + } + + first := createIdentity(email, "email_creds", creds) + require.NoError(t, reg.IdentityManager().Create(context.Background(), first)) + + second := createIdentity(email, "email_creds", creds) + err := reg.IdentityManager().Create(context.Background(), second) + require.Error(t, err) + + var verr = new(identity.ErrDuplicateCredentials) + assert.ErrorAs(t, err, &verr) + assert.EqualValues(t, []string{identity.CredentialsTypePassword.String()}, verr.AvailableCredentials()) + assert.Len(t, verr.AvailableOIDCProviders(), 0) + assert.Equal(t, verr.IdentifierHint(), email) + }) + + t.Run("type=webauthn", func(t *testing.T) { + email := uuid.Must(uuid.NewV4()).String() + "@ory.sh" + creds := map[identity.CredentialsType]identity.Credentials{ + identity.CredentialsTypeWebAuthn: { + Type: identity.CredentialsTypeWebAuthn, + Identifiers: []string{email}, + Config: sqlxx.JSONRawMessage(`{"credentials": [{"is_passwordless":true}]}`), + }, + } + + first := createIdentity(email, "email_webauthn", creds) + require.NoError(t, reg.IdentityManager().Create(context.Background(), first)) + + second := createIdentity(email, "email_webauthn", nil) + err := reg.IdentityManager().Create(context.Background(), second) + require.Error(t, err) + + var verr = new(identity.ErrDuplicateCredentials) + assert.ErrorAs(t, err, &verr) + assert.EqualValues(t, []string{identity.CredentialsTypeWebAuthn.String()}, verr.AvailableCredentials()) + assert.Len(t, verr.AvailableOIDCProviders(), 0) + assert.Equal(t, verr.IdentifierHint(), email) + }) + }) + + runAddress := func(t *testing.T, field string) { + t.Run("case=password duplicate", func(t *testing.T) { + // This test mimics a case where an existing user with email + password exists, and the + // new user tries to sign up with a verification email (NOT email + password) that matches + // this existing record. Here, the end result is that we want to show the + // user: "Sign up with email foo@bar.com and your password instead." + email := uuid.Must(uuid.NewV4()).String() + "@ory.sh" + creds := map[identity.CredentialsType]identity.Credentials{ + identity.CredentialsTypePassword: { + Type: identity.CredentialsTypePassword, + Identifiers: []string{email}, + Config: sqlxx.JSONRawMessage(`{"hashed_password":"$2a$08$.cOYmAd.vCpDOoiVJrO5B.hjTLKQQ6cAK40u8uB.FnZDyPvVvQ9Q."}`), + }, + } + + first := createIdentity(email, field, creds) + require.NoError(t, reg.IdentityManager().Create(context.Background(), first)) + + second := createIdentity(email, field, nil) + err := reg.IdentityManager().Create(context.Background(), second) + require.Error(t, err) + + var verr = new(identity.ErrDuplicateCredentials) + assert.ErrorAs(t, err, &verr) + assert.EqualValues(t, []string{identity.CredentialsTypePassword.String()}, verr.AvailableCredentials()) + assert.Len(t, verr.AvailableOIDCProviders(), 0) + assert.Equal(t, verr.IdentifierHint(), email) + }) + + t.Run("case=OIDC duplicate", func(t *testing.T) { + // This test mimics a case where user signed up using Social Sign In exists, and the + // new user tries to sign up with a verification email (NOT email + password) that matches + // this existing record (for example by using another social sign in provider. + // Here, the end result is that we want to show "Sign in using google instead". + email := uuid.Must(uuid.NewV4()).String() + "@ory.sh" + creds := map[identity.CredentialsType]identity.Credentials{ + identity.CredentialsTypeOIDC: { + Type: identity.CredentialsTypeOIDC, + // Identifiers in OIDC are not email addresses, but a unique user ID. + Identifiers: []string{"google:" + uuid.Must(uuid.NewV4()).String()}, + Config: sqlxx.JSONRawMessage(`{"providers":[{"provider": "google"},{"provider": "github"}]}`), + }, + } + + first := createIdentity(email, field, creds) + require.NoError(t, reg.IdentityManager().Create(context.Background(), first)) + + second := createIdentity(email, field, nil) + err := reg.IdentityManager().Create(context.Background(), second) + require.Error(t, err) + + var verr = new(identity.ErrDuplicateCredentials) + assert.ErrorAs(t, err, &verr) + assert.EqualValues(t, []string{identity.CredentialsTypeOIDC.String()}, verr.AvailableCredentials()) + assert.EqualValues(t, verr.AvailableOIDCProviders(), []string{"google", "github"}) + assert.Equal(t, verr.IdentifierHint(), email) + }) + } + + t.Run("case=verifiable address", func(t *testing.T) { + runAddress(t, "email_verify") + }) + + t.Run("case=recovery address", func(t *testing.T) { + runAddress(t, "email_recovery") + }) + }) }) t.Run("method=Update", func(t *testing.T) { diff --git a/identity/stub/manager.schema.json b/identity/stub/manager.schema.json index 1d3bad2a9089..2b7b6ef2aba1 100644 --- a/identity/stub/manager.schema.json +++ b/identity/stub/manager.schema.json @@ -29,6 +29,17 @@ } } }, + "email_webauthn": { + "type": "string", + "format": "email", + "ory.sh/kratos": { + "credentials": { + "webauthn": { + "identifier": true + } + } + } + }, "email_verify": { "type": "string", "format": "email", @@ -52,7 +63,6 @@ } }, "required": [ - "email" ] } }, diff --git a/schema/errors.go b/schema/errors.go index 46dab14bcb83..68683d369a06 100644 --- a/schema/errors.go +++ b/schema/errors.go @@ -5,6 +5,10 @@ package schema import ( "fmt" + "strings" + + "golang.org/x/text/cases" + "golang.org/x/text/language" "github.com/pkg/errors" @@ -123,13 +127,72 @@ func NewInvalidCredentialsError() error { }) } -type ValidationErrorContextDuplicateCredentialsError struct{} +type ValidationErrorContextDuplicateCredentialsError struct { + AvailableCredentials []string `json:"available_credential_types"` + AvailableOIDCProviders []string `json:"available_oidc_providers"` + IdentifierHint string `json:"credential_identifier_hint"` +} func (r *ValidationErrorContextDuplicateCredentialsError) AddContext(_, _ string) {} func (r *ValidationErrorContextDuplicateCredentialsError) FinishInstanceContext() {} -func NewDuplicateCredentialsError() error { +type DuplicateCredentialsHinter interface { + AvailableCredentials() []string + AvailableOIDCProviders() []string + IdentifierHint() string + HasHints() bool +} + +func NewDuplicateCredentialsError(err error) error { + if hinter := DuplicateCredentialsHinter(nil); errors.As(err, &hinter) && hinter.HasHints() { + oidcProviders := make([]string, 0, len(hinter.AvailableOIDCProviders())) + for _, provider := range hinter.AvailableOIDCProviders() { + oidcProviders = append(oidcProviders, cases.Title(language.English).String(provider)) + } + + reason := "" + if hinter.IdentifierHint() != "" { + reason = fmt.Sprintf("You tried signing with %s which is already in use by another account.", hinter.IdentifierHint()) + } else { + reason = "You tried to sign up using an email, phone, or username that is already used by another account." + } + + if len(hinter.AvailableCredentials()) > 0 { + humanReadable := make([]string, 0, len(hinter.AvailableCredentials())) + for _, cred := range hinter.AvailableCredentials() { + switch cred { + case "password": + humanReadable = append(humanReadable, "your password") + case "oidc": + humanReadable = append(humanReadable, "social sign in") + case "webauthn": + humanReadable = append(humanReadable, "your PassKey or a security key") + } + } + + reason = fmt.Sprintf("%s You can sign in using %s.", reason, strings.Join(humanReadable, ", ")) + if len(hinter.AvailableOIDCProviders()) > 0 { + reason = fmt.Sprintf("%s Use one of the following social sign in providers: %s", reason, strings.Join(oidcProviders, ", ")) + } + } else if len(hinter.AvailableOIDCProviders()) > 0 { + reason = fmt.Sprintf("%s You can sign in using one of the following social sign in providers: %s.", reason, strings.Join(oidcProviders, ", ")) + } + + return errors.WithStack(&ValidationError{ + ValidationError: &jsonschema.ValidationError{ + Message: `an account with the same identifier (email, phone, username, ...) exists already`, + InstancePtr: "#/", + Context: &ValidationErrorContextDuplicateCredentialsError{ + AvailableCredentials: hinter.AvailableCredentials(), + AvailableOIDCProviders: hinter.AvailableOIDCProviders(), + IdentifierHint: hinter.IdentifierHint(), + }, + }, + Messages: new(text.Messages).Add(text.NewErrorValidationDuplicateCredentialsWithHints(reason, hinter.AvailableCredentials(), hinter.AvailableOIDCProviders(), hinter.IdentifierHint())), + }) + } + return errors.WithStack(&ValidationError{ ValidationError: &jsonschema.ValidationError{ Message: `an account with the same identifier (email, phone, username, ...) exists already`, diff --git a/selfservice/flow/registration/error.go b/selfservice/flow/registration/error.go index a639d2c20c7d..b3ef3d9054df 100644 --- a/selfservice/flow/registration/error.go +++ b/selfservice/flow/registration/error.go @@ -8,6 +8,7 @@ import ( "go.opentelemetry.io/otel/trace" + "github.com/ory/kratos/identity" "github.com/ory/kratos/schema" "github.com/ory/kratos/selfservice/sessiontokenexchange" "github.com/ory/kratos/ui/node" @@ -25,11 +26,9 @@ import ( ) var ( - ErrHookAbortFlow = errors.New("aborted registration hook execution") - ErrAlreadyLoggedIn = herodot.ErrBadRequest.WithID(text.ErrIDAlreadyLoggedIn).WithError("you are already logged in").WithReason("A valid session was detected and thus registration is not possible.") - ErrRegistrationDisabled = herodot.ErrBadRequest.WithID(text.ErrIDSelfServiceFlowDisabled).WithError("registration flow disabled").WithReason("Registration is not allowed because it was disabled.") - ErrDuplicateCredentials = herodot.ErrBadRequest.WithError(text.NewErrorValidationDuplicateCredentials().Text) - ErrDuplicateCredentialsOnOIDCLink = herodot.ErrBadRequest.WithError(text.NewErrorValidationDuplicateCredentialsOnOIDCLink().Text) + ErrHookAbortFlow = errors.New("aborted registration hook execution") + ErrAlreadyLoggedIn = herodot.ErrBadRequest.WithID(text.ErrIDAlreadyLoggedIn).WithError("you are already logged in").WithReason("A valid session was detected and thus registration is not possible.") + ErrRegistrationDisabled = herodot.ErrBadRequest.WithID(text.ErrIDSelfServiceFlowDisabled).WithError("registration flow disabled").WithReason("Registration is not allowed because it was disabled.") ) type ( @@ -81,8 +80,8 @@ func (s *ErrorHandler) WriteFlowError( err error, ) { - if errors.Is(err, ErrDuplicateCredentials) { - err = schema.NewDuplicateCredentialsError() + if dup := new(identity.ErrDuplicateCredentials); errors.As(err, &dup) { + err = schema.NewDuplicateCredentialsError(dup) } s.d.Audit(). diff --git a/selfservice/flow/registration/hook.go b/selfservice/flow/registration/hook.go index 6a7d7d0f75bf..ee893f86572c 100644 --- a/selfservice/flow/registration/hook.go +++ b/selfservice/flow/registration/hook.go @@ -16,8 +16,6 @@ import ( "github.com/pkg/errors" - "github.com/ory/x/sqlcon" - "github.com/ory/kratos/driver/config" "github.com/ory/kratos/hydra" "github.com/ory/kratos/identity" @@ -145,12 +143,6 @@ func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Reque // We're now creating the identity because any of the hooks could trigger a "redirect" or a "session" which // would imply that the identity has to exist already. } else if err := e.d.IdentityManager().Create(r.Context(), i); err != nil { - if errors.Is(err, sqlcon.ErrUniqueViolation) { - // In this case the user is already registered through another method. - // We handle this case by returning a spcial error that is handled by - // the caller. - return ErrDuplicateCredentials - } return err } diff --git a/selfservice/flow/settings/hook.go b/selfservice/flow/settings/hook.go index 166894d6eb11..91c6b2c5122c 100644 --- a/selfservice/flow/settings/hook.go +++ b/selfservice/flow/settings/hook.go @@ -221,7 +221,7 @@ func (e *HookExecutor) PostSettingsHook(w http.ResponseWriter, r *http.Request, return errors.WithStack(NewFlowNeedsReAuth()) } if errors.Is(err, sqlcon.ErrUniqueViolation) { - return schema.NewDuplicateCredentialsError() + return schema.NewDuplicateCredentialsError(err) } return err } diff --git a/selfservice/strategy/oidc/strategy.go b/selfservice/strategy/oidc/strategy.go index aa296df7e98d..6d43dab936b4 100644 --- a/selfservice/strategy/oidc/strategy.go +++ b/selfservice/strategy/oidc/strategy.go @@ -522,7 +522,7 @@ func (s *Strategy) handleError(w http.ResponseWriter, r *http.Request, f flow.Fl // Reset all nodes to not confuse users. // This is kinda hacky and will probably need to be updated at some point. - if errors.Is(err, registration.ErrDuplicateCredentials) { + if dup := new(identity.ErrDuplicateCredentials); errors.As(err, &dup) { rf.UI.Messages.Add(text.NewErrorValidationDuplicateCredentialsOnOIDCLink()) lf, err := s.registrationToLogin(w, r, rf, provider) if err != nil { diff --git a/selfservice/strategy/password/registration_test.go b/selfservice/strategy/password/registration_test.go index 33bb46c485bf..dacdef8c9ff2 100644 --- a/selfservice/strategy/password/registration_test.go +++ b/selfservice/strategy/password/registration_test.go @@ -45,10 +45,12 @@ func newRegistrationRegistry(t *testing.T) *driver.RegistryDefault { ctx := context.Background() conf, reg := internal.NewFastRegistryWithMocks(t) conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+"."+string(identity.CredentialsTypePassword), map[string]interface{}{"enabled": true}) + conf.MustSet(ctx, config.ViperKeySelfServiceRegistrationLoginHints, true) return reg } func TestRegistration(t *testing.T) { + ctx := context.Background() t.Run("case=registration", func(t *testing.T) { reg := newRegistrationRegistry(t) @@ -300,7 +302,7 @@ func TestRegistration(t *testing.T) { body := testhelpers.SubmitRegistrationForm(t, true, apiClient, publicTS, applyTransform(values, transform), false, http.StatusBadRequest, publicTS.URL+registration.RouteSubmitFlow) - assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "An account with the same identifier (email, phone, username, ...) exists already.", "%s", body) + assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "You tried signing with registration-identifier-8-api-duplicate-"+suffix+" which is already in use by another account. You can sign in using your password.", "%s", body) }) t.Run("type=spa", func(t *testing.T) { @@ -312,7 +314,7 @@ func TestRegistration(t *testing.T) { _ = expectSuccessfulLogin(t, false, true, nil, values) body := registrationhelpers.ExpectValidationError(t, publicTS, conf, "spa", applyTransform(values, transform)) - assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "An account with the same identifier (email, phone, username, ...) exists already.", "%s", body) + assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "You tried signing with registration-identifier-8-spa-duplicate-"+suffix+" which is already in use by another account. You can sign in using your password.", "%s", body) }) t.Run("type=browser", func(t *testing.T) { @@ -324,7 +326,7 @@ func TestRegistration(t *testing.T) { _ = expectSuccessfulLogin(t, false, false, nil, values) body := registrationhelpers.ExpectValidationError(t, publicTS, conf, "browser", applyTransform(values, transform)) - assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "An account with the same identifier (email, phone, username, ...) exists already.", "%s", body) + assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "You tried signing with registration-identifier-8-browser-duplicate-"+suffix+" which is already in use by another account. You can sign in using your password.", "%s", body) }) } diff --git a/selfservice/strategy/webauthn/registration_test.go b/selfservice/strategy/webauthn/registration_test.go index 6c0eda973309..7326cdfd04ab 100644 --- a/selfservice/strategy/webauthn/registration_test.go +++ b/selfservice/strategy/webauthn/registration_test.go @@ -51,6 +51,7 @@ func newRegistrationRegistry(t *testing.T) *driver.RegistryDefault { conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+"."+string(identity.CredentialsTypePassword)+".enabled", true) enableWebAuthn(conf) conf.MustSet(ctx, config.ViperKeyWebAuthnPasswordless, true) + conf.MustSet(ctx, config.ViperKeySelfServiceRegistrationLoginHints, true) return reg } @@ -392,7 +393,7 @@ func TestRegistration(t *testing.T) { actual, _, _ = makeRegistration(t, f, values(email)) assert.Contains(t, gjson.Get(actual, "ui.action").String(), publicTS.URL+registration.RouteSubmitFlow, "%s", actual) registrationhelpers.CheckFormContent(t, []byte(actual), node.WebAuthnRegisterTrigger, "csrf_token", "traits.username") - assert.Equal(t, text.NewErrorValidationDuplicateCredentials().Text, gjson.Get(actual, "ui.messages.0.text").String(), "%s", actual) + assert.Equal(t, "You tried signing with "+email+" which is already in use by another account. You can sign in using your password.", gjson.Get(actual, "ui.messages.0.text").String(), "%s", actual) }) } }) diff --git a/spec/api.json b/spec/api.json index b63ad4a5a91c..2801989f8817 100755 --- a/spec/api.json +++ b/spec/api.json @@ -337,7 +337,7 @@ "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": { + "login_hints": { "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" }, @@ -6828,4 +6828,4 @@ ], "x-forwarded-proto": "string", "x-request-id": "string" -} \ No newline at end of file +} diff --git a/test/e2e/cypress/integration/profiles/email/registration/errors.spec.ts b/test/e2e/cypress/integration/profiles/email/registration/errors.spec.ts index 338ae2ba8156..e4384b3a091d 100644 --- a/test/e2e/cypress/integration/profiles/email/registration/errors.spec.ts +++ b/test/e2e/cypress/integration/profiles/email/registration/errors.spec.ts @@ -1,7 +1,7 @@ // Copyright © 2023 Ory Corp // SPDX-License-Identifier: Apache-2.0 -import { appPrefix, gen } from "../../../../helpers" +import { appPrefix, gen, website } from "../../../../helpers" import { routes as express } from "../../../../helpers/express" import { routes as react } from "../../../../helpers/react" @@ -22,6 +22,10 @@ describe("Registration failures with email profile", () => { before(() => { cy.useConfigProfile(profile) cy.proxy(app) + cy.updateConfigFile((config) => { + config.selfservice.flows.registration.login_hints = true + return config + }) }) beforeEach(() => { @@ -225,6 +229,29 @@ describe("Registration failures with email profile", () => { "must be <= 300 but found 600", ) }) + + it("should show a hint for existing account", () => { + const email = gen.email() + const password = gen.password() + + cy.registerApi({ + email, + password, + fields: { "traits.website": website }, + }) + + cy.get('input[name="traits.email"]').type(email) + cy.get('input[name="password"]').type(password) + cy.get('input[name="traits.website').type(website) + cy.get('input[name="traits.age"]').type(`30`) + cy.submitPasswordForm() + cy.get('[data-testid="ui/message/4000028"]').should( + "contain.text", + "You tried signing with " + + email + + " which is already in use by another account. You can sign in using your password.", + ) + }) }) }) }) diff --git a/test/e2e/cypress/support/config.d.ts b/test/e2e/cypress/support/config.d.ts index 3ee8e8657b91..e2bb5294b91e 100644 --- a/test/e2e/cypress/support/config.d.ts +++ b/test/e2e/cypress/support/config.d.ts @@ -483,6 +483,7 @@ export interface OryKratosConfiguration2 { lifespan?: string before?: SelfServiceBeforeRegistration after?: SelfServiceAfterRegistration + login_hints?: boolean } login?: { ui_url?: LoginUIURL diff --git a/text/id.go b/text/id.go index bb7a85c5279e..f216074e191f 100644 --- a/text/id.go +++ b/text/id.go @@ -121,6 +121,7 @@ const ( ErrorValidationUniqueItems ErrorValidationWrongType ErrorValidationDuplicateCredentialsOnOIDCLink + ErrorValidationDuplicateCredentialsWithHints ) const ( diff --git a/text/message_validation.go b/text/message_validation.go index 0c5cd85b15c0..dc62bf6157f2 100644 --- a/text/message_validation.go +++ b/text/message_validation.go @@ -164,6 +164,19 @@ func NewErrorValidationDuplicateCredentials() *Message { } } +func NewErrorValidationDuplicateCredentialsWithHints(reason string, availableCredentialTypes []string, availableOIDCProviders []string, credentialIdentifierHint string) *Message { + return &Message{ + ID: ErrorValidationDuplicateCredentialsWithHints, + Text: reason, + Type: Error, + Context: context(map[string]interface{}{ + "available_credential_types": availableCredentialTypes, + "available_oidc_providers": availableOIDCProviders, + "credential_identifier_hint": credentialIdentifierHint, + }), + } +} + func NewErrorValidationDuplicateCredentialsOnOIDCLink() *Message { return &Message{ ID: ErrorValidationDuplicateCredentialsOnOIDCLink, From 0ac757867beb1ba9a0affc2e773b5d93920dda0c Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Tue, 15 Aug 2023 15:02:39 +0000 Subject: [PATCH 035/282] autogen(openapi): regenerate swagger spec and internal client [skip ci] --- spec/api.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/api.json b/spec/api.json index 2801989f8817..b63ad4a5a91c 100755 --- a/spec/api.json +++ b/spec/api.json @@ -337,7 +337,7 @@ "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_hints": { + "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" }, @@ -6828,4 +6828,4 @@ ], "x-forwarded-proto": "string", "x-request-id": "string" -} +} \ No newline at end of file From ec85751bb78e83a52f7a360916d222140b9a8d90 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Tue, 15 Aug 2023 16:21:47 +0000 Subject: [PATCH 036/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62c4746e8466..b5619992e0e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -372,6 +372,27 @@ ([e3fcf0c](https://github.com/ory/kratos/commit/e3fcf0c31db9742ed61bcf783e37ee119ed19d42)) - Allow extra migrations in NewPersister ([96c1ff7](https://github.com/ory/kratos/commit/96c1ff7747ea38e23a3892f74b75ee555ed49c88)) +- Provide login hints when registration fails due to duplicate + credentials/addresses ([#3430](https://github.com/ory/kratos/issues/3430)) + ([8b28469](https://github.com/ory/kratos/commit/8b284697e4a26fb01ad57d2e9ebd8f714be49f33)): + + - feat: provide login hints when registration fails due to duplicate + credentials or identifiers + + - feat: identify edge cases and write tests + + - chore: synchronize workspaces + + - feat: make login hints configurable + + - chore: synchronize workspaces + + - chore: synchronize workspaces + + - chore: synchronize workspaces + + - chore: synchronize workspaces + - Support multiple origins for WebAuthN ([#3380](https://github.com/ory/kratos/issues/3380)) ([013f335](https://github.com/ory/kratos/commit/013f335881831bbf90ac31b219b57118fc089fe6)): From 09bcb71f1f0b3238e2d0f4376a1a2290d062c6c1 Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Wed, 16 Aug 2023 08:11:49 +0200 Subject: [PATCH 037/282] fix: add missing tracing & attributes in oidc strategy (#3429) --- persistence/sql/persister_errorx.go | 3 +++ selfservice/strategy/oidc/strategy.go | 33 +++++++++++++++++++-------- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/persistence/sql/persister_errorx.go b/persistence/sql/persister_errorx.go index 04a4a8657a78..15faf9fd163b 100644 --- a/persistence/sql/persister_errorx.go +++ b/persistence/sql/persister_errorx.go @@ -11,6 +11,7 @@ import ( "github.com/gofrs/uuid" "github.com/pkg/errors" + "go.opentelemetry.io/otel/attribute" "github.com/ory/jsonschema/v3" @@ -44,6 +45,8 @@ func (p *Persister) CreateErrorContainer(ctx context.Context, csrfToken string, return uuid.Nil, sqlcon.HandleError(err) } + span.SetAttributes(attribute.String("id", c.ID.String())) + return c.ID, nil } diff --git a/selfservice/strategy/oidc/strategy.go b/selfservice/strategy/oidc/strategy.go index 6d43dab936b4..2639868275c1 100644 --- a/selfservice/strategy/oidc/strategy.go +++ b/selfservice/strategy/oidc/strategy.go @@ -14,9 +14,13 @@ import ( "path/filepath" "strings" + "go.opentelemetry.io/otel/attribute" + "golang.org/x/oauth2" + "github.com/ory/kratos/cipher" "github.com/ory/kratos/selfservice/sessiontokenexchange" "github.com/ory/x/jsonnetsecure" + "github.com/ory/x/otelx" "github.com/ory/kratos/text" @@ -396,16 +400,7 @@ func (s *Strategy) handleCallback(w http.ResponseWriter, r *http.Request, ps htt return } - te, ok := provider.(TokenExchanger) - if !ok { - te, err = provider.OAuth2(r.Context()) - if err != nil { - s.forwardError(w, r, req, s.handleError(w, r, req, pid, nil, err)) - return - } - } - - token, err := te.Exchange(r.Context(), code) + token, err := s.ExchangeCode(r.Context(), provider, code) if err != nil { s.forwardError(w, r, req, s.handleError(w, r, req, pid, nil, err)) return @@ -460,6 +455,24 @@ func (s *Strategy) handleCallback(w http.ResponseWriter, r *http.Request, ps htt } } +func (s *Strategy) ExchangeCode(ctx context.Context, provider Provider, code string) (token *oauth2.Token, err error) { + ctx, span := s.d.Tracer(ctx).Tracer().Start(ctx, "strategy.oidc.ExchangeCode") + defer otelx.End(span, &err) + span.SetAttributes(attribute.String("provider_id", provider.Config().ID)) + span.SetAttributes(attribute.String("provider_label", provider.Config().Label)) + + te, ok := provider.(TokenExchanger) + if !ok { + te, err = provider.OAuth2(ctx) + if err != nil { + return nil, err + } + } + + token, err = te.Exchange(ctx, code) + return token, err +} + func (s *Strategy) populateMethod(r *http.Request, c *container.Container, message func(provider string) *text.Message) error { conf, err := s.Config(r.Context()) if err != nil { From 157d9345aeb04f371f9d85b70c89e8646e781333 Mon Sep 17 00:00:00 2001 From: Patrik Date: Wed, 16 Aug 2023 08:12:15 +0200 Subject: [PATCH 038/282] feat: hot-reload CORS origins (#3423) --- cmd/daemon/serve.go | 26 +- driver/config/config.go | 1 + driver/config/config_test.go | 28 +- driver/config/schema.go | 4 - go.mod | 54 +- go.sum | 634 +----- test/e2e/hydra-kratos-login-consent/go.mod | 4 +- test/e2e/hydra-kratos-login-consent/go.sum | 2211 ++++++++++++++----- test/e2e/hydra-login-consent/go.mod | 2 +- test/e2e/hydra-login-consent/go.sum | 2224 +++++++++++++++----- 10 files changed, 3429 insertions(+), 1759 deletions(-) delete mode 100644 driver/config/schema.go diff --git a/cmd/daemon/serve.go b/cmd/daemon/serve.go index f4eceda0e329..c58afcda76b7 100644 --- a/cmd/daemon/serve.go +++ b/cmd/daemon/serve.go @@ -9,10 +9,11 @@ import ( "net/http" "time" + "github.com/rs/cors" + "github.com/ory/x/otelx/semconv" "github.com/pkg/errors" - "github.com/rs/cors" "github.com/spf13/cobra" "github.com/urfave/negroni" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" @@ -68,7 +69,7 @@ func WithContext(ctx stdctx.Context) Option { } } -func ServePublic(r driver.Registry, cmd *cobra.Command, args []string, slOpts *servicelocatorx.Options, opts []Option) error { +func ServePublic(r driver.Registry, cmd *cobra.Command, _ []string, slOpts *servicelocatorx.Options, opts []Option) error { modifiers := NewOptions(cmd.Context(), opts) ctx := modifiers.ctx @@ -99,6 +100,16 @@ func ServePublic(r driver.Registry, cmd *cobra.Command, args []string, slOpts *s router := x.NewRouterPublic() csrf := x.NewCSRFHandler(router, r) + // we need to always load the CORS middleware even if it is disabled, to allow hot-enabling CORS + n.UseFunc(func(w http.ResponseWriter, req *http.Request, next http.HandlerFunc) { + cfg, enabled := r.Config().CORS(req.Context(), "public") + if !enabled { + next(w, req) + return + } + cors.New(cfg).ServeHTTP(w, req, next) + }) + n.UseFunc(x.CleanPath) // Prevent double slashes from breaking CSRF. r.WithCSRFHandler(csrf) n.UseHandler(r.CSRFHandler()) @@ -112,14 +123,9 @@ func ServePublic(r driver.Registry, cmd *cobra.Command, args []string, slOpts *s r.RegisterPublicRoutes(ctx, router) r.PrometheusManager().RegisterRouter(router.Router) - var handler http.Handler = n - options, enabled := r.Config().CORS(ctx, "public") - if enabled { - handler = cors.New(options).Handler(handler) - } - certs := c.GetTLSCertificatesForPublic(ctx) + var handler http.Handler = n if tracer := r.Tracer(ctx); tracer.IsLoaded() { handler = otelx.TraceHandler(handler, otelhttp.WithTracerProvider(tracer.Provider())) } @@ -152,7 +158,7 @@ func ServePublic(r driver.Registry, cmd *cobra.Command, args []string, slOpts *s return nil } -func ServeAdmin(r driver.Registry, cmd *cobra.Command, args []string, slOpts *servicelocatorx.Options, opts []Option) error { +func ServeAdmin(r driver.Registry, cmd *cobra.Command, _ []string, slOpts *servicelocatorx.Options, opts []Option) error { modifiers := NewOptions(cmd.Context(), opts) ctx := modifiers.ctx @@ -299,7 +305,7 @@ func sqa(ctx stdctx.Context, cmd *cobra.Command, d driver.Registry) *metricsx.Se ) } -func bgTasks(d driver.Registry, cmd *cobra.Command, args []string, slOpts *servicelocatorx.Options, opts []Option) error { +func bgTasks(d driver.Registry, cmd *cobra.Command, _ []string, _ *servicelocatorx.Options, opts []Option) error { modifiers := NewOptions(cmd.Context(), opts) ctx := modifiers.ctx diff --git a/driver/config/config.go b/driver/config/config.go index cc3c997ab493..1a0b76c6eb90 100644 --- a/driver/config/config.go +++ b/driver/config/config.go @@ -342,6 +342,7 @@ func New(ctx context.Context, l *logrusx.Logger, stdOutOrErr io.Writer, opts ... configx.WithStderrValidationReporter(), configx.OmitKeysFromTracing("dsn", "courier.smtp.connection_uri", "secrets.default", "secrets.cookie", "secrets.cipher", "client_secret"), configx.WithImmutables("serve", "profiling", "log"), + configx.WithExceptImmutables("serve.public.cors.allowed_origins"), configx.WithLogrusWatcher(l), configx.WithLogger(l), configx.WithContext(ctx), diff --git a/driver/config/config_test.go b/driver/config/config_test.go index 95cd4e6c70bb..13a16d7e48fe 100644 --- a/driver/config/config_test.go +++ b/driver/config/config_test.go @@ -46,9 +46,9 @@ import ( ) func TestViperProvider(t *testing.T) { + t.Parallel() ctx, cancel := context.WithCancel(context.Background()) t.Cleanup(cancel) - t.Parallel() t.Run("suite=loaders", func(t *testing.T) { p := config.MustNew(t, logrusx.New("", ""), os.Stderr, @@ -397,6 +397,7 @@ func TestViperProvider(t *testing.T) { } func TestBcrypt(t *testing.T) { + t.Parallel() ctx := context.Background() p := config.MustNew(t, logrusx.New("", ""), os.Stderr, configx.SkipValidation()) @@ -409,6 +410,7 @@ func TestBcrypt(t *testing.T) { } func TestProviderBaseURLs(t *testing.T) { + t.Parallel() ctx := context.Background() machineHostname, err := os.Hostname() if err != nil { @@ -436,6 +438,7 @@ func TestProviderBaseURLs(t *testing.T) { } func TestProviderSelfServiceLinkMethodBaseURL(t *testing.T) { + t.Parallel() ctx := context.Background() machineHostname, err := os.Hostname() if err != nil { @@ -450,6 +453,7 @@ func TestProviderSelfServiceLinkMethodBaseURL(t *testing.T) { } func TestViperProvider_Secrets(t *testing.T) { + t.Parallel() ctx := context.Background() p := config.MustNew(t, logrusx.New("", ""), os.Stderr, configx.SkipValidation()) @@ -464,6 +468,7 @@ func TestViperProvider_Secrets(t *testing.T) { } func TestViperProvider_Defaults(t *testing.T) { + t.Parallel() ctx := context.Background() l := logrusx.New("", "") @@ -573,6 +578,7 @@ func TestViperProvider_Defaults(t *testing.T) { } func TestViperProvider_ReturnTo(t *testing.T) { + t.Parallel() ctx := context.Background() l := logrusx.New("", "") p := config.MustNew(t, l, os.Stderr, configx.SkipValidation()) @@ -589,6 +595,7 @@ func TestViperProvider_ReturnTo(t *testing.T) { } func TestSession(t *testing.T) { + t.Parallel() ctx := context.Background() l := logrusx.New("", "") p := config.MustNew(t, l, os.Stderr, configx.SkipValidation()) @@ -615,6 +622,7 @@ func TestSession(t *testing.T) { } func TestCookies(t *testing.T) { + t.Parallel() ctx := context.Background() l := logrusx.New("", "") p := config.MustNew(t, l, os.Stderr, configx.SkipValidation()) @@ -660,6 +668,7 @@ func TestCookies(t *testing.T) { } func TestViperProvider_DSN(t *testing.T) { + t.Parallel() ctx := context.Background() t.Run("case=dsn: memory", func(t *testing.T) { @@ -693,6 +702,8 @@ func TestViperProvider_DSN(t *testing.T) { } func TestViperProvider_ParseURIOrFail(t *testing.T) { + t.Parallel() + ctx := context.Background() var exitCode int @@ -750,6 +761,8 @@ func TestViperProvider_ParseURIOrFail(t *testing.T) { } func TestViperProvider_HaveIBeenPwned(t *testing.T) { + t.Parallel() + ctx := context.Background() p := config.MustNew(t, logrusx.New("", ""), os.Stderr, configx.SkipValidation()) t.Run("case=hipb: host", func(t *testing.T) { @@ -794,8 +807,8 @@ func newTestConfig(t *testing.T) (_ *config.Config, _ *test.Hook, exited *bool) } func TestLoadingTLSConfig(t *testing.T) { - ctx := context.Background() t.Parallel() + ctx := context.Background() certPath, keyPath, certBase64, keyBase64 := testhelpers.GenerateTLSCertificateFilesForTests(t) @@ -888,6 +901,7 @@ func TestLoadingTLSConfig(t *testing.T) { } func TestIdentitySchemaValidation(t *testing.T) { + t.Parallel() files := []string{"stub/.identity.test.json", "stub/.identity.other.json"} ctx := context.Background() @@ -1061,6 +1075,7 @@ func TestIdentitySchemaValidation(t *testing.T) { } func TestPasswordless(t *testing.T) { + t.Parallel() ctx := context.Background() conf, err := config.New(ctx, logrusx.New("", ""), os.Stderr, @@ -1074,6 +1089,7 @@ func TestPasswordless(t *testing.T) { } func TestChangeMinPasswordLength(t *testing.T) { + t.Parallel() t.Run("case=must fail on minimum password length below enforced minimum", func(t *testing.T) { ctx := context.Background() @@ -1096,6 +1112,7 @@ func TestChangeMinPasswordLength(t *testing.T) { } func TestCourierEmailHTTP(t *testing.T) { + t.Parallel() ctx := context.Background() t.Run("case=configs set", func(t *testing.T) { @@ -1113,6 +1130,7 @@ func TestCourierEmailHTTP(t *testing.T) { } func TestCourierSMS(t *testing.T) { + t.Parallel() ctx := context.Background() t.Run("case=configs set", func(t *testing.T) { @@ -1133,6 +1151,7 @@ func TestCourierSMS(t *testing.T) { } func TestCourierSMTPUrl(t *testing.T) { + t.Parallel() ctx := context.Background() for _, tc := range []string{ @@ -1161,6 +1180,7 @@ func TestCourierSMTPUrl(t *testing.T) { } func TestCourierMessageTTL(t *testing.T) { + t.Parallel() ctx := context.Background() t.Run("case=configs set", func(t *testing.T) { @@ -1176,6 +1196,7 @@ func TestCourierMessageTTL(t *testing.T) { } func TestOAuth2Provider(t *testing.T) { + t.Parallel() ctx := context.Background() t.Run("case=configs set", func(t *testing.T) { @@ -1195,6 +1216,7 @@ func TestOAuth2Provider(t *testing.T) { } func TestWebauthn(t *testing.T) { + t.Parallel() ctx := context.Background() t.Run("case=multiple origins", func(t *testing.T) { @@ -1240,6 +1262,7 @@ func TestWebauthn(t *testing.T) { } func TestCourierTemplatesConfig(t *testing.T) { + t.Parallel() ctx := context.Background() t.Run("case=partial template update allowed", func(t *testing.T) { @@ -1294,6 +1317,7 @@ func TestCourierTemplatesConfig(t *testing.T) { } func TestCleanup(t *testing.T) { + t.Parallel() ctx := context.Background() p := config.MustNew(t, logrusx.New("", ""), os.Stderr, diff --git a/driver/config/schema.go b/driver/config/schema.go deleted file mode 100644 index 612cea9931d7..000000000000 --- a/driver/config/schema.go +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright © 2023 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -package config diff --git a/go.mod b/go.mod index e1e44a675583..b02a682e7151 100644 --- a/go.mod +++ b/go.mod @@ -71,12 +71,12 @@ require ( github.com/ory/dockertest/v3 v3.9.1 github.com/ory/go-acc v0.2.9-0.20230103102148-6b1c9a70dbbe github.com/ory/graceful v0.1.4-0.20230301144740-e222150c51d0 - github.com/ory/herodot v0.10.2 + github.com/ory/herodot v0.10.3-0.20230626083119-d7e5192f0d88 github.com/ory/hydra-client-go/v2 v2.0.3 github.com/ory/jsonschema/v3 v3.0.8 github.com/ory/mail/v3 v3.0.0 github.com/ory/nosurf v1.2.7 - github.com/ory/x v0.0.562 + github.com/ory/x v0.0.580 github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 github.com/pkg/errors v0.9.1 github.com/pquerna/otp v1.4.0 @@ -105,8 +105,6 @@ require ( ) require ( - cloud.google.com/go/compute v1.19.0 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver v1.5.0 // indirect @@ -121,22 +119,14 @@ require ( github.com/avast/retry-go/v4 v4.3.0 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bgentry/speakeasy v0.1.0 // indirect github.com/bmatcuk/doublestar v1.3.4 // indirect github.com/boombuler/barcode v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.2.0 // indirect - github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/cloudflare/cfssl v1.6.1 // indirect - github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe // indirect - github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b // indirect github.com/cockroachdb/cockroach-go/v2 v2.2.16 // indirect github.com/containerd/continuity v0.3.0 // indirect - github.com/coreos/go-semver v0.3.0 // indirect - github.com/coreos/go-systemd/v22 v22.3.2 // indirect github.com/cortesi/moddwatch v0.0.0-20210222043437-a6aaad86a36e // indirect github.com/cortesi/termlog v0.0.0-20210222042314-a1eec763abec // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/docker/cli v20.10.21+incompatible // indirect github.com/docker/distribution v2.8.2+incompatible // indirect github.com/docker/docker v20.10.24+incompatible // indirect @@ -144,17 +134,12 @@ require ( github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.0 // indirect github.com/elliotchance/orderedmap v1.4.0 // indirect - github.com/envoyproxy/go-control-plane v0.10.3 // indirect - github.com/envoyproxy/protoc-gen-validate v0.9.1 // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/fatih/structs v1.1.0 // indirect github.com/felixge/fgprof v0.9.3 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect - github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/fullstorydev/grpcurl v1.8.1 // indirect github.com/fxamacker/cbor/v2 v2.4.0 // indirect - github.com/go-bindata/go-bindata v3.1.2+incompatible // indirect github.com/go-crypt/x v0.2.1 // indirect github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -184,10 +169,8 @@ require ( github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/glog v1.0.0 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/btree v1.0.1 // indirect - github.com/google/certificate-transparency-go v1.1.2-0.20210511102531-373a877eec92 // indirect github.com/google/go-querystring v1.0.0 // indirect github.com/google/go-tpm v0.9.0 // indirect github.com/google/pprof v0.0.0-20221010195024-131d412537ea // indirect @@ -200,9 +183,7 @@ require ( github.com/gorilla/pat v1.0.1 // indirect github.com/gorilla/securecookie v1.1.1 // indirect github.com/gorilla/websocket v1.5.0 // indirect - github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect - github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.12.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-hclog v1.2.0 // indirect @@ -226,12 +207,9 @@ require ( github.com/jackc/pgx/v4 v4.17.2 // indirect github.com/jandelgado/gcov2lcov v1.0.5 // indirect github.com/jessevdk/go-flags v1.5.0 // indirect - github.com/jhump/protoreflect v1.8.2 // indirect github.com/jinzhu/copier v0.3.5 // indirect github.com/joho/godotenv v1.4.0 // indirect - github.com/jonboulle/clockwork v0.2.2 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/knadh/koanf/maps v0.1.1 // indirect github.com/knadh/koanf/parsers/toml v0.1.0 // indirect @@ -253,7 +231,6 @@ require ( github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.16 // indirect - github.com/mattn/go-runewidth v0.0.12 // indirect github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/microcosm-cc/bluemonday v1.0.21 // indirect @@ -262,12 +239,9 @@ require ( github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect github.com/nyaruka/phonenumbers v1.1.6 // indirect github.com/ogier/pflag v0.0.1 // indirect github.com/oklog/ulid v1.3.1 // indirect - github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc2 // indirect github.com/opencontainers/runc v1.1.5 // indirect @@ -282,15 +256,14 @@ require ( github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect - github.com/rivo/uniseg v0.2.0 // indirect github.com/rjeczalik/notify v0.0.0-20181126183243-629144ba06a1 // indirect github.com/rogpeppe/go-internal v1.9.0 // indirect - github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/seatgeek/logrus-gelf-formatter v0.0.0-20210414080842-5b05eb8ff761 // indirect github.com/segmentio/backo-go v1.0.1 // indirect github.com/sergi/go-diff v1.2.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect - github.com/soheilhy/cmux v0.1.5 // indirect + github.com/smartystreets/assertions v1.0.0 // indirect + github.com/smartystreets/goconvey v1.6.4 // indirect github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d // indirect github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e // indirect github.com/spf13/afero v1.9.5 // indirect @@ -304,26 +277,12 @@ require ( github.com/timtadh/data-structures v0.5.3 // indirect github.com/timtadh/lexmachine v0.2.2 // indirect github.com/tinylib/msgp v1.1.8 // indirect - github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 // indirect github.com/toqueteos/webbrowser v1.2.0 // indirect - github.com/urfave/cli v1.22.5 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect - github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect - go.etcd.io/bbolt v1.3.5 // indirect - go.etcd.io/etcd/api/v3 v3.5.6 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.6 // indirect - go.etcd.io/etcd/client/v2 v2.305.6 // indirect - go.etcd.io/etcd/client/v3 v3.5.6 // indirect - go.etcd.io/etcd/etcdctl/v3 v3.5.0-alpha.0 // indirect - go.etcd.io/etcd/pkg/v3 v3.5.0-alpha.0 // indirect - go.etcd.io/etcd/raft/v3 v3.5.0-alpha.0 // indirect - go.etcd.io/etcd/server/v3 v3.5.0-alpha.0 // indirect - go.etcd.io/etcd/tests/v3 v3.5.0-alpha.0 // indirect - go.etcd.io/etcd/v3 v3.5.0-alpha.0 // indirect go.mongodb.org/mongo-driver v1.10.3 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.36.4 // indirect go.opentelemetry.io/contrib/propagators/b3 v1.11.1 // indirect @@ -337,15 +296,11 @@ require ( go.opentelemetry.io/otel/metric v0.33.0 // indirect go.opentelemetry.io/otel/sdk v1.11.1 // indirect go.opentelemetry.io/proto/otlp v0.18.0 // indirect - go.uber.org/atomic v1.10.0 // indirect - go.uber.org/multierr v1.8.0 // indirect - go.uber.org/zap v1.21.0 // indirect golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect golang.org/x/mod v0.10.0 // indirect golang.org/x/sys v0.10.0 // indirect golang.org/x/term v0.10.0 // indirect golang.org/x/text v0.11.0 // indirect - golang.org/x/time v0.1.0 // indirect golang.org/x/tools v0.7.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/appengine v1.6.7 // indirect @@ -353,7 +308,6 @@ require ( google.golang.org/protobuf v1.30.0 // indirect gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect - gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 // indirect gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 // indirect diff --git a/go.sum b/go.sum index ba9c3f08b0ba..4362b761c20b 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,6 @@ -bazil.org/fuse v0.0.0-20180421153158-65cc252bf669/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= -bitbucket.org/creachadair/shell v0.0.6/go.mod h1:8Qqi/cYk7vPnsOePHroKXDJYmb5x7ENhtiFtfZq8K+M= -bitbucket.org/liamstask/goose v0.0.0-20150115234039-8488cc47d90c/go.mod h1:hSVuE3qU7grINVSwrmzHfpg9k87ALBk+XaualNyUzI4= 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.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= @@ -21,69 +17,36 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.19.0 h1:+9zda3WGgW1ZSTlVppLCYFIr48Pa35q1uG2N1itbCEQ= -cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/spanner v1.17.0/go.mod h1:+17t2ixFwRG4lWRwE+5kipDR9Ef07Jkmc8z0IbMDKUs= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -code.gitea.io/sdk/gitea v0.11.3/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY= -contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA= -contrib.go.opencensus.io/exporter/ocagent v0.5.0/go.mod h1:ImxhfLRpxoYiSq891pBrLVhN+qmP8BTVvdH2YLs7Gl0= -contrib.go.opencensus.io/exporter/stackdriver v0.12.1/go.mod h1:iwB6wGarfphGGe/e5CWqyUk/cLzKnWsOKPVW3no6OTw= -contrib.go.opencensus.io/exporter/stackdriver v0.13.5/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc= -contrib.go.opencensus.io/integrations/ocsql v0.1.4/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE= -contrib.go.opencensus.io/resource v0.1.1/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Azure/azure-amqp-common-go/v2 v2.1.0/go.mod h1:R8rea+gJRuJR6QxTir/XuEd+YuKoUiazDC/N96FiDEU= -github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= -github.com/Azure/azure-sdk-for-go v29.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go v30.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-service-bus-go v0.9.1/go.mod h1:yzBx6/BUGfjfeqbRZny9AQIbIe3AcV9WZbAdpkoXOa0= -github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= -github.com/Azure/go-autorest v12.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= -github.com/GeertJohan/go.rice v1.0.2/go.mod h1:af5vUNlDNkCjOZeSGFgIJxDje9qdjsO6hshx0gTmZt4= -github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20191009163259-e802c2cb94ae/go.mod h1:mjwGPas4yKduTyubHvD1Atl9r1rUq8DfVy+gkVvZ+oo= -github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= -github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/Masterminds/sprig v2.15.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= -github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8= github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= @@ -93,17 +56,10 @@ github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= -github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/a8m/envsubst v1.3.0 h1:GmXKmVssap0YtlU3E230W98RWtWCyIZzjtf1apWWyAg= github.com/a8m/envsubst v1.3.0/go.mod h1:MVUTQNGQ3tsjOOtKCNd+fl8RzhsXcDvvAEzkhGtlsbY= github.com/aeneasr/cupaloy/v2 v2.6.1-0.20210924214125-3dfdd01210a3 h1:/SkiUr3JJzun9QN9cpUVCPri2ZwOFJ3ani+F3vdoCiY= github.com/aeneasr/cupaloy/v2 v2.6.1-0.20210924214125-3dfdd01210a3/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0= -github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= -github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= -github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -112,27 +68,15 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15 h1:AUNCr9CiJuwrRYS3XieqF+Z9B9gNxo/eANAJCF2eiN4= github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ= -github.com/apache/beam v2.28.0+incompatible/go.mod h1:/8NX3Qi8vGstDLLaeaU7+lzVEu/ACaQhYjeefzQ0y1o= -github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/apex/log v1.1.4/go.mod h1:AlpoD9aScyQfJDVHmLMEcx4oU6LqzkWp4Mg9GdAcEvQ= -github.com/apex/logs v0.0.4/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= -github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE= -github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.4.0 h1:yCQqn7dwca4ITXb+CbubHmedzaQYHhNhrEXLYUeEe8Q= github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= @@ -140,28 +84,13 @@ github.com/avast/retry-go/v3 v3.1.1 h1:49Scxf4v8PmiQ/nY0aY3p0hDueqSmc7++cBbtiDGu github.com/avast/retry-go/v3 v3.1.1/go.mod h1:6cXRK369RpzFL3UQGqIUp9Q7GDrams+KsYWrfNA1/nQ= github.com/avast/retry-go/v4 v4.3.0 h1:cqI48aXx0BExKoM7XPklDpoHAg7/srPPLAfWG5z62jo= github.com/avast/retry-go/v4 v4.3.0/go.mod h1:bqOlT4nxk4phk9buiQFaghzjpqdchOSwPgjdfdQBtdg= -github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= -github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= -github.com/aws/aws-sdk-go v1.19.18/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.19.45/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.25.11/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= -github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= -github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= github.com/bmatcuk/doublestar v1.3.4 h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0= github.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= @@ -173,22 +102,11 @@ github.com/bwmarrin/discordgo v0.23.0 h1://ARp8qUrRZvDGMkfAjtcC20WOvsMtTgi+KrdKn github.com/bwmarrin/discordgo v0.23.0/go.mod h1:c1WtWUGN6nREDmzIpyTp/iD3VYt4Fpx+bVyfBG7JE+M= github.com/bxcodec/faker/v3 v3.3.1 h1:G7uldFk+iO/ES7W4v7JlI/WU9FQ6op9VJ15YZlDEhGQ= github.com/bxcodec/faker/v3 v3.3.1/go.mod h1:gF31YgnMSMKgkvl+fyEo1xuSMbEuieyqfeslGYFjneM= -github.com/caarlos0/ctrlc v1.0.0/go.mod h1:CdXpj4rmq0q/1Eb44M9zi2nKB0QraNKuRGYGrrHhcQw= -github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e/go.mod h1:9IOqJGCPMSc6E5ydlp5NIonxObaeu/Iub/X03EKPVYo= -github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= -github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e/go.mod h1:oDpT4efm8tSYHXV5tHSdRvBet/b/QzxZ+XyyPehvm3A= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4= github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= -github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= -github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= -github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d h1:S2NE3iHSwP0XV47EEXL8mWmRdEfGscSJ+7EgePNgt0s= -github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -201,90 +119,49 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= -github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/backoff v0.0.0-20161212185259-647f3cdfc87a/go.mod h1:rzgs2ZOiguV6/NpiDgADjRLPNyZlApIWxKpkT+X8SdY= -github.com/cloudflare/cfssl v1.6.1 h1:aIOUjpeuDJOpWjVJFP2ByplF53OgqG8I1S40Ggdlk3g= -github.com/cloudflare/cfssl v1.6.1/go.mod h1:ENhCj4Z17+bY2XikpxVmTHDg/C2IsG2Q0ZBeXpAqhCk= -github.com/cloudflare/redoctober v0.0.0-20201013214028-99c99a8e7544/go.mod h1:6Se34jNoqrd8bTxrmJB2Bg2aoZ2CdSXonils9NsiNgo= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210322005330-6414d713912e/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk= -github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b h1:ACGZRIr7HsgBKHsueQ1yM4WaVaXh21ynwqsF8M8tXhA= -github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/cockroach-go/v2 v2.2.16 h1:t9dmZuC9J2W8IDQDSIGXmP+fBuEJSsrGXxWQz4cYqBY= github.com/cockroachdb/cockroach-go/v2 v2.2.16/go.mod h1:xZ2VHjUEb/cySv0scXBx7YsBnHtLHkR1+w/w73b5i3M= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5 h1:xD/lrqdvwsc+O2bjSSi3YqY73Ke3LAiSCx49aCesA0E= -github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= -github.com/cockroachdb/errors v1.2.4 h1:Lap807SXTH5tri2TivECb/4abUkMZC9zRoLarvcKDqs= -github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= -github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY= -github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= -github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= -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/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk= github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 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/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= -github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cortesi/modd v0.0.0-20210323234521-b35eddab86cc h1:JPkUs3TdeYIbBy9GTDdez9rBbbl6E9BNRa9jlfEDjnE= github.com/cortesi/modd v0.0.0-20210323234521-b35eddab86cc/go.mod h1:h20oNPW+cbtizAJwm90svrR7HlV7XvSNT5di+GP7SbA= github.com/cortesi/moddwatch v0.0.0-20210222043437-a6aaad86a36e h1:vNbhR09qtq9ELJgvhAWng4zl/4CVTPBPVev3R8MlUYc= github.com/cortesi/moddwatch v0.0.0-20210222043437-a6aaad86a36e/go.mod h1:MUkYRZrwFTHATqCI5tDJRPqmBt9xf3q4+Avfut7kCCE= github.com/cortesi/termlog v0.0.0-20210222042314-a1eec763abec h1:v7D8uHsIKsyjfyhhNdY4qivqN558Ejiq+CDXiUljZ+4= github.com/cortesi/termlog v0.0.0-20210222042314-a1eec763abec/go.mod h1:10Fm2kasJmcKf1FSMQGSWb976sfR29hejNtfS9AydB4= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 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/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= -github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= -github.com/daaku/go.zipexe v1.0.1/go.mod h1:5xWogtqlYnfBXkSB1o9xysukNP9GTvaNkqzUZbt3Bw8= -github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davidrjonas/semver-cli v0.0.0-20190116233701-ee19a9a0dda6 h1:VzPvKOw28XJ77PYwOq5gAqvFB4gk6gst0HxxiW8kfZQ= github.com/davidrjonas/semver-cli v0.0.0-20190116233701-ee19a9a0dda6/go.mod h1:+6FzxsSbK4oEuvdN06Jco8zKB2mQqIB6UduZdd0Zesk= -github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY= github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= -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 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= 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/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= github.com/docker/cli v20.10.21+incompatible h1:qVkgyYUnOLQ98LtXBrwd/duVqPT2X4SHndOuGsfwyhU= github.com/docker/cli v20.10.21+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= @@ -296,34 +173,18 @@ github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5Xh github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.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 v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/elliotchance/orderedmap v1.4.0 h1:wZtfeEONCbx6in1CZyE6bELEt/vFayMvsxqI5SgsR+A= github.com/elliotchance/orderedmap v1.4.0/go.mod h1:wsDwEaX5jEoyhbs7x93zk2H/qv0zwuhg4inXhDkYqys= -github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= -github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.10.3 h1:xdCVXxEe0Y3FQith+0cj2irwZudqGYvecuLB1HtdexY= -github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.3.0-java/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.6.1/go.mod h1:txg5va2Qkip90uYoSKH+nkAAmXrb2j3iq4FLwdrCbXQ= -github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= -github.com/envoyproxy/protoc-gen-validate v0.9.1 h1:PS7VIOgmSVhWUEeZwTe7z7zouA22Cr590PzXKbZHOVY= -github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= -github.com/etcd-io/gofail v0.0.0-20190801230047-ad7f989257ca/go.mod h1:49H/RkXP8pKaZy4h0d+NW16rSLhyVBt4o6VLJbmOqDE= github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -339,31 +200,14 @@ github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNu github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c= -github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= -github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= -github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= -github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/fullstorydev/grpcurl v1.8.0/go.mod h1:Mn2jWbdMrQGJQ8UD62uNyMumT2acsZUCkZIqFxsQf1o= -github.com/fullstorydev/grpcurl v1.8.1 h1:Pp648wlTTg3OKySeqxM5pzh8XF6vLqrm8wRq66+5Xo0= -github.com/fullstorydev/grpcurl v1.8.1/go.mod h1:3BWhvHZwNO7iLXaQlojdg5NA6SxUDePli4ecpK1N7gw= github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88= github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= -github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs= -github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/go-bindata/go-bindata v3.1.2+incompatible h1:5vjJMVhowQdPzjE1LdxyFF7YFTXg5IgGVW4gBr5IbvE= -github.com/go-bindata/go-bindata v3.1.2+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo= github.com/go-crypt/crypt v0.2.9 h1:5gWWTId2Qyqs9ROIsegt5pnqo9wUSRLbhpkR6JSftjg= github.com/go-crypt/crypt v0.2.9/go.mod h1:JjzdTYE2mArb6nBoIvvpF7o46/rK/1pfmlArCRMTFUk= github.com/go-crypt/x v0.2.1 h1:OGw78Bswme9lffCOX6tyuC280ouU5391glsvThMtM5U= @@ -373,10 +217,8 @@ github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm 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-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -434,7 +276,6 @@ github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD87 github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= -github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -444,8 +285,6 @@ github.com/go-swagger/go-swagger v0.30.3/go.mod h1:neDPes8r8PCz2JPvHRDj8BTULLh4V github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013 h1:l9rI6sNaZgNC0LnF3MiE+qTmyBA/tZAg1rtyrGbUMK0= github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/go-webauthn/webauthn v0.0.0-20220330035159-03696f3d4499 h1:jaQHuGKk9NVcfu9VbA7ygslr/7utxdYs47i4osBhZP8= -github.com/go-webauthn/webauthn v0.0.0-20220330035159-03696f3d4499/go.mod h1:UMk1JMDgQDcdI2vQz+WJOIUTSjIq07qSepAVgc93rUc= github.com/go-webauthn/webauthn v0.8.4 h1:/emQ9b9Rj4flWO94Fo8KJeYvZ6VzPywXsmqyDA/WicY= github.com/go-webauthn/webauthn v0.8.4/go.mod h1:ZqEa9OnSCdQf6CJvTWTDCsUcPRi8F3h7XCIDINwbBgI= github.com/go-webauthn/x v0.1.4 h1:sGmIFhcY70l6k7JIDfnjVBiAAFEssga5lXIUXe0GtAs= @@ -505,7 +344,6 @@ github.com/gobuffalo/validate/v3 v3.3.3 h1:o7wkIGSvZBYBd6ChQoLxkz2y1pfmhbI4jNJYh github.com/gobuffalo/validate/v3 v3.3.3/go.mod h1:YC7FsbJ/9hW/VjQdmXPvFqvRis4vrRYFxr69WiNZw6g= github.com/goccy/go-yaml v1.9.6 h1:KhAu1zf9JXnm3vbG49aDE0E5uEBUsM4uwD31/58ZWyI= github.com/goccy/go-yaml v1.9.6/go.mod h1:JubOolP3gh0HpiBc4BLRD4YmjEjHAmIIB2aaXKkTfoE= -github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= @@ -514,31 +352,19 @@ github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRx github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.3.1+incompatible h1:0/KbAdpx3UXAx1kEOWHJeOkpbgRFGHVgv+CFIY7dBJI= github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v4 v4.1.0 h1:XUgk2Ex5veyVFVeLm0xhusUTQybEbexJXrvPNOKkSY0= -github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/gddo v0.0.0-20190904175337-72a348e765d2 h1:xisWqjiKEff2B0KfFYGpCqc3M3zdTz+OHQHRc09FeYk= 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/glog v0.0.0-20210429001901-424d2337a529/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -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/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -546,7 +372,6 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -564,20 +389,14 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/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/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= -github.com/google/certificate-transparency-go v1.1.2-0.20210422104406-9f33727a7a18/go.mod h1:6CKh9dscIRoqc2kC6YUFICHZMT9NrClyPrRVFrdw1QQ= -github.com/google/certificate-transparency-go v1.1.2-0.20210511102531-373a877eec92 h1:806qveZBQtRNHroYHyg6yrsjqBJh9kIB4nfmB8uJnak= -github.com/google/certificate-transparency-go v1.1.2-0.20210511102531-373a877eec92/go.mod h1:kXWPsHVPSKVuxPPG69BRtumCbAW537FydV/GH89oBhM= 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= @@ -586,7 +405,6 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -594,22 +412,16 @@ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8 github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-github/v27 v27.0.1 h1:sSMFSShNn4VnqCqs+qhab6TS3uQc+uVR6TD1bW6MavM= github.com/google/go-github/v27 v27.0.1/go.mod h1:/0Gr8pJ55COkmv+S/yPKCczSkUPIM/LnFyubufRNIS0= -github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM= github.com/google/go-github/v38 v38.1.0 h1:C6h1FkaITcBFK7gAmq4eFzt6gbhEhk7L5z6R3Uva+po= github.com/google/go-github/v38 v38.1.0/go.mod h1:cStvrz/7nFr0FoENgG6GLbp53WaelXucT+BBz/3VKx4= github.com/google/go-jsonnet v0.19.0 h1:G7uJZhi8t1eg5NZ+PZJ3bU0GZ4suYGGy79BCtEswlbM= github.com/google/go-jsonnet v0.19.0/go.mod h1:5JVT33JVCoehdTj5Z2KJq1eIdt3Nb8PCmZ+W5D8U350= -github.com/google/go-licenses v0.0.0-20210329231322-ce1d9163b77d/go.mod h1:+TYOmkVoJOpwnS0wfdsJCV9CoD5nJYsHoFk/0CrTK4M= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/go-replayers/grpcreplay v0.1.0/go.mod h1:8Ig2Idjpr6gifRd6pNVggX6TC1Zw6Jx74AKp7QNH2QE= -github.com/google/go-replayers/httpreplay v0.1.0/go.mod h1:YKZViNhiGgqdBlUbI2MwGpq4pXxNmhJLPHQ7cv2b5no= github.com/google/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk= github.com/google/go-tpm v0.9.0/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47QWKfU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/licenseclassifier v0.0.0-20210325184830-bb04aff29e72/go.mod h1:qsqn2hxC+vURpyBRygGUuinTO42MFRLcsmQ/P8v94+M= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -622,78 +434,47 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= github.com/google/pprof v0.0.0-20221010195024-131d412537ea h1:R3VfsTXMMK4JCWZDdxScmnTzu9n9YRsDvguLis0U/b8= github.com/google/pprof v0.0.0-20221010195024-131d412537ea/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/rpmpack v0.0.0-20191226140753-aa36bfddb3a0/go.mod h1:RaTPr0KUf2K7fnZYLNDrr8rxAamWs3iNywJLtQ2AzBg= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= -github.com/google/trillian v1.3.14-0.20210409160123-c5ea3abd4a41/go.mod h1:1dPv0CUjNQVFEDuAUFhZql16pw/VlPgaX8qj+g5pVzQ= -github.com/google/trillian v1.3.14-0.20210428093031-b4ddea2e86b1/go.mod h1:FdIJX+NoDk/dIN2ZxTyz5nAJWgf+NSSSriPAMThChTY= -github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs16741s= -github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= -github.com/goreleaser/goreleaser v0.134.0/go.mod h1:ZT6Y2rSYa6NxQzIsdfWWNWAlYGXGbreo66NmE+3X3WQ= -github.com/goreleaser/nfpm v1.2.1/go.mod h1:TtWrABZozuLOttX2uDlYyECfQX7x5XYkVxhjYcR6G9w= github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/pat v1.0.1 h1:OeSoj6sffw4/majibAY2BAUsXjNP7fEE+w30KickaL4= github.com/gorilla/pat v1.0.1/go.mod h1:YeAe0gNeiNT5hoiZRI4yiOky6jVdNvfO2N6Kav/HmxY= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= -github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= -github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.9.2/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw= -github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= github.com/grpc-ecosystem/grpc-gateway/v2 v2.12.0 h1:kr3j8iIMR4ywO/O0rvksXaJvauGGCMg2zAZIiNZ9uIQ= github.com/grpc-ecosystem/grpc-gateway/v2 v2.12.0/go.mod h1:ummNFgdgLhhX7aIiy35vVmQNS0rWXknfPE0qe6fmFXg= github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69 h1:7xsUJsB2NrdcttQPa7JLEaGzvdbk7KvfrjgHZXOQRo0= github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69/go.mod h1:YLEMZOtU+AZ7dhN9T/IpGhXVGly2bvkJQ+zxj3WeVQo= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/api v1.18.0 h1:R7PPNzTCeN6VuQNDwwhZWJvzCtGSrNpJqfb22h3yH9g= github.com/hashicorp/consul/api v1.18.0/go.mod h1:owRRGJ9M5xReDC5nfT8FTJrNAPbT4NM6p/k+d03q2v4= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.13.0 h1:lce3nFlpv8humJL8rNrrGHYSKc3q+Kxfeg3Ii1m6ZWU= github.com/hashicorp/consul/sdk v0.13.0/go.mod h1:0hs/l5fOVhJy/VdcoaNqUSi2AUs95eF5WKtv+EYIQqE= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -714,12 +495,9 @@ github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iP github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= -github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0= github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= @@ -730,10 +508,8 @@ github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= -github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= @@ -741,21 +517,14 @@ github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uG github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM= github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= -github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/ian-kent/envconf v0.0.0-20141026121121-c19809918c02 h1:dU8zq210pt1b71X8xh9GOxC7uBHNtQ9BYC+Lb6SA/mA= github.com/ian-kent/envconf v0.0.0-20141026121121-c19809918c02/go.mod h1:1m5fo3aKG2moYtGHC4I2nFkXmG97+vCeaEIWC+mXTSI= github.com/ian-kent/go-log v0.0.0-20160113211217-5731446c36ab h1:OgrFrYWlVzY7Tc8rq7Y4ErlKo28igc70gbfJGTVWTJk= @@ -764,14 +533,9 @@ github.com/ian-kent/goose v0.0.0-20141221090059-c3541ea826ad h1:5UZIY1lPvsBrRQRg github.com/ian-kent/goose v0.0.0-20141221090059-c3541ea826ad/go.mod h1:VHyJj0/IJFmpYvVqWFIN2HgjCatXujj7XaLLyOMC23M= github.com/ian-kent/linkio v0.0.0-20170807205755-97566b872887 h1:LPaZmcRJS13h+igi07S26uKy0qxCa76u1+pArD+JGrY= github.com/ian-kent/linkio v0.0.0-20170807205755-97566b872887/go.mod h1:aE63iKqF9rMrshaEiYZroUYFZLaYoTuA7pBMsg3lJoY= -github.com/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= -github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= -github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= @@ -779,7 +543,6 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf h1:FtEj8sfIcaaBfAKrE1Cwb61YDtYq9JxChK1c7AKce7s= github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf/go.mod h1:yrqSXGoD/4EKfF26AOGzscPOgTTJcyAwM2rpixWT+t4= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= @@ -840,40 +603,25 @@ github.com/jandelgado/gcov2lcov v1.0.5 h1:rkBt40h0CVK4oCb8Dps950gvfd1rYvQ8+cWa34 github.com/jandelgado/gcov2lcov v1.0.5/go.mod h1:NnSxK6TMlg1oGDBfGelGbjgorT5/L3cchlbtgFYZSss= github.com/jarcoal/httpmock v1.0.5 h1:cHtVEcTxRSX4J0je7mWPfc9BpDpqzXSJ5HbymZmyHck= github.com/jarcoal/httpmock v1.0.5/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= -github.com/jhump/protoreflect v1.6.1/go.mod h1:RZQ/lnuN+zqeRVpQigTwO6o0AJUkxbnSnpuG7toUTG4= -github.com/jhump/protoreflect v1.8.2 h1:k2xE7wcUomeqwY0LDCYA16y4WWfyTcMx5mKhk0d4ua0= -github.com/jhump/protoreflect v1.8.2/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg= github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg= github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548/go.mod h1:hGT6jSUVzF6no3QaDSMLGLEHtHSBSefs+MgcDWnmhmo= -github.com/jmoiron/sqlx v1.3.3/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ= github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= -github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= @@ -881,7 +629,6 @@ github.com/jteeuwen/go-bindata v3.0.7+incompatible h1:91Uy4d9SYVr1kyTJ15wJsog+es github.com/jteeuwen/go-bindata v3.0.7+incompatible/go.mod h1:JVvhzYOiGBnFSYRyV00iY8q7/0PThjIYav1p9h5dmKs= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= 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= @@ -889,13 +636,8 @@ github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaR github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= -github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= -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/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE= -github.com/kisom/goutils v1.4.3/go.mod h1:Lp5qrquG7yhYnWzZCI/68Pa/GpFynw//od6EkGnWpac= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs= github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI= @@ -925,31 +667,19 @@ 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/kylelemons/go-gypsy v1.0.0/go.mod h1:chkXM0zjdpXOiqkCW1XcCHDfjfk14PH2KKkQWxfJUcU= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/laher/mergefs v0.1.2-0.20230223191438-d16611b2f4e7 h1:PDeBswTUsSIT4QSrzLvlqKlGrANYa7TrXUwdBN9myU8= github.com/laher/mergefs v0.1.2-0.20230223191438-d16611b2f4e7/go.mod h1:FSY1hYy94on4Tz60waRMGdO1awwS23BacqJlqf9lJ9Q= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= -github.com/letsencrypt/pkcs11key/v4 v4.0.0/go.mod h1:EFUvBDay26dErnNb70Nd0/VW3tJiIbETBPTl9ATXQag= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.10.1/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= -github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/luna-duclos/instrumentedsql v1.1.3 h1:t7mvC0z1jUt5A0UQ6I/0H31ryymuQRnJcWCiqV3lSAA= github.com/luna-duclos/instrumentedsql v1.1.3/go.mod h1:9J1njvFds+zN7y85EDhN9XNQLANWwZt2ULeIC8yMNYs= -github.com/lyft/protoc-gen-star v0.5.1/go.mod h1:9toiA3cC7z5uVbODF7kEQ91Xn7XNFkVUl+SrEe+ZORU= -github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= -github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= -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/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailhog/MailHog v1.0.1 h1:NDExFIj+JGzXT3kmG31r7Okrn78Sk/5p9lP/TV8OE4E= @@ -980,16 +710,13 @@ github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= 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-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= @@ -999,30 +726,19 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.12 h1:Y41i/hVW3Pgwr8gV+J23B9YEY0zxjptBuCWEaxmAOow= -github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= -github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mattn/go-sqlite3 v1.14.7-0.20210414154423-1157a4212dcb h1:ax2vG2unlxsjwS7PMRo4FECIfAdQLowd6ejWYwPQhBo= github.com/mattn/go-sqlite3 v1.14.7-0.20210414154423-1157a4212dcb/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= github.com/mattn/goveralls v0.0.7 h1:vzy0i4a2iDzEFMdXIxcanRadkr0FBvSBKUmj0P8SPlQ= github.com/mattn/goveralls v0.0.7/go.mod h1:h8b4ow6FxSPMQHF6o2ve3qsclnffZjYTNEKmLesRwqw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/microcosm-cc/bluemonday v1.0.20/go.mod h1:yfBmMi8mxvaZut3Yytv+jTXRY8mxyjJ0/kQBTElld50= github.com/microcosm-cc/bluemonday v1.0.21 h1:dNH3e4PSyE4vNX+KlRGHT5KrSvjeUkoNPwEORjffHJg= github.com/microcosm-cc/bluemonday v1.0.21/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/mikefarah/yq/v4 v4.19.1 h1:QrZCqjOBZ918aOZIfl/IwnHBv104SPfarhgO5MGd2W4= github.com/mikefarah/yq/v4 v4.19.1/go.mod h1:krTElh9V1fv3Cw7+21S8El/W/vn3f2buOOcJ4VyjsFY= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -1030,74 +746,41 @@ github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXx github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae h1:O4SWKdcHVCvYqyDV+9CJA1fcDN2L11Bule0iFy3YlAI= github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= -github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007/go.mod h1:m2XC9Qq0AlmmVksL6FktJCdTYyLk7V3fKyp0sl1yWQo= -github.com/mwitkow/go-proto-validators v0.2.0/go.mod h1:ZfA1hW+UH/2ZHOWvQ3HnQaU0DtnpXu850MZiy+YUgcc= -github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= -github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= -github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= -github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= -github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso= -github.com/nkovacs/streamquote v1.0.0/go.mod h1:BN+NaZ2CmdKqUuTUXUEm9j95B2TRbpOWpxbJYzzgUsc= github.com/nyaruka/phonenumbers v1.1.6 h1:DcueYq7QrOArAprAYNoQfDgp0KetO4LqtnBtQC6Wyes= github.com/nyaruka/phonenumbers v1.1.6/go.mod h1:yShPJHDSH3aTKzCbXyVxNpbl2kA+F+Ne5Pun/MvFRos= github.com/ogier/pflag v0.0.1 h1:RW6JSWSu/RkSatfcLtogGfFgpim5p7ARQ10ECk5O750= github.com/ogier/pflag v0.0.1/go.mod h1:zkFki7tvTa0tafRvTBIZTvzYyAu6kQhPZFnshFFPE+g= -github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= -github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= -github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= -github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= -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.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -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.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= @@ -1106,15 +789,7 @@ github.com/opencontainers/runc v1.1.5 h1:L44KXEpKmfWDcS02aeGm8QNTFXTo2D+8MYGDIJ/ github.com/opencontainers/runc v1.1.5/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= -github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= -github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= -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/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= -github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= -github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= -github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.4.1 h1:kNd/ST2yLLWhaWrkgchya40TJabe8Hioj9udfPcEO5A= github.com/openzipkin/zipkin-go v0.4.1/go.mod h1:qY0VqDSN1pOBN94dBc6w2GJlWLiovAyg7Qt6/I9HecM= github.com/ory/analytics-go/v5 v5.0.1 h1:LX8T5B9FN8KZXOtxgN+R3I4THRRVB6+28IKgKBpXmAM= @@ -1125,8 +800,8 @@ github.com/ory/go-acc v0.2.9-0.20230103102148-6b1c9a70dbbe h1:rvu4obdvqR0fkSIJ8I github.com/ory/go-acc v0.2.9-0.20230103102148-6b1c9a70dbbe/go.mod h1:z4n3u6as84LbV4YmgjHhnwtccQqzf4cZlSk9f1FhygI= github.com/ory/graceful v0.1.4-0.20230301144740-e222150c51d0 h1:VMUeLRfQD14fOMvhpYZIIT4vtAqxYh+f3KnSqCeJ13o= github.com/ory/graceful v0.1.4-0.20230301144740-e222150c51d0/go.mod h1:hg2iCy+LCWOXahBZ+NQa4dk8J2govyQD79rrqrgMyY8= -github.com/ory/herodot v0.10.2 h1:gGvNMHgAwWzdP/eo+roSiT5CGssygHSjDU7MSQNlJ4E= -github.com/ory/herodot v0.10.2/go.mod h1:MMNmY6MG1uB6fnXYFaHoqdV23DTWctlPsmRCeq/2+wc= +github.com/ory/herodot v0.10.3-0.20230626083119-d7e5192f0d88 h1:J0CIFKdpUeqKbVMw7pQ1qLtUnflRM1JWAcOEq7Hp4yg= +github.com/ory/herodot v0.10.3-0.20230626083119-d7e5192f0d88/go.mod h1:MMNmY6MG1uB6fnXYFaHoqdV23DTWctlPsmRCeq/2+wc= github.com/ory/hydra-client-go/v2 v2.0.3 h1:jIx968J9RBnjRuaQ21QMLCwZoa28FPvzYWAQ+88XVLw= github.com/ory/hydra-client-go/v2 v2.0.3/go.mod h1:FRuayIF1H/HD2umlad8c3h7RuHpcmsjBDpW0/R2OQ/U= github.com/ory/jsonschema/v3 v3.0.8 h1:Ssdb3eJ4lDZ/+XnGkvQS/te0p+EkolqwTsDOCxr/FmU= @@ -1138,34 +813,20 @@ github.com/ory/nosurf v1.2.7 h1:YrHrbSensQyU6r6HT/V5+HPdVEgrOTMJiLoJABSBOp4= github.com/ory/nosurf v1.2.7/go.mod h1:d4L3ZBa7Amv55bqxCBtCs63wSlyaiCkWVl4vKf3OUxA= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2 h1:zm6sDvHy/U9XrGpixwHiuAwpp0Ock6khSVHkrv6lQQU= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/ory/x v0.0.560 h1:aX05PSW5egp+TMXROTju/h5DG1V5Bh2qhTngEltuALA= -github.com/ory/x v0.0.560/go.mod h1:kup4ebSC4SzwU6KPZJ4G60UR3EEsHxJ0apQVflVw5yQ= -github.com/ory/x v0.0.562 h1:luIC7QLUaslkOHChidP3b79F1OPdNCXW93eRbcOsRCI= -github.com/ory/x v0.0.562/go.mod h1:kup4ebSC4SzwU6KPZJ4G60UR3EEsHxJ0apQVflVw5yQ= -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= -github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= -github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= -github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= +github.com/ory/x v0.0.580 h1:2acv/ORSaAnRGe7wEtWeyrT464o7r+8HC1fZGAb8Ui8= +github.com/ory/x v0.0.580/go.mod h1:zUGmLuqZ81XQPeTBmE1Fhfvr1ygEkDJky33IxvRaioA= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us= github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= -github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= -github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7/go.mod h1:zO8QMzTeZd5cpnIkz/Gn6iK0jDfGicM1nynOkkPIl28= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -1173,12 +834,9 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE 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/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA= github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= -github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= @@ -1188,62 +846,36 @@ github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQ github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg= github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= -github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU= github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= -github.com/prometheus/common v0.24.0/go.mod h1:H6QK/N6XVT42whUeIdI3dp36w49c+/iMDk7UAI2qm7Q= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/pseudomuto/protoc-gen-doc v1.4.1/go.mod h1:exDTOVwqpp30eV/EDPFLZy3Pwr2sn6hBC1WIYH/UbIg= -github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3Q8ViKSAXT0Q= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rjeczalik/notify v0.0.0-20181126183243-629144ba06a1 h1:FLWDC+iIP9BWgYKvWKKtOUZux35LIQNAuIzp/63RQJU= github.com/rjeczalik/notify v0.0.0-20181126183243-629144ba06a1/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= 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= @@ -1252,22 +884,17 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= 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/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/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samber/lo v1.37.0 h1:XjVcB8g6tgUp8rsPsJ2CvhClfImrpL04YpQHXeHPhRw= github.com/samber/lo v1.37.0/go.mod h1:9vaz2O4o8oOnK23pd2TrXufcbdbJIa3b6cstBWKpopA= -github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= -github.com/sassoftware/go-rpmutils v0.0.0-20190420191620-a8f1baeba37b/go.mod h1:am+Fp8Bt506lA3Rk3QCmSqmYmLMnPDhdDUcosQCAx+I= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= @@ -1291,12 +918,10 @@ github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5g github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= 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.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= @@ -1305,63 +930,37 @@ github.com/slack-go/slack v0.7.4/go.mod h1:FGqNzJBmxIsZURAxh2a8D21AnOVvvXZvGligs github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8= github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= -github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/soheilhy/cmux v0.1.5-0.20210205191134-5ec6847320e5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= -github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= -github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= -github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d h1:yKm7XZV6j9Ev6lojP2XaIshpT4ymkqhMeSghO5Ps00E= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e h1:qpG93cPwA5f7s/ZPBJnGOYQNK/vKsaDaseuKT5Asee8= 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.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= -github.com/spf13/afero v1.3.4/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= -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/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= 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 v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= -github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.1/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.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= github.com/sqs/goreturns v0.0.0-20181028201513-538ac6014518 h1:iD+PFTQwKEmbwSdwfvP5ld2WEI/g7qbdhmHJ2ASfYGs= github.com/sqs/goreturns v0.0.0-20181028201513-538ac6014518/go.mod h1:CKI4AZ4XmGV240rTHfO0hfE83S6/a3/Q1siZJ/vXf7A= -github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= -github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= 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/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v0.0.0-20170130113145-4d4bfba8f1d1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -1371,11 +970,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= @@ -1398,42 +994,18 @@ github.com/timtadh/lexmachine v0.2.2 h1:g55RnjdYazm5wnKv59pwFcBJHOyvTPfDEoz21s4P github.com/timtadh/lexmachine v0.2.2/go.mod h1:GBJvD5OAfRn/gnp92zb9KTgHLB7akKyxmVivoYCcjQI= github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0= github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= -github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= -github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0= -github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao= -github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4dN7GR16kFc5fp3d1RIYzJW5onx8Ybykw2YQFA= -github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE= github.com/toqueteos/webbrowser v1.2.0 h1:tVP/gpK69Fx+qMJKsLE7TD8LuGWPnEV71wBN9rrstGQ= github.com/toqueteos/webbrowser v1.2.0/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -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/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= -github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU= -github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= -github.com/weppos/publicsuffix-go v0.13.1-0.20210123135404-5fd73613514e/go.mod h1:HYux0V0Zi04bHNwOHy4cXJVz/TQjYonnF6aoYhj+3QE= -github.com/weppos/publicsuffix-go v0.15.1-0.20210511084619-b1f36a2d6c0b/go.mod h1:HYux0V0Zi04bHNwOHy4cXJVz/TQjYonnF6aoYhj+3QE= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= -github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug= -github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= @@ -1446,10 +1018,6 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= -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 h1:3lbZUMbMiGUW/LMkfsEABsc5zNT9+b1CvsJx47JzJ8g= github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= @@ -1460,58 +1028,20 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 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= -github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= -github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= -github.com/zmap/zcrypto v0.0.0-20210123152837-9cf5beac6d91/go.mod h1:R/deQh6+tSWlgI9tb4jNmXxn8nSCabl5ZQsBX9//I/E= -github.com/zmap/zcrypto v0.0.0-20210511125630-18f1e0152cfc/go.mod h1:FM4U1E3NzlNMRnSUTU3P1UdukWhYGifqEsjk9fn7BCk= -github.com/zmap/zlint/v3 v3.1.0/go.mod h1:L7t8s3sEKkb0A2BxGy1IWrxt1ZATa1R4QfJZaQOD3zU= github.com/zmb3/spotify/v2 v2.0.0 h1:NHW9btztNZTrJ0+3yMNyfY5qcu1ck9s36wwzc7zrCic= github.com/zmb3/spotify/v2 v2.0.0/go.mod h1:+LVh9CafHu7SedyqYmEf12Rd01dIVlEL845yNhksW0E= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0= -go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= -go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= -go.etcd.io/etcd/api/v3 v3.5.0-alpha.0/go.mod h1:mPcW6aZJukV6Aa81LSKpBjQXTWlXB5r74ymPoSWa3Sw= -go.etcd.io/etcd/api/v3 v3.5.6 h1:Cy2qx3npLcYqTKqGJzMypnMv2tiRyifZJ17BlWIWA7A= -go.etcd.io/etcd/api/v3 v3.5.6/go.mod h1:KFtNaxGDw4Yx/BA4iPPwevUTAuqcsPxzyX8PHydchN8= -go.etcd.io/etcd/client/pkg/v3 v3.5.6 h1:TXQWYceBKqLp4sa87rcPs11SXxUA/mHwH975v+BDvLU= -go.etcd.io/etcd/client/pkg/v3 v3.5.6/go.mod h1:ggrwbk069qxpKPq8/FKkQ3Xq9y39kbFR4LnKszpRXeQ= -go.etcd.io/etcd/client/v2 v2.305.0-alpha.0/go.mod h1:kdV+xzCJ3luEBSIeQyB/OEKkWKd8Zkux4sbDeANrosU= -go.etcd.io/etcd/client/v2 v2.305.6 h1:fIDR0p4KMjw01MJMfUIDWdQbjo06PD6CeYM5z4EHLi0= -go.etcd.io/etcd/client/v2 v2.305.6/go.mod h1:BHha8XJGe8vCIBfWBpbBLVZ4QjOIlfoouvOwydu63E0= -go.etcd.io/etcd/client/v3 v3.5.0-alpha.0/go.mod h1:wKt7jgDgf/OfKiYmCq5WFGxOFAkVMLxiiXgLDFhECr8= -go.etcd.io/etcd/client/v3 v3.5.6 h1:coLs69PWCXE9G4FKquzNaSHrRyMCAXwF+IX1tAPVO8E= -go.etcd.io/etcd/client/v3 v3.5.6/go.mod h1:f6GRinRMCsFVv9Ht42EyY7nfsVGwrNO0WEoS2pRKzQk= -go.etcd.io/etcd/etcdctl/v3 v3.5.0-alpha.0 h1:odMFuQQCg0UmPd7Cyw6TViRYv9ybGuXuki4CusDSzqA= -go.etcd.io/etcd/etcdctl/v3 v3.5.0-alpha.0/go.mod h1:YPwSaBciV5G6Gpt435AasAG3ROetZsKNUzibRa/++oo= -go.etcd.io/etcd/pkg/v3 v3.5.0-alpha.0 h1:3yLUEC0nFCxw/RArImOyRUI4OAFbg4PFpBbAhSNzKNY= -go.etcd.io/etcd/pkg/v3 v3.5.0-alpha.0/go.mod h1:tV31atvwzcybuqejDoY3oaNRTtlD2l/Ot78Pc9w7DMY= -go.etcd.io/etcd/raft/v3 v3.5.0-alpha.0 h1:DvYJotxV9q1Lkn7pknzAbFO/CLtCVidCr2K9qRLJ8pA= -go.etcd.io/etcd/raft/v3 v3.5.0-alpha.0/go.mod h1:FAwse6Zlm5v4tEWZaTjmNhe17Int4Oxbu7+2r0DiD3w= -go.etcd.io/etcd/server/v3 v3.5.0-alpha.0 h1:fYv7CmmdyuIu27UmKQjS9K/1GtcCa+XnPKqiKBbQkrk= -go.etcd.io/etcd/server/v3 v3.5.0-alpha.0/go.mod h1:tsKetYpt980ZTpzl/gb+UOJj9RkIyCb1u4wjzMg90BQ= -go.etcd.io/etcd/tests/v3 v3.5.0-alpha.0 h1:UcRoCA1FgXoc4CEM8J31fqEvI69uFIObY5ZDEFH7Znc= -go.etcd.io/etcd/tests/v3 v3.5.0-alpha.0/go.mod h1:HnrHxjyCuZ8YDt8PYVyQQ5d1ZQfzJVEtQWllr5Vp/30= -go.etcd.io/etcd/v3 v3.5.0-alpha.0 h1:ZuqKJkD2HrzFUj8IB+GLkTMKZ3+7mWx172vx6F1TukM= -go.etcd.io/etcd/v3 v3.5.0-alpha.0/go.mod h1:JZ79d3LV6NUfPjUxXrpiFAYcjhT+06qqw+i28snx8To= go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= go.mongodb.org/mongo-driver v1.8.3/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= go.mongodb.org/mongo-driver v1.10.3 h1:XDQEvmh6z1EUsXuIkXE9TaVeqHw6SwS1uf93jFs0HBA= go.mongodb.org/mongo-driver v1.10.3/go.mod h1:z4XpeoU6w+9Vht+jAFyLgVrD+jGSQQe0+CBWFHNiHt8= -go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0= -go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= -go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.36.4 h1:toN8e0U4RWQL4f8H+1eFtaeWe/IkSM3+81qJEDOgShs= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.36.4/go.mod h1:u4OeI4ujQmFbpZOOysLUfYrRWOmEVmvzkM2zExVorXM= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.4 h1:aUEBEdCa6iamGzg6fuYxDA8ThxvOG240mAvWDU+XLio= @@ -1541,71 +1071,44 @@ go.opentelemetry.io/otel/sdk v1.11.1/go.mod h1:/l3FE4SupHJ12TduVjUkZtlfFqDCQJlOl go.opentelemetry.io/otel/trace v1.11.1 h1:ofxdnzsNrGBYXbP7t7zpUK281+go5rF7dvdIZXF8gdQ= go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.18.0 h1:W5hyXNComRa23tGpKwG+FRAc4rfF6ZUg1JReK+QHS80= go.opentelemetry.io/proto/otlp v0.18.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= 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.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= -go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= -go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= -go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= -go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= -gocloud.dev v0.19.0/go.mod h1:SmKwiR8YwIMMJvQBKLsC3fHNyMwXLw3PMDO+VVteJMI= -golang.org/x/crypto v0.0.0-20180501155221-613d6eafa307/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/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-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-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-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-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= -golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220517005047-85d78b3ac167/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= -golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1618,7 +1121,6 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 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/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM= golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= @@ -1634,7 +1136,6 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -1646,37 +1147,26 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/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-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-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-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/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-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191119073136-fc4aabc6c914/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= @@ -1684,7 +1174,6 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL 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-20200421231249-e086a090c8fd/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= @@ -1694,19 +1183,14 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210323141857-08027d57d8cf/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= -golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -1717,14 +1201,10 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/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-20190402181905-9f3314589c9a/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= @@ -1732,11 +1212,7 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-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= golang.org/x/oauth2 v0.0.0-20210810183815-faf39c7919d5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= @@ -1762,15 +1238,9 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1782,20 +1252,16 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190620070143-6f217b454f45/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191119060738-e882bf8e40c2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1807,7 +1273,6 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1817,10 +1282,8 @@ golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201029080932-201ba4db2418/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1828,23 +1291,17 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210412220455-f1c623a9e750/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1863,8 +1320,6 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20191110171634-ad39bd3f0407/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -1875,8 +1330,6 @@ golang.org/x/term v0.0.0-20210317153231-de623e64d2a6/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= -golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1889,22 +1342,13 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= -golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -1914,7 +1358,6 @@ golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3 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-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -1924,19 +1367,15 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/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-20190729092621-ff9f1409240a/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-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191118222007-07fc4c7f2b98/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= @@ -1954,19 +1393,16 @@ golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapK 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-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 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-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200717024301-6ddee64345a6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201014170642-d1624618ad65/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -1975,8 +1411,6 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= @@ -1991,14 +1425,10 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/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.10.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= @@ -2014,30 +1444,19 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.45.0/go.mod h1:ISLIJCedJolbZvDfAk+Ctuq5hf+aJ33WgtUsfyFoLXA= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20181107211654-5fc9ac540362/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-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= -google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601/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= @@ -2054,7 +1473,6 @@ google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfG 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-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= @@ -2070,30 +1488,14 @@ google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210331142528-b7513248f0ba/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210413151531-c14fb6ef47c3/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210510173355-fb37daa5cd7a/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd h1:sLpv7bNL1AsX3fdnWh9WVh7ejIzXdOc1RRHGeAmeStU= google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= -google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= 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.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/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= @@ -2103,24 +1505,16 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag= google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/grpc/examples v0.0.0-20210304020650-930c79186c99 h1:qA8rMbz1wQ4DOFfM2ouD29DG9aHWBm6ZOy9BGxiUMmY= -google.golang.org/grpc/examples v0.0.0-20210304020650-930c79186c99/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= 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= @@ -2131,11 +1525,9 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= @@ -2148,16 +1540,10 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= -gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk= -gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/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/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.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= @@ -2165,16 +1551,9 @@ gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 h1:VpOs+IwYnYBaFnrNAeB8UUWtL3 gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 h1:6D+BvnJ/j6e222UW8s2qTSe3wGBtvo0MbVQG/c5k8RE= gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473/go.mod h1:N1eN2tsCx0Ydtgjl4cqmbRCsY4/+z4cYDeqwZTk6zog= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= -gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= -gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= -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/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -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.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -2197,7 +1576,6 @@ gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= gorm.io/gorm v1.23.5/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.2.0 h1:I0DwBVMGAx26dttAj1BtJLAkVGncrkkUXfJLC4Flt/I= -honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -2205,16 +1583,12 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh 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= -honnef.co/go/tools v0.1.4/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= mvdan.cc/editorconfig v0.1.1-0.20200121172147-e40951bde157/go.mod h1:Ge4atmRUYqueGppvJ7JNrtqpqokoJEFxYbP0Z+WeKS8= mvdan.cc/sh/v3 v3.3.0-0.dev.0.20210224101809-fb5052e7a010 h1:0xJA1YM0Ppa63jEfcdPsjRHo1qxklwXWhIPr9tAQ2J4= mvdan.cc/sh/v3 v3.3.0-0.dev.0.20210224101809-fb5052e7a010/go.mod h1:fPQmabBpREM/XQ9YXSU5ZFZ/Sm+PmKP9/vkFHgYKJEI= -pack.ag/amqp v0.11.2/go.mod h1:4/cbmt4EJXSKlG6LCfWHoqmN0uFdy5i/+YFz+fTfhV4= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= -sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/test/e2e/hydra-kratos-login-consent/go.mod b/test/e2e/hydra-kratos-login-consent/go.mod index 6c589972795e..50ac49304911 100644 --- a/test/e2e/hydra-kratos-login-consent/go.mod +++ b/test/e2e/hydra-kratos-login-consent/go.mod @@ -2,13 +2,11 @@ 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 + github.com/ory/x v0.0.577 ) diff --git a/test/e2e/hydra-kratos-login-consent/go.sum b/test/e2e/hydra-kratos-login-consent/go.sum index c241b3ef328f..54b76d20f1cc 100644 --- a/test/e2e/hydra-kratos-login-consent/go.sum +++ b/test/e2e/hydra-kratos-login-consent/go.sum @@ -1,10 +1,9 @@ -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.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= @@ -15,32 +14,586 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= +cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= +cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= +cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= +cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= +cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/accesscontextmanager v1.7.0/go.mod h1:CEGLewx8dwa33aDAZQujl7Dx+uYhS0eay198wB/VumQ= +cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= +cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= +cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/aiplatform v1.36.1/go.mod h1:WTm12vJRPARNvJ+v6P52RDHCNe4AhvjcIZ/9/RRHy/k= +cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= +cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= +cloud.google.com/go/analytics v0.17.0/go.mod h1:WXFa3WSym4IZ+JiKmavYdJwGG/CvpqiqczmL59bTD9M= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/analytics v0.19.0/go.mod h1:k8liqf5/HCnOUkbawNtrWWc+UAzyDlW89doe8TtoDsE= +cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= +cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= +cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.4.0/go.mod h1:EUG4PGcsZvxOXAdyEghIdXwAEi/4MEaoqLMLDMIwKXY= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apigeeregistry v0.6.0/go.mod h1:BFNzW7yQVLZ3yj0TKcwzb8n25CFBri51GVGOEUcgQsc= +cloud.google.com/go/apikeys v0.4.0/go.mod h1:XATS/yqZbaBK0HOssf+ALHp8jAlNHUgyfprvNcBIszU= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/apikeys v0.6.0/go.mod h1:kbpXu5upyiAlGkKrJgQl8A0rKNNJ7dQ377pdroRSSi8= +cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno= +cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/appengine v1.7.0/go.mod h1:eZqpbHFCqRGa2aCdope7eC0SWLV1j0neb/QnMJVWx6A= +cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= +cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= +cloud.google.com/go/area120 v0.7.0/go.mod h1:a3+8EUD1SX5RUcCs3MY5YasiO1z6yLiNLRiFrykbynY= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= +cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= +cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= +cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc= +cloud.google.com/go/artifactregistry v1.11.1/go.mod h1:lLYghw+Itq9SONbCa1YWBoWs1nOucMH0pwXN1rOBZFI= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/artifactregistry v1.12.0/go.mod h1:o6P3MIvtzTOnmvGagO9v/rOjjA0HmhJ+/6KAXrmYDCI= +cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= +cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= +cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= +cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ= +cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/asset v1.12.0/go.mod h1:h9/sFOa4eDIyKmH6QMpm4eUK3pDojWnUhTgJlk762Hg= +cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= +cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= +cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= +cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= +cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= +cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= +cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= +cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= +cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= +cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= +cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/beyondcorp v0.5.0/go.mod h1:uFqj9X+dSfrheVp7ssLTaRHd2EHqSL4QZmH4e8WXGGU= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= +cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw= +cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= +cloud.google.com/go/bigquery v1.47.0/go.mod h1:sA9XOgy0A8vQK9+MWhEQTY6Tix87M/ZurWFIxmF9I/E= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/bigquery v1.49.0/go.mod h1:Sv8hMmTFFYBlt/ftw2uN6dFdQPzBlREY9yBh7Oy7/4Q= +cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= +cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= +cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI= +cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/billing v1.13.0/go.mod h1:7kB2W9Xf98hP9Sr12KfECgfGclsH3CQR0R08tnRlRbc= +cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= +cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= +cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= +cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= +cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= +cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/channel v1.12.0/go.mod h1:VkxCGKASi4Cq7TbXxlaBezonAYpp1GCnKMY6tnMQnLU= +cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= +cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA= +cloud.google.com/go/cloudbuild v1.6.0/go.mod h1:UIbc/w9QCbH12xX+ezUsgblrWv+Cv4Tw83GiSMHOn9M= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/cloudbuild v1.9.0/go.mod h1:qK1d7s4QlO0VwfYn5YuClDGg2hfmLZEb4wQGAbIgL1s= +cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= +cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= +cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= +cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= +cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/cloudtasks v1.10.0/go.mod h1:NDSoTLkZ3+vExFEWu2UJV1arUyzVDAiZtdWcsUyNwBs= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= +cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= +cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= +cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= +cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= +cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= +cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= +cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= +cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/container v1.14.0/go.mod h1:3AoJMPhHfLDxLvrlVWaK57IXzaPnLaZq63WX59aQBfM= +cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= +cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/containeranalysis v0.9.0/go.mod h1:orbOANbwk5Ejoom+s+DUCTTJ7IBdBQJDcSylAx/on9s= +cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= +cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= +cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= +cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE= +cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM= +cloud.google.com/go/datacatalog v1.8.1/go.mod h1:RJ58z4rMp3gvETA465Vg+ag8BGgBdnRPEMMSTr5Uv+M= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/datacatalog v1.13.0/go.mod h1:E4Rj9a5ZtAxcQJlEBTLgMTphfP11/lNaAshpoBgemX8= +cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= +cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= +cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= +cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/dataform v0.7.0/go.mod h1:7NulqnVozfHvWUBpMDfKMUESr+85aJsC/2O0o3jWPDE= +cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= +cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= +cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= +cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataplex v1.6.0/go.mod h1:bMsomC/aEJOSpHXdFKFGQ1b0TDPIeL28nJObeO1ppRs= +cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= +cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= +cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= +cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= +cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= +cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/datastream v1.7.0/go.mod h1:uxVRMm2elUSPuh65IbZpzJNMbuzkcvu5CjMqVIUHrww= +cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= +cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/deploy v1.8.0/go.mod h1:z3myEJnA/2wnB4sgjqdMfgxCA0EqC3RBTNcVPs93mtQ= +cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= +cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= +cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= +cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek= +cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0= +cloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dialogflow v1.32.0/go.mod h1:jG9TRJl8CKrDhMEcvfcfFkkpp8ZhgPz3sBGmAUYJ2qE= +cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= +cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= +cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= +cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= +cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/documentai v1.18.0/go.mod h1:F6CK6iUH8J81FehpskRmhLq/3VlwQvb7TvwOceQ2tbs= +cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= +cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= +cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/edgecontainer v1.0.0/go.mod h1:cttArqZpBB2q58W/upSG++ooo6EsblxDIolxa3jSjbY= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= +cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= +cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/eventarc v1.11.0/go.mod h1:PyUjsUKPWoRBCHeOxZd/lbOOjahV41icXyUY5kSTvVY= +cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= +cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/filestore v1.6.0/go.mod h1:di5unNuss/qfZTw2U9nhFqo8/ZDSc466dre85Kydllg= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/firestore v1.8.0/go.mod h1:r3KB8cAdRIe8znzoPWLw8S6gpDVd9treohhn8b09424= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= +cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= +cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= +cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/functions v1.12.0/go.mod h1:AXWGrF3e2C/5ehvwYo/GH6O5s09tOPksiKhz+hH8WkA= +cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= +cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= +cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= +cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= +cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= +cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= +cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkehub v0.12.0/go.mod h1:djiIwwzTTBrF5NaXCGv3mf7klpEMcST17VBTVVDcuaw= +cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= +cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= +cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= +cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= +cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= +cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= +cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= +cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= +cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= +cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= +cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/iap v1.7.0/go.mod h1:beqQx56T9O1G1yNPph+spKpNibDlYIiIixiqsQXxLIo= +cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= +cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= +cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/iot v1.6.0/go.mod h1:IqdAsmE2cTYYNO1Fvjfzo9po179rAtJeVGUvkLN3rLE= +cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= +cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= +cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0= +cloud.google.com/go/kms v1.8.0/go.mod h1:4xFEhYFqvW+4VMELtZyxomGSYtSQKzM178ylFW4jMAg= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/kms v1.10.0/go.mod h1:ng3KTUtQQU9bPX3+QGLsflZIHlkbn8amFAMY63m8d24= +cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= +cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= +cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= +cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= +cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= +cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= +cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/maps v0.7.0/go.mod h1:3GnvVl3cqeSvgMcpRlQidXsPYuDGQ8naBis7MVzpXsY= +cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= +cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= +cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= +cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= +cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= +cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= +cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= +cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= +cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/monitoring v1.13.0/go.mod h1:k2yMBAB1H9JT/QETjNkgdCGD9bPF712XiLTVr+cBrpw= +cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= +cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= +cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= +cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkconnectivity v1.11.0/go.mod h1:iWmDD4QF16VCDLXUqvyspJjIEtBR/4zq5hwnY2X3scM= +cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= +cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= +cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/networksecurity v0.8.0/go.mod h1:B78DkqsxFG5zRSVuwYFRZ9Xz8IcQ5iECsNrPn74hKHU= +cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= +cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= +cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= +cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/notebooks v1.8.0/go.mod h1:Lq6dYKOYOWUCTvw5t2q1gp1lAp0zxAxRycayS0iJcqQ= +cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= +cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= +cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= +cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= +cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= +cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= +cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= +cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= +cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= +cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= +cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= +cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/policytroubleshooter v1.6.0/go.mod h1:zYqaPTsmfvpjm5ULxAyD/lINQxJ0DDsnWOP/GZ7xzBc= +cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= +cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/privatecatalog v0.8.0/go.mod h1:nQ6pfaegeDAq/Q5lrfCQzQLhubPiZhSaNhIgfJlnIXs= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= +cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsub v1.30.0/go.mod h1:qWi1OPS0B+b5L+Sg6Gmc9zD1Y+HaM0MdUr7LsupY1P4= +cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/pubsublite v1.7.0/go.mod h1:8hVMwRXfDfvGm3fahVbtDbiLePT3gpoiJYJY+vxWxVM= +cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= +cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= +cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= +cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= +cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE= +cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recaptchaenterprise/v2 v2.7.0/go.mod h1:19wVj/fs5RtYtynAPJdDTb69oW0vNHYDBTbB4NvMD9c= +cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= +cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= +cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= +cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= +cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= +cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= +cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= +cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= +cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcemanager v1.6.0/go.mod h1:YcpXGRs8fDzcUl1Xw8uOVmI8JEadvhRIkoXXUNVYcVo= +cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= +cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= +cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= +cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= +cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= +cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/run v0.9.0/go.mod h1:Wwu+/vvg8Y+JUApMwEDfVfhetv30hCG4ZwDR/IXl2Qg= +cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= +cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= +cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= +cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/scheduler v1.9.0/go.mod h1:yexg5t+KSmqu+njTIh3b7oYPheFtBWGcbVUYF1GGMIc= +cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= +cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= +cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= +cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= +cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= +cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q= +cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/security v1.13.0/go.mod h1:Q1Nvxl1PAgmeW0y3HTt54JYIvUdtcpYKVfIB8AOMZ+0= +cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= +cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= +cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= +cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/securitycenter v1.19.0/go.mod h1:LVLmSg8ZkkyaNy4u7HCIshAngSQ8EcIRREP3xBnyfag= +cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= +cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s= +cloud.google.com/go/servicecontrol v1.10.0/go.mod h1:pQvyvSRh7YzUF2efw7H87V92mxU8FnFDawMClGCNuAA= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicecontrol v1.11.1/go.mod h1:aSnNNlwEFBY+PWGQ2DoM0JJ/QUXqV5/ZD9DOLB7SnUk= +cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= +cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= +cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4= +cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicedirectory v1.9.0/go.mod h1:29je5JjiygNYlmsGz8k6o+OZ8vd4f//bQLtvzkPPT/s= +cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= +cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/servicemanagement v1.8.0/go.mod h1:MSS2TDlIEQD/fzsSGfCdJItQveu9NXnUniTrq/L8LK4= +cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E= +cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/serviceusage v1.6.0/go.mod h1:R5wwQcbOWsyuOfbP9tGdAnCAc6B9DRwPG1xtWMDeuPA= +cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= +cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= +cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= +cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= +cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/speech v1.15.0/go.mod h1:y6oH7GhqCaZANH7+Oe0BhgIogsNInLlz542tg3VqeYI= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= +cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= +cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= +cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= +cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= +cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= +cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/storagetransfer v1.8.0/go.mod h1:JpegsHHU1eXg7lMHkvf+KE5XDJ7EQu0GwNJbbVGanEw= +cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= +cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= +cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= +cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= +cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= +cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= +cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/trace v1.9.0/go.mod h1:lOQqpE5IaWY0Ixg7/r2SjixMuc6lfTFeO4QGM4dQWOk= +cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= +cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= +cloud.google.com/go/translate v1.5.0/go.mod h1:29YDSYveqqpA1CQFD7NQuP49xymq17RXNaUDdc0mNu0= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/translate v1.7.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= +cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw= +cloud.google.com/go/video v1.12.0/go.mod h1:MLQew95eTuaNDEGriQdcYn0dTwf9oWiA4uYebxM5kdg= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/video v1.14.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= +cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= +cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= +cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= +cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= +cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= +cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= +cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY= +cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vision/v2 v2.7.0/go.mod h1:H89VysHy21avemp6xcf9b9JvZHVehWbET0uT/bcuY/0= +cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= +cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmmigration v1.6.0/go.mod h1:bopQ/g4z+8qXzichC7GW1w2MjbErL54rk3/C843CjfY= +cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vmwareengine v0.3.0/go.mod h1:wvoyMvNWdIzxMYSpH/R7y2h5h3WFkx6d+1TIsP39WGY= +cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= +cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= +cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= +cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= +cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= +cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= +cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= +cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= +cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= +git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= 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/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= +github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= 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= @@ -48,416 +601,347 @@ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tN 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/Shopify/sarama v1.37.2/go.mod h1:Nxye/E+YPru//Bpaorfhc3JsSGYwCaDDj+R4bK52U5o= +github.com/Shopify/toxiproxy/v2 v2.5.0/go.mod h1:yhM2epWtAmel9CB8r2+L+PCmhH6yH2pITaPAo7jxJl0= +github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= +github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= +github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI= +github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= +github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/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/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= +github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/avast/retry-go/v4 v4.3.0 h1:cqI48aXx0BExKoM7XPklDpoHAg7/srPPLAfWG5z62jo= +github.com/avast/retry-go/v4 v4.3.0/go.mod h1:bqOlT4nxk4phk9buiQFaghzjpqdchOSwPgjdfdQBtdg= +github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/bmatcuk/doublestar/v2 v2.0.4/go.mod h1:QMmcs3H2AUQICWhfzLXz+IYln8lRQmTZRptLie8RgRw= 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/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/bradleyjkemp/cupaloy/v2 v2.8.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0= +github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic= 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/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 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/cockroachdb/cockroach-go/v2 v2.2.16/go.mod h1:xZ2VHjUEb/cySv0scXBx7YsBnHtLHkR1+w/w73b5i3M= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= 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/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-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/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= 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-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 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/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= 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/dgraph-io/ristretto v0.0.3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= 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/cli v20.10.14+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v20.10.21+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v20.10.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.24+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= 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/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= 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/eapache/go-resiliency v1.3.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= 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/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= +github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= +github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= 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/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= 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/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/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-bindata/go-bindata v3.1.2+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo= +github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= +github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= +github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= 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-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= +github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= 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/analysis v0.21.2 h1:hXFrOYFHUAMQdu6zwAiKKJHJQ8kqZs1ux/ru1P1wLJU= +github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= 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/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.20.3 h1:rz6kiC84sqNQoqrtulzaL/VERgkoCyB6WdEkc2ujzUc= +github.com/go-openapi/errors v0.20.3/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= 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/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/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/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs= +github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= 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/loads v0.21.1 h1:Wb3nVZpdEzDTcly8S4HMkey6fjARRzb7iEaySimlDW0= +github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g= 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/runtime v0.24.2 h1:yX9HMGQbz32M87ECaAhGpJjBmErO3QLcgdZj9BzGx7c= +github.com/go-openapi/runtime v0.24.2/go.mod h1:AKurw9fNre+h3ELZfk6ILsfvPN+bvvlaU/M9q/r9hpk= 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/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M= +github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= 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/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg= +github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= +github.com/go-openapi/strfmt v0.21.2/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= +github.com/go-openapi/strfmt v0.21.3 h1:xwhj5X6CjXEZZHMWy1zKJxvW9AfHC9pkyUjLvHtKG7o= +github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg= 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/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= 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-openapi/validate v0.21.0 h1:+Wqk39yKOhfpLqNLEC0/eViCkzM5FVXVqrvt526+wcI= +github.com/go-openapi/validate v0.21.0/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= +github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= +github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= 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/attrs v1.0.3/go.mod h1:KvDJCE0avbufqS0Bw3UV7RQynESY0jjod+572ctX4t8= 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/envy v1.10.2/go.mod h1:qGAGwdvDsaEtPhfBzb3o0SfDea8ByGn9j8bKmVft9z8= +github.com/gobuffalo/fizz v1.14.4/go.mod h1:9/2fGNXNeIFOXEEgTPJwiK63e44RjG+Nc4hfMm1ArGM= 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/flect v0.3.0/go.mod h1:5pf3aGnsvqvCj50AVni7mJJF8ICxGZ8HomberC3pXLE= 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/genny/v2 v2.1.0/go.mod h1:4yoTNk4bYuP3BMM6uQKYPvtP6WsXFGm2w2EFYZdRls8= 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/github_flavored_markdown v1.1.3/go.mod h1:IzgO5xS6hqkDmUh91BW/+Qxo/qYnvfzoz3A7uLkg77I= 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/helpers v0.6.7/go.mod h1:j0u1iC1VqlCaJEEVkZN8Ia3TEzfj/zoXANqyJExTMTA= 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/here v0.6.7/go.mod h1:vuCfanjqckTuRlqAitJz6QC4ABNnS27wLb816UhsPcc= +github.com/gobuffalo/httptest v1.5.2 h1:GpGy520SfY1QEmyPvaqmznTpG4gEQqQ82HtHqyNEreM= +github.com/gobuffalo/httptest v1.5.2/go.mod h1:FA23yjsWLGj92mVV74Qtc8eqluc11VqcWr8/C1vxt4g= 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/logger v1.0.7/go.mod h1:u40u6Bq3VVvaMcy5sRBclD8SXhBYPS0Qk95ubt+1xJM= 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/nulls v0.4.2/go.mod h1:EElw2zmBYafU2R9W4Ii1ByIj177wA/pc0JdjtD0EsH8= 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/packd v1.0.2/go.mod h1:sUc61tDqGMXON80zpKGp92lDb86Km28jfvX7IAyxFT8= 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/plush/v4 v4.1.16/go.mod h1:6t7swVsarJ8qSLw1qyAH/KbrcSTwdun2ASEQkOznakg= +github.com/gobuffalo/pop/v6 v6.0.8 h1:9+5ShHYh3x9NDFCITfm/gtKDDRSgOwiY7kA0Hf7N9aQ= +github.com/gobuffalo/pop/v6 v6.0.8/go.mod h1:f4JQ4Zvkffcevz+t+XAwBLStD7IQs19DiIGIDFYw1eA= 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/gobuffalo/tags/v3 v3.1.4/go.mod h1:ArRNo3ErlHO8BtdA0REaZxijuWnWzF6PUXngmMXd2I0= +github.com/gobuffalo/validate/v3 v3.3.3/go.mod h1:YC7FsbJ/9hW/VjQdmXPvFqvRis4vrRYFxr69WiNZw6g= +github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-yaml v1.9.6 h1:KhAu1zf9JXnm3vbG49aDE0E5uEBUsM4uwD31/58ZWyI= +github.com/goccy/go-yaml v1.9.6/go.mod h1:JubOolP3gh0HpiBc4BLRD4YmjEjHAmIIB2aaXKkTfoE= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= 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/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 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/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= 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/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -465,7 +949,8 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -478,21 +963,42 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4/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/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-jsonnet v0.19.0/go.mod h1:5JVT33JVCoehdTj5Z2KJq1eIdt3Nb8PCmZ+W5D8U350= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -500,394 +1006,667 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= +github.com/google/pprof v0.0.0-20221010195024-131d412537ea/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= +github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/gopherjs/gopherjs v0.0.0-20181004151105-1babbf986f6f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= +github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= +github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= +github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/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/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= 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/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= 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/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.12.0/go.mod h1:ummNFgdgLhhX7aIiy35vVmQNS0rWXknfPE0qe6fmFXg= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/api v1.15.3/go.mod h1:/g/qgcoBcEXALCNZgRRisyTW0nY86++L0KbeAMXYCeY= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.11.0/go.mod h1:yPkX5Q6CsxTFMjQQDJwzeNmUUF5NUGGbrDsv9wTb8cw= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= +github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.6.8/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ= +github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/memberlist v0.3.1/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/hashicorp/serf v0.9.8/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= 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/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= +github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf/go.mod h1:yrqSXGoD/4EKfF26AOGzscPOgTTJcyAwM2rpixWT+t4= 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/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= +github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= +github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= +github.com/jackc/pgconn v1.12.0/go.mod h1:ZkhRC59Llhrq3oSfrikvwQ5NaxYExr6twkdkMLaKono= +github.com/jackc/pgconn v1.12.1/go.mod h1:ZkhRC59Llhrq3oSfrikvwQ5NaxYExr6twkdkMLaKono= +github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI= 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/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= +github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= 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/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.3.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/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/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= +github.com/jackc/pgtype v1.11.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= 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/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= +github.com/jackc/pgx/v4 v4.16.0/go.mod h1:N0A9sFdWzkw/Jy1lwoiB64F2+ugFZi987zRxcPez/wI= +github.com/jackc/pgx/v4 v4.16.1/go.mod h1:SIhx0D5hoADaiXZVyv+3gSm3LCIIINTVO0PficsvWGQ= +github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw= 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/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jandelgado/gcov2lcov v1.0.4/go.mod h1:NnSxK6TMlg1oGDBfGelGbjgorT5/L3cchlbtgFYZSss= +github.com/jandelgado/gcov2lcov v1.0.5 h1:rkBt40h0CVK4oCb8Dps950gvfd1rYvQ8+cWa346lVU0= +github.com/jandelgado/gcov2lcov v1.0.5/go.mod h1:NnSxK6TMlg1oGDBfGelGbjgorT5/L3cchlbtgFYZSss= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.3/go.mod h1:dqRwJGXznQrzw6cWmyo6kH+E7jksEQG/CyVWsJEsJO0= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jezek/xgb v1.0.0/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jtolds/gls v4.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.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= 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/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= 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/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs= +github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI= +github.com/knadh/koanf/parsers/json v0.1.0 h1:dzSZl5pf5bBcW0Acnu20Djleto19T0CfHcvZ14NJ6fU= +github.com/knadh/koanf/parsers/json v0.1.0/go.mod h1:ll2/MlXcZ2BfXD6YJcjVFzhG9P0TdJ207aIBKQhV2hY= +github.com/knadh/koanf/parsers/toml v0.1.0/go.mod h1:yUprhq6eo3GbyVXFFMdbfZSo928ksS+uo0FFqNMnO18= +github.com/knadh/koanf/parsers/yaml v0.1.0/go.mod h1:cvbUDC7AL23pImuQP0oRw/hPuccrNBS2bps8asS0CwY= +github.com/knadh/koanf/providers/posflag v0.1.0/go.mod h1:SYg03v/t8ISBNrMBRMlojH8OsKowbkXV7giIbBVgbz0= +github.com/knadh/koanf/providers/rawbytes v0.1.0 h1:dpzgu2KO6uf6oCb4aP05KDmKmAmI51k5pe8RYKQ0qME= +github.com/knadh/koanf/providers/rawbytes v0.1.0/go.mod h1:mMTB1/IcJ/yE++A2iEZbY1MLygX7vttU+C+S/YmPu9c= +github.com/knadh/koanf/v2 v2.0.1 h1:1dYGITt1I23x8cfx8ZnldtezdyaZtfAuRtIFOiRzK7g= +github.com/knadh/koanf/v2 v2.0.1/go.mod h1:ZeiIlIDXTE7w1lMT6UVcNiRAS2/rCeLn/GdLNvY1Dus= 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/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/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/laher/mergefs v0.1.1/go.mod h1:FSY1hYy94on4Tz60waRMGdO1awwS23BacqJlqf9lJ9Q= +github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= 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/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/luna-duclos/instrumentedsql v1.1.3/go.mod h1:9J1njvFds+zN7y85EDhN9XNQLANWwZt2ULeIC8yMNYs= +github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= +github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= 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/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.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/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= 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/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= 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/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= 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-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/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.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-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/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= 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/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/microcosm-cc/bluemonday v1.0.20/go.mod h1:yfBmMi8mxvaZut3Yytv+jTXRY8mxyjJ0/kQBTElld50= +github.com/microcosm-cc/bluemonday v1.0.21/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= +github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= 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/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.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/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= +github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= +github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/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/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= 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/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/nyaruka/phonenumbers v1.0.73/go.mod h1:3aiS+PS3DuYwkbK3xdcmRwMiPNECZ0oENH8qUT1lY7Q= +github.com/nyaruka/phonenumbers v1.1.1 h1:fyoZmpLN2VCmAnc51XcrNOUVP2wT1ZzQl348ggIaXII= +github.com/nyaruka/phonenumbers v1.1.1/go.mod h1:cGaEsOrLjIL0iKGqJR5Rfywy86dSkbApEpXuM9KySNA= +github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= 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/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= 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/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v1.1.2/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= +github.com/opencontainers/runc v1.1.5/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/openzipkin/zipkin-go v0.4.1/go.mod h1:qY0VqDSN1pOBN94dBc6w2GJlWLiovAyg7Qt6/I9HecM= +github.com/ory/analytics-go/v5 v5.0.1/go.mod h1:lWCiCjAaJkKfgR/BN5DCLMol8BjKS1x+4jxBxff/FF0= +github.com/ory/dockertest/v3 v3.9.1/go.mod h1:42Ir9hmvaAPm0Mgibk6mBPi7SFvTXxEcnztDYOJ//uM= +github.com/ory/go-acc v0.2.6/go.mod h1:4Kb/UnPcT8qRAk3IAxta+hvVapdxTLWtrr7bFLlEgpw= +github.com/ory/go-acc v0.2.9-0.20230103102148-6b1c9a70dbbe h1:rvu4obdvqR0fkSIJ8IfgzKOWwZ5kOT2UNfLq81Qk7rc= +github.com/ory/go-acc v0.2.9-0.20230103102148-6b1c9a70dbbe/go.mod h1:z4n3u6as84LbV4YmgjHhnwtccQqzf4cZlSk9f1FhygI= +github.com/ory/herodot v0.10.3-0.20230626083119-d7e5192f0d88 h1:J0CIFKdpUeqKbVMw7pQ1qLtUnflRM1JWAcOEq7Hp4yg= +github.com/ory/herodot v0.10.3-0.20230626083119-d7e5192f0d88/go.mod h1:MMNmY6MG1uB6fnXYFaHoqdV23DTWctlPsmRCeq/2+wc= 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/jsonschema/v3 v3.0.7 h1:GQ9qfZDiJqs4l2d3p56dozCChvejQFZyLKGHYzDzOSo= +github.com/ory/jsonschema/v3 v3.0.7/go.mod h1:g8c8YOtN4TrR2wYeMdT02GDmzJDI0fEW2nI26BECafY= 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/ory/viper v1.7.5/go.mod h1:ypOuyJmEUb3oENywQZRgeAMwqgOyDqwboO1tj3DjTaM= +github.com/ory/x v0.0.577 h1:wJRrD2OvEFkbM/cwHrlkSY8VaEO6RUoOnDlUc34YRdk= +github.com/ory/x v0.0.577/go.mod h1:aeJFTlvDLGYSABzPS3z5SeLcYC52Ek7uGZiuYGcTMSU= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pborman/uuid v1.2.1/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/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= +github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs= +github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= +github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= +github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= +github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= +github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= +github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= 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/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= 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/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= 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/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= 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/rabbitmq/amqp091-go v1.5.0/go.mod h1:JsV0ofX5f1nwOGafb8L5rBItt9GyhfQfcJj+oyz0dGg= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/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/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= 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/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= 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/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= +github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= 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/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= +github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sagikazarmark/crypt v0.8.0/go.mod h1:TmKwZAo97S4Fy4sfMH/HX/cQP5D+ijra2NyLpNNmttY= 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/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/seatgeek/logrus-gelf-formatter v0.0.0-20210414080842-5b05eb8ff761 h1:0b8DF5kR0PhRoRXDiEEdzrgBc8UqVY4JWLkQJCRsLME= +github.com/seatgeek/logrus-gelf-formatter v0.0.0-20210414080842-5b05eb8ff761/go.mod h1:/THDZYi7F/BsVEcYzYPqdcWFQ+1C2InkawTKfLOAnzg= +github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= +github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= 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/backo-go v1.0.1/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/sergi/go-diff v1.2.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/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= 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/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 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/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= +github.com/spf13/afero v1.5.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= +github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= 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/cast v1.3.2-0.20200723214538-8d17101741c8/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= +github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= 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/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= +github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= +github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.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/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.14.0 h1:Rg7d3Lo706X9tHsJMUjdiwMpHB7W8WnSVOssIY+JElU= +github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As= 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/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1 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/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 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/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= +github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw= +github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= 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/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= +github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= 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/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= 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/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli/v2 v2.11.0/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo= +github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= +github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= +github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= +github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= 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/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= 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/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= +github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= 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.etcd.io/etcd/api/v3 v3.5.5/go.mod h1:KFtNaxGDw4Yx/BA4iPPwevUTAuqcsPxzyX8PHydchN8= +go.etcd.io/etcd/client/pkg/v3 v3.5.5/go.mod h1:ggrwbk069qxpKPq8/FKkQ3Xq9y39kbFR4LnKszpRXeQ= +go.etcd.io/etcd/client/v2 v2.305.5/go.mod h1:zQjKllfqfBVyVStbt4FaosoX2iYd8fV/GRy/PbowgP4= +go.etcd.io/etcd/client/v3 v3.5.5/go.mod h1:aApjR4WGlSumpnJ2kloS75h6aHUmAyaPLjHMxpc7E7c= 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.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= +go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= +go.mongodb.org/mongo-driver v1.8.3/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= +go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= +go.mongodb.org/mongo-driver v1.10.3 h1:XDQEvmh6z1EUsXuIkXE9TaVeqHw6SwS1uf93jFs0HBA= +go.mongodb.org/mongo-driver v1.10.3/go.mod h1:z4XpeoU6w+9Vht+jAFyLgVrD+jGSQQe0+CBWFHNiHt8= 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.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.36.4 h1:toN8e0U4RWQL4f8H+1eFtaeWe/IkSM3+81qJEDOgShs= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.36.4/go.mod h1:u4OeI4ujQmFbpZOOysLUfYrRWOmEVmvzkM2zExVorXM= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.4 h1:aUEBEdCa6iamGzg6fuYxDA8ThxvOG240mAvWDU+XLio= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.4/go.mod h1:l2MdsbKTocpPS5nQZscqTR9jd8u96VYZdcpF8Sye7mA= +go.opentelemetry.io/contrib/propagators/b3 v1.11.1/go.mod h1:ECIveyMXgnl4gorxFcA7RYjJY/Ql9n20ubhbfDc3QfA= +go.opentelemetry.io/contrib/propagators/jaeger v1.11.1/go.mod h1:dP/N3ZFADH8azBcZfGXEFNBXpEmPTXYcNj9rkw1+2Oc= +go.opentelemetry.io/contrib/samplers/jaegerremote v0.5.2/go.mod h1:Z0aRlRERn9v/3J2K+ATa6ffKyb8/i+/My/gTzFr3dII= +go.opentelemetry.io/otel v1.9.0/go.mod h1:np4EoPGzoPs3O67xUVNoPPcmSvsfOxNlNA4F4AC+0Eo= +go.opentelemetry.io/otel v1.11.1 h1:4WLLAmcfkmDk2ukNXJyq3/kiz/3UzCaYq6PskJsaou4= +go.opentelemetry.io/otel v1.11.1/go.mod h1:1nNhXBbWSD0nsL38H6btgnFN2k4i0sNLHNNMZMSbUGE= +go.opentelemetry.io/otel/exporters/jaeger v1.11.1/go.mod h1:lRa2w3bQ4R4QN6zYsDgy7tEezgoKEu7Ow2g35Y75+KI= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.9.0/go.mod h1:78XhIg8Ht9vR4tbLNUhXsiOnE2HOuSeKAiAcoVQEpOY= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.1/go.mod h1:i8vjiSzbiUC7wOQplijSXMYUpNM93DtlS5CbUT+C6oQ= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.9.0/go.mod h1:0EsCXjZAiiZGnLdEUXM9YjCKuuLZMYyglh2QDXcYKVA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.9.0/go.mod h1:smUdtylgc0YQiUr2PuifS4hBXhAS5xtR6WQhxP1wiNA= +go.opentelemetry.io/otel/exporters/zipkin v1.11.1/go.mod h1:T4S6aVwIS1+MHA+dJHCcPROtZe6ORwnv5vMKPRapsFw= +go.opentelemetry.io/otel/metric v0.33.0 h1:xQAyl7uGEYvrLAiV/09iTJlp1pZnQ9Wl793qbVvED1E= +go.opentelemetry.io/otel/metric v0.33.0/go.mod h1:QlTYc+EnYNq/M2mNk1qDDMRLpqCOj2f/r5c7Fd5FYaI= +go.opentelemetry.io/otel/sdk v1.9.0/go.mod h1:AEZc8nt5bd2F7BC24J5R0mrjYnpEgYHyTcM/vrSple4= +go.opentelemetry.io/otel/sdk v1.11.1/go.mod h1:/l3FE4SupHJ12TduVjUkZtlfFqDCQJlOlithYrdktys= +go.opentelemetry.io/otel/trace v1.9.0/go.mod h1:2737Q0MuG8q1uILYm2YYVkAyLtOofiTNGg6VODnOiPo= +go.opentelemetry.io/otel/trace v1.11.1 h1:ofxdnzsNrGBYXbP7t7zpUK281+go5rF7dvdIZXF8gdQ= +go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/proto/otlp v0.18.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= 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/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= 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= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= 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-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= @@ -897,33 +1676,59 @@ golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-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-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-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-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220517005047-85d78b3ac167/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= 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-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= 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/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +golang.org/x/exp/shiny v0.0.0-20220722155223-a9213eeb770e/go.mod h1:VjAR7z0ngyATZTELrBSkxOOHhhlnVUxDye4mcjx5h/8= 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/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20220902085622-e7cb96979f69/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY= +golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4= 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= @@ -934,28 +1739,36 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= 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.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 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-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -972,11 +1785,10 @@ golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLL 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-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -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= @@ -984,20 +1796,84 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ 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-20200520004742-59133d7f0dd7/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/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220725212005-46097bf591d3/go.mod h1:AaygXjzTFtRAg2ttMY5RMuhpJ3cNnI0XpyFJD1iQRSM= +golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20220927171203-f486391704dc/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221004154528-8021a29435af/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= 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-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.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-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= +golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= +golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= 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= @@ -1007,44 +1883,56 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/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/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0/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= @@ -1060,32 +1948,32 @@ golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBn 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-20190624222133-a101b041ded4/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-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-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-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/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= @@ -1098,22 +1986,52 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= +golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= 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= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= 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/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= +gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= +gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= +gonum.org/v1/gonum v0.12.0/go.mod h1:73TDxJfAAHeA8Mk9mf8NlIppyhQNo5GLTcYeqgo2lvY= 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= +gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= +gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= +gonum.org/v1/plot v0.12.0/go.mod h1:PgiMf9+3A3PnZdJIciIXmyN1FwdAA6rXELSN761oQkw= 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= @@ -1130,21 +2048,60 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= +google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= +google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= +google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= +google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= +google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= +google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= +google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= +google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= +google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0= +google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= 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/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-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= @@ -1163,17 +2120,118 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= 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-20200806141610-86f49bd18e98/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= +google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= +google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= +google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= +google.golang.org/genproto v0.0.0-20221109142239-94d6d90a7d66/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= +google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230112194545-e10362b5ecf9/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA= +google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= +google.golang.org/genproto v0.0.0-20230223222841-637eb2293923/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= +google.golang.org/genproto v0.0.0-20230303212802-e74f57abe488/go.mod h1:TvhZT5f700eVlTNwND1xoEZQeWTB2RY/65kplwl/bFA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd h1:sLpv7bNL1AsX3fdnWh9WVh7ejIzXdOc1RRHGeAmeStU= +google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= 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= @@ -1183,6 +2241,37 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag= +google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/grpc/examples v0.0.0-20210304020650-930c79186c99/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= 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= @@ -1192,45 +2281,58 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 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/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 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/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/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.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.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.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-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= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/postgres v1.3.5/go.mod h1:EGCWefLFQSVFrHGy4J8EtiHCWX5Q8t0yz2Jt9aKkGzU= +gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/gorm v1.23.5/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.2.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A= 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= @@ -1238,12 +2340,45 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh 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= +honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= +lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= +modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= +modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= +modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= +modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= +modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= +modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= +modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= +modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU= +modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= +modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= +modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= +modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s= +modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= +modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= +modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= +modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= +modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= 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= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/test/e2e/hydra-login-consent/go.mod b/test/e2e/hydra-login-consent/go.mod index 5e6f45c45d5f..f4617de82d7d 100644 --- a/test/e2e/hydra-login-consent/go.mod +++ b/test/e2e/hydra-login-consent/go.mod @@ -7,5 +7,5 @@ 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/v2 v2.0.3 - github.com/ory/x v0.0.116 + github.com/ory/x v0.0.577 ) diff --git a/test/e2e/hydra-login-consent/go.sum b/test/e2e/hydra-login-consent/go.sum index 63af4f53adee..980a48b5f5cb 100644 --- a/test/e2e/hydra-login-consent/go.sum +++ b/test/e2e/hydra-login-consent/go.sum @@ -1,10 +1,9 @@ -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.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= @@ -15,356 +14,863 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= +cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= +cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= +cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= +cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= +cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/accesscontextmanager v1.7.0/go.mod h1:CEGLewx8dwa33aDAZQujl7Dx+uYhS0eay198wB/VumQ= +cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= +cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= +cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/aiplatform v1.36.1/go.mod h1:WTm12vJRPARNvJ+v6P52RDHCNe4AhvjcIZ/9/RRHy/k= +cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= +cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= +cloud.google.com/go/analytics v0.17.0/go.mod h1:WXFa3WSym4IZ+JiKmavYdJwGG/CvpqiqczmL59bTD9M= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/analytics v0.19.0/go.mod h1:k8liqf5/HCnOUkbawNtrWWc+UAzyDlW89doe8TtoDsE= +cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= +cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= +cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.4.0/go.mod h1:EUG4PGcsZvxOXAdyEghIdXwAEi/4MEaoqLMLDMIwKXY= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apigeeregistry v0.6.0/go.mod h1:BFNzW7yQVLZ3yj0TKcwzb8n25CFBri51GVGOEUcgQsc= +cloud.google.com/go/apikeys v0.4.0/go.mod h1:XATS/yqZbaBK0HOssf+ALHp8jAlNHUgyfprvNcBIszU= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/apikeys v0.6.0/go.mod h1:kbpXu5upyiAlGkKrJgQl8A0rKNNJ7dQ377pdroRSSi8= +cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno= +cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/appengine v1.7.0/go.mod h1:eZqpbHFCqRGa2aCdope7eC0SWLV1j0neb/QnMJVWx6A= +cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= +cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= +cloud.google.com/go/area120 v0.7.0/go.mod h1:a3+8EUD1SX5RUcCs3MY5YasiO1z6yLiNLRiFrykbynY= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= +cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= +cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= +cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc= +cloud.google.com/go/artifactregistry v1.11.1/go.mod h1:lLYghw+Itq9SONbCa1YWBoWs1nOucMH0pwXN1rOBZFI= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/artifactregistry v1.12.0/go.mod h1:o6P3MIvtzTOnmvGagO9v/rOjjA0HmhJ+/6KAXrmYDCI= +cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= +cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= +cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= +cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ= +cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/asset v1.12.0/go.mod h1:h9/sFOa4eDIyKmH6QMpm4eUK3pDojWnUhTgJlk762Hg= +cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= +cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= +cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= +cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= +cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= +cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= +cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= +cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= +cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= +cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= +cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/beyondcorp v0.5.0/go.mod h1:uFqj9X+dSfrheVp7ssLTaRHd2EHqSL4QZmH4e8WXGGU= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= +cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw= +cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= +cloud.google.com/go/bigquery v1.47.0/go.mod h1:sA9XOgy0A8vQK9+MWhEQTY6Tix87M/ZurWFIxmF9I/E= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/bigquery v1.49.0/go.mod h1:Sv8hMmTFFYBlt/ftw2uN6dFdQPzBlREY9yBh7Oy7/4Q= +cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= +cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= +cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI= +cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/billing v1.13.0/go.mod h1:7kB2W9Xf98hP9Sr12KfECgfGclsH3CQR0R08tnRlRbc= +cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= +cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= +cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= +cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= +cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= +cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/channel v1.12.0/go.mod h1:VkxCGKASi4Cq7TbXxlaBezonAYpp1GCnKMY6tnMQnLU= +cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= +cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA= +cloud.google.com/go/cloudbuild v1.6.0/go.mod h1:UIbc/w9QCbH12xX+ezUsgblrWv+Cv4Tw83GiSMHOn9M= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/cloudbuild v1.9.0/go.mod h1:qK1d7s4QlO0VwfYn5YuClDGg2hfmLZEb4wQGAbIgL1s= +cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= +cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= +cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= +cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= +cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/cloudtasks v1.10.0/go.mod h1:NDSoTLkZ3+vExFEWu2UJV1arUyzVDAiZtdWcsUyNwBs= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= +cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= +cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= +cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= +cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= +cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= +cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= +cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= +cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/container v1.14.0/go.mod h1:3AoJMPhHfLDxLvrlVWaK57IXzaPnLaZq63WX59aQBfM= +cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= +cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/containeranalysis v0.9.0/go.mod h1:orbOANbwk5Ejoom+s+DUCTTJ7IBdBQJDcSylAx/on9s= +cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= +cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= +cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= +cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE= +cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM= +cloud.google.com/go/datacatalog v1.8.1/go.mod h1:RJ58z4rMp3gvETA465Vg+ag8BGgBdnRPEMMSTr5Uv+M= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/datacatalog v1.13.0/go.mod h1:E4Rj9a5ZtAxcQJlEBTLgMTphfP11/lNaAshpoBgemX8= +cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= +cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= +cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= +cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/dataform v0.7.0/go.mod h1:7NulqnVozfHvWUBpMDfKMUESr+85aJsC/2O0o3jWPDE= +cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= +cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= +cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= +cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataplex v1.6.0/go.mod h1:bMsomC/aEJOSpHXdFKFGQ1b0TDPIeL28nJObeO1ppRs= +cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= +cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= +cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= +cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= +cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= +cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/datastream v1.7.0/go.mod h1:uxVRMm2elUSPuh65IbZpzJNMbuzkcvu5CjMqVIUHrww= +cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= +cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/deploy v1.8.0/go.mod h1:z3myEJnA/2wnB4sgjqdMfgxCA0EqC3RBTNcVPs93mtQ= +cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= +cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= +cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= +cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek= +cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0= +cloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dialogflow v1.32.0/go.mod h1:jG9TRJl8CKrDhMEcvfcfFkkpp8ZhgPz3sBGmAUYJ2qE= +cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= +cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= +cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= +cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= +cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/documentai v1.18.0/go.mod h1:F6CK6iUH8J81FehpskRmhLq/3VlwQvb7TvwOceQ2tbs= +cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= +cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= +cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/edgecontainer v1.0.0/go.mod h1:cttArqZpBB2q58W/upSG++ooo6EsblxDIolxa3jSjbY= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= +cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= +cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/eventarc v1.11.0/go.mod h1:PyUjsUKPWoRBCHeOxZd/lbOOjahV41icXyUY5kSTvVY= +cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= +cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/filestore v1.6.0/go.mod h1:di5unNuss/qfZTw2U9nhFqo8/ZDSc466dre85Kydllg= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/firestore v1.8.0/go.mod h1:r3KB8cAdRIe8znzoPWLw8S6gpDVd9treohhn8b09424= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= +cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= +cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= +cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/functions v1.12.0/go.mod h1:AXWGrF3e2C/5ehvwYo/GH6O5s09tOPksiKhz+hH8WkA= +cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= +cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= +cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= +cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= +cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= +cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= +cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkehub v0.12.0/go.mod h1:djiIwwzTTBrF5NaXCGv3mf7klpEMcST17VBTVVDcuaw= +cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= +cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= +cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= +cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= +cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= +cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= +cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= +cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= +cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= +cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= +cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/iap v1.7.0/go.mod h1:beqQx56T9O1G1yNPph+spKpNibDlYIiIixiqsQXxLIo= +cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= +cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= +cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/iot v1.6.0/go.mod h1:IqdAsmE2cTYYNO1Fvjfzo9po179rAtJeVGUvkLN3rLE= +cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= +cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= +cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0= +cloud.google.com/go/kms v1.8.0/go.mod h1:4xFEhYFqvW+4VMELtZyxomGSYtSQKzM178ylFW4jMAg= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/kms v1.10.0/go.mod h1:ng3KTUtQQU9bPX3+QGLsflZIHlkbn8amFAMY63m8d24= +cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= +cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= +cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= +cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= +cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= +cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= +cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/maps v0.7.0/go.mod h1:3GnvVl3cqeSvgMcpRlQidXsPYuDGQ8naBis7MVzpXsY= +cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= +cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= +cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= +cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= +cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= +cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= +cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= +cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= +cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/monitoring v1.13.0/go.mod h1:k2yMBAB1H9JT/QETjNkgdCGD9bPF712XiLTVr+cBrpw= +cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= +cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= +cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= +cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkconnectivity v1.11.0/go.mod h1:iWmDD4QF16VCDLXUqvyspJjIEtBR/4zq5hwnY2X3scM= +cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= +cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= +cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/networksecurity v0.8.0/go.mod h1:B78DkqsxFG5zRSVuwYFRZ9Xz8IcQ5iECsNrPn74hKHU= +cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= +cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= +cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= +cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/notebooks v1.8.0/go.mod h1:Lq6dYKOYOWUCTvw5t2q1gp1lAp0zxAxRycayS0iJcqQ= +cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= +cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= +cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= +cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= +cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= +cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= +cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= +cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= +cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= +cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= +cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= +cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/policytroubleshooter v1.6.0/go.mod h1:zYqaPTsmfvpjm5ULxAyD/lINQxJ0DDsnWOP/GZ7xzBc= +cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= +cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/privatecatalog v0.8.0/go.mod h1:nQ6pfaegeDAq/Q5lrfCQzQLhubPiZhSaNhIgfJlnIXs= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= +cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsub v1.30.0/go.mod h1:qWi1OPS0B+b5L+Sg6Gmc9zD1Y+HaM0MdUr7LsupY1P4= +cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/pubsublite v1.7.0/go.mod h1:8hVMwRXfDfvGm3fahVbtDbiLePT3gpoiJYJY+vxWxVM= +cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= +cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= +cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= +cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= +cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE= +cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recaptchaenterprise/v2 v2.7.0/go.mod h1:19wVj/fs5RtYtynAPJdDTb69oW0vNHYDBTbB4NvMD9c= +cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= +cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= +cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= +cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= +cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= +cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= +cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= +cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= +cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcemanager v1.6.0/go.mod h1:YcpXGRs8fDzcUl1Xw8uOVmI8JEadvhRIkoXXUNVYcVo= +cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= +cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= +cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= +cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= +cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= +cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/run v0.9.0/go.mod h1:Wwu+/vvg8Y+JUApMwEDfVfhetv30hCG4ZwDR/IXl2Qg= +cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= +cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= +cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= +cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/scheduler v1.9.0/go.mod h1:yexg5t+KSmqu+njTIh3b7oYPheFtBWGcbVUYF1GGMIc= +cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= +cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= +cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= +cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= +cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= +cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q= +cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/security v1.13.0/go.mod h1:Q1Nvxl1PAgmeW0y3HTt54JYIvUdtcpYKVfIB8AOMZ+0= +cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= +cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= +cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= +cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/securitycenter v1.19.0/go.mod h1:LVLmSg8ZkkyaNy4u7HCIshAngSQ8EcIRREP3xBnyfag= +cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= +cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s= +cloud.google.com/go/servicecontrol v1.10.0/go.mod h1:pQvyvSRh7YzUF2efw7H87V92mxU8FnFDawMClGCNuAA= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicecontrol v1.11.1/go.mod h1:aSnNNlwEFBY+PWGQ2DoM0JJ/QUXqV5/ZD9DOLB7SnUk= +cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= +cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= +cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4= +cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicedirectory v1.9.0/go.mod h1:29je5JjiygNYlmsGz8k6o+OZ8vd4f//bQLtvzkPPT/s= +cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= +cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/servicemanagement v1.8.0/go.mod h1:MSS2TDlIEQD/fzsSGfCdJItQveu9NXnUniTrq/L8LK4= +cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E= +cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/serviceusage v1.6.0/go.mod h1:R5wwQcbOWsyuOfbP9tGdAnCAc6B9DRwPG1xtWMDeuPA= +cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= +cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= +cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= +cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= +cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/speech v1.15.0/go.mod h1:y6oH7GhqCaZANH7+Oe0BhgIogsNInLlz542tg3VqeYI= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= +cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= +cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= +cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= +cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= +cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= +cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/storagetransfer v1.8.0/go.mod h1:JpegsHHU1eXg7lMHkvf+KE5XDJ7EQu0GwNJbbVGanEw= +cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= +cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= +cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= +cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= +cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= +cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= +cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/trace v1.9.0/go.mod h1:lOQqpE5IaWY0Ixg7/r2SjixMuc6lfTFeO4QGM4dQWOk= +cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= +cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= +cloud.google.com/go/translate v1.5.0/go.mod h1:29YDSYveqqpA1CQFD7NQuP49xymq17RXNaUDdc0mNu0= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/translate v1.7.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= +cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw= +cloud.google.com/go/video v1.12.0/go.mod h1:MLQew95eTuaNDEGriQdcYn0dTwf9oWiA4uYebxM5kdg= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/video v1.14.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= +cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= +cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= +cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= +cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= +cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= +cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= +cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY= +cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vision/v2 v2.7.0/go.mod h1:H89VysHy21avemp6xcf9b9JvZHVehWbET0uT/bcuY/0= +cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= +cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmmigration v1.6.0/go.mod h1:bopQ/g4z+8qXzichC7GW1w2MjbErL54rk3/C843CjfY= +cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vmwareengine v0.3.0/go.mod h1:wvoyMvNWdIzxMYSpH/R7y2h5h3WFkx6d+1TIsP39WGY= +cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= +cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= +cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= +cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= +cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= +cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= +cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= +cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= +cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= +git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= 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/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= +github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= 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/ajg/form v0.0.0-20160822230020-523a5da1a92f/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/sarama v1.37.2/go.mod h1:Nxye/E+YPru//Bpaorfhc3JsSGYwCaDDj+R4bK52U5o= +github.com/Shopify/toxiproxy/v2 v2.5.0/go.mod h1:yhM2epWtAmel9CB8r2+L+PCmhH6yH2pITaPAo7jxJl0= +github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= +github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= +github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI= +github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= 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/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/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= +github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/avast/retry-go/v4 v4.3.0 h1:cqI48aXx0BExKoM7XPklDpoHAg7/srPPLAfWG5z62jo= +github.com/avast/retry-go/v4 v4.3.0/go.mod h1:bqOlT4nxk4phk9buiQFaghzjpqdchOSwPgjdfdQBtdg= +github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/bmatcuk/doublestar/v2 v2.0.4/go.mod h1:QMmcs3H2AUQICWhfzLXz+IYln8lRQmTZRptLie8RgRw= 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/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/bradleyjkemp/cupaloy/v2 v2.8.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0= +github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic= 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/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 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/cockroachdb/cockroach-go/v2 v2.2.16/go.mod h1:xZ2VHjUEb/cySv0scXBx7YsBnHtLHkR1+w/w73b5i3M= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= 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/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-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/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= 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-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 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/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= 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/dgraph-io/ristretto v0.0.3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= 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/cli v20.10.14+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v20.10.21+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v20.10.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.24+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= 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/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= 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/eapache/go-resiliency v1.3.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= 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/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= +github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= +github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= 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/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= 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/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-bindata/go-bindata v3.1.1+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo= +github.com/go-bindata/go-bindata v3.1.2+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo= +github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= +github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= +github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= 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-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= +github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= 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-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-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= +github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.20.3/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= +github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g= +github.com/go-openapi/runtime v0.24.2/go.mod h1:AKurw9fNre+h3ELZfk6ILsfvPN+bvvlaU/M9q/r9hpk= +github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= +github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg= +github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= +github.com/go-openapi/strfmt v0.21.2/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= +github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/validate v0.21.0/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= +github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= +github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -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/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/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= +github.com/gobuffalo/attrs v1.0.3/go.mod h1:KvDJCE0avbufqS0Bw3UV7RQynESY0jjod+572ctX4t8= +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.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.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.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/envy v1.10.2/go.mod h1:qGAGwdvDsaEtPhfBzb3o0SfDea8ByGn9j8bKmVft9z8= +github.com/gobuffalo/fizz v1.14.4/go.mod h1:9/2fGNXNeIFOXEEgTPJwiK63e44RjG+Nc4hfMm1ArGM= +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.3.0/go.mod h1:5pf3aGnsvqvCj50AVni7mJJF8ICxGZ8HomberC3pXLE= +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/v2 v2.1.0/go.mod h1:4yoTNk4bYuP3BMM6uQKYPvtP6WsXFGm2w2EFYZdRls8= 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.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/github_flavored_markdown v1.1.3/go.mod h1:IzgO5xS6hqkDmUh91BW/+Qxo/qYnvfzoz3A7uLkg77I= +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/helpers v0.6.7/go.mod h1:j0u1iC1VqlCaJEEVkZN8Ia3TEzfj/zoXANqyJExTMTA= 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/here v0.6.7/go.mod h1:vuCfanjqckTuRlqAitJz6QC4ABNnS27wLb816UhsPcc= +github.com/gobuffalo/httptest v1.5.2 h1:GpGy520SfY1QEmyPvaqmznTpG4gEQqQ82HtHqyNEreM= +github.com/gobuffalo/httptest v1.5.2/go.mod h1:FA23yjsWLGj92mVV74Qtc8eqluc11VqcWr8/C1vxt4g= 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/logger v1.0.7/go.mod h1:u40u6Bq3VVvaMcy5sRBclD8SXhBYPS0Qk95ubt+1xJM= 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/nulls v0.4.2/go.mod h1:EElw2zmBYafU2R9W4Ii1ByIj177wA/pc0JdjtD0EsH8= +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.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/packd v1.0.2/go.mod h1:sUc61tDqGMXON80zpKGp92lDb86Km28jfvX7IAyxFT8= +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/plush/v4 v4.1.16/go.mod h1:6t7swVsarJ8qSLw1qyAH/KbrcSTwdun2ASEQkOznakg= +github.com/gobuffalo/pop/v6 v6.0.8 h1:9+5ShHYh3x9NDFCITfm/gtKDDRSgOwiY7kA0Hf7N9aQ= +github.com/gobuffalo/pop/v6 v6.0.8/go.mod h1:f4JQ4Zvkffcevz+t+XAwBLStD7IQs19DiIGIDFYw1eA= 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/gobuffalo/tags/v3 v3.1.4/go.mod h1:ArRNo3ErlHO8BtdA0REaZxijuWnWzF6PUXngmMXd2I0= +github.com/gobuffalo/validate/v3 v3.3.3/go.mod h1:YC7FsbJ/9hW/VjQdmXPvFqvRis4vrRYFxr69WiNZw6g= +github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-yaml v1.9.6 h1:KhAu1zf9JXnm3vbG49aDE0E5uEBUsM4uwD31/58ZWyI= +github.com/goccy/go-yaml v1.9.6/go.mod h1:JubOolP3gh0HpiBc4BLRD4YmjEjHAmIIB2aaXKkTfoE= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= 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/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 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/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= 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/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -372,7 +878,8 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -385,20 +892,42 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4/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/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-jsonnet v0.19.0/go.mod h1:5JVT33JVCoehdTj5Z2KJq1eIdt3Nb8PCmZ+W5D8U350= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -406,395 +935,706 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= +github.com/google/pprof v0.0.0-20221010195024-131d412537ea/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= 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/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= +github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/gopherjs/gopherjs v0.0.0-20181004151105-1babbf986f6f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= +github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= +github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= +github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/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/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= 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/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= 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/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.12.0/go.mod h1:ummNFgdgLhhX7aIiy35vVmQNS0rWXknfPE0qe6fmFXg= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/api v1.15.3/go.mod h1:/g/qgcoBcEXALCNZgRRisyTW0nY86++L0KbeAMXYCeY= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.11.0/go.mod h1:yPkX5Q6CsxTFMjQQDJwzeNmUUF5NUGGbrDsv9wTb8cw= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= +github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.6.8/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ= +github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/memberlist v0.3.1/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/hashicorp/serf v0.9.8/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= 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/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= +github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf/go.mod h1:yrqSXGoD/4EKfF26AOGzscPOgTTJcyAwM2rpixWT+t4= 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/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= +github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= +github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= +github.com/jackc/pgconn v1.12.0/go.mod h1:ZkhRC59Llhrq3oSfrikvwQ5NaxYExr6twkdkMLaKono= +github.com/jackc/pgconn v1.12.1/go.mod h1:ZkhRC59Llhrq3oSfrikvwQ5NaxYExr6twkdkMLaKono= +github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI= 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/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= +github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= 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/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.3.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/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/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= +github.com/jackc/pgtype v1.11.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= 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/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= +github.com/jackc/pgx/v4 v4.16.0/go.mod h1:N0A9sFdWzkw/Jy1lwoiB64F2+ugFZi987zRxcPez/wI= +github.com/jackc/pgx/v4 v4.16.1/go.mod h1:SIhx0D5hoADaiXZVyv+3gSm3LCIIINTVO0PficsvWGQ= +github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw= 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/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jandelgado/gcov2lcov v1.0.4/go.mod h1:NnSxK6TMlg1oGDBfGelGbjgorT5/L3cchlbtgFYZSss= +github.com/jandelgado/gcov2lcov v1.0.5 h1:rkBt40h0CVK4oCb8Dps950gvfd1rYvQ8+cWa346lVU0= +github.com/jandelgado/gcov2lcov v1.0.5/go.mod h1:NnSxK6TMlg1oGDBfGelGbjgorT5/L3cchlbtgFYZSss= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.3/go.mod h1:dqRwJGXznQrzw6cWmyo6kH+E7jksEQG/CyVWsJEsJO0= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jezek/xgb v1.0.0/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jtolds/gls v4.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.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= 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.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs= +github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI= +github.com/knadh/koanf/parsers/json v0.1.0 h1:dzSZl5pf5bBcW0Acnu20Djleto19T0CfHcvZ14NJ6fU= +github.com/knadh/koanf/parsers/json v0.1.0/go.mod h1:ll2/MlXcZ2BfXD6YJcjVFzhG9P0TdJ207aIBKQhV2hY= +github.com/knadh/koanf/parsers/toml v0.1.0/go.mod h1:yUprhq6eo3GbyVXFFMdbfZSo928ksS+uo0FFqNMnO18= +github.com/knadh/koanf/parsers/yaml v0.1.0/go.mod h1:cvbUDC7AL23pImuQP0oRw/hPuccrNBS2bps8asS0CwY= +github.com/knadh/koanf/providers/posflag v0.1.0/go.mod h1:SYg03v/t8ISBNrMBRMlojH8OsKowbkXV7giIbBVgbz0= +github.com/knadh/koanf/providers/rawbytes v0.1.0 h1:dpzgu2KO6uf6oCb4aP05KDmKmAmI51k5pe8RYKQ0qME= +github.com/knadh/koanf/providers/rawbytes v0.1.0/go.mod h1:mMTB1/IcJ/yE++A2iEZbY1MLygX7vttU+C+S/YmPu9c= +github.com/knadh/koanf/v2 v2.0.1 h1:1dYGITt1I23x8cfx8ZnldtezdyaZtfAuRtIFOiRzK7g= +github.com/knadh/koanf/v2 v2.0.1/go.mod h1:ZeiIlIDXTE7w1lMT6UVcNiRAS2/rCeLn/GdLNvY1Dus= 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/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/laher/mergefs v0.1.1/go.mod h1:FSY1hYy94on4Tz60waRMGdO1awwS23BacqJlqf9lJ9Q= +github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= 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/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/luna-duclos/instrumentedsql v1.1.3/go.mod h1:9J1njvFds+zN7y85EDhN9XNQLANWwZt2ULeIC8yMNYs= +github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= +github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= 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/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/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mailru/easyjson v0.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.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= 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/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= 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/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= 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-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/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.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-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/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= 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/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/microcosm-cc/bluemonday v1.0.20/go.mod h1:yfBmMi8mxvaZut3Yytv+jTXRY8mxyjJ0/kQBTElld50= +github.com/microcosm-cc/bluemonday v1.0.21/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= +github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= 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/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= +github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= +github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= -github.com/monoculum/formam v0.0.0-20180901015400-4e68be1d79ba/go.mod h1:RKgILGEJq24YyJ2ban8EO0RUVSJlF1pGsEvoLEACr/Q= -github.com/moul/http2curl v0.0.0-20170919181001-9ac6cf4d929b/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= 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/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/nyaruka/phonenumbers v1.0.73/go.mod h1:3aiS+PS3DuYwkbK3xdcmRwMiPNECZ0oENH8qUT1lY7Q= +github.com/nyaruka/phonenumbers v1.1.1 h1:fyoZmpLN2VCmAnc51XcrNOUVP2wT1ZzQl348ggIaXII= +github.com/nyaruka/phonenumbers v1.1.1/go.mod h1:cGaEsOrLjIL0iKGqJR5Rfywy86dSkbApEpXuM9KySNA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/oleiade/reflections v1.0.0/go.mod h1:RbATFBbKYkVdqmSFtx13Bb/tVhR0lgOBXunWTZKeL4w= 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/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= 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/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v1.1.2/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= +github.com/opencontainers/runc v1.1.5/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/openzipkin/zipkin-go v0.4.1/go.mod h1:qY0VqDSN1pOBN94dBc6w2GJlWLiovAyg7Qt6/I9HecM= +github.com/ory/analytics-go/v5 v5.0.1/go.mod h1:lWCiCjAaJkKfgR/BN5DCLMol8BjKS1x+4jxBxff/FF0= +github.com/ory/dockertest/v3 v3.9.1/go.mod h1:42Ir9hmvaAPm0Mgibk6mBPi7SFvTXxEcnztDYOJ//uM= +github.com/ory/go-acc v0.2.6/go.mod h1:4Kb/UnPcT8qRAk3IAxta+hvVapdxTLWtrr7bFLlEgpw= +github.com/ory/go-acc v0.2.9-0.20230103102148-6b1c9a70dbbe h1:rvu4obdvqR0fkSIJ8IfgzKOWwZ5kOT2UNfLq81Qk7rc= +github.com/ory/go-acc v0.2.9-0.20230103102148-6b1c9a70dbbe/go.mod h1:z4n3u6as84LbV4YmgjHhnwtccQqzf4cZlSk9f1FhygI= +github.com/ory/herodot v0.10.3-0.20230626083119-d7e5192f0d88 h1:J0CIFKdpUeqKbVMw7pQ1qLtUnflRM1JWAcOEq7Hp4yg= +github.com/ory/herodot v0.10.3-0.20230626083119-d7e5192f0d88/go.mod h1:MMNmY6MG1uB6fnXYFaHoqdV23DTWctlPsmRCeq/2+wc= github.com/ory/hydra-client-go/v2 v2.0.3 h1:jIx968J9RBnjRuaQ21QMLCwZoa28FPvzYWAQ+88XVLw= github.com/ory/hydra-client-go/v2 v2.0.3/go.mod h1:FRuayIF1H/HD2umlad8c3h7RuHpcmsjBDpW0/R2OQ/U= -github.com/ory/jsonschema/v3 v3.0.1/go.mod h1:jgLHekkFk0uiGdEWGleC+tOm6JSSP8cbf17PnBuGXlw= -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/ory/jsonschema/v3 v3.0.7 h1:GQ9qfZDiJqs4l2d3p56dozCChvejQFZyLKGHYzDzOSo= +github.com/ory/jsonschema/v3 v3.0.7/go.mod h1:g8c8YOtN4TrR2wYeMdT02GDmzJDI0fEW2nI26BECafY= +github.com/ory/viper v1.7.5/go.mod h1:ypOuyJmEUb3oENywQZRgeAMwqgOyDqwboO1tj3DjTaM= +github.com/ory/x v0.0.577 h1:wJRrD2OvEFkbM/cwHrlkSY8VaEO6RUoOnDlUc34YRdk= +github.com/ory/x v0.0.577/go.mod h1:aeJFTlvDLGYSABzPS3z5SeLcYC52Ek7uGZiuYGcTMSU= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pborman/uuid v1.2.1/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/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= +github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs= +github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= +github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= +github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= +github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= +github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= +github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= 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/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= 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/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= 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/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= 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/rabbitmq/amqp091-go v1.5.0/go.mod h1:JsV0ofX5f1nwOGafb8L5rBItt9GyhfQfcJj+oyz0dGg= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/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/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= 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/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= 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/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= +github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= 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/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= +github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sagikazarmark/crypt v0.8.0/go.mod h1:TmKwZAo97S4Fy4sfMH/HX/cQP5D+ijra2NyLpNNmttY= 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/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/seatgeek/logrus-gelf-formatter v0.0.0-20210414080842-5b05eb8ff761 h1:0b8DF5kR0PhRoRXDiEEdzrgBc8UqVY4JWLkQJCRsLME= +github.com/seatgeek/logrus-gelf-formatter v0.0.0-20210414080842-5b05eb8ff761/go.mod h1:/THDZYi7F/BsVEcYzYPqdcWFQ+1C2InkawTKfLOAnzg= +github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= +github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= 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/backo-go v1.0.1/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/sergi/go-diff v1.2.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/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= 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/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 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/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= +github.com/spf13/afero v1.5.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= +github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= 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/cast v1.3.2-0.20200723214538-8d17101741c8/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= +github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= 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/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= +github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= +github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.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/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.14.0 h1:Rg7d3Lo706X9tHsJMUjdiwMpHB7W8WnSVOssIY+JElU= +github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As= 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/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/subosito/gotenv v1.1.1/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 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/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= +github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw= +github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= 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/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= +github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= 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/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= 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/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli/v2 v2.11.0/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo= +github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= +github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= +github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= +github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= 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/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= +github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= 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.etcd.io/etcd/api/v3 v3.5.5/go.mod h1:KFtNaxGDw4Yx/BA4iPPwevUTAuqcsPxzyX8PHydchN8= +go.etcd.io/etcd/client/pkg/v3 v3.5.5/go.mod h1:ggrwbk069qxpKPq8/FKkQ3Xq9y39kbFR4LnKszpRXeQ= +go.etcd.io/etcd/client/v2 v2.305.5/go.mod h1:zQjKllfqfBVyVStbt4FaosoX2iYd8fV/GRy/PbowgP4= +go.etcd.io/etcd/client/v3 v3.5.5/go.mod h1:aApjR4WGlSumpnJ2kloS75h6aHUmAyaPLjHMxpc7E7c= +go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= +go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= +go.mongodb.org/mongo-driver v1.8.3/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= +go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= +go.mongodb.org/mongo-driver v1.10.3/go.mod h1:z4XpeoU6w+9Vht+jAFyLgVrD+jGSQQe0+CBWFHNiHt8= 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.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.36.4 h1:toN8e0U4RWQL4f8H+1eFtaeWe/IkSM3+81qJEDOgShs= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.36.4/go.mod h1:u4OeI4ujQmFbpZOOysLUfYrRWOmEVmvzkM2zExVorXM= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.4 h1:aUEBEdCa6iamGzg6fuYxDA8ThxvOG240mAvWDU+XLio= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.4/go.mod h1:l2MdsbKTocpPS5nQZscqTR9jd8u96VYZdcpF8Sye7mA= +go.opentelemetry.io/contrib/propagators/b3 v1.11.1/go.mod h1:ECIveyMXgnl4gorxFcA7RYjJY/Ql9n20ubhbfDc3QfA= +go.opentelemetry.io/contrib/propagators/jaeger v1.11.1/go.mod h1:dP/N3ZFADH8azBcZfGXEFNBXpEmPTXYcNj9rkw1+2Oc= +go.opentelemetry.io/contrib/samplers/jaegerremote v0.5.2/go.mod h1:Z0aRlRERn9v/3J2K+ATa6ffKyb8/i+/My/gTzFr3dII= +go.opentelemetry.io/otel v1.9.0/go.mod h1:np4EoPGzoPs3O67xUVNoPPcmSvsfOxNlNA4F4AC+0Eo= +go.opentelemetry.io/otel v1.11.1 h1:4WLLAmcfkmDk2ukNXJyq3/kiz/3UzCaYq6PskJsaou4= +go.opentelemetry.io/otel v1.11.1/go.mod h1:1nNhXBbWSD0nsL38H6btgnFN2k4i0sNLHNNMZMSbUGE= +go.opentelemetry.io/otel/exporters/jaeger v1.11.1/go.mod h1:lRa2w3bQ4R4QN6zYsDgy7tEezgoKEu7Ow2g35Y75+KI= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.9.0/go.mod h1:78XhIg8Ht9vR4tbLNUhXsiOnE2HOuSeKAiAcoVQEpOY= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.1/go.mod h1:i8vjiSzbiUC7wOQplijSXMYUpNM93DtlS5CbUT+C6oQ= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.9.0/go.mod h1:0EsCXjZAiiZGnLdEUXM9YjCKuuLZMYyglh2QDXcYKVA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.9.0/go.mod h1:smUdtylgc0YQiUr2PuifS4hBXhAS5xtR6WQhxP1wiNA= +go.opentelemetry.io/otel/exporters/zipkin v1.11.1/go.mod h1:T4S6aVwIS1+MHA+dJHCcPROtZe6ORwnv5vMKPRapsFw= +go.opentelemetry.io/otel/metric v0.33.0 h1:xQAyl7uGEYvrLAiV/09iTJlp1pZnQ9Wl793qbVvED1E= +go.opentelemetry.io/otel/metric v0.33.0/go.mod h1:QlTYc+EnYNq/M2mNk1qDDMRLpqCOj2f/r5c7Fd5FYaI= +go.opentelemetry.io/otel/sdk v1.9.0/go.mod h1:AEZc8nt5bd2F7BC24J5R0mrjYnpEgYHyTcM/vrSple4= +go.opentelemetry.io/otel/sdk v1.11.1/go.mod h1:/l3FE4SupHJ12TduVjUkZtlfFqDCQJlOlithYrdktys= +go.opentelemetry.io/otel/trace v1.9.0/go.mod h1:2737Q0MuG8q1uILYm2YYVkAyLtOofiTNGg6VODnOiPo= +go.opentelemetry.io/otel/trace v1.11.1 h1:ofxdnzsNrGBYXbP7t7zpUK281+go5rF7dvdIZXF8gdQ= +go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/proto/otlp v0.18.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= 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/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= 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= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= 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-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-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-20190605123033-f99c8df09eb5/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-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-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-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220517005047-85d78b3ac167/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= 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-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= 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/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +golang.org/x/exp/shiny v0.0.0-20220722155223-a9213eeb770e/go.mod h1:VjAR7z0ngyATZTELrBSkxOOHhhlnVUxDye4mcjx5h/8= 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/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20220902085622-e7cb96979f69/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY= +golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4= 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= @@ -805,28 +1645,35 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= 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.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 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-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -841,11 +1688,10 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/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-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -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= @@ -853,98 +1699,180 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ 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-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220725212005-46097bf591d3/go.mod h1:AaygXjzTFtRAg2ttMY5RMuhpJ3cNnI0XpyFJD1iQRSM= +golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20220927171203-f486391704dc/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221004154528-8021a29435af/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= 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-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.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-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= +golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= +golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= 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/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/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/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0/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-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-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-20190624222133-a101b041ded4/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-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-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-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/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= @@ -957,22 +1885,52 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= +golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= 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= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= 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/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= +gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= +gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= +gonum.org/v1/gonum v0.12.0/go.mod h1:73TDxJfAAHeA8Mk9mf8NlIppyhQNo5GLTcYeqgo2lvY= 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= +gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= +gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= +gonum.org/v1/plot v0.12.0/go.mod h1:PgiMf9+3A3PnZdJIciIXmyN1FwdAA6rXELSN761oQkw= 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= @@ -989,21 +1947,60 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= +google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= +google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= +google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= +google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= +google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= +google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= +google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= +google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= +google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0= +google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= 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/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-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= @@ -1022,17 +2019,118 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= 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-20200806141610-86f49bd18e98/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= +google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= +google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= +google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= +google.golang.org/genproto v0.0.0-20221109142239-94d6d90a7d66/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= +google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230112194545-e10362b5ecf9/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA= +google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= +google.golang.org/genproto v0.0.0-20230223222841-637eb2293923/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= +google.golang.org/genproto v0.0.0-20230303212802-e74f57abe488/go.mod h1:TvhZT5f700eVlTNwND1xoEZQeWTB2RY/65kplwl/bFA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd h1:sLpv7bNL1AsX3fdnWh9WVh7ejIzXdOc1RRHGeAmeStU= +google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= 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= @@ -1042,6 +2140,37 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag= +google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/grpc/examples v0.0.0-20210304020650-930c79186c99/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= 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= @@ -1051,38 +2180,58 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 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/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/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.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/postgres v1.3.5/go.mod h1:EGCWefLFQSVFrHGy4J8EtiHCWX5Q8t0yz2Jt9aKkGzU= +gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/gorm v1.23.5/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.2.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A= 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= @@ -1090,12 +2239,45 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh 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= +honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= +lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= +modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= +modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= +modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= +modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= +modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= +modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= +modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= +modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU= +modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= +modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= +modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= +modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s= +modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= +modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= +modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= +modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= +modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= 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= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= From 44f1e70cb919eaec6652071dfeb00b3e52bf7e74 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Wed, 16 Aug 2023 07:41:58 +0000 Subject: [PATCH 039/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5619992e0e1..9c0141805e6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-08-15)](#2023-08-15) +- [ (2023-08-16)](#2023-08-16) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) - [Features](#features) @@ -309,7 +309,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-08-15) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-08-16) ### Bug Fixes @@ -326,6 +326,9 @@ Part of https://github.com/ory/network/issues/320 +- Add missing tracing & attributes in oidc strategy + ([#3429](https://github.com/ory/kratos/issues/3429)) + ([09bcb71](https://github.com/ory/kratos/commit/09bcb71f1f0b3238e2d0f4376a1a2290d062c6c1)) - Carry `oauth2_login_challenge` over to registration flow ([#3419](https://github.com/ory/kratos/issues/3419)) ([76241be](https://github.com/ory/kratos/commit/76241bee3dc7fec4690346ee85bc4b9f897fdd34)): @@ -372,6 +375,8 @@ ([e3fcf0c](https://github.com/ory/kratos/commit/e3fcf0c31db9742ed61bcf783e37ee119ed19d42)) - Allow extra migrations in NewPersister ([96c1ff7](https://github.com/ory/kratos/commit/96c1ff7747ea38e23a3892f74b75ee555ed49c88)) +- Hot-reload CORS origins ([#3423](https://github.com/ory/kratos/issues/3423)) + ([157d934](https://github.com/ory/kratos/commit/157d9345aeb04f371f9d85b70c89e8646e781333)) - Provide login hints when registration fails due to duplicate credentials/addresses ([#3430](https://github.com/ory/kratos/issues/3430)) ([8b28469](https://github.com/ory/kratos/commit/8b284697e4a26fb01ad57d2e9ebd8f714be49f33)): From 142994932e449d9948148804502c98ef73daafff Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Wed, 16 Aug 2023 17:47:02 +0200 Subject: [PATCH 040/282] fix: don't return 500 on conflict for POST /admin/identities (#3437) --- identity/error_test.go | 17 +++++++++++++++++ identity/handler.go | 7 ++++++- identity/manager.go | 12 ++++++++---- 3 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 identity/error_test.go diff --git a/identity/error_test.go b/identity/error_test.go new file mode 100644 index 000000000000..a4dabd6dbefe --- /dev/null +++ b/identity/error_test.go @@ -0,0 +1,17 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package identity + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestErrDuplicateCredentials(t *testing.T) { + inner := errors.New("inner error") + err := &ErrDuplicateCredentials{inner, nil, nil, ""} + assert.ErrorIs(t, err, inner) +} diff --git a/identity/handler.go b/identity/handler.go index 8de630ca85ef..7c32e56fa058 100644 --- a/identity/handler.go +++ b/identity/handler.go @@ -11,6 +11,7 @@ import ( "time" "github.com/ory/x/pagination/migrationpagination" + "github.com/ory/x/sqlcon" "github.com/ory/kratos/hash" "github.com/ory/kratos/x" @@ -419,7 +420,11 @@ func (h *Handler) create(w http.ResponseWriter, r *http.Request, _ httprouter.Pa } if err := h.r.IdentityManager().Create(r.Context(), i); err != nil { - h.r.Writer().WriteError(w, r, err) + if errors.Is(err, sqlcon.ErrUniqueViolation) { + h.r.Writer().WriteError(w, r, errors.WithStack(herodot.ErrConflict.WithReason("This identity conflicts with another identity that already exists."))) + } else { + h.r.Writer().WriteError(w, r, err) + } return } diff --git a/identity/manager.go b/identity/manager.go index ee62c5d7caed..b47a03c0ac61 100644 --- a/identity/manager.go +++ b/identity/manager.go @@ -254,7 +254,11 @@ type ErrDuplicateCredentials struct { var _ schema.DuplicateCredentialsHinter = (*ErrDuplicateCredentials)(nil) -func (e ErrDuplicateCredentials) AvailableCredentials() []string { +func (e *ErrDuplicateCredentials) Unwrap() error { + return e.error +} + +func (e *ErrDuplicateCredentials) AvailableCredentials() []string { res := make([]string, len(e.availableCredentials)) for k, v := range e.availableCredentials { res[k] = string(v) @@ -262,14 +266,14 @@ func (e ErrDuplicateCredentials) AvailableCredentials() []string { return res } -func (e ErrDuplicateCredentials) AvailableOIDCProviders() []string { +func (e *ErrDuplicateCredentials) AvailableOIDCProviders() []string { return e.availableOIDCProviders } -func (e ErrDuplicateCredentials) IdentifierHint() string { +func (e *ErrDuplicateCredentials) IdentifierHint() string { return e.identifierHint } -func (e ErrDuplicateCredentials) HasHints() bool { +func (e *ErrDuplicateCredentials) HasHints() bool { return len(e.availableCredentials) > 0 || len(e.availableOIDCProviders) > 0 || len(e.identifierHint) > 0 } From 610c76d9140f2f43217ac55094051a994ea83ecc Mon Sep 17 00:00:00 2001 From: Henning Perl Date: Thu, 17 Aug 2023 13:04:19 +0200 Subject: [PATCH 041/282] feat: transmit current session ID to Hydra when accepting the login (#3426) * chore: change react-native port to 19006 * feat: transmit current session ID when accepting login * fix: upgrade hydra in tests --------- Co-authored-by: Jonas Hungershausen Co-authored-by: aeneasr <3372410+aeneasr@users.noreply.github.com> --- Makefile | 2 +- go.mod | 28 +++++---- go.sum | 59 +++++++++++-------- hydra/fake.go | 10 ++-- hydra/hydra.go | 17 ++++-- selfservice/flow/login/handler.go | 32 +++++----- selfservice/flow/login/hook.go | 16 ++++- selfservice/flow/registration/hook.go | 8 ++- selfservice/flow/verification/handler.go | 8 ++- .../strategy/password/op_login_test.go | 10 ++-- test/e2e/cypress/helpers/index.ts | 2 +- .../profiles/mobile/mfa/backup.spec.ts | 17 ++++-- .../profiles/mobile/settings/errors.spec.ts | 2 +- .../profiles/mobile/settings/success.spec.ts | 11 ++-- test/e2e/playwright.config.ts | 2 +- test/e2e/playwright/kratos.base-config.json | 25 ++------ test/e2e/playwright/setup/default_config.ts | 4 +- test/e2e/profiles/kratos.base.yml | 4 +- test/e2e/run.sh | 9 +-- 19 files changed, 153 insertions(+), 113 deletions(-) diff --git a/Makefile b/Makefile index 1656375c5a31..d1eb8fae5ef1 100644 --- a/Makefile +++ b/Makefile @@ -52,7 +52,7 @@ docs/swagger: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -d -b .bin v1.52.2 .bin/hydra: Makefile - bash <(curl https://raw.githubusercontent.com/ory/meta/master/install.sh) -d -b .bin hydra v2.0.2 + bash <(curl https://raw.githubusercontent.com/ory/meta/master/install.sh) -d -b .bin hydra v2.2.0-rc.3 .bin/ory: Makefile curl https://raw.githubusercontent.com/ory/meta/master/install.sh | bash -s -- -b .bin ory v0.2.2 diff --git a/go.mod b/go.mod index b02a682e7151..0eca98e31a61 100644 --- a/go.mod +++ b/go.mod @@ -72,11 +72,11 @@ require ( github.com/ory/go-acc v0.2.9-0.20230103102148-6b1c9a70dbbe github.com/ory/graceful v0.1.4-0.20230301144740-e222150c51d0 github.com/ory/herodot v0.10.3-0.20230626083119-d7e5192f0d88 - github.com/ory/hydra-client-go/v2 v2.0.3 + github.com/ory/hydra-client-go/v2 v2.2.0-rc.3 github.com/ory/jsonschema/v3 v3.0.8 github.com/ory/mail/v3 v3.0.0 github.com/ory/nosurf v1.2.7 - github.com/ory/x v0.0.580 + github.com/ory/x v0.0.581 github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 github.com/pkg/errors v0.9.1 github.com/pquerna/otp v1.4.0 @@ -96,12 +96,13 @@ require ( go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.4 go.opentelemetry.io/otel v1.11.1 go.opentelemetry.io/otel/trace v1.11.1 - golang.org/x/crypto v0.11.0 - golang.org/x/net v0.10.0 - golang.org/x/oauth2 v0.6.0 + golang.org/x/crypto v0.12.0 + golang.org/x/net v0.14.0 + golang.org/x/oauth2 v0.11.0 golang.org/x/sync v0.1.0 + golang.org/x/text v0.12.0 golang.org/x/tools/cmd/cover v0.1.0-deprecated - google.golang.org/grpc v1.54.0 + google.golang.org/grpc v1.55.0 ) require ( @@ -168,7 +169,7 @@ require ( github.com/goccy/go-yaml v1.9.6 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/glog v1.0.0 // indirect + github.com/golang/glog v1.1.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/btree v1.0.1 // indirect github.com/google/go-querystring v1.0.0 // indirect @@ -295,17 +296,18 @@ require ( go.opentelemetry.io/otel/exporters/zipkin v1.11.1 // indirect go.opentelemetry.io/otel/metric v0.33.0 // indirect go.opentelemetry.io/otel/sdk v1.11.1 // indirect - go.opentelemetry.io/proto/otlp v0.18.0 // indirect + go.opentelemetry.io/proto/otlp v0.19.0 // indirect golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect golang.org/x/mod v0.10.0 // indirect - golang.org/x/sys v0.10.0 // indirect - golang.org/x/term v0.10.0 // indirect - golang.org/x/text v0.11.0 // indirect + golang.org/x/sys v0.11.0 // indirect + golang.org/x/term v0.11.0 // indirect golang.org/x/tools v0.7.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd // indirect - google.golang.org/protobuf v1.30.0 // indirect + google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index 4362b761c20b..cc12bfcf045d 100644 --- a/go.sum +++ b/go.sum @@ -137,6 +137,7 @@ github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvA github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk= github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= @@ -360,11 +361,13 @@ github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w github.com/golang/gddo v0.0.0-20190904175337-72a348e765d2 h1:xisWqjiKEff2B0KfFYGpCqc3M3zdTz+OHQHRc09FeYk= 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/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= +github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -495,6 +498,7 @@ github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iP github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0= github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= @@ -802,8 +806,8 @@ github.com/ory/graceful v0.1.4-0.20230301144740-e222150c51d0 h1:VMUeLRfQD14fOMvh github.com/ory/graceful v0.1.4-0.20230301144740-e222150c51d0/go.mod h1:hg2iCy+LCWOXahBZ+NQa4dk8J2govyQD79rrqrgMyY8= github.com/ory/herodot v0.10.3-0.20230626083119-d7e5192f0d88 h1:J0CIFKdpUeqKbVMw7pQ1qLtUnflRM1JWAcOEq7Hp4yg= github.com/ory/herodot v0.10.3-0.20230626083119-d7e5192f0d88/go.mod h1:MMNmY6MG1uB6fnXYFaHoqdV23DTWctlPsmRCeq/2+wc= -github.com/ory/hydra-client-go/v2 v2.0.3 h1:jIx968J9RBnjRuaQ21QMLCwZoa28FPvzYWAQ+88XVLw= -github.com/ory/hydra-client-go/v2 v2.0.3/go.mod h1:FRuayIF1H/HD2umlad8c3h7RuHpcmsjBDpW0/R2OQ/U= +github.com/ory/hydra-client-go/v2 v2.2.0-rc.3 h1:0AT8RYiPhT/+brKMSIX/0guSlDK3tg1AcXZgrb5F/tw= +github.com/ory/hydra-client-go/v2 v2.2.0-rc.3/go.mod h1:BS2mJTU+3d+Ii4JXLHlXcjS/BBSIu8OEH0AO71rAVt0= github.com/ory/jsonschema/v3 v3.0.8 h1:Ssdb3eJ4lDZ/+XnGkvQS/te0p+EkolqwTsDOCxr/FmU= github.com/ory/jsonschema/v3 v3.0.8/go.mod h1:ZPzqjDkwd3QTnb2Z6PAS+OTvBE2x5i6m25wCGx54W/0= github.com/ory/mail v2.3.1+incompatible/go.mod h1:87D9/1gB6ewElQoN0lXJ0ayfqcj3cW3qCTXh+5E9mfU= @@ -813,8 +817,8 @@ github.com/ory/nosurf v1.2.7 h1:YrHrbSensQyU6r6HT/V5+HPdVEgrOTMJiLoJABSBOp4= github.com/ory/nosurf v1.2.7/go.mod h1:d4L3ZBa7Amv55bqxCBtCs63wSlyaiCkWVl4vKf3OUxA= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2 h1:zm6sDvHy/U9XrGpixwHiuAwpp0Ock6khSVHkrv6lQQU= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/ory/x v0.0.580 h1:2acv/ORSaAnRGe7wEtWeyrT464o7r+8HC1fZGAb8Ui8= -github.com/ory/x v0.0.580/go.mod h1:zUGmLuqZ81XQPeTBmE1Fhfvr1ygEkDJky33IxvRaioA= +github.com/ory/x v0.0.581 h1:WjSAjuOluINj6wXn2bKbjpDbrBAkEyBFLOBgZeDfsIM= +github.com/ory/x v0.0.581/go.mod h1:zUGmLuqZ81XQPeTBmE1Fhfvr1ygEkDJky33IxvRaioA= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -1071,8 +1075,8 @@ go.opentelemetry.io/otel/sdk v1.11.1/go.mod h1:/l3FE4SupHJ12TduVjUkZtlfFqDCQJlOl go.opentelemetry.io/otel/trace v1.11.1 h1:ofxdnzsNrGBYXbP7t7zpUK281+go5rF7dvdIZXF8gdQ= go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.18.0 h1:W5hyXNComRa23tGpKwG+FRAc4rfF6ZUg1JReK+QHS80= -go.opentelemetry.io/proto/otlp v0.18.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= +go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= 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.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1109,8 +1113,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220517005047-85d78b3ac167/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1201,8 +1205,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1212,13 +1216,12 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210810183815-faf39c7919d5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= -golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= +golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= +golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= 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= @@ -1320,8 +1323,8 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20191110171634-ad39bd3f0407/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1330,8 +1333,8 @@ golang.org/x/term v0.0.0-20210317153231-de623e64d2a6/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= -golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= -golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= 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= @@ -1342,8 +1345,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 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= @@ -1490,8 +1493,12 @@ google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd h1:sLpv7bNL1AsX3fdnWh9WVh7ejIzXdOc1RRHGeAmeStU= -google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc h1:8DyZCyvI8mE1IdLy/60bS+52xfymkE72wv1asokgtao= +google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= +google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc h1:kVKPf/IiYSBWEWtkIn6wZXwWGCnLKcC8oWfZvXjsGnM= +google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc h1:XSJ8Vk1SWuNr8S18z1NZSziL0CPIXLCCMDOEFtHBOFc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1512,8 +1519,8 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag= -google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= +google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= +google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= google.golang.org/grpc/examples v0.0.0-20210304020650-930c79186c99 h1:qA8rMbz1wQ4DOFfM2ouD29DG9aHWBm6ZOy9BGxiUMmY= 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= @@ -1528,8 +1535,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= diff --git a/hydra/fake.go b/hydra/fake.go index 90215b8b83ef..9050833bb64b 100644 --- a/hydra/fake.go +++ b/hydra/fake.go @@ -9,7 +9,6 @@ import ( "github.com/ory/herodot" hydraclientgo "github.com/ory/hydra-client-go/v2" - "github.com/ory/kratos/session" ) const ( @@ -28,14 +27,17 @@ func NewFake() *FakeHydra { return &FakeHydra{} } -func (h *FakeHydra) AcceptLoginRequest(_ context.Context, loginChallenge string, _ string, _ session.AuthenticationMethods) (string, error) { - switch loginChallenge { +func (h *FakeHydra) AcceptLoginRequest(_ context.Context, params AcceptLoginRequestParams) (string, error) { + if params.SessionID == "" { + return "", errors.New("session id must not be empty") + } + switch params.LoginChallenge { case FakeInvalidLoginChallenge: return "", ErrFakeAcceptLoginRequestFailed case FakeValidLoginChallenge: return FakePostLoginURL, nil default: - panic("unknown fake login_challenge " + loginChallenge) + panic("unknown fake login_challenge " + params.LoginChallenge) } } diff --git a/hydra/hydra.go b/hydra/hydra.go index c0e94f63d5d3..1772decce090 100644 --- a/hydra/hydra.go +++ b/hydra/hydra.go @@ -28,8 +28,14 @@ type ( Provider interface { Hydra() Hydra } + AcceptLoginRequestParams struct { + LoginChallenge string + IdentityID string + SessionID string + AuthenticationMethods session.AuthenticationMethods + } Hydra interface { - AcceptLoginRequest(ctx context.Context, loginChallenge string, subject string, amr session.AuthenticationMethods) (string, error) + AcceptLoginRequest(ctx context.Context, params AcceptLoginRequestParams) (string, error) GetLoginRequest(ctx context.Context, loginChallenge string) (*hydraclientgo.OAuth2LoginRequest, error) } DefaultHydra struct { @@ -84,15 +90,16 @@ func (h *DefaultHydra) getAdminAPIClient(ctx context.Context) (hydraclientgo.OAu return hydraclientgo.NewAPIClient(configuration).OAuth2Api, nil } -func (h *DefaultHydra) AcceptLoginRequest(ctx context.Context, loginChallenge string, subject string, amr session.AuthenticationMethods) (string, error) { +func (h *DefaultHydra) AcceptLoginRequest(ctx context.Context, params AcceptLoginRequestParams) (string, error) { remember := h.d.Config().SessionPersistentCookie(ctx) rememberFor := int64(h.d.Config().SessionLifespan(ctx) / time.Second) - alr := hydraclientgo.NewAcceptOAuth2LoginRequest(subject) + alr := hydraclientgo.NewAcceptOAuth2LoginRequest(params.IdentityID) + alr.IdentityProviderSessionId = ¶ms.SessionID alr.Remember = &remember alr.RememberFor = &rememberFor alr.Amr = []string{} - for _, r := range amr { + for _, r := range params.AuthenticationMethods { alr.Amr = append(alr.Amr, string(r.Method)) } @@ -101,7 +108,7 @@ func (h *DefaultHydra) AcceptLoginRequest(ctx context.Context, loginChallenge st return "", err } - resp, r, err := aa.AcceptOAuth2LoginRequest(ctx).LoginChallenge(loginChallenge).AcceptOAuth2LoginRequest(*alr).Execute() + resp, r, err := aa.AcceptOAuth2LoginRequest(ctx).LoginChallenge(params.LoginChallenge).AcceptOAuth2LoginRequest(*alr).Execute() if err != nil { innerErr := herodot.ErrInternalServerError.WithWrap(err).WithReasonf("Unable to accept OAuth 2.0 Login Challenge.") if r != nil { diff --git a/selfservice/flow/login/handler.go b/selfservice/flow/login/handler.go index de939f9e89bb..aa512f8c2574 100644 --- a/selfservice/flow/login/handler.go +++ b/selfservice/flow/login/handler.go @@ -9,30 +9,26 @@ import ( "time" "github.com/gofrs/uuid" + "github.com/julienschmidt/httprouter" + "github.com/pkg/errors" "github.com/ory/herodot" hydraclientgo "github.com/ory/hydra-client-go/v2" + "github.com/ory/kratos/driver/config" "github.com/ory/kratos/hydra" - "github.com/ory/kratos/selfservice/sessiontokenexchange" - "github.com/ory/kratos/text" - "github.com/ory/x/sqlxx" - "github.com/ory/x/stringsx" - - "github.com/ory/nosurf" - "github.com/ory/kratos/identity" "github.com/ory/kratos/schema" - "github.com/ory/kratos/ui/node" - "github.com/ory/x/decoderx" - - "github.com/julienschmidt/httprouter" - "github.com/pkg/errors" - - "github.com/ory/kratos/driver/config" "github.com/ory/kratos/selfservice/errorx" "github.com/ory/kratos/selfservice/flow" + "github.com/ory/kratos/selfservice/sessiontokenexchange" "github.com/ory/kratos/session" + "github.com/ory/kratos/text" + "github.com/ory/kratos/ui/node" "github.com/ory/kratos/x" + "github.com/ory/nosurf" + "github.com/ory/x/decoderx" + "github.com/ory/x/sqlxx" + "github.com/ory/x/stringsx" "github.com/ory/x/urlx" ) @@ -451,7 +447,13 @@ func (h *Handler) createBrowserLoginFlow(w http.ResponseWriter, r *http.Request, return } - rt, err := h.d.Hydra().AcceptLoginRequest(r.Context(), string(hydraLoginChallenge), sess.IdentityID.String(), sess.AMR) + rt, err := h.d.Hydra().AcceptLoginRequest(r.Context(), + hydra.AcceptLoginRequestParams{ + LoginChallenge: string(hydraLoginChallenge), + IdentityID: sess.IdentityID.String(), + SessionID: sess.ID.String(), + AuthenticationMethods: sess.AMR, + }) if err != nil { h.d.SelfServiceErrorManager().Forward(r.Context(), w, r, err) return diff --git a/selfservice/flow/login/hook.go b/selfservice/flow/login/hook.go index 3cf333c4691f..c04b8cd0b2e3 100644 --- a/selfservice/flow/login/hook.go +++ b/selfservice/flow/login/hook.go @@ -239,7 +239,13 @@ func (e *HookExecutor) PostLoginHook( // If Kratos is used as a Hydra login provider, we need to redirect back to Hydra by returning a 422 status // with the post login challenge URL as the body. if a.OAuth2LoginChallenge != "" { - postChallengeURL, err := e.d.Hydra().AcceptLoginRequest(r.Context(), string(a.OAuth2LoginChallenge), i.ID.String(), s.AMR) + postChallengeURL, err := e.d.Hydra().AcceptLoginRequest(r.Context(), + hydra.AcceptLoginRequestParams{ + LoginChallenge: string(a.OAuth2LoginChallenge), + IdentityID: i.ID.String(), + SessionID: s.ID.String(), + AuthenticationMethods: s.AMR, + }) if err != nil { return err } @@ -267,7 +273,13 @@ func (e *HookExecutor) PostLoginHook( finalReturnTo := returnTo.String() if a.OAuth2LoginChallenge != "" { - rt, err := e.d.Hydra().AcceptLoginRequest(r.Context(), string(a.OAuth2LoginChallenge), i.ID.String(), s.AMR) + rt, err := e.d.Hydra().AcceptLoginRequest(r.Context(), + hydra.AcceptLoginRequestParams{ + LoginChallenge: string(a.OAuth2LoginChallenge), + IdentityID: i.ID.String(), + SessionID: s.ID.String(), + AuthenticationMethods: s.AMR, + }) if err != nil { return err } diff --git a/selfservice/flow/registration/hook.go b/selfservice/flow/registration/hook.go index ee893f86572c..83299d944262 100644 --- a/selfservice/flow/registration/hook.go +++ b/selfservice/flow/registration/hook.go @@ -245,7 +245,13 @@ func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Reque // redirect to the verification URL first and then return to Hydra. finalReturnTo = a.ReturnToVerification } else { - callbackURL, err := e.d.Hydra().AcceptLoginRequest(r.Context(), string(a.OAuth2LoginChallenge), i.ID.String(), s.AMR) + callbackURL, err := e.d.Hydra().AcceptLoginRequest(r.Context(), + hydra.AcceptLoginRequestParams{ + LoginChallenge: string(a.OAuth2LoginChallenge), + IdentityID: i.ID.String(), + SessionID: s.ID.String(), + AuthenticationMethods: s.AMR, + }) if err != nil { return err } diff --git a/selfservice/flow/verification/handler.go b/selfservice/flow/verification/handler.go index f47d13167dcf..48b440621dbc 100644 --- a/selfservice/flow/verification/handler.go +++ b/selfservice/flow/verification/handler.go @@ -448,7 +448,13 @@ func (h *Handler) updateVerificationFlow(w http.ResponseWriter, r *http.Request, return } - callbackURL, err := h.d.Hydra().AcceptLoginRequest(r.Context(), string(f.OAuth2LoginChallenge), s.IdentityID.String(), s.AMR) + callbackURL, err := h.d.Hydra().AcceptLoginRequest(r.Context(), + hydra.AcceptLoginRequestParams{ + LoginChallenge: string(f.OAuth2LoginChallenge), + IdentityID: s.IdentityID.String(), + SessionID: s.ID.String(), + AuthenticationMethods: s.AMR, + }) if err != nil { h.d.VerificationFlowErrorHandler().WriteFlowError(w, r, f, node.DefaultGroup, err) return diff --git a/selfservice/strategy/password/op_login_test.go b/selfservice/strategy/password/op_login_test.go index 0c4c5991ecd1..fd0f00eda6d1 100644 --- a/selfservice/strategy/password/op_login_test.go +++ b/selfservice/strategy/password/op_login_test.go @@ -37,7 +37,6 @@ import ( "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" ) @@ -93,13 +92,14 @@ func newHydra(t *testing.T, loginUI string, consentUI string) (hydraAdmin string hydraResource, err := pool.RunWithOptions(&dockertest.RunOptions{ Repository: "oryd/hydra", - Tag: "v2.0.0", + Tag: "v2.2.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", + "SECRETS_SYSTEM=someverylongsecretthatis32byteslong", }, Cmd: []string{"serve", "all", "--dev"}, ExposedPorts: []string{"4444/tcp", "4445/tcp"}, @@ -340,9 +340,9 @@ type AcceptWrongSubject struct { h *hydra.DefaultHydra } -func (h *AcceptWrongSubject) AcceptLoginRequest(ctx context.Context, loginChallenge string, subject string, amr session.AuthenticationMethods) (string, error) { - hackerman := uuid.Must(uuid.NewV4()) - return h.h.AcceptLoginRequest(ctx, loginChallenge, hackerman.String(), amr) +func (h *AcceptWrongSubject) AcceptLoginRequest(ctx context.Context, params hydra.AcceptLoginRequestParams) (string, error) { + params.IdentityID = uuid.Must(uuid.NewV4()).String() + return h.h.AcceptLoginRequest(ctx, params) } func (h *AcceptWrongSubject) GetLoginRequest(ctx context.Context, loginChallenge string) (*hydraclientgo.OAuth2LoginRequest, error) { diff --git a/test/e2e/cypress/helpers/index.ts b/test/e2e/cypress/helpers/index.ts index 7a08a35d3964..1fae8d176adb 100644 --- a/test/e2e/cypress/helpers/index.ts +++ b/test/e2e/cypress/helpers/index.ts @@ -45,7 +45,7 @@ export const APP_URL = ( ).replace(/\/$/, "") export const MOBILE_URL = ( - Cypress.env("mobile_url") || "http://localhost:4457" + Cypress.env("mobile_url") || "http://localhost:19006" ).replace(/\/$/, "") export const SPA_URL = ( Cypress.env("react_url") || "http://localhost:4455" diff --git a/test/e2e/cypress/integration/profiles/mobile/mfa/backup.spec.ts b/test/e2e/cypress/integration/profiles/mobile/mfa/backup.spec.ts index 838a0ff42d74..2bbcd3807c7b 100644 --- a/test/e2e/cypress/integration/profiles/mobile/mfa/backup.spec.ts +++ b/test/e2e/cypress/integration/profiles/mobile/mfa/backup.spec.ts @@ -76,15 +76,22 @@ context("Mobile Profile", () => { cy.get( '[data-testid="field/lookup_secret_regenerate/true"]:disabled', ).should("not.exist") - cy.get('[data-testid="field/lookup_secret_codes/text"]').then(($e) => { - newCodes = $e.text().trim().split(", ") - expect(newCodes.join(", ")).to.not.eq(codes.join(", ")) - }) + + cy.get('[data-testid="field/lookup_secret_codes/text"]') + .and(($e) => { + expect($e.text().trim().split(", ").join(", ")).to.not.eq( + codes.join(", "), + ) + }) + .then(($e) => { + newCodes = $e.text().trim().split(", ") + }) + cy.get('[data-testid="field/lookup_secret_confirm/true"]').click() cy.expectSettingsSaved() cy.get('[data-testid="field/lookup_secret_reveal/true"]').click() - cy.get('[data-testid="field/lookup_secret_codes/text"]').then(($e) => { + cy.get('[data-testid="field/lookup_secret_codes/text"]').and(($e) => { const actualCodes = $e.text().trim().split(", ") expect(actualCodes.join(", ")).to.eq(newCodes.join(", ")) }) diff --git a/test/e2e/cypress/integration/profiles/mobile/settings/errors.spec.ts b/test/e2e/cypress/integration/profiles/mobile/settings/errors.spec.ts index 31fb695e8d04..dd8a2283703a 100644 --- a/test/e2e/cypress/integration/profiles/mobile/settings/errors.spec.ts +++ b/test/e2e/cypress/integration/profiles/mobile/settings/errors.spec.ts @@ -35,7 +35,7 @@ context("Mobile Profile", () => { cy.get( '*[data-testid="settings-profile"] div[data-testid="submit-form"]', - ).should("have.attr", "data-focusable", "true") + ).should("not.have.attr", "data-focusable", "false") cy.get('*[data-testid="field/traits.website"]').should( "contain.text", diff --git a/test/e2e/cypress/integration/profiles/mobile/settings/success.spec.ts b/test/e2e/cypress/integration/profiles/mobile/settings/success.spec.ts index 8a30a3580fc3..89d295bfba7f 100644 --- a/test/e2e/cypress/integration/profiles/mobile/settings/success.spec.ts +++ b/test/e2e/cypress/integration/profiles/mobile/settings/success.spec.ts @@ -38,13 +38,14 @@ context("Mobile Profile", () => { cy.get( '*[data-testid="settings-password"] div[data-testid="submit-form"]', ).click() + cy.expectSettingsSaved() cy.get( '*[data-testid="settings-password"] div[data-testid="submit-form"]', - ).should("have.attr", "data-focusable", "true") + ).should("not.have.attr", "data-focusable", "false") cy.get('*[data-testid="logout"]').click() + cy.get('input[data-testid="identifier"]').should("exist") - cy.visit(MOBILE_URL + "/Home") cy.loginMobile({ email, password }) cy.get('[data-testid="session-token"]').should("not.exist") cy.loginMobile({ email, password: newPassword }) @@ -80,7 +81,7 @@ context("Mobile Profile", () => { ).click() cy.get( '*[data-testid="settings-profile"] div[data-testid="submit-form"]', - ).should("have.attr", "data-focusable", "true") + ).should("not.have.attr", "data-focusable", "false") cy.visit(MOBILE_URL + "/Home") cy.get('[data-testid="session-content"]').should( @@ -101,7 +102,7 @@ context("Mobile Profile", () => { ).click() cy.get( '*[data-testid="settings-profile"] div[data-testid="submit-form"]', - ).should("have.attr", "data-focusable", "true") + ).should("not.have.attr", "data-focusable", "false") cy.visit(MOBILE_URL + "/Home") cy.get('[data-testid="session-content"]').should("contain", newEmail) @@ -120,7 +121,7 @@ context("Mobile Profile", () => { ).click() cy.get( '*[data-testid="settings-profile"] div[data-testid="submit-form"]', - ).should("have.attr", "data-focusable", "true") + ).should("not.have.attr", "data-focusable", "false") cy.get('div[data-testid="field/code"] input').should("be.visible") diff --git a/test/e2e/playwright.config.ts b/test/e2e/playwright.config.ts index 663b48e04de3..677c0a3c2d46 100644 --- a/test/e2e/playwright.config.ts +++ b/test/e2e/playwright.config.ts @@ -22,7 +22,7 @@ export default defineConfig({ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { trace: process.env.CI ? "retain-on-failure" : "on", - baseURL: "http://localhost:4457", + baseURL: "http://localhost:19006", }, /* Configure projects for major browsers */ diff --git a/test/e2e/playwright/kratos.base-config.json b/test/e2e/playwright/kratos.base-config.json index 8486dc910d42..675f1a94862d 100644 --- a/test/e2e/playwright/kratos.base-config.json +++ b/test/e2e/playwright/kratos.base-config.json @@ -12,15 +12,8 @@ "base_url": "http://localhost:4455/", "cors": { "enabled": true, - "allowed_origins": [ - "http://localhost:3000", - "http://localhost:4457" - ], - "allowed_headers": [ - "Authorization", - "Content-Type", - "X-Session-Token" - ] + "allowed_origins": ["http://localhost:3000", "http://localhost:19006"], + "allowed_headers": ["Authorization", "Content-Type", "X-Session-Token"] } } }, @@ -29,18 +22,14 @@ "leak_sensitive_values": true }, "secrets": { - "cookie": [ - "PLEASE-CHANGE-ME-I-AM-VERY-INSECURE" - ], - "cipher": [ - "secret-thirty-two-character-long" - ] + "cookie": ["PLEASE-CHANGE-ME-I-AM-VERY-INSECURE"], + "cipher": ["secret-thirty-two-character-long"] }, "selfservice": { "default_browser_return_url": "http://localhost:4455/", "allowed_return_urls": [ "http://localhost:4455", - "http://localhost:4457", + "http://localhost:19006", "https://www.ory.sh/", "https://example.org/", "https://www.example.org/", @@ -69,9 +58,7 @@ "client_id": "client_id", "client_secret": "client_secret", "issuer_url": "http://localhost:4444/", - "scope": [ - "offline" - ], + "scope": ["offline"], "mapper_url": "file://test/e2e/profiles/oidc/hydra.jsonnet" } ] diff --git a/test/e2e/playwright/setup/default_config.ts b/test/e2e/playwright/setup/default_config.ts index 2617df23ae06..6cb3466b479c 100644 --- a/test/e2e/playwright/setup/default_config.ts +++ b/test/e2e/playwright/setup/default_config.ts @@ -18,7 +18,7 @@ export const default_config: OryKratosConfiguration = { base_url: "http://localhost:4455/", cors: { enabled: true, - allowed_origins: ["http://localhost:3000", "http://localhost:4457"], + allowed_origins: ["http://localhost:3000", "http://localhost:19006"], allowed_headers: ["Authorization", "Content-Type", "X-Session-Token"], }, }, @@ -36,7 +36,7 @@ export const default_config: OryKratosConfiguration = { default_browser_return_url: "http://localhost:4455/", allowed_return_urls: [ "http://localhost:4455", - "http://localhost:4457", + "http://localhost:19006", "https://www.ory.sh/", "https://example.org/", "https://www.example.org/", diff --git a/test/e2e/profiles/kratos.base.yml b/test/e2e/profiles/kratos.base.yml index d57e4b3d8ed5..2c6b6cca29f5 100644 --- a/test/e2e/profiles/kratos.base.yml +++ b/test/e2e/profiles/kratos.base.yml @@ -10,7 +10,7 @@ selfservice: default_browser_return_url: http://localhost:4455/ allowed_return_urls: - http://localhost:4455 - - http://localhost:4457/Callback + - http://localhost:19006/Callback - exp://example.com/Callback - https://www.ory.sh/ - https://example.org/ @@ -30,7 +30,7 @@ serve: enabled: true allowed_origins: - http://localhost:3000 - - http://localhost:4457 + - http://localhost:19006 allowed_headers: - Authorization - Content-Type diff --git a/test/e2e/run.sh b/test/e2e/run.sh index fdb7b623b25f..6119a2b61f8b 100755 --- a/test/e2e/run.sh +++ b/test/e2e/run.sh @@ -34,7 +34,7 @@ export KRATOS_BROWSER_URL=http://localhost:4433/ export KRATOS_ADMIN_URL=http://localhost:4434/ export KRATOS_UI_URL=http://localhost:4456/ export KRATOS_UI_REACT_URL=http://localhost:4458/ -export KRATOS_UI_REACT_NATIVE_URL=http://localhost:4457/ +export KRATOS_UI_REACT_NATIVE_URL=http://localhost:19006/ export LOG_LEAK_SENSITIVE_VALUES=true export DEV_DISABLE_API_FLOW_ENFORCEMENT=true @@ -137,7 +137,7 @@ prepare() { 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 19006 && exit 1 nc -zv localhost 4458 && exit 1 nc -zv localhost 4744 && exit 1 nc -zv localhost 4745 && exit 1 @@ -145,7 +145,7 @@ prepare() { ( cd "$rn_ui_dir" npm i expo-cli - WEB_PORT=4457 KRATOS_URL=http://localhost:4433 npm run web -- --non-interactive \ + KRATOS_URL=http://localhost:4433 CI=1 npm run web \ >"${base}/test/e2e/rn-profile-app.e2e.log" 2>&1 & ) @@ -196,6 +196,7 @@ prepare() { LOG_LEVEL=trace \ URLS_LOGIN=http://localhost:4455/login \ URLS_CONSENT=http://localhost:4746/consent \ + SECRETS_SYSTEM="[\"1234567890123456789012345678901\"]" \ hydra serve all --dev >"${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) @@ -286,7 +287,7 @@ run() { http-get://localhost:4445/health/ready \ http-get://localhost:4446/ \ http-get://localhost:4456/health/alive \ - http-get://localhost:4457/ \ + http-get://localhost:19006/ \ http-get://localhost:4437/mail \ http-get://localhost:4458/ \ http-get://localhost:4459/health From c09e30c640df9c3c43416f0bb20dc804895c99ac Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Thu, 17 Aug 2023 11:06:35 +0000 Subject: [PATCH 042/282] autogen(openapi): regenerate swagger spec and internal client [skip ci] --- internal/client-go/model_o_auth2_client.go | 116 +++++++++++++++++- ...consent_request_open_id_connect_context.go | 36 ++++++ .../client-go/model_o_auth2_login_request.go | 36 ++++++ internal/httpclient/model_o_auth2_client.go | 116 +++++++++++++++++- ...consent_request_open_id_connect_context.go | 36 ++++++ .../httpclient/model_o_auth2_login_request.go | 36 ++++++ spec/api.json | 34 +++-- spec/swagger.json | 44 ++++--- 8 files changed, 423 insertions(+), 31 deletions(-) diff --git a/internal/client-go/model_o_auth2_client.go b/internal/client-go/model_o_auth2_client.go index fbbed3db8d99..eab35e350486 100644 --- a/internal/client-go/model_o_auth2_client.go +++ b/internal/client-go/model_o_auth2_client.go @@ -18,8 +18,11 @@ import ( // OAuth2Client struct for OAuth2Client type OAuth2Client struct { - AllowedCorsOrigins []string `json:"allowed_cors_origins,omitempty"` - Audience []string `json:"audience,omitempty"` + AdditionalPropertiesField map[string]interface{} `json:"AdditionalProperties,omitempty"` + // OAuth 2.0 Access Token Strategy AccessTokenStrategy is the strategy used to generate access tokens. Valid options are `jwt` and `opaque`. `jwt` is a bad idea, see https://www.ory.sh/docs/hydra/advanced#json-web-tokens Setting the stragegy here overrides the global setting in `strategies.access_token`. + AccessTokenStrategy *string `json:"access_token_strategy,omitempty"` + AllowedCorsOrigins []string `json:"allowed_cors_origins,omitempty"` + Audience []string `json:"audience,omitempty"` // Specify a time duration in milliseconds, seconds, minutes, hours. AuthorizationCodeGrantAccessTokenLifespan *string `json:"authorization_code_grant_access_token_lifespan,omitempty"` // Specify a time duration in milliseconds, seconds, minutes, hours. @@ -87,9 +90,11 @@ type OAuth2Client struct { Scope *string `json:"scope,omitempty"` // OpenID Connect Sector Identifier URI 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"` + // SkipConsent skips the consent screen for this client. This field can only be set from the admin API. + SkipConsent *bool `json:"skip_consent,omitempty"` // OpenID Connect Subject Type 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"` - // OAuth 2.0 Token Endpoint Authentication Method Requested Client Authentication method for the Token Endpoint. The options are: `client_secret_post`: (default) Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` in the HTTP body. `client_secret_basic`: Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` encoded in the HTTP Authorization header. `private_key_jwt`: Use JSON Web Tokens to authenticate the client. `none`: Used for public clients (native apps, mobile apps) which can not have secrets. + // OAuth 2.0 Token Endpoint Authentication Method Requested Client Authentication method for the Token Endpoint. The options are: `client_secret_basic`: (default) Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` encoded in the HTTP Authorization header. `client_secret_post`: Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` in the HTTP body. `private_key_jwt`: Use JSON Web Tokens to authenticate the client. `none`: Used for public clients (native apps, mobile apps) which can not have secrets. TokenEndpointAuthMethod *string `json:"token_endpoint_auth_method,omitempty"` // OAuth 2.0 Token Endpoint Signing Algorithm Requested Client Authentication signing algorithm for the Token Endpoint. TokenEndpointAuthSigningAlg *string `json:"token_endpoint_auth_signing_alg,omitempty"` @@ -118,6 +123,70 @@ func NewOAuth2ClientWithDefaults() *OAuth2Client { return &this } +// GetAdditionalPropertiesField returns the AdditionalPropertiesField field value if set, zero value otherwise. +func (o *OAuth2Client) GetAdditionalPropertiesField() map[string]interface{} { + if o == nil || o.AdditionalPropertiesField == nil { + var ret map[string]interface{} + return ret + } + return o.AdditionalPropertiesField +} + +// GetAdditionalPropertiesFieldOk returns a tuple with the AdditionalPropertiesField field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetAdditionalPropertiesFieldOk() (map[string]interface{}, bool) { + if o == nil || o.AdditionalPropertiesField == nil { + return nil, false + } + return o.AdditionalPropertiesField, true +} + +// HasAdditionalPropertiesField returns a boolean if a field has been set. +func (o *OAuth2Client) HasAdditionalPropertiesField() bool { + if o != nil && o.AdditionalPropertiesField != nil { + return true + } + + return false +} + +// SetAdditionalPropertiesField gets a reference to the given map[string]interface{} and assigns it to the AdditionalPropertiesField field. +func (o *OAuth2Client) SetAdditionalPropertiesField(v map[string]interface{}) { + o.AdditionalPropertiesField = v +} + +// GetAccessTokenStrategy returns the AccessTokenStrategy field value if set, zero value otherwise. +func (o *OAuth2Client) GetAccessTokenStrategy() string { + if o == nil || o.AccessTokenStrategy == nil { + var ret string + return ret + } + return *o.AccessTokenStrategy +} + +// GetAccessTokenStrategyOk returns a tuple with the AccessTokenStrategy field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetAccessTokenStrategyOk() (*string, bool) { + if o == nil || o.AccessTokenStrategy == nil { + return nil, false + } + return o.AccessTokenStrategy, true +} + +// HasAccessTokenStrategy returns a boolean if a field has been set. +func (o *OAuth2Client) HasAccessTokenStrategy() bool { + if o != nil && o.AccessTokenStrategy != nil { + return true + } + + return false +} + +// SetAccessTokenStrategy gets a reference to the given string and assigns it to the AccessTokenStrategy field. +func (o *OAuth2Client) SetAccessTokenStrategy(v string) { + o.AccessTokenStrategy = &v +} + // GetAllowedCorsOrigins returns the AllowedCorsOrigins field value if set, zero value otherwise. func (o *OAuth2Client) GetAllowedCorsOrigins() []string { if o == nil || o.AllowedCorsOrigins == nil { @@ -1368,6 +1437,38 @@ func (o *OAuth2Client) SetSectorIdentifierUri(v string) { o.SectorIdentifierUri = &v } +// GetSkipConsent returns the SkipConsent field value if set, zero value otherwise. +func (o *OAuth2Client) GetSkipConsent() bool { + if o == nil || o.SkipConsent == nil { + var ret bool + return ret + } + return *o.SkipConsent +} + +// GetSkipConsentOk returns a tuple with the SkipConsent field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetSkipConsentOk() (*bool, bool) { + if o == nil || o.SkipConsent == nil { + return nil, false + } + return o.SkipConsent, true +} + +// HasSkipConsent returns a boolean if a field has been set. +func (o *OAuth2Client) HasSkipConsent() bool { + if o != nil && o.SkipConsent != nil { + return true + } + + return false +} + +// SetSkipConsent gets a reference to the given bool and assigns it to the SkipConsent field. +func (o *OAuth2Client) SetSkipConsent(v bool) { + o.SkipConsent = &v +} + // GetSubjectType returns the SubjectType field value if set, zero value otherwise. func (o *OAuth2Client) GetSubjectType() string { if o == nil || o.SubjectType == nil { @@ -1562,6 +1663,12 @@ func (o *OAuth2Client) SetUserinfoSignedResponseAlg(v string) { func (o OAuth2Client) MarshalJSON() ([]byte, error) { toSerialize := map[string]interface{}{} + if o.AdditionalPropertiesField != nil { + toSerialize["AdditionalProperties"] = o.AdditionalPropertiesField + } + if o.AccessTokenStrategy != nil { + toSerialize["access_token_strategy"] = o.AccessTokenStrategy + } if o.AllowedCorsOrigins != nil { toSerialize["allowed_cors_origins"] = o.AllowedCorsOrigins } @@ -1679,6 +1786,9 @@ func (o OAuth2Client) MarshalJSON() ([]byte, error) { if o.SectorIdentifierUri != nil { toSerialize["sector_identifier_uri"] = o.SectorIdentifierUri } + if o.SkipConsent != nil { + toSerialize["skip_consent"] = o.SkipConsent + } if o.SubjectType != nil { toSerialize["subject_type"] = o.SubjectType } diff --git a/internal/client-go/model_o_auth2_consent_request_open_id_connect_context.go b/internal/client-go/model_o_auth2_consent_request_open_id_connect_context.go index c0cbf7f3129e..68884830a9ee 100644 --- a/internal/client-go/model_o_auth2_consent_request_open_id_connect_context.go +++ b/internal/client-go/model_o_auth2_consent_request_open_id_connect_context.go @@ -17,6 +17,7 @@ import ( // OAuth2ConsentRequestOpenIDConnectContext OAuth2ConsentRequestOpenIDConnectContext struct for OAuth2ConsentRequestOpenIDConnectContext type OAuth2ConsentRequestOpenIDConnectContext struct { + AdditionalPropertiesField map[string]interface{} `json:"AdditionalProperties,omitempty"` // 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. @@ -46,6 +47,38 @@ func NewOAuth2ConsentRequestOpenIDConnectContextWithDefaults() *OAuth2ConsentReq return &this } +// GetAdditionalPropertiesField returns the AdditionalPropertiesField field value if set, zero value otherwise. +func (o *OAuth2ConsentRequestOpenIDConnectContext) GetAdditionalPropertiesField() map[string]interface{} { + if o == nil || o.AdditionalPropertiesField == nil { + var ret map[string]interface{} + return ret + } + return o.AdditionalPropertiesField +} + +// GetAdditionalPropertiesFieldOk returns a tuple with the AdditionalPropertiesField field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2ConsentRequestOpenIDConnectContext) GetAdditionalPropertiesFieldOk() (map[string]interface{}, bool) { + if o == nil || o.AdditionalPropertiesField == nil { + return nil, false + } + return o.AdditionalPropertiesField, true +} + +// HasAdditionalPropertiesField returns a boolean if a field has been set. +func (o *OAuth2ConsentRequestOpenIDConnectContext) HasAdditionalPropertiesField() bool { + if o != nil && o.AdditionalPropertiesField != nil { + return true + } + + return false +} + +// SetAdditionalPropertiesField gets a reference to the given map[string]interface{} and assigns it to the AdditionalPropertiesField field. +func (o *OAuth2ConsentRequestOpenIDConnectContext) SetAdditionalPropertiesField(v map[string]interface{}) { + o.AdditionalPropertiesField = v +} + // GetAcrValues returns the AcrValues field value if set, zero value otherwise. func (o *OAuth2ConsentRequestOpenIDConnectContext) GetAcrValues() []string { if o == nil || o.AcrValues == nil { @@ -208,6 +241,9 @@ func (o *OAuth2ConsentRequestOpenIDConnectContext) SetUiLocales(v []string) { func (o OAuth2ConsentRequestOpenIDConnectContext) MarshalJSON() ([]byte, error) { toSerialize := map[string]interface{}{} + if o.AdditionalPropertiesField != nil { + toSerialize["AdditionalProperties"] = o.AdditionalPropertiesField + } if o.AcrValues != nil { toSerialize["acr_values"] = o.AcrValues } diff --git a/internal/client-go/model_o_auth2_login_request.go b/internal/client-go/model_o_auth2_login_request.go index 9fcd87be72fa..a788c66ed3ca 100644 --- a/internal/client-go/model_o_auth2_login_request.go +++ b/internal/client-go/model_o_auth2_login_request.go @@ -17,6 +17,7 @@ import ( // OAuth2LoginRequest OAuth2LoginRequest struct for OAuth2LoginRequest type OAuth2LoginRequest struct { + AdditionalPropertiesField map[string]interface{} `json:"AdditionalProperties,omitempty"` // 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"` @@ -50,6 +51,38 @@ func NewOAuth2LoginRequestWithDefaults() *OAuth2LoginRequest { return &this } +// GetAdditionalPropertiesField returns the AdditionalPropertiesField field value if set, zero value otherwise. +func (o *OAuth2LoginRequest) GetAdditionalPropertiesField() map[string]interface{} { + if o == nil || o.AdditionalPropertiesField == nil { + var ret map[string]interface{} + return ret + } + return o.AdditionalPropertiesField +} + +// GetAdditionalPropertiesFieldOk returns a tuple with the AdditionalPropertiesField field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2LoginRequest) GetAdditionalPropertiesFieldOk() (map[string]interface{}, bool) { + if o == nil || o.AdditionalPropertiesField == nil { + return nil, false + } + return o.AdditionalPropertiesField, true +} + +// HasAdditionalPropertiesField returns a boolean if a field has been set. +func (o *OAuth2LoginRequest) HasAdditionalPropertiesField() bool { + if o != nil && o.AdditionalPropertiesField != nil { + return true + } + + return false +} + +// SetAdditionalPropertiesField gets a reference to the given map[string]interface{} and assigns it to the AdditionalPropertiesField field. +func (o *OAuth2LoginRequest) SetAdditionalPropertiesField(v map[string]interface{}) { + o.AdditionalPropertiesField = v +} + // GetChallenge returns the Challenge field value if set, zero value otherwise. func (o *OAuth2LoginRequest) GetChallenge() string { if o == nil || o.Challenge == nil { @@ -340,6 +373,9 @@ func (o *OAuth2LoginRequest) SetSubject(v string) { func (o OAuth2LoginRequest) MarshalJSON() ([]byte, error) { toSerialize := map[string]interface{}{} + if o.AdditionalPropertiesField != nil { + toSerialize["AdditionalProperties"] = o.AdditionalPropertiesField + } if o.Challenge != nil { toSerialize["challenge"] = o.Challenge } diff --git a/internal/httpclient/model_o_auth2_client.go b/internal/httpclient/model_o_auth2_client.go index fbbed3db8d99..eab35e350486 100644 --- a/internal/httpclient/model_o_auth2_client.go +++ b/internal/httpclient/model_o_auth2_client.go @@ -18,8 +18,11 @@ import ( // OAuth2Client struct for OAuth2Client type OAuth2Client struct { - AllowedCorsOrigins []string `json:"allowed_cors_origins,omitempty"` - Audience []string `json:"audience,omitempty"` + AdditionalPropertiesField map[string]interface{} `json:"AdditionalProperties,omitempty"` + // OAuth 2.0 Access Token Strategy AccessTokenStrategy is the strategy used to generate access tokens. Valid options are `jwt` and `opaque`. `jwt` is a bad idea, see https://www.ory.sh/docs/hydra/advanced#json-web-tokens Setting the stragegy here overrides the global setting in `strategies.access_token`. + AccessTokenStrategy *string `json:"access_token_strategy,omitempty"` + AllowedCorsOrigins []string `json:"allowed_cors_origins,omitempty"` + Audience []string `json:"audience,omitempty"` // Specify a time duration in milliseconds, seconds, minutes, hours. AuthorizationCodeGrantAccessTokenLifespan *string `json:"authorization_code_grant_access_token_lifespan,omitempty"` // Specify a time duration in milliseconds, seconds, minutes, hours. @@ -87,9 +90,11 @@ type OAuth2Client struct { Scope *string `json:"scope,omitempty"` // OpenID Connect Sector Identifier URI 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"` + // SkipConsent skips the consent screen for this client. This field can only be set from the admin API. + SkipConsent *bool `json:"skip_consent,omitempty"` // OpenID Connect Subject Type 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"` - // OAuth 2.0 Token Endpoint Authentication Method Requested Client Authentication method for the Token Endpoint. The options are: `client_secret_post`: (default) Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` in the HTTP body. `client_secret_basic`: Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` encoded in the HTTP Authorization header. `private_key_jwt`: Use JSON Web Tokens to authenticate the client. `none`: Used for public clients (native apps, mobile apps) which can not have secrets. + // OAuth 2.0 Token Endpoint Authentication Method Requested Client Authentication method for the Token Endpoint. The options are: `client_secret_basic`: (default) Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` encoded in the HTTP Authorization header. `client_secret_post`: Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` in the HTTP body. `private_key_jwt`: Use JSON Web Tokens to authenticate the client. `none`: Used for public clients (native apps, mobile apps) which can not have secrets. TokenEndpointAuthMethod *string `json:"token_endpoint_auth_method,omitempty"` // OAuth 2.0 Token Endpoint Signing Algorithm Requested Client Authentication signing algorithm for the Token Endpoint. TokenEndpointAuthSigningAlg *string `json:"token_endpoint_auth_signing_alg,omitempty"` @@ -118,6 +123,70 @@ func NewOAuth2ClientWithDefaults() *OAuth2Client { return &this } +// GetAdditionalPropertiesField returns the AdditionalPropertiesField field value if set, zero value otherwise. +func (o *OAuth2Client) GetAdditionalPropertiesField() map[string]interface{} { + if o == nil || o.AdditionalPropertiesField == nil { + var ret map[string]interface{} + return ret + } + return o.AdditionalPropertiesField +} + +// GetAdditionalPropertiesFieldOk returns a tuple with the AdditionalPropertiesField field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetAdditionalPropertiesFieldOk() (map[string]interface{}, bool) { + if o == nil || o.AdditionalPropertiesField == nil { + return nil, false + } + return o.AdditionalPropertiesField, true +} + +// HasAdditionalPropertiesField returns a boolean if a field has been set. +func (o *OAuth2Client) HasAdditionalPropertiesField() bool { + if o != nil && o.AdditionalPropertiesField != nil { + return true + } + + return false +} + +// SetAdditionalPropertiesField gets a reference to the given map[string]interface{} and assigns it to the AdditionalPropertiesField field. +func (o *OAuth2Client) SetAdditionalPropertiesField(v map[string]interface{}) { + o.AdditionalPropertiesField = v +} + +// GetAccessTokenStrategy returns the AccessTokenStrategy field value if set, zero value otherwise. +func (o *OAuth2Client) GetAccessTokenStrategy() string { + if o == nil || o.AccessTokenStrategy == nil { + var ret string + return ret + } + return *o.AccessTokenStrategy +} + +// GetAccessTokenStrategyOk returns a tuple with the AccessTokenStrategy field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetAccessTokenStrategyOk() (*string, bool) { + if o == nil || o.AccessTokenStrategy == nil { + return nil, false + } + return o.AccessTokenStrategy, true +} + +// HasAccessTokenStrategy returns a boolean if a field has been set. +func (o *OAuth2Client) HasAccessTokenStrategy() bool { + if o != nil && o.AccessTokenStrategy != nil { + return true + } + + return false +} + +// SetAccessTokenStrategy gets a reference to the given string and assigns it to the AccessTokenStrategy field. +func (o *OAuth2Client) SetAccessTokenStrategy(v string) { + o.AccessTokenStrategy = &v +} + // GetAllowedCorsOrigins returns the AllowedCorsOrigins field value if set, zero value otherwise. func (o *OAuth2Client) GetAllowedCorsOrigins() []string { if o == nil || o.AllowedCorsOrigins == nil { @@ -1368,6 +1437,38 @@ func (o *OAuth2Client) SetSectorIdentifierUri(v string) { o.SectorIdentifierUri = &v } +// GetSkipConsent returns the SkipConsent field value if set, zero value otherwise. +func (o *OAuth2Client) GetSkipConsent() bool { + if o == nil || o.SkipConsent == nil { + var ret bool + return ret + } + return *o.SkipConsent +} + +// GetSkipConsentOk returns a tuple with the SkipConsent field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetSkipConsentOk() (*bool, bool) { + if o == nil || o.SkipConsent == nil { + return nil, false + } + return o.SkipConsent, true +} + +// HasSkipConsent returns a boolean if a field has been set. +func (o *OAuth2Client) HasSkipConsent() bool { + if o != nil && o.SkipConsent != nil { + return true + } + + return false +} + +// SetSkipConsent gets a reference to the given bool and assigns it to the SkipConsent field. +func (o *OAuth2Client) SetSkipConsent(v bool) { + o.SkipConsent = &v +} + // GetSubjectType returns the SubjectType field value if set, zero value otherwise. func (o *OAuth2Client) GetSubjectType() string { if o == nil || o.SubjectType == nil { @@ -1562,6 +1663,12 @@ func (o *OAuth2Client) SetUserinfoSignedResponseAlg(v string) { func (o OAuth2Client) MarshalJSON() ([]byte, error) { toSerialize := map[string]interface{}{} + if o.AdditionalPropertiesField != nil { + toSerialize["AdditionalProperties"] = o.AdditionalPropertiesField + } + if o.AccessTokenStrategy != nil { + toSerialize["access_token_strategy"] = o.AccessTokenStrategy + } if o.AllowedCorsOrigins != nil { toSerialize["allowed_cors_origins"] = o.AllowedCorsOrigins } @@ -1679,6 +1786,9 @@ func (o OAuth2Client) MarshalJSON() ([]byte, error) { if o.SectorIdentifierUri != nil { toSerialize["sector_identifier_uri"] = o.SectorIdentifierUri } + if o.SkipConsent != nil { + toSerialize["skip_consent"] = o.SkipConsent + } if o.SubjectType != nil { toSerialize["subject_type"] = o.SubjectType } diff --git a/internal/httpclient/model_o_auth2_consent_request_open_id_connect_context.go b/internal/httpclient/model_o_auth2_consent_request_open_id_connect_context.go index c0cbf7f3129e..68884830a9ee 100644 --- a/internal/httpclient/model_o_auth2_consent_request_open_id_connect_context.go +++ b/internal/httpclient/model_o_auth2_consent_request_open_id_connect_context.go @@ -17,6 +17,7 @@ import ( // OAuth2ConsentRequestOpenIDConnectContext OAuth2ConsentRequestOpenIDConnectContext struct for OAuth2ConsentRequestOpenIDConnectContext type OAuth2ConsentRequestOpenIDConnectContext struct { + AdditionalPropertiesField map[string]interface{} `json:"AdditionalProperties,omitempty"` // 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. @@ -46,6 +47,38 @@ func NewOAuth2ConsentRequestOpenIDConnectContextWithDefaults() *OAuth2ConsentReq return &this } +// GetAdditionalPropertiesField returns the AdditionalPropertiesField field value if set, zero value otherwise. +func (o *OAuth2ConsentRequestOpenIDConnectContext) GetAdditionalPropertiesField() map[string]interface{} { + if o == nil || o.AdditionalPropertiesField == nil { + var ret map[string]interface{} + return ret + } + return o.AdditionalPropertiesField +} + +// GetAdditionalPropertiesFieldOk returns a tuple with the AdditionalPropertiesField field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2ConsentRequestOpenIDConnectContext) GetAdditionalPropertiesFieldOk() (map[string]interface{}, bool) { + if o == nil || o.AdditionalPropertiesField == nil { + return nil, false + } + return o.AdditionalPropertiesField, true +} + +// HasAdditionalPropertiesField returns a boolean if a field has been set. +func (o *OAuth2ConsentRequestOpenIDConnectContext) HasAdditionalPropertiesField() bool { + if o != nil && o.AdditionalPropertiesField != nil { + return true + } + + return false +} + +// SetAdditionalPropertiesField gets a reference to the given map[string]interface{} and assigns it to the AdditionalPropertiesField field. +func (o *OAuth2ConsentRequestOpenIDConnectContext) SetAdditionalPropertiesField(v map[string]interface{}) { + o.AdditionalPropertiesField = v +} + // GetAcrValues returns the AcrValues field value if set, zero value otherwise. func (o *OAuth2ConsentRequestOpenIDConnectContext) GetAcrValues() []string { if o == nil || o.AcrValues == nil { @@ -208,6 +241,9 @@ func (o *OAuth2ConsentRequestOpenIDConnectContext) SetUiLocales(v []string) { func (o OAuth2ConsentRequestOpenIDConnectContext) MarshalJSON() ([]byte, error) { toSerialize := map[string]interface{}{} + if o.AdditionalPropertiesField != nil { + toSerialize["AdditionalProperties"] = o.AdditionalPropertiesField + } if o.AcrValues != nil { toSerialize["acr_values"] = o.AcrValues } diff --git a/internal/httpclient/model_o_auth2_login_request.go b/internal/httpclient/model_o_auth2_login_request.go index 9fcd87be72fa..a788c66ed3ca 100644 --- a/internal/httpclient/model_o_auth2_login_request.go +++ b/internal/httpclient/model_o_auth2_login_request.go @@ -17,6 +17,7 @@ import ( // OAuth2LoginRequest OAuth2LoginRequest struct for OAuth2LoginRequest type OAuth2LoginRequest struct { + AdditionalPropertiesField map[string]interface{} `json:"AdditionalProperties,omitempty"` // 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"` @@ -50,6 +51,38 @@ func NewOAuth2LoginRequestWithDefaults() *OAuth2LoginRequest { return &this } +// GetAdditionalPropertiesField returns the AdditionalPropertiesField field value if set, zero value otherwise. +func (o *OAuth2LoginRequest) GetAdditionalPropertiesField() map[string]interface{} { + if o == nil || o.AdditionalPropertiesField == nil { + var ret map[string]interface{} + return ret + } + return o.AdditionalPropertiesField +} + +// GetAdditionalPropertiesFieldOk returns a tuple with the AdditionalPropertiesField field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2LoginRequest) GetAdditionalPropertiesFieldOk() (map[string]interface{}, bool) { + if o == nil || o.AdditionalPropertiesField == nil { + return nil, false + } + return o.AdditionalPropertiesField, true +} + +// HasAdditionalPropertiesField returns a boolean if a field has been set. +func (o *OAuth2LoginRequest) HasAdditionalPropertiesField() bool { + if o != nil && o.AdditionalPropertiesField != nil { + return true + } + + return false +} + +// SetAdditionalPropertiesField gets a reference to the given map[string]interface{} and assigns it to the AdditionalPropertiesField field. +func (o *OAuth2LoginRequest) SetAdditionalPropertiesField(v map[string]interface{}) { + o.AdditionalPropertiesField = v +} + // GetChallenge returns the Challenge field value if set, zero value otherwise. func (o *OAuth2LoginRequest) GetChallenge() string { if o == nil || o.Challenge == nil { @@ -340,6 +373,9 @@ func (o *OAuth2LoginRequest) SetSubject(v string) { func (o OAuth2LoginRequest) MarshalJSON() ([]byte, error) { toSerialize := map[string]interface{}{} + if o.AdditionalPropertiesField != nil { + toSerialize["AdditionalProperties"] = o.AdditionalPropertiesField + } if o.Challenge != nil { toSerialize["challenge"] = o.Challenge } diff --git a/spec/api.json b/spec/api.json index b63ad4a5a91c..ba53f81316a8 100755 --- a/spec/api.json +++ b/spec/api.json @@ -119,6 +119,14 @@ }, "OAuth2Client": { "properties": { + "AdditionalProperties": { + "additionalProperties": {}, + "type": "object" + }, + "access_token_strategy": { + "description": "OAuth 2.0 Access Token Strategy AccessTokenStrategy is the strategy used to generate access tokens. Valid options are `jwt` and `opaque`. `jwt` is a bad idea, see https://www.ory.sh/docs/hydra/advanced#json-web-tokens Setting the stragegy here overrides the global setting in `strategies.access_token`.", + "type": "string" + }, "allowed_cors_origins": { "items": { "type": "string" @@ -289,12 +297,16 @@ "description": "OpenID Connect Sector Identifier URI 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" }, + "skip_consent": { + "description": "SkipConsent skips the consent screen for this client. This field can only be set from the admin API.", + "type": "boolean" + }, "subject_type": { "description": "OpenID Connect Subject Type 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": "OAuth 2.0 Token Endpoint Authentication Method Requested Client Authentication method for the Token Endpoint. The options are: `client_secret_post`: (default) Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` in the HTTP body. `client_secret_basic`: Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` encoded in the HTTP Authorization header. `private_key_jwt`: Use JSON Web Tokens to authenticate the client. `none`: Used for public clients (native apps, mobile apps) which can not have secrets.", + "description": "OAuth 2.0 Token Endpoint Authentication Method Requested Client Authentication method for the Token Endpoint. The options are: `client_secret_basic`: (default) Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` encoded in the HTTP Authorization header. `client_secret_post`: Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` in the HTTP body. `private_key_jwt`: Use JSON Web Tokens to authenticate the client. `none`: Used for public clients (native apps, mobile apps) which can not have secrets.", "type": "string" }, "token_endpoint_auth_signing_alg": { @@ -321,6 +333,10 @@ "OAuth2ConsentRequestOpenIDConnectContext": { "description": "OAuth2ConsentRequestOpenIDConnectContext struct for OAuth2ConsentRequestOpenIDConnectContext", "properties": { + "AdditionalProperties": { + "additionalProperties": {}, + "type": "object" + }, "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": { @@ -354,6 +370,10 @@ "OAuth2LoginRequest": { "description": "OAuth2LoginRequest struct for OAuth2LoginRequest", "properties": { + "AdditionalProperties": { + "additionalProperties": {}, + "type": "object" + }, "challenge": { "description": "ID is the identifier (\\\"login challenge\\\") of the login request. It is used to identify the session.", "type": "string" @@ -3279,13 +3299,11 @@ } }, { - "description": "Pagination Page\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.", + "description": "Pagination Page\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.\nThe first page can be retrieved by omitting this parameter. Following page pointers will be returned in the\n`Link` header.", "in": "query", "name": "page", "schema": { - "default": 1, "format": "int64", - "minimum": 1, "type": "integer" } }, @@ -3903,13 +3921,11 @@ } }, { - "description": "Pagination Page\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.", + "description": "Pagination Page\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.\nThe first page can be retrieved by omitting this parameter. Following page pointers will be returned in the\n`Link` header.", "in": "query", "name": "page", "schema": { - "default": 1, "format": "int64", - "minimum": 1, "type": "integer" } }, @@ -4518,13 +4534,11 @@ } }, { - "description": "Pagination Page\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.", + "description": "Pagination Page\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.\nThe first page can be retrieved by omitting this parameter. Following page pointers will be returned in the\n`Link` header.", "in": "query", "name": "page", "schema": { - "default": 1, "format": "int64", - "minimum": 1, "type": "integer" } } diff --git a/spec/swagger.json b/spec/swagger.json index cad0b006024e..2a8213001b3b 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -196,11 +196,9 @@ "in": "query" }, { - "minimum": 1, "type": "integer", "format": "int64", - "default": 1, - "description": "Pagination Page\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.", + "description": "Pagination Page\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.\nThe first page can be retrieved by omitting this parameter. Following page pointers will be returned in the\n`Link` header.", "name": "page", "in": "query" }, @@ -683,11 +681,9 @@ "in": "query" }, { - "minimum": 1, "type": "integer", "format": "int64", - "default": 1, - "description": "Pagination Page\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.", + "description": "Pagination Page\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.\nThe first page can be retrieved by omitting this parameter. Following page pointers will be returned in the\n`Link` header.", "name": "page", "in": "query" }, @@ -1231,11 +1227,9 @@ "in": "query" }, { - "minimum": 1, "type": "integer", "format": "int64", - "default": 1, - "description": "Pagination Page\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.", + "description": "Pagination Page\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.\nThe first page can be retrieved by omitting this parameter. Following page pointers will be returned in the\n`Link` header.", "name": "page", "in": "query" } @@ -3100,6 +3094,14 @@ "type": "object", "title": "OAuth2Client OAuth 2.0 Clients are used to perform OAuth 2.0 and OpenID Connect flows. Usually, OAuth 2.0 clients are generated for applications which want to consume your OAuth 2.0 or OpenID Connect capabilities.", "properties": { + "AdditionalProperties": { + "type": "object", + "additionalProperties": {} + }, + "access_token_strategy": { + "description": "OAuth 2.0 Access Token Strategy AccessTokenStrategy is the strategy used to generate access tokens. Valid options are `jwt` and `opaque`. `jwt` is a bad idea, see https://www.ory.sh/docs/hydra/advanced#json-web-tokens Setting the stragegy here overrides the global setting in `strategies.access_token`.", + "type": "string" + }, "allowed_cors_origins": { "type": "array", "items": { @@ -3271,12 +3273,16 @@ "description": "OpenID Connect Sector Identifier URI 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" }, + "skip_consent": { + "description": "SkipConsent skips the consent screen for this client. This field can only be set from the admin API.", + "type": "boolean" + }, "subject_type": { "description": "OpenID Connect Subject Type 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": "OAuth 2.0 Token Endpoint Authentication Method Requested Client Authentication method for the Token Endpoint. The options are: `client_secret_post`: (default) Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` in the HTTP body. `client_secret_basic`: Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` encoded in the HTTP Authorization header. `private_key_jwt`: Use JSON Web Tokens to authenticate the client. `none`: Used for public clients (native apps, mobile apps) which can not have secrets.", + "description": "OAuth 2.0 Token Endpoint Authentication Method Requested Client Authentication method for the Token Endpoint. The options are: `client_secret_basic`: (default) Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` encoded in the HTTP Authorization header. `client_secret_post`: Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` in the HTTP body. `private_key_jwt`: Use JSON Web Tokens to authenticate the client. `none`: Used for public clients (native apps, mobile apps) which can not have secrets.", "type": "string" }, "token_endpoint_auth_signing_alg": { @@ -3302,6 +3308,10 @@ "description": "OAuth2ConsentRequestOpenIDConnectContext struct for OAuth2ConsentRequestOpenIDConnectContext", "type": "object", "properties": { + "AdditionalProperties": { + "type": "object", + "additionalProperties": {} + }, "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", @@ -3335,6 +3345,10 @@ "description": "OAuth2LoginRequest struct for OAuth2LoginRequest", "type": "object", "properties": { + "AdditionalProperties": { + "type": "object", + "additionalProperties": {} + }, "challenge": { "description": "ID is the identifier (\\\"login challenge\\\") of the login request. It is used to identify the session.", "type": "string" @@ -5872,7 +5886,7 @@ "x-total-count": { "type": "integer", "format": "int64", - "description": "The X-Total-Count HTTP Header\n\nThe `X-Total-Count` header contains the total number of items in the collection." + "description": "The X-Total-Count HTTP Header\n\nThe `X-Total-Count` header contains the total number of items in the collection.\n\nDEPRECATED: This header will be removed eventually. Please use the `Link` header\ninstead to check whether you are on the last page." } } }, @@ -5892,7 +5906,7 @@ "x-total-count": { "type": "integer", "format": "int64", - "description": "The X-Total-Count HTTP Header\n\nThe `X-Total-Count` header contains the total number of items in the collection." + "description": "The X-Total-Count HTTP Header\n\nThe `X-Total-Count` header contains the total number of items in the collection.\n\nDEPRECATED: This header will be removed eventually. Please use the `Link` header\ninstead to check whether you are on the last page." } } }, @@ -5912,7 +5926,7 @@ "x-total-count": { "type": "integer", "format": "int64", - "description": "The X-Total-Count HTTP Header\n\nThe `X-Total-Count` header contains the total number of items in the collection." + "description": "The X-Total-Count HTTP Header\n\nThe `X-Total-Count` header contains the total number of items in the collection.\n\nDEPRECATED: This header will be removed eventually. Please use the `Link` header\ninstead to check whether you are on the last page." } } }, @@ -5932,7 +5946,7 @@ "x-total-count": { "type": "integer", "format": "int64", - "description": "The X-Total-Count HTTP Header\n\nThe `X-Total-Count` header contains the total number of items in the collection." + "description": "The X-Total-Count HTTP Header\n\nThe `X-Total-Count` header contains the total number of items in the collection.\n\nDEPRECATED: This header will be removed eventually. Please use the `Link` header\ninstead to check whether you are on the last page." } } }, @@ -5952,7 +5966,7 @@ "x-total-count": { "type": "integer", "format": "int64", - "description": "The X-Total-Count HTTP Header\n\nThe `X-Total-Count` header contains the total number of items in the collection." + "description": "The X-Total-Count HTTP Header\n\nThe `X-Total-Count` header contains the total number of items in the collection.\n\nDEPRECATED: This header will be removed eventually. Please use the `Link` header\ninstead to check whether you are on the last page." } } }, From 0827ae5b9be3278e83c4585a9b17a64a6c70a4f6 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Thu, 17 Aug 2023 12:31:19 +0000 Subject: [PATCH 043/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c0141805e6a..df2e6b1e214b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-08-16)](#2023-08-16) +- [ (2023-08-17)](#2023-08-17) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) - [Features](#features) @@ -309,7 +309,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-08-16) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-08-17) ### Bug Fixes @@ -335,6 +335,9 @@ Fixes https://github.com/ory/kratos/issues/3321 +- Don't return 500 on conflict for POST /admin/identities + ([#3437](https://github.com/ory/kratos/issues/3437)) + ([1429949](https://github.com/ory/kratos/commit/142994932e449d9948148804502c98ef73daafff)) - False-positives for requiring re-authentication on update ([#3421](https://github.com/ory/kratos/issues/3421)) ([ce8139f](https://github.com/ory/kratos/commit/ce8139f2325a8317388cbcaaa98f3f83d626657b)) @@ -404,6 +407,16 @@ Users can now supply a list of origins for webauthn in the configuration. +- Transmit current session ID to Hydra when accepting the login + ([#3426](https://github.com/ory/kratos/issues/3426)) + ([610c76d](https://github.com/ory/kratos/commit/610c76d9140f2f43217ac55094051a994ea83ecc)): + + - chore: change react-native port to 19006 + + - feat: transmit current session ID when accepting login + + - fix: upgrade hydra in tests + ### Tests - **e2e:** Logout return_to ([#3418](https://github.com/ory/kratos/issues/3418)) From 8bb0d1d243fa5e03b6fe1a746d3317f4c477f5a0 Mon Sep 17 00:00:00 2001 From: Patrik Date: Fri, 18 Aug 2023 16:44:15 +0200 Subject: [PATCH 044/282] chore: add more tracing around webhooks (#3441) --- courier/http.go | 2 +- courier/sms.go | 2 +- go.mod | 3 ++- go.sum | 9 ++++----- request/builder.go | 15 ++++++++++++++- request/builder_test.go | 6 ++++-- selfservice/hook/web_hook.go | 2 +- 7 files changed, 27 insertions(+), 12 deletions(-) diff --git a/courier/http.go b/courier/http.go index 1e70803b9cff..6542d26964af 100644 --- a/courier/http.go +++ b/courier/http.go @@ -33,7 +33,7 @@ func (c *courier) dispatchMailerEmail(ctx context.Context, msg Message) (err err ctx, span := c.deps.Tracer(ctx).Tracer().Start(ctx, "courier.http.dispatchMailerEmail") defer otelx.End(span, &err) - builder, err := request.NewBuilder(c.httpClient.RequestConfig, c.deps) + builder, err := request.NewBuilder(ctx, c.httpClient.RequestConfig, c.deps) if err != nil { return err } diff --git a/courier/sms.go b/courier/sms.go index c73673d3fb66..e6b7a1925a9b 100644 --- a/courier/sms.go +++ b/courier/sms.go @@ -83,7 +83,7 @@ func (c *courier) dispatchSMS(ctx context.Context, msg Message) error { return err } - builder, err := request.NewBuilder(c.smsClient.RequestConfig, c.deps) + builder, err := request.NewBuilder(ctx, c.smsClient.RequestConfig, c.deps) if err != nil { return err } diff --git a/go.mod b/go.mod index 0eca98e31a61..b7a72b85f39b 100644 --- a/go.mod +++ b/go.mod @@ -76,7 +76,7 @@ require ( github.com/ory/jsonschema/v3 v3.0.8 github.com/ory/mail/v3 v3.0.0 github.com/ory/nosurf v1.2.7 - github.com/ory/x v0.0.581 + github.com/ory/x v0.0.583 github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 github.com/pkg/errors v0.9.1 github.com/pquerna/otp v1.4.0 @@ -166,6 +166,7 @@ require ( github.com/gobuffalo/plush/v4 v4.1.18 // indirect github.com/gobuffalo/tags/v3 v3.1.4 // indirect github.com/gobuffalo/validate/v3 v3.3.3 // indirect + github.com/gobwas/glob v0.2.3 // indirect github.com/goccy/go-yaml v1.9.6 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect diff --git a/go.sum b/go.sum index cc12bfcf045d..5422e5e53752 100644 --- a/go.sum +++ b/go.sum @@ -137,7 +137,6 @@ github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvA github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk= github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= @@ -343,6 +342,8 @@ github.com/gobuffalo/tags/v3 v3.1.4 h1:X/ydLLPhgXV4h04Hp2xlbI2oc5MDaa7eub6zw8oHj github.com/gobuffalo/tags/v3 v3.1.4/go.mod h1:ArRNo3ErlHO8BtdA0REaZxijuWnWzF6PUXngmMXd2I0= github.com/gobuffalo/validate/v3 v3.3.3 h1:o7wkIGSvZBYBd6ChQoLxkz2y1pfmhbI4jNJYh6PuNJ4= github.com/gobuffalo/validate/v3 v3.3.3/go.mod h1:YC7FsbJ/9hW/VjQdmXPvFqvRis4vrRYFxr69WiNZw6g= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/goccy/go-yaml v1.9.6 h1:KhAu1zf9JXnm3vbG49aDE0E5uEBUsM4uwD31/58ZWyI= github.com/goccy/go-yaml v1.9.6/go.mod h1:JubOolP3gh0HpiBc4BLRD4YmjEjHAmIIB2aaXKkTfoE= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -367,7 +368,6 @@ github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -498,7 +498,6 @@ github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iP github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= -github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0= github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= @@ -817,8 +816,8 @@ github.com/ory/nosurf v1.2.7 h1:YrHrbSensQyU6r6HT/V5+HPdVEgrOTMJiLoJABSBOp4= github.com/ory/nosurf v1.2.7/go.mod h1:d4L3ZBa7Amv55bqxCBtCs63wSlyaiCkWVl4vKf3OUxA= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2 h1:zm6sDvHy/U9XrGpixwHiuAwpp0Ock6khSVHkrv6lQQU= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/ory/x v0.0.581 h1:WjSAjuOluINj6wXn2bKbjpDbrBAkEyBFLOBgZeDfsIM= -github.com/ory/x v0.0.581/go.mod h1:zUGmLuqZ81XQPeTBmE1Fhfvr1ygEkDJky33IxvRaioA= +github.com/ory/x v0.0.583 h1:z6xkrTip16ytAcEvL+nRdK0J+jPWyBeo8qpFOAErZ1g= +github.com/ory/x v0.0.583/go.mod h1:tgk6em/hJrDRmWAlM2g1hSNnE6rmCOk4eQ/q53/2kZc= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= diff --git a/request/builder.go b/request/builder.go index fae2c3d13d58..48d43856edf1 100644 --- a/request/builder.go +++ b/request/builder.go @@ -13,6 +13,10 @@ import ( "reflect" "strings" + "go.opentelemetry.io/otel/attribute" + + "github.com/ory/x/otelx" + "github.com/google/go-jsonnet" "github.com/hashicorp/go-retryablehttp" "github.com/pkg/errors" @@ -32,6 +36,7 @@ const ( type ( Dependencies interface { x.LoggingProvider + x.TracingProvider x.HTTPClientProvider jsonnetsecure.VMProvider } @@ -42,12 +47,17 @@ type ( } ) -func NewBuilder(config json.RawMessage, deps Dependencies) (*Builder, error) { +func NewBuilder(ctx context.Context, config json.RawMessage, deps Dependencies) (_ *Builder, err error) { + _, span := deps.Tracer(ctx).Tracer().Start(ctx, "request.NewBuilder") + defer otelx.End(span, &err) + c, err := parseConfig(config) if err != nil { return nil, err } + span.SetAttributes(attribute.String("url", c.URL), attribute.String("method", c.Method)) + r, err := retryablehttp.NewRequest(c.Method, c.URL, nil) if err != nil { return nil, err @@ -74,6 +84,9 @@ func (b *Builder) addAuth() error { } func (b *Builder) addBody(ctx context.Context, body interface{}) error { + ctx, span := b.deps.Tracer(ctx).Tracer().Start(ctx, "request.Builder.addBody") + defer span.End() + if isNilInterface(body) { return nil } diff --git a/request/builder_test.go b/request/builder_test.go index a947b75e2e51..cffa032cc2f9 100644 --- a/request/builder_test.go +++ b/request/builder_test.go @@ -18,6 +18,7 @@ import ( "github.com/ory/kratos/x" "github.com/ory/x/jsonnetsecure" "github.com/ory/x/logrusx" + "github.com/ory/x/otelx" ) type testRequestBody struct { @@ -244,7 +245,7 @@ func TestBuildRequest(t *testing.T) { } { t.Run( "request-type="+tc.name, func(t *testing.T) { - rb, err := NewBuilder(json.RawMessage(tc.rawConfig), newTestDependencyProvider(t)) + rb, err := NewBuilder(context.Background(), json.RawMessage(tc.rawConfig), newTestDependencyProvider(t)) require.NoError(t, err) assert.Equal(t, tc.bodyTemplateURI, rb.Config.TemplateURI) @@ -272,7 +273,7 @@ func TestBuildRequest(t *testing.T) { t.Run( "cancel request", func(t *testing.T) { - rb, err := NewBuilder(json.RawMessage( + rb, err := NewBuilder(context.Background(), json.RawMessage( `{ "url": "https://test.kratos.ory.sh/my_endpoint6", "method": "POST", @@ -296,6 +297,7 @@ func newTestDependencyProvider(t *testing.T) *testDependencyProvider { return &testDependencyProvider{ SimpleLoggerWithClient: x.SimpleLoggerWithClient{ L: logrusx.New("kratos", "test"), + T: otelx.NewNoop(nil, nil), }, TestProvider: jsonnetsecure.NewTestProvider(t), } diff --git a/selfservice/hook/web_hook.go b/selfservice/hook/web_hook.go index 474a18343c61..6a5a8f358e47 100644 --- a/selfservice/hook/web_hook.go +++ b/selfservice/hook/web_hook.go @@ -327,7 +327,7 @@ func (e *WebHook) execute(ctx context.Context, data *templateContext) error { } }() - builder, err := request.NewBuilder(e.conf, e.deps) + builder, err := request.NewBuilder(ctx, e.conf, e.deps) if err != nil { return err } From 2f5ba1f3f0325d630fbfda7e3e6fe1fba76a2bba Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Fri, 18 Aug 2023 16:17:57 +0000 Subject: [PATCH 045/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index df2e6b1e214b..7bc320acecc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-08-17)](#2023-08-17) +- [ (2023-08-18)](#2023-08-18) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) - [Features](#features) @@ -309,7 +309,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-08-17) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-08-18) ### Bug Fixes From 6c1d2f1e4173cfb9a7abe2bfe4f20e47b7568d3b Mon Sep 17 00:00:00 2001 From: BrandonNoad Date: Mon, 21 Aug 2023 11:00:37 -0300 Subject: [PATCH 046/282] fix: allow post recovery hooks to interrupt the flow (#3393) --- .../strategy/code/strategy_recovery.go | 8 +-- .../strategy/code/strategy_recovery_test.go | 66 +++++++++++++++++++ .../strategy/link/strategy_recovery.go | 8 +-- .../strategy/link/strategy_recovery_test.go | 66 +++++++++++++++++++ 4 files changed, 140 insertions(+), 8 deletions(-) diff --git a/selfservice/strategy/code/strategy_recovery.go b/selfservice/strategy/code/strategy_recovery.go index 466b9d26c3de..d06c5e2c9009 100644 --- a/selfservice/strategy/code/strategy_recovery.go +++ b/selfservice/strategy/code/strategy_recovery.go @@ -373,6 +373,10 @@ func (s *Strategy) recoveryIssueSession(w http.ResponseWriter, r *http.Request, return s.retryRecoveryFlowWithError(w, r, f.Type, err) } + if err := s.deps.RecoveryExecutor().PostRecoveryHook(w, r, f, sess); err != nil { + return s.retryRecoveryFlowWithError(w, r, f.Type, err) + } + // TODO: How does this work with Mobile? if err := s.deps.SessionManager().UpsertAndIssueCookie(ctx, w, r, sess); err != nil { return s.retryRecoveryFlowWithError(w, r, f.Type, err) @@ -393,10 +397,6 @@ func (s *Strategy) recoveryIssueSession(w http.ResponseWriter, r *http.Request, return s.retryRecoveryFlowWithError(w, r, flow.TypeBrowser, err) } - if err := s.deps.RecoveryExecutor().PostRecoveryHook(w, r, f, sess); err != nil { - return s.retryRecoveryFlowWithError(w, r, f.Type, err) - } - config := s.deps.Config() sf.UI.Messages.Set(text.NewRecoverySuccessful(time.Now().Add(config.SelfServiceFlowSettingsPrivilegedSessionMaxAge(ctx)))) diff --git a/selfservice/strategy/code/strategy_recovery_test.go b/selfservice/strategy/code/strategy_recovery_test.go index e07c0fb28f50..2adbf97213d4 100644 --- a/selfservice/strategy/code/strategy_recovery_test.go +++ b/selfservice/strategy/code/strategy_recovery_test.go @@ -1055,6 +1055,72 @@ func TestRecovery(t *testing.T) { assert.Empty(t, gjson.Get(body, "ui.nodes.#(attributes.name==code).messages").Array()) testhelpers.AssertMessage(t, []byte(body), "The recovery code is invalid or has already been used. Please try again.") }) + + t.Run("description=should recover if post recovery hook is successful", func(t *testing.T) { + conf.MustSet(ctx, config.HookStrategyKey(config.ViperKeySelfServiceRecoveryAfter, config.HookGlobal), []config.SelfServiceHook{{Name: "err", Config: []byte(`{}`)}}) + t.Cleanup(func() { + conf.MustSet(ctx, config.HookStrategyKey(config.ViperKeySelfServiceRecoveryAfter, config.HookGlobal), nil) + }) + + recoveryEmail := testhelpers.RandomEmail() + createIdentityToRecover(t, reg, recoveryEmail) + + cl := testhelpers.NewClientWithCookies(t) + body := expectSuccessfulRecovery(t, cl, RecoveryFlowTypeBrowser, func(v url.Values) { + v.Set("email", recoveryEmail) + }) + + message := testhelpers.CourierExpectMessage(t, reg, recoveryEmail, "Recover access to your account") + recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) + + action := gjson.Get(body, "ui.action").String() + require.NotEmpty(t, action) + assert.Equal(t, recoveryEmail, gjson.Get(body, "ui.nodes.#(attributes.name==email).attributes.value").String()) + + cl.CheckRedirect = func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + } + + body = submitRecoveryCode(t, cl, body, RecoveryFlowTypeBrowser, recoveryCode, http.StatusSeeOther) + + require.Len(t, cl.Jar.Cookies(urlx.ParseOrPanic(public.URL)), 2) + cookies := spew.Sdump(cl.Jar.Cookies(urlx.ParseOrPanic(public.URL))) + assert.Contains(t, cookies, "ory_kratos_session") + }) + + t.Run("description=should not be able to recover if post recovery hook fails", func(t *testing.T) { + conf.MustSet(ctx, config.HookStrategyKey(config.ViperKeySelfServiceRecoveryAfter, config.HookGlobal), []config.SelfServiceHook{{Name: "err", Config: []byte(`{"ExecutePostRecoveryHook": "err"}`)}}) + t.Cleanup(func() { + conf.MustSet(ctx, config.HookStrategyKey(config.ViperKeySelfServiceRecoveryAfter, config.HookGlobal), nil) + }) + + recoveryEmail := testhelpers.RandomEmail() + createIdentityToRecover(t, reg, recoveryEmail) + + cl := testhelpers.NewClientWithCookies(t) + body := expectSuccessfulRecovery(t, cl, RecoveryFlowTypeBrowser, func(v url.Values) { + v.Set("email", recoveryEmail) + }) + + message := testhelpers.CourierExpectMessage(t, reg, recoveryEmail, "Recover access to your account") + recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) + + action := gjson.Get(body, "ui.action").String() + require.NotEmpty(t, action) + assert.Equal(t, recoveryEmail, gjson.Get(body, "ui.nodes.#(attributes.name==email).attributes.value").String()) + + cl.CheckRedirect = func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + } + + initialFlowId := gjson.Get(body, "id") + body = submitRecoveryCode(t, cl, body, RecoveryFlowTypeBrowser, recoveryCode, http.StatusSeeOther) + assert.NotEqual(t, gjson.Get(body, "id"), initialFlowId) + + require.Len(t, cl.Jar.Cookies(urlx.ParseOrPanic(public.URL)), 1) + cookies := spew.Sdump(cl.Jar.Cookies(urlx.ParseOrPanic(public.URL))) + assert.NotContains(t, cookies, "ory_kratos_session") + }) } func TestDisabledStrategy(t *testing.T) { diff --git a/selfservice/strategy/link/strategy_recovery.go b/selfservice/strategy/link/strategy_recovery.go index 799b10422c89..6ab3ff4ae904 100644 --- a/selfservice/strategy/link/strategy_recovery.go +++ b/selfservice/strategy/link/strategy_recovery.go @@ -296,6 +296,10 @@ func (s *Strategy) recoveryIssueSession(w http.ResponseWriter, r *http.Request, return s.retryRecoveryFlowWithError(w, r, flow.TypeBrowser, err) } + if err := s.d.RecoveryExecutor().PostRecoveryHook(w, r, f, sess); err != nil { + return s.retryRecoveryFlowWithError(w, r, flow.TypeBrowser, err) + } + if err := s.d.SessionManager().UpsertAndIssueCookie(r.Context(), w, r, sess); err != nil { return s.retryRecoveryFlowWithError(w, r, flow.TypeBrowser, err) } @@ -316,10 +320,6 @@ func (s *Strategy) recoveryIssueSession(w http.ResponseWriter, r *http.Request, return s.retryRecoveryFlowWithError(w, r, flow.TypeBrowser, err) } - if err := s.d.RecoveryExecutor().PostRecoveryHook(w, r, f, sess); err != nil { - return s.retryRecoveryFlowWithError(w, r, flow.TypeBrowser, err) - } - sf.UI.Messages.Set(text.NewRecoverySuccessful(time.Now().Add(s.d.Config().SelfServiceFlowSettingsPrivilegedSessionMaxAge(r.Context())))) if err := s.d.SettingsFlowPersister().UpdateSettingsFlow(r.Context(), sf); err != nil { return s.retryRecoveryFlowWithError(w, r, flow.TypeBrowser, err) diff --git a/selfservice/strategy/link/strategy_recovery_test.go b/selfservice/strategy/link/strategy_recovery_test.go index 6dee51cf9207..4af007577500 100644 --- a/selfservice/strategy/link/strategy_recovery_test.go +++ b/selfservice/strategy/link/strategy_recovery_test.go @@ -823,6 +823,72 @@ func TestRecovery(t *testing.T) { assert.Nil(t, addr.VerifiedAt) assert.Equal(t, identity.VerifiableAddressStatusPending, addr.Status) }) + + t.Run("description=should recover if post recovery hook is successful", func(t *testing.T) { + conf.MustSet(ctx, config.HookStrategyKey(config.ViperKeySelfServiceRecoveryAfter, config.HookGlobal), []config.SelfServiceHook{{Name: "err", Config: []byte(`{}`)}}) + t.Cleanup(func() { + conf.MustSet(ctx, config.HookStrategyKey(config.ViperKeySelfServiceRecoveryAfter, config.HookGlobal), nil) + }) + + recoveryEmail := testhelpers.RandomEmail() + createIdentityToRecover(t, reg, recoveryEmail) + + var check = func(t *testing.T, actual string) { + message := testhelpers.CourierExpectMessage(t, reg, recoveryEmail, "Recover access to your account") + recoveryLink := testhelpers.CourierExpectLinkInMessage(t, message, 1) + + cl := testhelpers.NewClientWithCookies(t) + cl.CheckRedirect = func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + } + res, err := cl.Get(recoveryLink) + require.NoError(t, err) + require.NoError(t, res.Body.Close()) + assert.Equal(t, http.StatusSeeOther, res.StatusCode) + require.Len(t, cl.Jar.Cookies(urlx.ParseOrPanic(public.URL)), 2) + cookies := spew.Sdump(cl.Jar.Cookies(urlx.ParseOrPanic(public.URL))) + assert.Contains(t, cookies, "ory_kratos_session") + } + + var values = func(v url.Values) { + v.Set("email", recoveryEmail) + } + + check(t, expectSuccess(t, nil, false, false, values)) + }) + + t.Run("description=should not be able to recover if post recovery hook fails", func(t *testing.T) { + conf.MustSet(ctx, config.HookStrategyKey(config.ViperKeySelfServiceRecoveryAfter, config.HookGlobal), []config.SelfServiceHook{{Name: "err", Config: []byte(`{"ExecutePostRecoveryHook": "err"}`)}}) + t.Cleanup(func() { + conf.MustSet(ctx, config.HookStrategyKey(config.ViperKeySelfServiceRecoveryAfter, config.HookGlobal), nil) + }) + + recoveryEmail := testhelpers.RandomEmail() + createIdentityToRecover(t, reg, recoveryEmail) + + var check = func(t *testing.T, actual string) { + message := testhelpers.CourierExpectMessage(t, reg, recoveryEmail, "Recover access to your account") + recoveryLink := testhelpers.CourierExpectLinkInMessage(t, message, 1) + + cl := testhelpers.NewClientWithCookies(t) + cl.CheckRedirect = func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + } + res, err := cl.Get(recoveryLink) + require.NoError(t, err) + require.NoError(t, res.Body.Close()) + assert.Equal(t, http.StatusSeeOther, res.StatusCode) + require.Len(t, cl.Jar.Cookies(urlx.ParseOrPanic(public.URL)), 1) + cookies := spew.Sdump(cl.Jar.Cookies(urlx.ParseOrPanic(public.URL))) + assert.NotContains(t, cookies, "ory_kratos_session") + } + + var values = func(v url.Values) { + v.Set("email", recoveryEmail) + } + + check(t, expectSuccess(t, nil, false, false, values)) + }) } func TestDisabledEndpoint(t *testing.T) { From e08f831c2715e515bf58dc2dbb47fc3576421a5c Mon Sep 17 00:00:00 2001 From: Henning Perl Date: Tue, 22 Aug 2023 08:07:55 +0200 Subject: [PATCH 047/282] fix: don't require session for OIDC verification (#3443) --- driver/registry_default.go | 11 +++ driver/registry_default_verification.go | 4 +- ...auth2_login_challenge_identity_id.down.sql | 2 + ...2_login_challenge_identity_id.mysql.up.sql | 1 + ..._oauth2_login_challenge_identity_id.up.sql | 1 + schema/handler_test.go | 30 +++--- selfservice/flow/flow.go | 8 +- selfservice/flow/registration/flow.go | 6 +- .../flow/verification/fake_strategy.go | 34 +++++++ selfservice/flow/verification/flow.go | 6 +- selfservice/flow/verification/handler.go | 39 +++++--- selfservice/flow/verification/handler_test.go | 91 +++++++++++++++++-- .../verification/stub/identity.schema.json | 16 ++++ selfservice/hook/verification.go | 23 +++-- 14 files changed, 218 insertions(+), 54 deletions(-) create mode 100644 persistence/sql/migrations/sql/20230818000000000001_verification_add_oauth2_login_challenge_identity_id.down.sql create mode 100644 persistence/sql/migrations/sql/20230818000000000001_verification_add_oauth2_login_challenge_identity_id.mysql.up.sql create mode 100644 persistence/sql/migrations/sql/20230818000000000001_verification_add_oauth2_login_challenge_identity_id.up.sql create mode 100644 selfservice/flow/verification/fake_strategy.go create mode 100644 selfservice/flow/verification/stub/identity.schema.json diff --git a/driver/registry_default.go b/driver/registry_default.go index f1307e310902..d0ffa2d2c198 100644 --- a/driver/registry_default.go +++ b/driver/registry_default.go @@ -9,6 +9,7 @@ import ( "net/http" "strings" "sync" + "testing" "time" "github.com/ory/x/contextx" @@ -390,6 +391,16 @@ func (m *RegistryDefault) WithConfig(c *config.Config) Registry { return m } +// WithSelfserviceStrategies is only available in testing and overrides the +// selfservice strategies with the given ones. +func (m *RegistryDefault) WithSelfserviceStrategies(t testing.TB, strategies []any) Registry { + if t == nil { + panic("Passing selfservice strategies is only supported in testing") + } + m.selfserviceStrategies = strategies + return m +} + func (m *RegistryDefault) Writer() herodot.Writer { if m.writer == nil { h := herodot.NewJSONWriter(m.Logger()) diff --git a/driver/registry_default_verification.go b/driver/registry_default_verification.go index 4fa38a0749b6..f2c7a48737cd 100644 --- a/driver/registry_default_verification.go +++ b/driver/registry_default_verification.go @@ -74,10 +74,10 @@ func (m *RegistryDefault) VerificationStrategies(ctx context.Context) (verificat return } -func (m *RegistryDefault) AllVerificationStrategies() (recoveryStrategies verification.Strategies) { +func (m *RegistryDefault) AllVerificationStrategies() (verificationStrategies verification.Strategies) { for _, strategy := range m.selfServiceStrategies() { if s, ok := strategy.(verification.Strategy); ok { - recoveryStrategies = append(recoveryStrategies, s) + verificationStrategies = append(verificationStrategies, s) } } diff --git a/persistence/sql/migrations/sql/20230818000000000001_verification_add_oauth2_login_challenge_identity_id.down.sql b/persistence/sql/migrations/sql/20230818000000000001_verification_add_oauth2_login_challenge_identity_id.down.sql new file mode 100644 index 000000000000..d8fa0889051f --- /dev/null +++ b/persistence/sql/migrations/sql/20230818000000000001_verification_add_oauth2_login_challenge_identity_id.down.sql @@ -0,0 +1,2 @@ +ALTER TABLE selfservice_verification_flows DROP COLUMN session_id; + diff --git a/persistence/sql/migrations/sql/20230818000000000001_verification_add_oauth2_login_challenge_identity_id.mysql.up.sql b/persistence/sql/migrations/sql/20230818000000000001_verification_add_oauth2_login_challenge_identity_id.mysql.up.sql new file mode 100644 index 000000000000..db94be8aac32 --- /dev/null +++ b/persistence/sql/migrations/sql/20230818000000000001_verification_add_oauth2_login_challenge_identity_id.mysql.up.sql @@ -0,0 +1 @@ +ALTER TABLE selfservice_verification_flows ADD COLUMN session_id VARCHAR(36); diff --git a/persistence/sql/migrations/sql/20230818000000000001_verification_add_oauth2_login_challenge_identity_id.up.sql b/persistence/sql/migrations/sql/20230818000000000001_verification_add_oauth2_login_challenge_identity_id.up.sql new file mode 100644 index 000000000000..af54e4e5368c --- /dev/null +++ b/persistence/sql/migrations/sql/20230818000000000001_verification_add_oauth2_login_challenge_identity_id.up.sql @@ -0,0 +1 @@ +ALTER TABLE selfservice_verification_flows ADD COLUMN session_id UUID; diff --git a/schema/handler_test.go b/schema/handler_test.go index d9c30f552ac2..b88cdd55df46 100644 --- a/schema/handler_test.go +++ b/schema/handler_test.go @@ -81,7 +81,7 @@ func TestHandler(t *testing.T) { return s } - getFromTS := func(url string, expectCode int) []byte { + getFromTS := func(t *testing.T, url string, expectCode int) []byte { res, err := ts.Client().Get(url) require.NoError(t, err) body, err := io.ReadAll(res.Body) @@ -92,12 +92,12 @@ func TestHandler(t *testing.T) { return body } - getFromTSById := func(id string, expectCode int) []byte { - return getFromTS(fmt.Sprintf("%s/schemas/%s", ts.URL, id), expectCode) + getFromTSById := func(t *testing.T, id string, expectCode int) []byte { + return getFromTS(t, fmt.Sprintf("%s/schemas/%s", ts.URL, id), expectCode) } - getFromTSPaginated := func(page, perPage, expectCode int) []byte { - return getFromTS(fmt.Sprintf("%s/schemas?page=%d&per_page=%d", ts.URL, page, perPage), expectCode) + getFromTSPaginated := func(t *testing.T, page, perPage, expectCode int) []byte { + return getFromTS(t, fmt.Sprintf("%s/schemas?page=%d&per_page=%d", ts.URL, page, perPage), expectCode) } getFromFS := func(id string) []byte { @@ -132,46 +132,46 @@ func TestHandler(t *testing.T) { setSchemas(schemas) t.Run("case=get default schema", func(t *testing.T) { - server := getFromTSById(config.DefaultIdentityTraitsSchemaID, http.StatusOK) + server := getFromTSById(t, config.DefaultIdentityTraitsSchemaID, http.StatusOK) file := getFromFS(config.DefaultIdentityTraitsSchemaID) require.JSONEq(t, string(file), string(server)) }) t.Run("case=get other schema", func(t *testing.T) { - server := getFromTSById("identity2", http.StatusOK) + server := getFromTSById(t, "identity2", http.StatusOK) file := getFromFS("identity2") require.JSONEq(t, string(file), string(server)) }) t.Run("case=get base64 schema", func(t *testing.T) { - server := getFromTSById("base64", http.StatusOK) + server := getFromTSById(t, "base64", http.StatusOK) file := getFromFS("base64") require.JSONEq(t, string(file), string(server)) }) t.Run("case=get encoded schema", func(t *testing.T) { - server := getFromTSById("cHJlc2V0Oi8vZW1haWw", http.StatusOK) + server := getFromTSById(t, "cHJlc2V0Oi8vZW1haWw", http.StatusOK) file := getFromFS("preset://email") require.JSONEq(t, string(file), string(server)) }) t.Run("case=get unreachable schema", func(t *testing.T) { - reason := getFromTSById("unreachable", http.StatusInternalServerError) + reason := getFromTSById(t, "unreachable", http.StatusInternalServerError) require.Contains(t, string(reason), "could not be found or opened") }) t.Run("case=get no-file schema", func(t *testing.T) { - reason := getFromTSById("no-file", http.StatusInternalServerError) + reason := getFromTSById(t, "no-file", http.StatusInternalServerError) require.Contains(t, string(reason), "could not be found or opened") }) t.Run("case=get directory schema", func(t *testing.T) { - reason := getFromTSById("directory", http.StatusInternalServerError) + reason := getFromTSById(t, "directory", http.StatusInternalServerError) require.Contains(t, string(reason), "could not be found or opened") }) t.Run("case=get not-existing schema", func(t *testing.T) { - _ = getFromTSById("not-existing", http.StatusNotFound) + _ = getFromTSById(t, "not-existing", http.StatusNotFound) }) t.Run("case=get all schemas", func(t *testing.T) { @@ -188,7 +188,7 @@ func TestHandler(t *testing.T) { }, }) - body := getFromTSPaginated(0, 2, http.StatusOK) + body := getFromTSPaginated(t, 0, 2, http.StatusOK) var result []client.IdentitySchemaContainer require.NoError(t, json.Unmarshal(body, &result)) @@ -230,7 +230,7 @@ func TestHandler(t *testing.T) { }, }) - body1, body2 := getFromTSPaginated(0, 1, http.StatusOK), getFromTSPaginated(1, 1, http.StatusOK) + body1, body2 := getFromTSPaginated(t, 0, 1, http.StatusOK), getFromTSPaginated(t, 1, 1, http.StatusOK) var result1, result2 schema.IdentitySchemas require.NoError(t, json.Unmarshal(body1, &result1)) diff --git a/selfservice/flow/flow.go b/selfservice/flow/flow.go index 912cb72fa715..c581b117ac04 100644 --- a/selfservice/flow/flow.go +++ b/selfservice/flow/flow.go @@ -10,11 +10,9 @@ import ( "github.com/pkg/errors" + "github.com/ory/herodot" "github.com/ory/kratos/driver/config" "github.com/ory/kratos/ui/container" - "github.com/ory/x/sqlxx" - - "github.com/ory/herodot" "github.com/ory/kratos/x" "github.com/gofrs/uuid" @@ -42,10 +40,6 @@ type Flow interface { GetUI() *container.Container } -type Challenger interface { - GetOAuth2LoginChallenge() sqlxx.NullString -} - type FlowWithRedirect interface { SecureRedirectToOpts(ctx context.Context, cfg config.Provider) (opts []x.SecureRedirectOption) } diff --git a/selfservice/flow/registration/flow.go b/selfservice/flow/registration/flow.go index 0b1c49c69080..b16bf2048ce5 100644 --- a/selfservice/flow/registration/flow.go +++ b/selfservice/flow/registration/flow.go @@ -154,7 +154,7 @@ func NewFlow(conf *config.Config, exp time.Duration, csrf string, r *http.Reques }, nil } -func (f Flow) TableName(ctx context.Context) string { +func (f Flow) TableName(context.Context) string { return "selfservice_registration_flows" } @@ -229,10 +229,6 @@ func (f *Flow) ContinueWith() []flow.ContinueWith { return f.ContinueWithItems } -func (f Flow) GetOAuth2LoginChallenge() sqlxx.NullString { - return f.OAuth2LoginChallenge -} - func (f *Flow) SecureRedirectToOpts(ctx context.Context, cfg config.Provider) (opts []x.SecureRedirectOption) { return []x.SecureRedirectOption{ x.SecureRedirectReturnTo(f.ReturnTo), diff --git a/selfservice/flow/verification/fake_strategy.go b/selfservice/flow/verification/fake_strategy.go new file mode 100644 index 000000000000..58f6b1e5af5c --- /dev/null +++ b/selfservice/flow/verification/fake_strategy.go @@ -0,0 +1,34 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package verification + +import ( + "context" + "net/http" + + "github.com/ory/kratos/identity" + "github.com/ory/kratos/ui/node" +) + +type FakeStrategy struct{} + +func (f FakeStrategy) VerificationStrategyID() string { + return "fake" +} + +func (f FakeStrategy) VerificationNodeGroup() node.UiNodeGroup { + return "fake" +} + +func (f FakeStrategy) PopulateVerificationMethod(*http.Request, *Flow) error { + return nil +} + +func (f FakeStrategy) Verify(_ http.ResponseWriter, _ *http.Request, _ *Flow) (err error) { + return nil +} + +func (f FakeStrategy) SendVerificationEmail(context.Context, *Flow, *identity.Identity, *identity.VerifiableAddress) error { + return nil +} diff --git a/selfservice/flow/verification/flow.go b/selfservice/flow/verification/flow.go index 88f6600161e3..a77cf30dc688 100644 --- a/selfservice/flow/verification/flow.go +++ b/selfservice/flow/verification/flow.go @@ -79,8 +79,12 @@ type Flow struct { // required: true State State `json:"state" faker:"-" db:"state"` + // OAuth2LoginChallenge holds the login challenge originally set during the registration flow. OAuth2LoginChallenge sqlxx.NullString `json:"-" db:"oauth2_login_challenge"` + // SessionID holds the session id if set from a registraton hook. + SessionID uuid.NullUUID `json:"-" faker:"-" db:"session_id"` + // CSRFToken contains the anti-csrf token associated with this request. CSRFToken string `json:"-" db:"csrf_token"` @@ -99,7 +103,7 @@ func (f *Flow) GetRequestURL() string { return f.RequestURL } -func (f Flow) TableName(ctx context.Context) string { +func (f Flow) TableName(context.Context) string { return "selfservice_verification_flows" } diff --git a/selfservice/flow/verification/handler.go b/selfservice/flow/verification/handler.go index 48b440621dbc..2ed3ca3f3679 100644 --- a/selfservice/flow/verification/handler.go +++ b/selfservice/flow/verification/handler.go @@ -4,6 +4,7 @@ package verification import ( + "context" "net/http" "time" @@ -47,6 +48,7 @@ type ( identity.PrivilegedPoolProvider config.Provider hydra.Provider + session.PersistenceProvider session.ManagementProvider x.CSRFTokenGeneratorProvider @@ -396,7 +398,8 @@ func (h *Handler) updateVerificationFlow(w http.ResponseWriter, r *http.Request, return } - f, err := h.d.VerificationFlowPersister().GetVerificationFlow(r.Context(), rid) + ctx := r.Context() + f, err := h.d.VerificationFlowPersister().GetVerificationFlow(ctx, rid) if errors.Is(err, sqlcon.ErrNoRows) { h.d.VerificationFlowErrorHandler().WriteFlowError(w, r, nil, node.DefaultGroup, errors.WithStack(herodot.ErrNotFound.WithReasonf("The verification request could not be found. Please restart the flow."))) return @@ -441,19 +444,20 @@ func (h *Handler) updateVerificationFlow(w http.ResponseWriter, r *http.Request, if x.IsBrowserRequest(r) { // Special case: If we ended up here through a OAuth2 login challenge, we need to accept the login request // and redirect back to the OAuth2 provider. - if found && f.OAuth2LoginChallenge.String() != "" { - s, err := h.d.SessionManager().FetchFromRequest(r.Context(), r) - if err != nil { - h.d.VerificationFlowErrorHandler().WriteFlowError(w, r, f, node.DefaultGroup, err) + if f.OAuth2LoginChallenge.String() != "" { + sess := h.maybeGetSession(ctx, f) + if sess == nil { + h.d.VerificationFlowErrorHandler().WriteFlowError(w, r, f, node.DefaultGroup, + herodot.ErrBadRequest.WithReasonf("No session was found for this flow. Please retry the authentication.")) return } - callbackURL, err := h.d.Hydra().AcceptLoginRequest(r.Context(), + callbackURL, err := h.d.Hydra().AcceptLoginRequest(ctx, hydra.AcceptLoginRequestParams{ LoginChallenge: string(f.OAuth2LoginChallenge), - IdentityID: s.IdentityID.String(), - SessionID: s.ID.String(), - AuthenticationMethods: s.AMR, + IdentityID: sess.IdentityID.String(), + SessionID: sess.ID.String(), + AuthenticationMethods: sess.AMR, }) if err != nil { h.d.VerificationFlowErrorHandler().WriteFlowError(w, r, f, node.DefaultGroup, err) @@ -464,11 +468,11 @@ func (h *Handler) updateVerificationFlow(w http.ResponseWriter, r *http.Request, return } - http.Redirect(w, r, f.AppendTo(h.d.Config().SelfServiceFlowVerificationUI(r.Context())).String(), http.StatusSeeOther) + http.Redirect(w, r, f.AppendTo(h.d.Config().SelfServiceFlowVerificationUI(ctx)).String(), http.StatusSeeOther) return } - updatedFlow, err := h.d.VerificationFlowPersister().GetVerificationFlow(r.Context(), f.ID) + updatedFlow, err := h.d.VerificationFlowPersister().GetVerificationFlow(ctx, f.ID) if err != nil { h.d.VerificationFlowErrorHandler().WriteFlowError(w, r, f, g, err) return @@ -476,3 +480,16 @@ func (h *Handler) updateVerificationFlow(w http.ResponseWriter, r *http.Request, h.d.Writer().Write(w, r, updatedFlow) } + +// maybeGetSession returns the session if it was found in the flow or nil otherwise. +func (h *Handler) maybeGetSession(ctx context.Context, f *Flow) *session.Session { + if !f.SessionID.Valid { + return nil + } + s, err := h.d.SessionPersister().GetSession(ctx, f.SessionID.UUID, session.ExpandNothing) + if err != nil { + return nil + } + + return s +} diff --git a/selfservice/flow/verification/handler_test.go b/selfservice/flow/verification/handler_test.go index de060a057c9d..cfac42d1eced 100644 --- a/selfservice/flow/verification/handler_test.go +++ b/selfservice/flow/verification/handler_test.go @@ -12,14 +12,14 @@ import ( "testing" "time" - "github.com/gofrs/uuid" - "github.com/gobuffalo/httptest" + "github.com/gofrs/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tidwall/gjson" "github.com/ory/kratos/driver/config" + "github.com/ory/kratos/hydra" "github.com/ory/kratos/internal" "github.com/ory/kratos/internal/testhelpers" "github.com/ory/kratos/selfservice/flow/verification" @@ -168,20 +168,97 @@ func TestGetFlow(t *testing.T) { router := x.NewRouterPublic() ts, _ := testhelpers.NewKratosServerWithRouters(t, reg, router, x.NewRouterAdmin()) - c := &http.Client{} - // don't get the reference, instead copy the values, so we don't alter the client directly. - *c = *ts.Client() // prevent the redirect - c.CheckRedirect = func(req *http.Request, via []*http.Request) error { + ts.Client().CheckRedirect = func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse } req, err := http.NewRequest("GET", ts.URL+verification.RouteInitBrowserFlow, nil) require.NoError(t, err) - res, err := c.Do(req) + res, err := ts.Client().Do(req) require.NoError(t, err) defer res.Body.Close() // here we check that the redirect status is 303 require.Equal(t, http.StatusSeeOther, res.StatusCode) }) } + +func TestPostFlow(t *testing.T) { + ctx := context.Background() + conf, reg := internal.NewFastRegistryWithMocks(t) + reg.WithSelfserviceStrategies(t, []any{&verification.FakeStrategy{}}) + reg.WithHydra(hydra.NewFake()) + conf.MustSet(ctx, config.ViperKeySelfServiceVerificationEnabled, true) + testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/identity.schema.json") + + public, _ := testhelpers.NewKratosServerWithCSRF(t, reg) + _ = testhelpers.NewErrorTestServer(t, reg) + _ = testhelpers.NewRedirTS(t, "", conf) + + t.Run("case=valid", func(t *testing.T) { + f := &verification.Flow{ + ID: uuid.Must(uuid.NewV4()), + Type: "browser", + ExpiresAt: time.Now().Add(1 * time.Hour), + IssuedAt: time.Now(), + } + require.NoError(t, reg.VerificationFlowPersister().CreateVerificationFlow(ctx, f)) + + client := testhelpers.NewClientWithCookies(t) + + u := public.URL + verification.RouteSubmitFlow + "?flow=" + f.ID.String() + resp, err := client.PostForm(u, url.Values{"method": {"fake"}}) + require.NoError(t, err) + assert.EqualValues(t, http.StatusOK, resp.StatusCode) + }) + + t.Run("suite=with OIDC login challenge", func(t *testing.T) { + t.Run("case=succeeds with a session", func(t *testing.T) { + s := testhelpers.CreateSession(t, reg) + + f := &verification.Flow{ + ID: uuid.Must(uuid.NewV4()), + Type: "browser", + ExpiresAt: time.Now().Add(1 * time.Hour), + IssuedAt: time.Now(), + OAuth2LoginChallenge: hydra.FakeValidLoginChallenge, + SessionID: uuid.NullUUID{UUID: s.ID, Valid: true}, + } + require.NoError(t, reg.VerificationFlowPersister().CreateVerificationFlow(ctx, f)) + + client := testhelpers.NewNoRedirectClientWithCookies(t) + + u := public.URL + verification.RouteSubmitFlow + "?flow=" + f.ID.String() + resp, err := client.PostForm(u, url.Values{"method": {"fake"}}) + require.NoError(t, err) + assert.Equal(t, http.StatusSeeOther, resp.StatusCode) + assert.Equal(t, hydra.FakePostLoginURL, resp.Header.Get("Location")) + }) + + t.Run("case=fails without a session", func(t *testing.T) { + client := testhelpers.NewClientWithCookies(t) + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + _, err := w.Write(x.EasyGetBody(t, client, public.URL+verification.RouteGetFlow+"?id="+r.URL.Query().Get("flow"))) + require.NoError(t, err) + })) + t.Cleanup(ts.Close) + conf.MustSet(ctx, config.ViperKeySelfServiceVerificationUI, ts.URL) + + f := &verification.Flow{ + ID: uuid.Must(uuid.NewV4()), + Type: "browser", + ExpiresAt: time.Now().Add(1 * time.Hour), + IssuedAt: time.Now(), + OAuth2LoginChallenge: hydra.FakeValidLoginChallenge, + } + require.NoError(t, reg.VerificationFlowPersister().CreateVerificationFlow(ctx, f)) + + u := public.URL + verification.RouteSubmitFlow + "?flow=" + f.ID.String() + resp, err := client.PostForm(u, url.Values{"method": {"fake"}}) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + assert.Equal(t, f.ID.String(), resp.Request.URL.Query().Get("flow")) + }) + }) + +} diff --git a/selfservice/flow/verification/stub/identity.schema.json b/selfservice/flow/verification/stub/identity.schema.json new file mode 100644 index 000000000000..c7005d87ce8d --- /dev/null +++ b/selfservice/flow/verification/stub/identity.schema.json @@ -0,0 +1,16 @@ +{ + "$id": "https://example.com/registration.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Person", + "type": "object", + "properties": { + "traits": { + "type": "object", + "properties": { + "bar": { + "type": "string" + } + } + } + } +} diff --git a/selfservice/hook/verification.go b/selfservice/hook/verification.go index 8f8deea73eb9..899542bd8f60 100644 --- a/selfservice/hook/verification.go +++ b/selfservice/hook/verification.go @@ -7,6 +7,8 @@ import ( "context" "net/http" + "github.com/gofrs/uuid" + "github.com/ory/kratos/driver/config" "github.com/ory/kratos/identity" "github.com/ory/kratos/selfservice/flow" @@ -42,17 +44,26 @@ func NewVerifier(r verifierDependencies) *Verifier { func (e *Verifier) ExecutePostRegistrationPostPersistHook(w http.ResponseWriter, r *http.Request, f *registration.Flow, s *session.Session) error { return otelx.WithSpan(r.Context(), "selfservice.hook.Verifier.ExecutePostRegistrationPostPersistHook", func(ctx context.Context) error { - return e.do(w, r.WithContext(ctx), s.Identity, f) + return e.do(w, r.WithContext(ctx), s.Identity, f, func(v *verification.Flow) { + v.OAuth2LoginChallenge = f.OAuth2LoginChallenge + v.SessionID = uuid.NullUUID{UUID: s.ID, Valid: true} + }) }) } -func (e *Verifier) ExecuteSettingsPostPersistHook(w http.ResponseWriter, r *http.Request, a *settings.Flow, i *identity.Identity) error { +func (e *Verifier) ExecuteSettingsPostPersistHook(w http.ResponseWriter, r *http.Request, f *settings.Flow, i *identity.Identity) error { return otelx.WithSpan(r.Context(), "selfservice.hook.Verifier.ExecuteSettingsPostPersistHook", func(ctx context.Context) error { - return e.do(w, r.WithContext(ctx), i, a) + return e.do(w, r.WithContext(ctx), i, f, nil) }) } -func (e *Verifier) do(w http.ResponseWriter, r *http.Request, i *identity.Identity, f flow.FlowWithContinueWith) error { +func (e *Verifier) do( + w http.ResponseWriter, + r *http.Request, + i *identity.Identity, + f flow.FlowWithContinueWith, + flowCallback func(*verification.Flow), +) error { // This is called after the identity has been created so we can safely assume that all addresses are available // already. @@ -83,8 +94,8 @@ func (e *Verifier) do(w http.ResponseWriter, r *http.Request, i *identity.Identi return err } - if f, ok := f.(flow.Challenger); ok { - verificationFlow.OAuth2LoginChallenge = f.GetOAuth2LoginChallenge() + if flowCallback != nil { + flowCallback(verificationFlow) } verificationFlow.State = verification.StateEmailSent From ecd557f93f24afc0db906dd5d49042817cc41baf Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Tue, 22 Aug 2023 07:38:47 +0000 Subject: [PATCH 048/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bc320acecc9..9fb85b9c7242 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-08-18)](#2023-08-18) +- [ (2023-08-22)](#2023-08-22) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) - [Features](#features) @@ -309,7 +309,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-08-18) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-08-22) ### Bug Fixes @@ -329,12 +329,18 @@ - Add missing tracing & attributes in oidc strategy ([#3429](https://github.com/ory/kratos/issues/3429)) ([09bcb71](https://github.com/ory/kratos/commit/09bcb71f1f0b3238e2d0f4376a1a2290d062c6c1)) +- Allow post recovery hooks to interrupt the flow + ([#3393](https://github.com/ory/kratos/issues/3393)) + ([6c1d2f1](https://github.com/ory/kratos/commit/6c1d2f1e4173cfb9a7abe2bfe4f20e47b7568d3b)) - Carry `oauth2_login_challenge` over to registration flow ([#3419](https://github.com/ory/kratos/issues/3419)) ([76241be](https://github.com/ory/kratos/commit/76241bee3dc7fec4690346ee85bc4b9f897fdd34)): Fixes https://github.com/ory/kratos/issues/3321 +- Don't require session for OIDC verification + ([#3443](https://github.com/ory/kratos/issues/3443)) + ([e08f831](https://github.com/ory/kratos/commit/e08f831c2715e515bf58dc2dbb47fc3576421a5c)) - Don't return 500 on conflict for POST /admin/identities ([#3437](https://github.com/ory/kratos/issues/3437)) ([1429949](https://github.com/ory/kratos/commit/142994932e449d9948148804502c98ef73daafff)) From bb2527668fad8db7213c8a920d6dd13c6ff99cef Mon Sep 17 00:00:00 2001 From: Eric Fesler Date: Tue, 22 Aug 2023 11:02:49 +0200 Subject: [PATCH 049/282] chore: remove comment (#3442) The comment triggered Ory Closed Reference Notifier GitHub action. However, this is not relevant anymore. Resolve #2630 --- driver/config/config_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver/config/config_test.go b/driver/config/config_test.go index 13a16d7e48fe..365b19323fd7 100644 --- a/driver/config/config_test.go +++ b/driver/config/config_test.go @@ -957,7 +957,7 @@ func TestIdentitySchemaValidation(t *testing.T) { testWatch := func(t *testing.T, ctx context.Context, cmd *cobra.Command, identity *configFile) (*config.Config, *test.Hook, func([]map[string]string)) { tdir := t.TempDir() assert.NoError(t, - os.MkdirAll(tdir, // DO NOT CHANGE THIS: https://github.com/fsnotify/fsnotify/issues/340 + os.MkdirAll(tdir, os.ModePerm)) configFileName := randx.MustString(8, randx.Alpha) tmpConfig, err := os.Create(filepath.Join(tdir, configFileName+".config.yaml")) From e7b33a168bf0c0fe0492901abd3df8b6d6a08a68 Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Tue, 22 Aug 2023 16:30:40 +0200 Subject: [PATCH 050/282] feat: allow marking OIDC provider-verified addresses as verified during registration (#3448) This feature allows marking emails provided by social sign in providers as verified. Closes #3445 Closes #3424 Closes #1057 Co-authored-by: Krzysztof Bogacki --- .../strategy/oidc/strategy_registration.go | 68 ++++++++++++++++--- selfservice/strategy/oidc/strategy_test.go | 32 +++++++++ .../strategy/oidc/stub/oidc.hydra.jsonnet | 5 +- .../registration-verifiable-email.schema.json | 61 +++++++++++++++++ 4 files changed, 156 insertions(+), 10 deletions(-) create mode 100644 selfservice/strategy/oidc/stub/registration-verifiable-email.schema.json diff --git a/selfservice/strategy/oidc/strategy_registration.go b/selfservice/strategy/oidc/strategy_registration.go index 1e303c50df35..6fcac4987d20 100644 --- a/selfservice/strategy/oidc/strategy_registration.go +++ b/selfservice/strategy/oidc/strategy_registration.go @@ -7,8 +7,11 @@ import ( "bytes" "encoding/json" "net/http" + "strings" "time" + "github.com/ory/x/sqlxx" + "github.com/ory/herodot" "github.com/ory/x/fetcher" @@ -38,7 +41,14 @@ var _ registration.Strategy = new(Strategy) type MetadataType string +type VerifiedAddress struct { + Value string `json:"value"` + Via identity.VerifiableAddressType `json:"via"` +} + const ( + VerifiedAddressesKey = "identity.verified_addresses" + PublicMetadata MetadataType = "identity.metadata_public" AdminMetadata MetadataType = "identity.metadata_admin" ) @@ -249,7 +259,7 @@ func (s *Strategy) processRegistration(w http.ResponseWriter, r *http.Request, r return nil, s.handleError(w, r, rf, provider.Config().ID, nil, err) } - i, err := s.createIdentity(w, r, rf, claims, provider, container, jn) + i, va, err := s.createIdentity(w, r, rf, claims, provider, container, jn) if err != nil { return nil, s.handleError(w, r, rf, provider.Config().ID, nil, err) } @@ -259,6 +269,18 @@ func (s *Strategy) processRegistration(w http.ResponseWriter, r *http.Request, r return nil, s.handleError(w, r, rf, provider.Config().ID, i.Traits, err) } + for n := range i.VerifiableAddresses { + verifiable := &i.VerifiableAddresses[n] + for _, verified := range va { + if verifiable.Via == verified.Via && verifiable.Value == verified.Value { + verifiable.Status = identity.VerifiableAddressStatusCompleted + verifiable.Verified = true + t := sqlxx.NullTime(time.Now().UTC().Round(time.Second)) + verifiable.VerifiedAt = &t + } + } + } + var it string if idToken, ok := token.Extra("id_token").(string); ok { if it, err = s.d.Cipher(r.Context()).Encrypt(r.Context(), []byte(idToken)); err != nil { @@ -289,34 +311,39 @@ func (s *Strategy) processRegistration(w http.ResponseWriter, r *http.Request, r return nil, nil } -func (s *Strategy) createIdentity(w http.ResponseWriter, r *http.Request, a *registration.Flow, claims *Claims, provider Provider, container *authCodeContainer, jn *bytes.Buffer) (*identity.Identity, error) { +func (s *Strategy) createIdentity(w http.ResponseWriter, r *http.Request, a *registration.Flow, claims *Claims, provider Provider, container *authCodeContainer, jn *bytes.Buffer) (*identity.Identity, []VerifiedAddress, error) { var jsonClaims bytes.Buffer if err := json.NewEncoder(&jsonClaims).Encode(claims); err != nil { - return nil, s.handleError(w, r, a, provider.Config().ID, nil, err) + return nil, nil, s.handleError(w, r, a, provider.Config().ID, nil, err) } vm, err := s.d.JsonnetVM(r.Context()) if err != nil { - return nil, s.handleError(w, r, a, provider.Config().ID, nil, err) + return nil, nil, s.handleError(w, r, a, provider.Config().ID, nil, err) } vm.ExtCode("claims", jsonClaims.String()) evaluated, err := vm.EvaluateAnonymousSnippet(provider.Config().Mapper, jn.String()) if err != nil { - return nil, s.handleError(w, r, a, provider.Config().ID, nil, err) + return nil, nil, s.handleError(w, r, a, provider.Config().ID, nil, err) } i := identity.NewIdentity(s.d.Config().DefaultIdentityTraitsSchemaID(r.Context())) if err := s.setTraits(w, r, a, claims, provider, container, evaluated, i); err != nil { - return nil, s.handleError(w, r, a, provider.Config().ID, i.Traits, err) + return nil, nil, s.handleError(w, r, a, provider.Config().ID, i.Traits, err) } if err := s.setMetadata(evaluated, i, PublicMetadata); err != nil { - return nil, s.handleError(w, r, a, provider.Config().ID, i.Traits, err) + return nil, nil, s.handleError(w, r, a, provider.Config().ID, i.Traits, err) } if err := s.setMetadata(evaluated, i, AdminMetadata); err != nil { - return nil, s.handleError(w, r, a, provider.Config().ID, i.Traits, err) + return nil, nil, s.handleError(w, r, a, provider.Config().ID, i.Traits, err) + } + + va, err := s.extractVerifiedAddresses(evaluated) + if err != nil { + return nil, nil, s.handleError(w, r, a, provider.Config().ID, i.Traits, err) } s.d.Logger(). @@ -326,7 +353,7 @@ func (s *Strategy) createIdentity(w http.ResponseWriter, r *http.Request, a *reg WithSensitiveField("mapper_jsonnet_output", evaluated). WithField("mapper_jsonnet_url", provider.Config().Mapper). Debug("OpenID Connect Jsonnet mapper completed.") - return i, nil + return i, va, nil } func (s *Strategy) setTraits(w http.ResponseWriter, r *http.Request, a *registration.Flow, claims *Claims, provider Provider, container *authCodeContainer, evaluated string, i *identity.Identity) error { @@ -370,3 +397,26 @@ func (s *Strategy) setMetadata(evaluated string, i *identity.Identity, m Metadat return nil } + +func (s *Strategy) extractVerifiedAddresses(evaluated string) ([]VerifiedAddress, error) { + if verifiedAddresses := gjson.Get(evaluated, VerifiedAddressesKey); verifiedAddresses.Exists() { + if !verifiedAddresses.IsArray() { + return nil, errors.WithStack(herodot.ErrBadRequest.WithReasonf("OpenID Connect Jsonnet mapper did not return an array for key %s. Please check your Jsonnet code!", VerifiedAddressesKey)) + } + + var va []VerifiedAddress + if err := json.Unmarshal([]byte(verifiedAddresses.Raw), &va); err != nil { + return nil, errors.WithStack(herodot.ErrBadRequest.WithReasonf("Failed to unmarshal value for key %s. Please check your Jsonnet code!", VerifiedAddressesKey).WithDebugf("%s", err)) + } + + for _, va := range va { + if va.Via == identity.VerifiableAddressTypeEmail { + va.Value = strings.ToLower(strings.TrimSpace(va.Value)) + } + } + + return va, nil + } + + return nil, nil +} diff --git a/selfservice/strategy/oidc/strategy_test.go b/selfservice/strategy/oidc/strategy_test.go index 4c6284ac5c4c..401714c4b43a 100644 --- a/selfservice/strategy/oidc/strategy_test.go +++ b/selfservice/strategy/oidc/strategy_test.go @@ -804,6 +804,38 @@ func TestStrategy(t *testing.T) { }) }) + t.Run("case=verified addresses should be respected", func(t *testing.T) { + scope = []string{"openid"} + + testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/registration-verifiable-email.schema.json") + + var assertVerifiedEmail = func(t *testing.T, body []byte, verified bool) { + assert.Len(t, gjson.GetBytes(body, "identity.verifiable_addresses").Array(), 1, "%s", body) + assert.Equal(t, "email", gjson.GetBytes(body, "identity.verifiable_addresses.0.via").String(), "%s", body) + assert.Equal(t, subject, gjson.GetBytes(body, "identity.verifiable_addresses.0.value").String(), "%s", body) + assert.Equal(t, verified, gjson.GetBytes(body, "identity.verifiable_addresses.0.verified").Bool(), "%s", body) + } + + t.Run("case=should have verified address when subject matches", func(t *testing.T) { + subject = "verified-email@ory.sh" + r := newBrowserRegistrationFlow(t, returnTS.URL, time.Minute) + action := assertFormValues(t, r.ID, "valid") + res, body := makeRequest(t, "valid", action, url.Values{}) + assertIdentity(t, res, body) + assertVerifiedEmail(t, body, true) + }) + + t.Run("case=should have unverified address when subject does not match", func(t *testing.T) { + subject = "changed-verified-email@ory.sh" + r := newBrowserRegistrationFlow(t, returnTS.URL, time.Minute) + action := assertFormValues(t, r.ID, "valid") + res, body := makeRequest(t, "valid", action, url.Values{"traits.subject": {"unverified-email@ory.sh"}}) + subject = "unverified-email@ory.sh" + assertIdentity(t, res, body) + assertVerifiedEmail(t, body, false) + }) + }) + t.Run("method=TestPopulateSignUpMethod", func(t *testing.T) { conf.MustSet(ctx, config.ViperKeyPublicBaseURL, "https://foo/") diff --git a/selfservice/strategy/oidc/stub/oidc.hydra.jsonnet b/selfservice/strategy/oidc/stub/oidc.hydra.jsonnet index c36630e1e334..982f5fca3e5a 100644 --- a/selfservice/strategy/oidc/stub/oidc.hydra.jsonnet +++ b/selfservice/strategy/oidc/stub/oidc.hydra.jsonnet @@ -15,6 +15,9 @@ else }, metadata_admin: { [if "phone_number" in claims then "phone_number" else null]: claims.phone_number, - } + }, + verified_addresses: [ + { via: "email", value: claims.sub }, + ], }, } diff --git a/selfservice/strategy/oidc/stub/registration-verifiable-email.schema.json b/selfservice/strategy/oidc/stub/registration-verifiable-email.schema.json new file mode 100644 index 000000000000..b405c2402d78 --- /dev/null +++ b/selfservice/strategy/oidc/stub/registration-verifiable-email.schema.json @@ -0,0 +1,61 @@ +{ + "$id": "https://example.com/person.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Person", + "type": "object", + "properties": { + "traits": { + "type": "object", + "properties": { + "subject": { + "format": "email", + "type": "string", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + }, + "verification": { + "via": "email" + } + } + }, + "name": { + "type": "string", + "minLength": 2 + }, + "website": { + "type": "string", + "format": "uri" + }, + "groups": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "subject" + ] + }, + "metadata_public": { + "type": "object", + "properties": { + "picture": { + "type": "string" + } + } + }, + "metadata_admin": { + "type": "object", + "properties": { + "phone_number": { + "type": "string" + } + } + } + }, + "additionalProperties": false +} From 318ea2ca1f07a7cd7e5b797f790588bd2af76a74 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Tue, 22 Aug 2023 15:56:17 +0000 Subject: [PATCH 051/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fb85b9c7242..87841af326da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -384,6 +384,16 @@ ([e3fcf0c](https://github.com/ory/kratos/commit/e3fcf0c31db9742ed61bcf783e37ee119ed19d42)) - Allow extra migrations in NewPersister ([96c1ff7](https://github.com/ory/kratos/commit/96c1ff7747ea38e23a3892f74b75ee555ed49c88)) +- Allow marking OIDC provider-verified addresses as verified during registration + ([#3448](https://github.com/ory/kratos/issues/3448)) + ([e7b33a1](https://github.com/ory/kratos/commit/e7b33a168bf0c0fe0492901abd3df8b6d6a08a68)), + closes [#3445](https://github.com/ory/kratos/issues/3445) + [#3424](https://github.com/ory/kratos/issues/3424) + [#1057](https://github.com/ory/kratos/issues/1057): + + This feature allows marking emails provided by social sign in providers as + verified. + - Hot-reload CORS origins ([#3423](https://github.com/ory/kratos/issues/3423)) ([157d934](https://github.com/ory/kratos/commit/157d9345aeb04f371f9d85b70c89e8646e781333)) - Provide login hints when registration fails due to duplicate From 77c3196fd60c5927b84e9a7f6546f80ac2d78ee5 Mon Sep 17 00:00:00 2001 From: Henning Perl Date: Thu, 24 Aug 2023 09:59:32 +0200 Subject: [PATCH 052/282] fix: registration with verification (#3451) --- ...add_oauth2_login_challenge_params.down.sql | 2 ++ ...oauth2_login_challenge_params.mysql.up.sql | 2 ++ ...auth2_login_challenge_params.sqlite.up.sql | 2 ++ ...n_add_oauth2_login_challenge_params.up.sql | 2 ++ selfservice/flow/verification/flow.go | 17 ++++++++++--- selfservice/flow/verification/handler.go | 24 ++++--------------- selfservice/flow/verification/handler_test.go | 10 +++++--- selfservice/hook/verification.go | 2 ++ session/session.go | 6 +++++ 9 files changed, 42 insertions(+), 25 deletions(-) create mode 100644 persistence/sql/migrations/sql/20230823000000000001_verification_add_oauth2_login_challenge_params.down.sql create mode 100644 persistence/sql/migrations/sql/20230823000000000001_verification_add_oauth2_login_challenge_params.mysql.up.sql create mode 100644 persistence/sql/migrations/sql/20230823000000000001_verification_add_oauth2_login_challenge_params.sqlite.up.sql create mode 100644 persistence/sql/migrations/sql/20230823000000000001_verification_add_oauth2_login_challenge_params.up.sql diff --git a/persistence/sql/migrations/sql/20230823000000000001_verification_add_oauth2_login_challenge_params.down.sql b/persistence/sql/migrations/sql/20230823000000000001_verification_add_oauth2_login_challenge_params.down.sql new file mode 100644 index 000000000000..1a1437ae0526 --- /dev/null +++ b/persistence/sql/migrations/sql/20230823000000000001_verification_add_oauth2_login_challenge_params.down.sql @@ -0,0 +1,2 @@ +ALTER TABLE selfservice_verification_flows DROP COLUMN identity_id; +ALTER TABLE selfservice_verification_flows DROP COLUMN authentication_methods; diff --git a/persistence/sql/migrations/sql/20230823000000000001_verification_add_oauth2_login_challenge_params.mysql.up.sql b/persistence/sql/migrations/sql/20230823000000000001_verification_add_oauth2_login_challenge_params.mysql.up.sql new file mode 100644 index 000000000000..31614eb14175 --- /dev/null +++ b/persistence/sql/migrations/sql/20230823000000000001_verification_add_oauth2_login_challenge_params.mysql.up.sql @@ -0,0 +1,2 @@ +ALTER TABLE selfservice_verification_flows ADD COLUMN identity_id VARCHAR(36); +ALTER TABLE selfservice_verification_flows ADD COLUMN authentication_methods JSON; diff --git a/persistence/sql/migrations/sql/20230823000000000001_verification_add_oauth2_login_challenge_params.sqlite.up.sql b/persistence/sql/migrations/sql/20230823000000000001_verification_add_oauth2_login_challenge_params.sqlite.up.sql new file mode 100644 index 000000000000..ab661e1c6753 --- /dev/null +++ b/persistence/sql/migrations/sql/20230823000000000001_verification_add_oauth2_login_challenge_params.sqlite.up.sql @@ -0,0 +1,2 @@ +ALTER TABLE selfservice_verification_flows ADD COLUMN identity_id VARCHAR(36); +ALTER TABLE selfservice_verification_flows ADD COLUMN authentication_methods TEXT; diff --git a/persistence/sql/migrations/sql/20230823000000000001_verification_add_oauth2_login_challenge_params.up.sql b/persistence/sql/migrations/sql/20230823000000000001_verification_add_oauth2_login_challenge_params.up.sql new file mode 100644 index 000000000000..42b75ecd7dfd --- /dev/null +++ b/persistence/sql/migrations/sql/20230823000000000001_verification_add_oauth2_login_challenge_params.up.sql @@ -0,0 +1,2 @@ +ALTER TABLE selfservice_verification_flows ADD COLUMN identity_id UUID; +ALTER TABLE selfservice_verification_flows ADD COLUMN authentication_methods JSON; diff --git a/selfservice/flow/verification/flow.go b/selfservice/flow/verification/flow.go index a77cf30dc688..71a484f7d9c5 100644 --- a/selfservice/flow/verification/flow.go +++ b/selfservice/flow/verification/flow.go @@ -17,6 +17,7 @@ import ( "github.com/ory/kratos/driver/config" "github.com/ory/kratos/selfservice/flow" + "github.com/ory/kratos/session" "github.com/ory/kratos/ui/container" "github.com/ory/kratos/x" "github.com/ory/x/sqlxx" @@ -81,9 +82,7 @@ type Flow struct { // OAuth2LoginChallenge holds the login challenge originally set during the registration flow. OAuth2LoginChallenge sqlxx.NullString `json:"-" db:"oauth2_login_challenge"` - - // SessionID holds the session id if set from a registraton hook. - SessionID uuid.NullUUID `json:"-" faker:"-" db:"session_id"` + OAuth2LoginChallengeParams // CSRFToken contains the anti-csrf token associated with this request. CSRFToken string `json:"-" db:"csrf_token"` @@ -95,6 +94,18 @@ type Flow struct { NID uuid.UUID `json:"-" faker:"-" db:"nid"` } +type OAuth2LoginChallengeParams struct { + // SessionID holds the session id if set from a registraton hook. + SessionID uuid.NullUUID `json:"-" faker:"-" db:"session_id"` + + // IdentityID holds the identity id if set from a registraton hook. + IdentityID uuid.NullUUID `json:"-" faker:"-" db:"identity_id"` + + // AMR contains a list of authentication methods that were used to verify the + // session if set from a registration hook. + AMR session.AuthenticationMethods `db:"authentication_methods" json:"-"` +} + func (f *Flow) GetType() flow.Type { return f.Type } diff --git a/selfservice/flow/verification/handler.go b/selfservice/flow/verification/handler.go index 2ed3ca3f3679..977cb7bd8616 100644 --- a/selfservice/flow/verification/handler.go +++ b/selfservice/flow/verification/handler.go @@ -4,7 +4,6 @@ package verification import ( - "context" "net/http" "time" @@ -54,6 +53,7 @@ type ( x.CSRFTokenGeneratorProvider x.WriterProvider x.CSRFProvider + x.LoggingProvider FlowPersistenceProvider ErrorHandlerProvider @@ -445,8 +445,7 @@ func (h *Handler) updateVerificationFlow(w http.ResponseWriter, r *http.Request, // Special case: If we ended up here through a OAuth2 login challenge, we need to accept the login request // and redirect back to the OAuth2 provider. if f.OAuth2LoginChallenge.String() != "" { - sess := h.maybeGetSession(ctx, f) - if sess == nil { + if !f.IdentityID.Valid || !f.SessionID.Valid { h.d.VerificationFlowErrorHandler().WriteFlowError(w, r, f, node.DefaultGroup, herodot.ErrBadRequest.WithReasonf("No session was found for this flow. Please retry the authentication.")) return @@ -455,9 +454,9 @@ func (h *Handler) updateVerificationFlow(w http.ResponseWriter, r *http.Request, callbackURL, err := h.d.Hydra().AcceptLoginRequest(ctx, hydra.AcceptLoginRequestParams{ LoginChallenge: string(f.OAuth2LoginChallenge), - IdentityID: sess.IdentityID.String(), - SessionID: sess.ID.String(), - AuthenticationMethods: sess.AMR, + IdentityID: f.IdentityID.UUID.String(), + SessionID: f.SessionID.UUID.String(), + AuthenticationMethods: f.AMR, }) if err != nil { h.d.VerificationFlowErrorHandler().WriteFlowError(w, r, f, node.DefaultGroup, err) @@ -480,16 +479,3 @@ func (h *Handler) updateVerificationFlow(w http.ResponseWriter, r *http.Request, h.d.Writer().Write(w, r, updatedFlow) } - -// maybeGetSession returns the session if it was found in the flow or nil otherwise. -func (h *Handler) maybeGetSession(ctx context.Context, f *Flow) *session.Session { - if !f.SessionID.Valid { - return nil - } - s, err := h.d.SessionPersister().GetSession(ctx, f.SessionID.UUID, session.ExpandNothing) - if err != nil { - return nil - } - - return s -} diff --git a/selfservice/flow/verification/handler_test.go b/selfservice/flow/verification/handler_test.go index cfac42d1eced..092f659e4a36 100644 --- a/selfservice/flow/verification/handler_test.go +++ b/selfservice/flow/verification/handler_test.go @@ -20,9 +20,11 @@ import ( "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/selfservice/flow/verification" + "github.com/ory/kratos/session" "github.com/ory/kratos/x" ) @@ -214,15 +216,17 @@ func TestPostFlow(t *testing.T) { t.Run("suite=with OIDC login challenge", func(t *testing.T) { t.Run("case=succeeds with a session", func(t *testing.T) { - s := testhelpers.CreateSession(t, reg) - f := &verification.Flow{ ID: uuid.Must(uuid.NewV4()), Type: "browser", ExpiresAt: time.Now().Add(1 * time.Hour), IssuedAt: time.Now(), OAuth2LoginChallenge: hydra.FakeValidLoginChallenge, - SessionID: uuid.NullUUID{UUID: s.ID, Valid: true}, + OAuth2LoginChallengeParams: verification.OAuth2LoginChallengeParams{ + SessionID: uuid.NullUUID{UUID: uuid.Must(uuid.NewV4()), Valid: true}, + IdentityID: uuid.NullUUID{UUID: uuid.Must(uuid.NewV4()), Valid: true}, + AMR: session.AuthenticationMethods{{Method: identity.CredentialsTypePassword}}, + }, } require.NoError(t, reg.VerificationFlowPersister().CreateVerificationFlow(ctx, f)) diff --git a/selfservice/hook/verification.go b/selfservice/hook/verification.go index 899542bd8f60..ba4d7e7d79a7 100644 --- a/selfservice/hook/verification.go +++ b/selfservice/hook/verification.go @@ -47,6 +47,8 @@ func (e *Verifier) ExecutePostRegistrationPostPersistHook(w http.ResponseWriter, return e.do(w, r.WithContext(ctx), s.Identity, f, func(v *verification.Flow) { v.OAuth2LoginChallenge = f.OAuth2LoginChallenge v.SessionID = uuid.NullUUID{UUID: s.ID, Valid: true} + v.IdentityID = uuid.NullUUID{UUID: s.Identity.ID, Valid: true} + v.AMR = s.AMR }) }) } diff --git a/session/session.go b/session/session.go index c409323c2962..f915fd0aad02 100644 --- a/session/session.go +++ b/session/session.go @@ -329,6 +329,9 @@ type AuthenticationMethod struct { // Scan implements the Scanner interface. func (n *AuthenticationMethod) Scan(value interface{}) error { + if value == nil { + return nil + } v := fmt.Sprintf("%s", value) if len(v) == 0 { return nil @@ -347,6 +350,9 @@ func (n AuthenticationMethod) Value() (driver.Value, error) { // Scan implements the Scanner interface. func (n *AuthenticationMethods) Scan(value interface{}) error { + if value == nil { + return nil + } v := fmt.Sprintf("%s", value) if len(v) == 0 { return nil From 9f80425a8c297db70bd871e3ce821ad035746b01 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Thu, 24 Aug 2023 08:01:50 +0000 Subject: [PATCH 053/282] autogen(openapi): regenerate swagger spec and internal client [skip ci] --- spec/api.json | 3 +++ spec/swagger.json | 3 +++ 2 files changed, 6 insertions(+) diff --git a/spec/api.json b/spec/api.json index ba53f81316a8..d1973e17f7fd 100755 --- a/spec/api.json +++ b/spec/api.json @@ -367,6 +367,9 @@ }, "type": "object" }, + "OAuth2LoginChallengeParams": { + "type": "object" + }, "OAuth2LoginRequest": { "description": "OAuth2LoginRequest struct for OAuth2LoginRequest", "properties": { diff --git a/spec/swagger.json b/spec/swagger.json index 2a8213001b3b..01ad8fb3bf27 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -3341,6 +3341,9 @@ } } }, + "OAuth2LoginChallengeParams": { + "type": "object" + }, "OAuth2LoginRequest": { "description": "OAuth2LoginRequest struct for OAuth2LoginRequest", "type": "object", From c492bdcd0c5dbdf527ae523d879a6c1eeb9c4cdf Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Thu, 24 Aug 2023 11:10:42 +0200 Subject: [PATCH 054/282] fix: pass context (#3452) --- session/manager_http.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/session/manager_http.go b/session/manager_http.go index b4577e4c9035..252a0dc285d7 100644 --- a/session/manager_http.go +++ b/session/manager_http.go @@ -195,16 +195,16 @@ func (s *ManagerHTTP) getCookie(r *http.Request) (*sessions.Session, error) { } func (s *ManagerHTTP) extractToken(r *http.Request) string { - _, span := s.r.Tracer(r.Context()).Tracer().Start(r.Context(), "sessions.ManagerHTTP.extractToken") + ctx, span := s.r.Tracer(r.Context()).Tracer().Start(r.Context(), "sessions.ManagerHTTP.extractToken") defer span.End() if token := r.Header.Get("X-Session-Token"); len(token) > 0 { return token } - cookie, err := s.getCookie(r) + cookie, err := s.getCookie(r.WithContext(ctx)) if err != nil { - token, _ := bearerTokenFromRequest(r) + token, _ := bearerTokenFromRequest(r.WithContext(ctx)) return token } @@ -213,7 +213,7 @@ func (s *ManagerHTTP) extractToken(r *http.Request) string { return token } - token, _ = bearerTokenFromRequest(r) + token, _ = bearerTokenFromRequest(r.WithContext(ctx)) return token } From 703b910927d879558bfeb0fd2c3339b1d301fac8 Mon Sep 17 00:00:00 2001 From: Krzysztof Bogacki Date: Thu, 24 Aug 2023 11:11:00 +0200 Subject: [PATCH 055/282] fix: properly normalize OIDC verified emails (#3450) --- selfservice/strategy/oidc/strategy_registration.go | 3 ++- selfservice/strategy/oidc/strategy_test.go | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/selfservice/strategy/oidc/strategy_registration.go b/selfservice/strategy/oidc/strategy_registration.go index 6fcac4987d20..464f4ad5796f 100644 --- a/selfservice/strategy/oidc/strategy_registration.go +++ b/selfservice/strategy/oidc/strategy_registration.go @@ -409,7 +409,8 @@ func (s *Strategy) extractVerifiedAddresses(evaluated string) ([]VerifiedAddress return nil, errors.WithStack(herodot.ErrBadRequest.WithReasonf("Failed to unmarshal value for key %s. Please check your Jsonnet code!", VerifiedAddressesKey).WithDebugf("%s", err)) } - for _, va := range va { + for i := range va { + va := &va[i] if va.Via == identity.VerifiableAddressTypeEmail { va.Value = strings.ToLower(strings.TrimSpace(va.Value)) } diff --git a/selfservice/strategy/oidc/strategy_test.go b/selfservice/strategy/oidc/strategy_test.go index 401714c4b43a..0969caa38da5 100644 --- a/selfservice/strategy/oidc/strategy_test.go +++ b/selfservice/strategy/oidc/strategy_test.go @@ -825,6 +825,17 @@ func TestStrategy(t *testing.T) { assertVerifiedEmail(t, body, true) }) + t.Run("case=should have verified address when subject matches after normalization", func(t *testing.T) { + subject = " Denormalized-Verified-Email@ory.sh " + r := newBrowserRegistrationFlow(t, returnTS.URL, time.Minute) + action := assertFormValues(t, r.ID, "valid") + res, body := makeRequest(t, "valid", action, url.Values{"traits.subject": {"denormalized-verified-EMAIL@ory.sh"}}) + subject = "denormalized-verified-EMAIL@ory.sh" + assertIdentity(t, res, body) + subject = "denormalized-verified-email@ory.sh" + assertVerifiedEmail(t, body, true) + }) + t.Run("case=should have unverified address when subject does not match", func(t *testing.T) { subject = "changed-verified-email@ory.sh" r := newBrowserRegistrationFlow(t, returnTS.URL, time.Minute) From dda19e83efaef8f78eb7f754fe435c66ab33f997 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20B=C5=82aszczyk?= Date: Fri, 25 Aug 2023 08:44:00 +0200 Subject: [PATCH 056/282] chore: update Dockerfile-alpine (#3453) --- .docker/Dockerfile-alpine | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.docker/Dockerfile-alpine b/.docker/Dockerfile-alpine index 29a9663d2b5a..6f1713e00bcf 100644 --- a/.docker/Dockerfile-alpine +++ b/.docker/Dockerfile-alpine @@ -1,4 +1,4 @@ -FROM alpine:3.18 +FROM alpine:3.18.3 # Because this image supports SQLite, we create /home/ory and /home/ory/sqlite which is owned by the ory user # and declare /home/ory/sqlite a volume. From 37f16577d92ba88869bf15fb1ea54e819b062724 Mon Sep 17 00:00:00 2001 From: Patrik Date: Mon, 28 Aug 2023 14:45:25 +0200 Subject: [PATCH 057/282] feat: improve messages for easier i18n (#3457) --- cmd/clidoc/main.go | 44 ++-- hash/hasher_bcrypt.go | 4 +- schema/errors.go | 8 +- ...=fails_if_active_strategy_is_disabled.json | 3 +- ...=fails_if_active_strategy_is_disabled.json | 3 +- selfservice/strategy/password/registration.go | 5 +- .../strategy/password/settings_test.go | 12 +- selfservice/strategy/password/validator.go | 9 +- .../strategy/password/validator_test.go | 4 +- ...ntial_available-type=browser-response.json | 3 +- ...redential_available-type=spa-response.json | 3 +- .../email/registration/errors.spec.ts | 4 +- .../profiles/email/settings/errors.spec.ts | 2 +- .../profiles/email/settings/success.spec.ts | 5 +- test/e2e/cypress/support/commands.ts | 6 +- text/id.go | 8 +- text/message.go | 12 + text/message_login.go | 2 +- text/message_recovery.go | 2 +- text/message_registration.go | 2 +- text/message_settings.go | 2 +- text/message_validation.go | 242 +++++++++++++----- text/message_verification.go | 2 +- text/type.go | 2 +- ui/container/container.go | 53 +++- 25 files changed, 305 insertions(+), 137 deletions(-) diff --git a/cmd/clidoc/main.go b/cmd/clidoc/main.go index 6b4bbd7840af..d3775d1eafb1 100644 --- a/cmd/clidoc/main.go +++ b/cmd/clidoc/main.go @@ -33,11 +33,11 @@ var inAMinute = time.Date(2020, 1, 1, 1, 0, 0, 0, time.UTC).Add(time.Minute) var messages map[string]*text.Message func init() { - text.Now = func() time.Time { - return inAMinute - } text.Until = func(t time.Time) time.Duration { - return time.Second + return time.Minute + } + text.Since = func(time.Time) time.Duration { + return time.Minute } messages = map[string]*text.Message{ @@ -59,8 +59,8 @@ func init() { "NewInfoSelfServiceSettingsRegenerateLookup": text.NewInfoSelfServiceSettingsRegenerateLookup(), "NewInfoSelfServiceSettingsDisableLookup": text.NewInfoSelfServiceSettingsDisableLookup(), "NewInfoSelfServiceSettingsLookupConfirm": text.NewInfoSelfServiceSettingsLookupConfirm(), - "NewInfoSelfServiceSettingsLookupSecretList": text.NewInfoSelfServiceSettingsLookupSecretList([]string{"{code-1}", "{code-2}"}, []interface{}{ - text.NewInfoSelfServiceSettingsLookupSecret("{code}"), + "NewInfoSelfServiceSettingsLookupSecretList": text.NewInfoSelfServiceSettingsLookupSecretList([]string{"{secrets_list}"}, []interface{}{ + text.NewInfoSelfServiceSettingsLookupSecret("{secret}"), text.NewInfoSelfServiceSettingsLookupSecretUsed(aSecondAgo), }), "NewInfoSelfServiceSettingsLookupSecret": text.NewInfoSelfServiceSettingsLookupSecret("{secret}"), @@ -82,19 +82,25 @@ func init() { "NewErrorSystemGeneric": text.NewErrorSystemGeneric("{reason}"), "NewValidationErrorGeneric": text.NewValidationErrorGeneric("{reason}"), "NewValidationErrorRequired": text.NewValidationErrorRequired("{field}"), - "NewErrorValidationMinLength": text.NewErrorValidationMinLength("length must be >= 5, but got 3"), - "NewErrorValidationMaxLength": text.NewErrorValidationMaxLength("length must be <= 5, but got 6"), - "NewErrorValidationInvalidFormat": text.NewErrorValidationInvalidFormat("does not match pattern \"^[a-z]*$\""), - "NewErrorValidationMinimum": text.NewErrorValidationMinimum("must be >= 5 but found 3"), - "NewErrorValidationExclusiveMinimum": text.NewErrorValidationExclusiveMinimum("must be > 5 but found 5"), - "NewErrorValidationMaximum": text.NewErrorValidationMaximum("must be <= 5 but found 6"), - "NewErrorValidationExclusiveMaximum": text.NewErrorValidationExclusiveMaximum("must be < 5 but found 5"), - "NewErrorValidationMultipleOf": text.NewErrorValidationMultipleOf("7 not multipleOf 3"), - "NewErrorValidationMaxItems": text.NewErrorValidationMaxItems("maximum 3 items allowed, but found 4 items"), - "NewErrorValidationMinItems": text.NewErrorValidationMinItems("minimum 3 items allowed, but found 2 items"), - "NewErrorValidationUniqueItems": text.NewErrorValidationUniqueItems("items at index 0 and 2 are equal"), - "NewErrorValidationWrongType": text.NewErrorValidationWrongType("expected number, but got string"), - "NewErrorValidationPasswordPolicyViolation": text.NewErrorValidationPasswordPolicyViolation("{reason}"), + "NewErrorValidationMinLength": text.NewErrorValidationMinLength(5, 3), + "NewErrorValidationMaxLength": text.NewErrorValidationMaxLength(5, 6), + "NewErrorValidationInvalidFormat": text.NewErrorValidationInvalidFormat("{pattern}"), + "NewErrorValidationMinimum": text.NewErrorValidationMinimum(5, 3), + "NewErrorValidationExclusiveMinimum": text.NewErrorValidationExclusiveMinimum(5, 5), + "NewErrorValidationMaximum": text.NewErrorValidationMaximum(5, 6), + "NewErrorValidationExclusiveMaximum": text.NewErrorValidationExclusiveMaximum(5, 5), + "NewErrorValidationMultipleOf": text.NewErrorValidationMultipleOf(7, 3), + "NewErrorValidationMaxItems": text.NewErrorValidationMaxItems(3, 4), + "NewErrorValidationMinItems": text.NewErrorValidationMinItems(3, 2), + "NewErrorValidationUniqueItems": text.NewErrorValidationUniqueItems(0, 2), + "NewErrorValidationWrongType": text.NewErrorValidationWrongType([]string{"{allowed_types_list}"}, "{actual_type}"), + "NewErrorValidationConst": text.NewErrorValidationConst("{expected}"), + "NewErrorValidationConstGeneric": text.NewErrorValidationConstGeneric(), + "NewErrorValidationPasswordPolicyViolationGeneric": text.NewErrorValidationPasswordPolicyViolationGeneric("{reason}"), + "NewErrorValidationPasswordIdentifierTooSimilar": text.NewErrorValidationPasswordIdentifierTooSimilar(), + "NewErrorValidationPasswordMinLength": text.NewErrorValidationPasswordMinLength(6, 5), + "NewErrorValidationPasswordMaxLength": text.NewErrorValidationPasswordMaxLength(72, 80), + "NewErrorValidationPasswordTooManyBreaches": text.NewErrorValidationPasswordTooManyBreaches(101), "NewErrorValidationInvalidCredentials": text.NewErrorValidationInvalidCredentials(), "NewErrorValidationDuplicateCredentials": text.NewErrorValidationDuplicateCredentials(), "NewErrorValidationDuplicateCredentialsWithHints": text.NewErrorValidationDuplicateCredentialsWithHints("{reason}", nil, nil, ""), diff --git a/hash/hasher_bcrypt.go b/hash/hasher_bcrypt.go index 330936a44343..dab6030a8376 100644 --- a/hash/hasher_bcrypt.go +++ b/hash/hasher_bcrypt.go @@ -7,6 +7,8 @@ import ( "context" "fmt" + "github.com/ory/kratos/text" + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" @@ -58,7 +60,7 @@ func validateBcryptPasswordLength(password []byte) error { if len(password) > 72 { return schema.NewPasswordPolicyViolationError( "#/password", - "passwords are limited to a maximum length of 72 characters", + text.NewErrorValidationPasswordMaxLength(72, len(password)), ) } return nil diff --git a/schema/errors.go b/schema/errors.go index 68683d369a06..73d144e0be9e 100644 --- a/schema/errors.go +++ b/schema/errors.go @@ -87,16 +87,16 @@ func (r *ValidationErrorContextPasswordPolicyViolation) AddContext(_, _ string) func (r *ValidationErrorContextPasswordPolicyViolation) FinishInstanceContext() {} -func NewPasswordPolicyViolationError(instancePtr string, reason string) error { +func NewPasswordPolicyViolationError(instancePtr string, message *text.Message) error { return errors.WithStack(&ValidationError{ ValidationError: &jsonschema.ValidationError{ - Message: fmt.Sprintf("the password does not fulfill the password policy because: %s", reason), + Message: fmt.Sprintf("the password does not fulfill the password policy because: %s", message.Text), InstancePtr: instancePtr, Context: &ValidationErrorContextPasswordPolicyViolation{ - Reason: reason, + Reason: message.Text, }, }, - Messages: new(text.Messages).Add(text.NewErrorValidationPasswordPolicyViolation(reason)), + Messages: new(text.Messages).Add(message), }) } diff --git a/selfservice/flow/recovery/.snapshots/TestHandleError-flow=api-case=fails_if_active_strategy_is_disabled.json b/selfservice/flow/recovery/.snapshots/TestHandleError-flow=api-case=fails_if_active_strategy_is_disabled.json index 0551ed7da92e..4bb7e689fd5a 100644 --- a/selfservice/flow/recovery/.snapshots/TestHandleError-flow=api-case=fails_if_active_strategy_is_disabled.json +++ b/selfservice/flow/recovery/.snapshots/TestHandleError-flow=api-case=fails_if_active_strategy_is_disabled.json @@ -61,7 +61,8 @@ { "id": 4000001, "text": "The active recovery strategy code is not enabled. Please enable it in the configuration.", - "type": "error" + "type": "error", + "context": {} } ] }, diff --git a/selfservice/flow/recovery/.snapshots/TestHandleError-flow=spa-case=fails_if_active_strategy_is_disabled.json b/selfservice/flow/recovery/.snapshots/TestHandleError-flow=spa-case=fails_if_active_strategy_is_disabled.json index 0d17f9aab108..7e6c9fd7f953 100644 --- a/selfservice/flow/recovery/.snapshots/TestHandleError-flow=spa-case=fails_if_active_strategy_is_disabled.json +++ b/selfservice/flow/recovery/.snapshots/TestHandleError-flow=spa-case=fails_if_active_strategy_is_disabled.json @@ -61,7 +61,8 @@ { "id": 4000001, "text": "The active recovery strategy code is not enabled. Please enable it in the configuration.", - "type": "error" + "type": "error", + "context": {} } ] }, diff --git a/selfservice/strategy/password/registration.go b/selfservice/strategy/password/registration.go index 57ebca990923..5fa174f48cbc 100644 --- a/selfservice/strategy/password/registration.go +++ b/selfservice/strategy/password/registration.go @@ -136,7 +136,10 @@ func (s *Strategy) validateCredentials(ctx context.Context, i *identity.Identity if _, ok := errorsx.Cause(err).(*herodot.DefaultError); ok { return err } - return schema.NewPasswordPolicyViolationError("#/password", err.Error()) + if message := new(text.Message); errors.As(err, &message) { + return schema.NewPasswordPolicyViolationError("#/password", message) + } + return schema.NewPasswordPolicyViolationError("#/password", text.NewErrorValidationPasswordPolicyViolationGeneric(err.Error())) } } diff --git a/selfservice/strategy/password/settings_test.go b/selfservice/strategy/password/settings_test.go index b5c865dbd177..502f7e5c98a1 100644 --- a/selfservice/strategy/password/settings_test.go +++ b/selfservice/strategy/password/settings_test.go @@ -133,10 +133,10 @@ func TestSettings(t *testing.T) { } t.Run("description=should fail if password violates policy", func(t *testing.T) { - var check = func(t *testing.T, actual string) { + var check = func(t *testing.T, reason, actual string) { assert.Empty(t, gjson.Get(actual, "ui.nodes.#(attributes.name==password).attributes.value").String(), "%s", actual) assert.NotEmpty(t, gjson.Get(actual, "ui.nodes.#(attributes.name==csrf_token).attributes.value").String(), "%s", actual) - assert.Contains(t, gjson.Get(actual, "ui.nodes.#(attributes.name==password).messages.0.text").String(), "password can not be used because", "%s", actual) + assert.Equal(t, reason, gjson.Get(actual, "ui.nodes.#(attributes.name==password).messages.0.text").String(), "%s", actual) } t.Run("session=with privileged session", func(t *testing.T) { @@ -148,15 +148,15 @@ func TestSettings(t *testing.T) { } t.Run("type=api", func(t *testing.T) { - check(t, expectValidationError(t, true, false, apiUser1, payload)) + check(t, "The password must be at least 8 characters long, but got 6.", expectValidationError(t, true, false, apiUser1, payload)) }) t.Run("spa=spa", func(t *testing.T) { - check(t, expectValidationError(t, false, true, browserUser1, payload)) + check(t, "The password must be at least 8 characters long, but got 6.", expectValidationError(t, false, true, browserUser1, payload)) }) t.Run("type=browser", func(t *testing.T) { - check(t, expectValidationError(t, false, false, browserUser1, payload)) + check(t, "The password must be at least 8 characters long, but got 6.", expectValidationError(t, false, false, browserUser1, payload)) }) }) @@ -190,7 +190,7 @@ func TestSettings(t *testing.T) { t.Run("type=browser", func(t *testing.T) { _ = testhelpers.NewSettingsLoginAcceptAPIServer(t, testhelpers.NewSDKCustomClient(publicTS, browserUser1), conf) - check(t, expectValidationError(t, false, false, browserUser1, payload)) + check(t, "The password must be at least 8 characters long, but got 6.", expectValidationError(t, false, false, browserUser1, payload)) }) }) }) diff --git a/selfservice/strategy/password/validator.go b/selfservice/strategy/password/validator.go index ada93679a9d8..0875dff6a868 100644 --- a/selfservice/strategy/password/validator.go +++ b/selfservice/strategy/password/validator.go @@ -14,6 +14,8 @@ import ( "strings" "time" + "github.com/ory/kratos/text" + "github.com/arbovm/levenshtein" "github.com/dgraph-io/ristretto" "github.com/hashicorp/go-retryablehttp" @@ -45,7 +47,6 @@ var ( _ Validator = new(DefaultPasswordValidator) ErrNetworkFailure = stderrs.New("unable to check if password has been leaked because an unexpected network error occurred") ErrUnexpectedStatusCode = stderrs.New("unexpected status code") - ErrTooManyBreaches = stderrs.New("the password has been found in data breaches and must no longer be used") ) // DefaultPasswordValidator implements Validator. It is based on best @@ -179,7 +180,7 @@ func (s *DefaultPasswordValidator) validate(ctx context.Context, identifier, pas passwordPolicyConfig := s.reg.Config().PasswordPolicyConfig(ctx) if len(password) < int(passwordPolicyConfig.MinPasswordLength) { - return errors.Errorf("password length must be at least %d characters but only got %d", passwordPolicyConfig.MinPasswordLength, len(password)) + return text.NewErrorValidationPasswordMinLength(int(passwordPolicyConfig.MinPasswordLength), len(password)) } if passwordPolicyConfig.IdentifierSimilarityCheckEnabled && len(identifier) > 0 { @@ -187,7 +188,7 @@ func (s *DefaultPasswordValidator) validate(ctx context.Context, identifier, pas dist := levenshtein.Distance(compIdentifier, compPassword) lcs := float32(lcsLength(compIdentifier, compPassword)) / float32(len(compPassword)) if dist < s.minIdentifierPasswordDist || lcs > s.maxIdentifierPasswordSubstrThreshold { - return errors.Errorf("the password is too similar to the user identifier") + return text.NewErrorValidationPasswordIdentifierTooSimilar() } } @@ -215,7 +216,7 @@ func (s *DefaultPasswordValidator) validate(ctx context.Context, identifier, pas v, ok := c.(int64) if ok && v > int64(s.reg.Config().PasswordPolicyConfig(ctx).MaxBreaches) { - return errors.WithStack(ErrTooManyBreaches) + return text.NewErrorValidationPasswordTooManyBreaches(v) } return nil diff --git a/selfservice/strategy/password/validator_test.go b/selfservice/strategy/password/validator_test.go index c3a066aad5dc..f101cc19b59f 100644 --- a/selfservice/strategy/password/validator_test.go +++ b/selfservice/strategy/password/validator_test.go @@ -17,6 +17,8 @@ import ( "testing" "time" + "github.com/ory/kratos/text" + "github.com/stretchr/testify/assert" "github.com/ory/herodot" @@ -224,7 +226,7 @@ func TestDefaultPasswordValidationStrategy(t *testing.T) { res: func(t *testing.T, hash string) string { return fmt.Sprintf("%s:%d", hash, conf.PasswordPolicyConfig(ctx).MaxBreaches+1) }, - expectErr: password.ErrTooManyBreaches, + expectErr: text.NewErrorValidationPasswordTooManyBreaches(int64(conf.PasswordPolicyConfig(ctx).MaxBreaches) + 1), }, } { t.Run(fmt.Sprintf("case=%s/expected err=%s", tc.name, tc.expectErr), func(t *testing.T) { diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=fails_to_remove_security_key_if_it_is_passwordless_and_the_last_credential_available-type=browser-response.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=fails_to_remove_security_key_if_it_is_passwordless_and_the_last_credential_available-type=browser-response.json index c8a8492004cd..c3147ce1a714 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=fails_to_remove_security_key_if_it_is_passwordless_and_the_last_credential_available-type=browser-response.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=fails_to_remove_security_key_if_it_is_passwordless_and_the_last_credential_available-type=browser-response.json @@ -11,7 +11,8 @@ { "id": 4000001, "text": "unable to remove this security key because it would lock you out of your account", - "type": "error" + "type": "error", + "context": {} } ], "meta": {} diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=fails_to_remove_security_key_if_it_is_passwordless_and_the_last_credential_available-type=spa-response.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=fails_to_remove_security_key_if_it_is_passwordless_and_the_last_credential_available-type=spa-response.json index c8a8492004cd..c3147ce1a714 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=fails_to_remove_security_key_if_it_is_passwordless_and_the_last_credential_available-type=spa-response.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=fails_to_remove_security_key_if_it_is_passwordless_and_the_last_credential_available-type=spa-response.json @@ -11,7 +11,8 @@ { "id": 4000001, "text": "unable to remove this security key because it would lock you out of your account", - "type": "error" + "type": "error", + "context": {} } ], "meta": {} diff --git a/test/e2e/cypress/integration/profiles/email/registration/errors.spec.ts b/test/e2e/cypress/integration/profiles/email/registration/errors.spec.ts index e4384b3a091d..bf0712da054e 100644 --- a/test/e2e/cypress/integration/profiles/email/registration/errors.spec.ts +++ b/test/e2e/cypress/integration/profiles/email/registration/errors.spec.ts @@ -67,7 +67,7 @@ describe("Registration failures with email profile", () => { .should("have.value", "12345678") cy.submitPasswordForm() - cy.get('[data-testid="ui/message/4000005"]').should( + cy.get('[data-testid="ui/message/4000034"]').should( "contain.text", "data breaches", ) @@ -79,7 +79,7 @@ describe("Registration failures with email profile", () => { cy.get('input[name="password"]').type(identity) cy.submitPasswordForm() - cy.get('[data-testid="ui/message/4000005"]').should( + cy.get('[data-testid="ui/message/4000031"]').should( "contain.text", "too similar", ) diff --git a/test/e2e/cypress/integration/profiles/email/settings/errors.spec.ts b/test/e2e/cypress/integration/profiles/email/settings/errors.spec.ts index fb8c99ed9935..c26a001a662d 100644 --- a/test/e2e/cypress/integration/profiles/email/settings/errors.spec.ts +++ b/test/e2e/cypress/integration/profiles/email/settings/errors.spec.ts @@ -161,7 +161,7 @@ context("Settings failures with email profile", () => { it("fails if password policy is violated", () => { cy.get('input[name="password"]').clear().type("12345678") cy.get('button[value="password"]').click() - cy.get('[data-testid="ui/message/4000005"]').should( + cy.get('[data-testid="ui/message/4000034"]').should( "contain.text", "data breaches", ) diff --git a/test/e2e/cypress/integration/profiles/email/settings/success.spec.ts b/test/e2e/cypress/integration/profiles/email/settings/success.spec.ts index 763c7f66aff2..5e301cdb3ff2 100644 --- a/test/e2e/cypress/integration/profiles/email/settings/success.spec.ts +++ b/test/e2e/cypress/integration/profiles/email/settings/success.spec.ts @@ -61,14 +61,15 @@ context("Settings success with email profile", () => { cy.get('input[name="password"]').clear().type("123") cy.get('button[value="password"]').click() cy.get('[data-testid="ui/message/1050001"]').should("not.exist") - cy.get('[data-testid="ui/message/4000005"]').should("exist") + cy.get('[data-testid="ui/message/4000032"]').should("exist") cy.get('input[name="password"]').should("be.empty") password = up(password) cy.get('input[name="password"]').clear().type(password) cy.get('button[value="password"]').click() cy.expectSettingsSaved() - cy.get('[data-testid="ui/message/4000005"]').should("not.exist") + cy.get('[data-testid="ui/message/4000032"]').should("not.exist") + cy.get('[data-testid="ui/message/1050001"]').should("exist") cy.get('input[name="password"]').should("be.empty") }) diff --git a/test/e2e/cypress/support/commands.ts b/test/e2e/cypress/support/commands.ts index 91622e42dd2c..9ab3ea5a41ff 100644 --- a/test/e2e/cypress/support/commands.ts +++ b/test/e2e/cypress/support/commands.ts @@ -811,17 +811,17 @@ Cypress.Commands.add( failOnStatusCode: false, }) }) - .then(({ status }) => { + .then(({ status, body }) => { console.log("Login sequence completed: ", { email, password, expectSession, }) if (expectSession) { - expect(status).to.eq(200) + expect(status).to.eq(200, body) return cy.getSession() } else { - expect(status).to.not.eq(200) + expect(status).to.not.eq(200, body) return cy.noSession() } }) diff --git a/text/id.go b/text/id.go index f216074e191f..0716ad991d8d 100644 --- a/text/id.go +++ b/text/id.go @@ -98,7 +98,7 @@ const ( ErrorValidationRequired ErrorValidationMinLength ErrorValidationInvalidFormat - ErrorValidationPasswordPolicyViolation + ErrorValidationPasswordPolicyViolationGeneric ErrorValidationInvalidCredentials ErrorValidationDuplicateCredentials ErrorValidationTOTPVerifierWrong @@ -122,6 +122,12 @@ const ( ErrorValidationWrongType ErrorValidationDuplicateCredentialsOnOIDCLink ErrorValidationDuplicateCredentialsWithHints + ErrorValidationConst + ErrorValidationConstGeneric + ErrorValidationPasswordIdentifierTooSimilar + ErrorValidationPasswordMinLength + ErrorValidationPasswordMaxLength + ErrorValidationPasswordTooManyBreaches ) const ( diff --git a/text/message.go b/text/message.go index 3c748e6de63b..f1063c048017 100644 --- a/text/message.go +++ b/text/message.go @@ -72,3 +72,15 @@ func (m *Message) Scan(value interface{}) error { func (m Message) Value() (driver.Value, error) { return sqlxx.JSONValue(&m) } + +func (m *Message) Error() string { + return m.Text +} + +func (m *Message) Is(err error) bool { + em, ok := err.(*Message) + if !ok { + return false + } + return m.ID == em.ID +} diff --git a/text/message_login.go b/text/message_login.go index 0a751530ddf0..8f69fa1989a8 100644 --- a/text/message_login.go +++ b/text/message_login.go @@ -112,7 +112,7 @@ func NewInfoLoginWith(provider string) *Message { func NewErrorValidationLoginFlowExpired(expiredAt time.Time) *Message { return &Message{ ID: ErrorValidationLoginFlowExpired, - Text: fmt.Sprintf("The login flow expired %.2f minutes ago, please try again.", Now().Sub(expiredAt).Minutes()), + Text: fmt.Sprintf("The login flow expired %.2f minutes ago, please try again.", Since(expiredAt).Minutes()), Type: Error, Context: context(map[string]interface{}{ "expired_at": expiredAt, diff --git a/text/message_recovery.go b/text/message_recovery.go index 788b88f2808b..94801365a555 100644 --- a/text/message_recovery.go +++ b/text/message_recovery.go @@ -11,7 +11,7 @@ import ( func NewErrorValidationRecoveryFlowExpired(expiredAt time.Time) *Message { return &Message{ ID: ErrorValidationRecoveryFlowExpired, - Text: fmt.Sprintf("The recovery flow expired %.2f minutes ago, please try again.", (-Until(expiredAt)).Minutes()), + Text: fmt.Sprintf("The recovery flow expired %.2f minutes ago, please try again.", Since(expiredAt).Minutes()), Type: Error, Context: context(map[string]interface{}{ "expired_at": expiredAt, diff --git a/text/message_registration.go b/text/message_registration.go index be9135cd06bb..96fd9d4326b5 100644 --- a/text/message_registration.go +++ b/text/message_registration.go @@ -39,7 +39,7 @@ func NewInfoRegistrationContinue() *Message { func NewErrorValidationRegistrationFlowExpired(expiredAt time.Time) *Message { return &Message{ ID: ErrorValidationRegistrationFlowExpired, - Text: fmt.Sprintf("The registration flow expired %.2f minutes ago, please try again.", (-Until(expiredAt)).Minutes()), + Text: fmt.Sprintf("The registration flow expired %.2f minutes ago, please try again.", Since(expiredAt).Minutes()), Type: Error, Context: context(map[string]interface{}{ "expired_at": expiredAt, diff --git a/text/message_settings.go b/text/message_settings.go index 7b4e9358b392..cade5de855cb 100644 --- a/text/message_settings.go +++ b/text/message_settings.go @@ -12,7 +12,7 @@ import ( func NewErrorValidationSettingsFlowExpired(expiredAt time.Time) *Message { return &Message{ ID: ErrorValidationSettingsFlowExpired, - Text: fmt.Sprintf("The settings flow expired %.2f minutes ago, please try again.", (-Until(expiredAt)).Minutes()), + Text: fmt.Sprintf("The settings flow expired %.2f minutes ago, please try again.", Since(expiredAt).Minutes()), Type: Error, Context: context(map[string]interface{}{ "expired_at": expiredAt, diff --git a/text/message_validation.go b/text/message_validation.go index dc62bf6157f2..3467261bb68d 100644 --- a/text/message_validation.go +++ b/text/message_validation.go @@ -5,6 +5,7 @@ package text import ( "fmt" + "strings" ) func NewValidationErrorGeneric(reason string) *Message { @@ -12,7 +13,7 @@ func NewValidationErrorGeneric(reason string) *Message { ID: ErrorValidationGeneric, Text: reason, Type: Error, - Context: nil, + Context: context(nil), } } @@ -21,131 +22,230 @@ func NewValidationErrorRequired(missing string) *Message { ID: ErrorValidationRequired, Text: fmt.Sprintf("Property %s is missing.", missing), Type: Error, - Context: context(map[string]interface{}{ + Context: context(map[string]any{ "property": missing, }), } } -func NewErrorValidationMinLength(reason string) *Message { +func NewErrorValidationMinLength(minLength, actualLength int) *Message { return &Message{ - ID: ErrorValidationMinLength, - Text: reason, - Type: Error, - Context: context(nil), + ID: ErrorValidationMinLength, + Text: fmt.Sprintf("length must be >= %d, but got %d", minLength, actualLength), + Type: Error, + Context: context(map[string]any{ + "min_length": minLength, + "actual_length": actualLength, + }), } } -func NewErrorValidationMaxLength(reason string) *Message { +func NewErrorValidationMaxLength(maxLength, actualLength int) *Message { return &Message{ - ID: ErrorValidationMaxLength, - Text: reason, - Type: Error, - Context: context(nil), + ID: ErrorValidationMaxLength, + Text: fmt.Sprintf("length must be <= %d, but got %d", maxLength, actualLength), + Type: Error, + Context: context(map[string]any{ + "max_length": maxLength, + "actual_length": actualLength, + }), } } -func NewErrorValidationInvalidFormat(reason string) *Message { +func NewErrorValidationInvalidFormat(pattern string) *Message { return &Message{ - ID: ErrorValidationInvalidFormat, - Text: reason, - Type: Error, - Context: context(nil), + ID: ErrorValidationInvalidFormat, + Text: fmt.Sprintf("does not match pattern %q", pattern), + Type: Error, + Context: context(map[string]any{ + "pattern": pattern, + }), } } -func NewErrorValidationMinimum(reason string) *Message { +func NewErrorValidationMinimum(minimum, actual float64) *Message { return &Message{ - ID: ErrorValidationMinimum, - Text: reason, - Type: Error, - Context: context(nil), + ID: ErrorValidationMinimum, + Text: fmt.Sprintf("must be >= %v but found %v", minimum, actual), + Type: Error, + Context: context(map[string]any{ + "minimum": minimum, + "actual": actual, + }), } } -func NewErrorValidationExclusiveMinimum(reason string) *Message { +func NewErrorValidationExclusiveMinimum(minimum, actual float64) *Message { return &Message{ - ID: ErrorValidationExclusiveMinimum, - Text: reason, - Type: Error, - Context: context(nil), + ID: ErrorValidationExclusiveMinimum, + Text: fmt.Sprintf("must be > %v but found %v", minimum, actual), + Type: Error, + Context: context(map[string]any{ + "minimum": minimum, + "actual": actual, + }), } } -func NewErrorValidationMaximum(reason string) *Message { +func NewErrorValidationMaximum(maximum, actual float64) *Message { return &Message{ - ID: ErrorValidationMaximum, - Text: reason, - Type: Error, - Context: context(nil), + ID: ErrorValidationMaximum, + Text: fmt.Sprintf("must be <= %v but found %v", maximum, actual), + Type: Error, + Context: context(map[string]any{ + "maximum": maximum, + "actual": actual, + }), } } -func NewErrorValidationExclusiveMaximum(reason string) *Message { +func NewErrorValidationExclusiveMaximum(maximum, actual float64) *Message { return &Message{ - ID: ErrorValidationExclusiveMaximum, - Text: reason, - Type: Error, - Context: context(nil), + ID: ErrorValidationExclusiveMaximum, + Text: fmt.Sprintf("must be < %v but found %v", maximum, actual), + Type: Error, + Context: context(map[string]any{ + "maximum": maximum, + "actual": actual, + }), } } -func NewErrorValidationMultipleOf(reason string) *Message { +func NewErrorValidationMultipleOf(base, actual float64) *Message { return &Message{ - ID: ErrorValidationMultipleOf, - Text: reason, - Type: Error, - Context: context(nil), + ID: ErrorValidationMultipleOf, + Text: fmt.Sprintf("%v not multipleOf %v", actual, base), + Type: Error, + Context: context(map[string]any{ + "base": base, + "actual": actual, + }), } } -func NewErrorValidationMaxItems(reason string) *Message { +func NewErrorValidationMaxItems(maxItems, actualItems int) *Message { return &Message{ - ID: ErrorValidationMaxItems, - Text: reason, - Type: Error, - Context: context(nil), + ID: ErrorValidationMaxItems, + Text: fmt.Sprintf("maximum %d items allowed, but found %d items", maxItems, actualItems), + Type: Error, + Context: context(map[string]any{ + "max_items": maxItems, + "actual_items": actualItems, + }), } } -func NewErrorValidationMinItems(reason string) *Message { +func NewErrorValidationMinItems(minItems, actualItems int) *Message { return &Message{ - ID: ErrorValidationMinItems, - Text: reason, - Type: Error, - Context: context(nil), + ID: ErrorValidationMinItems, + Text: fmt.Sprintf("minimum %d items allowed, but found %d items", minItems, actualItems), + Type: Error, + Context: context(map[string]any{ + "min_items": minItems, + "actual_items": actualItems, + }), } } -func NewErrorValidationUniqueItems(reason string) *Message { +func NewErrorValidationUniqueItems(indexA, indexB int) *Message { return &Message{ - ID: ErrorValidationUniqueItems, - Text: reason, - Type: Error, - Context: context(nil), + ID: ErrorValidationUniqueItems, + Text: fmt.Sprintf("items at index %d and %d are equal", indexA, indexB), + Type: Error, + Context: context(map[string]any{ + "index_a": indexA, + "index_b": indexB, + }), } } -func NewErrorValidationWrongType(reason string) *Message { +func NewErrorValidationWrongType(allowedTypes []string, actualType string) *Message { return &Message{ - ID: ErrorValidationWrongType, - Text: reason, + ID: ErrorValidationWrongType, + Text: fmt.Sprintf("expected %s, but got %s", strings.Join(allowedTypes, " or "), actualType), + Type: Error, + Context: context(map[string]any{ + "allowed_types": allowedTypes, + "actual_type": actualType, + }), + } +} + +func NewErrorValidationConst(expected any) *Message { + return &Message{ + ID: ErrorValidationConst, + Text: fmt.Sprintf("must be equal to constant %v", expected), + Type: Error, + Context: context(map[string]any{ + "expected": expected, + }), + } +} + +func NewErrorValidationConstGeneric() *Message { + return &Message{ + ID: ErrorValidationConstGeneric, + Text: "const failed", Type: Error, Context: context(nil), } } -func NewErrorValidationPasswordPolicyViolation(reason string) *Message { +func NewErrorValidationPasswordPolicyViolationGeneric(reason string) *Message { return &Message{ - ID: ErrorValidationPasswordPolicyViolation, + ID: ErrorValidationPasswordPolicyViolationGeneric, Text: fmt.Sprintf("The password can not be used because %s.", reason), Type: Error, - Context: context(map[string]interface{}{ + Context: context(map[string]any{ "reason": reason, }), } } +func NewErrorValidationPasswordIdentifierTooSimilar() *Message { + return &Message{ + ID: ErrorValidationPasswordIdentifierTooSimilar, + Text: "The password can not be used because it is too similar to the identifier.", + Type: Error, + Context: context(nil), + } +} + +func NewErrorValidationPasswordMinLength(minLength, actualLength int) *Message { + return &Message{ + ID: ErrorValidationPasswordMinLength, + Text: fmt.Sprintf("The password must be at least %d characters long, but got %d.", minLength, actualLength), + Type: Error, + Context: context(map[string]any{ + "min_length": minLength, + "actual_length": actualLength, + }), + } +} + +func NewErrorValidationPasswordMaxLength(maxLength, actualLength int) *Message { + return &Message{ + ID: ErrorValidationPasswordMaxLength, + Text: fmt.Sprintf("The password must be at most %d characters long, but got %d.", maxLength, actualLength), + Type: Error, + Context: context(map[string]any{ + "max_length": maxLength, + "actual_length": actualLength, + }), + } +} + +func NewErrorValidationPasswordTooManyBreaches(breaches int64) *Message { + return &Message{ + ID: ErrorValidationPasswordTooManyBreaches, + Text: "The password has been found in data breaches and must no longer be used.", + Type: Error, + Context: context(map[string]any{ + "breaches": breaches, + }), + } +} + func NewErrorValidationInvalidCredentials() *Message { return &Message{ ID: ErrorValidationInvalidCredentials, @@ -169,7 +269,7 @@ func NewErrorValidationDuplicateCredentialsWithHints(reason string, availableCre ID: ErrorValidationDuplicateCredentialsWithHints, Text: reason, Type: Error, - Context: context(map[string]interface{}{ + Context: context(map[string]any{ "available_credential_types": availableCredentialTypes, "available_oidc_providers": availableOIDCProviders, "credential_identifier_hint": credentialIdentifierHint, @@ -215,17 +315,19 @@ func NewErrorValidationLookupInvalid() *Message { func NewErrorValidationIdentifierMissing() *Message { return &Message{ - ID: ErrorValidationIdentifierMissing, - Text: "Could not find any login identifiers. Did you forget to set them? This could also be caused by a server misconfiguration.", - Type: Error, + ID: ErrorValidationIdentifierMissing, + Text: "Could not find any login identifiers. Did you forget to set them? This could also be caused by a server misconfiguration.", + Type: Error, + Context: context(nil), } } func NewErrorValidationAddressNotVerified() *Message { return &Message{ - ID: ErrorValidationAddressNotVerified, - Text: "Account not active yet. Did you forget to verify your email address?", - Type: Error, + ID: ErrorValidationAddressNotVerified, + Text: "Account not active yet. Did you forget to verify your email address?", + Type: Error, + Context: context(nil), } } diff --git a/text/message_verification.go b/text/message_verification.go index 6719f7ee9436..fccec0b0d521 100644 --- a/text/message_verification.go +++ b/text/message_verification.go @@ -11,7 +11,7 @@ import ( func NewErrorValidationVerificationFlowExpired(expiredAt time.Time) *Message { return &Message{ ID: ErrorValidationVerificationFlowExpired, - Text: fmt.Sprintf("The verification flow expired %.2f minutes ago, please try again.", (-Until(expiredAt)).Minutes()), + Text: fmt.Sprintf("The verification flow expired %.2f minutes ago, please try again.", Since(expiredAt).Minutes()), Type: Error, Context: context(map[string]interface{}{ "expired_at": expiredAt, diff --git a/text/type.go b/text/type.go index 91a84add5b52..b6ea05b3e242 100644 --- a/text/type.go +++ b/text/type.go @@ -15,5 +15,5 @@ const ( Success UITextType = "success" ) -var Now = time.Now var Until = time.Until +var Since = time.Since diff --git a/ui/container/container.go b/ui/container/container.go index af74fa0f00ce..8c1b4a0b7a47 100644 --- a/ui/container/container.go +++ b/ui/container/container.go @@ -219,29 +219,58 @@ func translateValidationError(err *jsonschema.ValidationError) *text.Message { segments := strings.Split(err.SchemaPtr, "/") switch segments[len(segments)-1] { case "minLength": - return text.NewErrorValidationMinLength(err.Message) + minLength, actual := -1, -1 + _, _ = fmt.Sscanf(err.Message, "length must be >= %d, but got %d", &minLength, &actual) + return text.NewErrorValidationMinLength(minLength, actual) case "maxLength": - return text.NewErrorValidationMaxLength(err.Message) + maxLength, actual := -1, -1 + _, _ = fmt.Sscanf(err.Message, "length must be <= %d, but got %d", &maxLength, &actual) + return text.NewErrorValidationMaxLength(maxLength, actual) case "pattern": - return text.NewErrorValidationInvalidFormat(err.Message) + pattern := "" + _, _ = fmt.Sscanf(err.Message, "does not match pattern %q", &pattern) + return text.NewErrorValidationInvalidFormat(pattern) case "minimum": - return text.NewErrorValidationMinimum(err.Message) + minimum, actual := -1.0, -1.0 + _, _ = fmt.Sscanf(err.Message, "must be >= %v but found %v", &minimum, &actual) + return text.NewErrorValidationMinimum(minimum, actual) case "exclusiveMinimum": - return text.NewErrorValidationExclusiveMinimum(err.Message) + minimum, actual := -1.0, -1.0 + _, _ = fmt.Sscanf(err.Message, "must be > %v but found %v", &minimum, &actual) + return text.NewErrorValidationExclusiveMinimum(minimum, actual) case "maximum": - return text.NewErrorValidationMaximum(err.Message) + maximum, actual := -1.0, -1.0 + _, _ = fmt.Sscanf(err.Message, "must be <= %v but found %v", &maximum, &actual) + return text.NewErrorValidationMaximum(maximum, actual) case "exclusiveMaximum": - return text.NewErrorValidationExclusiveMaximum(err.Message) + maximum, actual := -1.0, -1.0 + _, _ = fmt.Sscanf(err.Message, "must be < %v but found %v", &maximum, &actual) + return text.NewErrorValidationExclusiveMaximum(maximum, actual) case "multipleOf": - return text.NewErrorValidationMultipleOf(err.Message) + base, actual := -1.0, -1.0 + _, _ = fmt.Sscanf(err.Message, "%v not multipleOf %v", &actual, &base) + return text.NewErrorValidationMultipleOf(base, actual) case "maxItems": - return text.NewErrorValidationMaxItems(err.Message) + maxItems, actual := -1, -1 + _, _ = fmt.Sscanf(err.Message, "maximum %d items allowed, but found %d items", &maxItems, &actual) + return text.NewErrorValidationMaxItems(maxItems, actual) case "minItems": - return text.NewErrorValidationMinItems(err.Message) + minItems, actual := -1, -1 + _, _ = fmt.Sscanf(err.Message, "minimum %d items allowed, but found %d items", &minItems, &actual) + return text.NewErrorValidationMinItems(minItems, actual) case "uniqueItems": - return text.NewErrorValidationUniqueItems(err.Message) + indexA, indexB := -1, -1 + _, _ = fmt.Sscanf(err.Message, "items at index %d and %d are equal", &indexA, &indexB) + return text.NewErrorValidationUniqueItems(indexA, indexB) case "type": - return text.NewErrorValidationWrongType(err.Message) + allowedTypes, actualType, _ := strings.Cut(strings.TrimPrefix(err.Message, "expected "), ", but got ") + return text.NewErrorValidationWrongType(strings.Split(allowedTypes, " or "), actualType) + case "const": + if err.Message != "const failed" { + expectedValue := strings.TrimPrefix(err.Message, "value must be ") + return text.NewErrorValidationConst(expectedValue) + } + return text.NewErrorValidationConstGeneric() default: return text.NewValidationErrorGeneric(err.Message) } From 80402beb109c8aef20cad7785d41175a86cb0379 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Mon, 28 Aug 2023 14:13:46 +0000 Subject: [PATCH 058/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87841af326da..f75b3b201d16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-08-22)](#2023-08-22) +- [ (2023-08-28)](#2023-08-28) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) - [Features](#features) @@ -309,7 +309,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-08-22) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-08-28) ### Bug Fixes @@ -347,6 +347,11 @@ - False-positives for requiring re-authentication on update ([#3421](https://github.com/ory/kratos/issues/3421)) ([ce8139f](https://github.com/ory/kratos/commit/ce8139f2325a8317388cbcaaa98f3f83d626657b)) +- Pass context ([#3452](https://github.com/ory/kratos/issues/3452)) + ([c492bdc](https://github.com/ory/kratos/commit/c492bdcd0c5dbdf527ae523d879a6c1eeb9c4cdf)) +- Properly normalize OIDC verified emails + ([#3450](https://github.com/ory/kratos/issues/3450)) + ([703b910](https://github.com/ory/kratos/commit/703b910927d879558bfeb0fd2c3339b1d301fac8)) - Redirect to verification URL even if login_challenge is set ([#3412](https://github.com/ory/kratos/issues/3412)) ([cd9e6a0](https://github.com/ory/kratos/commit/cd9e6a0e1e4cb4957d2a50ae3d288ebb0591e42d)): @@ -360,6 +365,9 @@ Significantly improves performance by reducing the amount of queries we need to do when checking for the different AAL levels. +- Registration with verification + ([#3451](https://github.com/ory/kratos/issues/3451)) + ([77c3196](https://github.com/ory/kratos/commit/77c3196fd60c5927b84e9a7f6546f80ac2d78ee5)) - Remove requirement for smtp section ([#3405](https://github.com/ory/kratos/issues/3405)) ([59a3f14](https://github.com/ory/kratos/commit/59a3f1469b8412e49846a500493cb02fc6eb34b1)) @@ -396,6 +404,9 @@ - Hot-reload CORS origins ([#3423](https://github.com/ory/kratos/issues/3423)) ([157d934](https://github.com/ory/kratos/commit/157d9345aeb04f371f9d85b70c89e8646e781333)) +- Improve messages for easier i18n + ([#3457](https://github.com/ory/kratos/issues/3457)) + ([37f1657](https://github.com/ory/kratos/commit/37f16577d92ba88869bf15fb1ea54e819b062724)) - Provide login hints when registration fails due to duplicate credentials/addresses ([#3430](https://github.com/ory/kratos/issues/3430)) ([8b28469](https://github.com/ory/kratos/commit/8b284697e4a26fb01ad57d2e9ebd8f714be49f33)): From eaaf37519917612671238412a633847386d7c613 Mon Sep 17 00:00:00 2001 From: Alano Terblanche <18033717+Benehiko@users.noreply.github.com> Date: Tue, 29 Aug 2023 15:43:03 +0200 Subject: [PATCH 059/282] feat: passwordless browser login and registration via code to email (#3378) This feature adds passwordless email code login. When a user signs up, or signs in, a code is sent to their email address which they can use to complete the authentication process. This feature is currently only working for browser facing APIs. Closes #2029 Closes ory-corp/cloud#3573 --- .schema/openapi/patches/identity.yaml | 3 +- .schema/openapi/patches/selfservice.yaml | 16 + Makefile | 8 +- cmd/clidoc/main.go | 18 +- courier/email_templates.go | 18 + courier/email_templates_test.go | 5 +- .../login_code/valid/email.body.gotmpl | 5 + .../valid/email.body.plaintext.gotmpl | 5 + .../login_code/valid/email.subject.gotmpl | 1 + .../registration_code/valid/email.body.gotmpl | 5 + .../valid/email.body.plaintext.gotmpl | 5 + .../valid/email.subject.gotmpl | 1 + courier/template/email/login_code_valid.go | 51 ++ .../template/email/login_code_valid_test.go | 30 + .../template/email/registration_code_valid.go | 51 ++ .../email/registration_code_valid_test.go | 30 + courier/template/template.go | 2 + courier/template/testhelpers/testhelpers.go | 7 +- coverage/.gitignore | 1 + driver/config/config.go | 51 +- driver/config/config_test.go | 17 +- driver/registry_default.go | 42 +- driver/registry_default_hooks.go | 7 + driver/registry_default_registration.go | 6 +- driver/registry_default_test.go | 27 +- embedx/config.schema.json | 87 ++- embedx/identity_extension.schema.json | 22 +- identity/credentials.go | 14 + identity/credentials_code.go | 26 + identity/extension_credentials.go | 28 +- identity/extension_credentials_test.go | 15 + .../extension/credentials/code.schema.json | 20 + internal/client-go/.openapi-generator/FILES | 10 + internal/client-go/README.md | 5 + .../model_identity_credentials_code.go | 162 ++++++ .../model_identity_credentials_otp.go | 162 ++++++ .../model_identity_credentials_type.go | 3 +- internal/client-go/model_login_flow.go | 34 +- internal/client-go/model_login_flow_state.go | 85 +++ internal/client-go/model_message.go | 2 +- internal/client-go/model_recovery_flow.go | 21 +- internal/client-go/model_registration_flow.go | 34 +- .../model_registration_flow_state.go | 85 +++ .../model_self_service_login_flow_state.go | 85 +++ .../model_self_service_recovery_flow_state.go | 13 +- ...el_self_service_registration_flow_state.go | 85 +++ .../model_self_service_settings_flow_state.go | 13 +- ...el_self_service_verification_flow_state.go | 13 +- internal/client-go/model_settings_flow.go | 21 +- .../client-go/model_update_login_flow_body.go | 30 + ...odel_update_login_flow_with_code_method.go | 249 +++++++++ .../model_update_registration_flow_body.go | 30 + ...date_registration_flow_with_code_method.go | 286 ++++++++++ internal/client-go/model_verification_flow.go | 21 +- internal/httpclient/.openapi-generator/FILES | 10 + internal/httpclient/README.md | 5 + .../model_identity_credentials_code.go | 162 ++++++ .../model_identity_credentials_type.go | 3 +- internal/httpclient/model_login_flow.go | 34 +- internal/httpclient/model_login_flow_state.go | 85 +++ internal/httpclient/model_message.go | 2 +- internal/httpclient/model_recovery_flow.go | 21 +- .../httpclient/model_registration_flow.go | 34 +- .../model_registration_flow_state.go | 85 +++ internal/httpclient/model_settings_flow.go | 21 +- .../model_update_login_flow_body.go | 30 + ...odel_update_login_flow_with_code_method.go | 249 +++++++++ .../model_update_registration_flow_body.go | 30 + ...date_registration_flow_with_code_method.go | 286 ++++++++++ .../httpclient/model_verification_flow.go | 21 +- internal/testhelpers/courier.go | 27 +- persistence/reference.go | 2 + .../28ff0031-190b-4253-bd15-14308dec013e.json | 17 + .../bd292366-af32-4ba6-bdf0-11d6d1a217f3.json | 6 + .../00b1517f-2467-4aaf-b0a5-82b4a27dcaf5.json | 18 + .../0bc96cc9-dda4-4700-9e42-35731f2af91e.json | 3 +- .../1fb23c75-b809-42cc-8984-6ca2d0a1192f.json | 3 +- .../202c1981-1e25-47f0-8764-75ad506c2bec.json | 3 +- .../349c945a-60f8-436a-a301-7a42c92604f9.json | 3 +- .../38caf592-b042-4551-b92f-8d5223c2a4e2.json | 3 +- .../3a9ea34f-0f12-469b-9417-3ae5795a7baa.json | 3 +- .../43c99182-bb67-47e1-b564-bb23bd8d4393.json | 3 +- .../47edd3a8-0998-4779-9469-f4b8ee4430df.json | 3 +- .../56d94e8b-8a5d-4b7f-8a6e-3259d2b2903e.json | 3 +- .../6d387820-f2f4-4f9f-9980-a90d89e7811f.json | 3 +- .../916ded11-aa64-4a27-b06e-96e221a509d7.json | 3 +- .../99974ce6-388c-4669-a95a-7757ee724020.json | 3 +- .../b1fac7fb-d016-4a06-a7fe-e4eab2a0429f.json | 3 +- .../cccccccc-dda4-4700-9e42-35731f2af911.json | 3 +- .../cccccccc-dda4-4700-9e42-35731f2af91e.json | 3 +- .../d6aa1f23-88c9-4b9b-a850-392f48c7f9e8.json | 3 +- .../f1f66a69-ce02-4a12-9591-9e02dda30a0d.json | 5 + .../05a7f09d-4ef3-41fb-958a-6ad74584b36a.json | 3 +- .../22d58184-b97d-44a5-bbaf-0aa8b4000d81.json | 3 +- .../2bf132e0-5d40-4df9-9a11-9106e5333735.json | 3 +- .../696e7022-c466-44f6-89c6-8cf93c06a62a.json | 3 +- .../69c80296-36cd-4afc-921a-15369cac5bf0.json | 14 + .../87fa3f43-5155-42b4-a1ad-174c2595fdaf.json | 3 +- .../8ef215a9-e8d5-43b3-9aa3-cb4333562e36.json | 3 +- .../8f32efdc-f6fc-4c27-a3c2-579d109eff60.json | 3 +- .../9edcf051-1cd0-44cc-bd2f-6ac21f0c24dd.json | 3 +- .../e2150cdc-23ac-4940-a240-6c79c27ab029.json | 3 +- .../ef18b06e-4700-4021-9949-ef783cd86be1.json | 3 +- .../ef18b06e-4700-4021-9949-ef783cd86be8.json | 3 +- .../f1b5ed18-113a-4a98-aae7-d4eba007199c.json | 3 +- persistence/sql/migratest/migration_test.go | 38 +- .../testdata/20230707133700_testdata.sql | 30 + .../testdata/20230707133701_testdata.sql | 23 + ...ce_registration_login_flows_state.down.sql | 2 + ...vice_registration_login_flows_state.up.sql | 2 + ...7133700000000_identity_login_code.down.sql | 3 + ...700000000_identity_login_code.mysql.up.sql | 29 + ...707133700000000_identity_login_code.up.sql | 28 + ...000001_identity_registration_code.down.sql | 3 + ...01_identity_registration_code.mysql.up.sql | 27 + ...00000001_identity_registration_code.up.sql | 27 + ...73852000000_credential_types_code.down.sql | 1 + ...2173852000000_credential_types_code.up.sql | 1 + persistence/sql/persister_code.go | 123 ++++ persistence/sql/persister_login.go | 1 - persistence/sql/persister_login_code.go | 69 +++ persistence/sql/persister_recovery.go | 151 +---- persistence/sql/persister_recovery_code.go | 84 +++ .../sql/persister_registration_code.go | 76 +++ persistence/sql/persister_verification.go | 154 ----- .../sql/persister_verification_code.go | 77 +++ schema/errors.go | 40 ++ schema/extension.go | 4 + selfservice/flow/error_test.go | 23 + selfservice/flow/flow.go | 3 + selfservice/flow/login/flow.go | 24 + selfservice/flow/login/hook.go | 1 - selfservice/flow/login/sort.go | 1 + selfservice/flow/login/state.go | 17 + selfservice/flow/name.go | 28 + selfservice/flow/recovery/flow.go | 18 +- selfservice/flow/recovery/flow_test.go | 2 +- selfservice/flow/recovery/handler.go | 5 +- selfservice/flow/recovery/state.go | 33 +- selfservice/flow/recovery/strategy.go | 2 +- selfservice/flow/recovery/test/persistence.go | 11 +- selfservice/flow/registration/flow.go | 23 + selfservice/flow/registration/sort.go | 1 + selfservice/flow/registration/state.go | 15 + selfservice/flow/request.go | 27 +- selfservice/flow/request_test.go | 73 ++- selfservice/flow/settings/flow.go | 16 +- selfservice/flow/settings/hook.go | 2 +- selfservice/flow/settings/state.go | 9 +- selfservice/flow/settings/test/persistence.go | 6 +- selfservice/flow/state.go | 100 ++++ selfservice/flow/{recovery => }/state_test.go | 2 +- selfservice/flow/verification/error.go | 4 +- .../flow/verification/fake_strategy.go | 6 + selfservice/flow/verification/flow.go | 18 +- selfservice/flow/verification/flow_test.go | 3 +- selfservice/flow/verification/handler.go | 4 +- selfservice/flow/verification/handler_test.go | 5 +- selfservice/flow/verification/state.go | 33 +- selfservice/flow/verification/state_test.go | 20 - selfservice/flow/verification/strategy.go | 2 +- .../flow/verification/test/persistence.go | 10 +- selfservice/hook/code_address_verifier.go | 53 ++ .../hook/code_address_verifier_test.go | 90 +++ selfservice/hook/stub/code.schema.json | 27 + selfservice/hook/verification.go | 8 +- selfservice/hook/verification_test.go | 5 +- .../strategy/code/.schema/login.schema.json | 32 ++ .../code/.schema/registration.schema.json | 32 ++ ...erification_payloads_after_submission.json | 26 +- selfservice/strategy/code/code_login.go | 114 ++++ selfservice/strategy/code/code_login_test.go | 81 +++ selfservice/strategy/code/code_recovery.go | 25 +- .../strategy/code/code_recovery_test.go | 28 +- .../strategy/code/code_registration.go | 109 ++++ .../strategy/code/code_registration_test.go | 80 +++ selfservice/strategy/code/code_sender.go | 98 ++++ selfservice/strategy/code/code_sender_test.go | 4 - ...ification_code.go => code_verification.go} | 11 + .../strategy/code/code_verification_test.go | 81 +++ selfservice/strategy/code/persistence.go | 22 + selfservice/strategy/code/schema.go | 6 + selfservice/strategy/code/strategy.go | 260 ++++++++- selfservice/strategy/code/strategy_login.go | 279 ++++++++++ .../strategy/code/strategy_login_test.go | 456 +++++++++++++++ .../strategy/code/strategy_recovery.go | 58 +- .../strategy/code/strategy_recovery_test.go | 22 +- .../strategy/code/strategy_registration.go | 284 ++++++++++ .../code/strategy_registration_test.go | 526 ++++++++++++++++++ .../strategy/code/strategy_verification.go | 49 +- .../code/strategy_verification_test.go | 59 +- .../code/stub/code.identity.schema.json | 61 ++ selfservice/strategy/code/test/persistence.go | 8 +- selfservice/strategy/link/strategy.go | 22 +- .../strategy/link/strategy_recovery.go | 20 +- .../strategy/link/strategy_recovery_test.go | 65 +-- .../strategy/link/strategy_verification.go | 18 +- .../link/strategy_verification_test.go | 46 +- selfservice/strategy/link/test/persistence.go | 8 +- selfservice/strategy/lookup/login.go | 2 +- selfservice/strategy/lookup/settings.go | 4 +- selfservice/strategy/lookup/settings_test.go | 18 +- selfservice/strategy/oidc/strategy.go | 3 + selfservice/strategy/oidc/strategy_login.go | 4 +- .../strategy/oidc/strategy_registration.go | 4 +- .../strategy/oidc/strategy_settings_test.go | 98 ++-- selfservice/strategy/password/login.go | 2 +- selfservice/strategy/password/registration.go | 2 +- .../strategy/password/registration_test.go | 2 +- selfservice/strategy/password/settings.go | 4 +- selfservice/strategy/password/strategy.go | 8 +- selfservice/strategy/profile/strategy.go | 4 +- selfservice/strategy/profile/strategy_test.go | 51 +- selfservice/strategy/totp/login.go | 2 +- selfservice/strategy/totp/settings.go | 6 +- selfservice/strategy/totp/settings_test.go | 18 +- ...ebauthn_login_is_invalid-type=browser.json | 3 +- ...if_webauthn_login_is_invalid-type=spa.json | 3 +- selfservice/strategy/webauthn/login.go | 2 +- selfservice/strategy/webauthn/registration.go | 2 +- selfservice/strategy/webauthn/settings.go | 4 +- .../strategy/webauthn/settings_test.go | 10 +- spec/api.json | 146 ++++- spec/swagger.json | 130 ++++- test/e2e/.go-version | 1 + .../profiles/code/login/error.spec.ts | 176 ++++++ .../profiles/code/login/success.spec.ts | 164 ++++++ .../profiles/code/registration/error.spec.ts | 144 +++++ .../code/registration/success.spec.ts | 241 ++++++++ test/e2e/cypress/support/commands.ts | 189 ++++++- test/e2e/cypress/support/config.d.ts | 130 +++-- test/e2e/cypress/support/index.d.ts | 59 +- test/e2e/profiles/code/.kratos.yml | 48 ++ .../identity.code.only.traits.schema.json | 31 ++ .../code/identity.complex.traits.schema.json | 77 +++ .../profiles/code/identity.traits.schema.json | 39 ++ test/e2e/run.sh | 4 +- text/id.go | 40 +- text/message_login.go | 35 ++ text/message_node.go | 16 + text/message_registration.go | 35 ++ text/message_validation.go | 18 + ui/container/container.go | 3 +- x/xsql/sql.go | 2 + 244 files changed, 8950 insertions(+), 1071 deletions(-) create mode 100644 courier/template/courier/builtin/templates/login_code/valid/email.body.gotmpl create mode 100644 courier/template/courier/builtin/templates/login_code/valid/email.body.plaintext.gotmpl create mode 100644 courier/template/courier/builtin/templates/login_code/valid/email.subject.gotmpl create mode 100644 courier/template/courier/builtin/templates/registration_code/valid/email.body.gotmpl create mode 100644 courier/template/courier/builtin/templates/registration_code/valid/email.body.plaintext.gotmpl create mode 100644 courier/template/courier/builtin/templates/registration_code/valid/email.subject.gotmpl create mode 100644 courier/template/email/login_code_valid.go create mode 100644 courier/template/email/login_code_valid_test.go create mode 100644 courier/template/email/registration_code_valid.go create mode 100644 courier/template/email/registration_code_valid_test.go create mode 100644 coverage/.gitignore create mode 100644 identity/credentials_code.go create mode 100644 identity/stub/extension/credentials/code.schema.json create mode 100644 internal/client-go/model_identity_credentials_code.go create mode 100644 internal/client-go/model_identity_credentials_otp.go create mode 100644 internal/client-go/model_login_flow_state.go create mode 100644 internal/client-go/model_registration_flow_state.go create mode 100644 internal/client-go/model_self_service_login_flow_state.go create mode 100644 internal/client-go/model_self_service_registration_flow_state.go create mode 100644 internal/client-go/model_update_login_flow_with_code_method.go create mode 100644 internal/client-go/model_update_registration_flow_with_code_method.go create mode 100644 internal/httpclient/model_identity_credentials_code.go create mode 100644 internal/httpclient/model_login_flow_state.go create mode 100644 internal/httpclient/model_registration_flow_state.go create mode 100644 internal/httpclient/model_update_login_flow_with_code_method.go create mode 100644 internal/httpclient/model_update_registration_flow_with_code_method.go create mode 100644 persistence/sql/migratest/fixtures/identity/28ff0031-190b-4253-bd15-14308dec013e.json create mode 100644 persistence/sql/migratest/fixtures/login_code/bd292366-af32-4ba6-bdf0-11d6d1a217f3.json create mode 100644 persistence/sql/migratest/fixtures/login_flow/00b1517f-2467-4aaf-b0a5-82b4a27dcaf5.json create mode 100644 persistence/sql/migratest/fixtures/registration_code/f1f66a69-ce02-4a12-9591-9e02dda30a0d.json create mode 100644 persistence/sql/migratest/fixtures/registration_flow/69c80296-36cd-4afc-921a-15369cac5bf0.json create mode 100644 persistence/sql/migratest/testdata/20230707133700_testdata.sql create mode 100644 persistence/sql/migratest/testdata/20230707133701_testdata.sql create mode 100644 persistence/sql/migrations/sql/20230703143600000001_selfservice_registration_login_flows_state.down.sql create mode 100644 persistence/sql/migrations/sql/20230703143600000001_selfservice_registration_login_flows_state.up.sql create mode 100644 persistence/sql/migrations/sql/20230707133700000000_identity_login_code.down.sql create mode 100644 persistence/sql/migrations/sql/20230707133700000000_identity_login_code.mysql.up.sql create mode 100644 persistence/sql/migrations/sql/20230707133700000000_identity_login_code.up.sql create mode 100644 persistence/sql/migrations/sql/20230707133700000001_identity_registration_code.down.sql create mode 100644 persistence/sql/migrations/sql/20230707133700000001_identity_registration_code.mysql.up.sql create mode 100644 persistence/sql/migrations/sql/20230707133700000001_identity_registration_code.up.sql create mode 100644 persistence/sql/migrations/sql/20230712173852000000_credential_types_code.down.sql create mode 100644 persistence/sql/migrations/sql/20230712173852000000_credential_types_code.up.sql create mode 100644 persistence/sql/persister_code.go create mode 100644 persistence/sql/persister_login_code.go create mode 100644 persistence/sql/persister_recovery_code.go create mode 100644 persistence/sql/persister_registration_code.go create mode 100644 persistence/sql/persister_verification_code.go create mode 100644 selfservice/flow/login/state.go create mode 100644 selfservice/flow/name.go create mode 100644 selfservice/flow/registration/state.go create mode 100644 selfservice/flow/state.go rename selfservice/flow/{recovery => }/state_test.go (97%) delete mode 100644 selfservice/flow/verification/state_test.go create mode 100644 selfservice/hook/code_address_verifier.go create mode 100644 selfservice/hook/code_address_verifier_test.go create mode 100644 selfservice/hook/stub/code.schema.json create mode 100644 selfservice/strategy/code/.schema/login.schema.json create mode 100644 selfservice/strategy/code/.schema/registration.schema.json create mode 100644 selfservice/strategy/code/code_login.go create mode 100644 selfservice/strategy/code/code_login_test.go create mode 100644 selfservice/strategy/code/code_registration.go create mode 100644 selfservice/strategy/code/code_registration_test.go rename selfservice/strategy/code/{verification_code.go => code_verification.go} (93%) create mode 100644 selfservice/strategy/code/code_verification_test.go create mode 100644 selfservice/strategy/code/strategy_login.go create mode 100644 selfservice/strategy/code/strategy_login_test.go create mode 100644 selfservice/strategy/code/strategy_registration.go create mode 100644 selfservice/strategy/code/strategy_registration_test.go create mode 100644 selfservice/strategy/code/stub/code.identity.schema.json mode change 100755 => 100644 spec/api.json create mode 100644 test/e2e/.go-version create mode 100644 test/e2e/cypress/integration/profiles/code/login/error.spec.ts create mode 100644 test/e2e/cypress/integration/profiles/code/login/success.spec.ts create mode 100644 test/e2e/cypress/integration/profiles/code/registration/error.spec.ts create mode 100644 test/e2e/cypress/integration/profiles/code/registration/success.spec.ts create mode 100644 test/e2e/profiles/code/.kratos.yml create mode 100644 test/e2e/profiles/code/identity.code.only.traits.schema.json create mode 100644 test/e2e/profiles/code/identity.complex.traits.schema.json create mode 100644 test/e2e/profiles/code/identity.traits.schema.json diff --git a/.schema/openapi/patches/identity.yaml b/.schema/openapi/patches/identity.yaml index a227523488cf..c5f5ede63c58 100644 --- a/.schema/openapi/patches/identity.yaml +++ b/.schema/openapi/patches/identity.yaml @@ -11,6 +11,7 @@ - oidc - webauthn - lookup_secret + - code - op: add path: /paths/~1admin~1identities~1{id}/get/parameters/1/schema/items/enum value: @@ -19,6 +20,7 @@ - oidc - webauthn - lookup_secret + - code - op: remove path: /components/schemas/updateIdentityBody/properties/metadata_admin/type - op: remove @@ -32,4 +34,3 @@ - op: add path: /components/schemas/nullJsonRawMessage/nullable value: true - diff --git a/.schema/openapi/patches/selfservice.yaml b/.schema/openapi/patches/selfservice.yaml index aba0dde128b0..a966cf27401e 100644 --- a/.schema/openapi/patches/selfservice.yaml +++ b/.schema/openapi/patches/selfservice.yaml @@ -17,6 +17,7 @@ - "$ref": "#/components/schemas/updateRegistrationFlowWithPasswordMethod" - "$ref": "#/components/schemas/updateRegistrationFlowWithOidcMethod" - "$ref": "#/components/schemas/updateRegistrationFlowWithWebAuthnMethod" + - "$ref": "#/components/schemas/updateRegistrationFlowWithCodeMethod" - op: add path: /components/schemas/updateRegistrationFlowBody/discriminator value: @@ -25,6 +26,13 @@ password: "#/components/schemas/updateRegistrationFlowWithPasswordMethod" oidc: "#/components/schemas/updateRegistrationFlowWithOidcMethod" webauthn: "#/components/schemas/updateRegistrationFlowWithWebAuthnMethod" + code: "#/components/schemas/updateRegistrationFlowWithCodeMethod" +- op: add + path: /components/schemas/registrationFlowState/enum + value: + - choose_method + - sent_email + - passed_challenge # end # All modifications for the login flow @@ -38,6 +46,7 @@ - "$ref": "#/components/schemas/updateLoginFlowWithTotpMethod" - "$ref": "#/components/schemas/updateLoginFlowWithWebAuthnMethod" - "$ref": "#/components/schemas/updateLoginFlowWithLookupSecretMethod" + - "$ref": "#/components/schemas/updateLoginFlowWithCodeMethod" - op: add path: /components/schemas/updateLoginFlowBody/discriminator value: @@ -48,6 +57,13 @@ totp: "#/components/schemas/updateLoginFlowWithTotpMethod" webauthn: "#/components/schemas/updateLoginFlowWithWebAuthnMethod" lookup_secret: "#/components/schemas/updateLoginFlowWithLookupSecretMethod" + code: "#/components/schemas/updateLoginFlowWithCodeMethod" +- op: add + path: /components/schemas/loginFlowState/enum + value: + - choose_method + - sent_email + - passed_challenge # end # All modifications for the recovery flow diff --git a/Makefile b/Makefile index d1eb8fae5ef1..854832f11cb6 100644 --- a/Makefile +++ b/Makefile @@ -83,7 +83,13 @@ test-short: .PHONY: test-coverage test-coverage: .bin/go-acc .bin/goveralls - go-acc -o coverage.out ./... -- -v -failfast -timeout=20m -tags sqlite + go-acc -o coverage.out ./... -- -failfast -timeout=20m -tags sqlite,json1 + +.PHONY: test-coverage-next +test-coverage-next: .bin/go-acc .bin/goveralls + go test -short -failfast -timeout=20m -tags sqlite,json1 -cover ./... --args test.gocoverdir="$$PWD/coverage" + go tool covdata percent -i=coverage + go tool covdata textfmt -i=./coverage -o coverage.new.out # Generates the SDK .PHONY: sdk diff --git a/cmd/clidoc/main.go b/cmd/clidoc/main.go index d3775d1eafb1..afdad6fcd3fe 100644 --- a/cmd/clidoc/main.go +++ b/cmd/clidoc/main.go @@ -27,8 +27,10 @@ import ( "github.com/ory/x/clidoc" ) -var aSecondAgo = time.Date(2020, 1, 1, 1, 0, 0, 0, time.UTC).Add(-time.Second) -var inAMinute = time.Date(2020, 1, 1, 1, 0, 0, 0, time.UTC).Add(time.Minute) +var ( + aSecondAgo = time.Date(2020, 1, 1, 1, 0, 0, 0, time.UTC).Add(-time.Second) + inAMinute = time.Date(2020, 1, 1, 1, 0, 0, 0, time.UTC).Add(time.Minute) +) var messages map[string]*text.Message @@ -151,6 +153,18 @@ func init() { "NewInfoSelfServiceContinueLoginWebAuthn": text.NewInfoSelfServiceContinueLoginWebAuthn(), "NewInfoSelfServiceLoginContinue": text.NewInfoSelfServiceLoginContinue(), "NewErrorValidationSuchNoWebAuthnUser": text.NewErrorValidationSuchNoWebAuthnUser(), + "NewRegistrationEmailWithCodeSent": text.NewRegistrationEmailWithCodeSent(), + "NewLoginEmailWithCodeSent": text.NewLoginEmailWithCodeSent(), + "NewErrorValidationRegistrationCodeInvalidOrAlreadyUsed": text.NewErrorValidationRegistrationCodeInvalidOrAlreadyUsed(), + "NewErrorValidationLoginCodeInvalidOrAlreadyUsed": text.NewErrorValidationLoginCodeInvalidOrAlreadyUsed(), + "NewErrorValidationNoCodeUser": text.NewErrorValidationNoCodeUser(), + "NewInfoNodeLabelRegistrationCode": text.NewInfoNodeLabelRegistrationCode(), + "NewInfoNodeLabelLoginCode": text.NewInfoNodeLabelLoginCode(), + "NewErrorValidationLoginRetrySuccessful": text.NewErrorValidationLoginRetrySuccessful(), + "NewErrorValidationTraitsMismatch": text.NewErrorValidationTraitsMismatch(), + "NewInfoSelfServiceLoginCode": text.NewInfoSelfServiceLoginCode(), + "NewErrorValidationRegistrationRetrySuccessful": text.NewErrorValidationRegistrationRetrySuccessful(), + "NewInfoSelfServiceRegistrationRegisterCode": text.NewInfoSelfServiceRegistrationRegisterCode(), } } diff --git a/courier/email_templates.go b/courier/email_templates.go index 8d5d51f0ceaa..d2bae0a197e4 100644 --- a/courier/email_templates.go +++ b/courier/email_templates.go @@ -40,6 +40,8 @@ const ( TypeVerificationCodeValid TemplateType = "verification_code_valid" TypeOTP TemplateType = "otp" TypeTestStub TemplateType = "stub" + TypeLoginCodeValid TemplateType = "login_code_valid" + TypeRegistrationCodeValid TemplateType = "registration_code_valid" ) func GetEmailTemplateType(t EmailTemplate) (TemplateType, error) { @@ -60,6 +62,10 @@ func GetEmailTemplateType(t EmailTemplate) (TemplateType, error) { return TypeVerificationCodeInvalid, nil case *email.VerificationCodeValid: return TypeVerificationCodeValid, nil + case *email.LoginCodeValid: + return TypeLoginCodeValid, nil + case *email.RegistrationCodeValid: + return TypeRegistrationCodeValid, nil case *email.TestStub: return TypeTestStub, nil default: @@ -123,6 +129,18 @@ func NewEmailTemplateFromMessage(d template.Dependencies, msg Message) (EmailTem return nil, err } return email.NewTestStub(d, &t), nil + case TypeLoginCodeValid: + var t email.LoginCodeValidModel + if err := json.Unmarshal(msg.TemplateData, &t); err != nil { + return nil, err + } + return email.NewLoginCodeValid(d, &t), nil + case TypeRegistrationCodeValid: + var t email.RegistrationCodeValidModel + if err := json.Unmarshal(msg.TemplateData, &t); err != nil { + return nil, err + } + return email.NewRegistrationCodeValid(d, &t), nil default: return nil, errors.Errorf("received unexpected message template type: %s", msg.TemplateType) } diff --git a/courier/email_templates_test.go b/courier/email_templates_test.go index 2e8f8520bb7f..40afb5dc6863 100644 --- a/courier/email_templates_test.go +++ b/courier/email_templates_test.go @@ -27,6 +27,8 @@ func TestGetTemplateType(t *testing.T) { courier.TypeVerificationCodeInvalid: &email.VerificationCodeInvalid{}, courier.TypeVerificationCodeValid: &email.VerificationCodeValid{}, courier.TypeTestStub: &email.TestStub{}, + courier.TypeLoginCodeValid: &email.LoginCodeValid{}, + courier.TypeRegistrationCodeValid: &email.RegistrationCodeValid{}, } { t.Run(fmt.Sprintf("case=%s", expectedType), func(t *testing.T) { actualType, err := courier.GetEmailTemplateType(tmpl) @@ -50,6 +52,8 @@ func TestNewEmailTemplateFromMessage(t *testing.T) { courier.TypeVerificationCodeInvalid: email.NewVerificationCodeInvalid(reg, &email.VerificationCodeInvalidModel{To: "baz"}), courier.TypeVerificationCodeValid: email.NewVerificationCodeValid(reg, &email.VerificationCodeValidModel{To: "faz", VerificationURL: "http://bar.foo", VerificationCode: "123456678"}), courier.TypeTestStub: email.NewTestStub(reg, &email.TestStubModel{To: "far", Subject: "test subject", Body: "test body"}), + courier.TypeLoginCodeValid: email.NewLoginCodeValid(reg, &email.LoginCodeValidModel{To: "far", LoginCode: "123456"}), + courier.TypeRegistrationCodeValid: email.NewRegistrationCodeValid(reg, &email.RegistrationCodeValidModel{To: "far", RegistrationCode: "123456"}), } { t.Run(fmt.Sprintf("case=%s", tmplType), func(t *testing.T) { tmplData, err := json.Marshal(expectedTmpl) @@ -84,7 +88,6 @@ func TestNewEmailTemplateFromMessage(t *testing.T) { actualBodyPlaintext, err := actualTmpl.EmailBodyPlaintext(ctx) require.NoError(t, err) require.Equal(t, expectedBodyPlaintext, actualBodyPlaintext) - }) } } diff --git a/courier/template/courier/builtin/templates/login_code/valid/email.body.gotmpl b/courier/template/courier/builtin/templates/login_code/valid/email.body.gotmpl new file mode 100644 index 000000000000..505684b9849b --- /dev/null +++ b/courier/template/courier/builtin/templates/login_code/valid/email.body.gotmpl @@ -0,0 +1,5 @@ +Hi, + +please login to your account by entering the following code: + +{{ .LoginCode }} diff --git a/courier/template/courier/builtin/templates/login_code/valid/email.body.plaintext.gotmpl b/courier/template/courier/builtin/templates/login_code/valid/email.body.plaintext.gotmpl new file mode 100644 index 000000000000..505684b9849b --- /dev/null +++ b/courier/template/courier/builtin/templates/login_code/valid/email.body.plaintext.gotmpl @@ -0,0 +1,5 @@ +Hi, + +please login to your account by entering the following code: + +{{ .LoginCode }} diff --git a/courier/template/courier/builtin/templates/login_code/valid/email.subject.gotmpl b/courier/template/courier/builtin/templates/login_code/valid/email.subject.gotmpl new file mode 100644 index 000000000000..19d7bfd57d49 --- /dev/null +++ b/courier/template/courier/builtin/templates/login_code/valid/email.subject.gotmpl @@ -0,0 +1 @@ +Login to your account diff --git a/courier/template/courier/builtin/templates/registration_code/valid/email.body.gotmpl b/courier/template/courier/builtin/templates/registration_code/valid/email.body.gotmpl new file mode 100644 index 000000000000..6b9c31799995 --- /dev/null +++ b/courier/template/courier/builtin/templates/registration_code/valid/email.body.gotmpl @@ -0,0 +1,5 @@ +Hi, + +please complete your account registration by entering the following code: + +{{ .RegistrationCode }} diff --git a/courier/template/courier/builtin/templates/registration_code/valid/email.body.plaintext.gotmpl b/courier/template/courier/builtin/templates/registration_code/valid/email.body.plaintext.gotmpl new file mode 100644 index 000000000000..6b9c31799995 --- /dev/null +++ b/courier/template/courier/builtin/templates/registration_code/valid/email.body.plaintext.gotmpl @@ -0,0 +1,5 @@ +Hi, + +please complete your account registration by entering the following code: + +{{ .RegistrationCode }} diff --git a/courier/template/courier/builtin/templates/registration_code/valid/email.subject.gotmpl b/courier/template/courier/builtin/templates/registration_code/valid/email.subject.gotmpl new file mode 100644 index 000000000000..0f36292619ef --- /dev/null +++ b/courier/template/courier/builtin/templates/registration_code/valid/email.subject.gotmpl @@ -0,0 +1 @@ +Complete your account registration diff --git a/courier/template/email/login_code_valid.go b/courier/template/email/login_code_valid.go new file mode 100644 index 000000000000..2debc3a0cb7c --- /dev/null +++ b/courier/template/email/login_code_valid.go @@ -0,0 +1,51 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package email + +import ( + "context" + "encoding/json" + "os" + "strings" + + "github.com/ory/kratos/courier/template" +) + +type ( + LoginCodeValid struct { + deps template.Dependencies + model *LoginCodeValidModel + } + LoginCodeValidModel struct { + To string + LoginCode string + Identity map[string]interface{} + } +) + +func NewLoginCodeValid(d template.Dependencies, m *LoginCodeValidModel) *LoginCodeValid { + return &LoginCodeValid{deps: d, model: m} +} + +func (t *LoginCodeValid) EmailRecipient() (string, error) { + return t.model.To, nil +} + +func (t *LoginCodeValid) EmailSubject(ctx context.Context) (string, error) { + subject, err := template.LoadText(ctx, t.deps, os.DirFS(t.deps.CourierConfig().CourierTemplatesRoot(ctx)), "login_code/valid/email.subject.gotmpl", "login_code/valid/email.subject*", t.model, t.deps.CourierConfig().CourierTemplatesLoginCodeValid(ctx).Subject) + + return strings.TrimSpace(subject), err +} + +func (t *LoginCodeValid) EmailBody(ctx context.Context) (string, error) { + return template.LoadHTML(ctx, t.deps, os.DirFS(t.deps.CourierConfig().CourierTemplatesRoot(ctx)), "login_code/valid/email.body.gotmpl", "login_code/valid/email.body*", t.model, t.deps.CourierConfig().CourierTemplatesLoginCodeValid(ctx).Body.HTML) +} + +func (t *LoginCodeValid) EmailBodyPlaintext(ctx context.Context) (string, error) { + return template.LoadText(ctx, t.deps, os.DirFS(t.deps.CourierConfig().CourierTemplatesRoot(ctx)), "login_code/valid/email.body.plaintext.gotmpl", "login_code/valid/email.body.plaintext*", t.model, t.deps.CourierConfig().CourierTemplatesLoginCodeValid(ctx).Body.PlainText) +} + +func (t *LoginCodeValid) MarshalJSON() ([]byte, error) { + return json.Marshal(t.model) +} diff --git a/courier/template/email/login_code_valid_test.go b/courier/template/email/login_code_valid_test.go new file mode 100644 index 000000000000..dca97defe08c --- /dev/null +++ b/courier/template/email/login_code_valid_test.go @@ -0,0 +1,30 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package email_test + +import ( + "context" + "testing" + + "github.com/ory/kratos/courier" + "github.com/ory/kratos/courier/template/email" + "github.com/ory/kratos/courier/template/testhelpers" + "github.com/ory/kratos/internal" +) + +func TestLoginCodeValid(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + + t.Run("test=with courier templates directory", func(t *testing.T) { + _, reg := internal.NewFastRegistryWithMocks(t) + tpl := email.NewLoginCodeValid(reg, &email.LoginCodeValidModel{}) + + testhelpers.TestRendered(t, ctx, tpl) + }) + + t.Run("test=with remote resources", func(t *testing.T) { + testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/login_code/valid", courier.TypeLoginCodeValid) + }) +} diff --git a/courier/template/email/registration_code_valid.go b/courier/template/email/registration_code_valid.go new file mode 100644 index 000000000000..f7e39e334976 --- /dev/null +++ b/courier/template/email/registration_code_valid.go @@ -0,0 +1,51 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package email + +import ( + "context" + "encoding/json" + "os" + "strings" + + "github.com/ory/kratos/courier/template" +) + +type ( + RegistrationCodeValid struct { + deps template.Dependencies + model *RegistrationCodeValidModel + } + RegistrationCodeValidModel struct { + To string + Traits map[string]interface{} + RegistrationCode string + } +) + +func NewRegistrationCodeValid(d template.Dependencies, m *RegistrationCodeValidModel) *RegistrationCodeValid { + return &RegistrationCodeValid{deps: d, model: m} +} + +func (t *RegistrationCodeValid) EmailRecipient() (string, error) { + return t.model.To, nil +} + +func (t *RegistrationCodeValid) EmailSubject(ctx context.Context) (string, error) { + subject, err := template.LoadText(ctx, t.deps, os.DirFS(t.deps.CourierConfig().CourierTemplatesRoot(ctx)), "registration_code/valid/email.subject.gotmpl", "registration_code/valid/email.subject*", t.model, t.deps.CourierConfig().CourierTemplatesRegistrationCodeValid(ctx).Subject) + + return strings.TrimSpace(subject), err +} + +func (t *RegistrationCodeValid) EmailBody(ctx context.Context) (string, error) { + return template.LoadHTML(ctx, t.deps, os.DirFS(t.deps.CourierConfig().CourierTemplatesRoot(ctx)), "registration_code/valid/email.body.gotmpl", "registration_code/valid/email.body*", t.model, t.deps.CourierConfig().CourierTemplatesRegistrationCodeValid(ctx).Body.HTML) +} + +func (t *RegistrationCodeValid) EmailBodyPlaintext(ctx context.Context) (string, error) { + return template.LoadText(ctx, t.deps, os.DirFS(t.deps.CourierConfig().CourierTemplatesRoot(ctx)), "registration_code/valid/email.body.plaintext.gotmpl", "registration_code/valid/email.body.plaintext*", t.model, t.deps.CourierConfig().CourierTemplatesRegistrationCodeValid(ctx).Body.PlainText) +} + +func (t *RegistrationCodeValid) MarshalJSON() ([]byte, error) { + return json.Marshal(t.model) +} diff --git a/courier/template/email/registration_code_valid_test.go b/courier/template/email/registration_code_valid_test.go new file mode 100644 index 000000000000..be4cfe8059ea --- /dev/null +++ b/courier/template/email/registration_code_valid_test.go @@ -0,0 +1,30 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package email_test + +import ( + "context" + "testing" + + "github.com/ory/kratos/courier" + "github.com/ory/kratos/courier/template/email" + "github.com/ory/kratos/courier/template/testhelpers" + "github.com/ory/kratos/internal" +) + +func TestRegistrationCodeValid(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + + t.Run("test=with courier templates directory", func(t *testing.T) { + _, reg := internal.NewFastRegistryWithMocks(t) + tpl := email.NewRegistrationCodeValid(reg, &email.RegistrationCodeValidModel{}) + + testhelpers.TestRendered(t, ctx, tpl) + }) + + t.Run("test=with remote resources", func(t *testing.T) { + testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/registration_code/valid", courier.TypeRegistrationCodeValid) + }) +} diff --git a/courier/template/template.go b/courier/template/template.go index 3ee99428aa5b..483c40bd2f5e 100644 --- a/courier/template/template.go +++ b/courier/template/template.go @@ -19,6 +19,8 @@ type ( CourierTemplatesVerificationValid() *config.CourierEmailTemplate CourierTemplatesRecoveryInvalid() *config.CourierEmailTemplate CourierTemplatesRecoveryValid() *config.CourierEmailTemplate + CourierTemplatesLoginValid() *config.CourierEmailTemplate + CourierTemplatesRegistrationValid() *config.CourierEmailTemplate } Dependencies interface { diff --git a/courier/template/testhelpers/testhelpers.go b/courier/template/testhelpers/testhelpers.go index 936eedb0a65e..6c2923dbe416 100644 --- a/courier/template/testhelpers/testhelpers.go +++ b/courier/template/testhelpers/testhelpers.go @@ -40,7 +40,8 @@ func SetupRemoteConfig(t *testing.T, ctx context.Context, plaintext string, html func TestRendered(t *testing.T, ctx context.Context, tpl interface { EmailBody(context.Context) (string, error) EmailSubject(context.Context) (string, error) -}) { +}, +) { rendered, err := tpl.EmailBody(ctx) require.NoError(t, err) assert.NotEmpty(t, rendered) @@ -83,6 +84,10 @@ func TestRemoteTemplates(t *testing.T, basePath string, tmplType courier.Templat return email.NewVerificationCodeInvalid(d, &email.VerificationCodeInvalidModel{}) case courier.TypeVerificationCodeValid: return email.NewVerificationCodeValid(d, &email.VerificationCodeValidModel{}) + case courier.TypeLoginCodeValid: + return email.NewLoginCodeValid(d, &email.LoginCodeValidModel{}) + case courier.TypeRegistrationCodeValid: + return email.NewRegistrationCodeValid(d, &email.RegistrationCodeValidModel{}) default: return nil } diff --git a/coverage/.gitignore b/coverage/.gitignore new file mode 100644 index 000000000000..72e8ffc0db8a --- /dev/null +++ b/coverage/.gitignore @@ -0,0 +1 @@ +* diff --git a/driver/config/config.go b/driver/config/config.go index 1a0b76c6eb90..c0614d636894 100644 --- a/driver/config/config.go +++ b/driver/config/config.go @@ -68,6 +68,8 @@ const ( ViperKeyCourierTemplatesVerificationCodeValidEmail = "courier.templates.verification_code.valid.email" ViperKeyCourierDeliveryStrategy = "courier.delivery_strategy" ViperKeyCourierHTTPRequestConfig = "courier.http.request_config" + ViperKeyCourierTemplatesLoginCodeValidEmail = "courier.templates.login_code.valid.email" + ViperKeyCourierTemplatesRegistrationCodeValidEmail = "courier.templates.registration_code.valid.email" ViperKeyCourierSMTPFrom = "courier.smtp.from_address" ViperKeyCourierSMTPFromName = "courier.smtp.from_name" ViperKeyCourierSMTPHeaders = "courier.smtp.headers" @@ -226,6 +228,10 @@ type ( Enabled bool `json:"enabled"` Config json.RawMessage `json:"config"` } + SelfServiceStrategyCode struct { + *SelfServiceStrategy + PasswordlessEnabled bool `json:"passwordless_enabled"` + } Schema struct { ID string `json:"id" koanf:"id"` URL string `json:"url" koanf:"url"` @@ -279,6 +285,8 @@ type ( CourierTemplatesRecoveryCodeValid(ctx context.Context) *CourierEmailTemplate CourierTemplatesVerificationCodeInvalid(ctx context.Context) *CourierEmailTemplate CourierTemplatesVerificationCodeValid(ctx context.Context) *CourierEmailTemplate + CourierTemplatesLoginCodeValid(ctx context.Context) *CourierEmailTemplate + CourierTemplatesRegistrationCodeValid(ctx context.Context) *CourierEmailTemplate CourierMessageRetries(ctx context.Context) int } ) @@ -729,7 +737,8 @@ func (p *Config) SelfServiceStrategy(ctx context.Context, strategy string) *Self config = c } - enabledKey := fmt.Sprintf("%s.%s.enabled", ViperKeySelfServiceStrategyConfig, strategy) + basePath := fmt.Sprintf("%s.%s", ViperKeySelfServiceStrategyConfig, strategy) + enabledKey := fmt.Sprintf("%s.enabled", basePath) s := &SelfServiceStrategy{ Enabled: pp.Bool(enabledKey), Config: json.RawMessage(config), @@ -739,6 +748,7 @@ func (p *Config) SelfServiceStrategy(ctx context.Context, strategy string) *Self // we need to forcibly set these values here: if !pp.Exists(enabledKey) { switch strategy { + case "otp": case "password": fallthrough case "profile": @@ -755,6 +765,37 @@ func (p *Config) SelfServiceStrategy(ctx context.Context, strategy string) *Self return s } +func (p *Config) SelfServiceCodeStrategy(ctx context.Context) *SelfServiceStrategyCode { + pp := p.GetProvider(ctx) + + config := "{}" + out, err := pp.Marshal(kjson.Parser()) + if err != nil { + p.l.WithError(err).Warn("Unable to marshal self service strategy configuration.") + } else if c := gjson.GetBytes(out, + fmt.Sprintf("%s.%s.config", ViperKeySelfServiceStrategyConfig, "code")).Raw; len(c) > 0 { + config = c + } + + basePath := fmt.Sprintf("%s.%s", ViperKeySelfServiceStrategyConfig, "code") + enabledKey := fmt.Sprintf("%s.enabled", basePath) + passwordlessKey := fmt.Sprintf("%s.passwordless_enabled", basePath) + + s := &SelfServiceStrategyCode{ + SelfServiceStrategy: &SelfServiceStrategy{ + Enabled: pp.Bool(enabledKey), + Config: json.RawMessage(config), + }, + PasswordlessEnabled: pp.Bool(passwordlessKey), + } + + if !pp.Exists(enabledKey) { + s.PasswordlessEnabled = false + s.Enabled = true + } + return s +} + func (p *Config) SecretsDefault(ctx context.Context) [][]byte { pp := p.GetProvider(ctx) secrets := pp.Strings(ViperKeySecretsDefault) @@ -1096,6 +1137,14 @@ func (p *Config) CourierTemplatesVerificationCodeValid(ctx context.Context) *Cou return p.CourierTemplatesHelper(ctx, ViperKeyCourierTemplatesVerificationCodeValidEmail) } +func (p *Config) CourierTemplatesLoginCodeValid(ctx context.Context) *CourierEmailTemplate { + return p.CourierTemplatesHelper(ctx, ViperKeyCourierTemplatesLoginCodeValidEmail) +} + +func (p *Config) CourierTemplatesRegistrationCodeValid(ctx context.Context) *CourierEmailTemplate { + return p.CourierTemplatesHelper(ctx, ViperKeyCourierTemplatesRegistrationCodeValidEmail) +} + func (p *Config) CourierMessageRetries(ctx context.Context) int { return p.GetProvider(ctx).IntF(ViperKeyCourierMessageRetries, 5) } diff --git a/driver/config/config_test.go b/driver/config/config_test.go index 365b19323fd7..dee0baa5e657 100644 --- a/driver/config/config_test.go +++ b/driver/config/config_test.go @@ -381,8 +381,10 @@ func TestViperProvider(t *testing.T) { t.Run("group=hashers", func(t *testing.T) { c := p.HasherArgon2(ctx) - assert.Equal(t, &config.Argon2{Memory: 1048576, Iterations: 2, Parallelism: 4, - SaltLength: 16, KeyLength: 32, DedicatedMemory: config.Argon2DefaultDedicatedMemory, ExpectedDeviation: config.Argon2DefaultDeviation, ExpectedDuration: config.Argon2DefaultDuration}, c) + assert.Equal(t, &config.Argon2{ + Memory: 1048576, Iterations: 2, Parallelism: 4, + SaltLength: 16, KeyLength: 32, DedicatedMemory: config.Argon2DefaultDedicatedMemory, ExpectedDeviation: config.Argon2DefaultDeviation, ExpectedDuration: config.Argon2DefaultDuration, + }, c) }) t.Run("group=set_provider_by_json", func(t *testing.T) { @@ -505,6 +507,7 @@ func TestViperProvider_Defaults(t *testing.T) { assert.True(t, p.SelfServiceStrategy(ctx, "profile").Enabled) assert.True(t, p.SelfServiceStrategy(ctx, "link").Enabled) assert.True(t, p.SelfServiceStrategy(ctx, "code").Enabled) + assert.False(t, p.SelfServiceCodeStrategy(ctx).PasswordlessEnabled) assert.False(t, p.SelfServiceStrategy(ctx, "oidc").Enabled) }, }, @@ -520,6 +523,7 @@ func TestViperProvider_Defaults(t *testing.T) { assert.True(t, p.SelfServiceStrategy(ctx, "profile").Enabled) assert.True(t, p.SelfServiceStrategy(ctx, "link").Enabled) assert.True(t, p.SelfServiceStrategy(ctx, "code").Enabled) + assert.False(t, p.SelfServiceCodeStrategy(ctx).PasswordlessEnabled) assert.False(t, p.SelfServiceStrategy(ctx, "oidc").Enabled) }, }, @@ -535,6 +539,7 @@ func TestViperProvider_Defaults(t *testing.T) { assert.False(t, p.SelfServiceStrategy(ctx, "link").Enabled) assert.True(t, p.SelfServiceStrategy(ctx, "code").Enabled) assert.True(t, p.SelfServiceStrategy(ctx, "oidc").Enabled) + assert.False(t, p.SelfServiceCodeStrategy(ctx).PasswordlessEnabled) }, }, { @@ -561,7 +566,7 @@ func TestViperProvider_Defaults(t *testing.T) { assert.False(t, p.SelfServiceStrategy(ctx, "link").Enabled) assert.True(t, p.SelfServiceStrategy(ctx, "code").Enabled) assert.False(t, p.SelfServiceStrategy(ctx, "oidc").Enabled) - + assert.False(t, p.SelfServiceCodeStrategy(ctx).PasswordlessEnabled) assert.False(t, p.SelfServiceFlowRecoveryNotifyUnknownRecipients(ctx)) assert.False(t, p.SelfServiceFlowVerificationNotifyUnknownRecipients(ctx)) }) @@ -897,7 +902,6 @@ func TestLoadingTLSConfig(t *testing.T) { assert.Equal(t, "Unable to load HTTPS TLS Certificate", hook.LastEntry().Message) assert.True(t, *exited) }) - } func TestIdentitySchemaValidation(t *testing.T) { @@ -1022,7 +1026,6 @@ func TestIdentitySchemaValidation(t *testing.T) { assert.Error(t, e) assert.Contains(t, e.Error(), "Client.Timeout") } - }) t.Run("case=validate schema is validated on file change", func(t *testing.T) { @@ -1051,7 +1054,7 @@ func TestIdentitySchemaValidation(t *testing.T) { // There are a bunch of log messages beeing logged. We are looking for a specific one. timeout := time.After(time.Millisecond * 500) - var success = false + success := false for !success { for _, v := range hook.AllEntries() { s, err := v.String() @@ -1064,7 +1067,7 @@ func TestIdentitySchemaValidation(t *testing.T) { t.Fatal("the test could not complete as the context timed out before the file watcher updated") case <-timeout: t.Fatal("Expected log line was not encountered within specified timeout") - default: //nothing + default: // nothing } } diff --git a/driver/registry_default.go b/driver/registry_default.go index d0ffa2d2c198..514409f5bd1e 100644 --- a/driver/registry_default.go +++ b/driver/registry_default.go @@ -97,11 +97,12 @@ type RegistryDefault struct { persister persistence.Persister migrationStatus popx.MigrationStatuses - hookVerifier *hook.Verifier - hookSessionIssuer *hook.SessionIssuer - hookSessionDestroyer *hook.SessionDestroyer - hookAddressVerifier *hook.AddressVerifier - hookShowVerificationUI *hook.ShowVerificationUIHook + hookVerifier *hook.Verifier + hookSessionIssuer *hook.SessionIssuer + hookSessionDestroyer *hook.SessionDestroyer + hookAddressVerifier *hook.AddressVerifier + hookShowVerificationUI *hook.ShowVerificationUIHook + hookCodeAddressVerifier *hook.CodeAddressVerifier identityHandler *identity.Handler identityValidator *identity.Validator @@ -327,10 +328,28 @@ func (m *RegistryDefault) selfServiceStrategies() []interface{} { return m.selfserviceStrategies } +func (m *RegistryDefault) strategyRegistrationEnabled(ctx context.Context, id string) bool { + switch id { + case identity.CredentialsTypeCodeAuth.String(): + return m.Config().SelfServiceCodeStrategy(ctx).PasswordlessEnabled + default: + return m.Config().SelfServiceStrategy(ctx, id).Enabled + } +} + +func (m *RegistryDefault) strategyLoginEnabled(ctx context.Context, id string) bool { + switch id { + case identity.CredentialsTypeCodeAuth.String(): + return m.Config().SelfServiceCodeStrategy(ctx).PasswordlessEnabled + default: + return m.Config().SelfServiceStrategy(ctx, id).Enabled + } +} + func (m *RegistryDefault) RegistrationStrategies(ctx context.Context) (registrationStrategies registration.Strategies) { for _, strategy := range m.selfServiceStrategies() { if s, ok := strategy.(registration.Strategy); ok { - if m.Config().SelfServiceStrategy(ctx, string(s.ID())).Enabled { + if m.strategyRegistrationEnabled(ctx, s.ID().String()) { registrationStrategies = append(registrationStrategies, s) } } @@ -352,7 +371,7 @@ func (m *RegistryDefault) AllRegistrationStrategies() registration.Strategies { func (m *RegistryDefault) LoginStrategies(ctx context.Context) (loginStrategies login.Strategies) { for _, strategy := range m.selfServiceStrategies() { if s, ok := strategy.(login.Strategy); ok { - if m.Config().SelfServiceStrategy(ctx, string(s.ID())).Enabled { + if m.strategyLoginEnabled(ctx, s.ID().String()) { loginStrategies = append(loginStrategies, s) } } @@ -660,7 +679,6 @@ func (m *RegistryDefault) Init(ctx context.Context, ctxer contextx.Contextualize m.persister = p.WithNetworkID(net.ID) return nil }, bc) - if err != nil { return err } @@ -744,6 +762,14 @@ func (m *RegistryDefault) VerificationCodePersister() code.VerificationCodePersi return m.Persister() } +func (m *RegistryDefault) RegistrationCodePersister() code.RegistrationCodePersister { + return m.Persister() +} + +func (m *RegistryDefault) LoginCodePersister() code.LoginCodePersister { + return m.Persister() +} + func (m *RegistryDefault) Persister() persistence.Persister { return m.persister } diff --git a/driver/registry_default_hooks.go b/driver/registry_default_hooks.go index 6efffc05a777..c3f809d2144e 100644 --- a/driver/registry_default_hooks.go +++ b/driver/registry_default_hooks.go @@ -15,6 +15,13 @@ func (m *RegistryDefault) HookVerifier() *hook.Verifier { return m.hookVerifier } +func (m *RegistryDefault) HookCodeAddressVerifier() *hook.CodeAddressVerifier { + if m.hookCodeAddressVerifier == nil { + m.hookCodeAddressVerifier = hook.NewCodeAddressVerifier(m) + } + return m.hookCodeAddressVerifier +} + func (m *RegistryDefault) HookSessionIssuer() *hook.SessionIssuer { if m.hookSessionIssuer == nil { m.hookSessionIssuer = hook.NewSessionIssuer(m) diff --git a/driver/registry_default_registration.go b/driver/registry_default_registration.go index 7f78517891f0..89ed5e656c74 100644 --- a/driver/registry_default_registration.go +++ b/driver/registry_default_registration.go @@ -12,6 +12,10 @@ import ( ) func (m *RegistryDefault) PostRegistrationPrePersistHooks(ctx context.Context, credentialsType identity.CredentialsType) (b []registration.PostHookPrePersistExecutor) { + if credentialsType == identity.CredentialsTypeCodeAuth && m.Config().SelfServiceCodeStrategy(ctx).PasswordlessEnabled { + b = append(b, m.HookCodeAddressVerifier()) + } + for _, v := range m.getHooks(string(credentialsType), m.Config().SelfServiceFlowRegistrationAfterHooks(ctx, string(credentialsType))) { if hook, ok := v.(registration.PostHookPrePersistExecutor); ok { b = append(b, hook) @@ -35,7 +39,7 @@ func (m *RegistryDefault) PostRegistrationPostPersistHooks(ctx context.Context, } if len(b) == initialHookCount { - // since we don't want merging hooks defined in a specific strategy and global hooks + // since we don't want merging hooks defined in a specific strategy and // global hooks are added only if no strategy specific hooks are defined for _, v := range m.getHooks(config.HookGlobal, m.Config().SelfServiceFlowRegistrationAfterHooks(ctx, config.HookGlobal)) { if hook, ok := v.(registration.PostHookPostPersistExecutor); ok { diff --git a/driver/registry_default_test.go b/driver/registry_default_test.go index 3bccf3e24b03..533cdd621a9a 100644 --- a/driver/registry_default_test.go +++ b/driver/registry_default_test.go @@ -627,7 +627,8 @@ func TestDriverDefault_Strategies(t *testing.T) { { prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".password.enabled", false) - }}, + }, + }, { prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".password.enabled", true) @@ -649,6 +650,13 @@ func TestDriverDefault_Strategies(t *testing.T) { }, expect: []string{"password", "oidc"}, }, + { + prep: func(conf *config.Config) { + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".password.enabled", true) + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.passwordless_enabled", true) + }, + expect: []string{"password", "code"}, + }, } { t.Run(fmt.Sprintf("run=%d", k), func(t *testing.T) { conf, reg := internal.NewVeryFastRegistryWithoutDB(t) @@ -672,7 +680,8 @@ func TestDriverDefault_Strategies(t *testing.T) { { prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".password.enabled", false) - }}, + }, + }, { prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".password.enabled", true) @@ -694,6 +703,13 @@ func TestDriverDefault_Strategies(t *testing.T) { }, expect: []string{"password", "oidc", "totp"}, }, + { + prep: func(conf *config.Config) { + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".password.enabled", true) + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.passwordless_enabled", true) + }, + expect: []string{"password", "code"}, + }, } { t.Run(fmt.Sprintf("run=%d", k), func(t *testing.T) { conf, reg := internal.NewVeryFastRegistryWithoutDB(t) @@ -760,7 +776,8 @@ func TestDriverDefault_Strategies(t *testing.T) { }), configx.SkipValidation()) return c - }}, + }, + }, { prep: func(t *testing.T) *config.Config { c := config.MustNew(t, l, @@ -834,7 +851,7 @@ func TestDefaultRegistry_AllStrategies(t *testing.T) { _, reg := internal.NewVeryFastRegistryWithoutDB(t) t.Run("case=all login strategies", func(t *testing.T) { - expects := []string{"password", "oidc", "totp", "webauthn", "lookup_secret"} + expects := []string{"password", "oidc", "code", "totp", "webauthn", "lookup_secret"} s := reg.AllLoginStrategies() require.Len(t, s, len(expects)) for k, e := range expects { @@ -843,7 +860,7 @@ func TestDefaultRegistry_AllStrategies(t *testing.T) { }) t.Run("case=all registration strategies", func(t *testing.T) { - expects := []string{"password", "oidc", "webauthn"} + expects := []string{"password", "oidc", "code", "webauthn"} s := reg.AllRegistrationStrategies() require.Len(t, s, len(expects)) for k, e := range expects { diff --git a/embedx/config.schema.json b/embedx/config.schema.json index 61ba37c6708f..be8dddc87f9b 100644 --- a/embedx/config.schema.json +++ b/embedx/config.schema.json @@ -875,6 +875,9 @@ "oidc": { "$ref": "#/definitions/selfServiceAfterOIDCLoginMethod" }, + "code": { + "$ref": "#/definitions/selfServiceAfterDefaultLoginMethod" + }, "hooks": { "type": "array", "items": { @@ -947,6 +950,9 @@ "oidc": { "$ref": "#/definitions/selfServiceAfterRegistrationMethod" }, + "code": { + "$ref": "#/definitions/selfServiceAfterRegistrationMethod" + }, "hooks": { "$ref": "#/definitions/selfServiceHooks" } @@ -1447,6 +1453,11 @@ "type": "object", "additionalProperties": false, "properties": { + "passwordless_enabled": { + "type": "boolean", + "title": "Enables Login and Registration with the Code Method", + "default": false + }, "enabled": { "type": "boolean", "title": "Enables Code Method", @@ -1643,8 +1654,12 @@ "display_name" ], "properties": { - "origin": {"not": {}}, - "origins": {"not": {}} + "origin": { + "not": {} + }, + "origins": { + "not": {} + } } }, { @@ -1654,8 +1669,12 @@ "origin" ], "properties": { - "origin": {"type": "string"}, - "origins": {"not": {}} + "origin": { + "type": "string" + }, + "origins": { + "not": {} + } } }, { @@ -1665,8 +1684,15 @@ "origins" ], "properties": { - "origin": {"not": {}}, - "origins": {"type": "array", "items": {"type": "string"}} + "origin": { + "not": {} + }, + "origins": { + "type": "array", + "items": { + "type": "string" + } + } } } ] @@ -1805,6 +1831,42 @@ }, "verification_code": { "$ref": "#/definitions/courierTemplates" + }, + "registration_code": { + "additionalProperties": false, + "type": "object", + "properties": { + "valid": { + "additionalProperties": false, + "type": "object", + "properties": { + "email": { + "$ref": "#/definitions/emailCourierTemplate" + } + }, + "required": [ + "email" + ] + } + } + }, + "login_code": { + "additionalProperties": false, + "type": "object", + "properties": { + "valid": { + "additionalProperties": false, + "type": "object", + "properties": { + "email": { + "$ref": "#/definitions/emailCourierTemplate" + } + }, + "required": [ + "email" + ] + } + } } } }, @@ -1829,7 +1891,10 @@ "title": "Delivery Strategy", "description": "Defines how emails will be sent, either through SMTP (default) or HTTP.", "type": "string", - "enum": ["smtp", "http"], + "enum": [ + "smtp", + "http" + ], "default": "smtp" }, "http": { @@ -2026,10 +2091,10 @@ ] }, "override_return_to": { - "title":"Persist OAuth2 request between flows", - "type":"boolean", - "default":false, - "description":"Override the return_to query parameter with the OAuth2 provider request URL when perfoming an OAuth2 login flow." + "title": "Persist OAuth2 request between flows", + "type": "boolean", + "default": false, + "description": "Override the return_to query parameter with the OAuth2 provider request URL when perfoming an OAuth2 login flow." } }, "additionalProperties": false diff --git a/embedx/identity_extension.schema.json b/embedx/identity_extension.schema.json index ef402cdadcfb..9af2e97f07ce 100644 --- a/embedx/identity_extension.schema.json +++ b/embedx/identity_extension.schema.json @@ -38,6 +38,19 @@ "type": "boolean" } } + }, + "code": { + "type": "object", + "additionalProperties": false, + "properties": { + "identifier": { + "type": "boolean" + }, + "via": { + "type": "string", + "enum": ["email"] + } + } } } }, @@ -47,10 +60,7 @@ "properties": { "via": { "type": "string", - "enum": [ - "email", - "phone" - ] + "enum": ["email", "phone"] } } }, @@ -60,9 +70,7 @@ "properties": { "via": { "type": "string", - "enum": [ - "email" - ] + "enum": ["email"] } } } diff --git a/identity/credentials.go b/identity/credentials.go index af79ba3f2ed6..6ccbe867c89a 100644 --- a/identity/credentials.go +++ b/identity/credentials.go @@ -94,6 +94,8 @@ func (c CredentialsType) ToUiNodeGroup() node.UiNodeGroup { return node.WebAuthnGroup case CredentialsTypeLookup: return node.LookupGroup + case CredentialsTypeCodeAuth: + return node.CodeGroup default: return node.DefaultGroup } @@ -106,6 +108,7 @@ const ( CredentialsTypeTOTP CredentialsType = "totp" CredentialsTypeLookup CredentialsType = "lookup_secret" CredentialsTypeWebAuthn CredentialsType = "webauthn" + CredentialsTypeCodeAuth CredentialsType = "code" ) var AllCredentialTypes = []CredentialsType{ @@ -114,6 +117,7 @@ var AllCredentialTypes = []CredentialsType{ CredentialsTypeTOTP, CredentialsTypeLookup, CredentialsTypeWebAuthn, + CredentialsTypeCodeAuth, } const ( @@ -131,6 +135,7 @@ func ParseCredentialsType(in string) (CredentialsType, bool) { CredentialsTypeTOTP, CredentialsTypeLookup, CredentialsTypeWebAuthn, + CredentialsTypeCodeAuth, CredentialsTypeRecoveryLink, CredentialsTypeRecoveryCode, } { @@ -141,6 +146,15 @@ func ParseCredentialsType(in string) (CredentialsType, bool) { return "", false } +// swagger:ignore +type CredentialsIdentifierAddressType string + +const ( + CredentialsIdentifierAddressTypeEmail CredentialsIdentifierAddressType = AddressTypeEmail + CredentialsIdentifierAddressTypePhone CredentialsIdentifierAddressType = AddressTypePhone + CredentialsIdentifierAddressTypeNone CredentialsIdentifierAddressType = "none" +) + // Credentials represents a specific credential type // // swagger:model identityCredentials diff --git a/identity/credentials_code.go b/identity/credentials_code.go new file mode 100644 index 000000000000..184479ae1700 --- /dev/null +++ b/identity/credentials_code.go @@ -0,0 +1,26 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package identity + +import ( + "database/sql" +) + +type CodeAddressType string + +const ( + CodeAddressTypeEmail CodeAddressType = AddressTypeEmail + CodeAddressTypePhone CodeAddressType = AddressTypePhone +) + +// CredentialsCode represents a one time login/registration code +// +// swagger:model identityCredentialsCode +type CredentialsCode struct { + // The type of the address for this code + AddressType CodeAddressType `json:"address_type"` + + // UsedAt indicates whether and when a recovery code was used. + UsedAt sql.NullTime `json:"used_at,omitempty"` +} diff --git a/identity/extension_credentials.go b/identity/extension_credentials.go index 95a1ee8d4c93..69fb53810fbc 100644 --- a/identity/extension_credentials.go +++ b/identity/extension_credentials.go @@ -11,6 +11,7 @@ import ( "github.com/ory/jsonschema/v3" "github.com/ory/x/sqlxx" "github.com/ory/x/stringslice" + "github.com/ory/x/stringsx" "github.com/ory/kratos/schema" ) @@ -25,7 +26,7 @@ func NewSchemaExtensionCredentials(i *Identity) *SchemaExtensionCredentials { return &SchemaExtensionCredentials{i: i} } -func (r *SchemaExtensionCredentials) setIdentifier(ct CredentialsType, value interface{}) { +func (r *SchemaExtensionCredentials) setIdentifier(ct CredentialsType, value interface{}, addressType CredentialsIdentifierAddressType) { cred, ok := r.i.GetCredentials(ct) if !ok { cred = &Credentials{ @@ -43,16 +44,35 @@ func (r *SchemaExtensionCredentials) setIdentifier(ct CredentialsType, value int r.i.SetCredentials(ct, *cred) } -func (r *SchemaExtensionCredentials) Run(_ jsonschema.ValidationContext, s schema.ExtensionConfig, value interface{}) error { +func (r *SchemaExtensionCredentials) Run(ctx jsonschema.ValidationContext, s schema.ExtensionConfig, value interface{}) error { r.l.Lock() defer r.l.Unlock() if s.Credentials.Password.Identifier { - r.setIdentifier(CredentialsTypePassword, value) + r.setIdentifier(CredentialsTypePassword, value, CredentialsIdentifierAddressTypeNone) } if s.Credentials.WebAuthn.Identifier { - r.setIdentifier(CredentialsTypeWebAuthn, value) + r.setIdentifier(CredentialsTypeWebAuthn, value, CredentialsIdentifierAddressTypeNone) + } + + if s.Credentials.Code.Identifier { + switch f := stringsx.SwitchExact(s.Credentials.Code.Via); { + case f.AddCase(AddressTypeEmail): + if !jsonschema.Formats["email"](value) { + return ctx.Error("format", "%q is not a valid %q", value, s.Credentials.Code.Via) + } + + r.setIdentifier(CredentialsTypeCodeAuth, value, AddressTypeEmail) + // case f.AddCase(AddressTypePhone): + // if !jsonschema.Formats["tel"](value) { + // return ctx.Error("format", "%q is not a valid %q", value, s.Credentials.Code.Via) + // } + // + // r.setIdentifier(CredentialsTypeCodeAuth, value, CredentialsIdentifierAddressType(AddressTypePhone)) + default: + return ctx.Error("", "credentials.code.via has unknown value %q", s.Credentials.Code.Via) + } } return nil diff --git a/identity/extension_credentials_test.go b/identity/extension_credentials_test.go index cf580c6a0c10..95cd9d000c6a 100644 --- a/identity/extension_credentials_test.go +++ b/identity/extension_credentials_test.go @@ -72,6 +72,21 @@ func TestSchemaExtensionCredentials(t *testing.T) { }, ct: identity.CredentialsTypeWebAuthn, }, + { + doc: `{"email":"foo@ory.sh"}`, + schema: "file://./stub/extension/credentials/code.schema.json", + expect: []string{"foo@ory.sh"}, + ct: identity.CredentialsTypeCodeAuth, + }, + { + doc: `{"email":"FOO@ory.sh"}`, + schema: "file://./stub/extension/credentials/code.schema.json", + expect: []string{"foo@ory.sh"}, + existing: &identity.Credentials{ + Identifiers: []string{"not-foo@ory.sh"}, + }, + ct: identity.CredentialsTypeCodeAuth, + }, } { t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { c := jsonschema.NewCompiler() diff --git a/identity/stub/extension/credentials/code.schema.json b/identity/stub/extension/credentials/code.schema.json new file mode 100644 index 000000000000..bef244bc9ae5 --- /dev/null +++ b/identity/stub/extension/credentials/code.schema.json @@ -0,0 +1,20 @@ +{ + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + }, + "code": { + "identifier": true, + "via": "email" + } + } + } + } + } +} diff --git a/internal/client-go/.openapi-generator/FILES b/internal/client-go/.openapi-generator/FILES index f7968b85c90e..959499576b3d 100644 --- a/internal/client-go/.openapi-generator/FILES +++ b/internal/client-go/.openapi-generator/FILES @@ -34,6 +34,7 @@ docs/HealthStatus.md docs/Identity.md docs/IdentityApi.md docs/IdentityCredentials.md +docs/IdentityCredentialsCode.md docs/IdentityCredentialsOidc.md docs/IdentityCredentialsOidcProvider.md docs/IdentityCredentialsPassword.md @@ -52,6 +53,7 @@ docs/IsAlive200Response.md docs/IsReady503Response.md docs/JsonPatch.md docs/LoginFlow.md +docs/LoginFlowState.md docs/LogoutFlow.md docs/Message.md docs/MessageDispatch.md @@ -69,6 +71,7 @@ docs/RecoveryFlowState.md docs/RecoveryIdentityAddress.md docs/RecoveryLinkForIdentity.md docs/RegistrationFlow.md +docs/RegistrationFlowState.md docs/SelfServiceFlowExpiredError.md docs/Session.md docs/SessionAuthenticationMethod.md @@ -92,6 +95,7 @@ docs/UiNodeTextAttributes.md docs/UiText.md docs/UpdateIdentityBody.md docs/UpdateLoginFlowBody.md +docs/UpdateLoginFlowWithCodeMethod.md docs/UpdateLoginFlowWithLookupSecretMethod.md docs/UpdateLoginFlowWithOidcMethod.md docs/UpdateLoginFlowWithPasswordMethod.md @@ -101,6 +105,7 @@ docs/UpdateRecoveryFlowBody.md docs/UpdateRecoveryFlowWithCodeMethod.md docs/UpdateRecoveryFlowWithLinkMethod.md docs/UpdateRegistrationFlowBody.md +docs/UpdateRegistrationFlowWithCodeMethod.md docs/UpdateRegistrationFlowWithOidcMethod.md docs/UpdateRegistrationFlowWithPasswordMethod.md docs/UpdateRegistrationFlowWithWebAuthnMethod.md @@ -144,6 +149,7 @@ model_health_not_ready_status.go model_health_status.go model_identity.go model_identity_credentials.go +model_identity_credentials_code.go model_identity_credentials_oidc.go model_identity_credentials_oidc_provider.go model_identity_credentials_password.go @@ -162,6 +168,7 @@ model_is_alive_200_response.go model_is_ready_503_response.go model_json_patch.go model_login_flow.go +model_login_flow_state.go model_logout_flow.go model_message.go model_message_dispatch.go @@ -178,6 +185,7 @@ model_recovery_flow_state.go model_recovery_identity_address.go model_recovery_link_for_identity.go model_registration_flow.go +model_registration_flow_state.go model_self_service_flow_expired_error.go model_session.go model_session_authentication_method.go @@ -201,6 +209,7 @@ model_ui_node_text_attributes.go model_ui_text.go model_update_identity_body.go model_update_login_flow_body.go +model_update_login_flow_with_code_method.go model_update_login_flow_with_lookup_secret_method.go model_update_login_flow_with_oidc_method.go model_update_login_flow_with_password_method.go @@ -210,6 +219,7 @@ model_update_recovery_flow_body.go model_update_recovery_flow_with_code_method.go model_update_recovery_flow_with_link_method.go model_update_registration_flow_body.go +model_update_registration_flow_with_code_method.go model_update_registration_flow_with_oidc_method.go model_update_registration_flow_with_password_method.go model_update_registration_flow_with_web_authn_method.go diff --git a/internal/client-go/README.md b/internal/client-go/README.md index cb48b260e91f..084b578785ee 100644 --- a/internal/client-go/README.md +++ b/internal/client-go/README.md @@ -159,6 +159,7 @@ Class | Method | HTTP request | Description - [HealthStatus](docs/HealthStatus.md) - [Identity](docs/Identity.md) - [IdentityCredentials](docs/IdentityCredentials.md) + - [IdentityCredentialsCode](docs/IdentityCredentialsCode.md) - [IdentityCredentialsOidc](docs/IdentityCredentialsOidc.md) - [IdentityCredentialsOidcProvider](docs/IdentityCredentialsOidcProvider.md) - [IdentityCredentialsPassword](docs/IdentityCredentialsPassword.md) @@ -177,6 +178,7 @@ Class | Method | HTTP request | Description - [IsReady503Response](docs/IsReady503Response.md) - [JsonPatch](docs/JsonPatch.md) - [LoginFlow](docs/LoginFlow.md) + - [LoginFlowState](docs/LoginFlowState.md) - [LogoutFlow](docs/LogoutFlow.md) - [Message](docs/Message.md) - [MessageDispatch](docs/MessageDispatch.md) @@ -193,6 +195,7 @@ Class | Method | HTTP request | Description - [RecoveryIdentityAddress](docs/RecoveryIdentityAddress.md) - [RecoveryLinkForIdentity](docs/RecoveryLinkForIdentity.md) - [RegistrationFlow](docs/RegistrationFlow.md) + - [RegistrationFlowState](docs/RegistrationFlowState.md) - [SelfServiceFlowExpiredError](docs/SelfServiceFlowExpiredError.md) - [Session](docs/Session.md) - [SessionAuthenticationMethod](docs/SessionAuthenticationMethod.md) @@ -216,6 +219,7 @@ Class | Method | HTTP request | Description - [UiText](docs/UiText.md) - [UpdateIdentityBody](docs/UpdateIdentityBody.md) - [UpdateLoginFlowBody](docs/UpdateLoginFlowBody.md) + - [UpdateLoginFlowWithCodeMethod](docs/UpdateLoginFlowWithCodeMethod.md) - [UpdateLoginFlowWithLookupSecretMethod](docs/UpdateLoginFlowWithLookupSecretMethod.md) - [UpdateLoginFlowWithOidcMethod](docs/UpdateLoginFlowWithOidcMethod.md) - [UpdateLoginFlowWithPasswordMethod](docs/UpdateLoginFlowWithPasswordMethod.md) @@ -225,6 +229,7 @@ Class | Method | HTTP request | Description - [UpdateRecoveryFlowWithCodeMethod](docs/UpdateRecoveryFlowWithCodeMethod.md) - [UpdateRecoveryFlowWithLinkMethod](docs/UpdateRecoveryFlowWithLinkMethod.md) - [UpdateRegistrationFlowBody](docs/UpdateRegistrationFlowBody.md) + - [UpdateRegistrationFlowWithCodeMethod](docs/UpdateRegistrationFlowWithCodeMethod.md) - [UpdateRegistrationFlowWithOidcMethod](docs/UpdateRegistrationFlowWithOidcMethod.md) - [UpdateRegistrationFlowWithPasswordMethod](docs/UpdateRegistrationFlowWithPasswordMethod.md) - [UpdateRegistrationFlowWithWebAuthnMethod](docs/UpdateRegistrationFlowWithWebAuthnMethod.md) diff --git a/internal/client-go/model_identity_credentials_code.go b/internal/client-go/model_identity_credentials_code.go new file mode 100644 index 000000000000..f542b359639a --- /dev/null +++ b/internal/client-go/model_identity_credentials_code.go @@ -0,0 +1,162 @@ +/* + * Ory Identities API + * + * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. + * + * API version: + * Contact: office@ory.sh + */ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +import ( + "encoding/json" + "time" +) + +// IdentityCredentialsCode CredentialsCode represents a one time login/registration code +type IdentityCredentialsCode struct { + AddressType *string `json:"address_type,omitempty"` + UsedAt NullableTime `json:"used_at,omitempty"` +} + +// NewIdentityCredentialsCode instantiates a new IdentityCredentialsCode 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 NewIdentityCredentialsCode() *IdentityCredentialsCode { + this := IdentityCredentialsCode{} + return &this +} + +// NewIdentityCredentialsCodeWithDefaults instantiates a new IdentityCredentialsCode 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 NewIdentityCredentialsCodeWithDefaults() *IdentityCredentialsCode { + this := IdentityCredentialsCode{} + return &this +} + +// GetAddressType returns the AddressType field value if set, zero value otherwise. +func (o *IdentityCredentialsCode) GetAddressType() string { + if o == nil || o.AddressType == nil { + var ret string + return ret + } + return *o.AddressType +} + +// GetAddressTypeOk returns a tuple with the AddressType field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *IdentityCredentialsCode) GetAddressTypeOk() (*string, bool) { + if o == nil || o.AddressType == nil { + return nil, false + } + return o.AddressType, true +} + +// HasAddressType returns a boolean if a field has been set. +func (o *IdentityCredentialsCode) HasAddressType() bool { + if o != nil && o.AddressType != nil { + return true + } + + return false +} + +// SetAddressType gets a reference to the given string and assigns it to the AddressType field. +func (o *IdentityCredentialsCode) SetAddressType(v string) { + o.AddressType = &v +} + +// GetUsedAt returns the UsedAt field value if set, zero value otherwise (both if not set or set to explicit null). +func (o *IdentityCredentialsCode) GetUsedAt() time.Time { + if o == nil || o.UsedAt.Get() == nil { + var ret time.Time + return ret + } + return *o.UsedAt.Get() +} + +// GetUsedAtOk returns a tuple with the UsedAt 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 *IdentityCredentialsCode) GetUsedAtOk() (*time.Time, bool) { + if o == nil { + return nil, false + } + return o.UsedAt.Get(), o.UsedAt.IsSet() +} + +// HasUsedAt returns a boolean if a field has been set. +func (o *IdentityCredentialsCode) HasUsedAt() bool { + if o != nil && o.UsedAt.IsSet() { + return true + } + + return false +} + +// SetUsedAt gets a reference to the given NullableTime and assigns it to the UsedAt field. +func (o *IdentityCredentialsCode) SetUsedAt(v time.Time) { + o.UsedAt.Set(&v) +} + +// SetUsedAtNil sets the value for UsedAt to be an explicit nil +func (o *IdentityCredentialsCode) SetUsedAtNil() { + o.UsedAt.Set(nil) +} + +// UnsetUsedAt ensures that no value is present for UsedAt, not even an explicit nil +func (o *IdentityCredentialsCode) UnsetUsedAt() { + o.UsedAt.Unset() +} + +func (o IdentityCredentialsCode) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if o.AddressType != nil { + toSerialize["address_type"] = o.AddressType + } + if o.UsedAt.IsSet() { + toSerialize["used_at"] = o.UsedAt.Get() + } + return json.Marshal(toSerialize) +} + +type NullableIdentityCredentialsCode struct { + value *IdentityCredentialsCode + isSet bool +} + +func (v NullableIdentityCredentialsCode) Get() *IdentityCredentialsCode { + return v.value +} + +func (v *NullableIdentityCredentialsCode) Set(val *IdentityCredentialsCode) { + v.value = val + v.isSet = true +} + +func (v NullableIdentityCredentialsCode) IsSet() bool { + return v.isSet +} + +func (v *NullableIdentityCredentialsCode) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableIdentityCredentialsCode(val *IdentityCredentialsCode) *NullableIdentityCredentialsCode { + return &NullableIdentityCredentialsCode{value: val, isSet: true} +} + +func (v NullableIdentityCredentialsCode) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableIdentityCredentialsCode) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/client-go/model_identity_credentials_otp.go b/internal/client-go/model_identity_credentials_otp.go new file mode 100644 index 000000000000..b60601987e67 --- /dev/null +++ b/internal/client-go/model_identity_credentials_otp.go @@ -0,0 +1,162 @@ +/* + * Ory Identities API + * + * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. + * + * API version: + * Contact: office@ory.sh + */ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +import ( + "encoding/json" + "time" +) + +// IdentityCredentialsOTP CredentialsOTP represents an OTP code +type IdentityCredentialsOTP struct { + AddressType *string `json:"address_type,omitempty"` + UsedAt NullableTime `json:"used_at,omitempty"` +} + +// NewIdentityCredentialsOTP instantiates a new IdentityCredentialsOTP 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 NewIdentityCredentialsOTP() *IdentityCredentialsOTP { + this := IdentityCredentialsOTP{} + return &this +} + +// NewIdentityCredentialsOTPWithDefaults instantiates a new IdentityCredentialsOTP 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 NewIdentityCredentialsOTPWithDefaults() *IdentityCredentialsOTP { + this := IdentityCredentialsOTP{} + return &this +} + +// GetAddressType returns the AddressType field value if set, zero value otherwise. +func (o *IdentityCredentialsOTP) GetAddressType() string { + if o == nil || o.AddressType == nil { + var ret string + return ret + } + return *o.AddressType +} + +// GetAddressTypeOk returns a tuple with the AddressType field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *IdentityCredentialsOTP) GetAddressTypeOk() (*string, bool) { + if o == nil || o.AddressType == nil { + return nil, false + } + return o.AddressType, true +} + +// HasAddressType returns a boolean if a field has been set. +func (o *IdentityCredentialsOTP) HasAddressType() bool { + if o != nil && o.AddressType != nil { + return true + } + + return false +} + +// SetAddressType gets a reference to the given string and assigns it to the AddressType field. +func (o *IdentityCredentialsOTP) SetAddressType(v string) { + o.AddressType = &v +} + +// GetUsedAt returns the UsedAt field value if set, zero value otherwise (both if not set or set to explicit null). +func (o *IdentityCredentialsOTP) GetUsedAt() time.Time { + if o == nil || o.UsedAt.Get() == nil { + var ret time.Time + return ret + } + return *o.UsedAt.Get() +} + +// GetUsedAtOk returns a tuple with the UsedAt 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 *IdentityCredentialsOTP) GetUsedAtOk() (*time.Time, bool) { + if o == nil { + return nil, false + } + return o.UsedAt.Get(), o.UsedAt.IsSet() +} + +// HasUsedAt returns a boolean if a field has been set. +func (o *IdentityCredentialsOTP) HasUsedAt() bool { + if o != nil && o.UsedAt.IsSet() { + return true + } + + return false +} + +// SetUsedAt gets a reference to the given NullableTime and assigns it to the UsedAt field. +func (o *IdentityCredentialsOTP) SetUsedAt(v time.Time) { + o.UsedAt.Set(&v) +} + +// SetUsedAtNil sets the value for UsedAt to be an explicit nil +func (o *IdentityCredentialsOTP) SetUsedAtNil() { + o.UsedAt.Set(nil) +} + +// UnsetUsedAt ensures that no value is present for UsedAt, not even an explicit nil +func (o *IdentityCredentialsOTP) UnsetUsedAt() { + o.UsedAt.Unset() +} + +func (o IdentityCredentialsOTP) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if o.AddressType != nil { + toSerialize["address_type"] = o.AddressType + } + if o.UsedAt.IsSet() { + toSerialize["used_at"] = o.UsedAt.Get() + } + return json.Marshal(toSerialize) +} + +type NullableIdentityCredentialsOTP struct { + value *IdentityCredentialsOTP + isSet bool +} + +func (v NullableIdentityCredentialsOTP) Get() *IdentityCredentialsOTP { + return v.value +} + +func (v *NullableIdentityCredentialsOTP) Set(val *IdentityCredentialsOTP) { + v.value = val + v.isSet = true +} + +func (v NullableIdentityCredentialsOTP) IsSet() bool { + return v.isSet +} + +func (v *NullableIdentityCredentialsOTP) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableIdentityCredentialsOTP(val *IdentityCredentialsOTP) *NullableIdentityCredentialsOTP { + return &NullableIdentityCredentialsOTP{value: val, isSet: true} +} + +func (v NullableIdentityCredentialsOTP) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableIdentityCredentialsOTP) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/client-go/model_identity_credentials_type.go b/internal/client-go/model_identity_credentials_type.go index f02f3f19b898..a9d01c54e796 100644 --- a/internal/client-go/model_identity_credentials_type.go +++ b/internal/client-go/model_identity_credentials_type.go @@ -26,6 +26,7 @@ const ( IDENTITYCREDENTIALSTYPE_OIDC IdentityCredentialsType = "oidc" IDENTITYCREDENTIALSTYPE_WEBAUTHN IdentityCredentialsType = "webauthn" IDENTITYCREDENTIALSTYPE_LOOKUP_SECRET IdentityCredentialsType = "lookup_secret" + IDENTITYCREDENTIALSTYPE_CODE IdentityCredentialsType = "code" ) func (v *IdentityCredentialsType) UnmarshalJSON(src []byte) error { @@ -35,7 +36,7 @@ func (v *IdentityCredentialsType) UnmarshalJSON(src []byte) error { return err } enumTypeValue := IdentityCredentialsType(value) - for _, existing := range []IdentityCredentialsType{"password", "totp", "oidc", "webauthn", "lookup_secret"} { + for _, existing := range []IdentityCredentialsType{"password", "totp", "oidc", "webauthn", "lookup_secret", "code"} { if existing == enumTypeValue { *v = enumTypeValue return nil diff --git a/internal/client-go/model_login_flow.go b/internal/client-go/model_login_flow.go index 1b3f4b6c7dde..dc7c67ea2649 100644 --- a/internal/client-go/model_login_flow.go +++ b/internal/client-go/model_login_flow.go @@ -39,6 +39,8 @@ type LoginFlow struct { ReturnTo *string `json:"return_to,omitempty"` // SessionTokenExchangeCode holds the secret code that the client can use to retrieve a session token after the login flow has been completed. This is only set if the client has requested a session token exchange code, and if the flow is of type \"api\", and only on creating the login flow. SessionTokenExchangeCode *string `json:"session_token_exchange_code,omitempty"` + // State represents the state of this request: choose_method: ask the user to choose a method to sign in with sent_email: the email has been sent to the user passed_challenge: the request was successful and the login challenge was passed. + State interface{} `json:"state"` // The flow type can either be `api` or `browser`. Type string `json:"type"` Ui UiContainer `json:"ui"` @@ -50,12 +52,13 @@ type LoginFlow struct { // 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 NewLoginFlow(expiresAt time.Time, id string, issuedAt time.Time, requestUrl string, type_ string, ui UiContainer) *LoginFlow { +func NewLoginFlow(expiresAt time.Time, id string, issuedAt time.Time, requestUrl string, state interface{}, type_ string, ui UiContainer) *LoginFlow { this := LoginFlow{} this.ExpiresAt = expiresAt this.Id = id this.IssuedAt = issuedAt this.RequestUrl = requestUrl + this.State = state this.Type = type_ this.Ui = ui return &this @@ -421,6 +424,32 @@ func (o *LoginFlow) SetSessionTokenExchangeCode(v string) { o.SessionTokenExchangeCode = &v } +// GetState returns the State field value +// If the value is explicit nil, the zero value for interface{} will be returned +func (o *LoginFlow) GetState() interface{} { + if o == nil { + var ret interface{} + return ret + } + + return o.State +} + +// GetStateOk returns a tuple with the State field value +// 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 *LoginFlow) GetStateOk() (*interface{}, bool) { + if o == nil || o.State == nil { + return nil, false + } + return &o.State, true +} + +// SetState sets field value +func (o *LoginFlow) SetState(v interface{}) { + o.State = v +} + // GetType returns the Type field value func (o *LoginFlow) GetType() string { if o == nil { @@ -539,6 +568,9 @@ func (o LoginFlow) MarshalJSON() ([]byte, error) { if o.SessionTokenExchangeCode != nil { toSerialize["session_token_exchange_code"] = o.SessionTokenExchangeCode } + if o.State != nil { + toSerialize["state"] = o.State + } if true { toSerialize["type"] = o.Type } diff --git a/internal/client-go/model_login_flow_state.go b/internal/client-go/model_login_flow_state.go new file mode 100644 index 000000000000..ce5570b79032 --- /dev/null +++ b/internal/client-go/model_login_flow_state.go @@ -0,0 +1,85 @@ +/* + * Ory Identities API + * + * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. + * + * API version: + * Contact: office@ory.sh + */ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +import ( + "encoding/json" + "fmt" +) + +// LoginFlowState The state represents the state of the login flow. choose_method: ask the user to choose a method (e.g. login account via email) sent_email: the email has been sent to the user passed_challenge: the request was successful and the login challenge was passed. +type LoginFlowState string + +// List of loginFlowState +const ( + LOGINFLOWSTATE_CHOOSE_METHOD LoginFlowState = "choose_method" + LOGINFLOWSTATE_SENT_EMAIL LoginFlowState = "sent_email" + LOGINFLOWSTATE_PASSED_CHALLENGE LoginFlowState = "passed_challenge" +) + +func (v *LoginFlowState) UnmarshalJSON(src []byte) error { + var value string + err := json.Unmarshal(src, &value) + if err != nil { + return err + } + enumTypeValue := LoginFlowState(value) + for _, existing := range []LoginFlowState{"choose_method", "sent_email", "passed_challenge"} { + if existing == enumTypeValue { + *v = enumTypeValue + return nil + } + } + + return fmt.Errorf("%+v is not a valid LoginFlowState", value) +} + +// Ptr returns reference to loginFlowState value +func (v LoginFlowState) Ptr() *LoginFlowState { + return &v +} + +type NullableLoginFlowState struct { + value *LoginFlowState + isSet bool +} + +func (v NullableLoginFlowState) Get() *LoginFlowState { + return v.value +} + +func (v *NullableLoginFlowState) Set(val *LoginFlowState) { + v.value = val + v.isSet = true +} + +func (v NullableLoginFlowState) IsSet() bool { + return v.isSet +} + +func (v *NullableLoginFlowState) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableLoginFlowState(val *LoginFlowState) *NullableLoginFlowState { + return &NullableLoginFlowState{value: val, isSet: true} +} + +func (v NullableLoginFlowState) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableLoginFlowState) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/client-go/model_message.go b/internal/client-go/model_message.go index 3a6f3f92362b..f0452185f169 100644 --- a/internal/client-go/model_message.go +++ b/internal/client-go/model_message.go @@ -28,7 +28,7 @@ type Message struct { SendCount int64 `json:"send_count"` Status CourierMessageStatus `json:"status"` Subject string `json:"subject"` - // recovery_invalid TypeRecoveryInvalid recovery_valid TypeRecoveryValid recovery_code_invalid TypeRecoveryCodeInvalid recovery_code_valid TypeRecoveryCodeValid verification_invalid TypeVerificationInvalid verification_valid TypeVerificationValid verification_code_invalid TypeVerificationCodeInvalid verification_code_valid TypeVerificationCodeValid otp TypeOTP stub TypeTestStub + // recovery_invalid TypeRecoveryInvalid recovery_valid TypeRecoveryValid recovery_code_invalid TypeRecoveryCodeInvalid recovery_code_valid TypeRecoveryCodeValid verification_invalid TypeVerificationInvalid verification_valid TypeVerificationValid verification_code_invalid TypeVerificationCodeInvalid verification_code_valid TypeVerificationCodeValid otp TypeOTP stub TypeTestStub login_code_valid TypeLoginCodeValid registration_code_valid TypeRegistrationCodeValid TemplateType string `json:"template_type"` Type CourierMessageType `json:"type"` // UpdatedAt is a helper struct field for gobuffalo.pop. diff --git a/internal/client-go/model_recovery_flow.go b/internal/client-go/model_recovery_flow.go index 6ae19ebd60e6..acf4ff667df3 100644 --- a/internal/client-go/model_recovery_flow.go +++ b/internal/client-go/model_recovery_flow.go @@ -29,8 +29,9 @@ type RecoveryFlow struct { // 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. - ReturnTo *string `json:"return_to,omitempty"` - State RecoveryFlowState `json:"state"` + ReturnTo *string `json:"return_to,omitempty"` + // State represents the state of this request: choose_method: ask the user to choose a method (e.g. recover account via email) sent_email: the email has been sent to the user passed_challenge: the request was successful and the recovery challenge was passed. + State interface{} `json:"state"` // The flow type can either be `api` or `browser`. Type string `json:"type"` Ui UiContainer `json:"ui"` @@ -40,7 +41,7 @@ type RecoveryFlow struct { // 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 NewRecoveryFlow(expiresAt time.Time, id string, issuedAt time.Time, requestUrl string, state RecoveryFlowState, type_ string, ui UiContainer) *RecoveryFlow { +func NewRecoveryFlow(expiresAt time.Time, id string, issuedAt time.Time, requestUrl string, state interface{}, type_ string, ui UiContainer) *RecoveryFlow { this := RecoveryFlow{} this.ExpiresAt = expiresAt this.Id = id @@ -221,9 +222,10 @@ func (o *RecoveryFlow) SetReturnTo(v string) { } // GetState returns the State field value -func (o *RecoveryFlow) GetState() RecoveryFlowState { +// If the value is explicit nil, the zero value for interface{} will be returned +func (o *RecoveryFlow) GetState() interface{} { if o == nil { - var ret RecoveryFlowState + var ret interface{} return ret } @@ -232,15 +234,16 @@ func (o *RecoveryFlow) GetState() RecoveryFlowState { // GetStateOk returns a tuple with the State field value // and a boolean to check if the value has been set. -func (o *RecoveryFlow) GetStateOk() (*RecoveryFlowState, bool) { - if o == nil { +// NOTE: If the value is an explicit nil, `nil, true` will be returned +func (o *RecoveryFlow) GetStateOk() (*interface{}, bool) { + if o == nil || o.State == nil { return nil, false } return &o.State, true } // SetState sets field value -func (o *RecoveryFlow) SetState(v RecoveryFlowState) { +func (o *RecoveryFlow) SetState(v interface{}) { o.State = v } @@ -312,7 +315,7 @@ func (o RecoveryFlow) MarshalJSON() ([]byte, error) { if o.ReturnTo != nil { toSerialize["return_to"] = o.ReturnTo } - if true { + if o.State != nil { toSerialize["state"] = o.State } if true { diff --git a/internal/client-go/model_registration_flow.go b/internal/client-go/model_registration_flow.go index fe9f697b5551..9b08288d6a16 100644 --- a/internal/client-go/model_registration_flow.go +++ b/internal/client-go/model_registration_flow.go @@ -34,6 +34,8 @@ type RegistrationFlow struct { ReturnTo *string `json:"return_to,omitempty"` // SessionTokenExchangeCode holds the secret code that the client can use to retrieve a session token after the flow has been completed. This is only set if the client has requested a session token exchange code, and if the flow is of type \"api\", and only on creating the flow. SessionTokenExchangeCode *string `json:"session_token_exchange_code,omitempty"` + // State represents the state of this request: choose_method: ask the user to choose a method (e.g. registration with email) sent_email: the email has been sent to the user passed_challenge: the request was successful and the registration challenge was passed. + State interface{} `json:"state"` // TransientPayload is used to pass data from the registration to a webhook TransientPayload map[string]interface{} `json:"transient_payload,omitempty"` // The flow type can either be `api` or `browser`. @@ -45,12 +47,13 @@ type RegistrationFlow struct { // 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 NewRegistrationFlow(expiresAt time.Time, id string, issuedAt time.Time, requestUrl string, type_ string, ui UiContainer) *RegistrationFlow { +func NewRegistrationFlow(expiresAt time.Time, id string, issuedAt time.Time, requestUrl string, state interface{}, type_ string, ui UiContainer) *RegistrationFlow { this := RegistrationFlow{} this.ExpiresAt = expiresAt this.Id = id this.IssuedAt = issuedAt this.RequestUrl = requestUrl + this.State = state this.Type = type_ this.Ui = ui return &this @@ -320,6 +323,32 @@ func (o *RegistrationFlow) SetSessionTokenExchangeCode(v string) { o.SessionTokenExchangeCode = &v } +// GetState returns the State field value +// If the value is explicit nil, the zero value for interface{} will be returned +func (o *RegistrationFlow) GetState() interface{} { + if o == nil { + var ret interface{} + return ret + } + + return o.State +} + +// GetStateOk returns a tuple with the State field value +// 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 *RegistrationFlow) GetStateOk() (*interface{}, bool) { + if o == nil || o.State == nil { + return nil, false + } + return &o.State, true +} + +// SetState sets field value +func (o *RegistrationFlow) SetState(v interface{}) { + o.State = v +} + // GetTransientPayload returns the TransientPayload field value if set, zero value otherwise. func (o *RegistrationFlow) GetTransientPayload() map[string]interface{} { if o == nil || o.TransientPayload == nil { @@ -429,6 +458,9 @@ func (o RegistrationFlow) MarshalJSON() ([]byte, error) { if o.SessionTokenExchangeCode != nil { toSerialize["session_token_exchange_code"] = o.SessionTokenExchangeCode } + if o.State != nil { + toSerialize["state"] = o.State + } if o.TransientPayload != nil { toSerialize["transient_payload"] = o.TransientPayload } diff --git a/internal/client-go/model_registration_flow_state.go b/internal/client-go/model_registration_flow_state.go new file mode 100644 index 000000000000..86f3fd38cff0 --- /dev/null +++ b/internal/client-go/model_registration_flow_state.go @@ -0,0 +1,85 @@ +/* + * Ory Identities API + * + * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. + * + * API version: + * Contact: office@ory.sh + */ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +import ( + "encoding/json" + "fmt" +) + +// RegistrationFlowState choose_method: ask the user to choose a method (e.g. registration with email) sent_email: the email has been sent to the user passed_challenge: the request was successful and the registration challenge was passed. +type RegistrationFlowState string + +// List of registrationFlowState +const ( + REGISTRATIONFLOWSTATE_CHOOSE_METHOD RegistrationFlowState = "choose_method" + REGISTRATIONFLOWSTATE_SENT_EMAIL RegistrationFlowState = "sent_email" + REGISTRATIONFLOWSTATE_PASSED_CHALLENGE RegistrationFlowState = "passed_challenge" +) + +func (v *RegistrationFlowState) UnmarshalJSON(src []byte) error { + var value string + err := json.Unmarshal(src, &value) + if err != nil { + return err + } + enumTypeValue := RegistrationFlowState(value) + for _, existing := range []RegistrationFlowState{"choose_method", "sent_email", "passed_challenge"} { + if existing == enumTypeValue { + *v = enumTypeValue + return nil + } + } + + return fmt.Errorf("%+v is not a valid RegistrationFlowState", value) +} + +// Ptr returns reference to registrationFlowState value +func (v RegistrationFlowState) Ptr() *RegistrationFlowState { + return &v +} + +type NullableRegistrationFlowState struct { + value *RegistrationFlowState + isSet bool +} + +func (v NullableRegistrationFlowState) Get() *RegistrationFlowState { + return v.value +} + +func (v *NullableRegistrationFlowState) Set(val *RegistrationFlowState) { + v.value = val + v.isSet = true +} + +func (v NullableRegistrationFlowState) IsSet() bool { + return v.isSet +} + +func (v *NullableRegistrationFlowState) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableRegistrationFlowState(val *RegistrationFlowState) *NullableRegistrationFlowState { + return &NullableRegistrationFlowState{value: val, isSet: true} +} + +func (v NullableRegistrationFlowState) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableRegistrationFlowState) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/client-go/model_self_service_login_flow_state.go b/internal/client-go/model_self_service_login_flow_state.go new file mode 100644 index 000000000000..093d300fe207 --- /dev/null +++ b/internal/client-go/model_self_service_login_flow_state.go @@ -0,0 +1,85 @@ +/* + * Ory Identities API + * + * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. + * + * API version: + * Contact: office@ory.sh + */ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +import ( + "encoding/json" + "fmt" +) + +// SelfServiceLoginFlowState The state represents the state of the login flow. choose_method: ask the user to choose a method (e.g. login account via email) sent_email: the email has been sent to the user passed_challenge: the request was successful and the login challenge was passed. +type SelfServiceLoginFlowState string + +// List of SelfServiceLoginFlowState +const ( + SELFSERVICELOGINFLOWSTATE_CHOOSE_METHOD SelfServiceLoginFlowState = "choose_method" + SELFSERVICELOGINFLOWSTATE_SENT_EMAIL SelfServiceLoginFlowState = "sent_email" + SELFSERVICELOGINFLOWSTATE_PASSED_CHALLENGE SelfServiceLoginFlowState = "passed_challenge" +) + +func (v *SelfServiceLoginFlowState) UnmarshalJSON(src []byte) error { + var value string + err := json.Unmarshal(src, &value) + if err != nil { + return err + } + enumTypeValue := SelfServiceLoginFlowState(value) + for _, existing := range []SelfServiceLoginFlowState{"choose_method", "sent_email", "passed_challenge"} { + if existing == enumTypeValue { + *v = enumTypeValue + return nil + } + } + + return fmt.Errorf("%+v is not a valid SelfServiceLoginFlowState", value) +} + +// Ptr returns reference to SelfServiceLoginFlowState value +func (v SelfServiceLoginFlowState) Ptr() *SelfServiceLoginFlowState { + return &v +} + +type NullableSelfServiceLoginFlowState struct { + value *SelfServiceLoginFlowState + isSet bool +} + +func (v NullableSelfServiceLoginFlowState) Get() *SelfServiceLoginFlowState { + return v.value +} + +func (v *NullableSelfServiceLoginFlowState) Set(val *SelfServiceLoginFlowState) { + v.value = val + v.isSet = true +} + +func (v NullableSelfServiceLoginFlowState) IsSet() bool { + return v.isSet +} + +func (v *NullableSelfServiceLoginFlowState) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableSelfServiceLoginFlowState(val *SelfServiceLoginFlowState) *NullableSelfServiceLoginFlowState { + return &NullableSelfServiceLoginFlowState{value: val, isSet: true} +} + +func (v NullableSelfServiceLoginFlowState) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableSelfServiceLoginFlowState) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/client-go/model_self_service_recovery_flow_state.go b/internal/client-go/model_self_service_recovery_flow_state.go index efb98b8d127e..ae492a51d26b 100644 --- a/internal/client-go/model_self_service_recovery_flow_state.go +++ b/internal/client-go/model_self_service_recovery_flow_state.go @@ -1,13 +1,10 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - /* - * Ory Kratos API + * Ory Identities 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. + * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. * * API version: - * Contact: hi@ory.sh + * Contact: office@ory.sh */ // Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. @@ -22,7 +19,7 @@ import ( // SelfServiceRecoveryFlowState The state represents the state of the recovery flow. choose_method: ask the user to choose a method (e.g. recover account via email) sent_email: the email has been sent to the user passed_challenge: the request was successful and the recovery challenge was passed. type SelfServiceRecoveryFlowState string -// List of selfServiceRecoveryFlowState +// List of SelfServiceRecoveryFlowState const ( SELFSERVICERECOVERYFLOWSTATE_CHOOSE_METHOD SelfServiceRecoveryFlowState = "choose_method" SELFSERVICERECOVERYFLOWSTATE_SENT_EMAIL SelfServiceRecoveryFlowState = "sent_email" @@ -46,7 +43,7 @@ func (v *SelfServiceRecoveryFlowState) UnmarshalJSON(src []byte) error { return fmt.Errorf("%+v is not a valid SelfServiceRecoveryFlowState", value) } -// Ptr returns reference to selfServiceRecoveryFlowState value +// Ptr returns reference to SelfServiceRecoveryFlowState value func (v SelfServiceRecoveryFlowState) Ptr() *SelfServiceRecoveryFlowState { return &v } diff --git a/internal/client-go/model_self_service_registration_flow_state.go b/internal/client-go/model_self_service_registration_flow_state.go new file mode 100644 index 000000000000..a84387784ef1 --- /dev/null +++ b/internal/client-go/model_self_service_registration_flow_state.go @@ -0,0 +1,85 @@ +/* + * Ory Identities API + * + * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. + * + * API version: + * Contact: office@ory.sh + */ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +import ( + "encoding/json" + "fmt" +) + +// SelfServiceRegistrationFlowState choose_method: ask the user to choose a method (e.g. registration with email) sent_email: the email has been sent to the user passed_challenge: the request was successful and the registration challenge was passed. +type SelfServiceRegistrationFlowState string + +// List of SelfServiceRegistrationFlowState +const ( + SELFSERVICEREGISTRATIONFLOWSTATE_CHOOSE_METHOD SelfServiceRegistrationFlowState = "choose_method" + SELFSERVICEREGISTRATIONFLOWSTATE_SENT_EMAIL SelfServiceRegistrationFlowState = "sent_email" + SELFSERVICEREGISTRATIONFLOWSTATE_PASSED_CHALLENGE SelfServiceRegistrationFlowState = "passed_challenge" +) + +func (v *SelfServiceRegistrationFlowState) UnmarshalJSON(src []byte) error { + var value string + err := json.Unmarshal(src, &value) + if err != nil { + return err + } + enumTypeValue := SelfServiceRegistrationFlowState(value) + for _, existing := range []SelfServiceRegistrationFlowState{"choose_method", "sent_email", "passed_challenge"} { + if existing == enumTypeValue { + *v = enumTypeValue + return nil + } + } + + return fmt.Errorf("%+v is not a valid SelfServiceRegistrationFlowState", value) +} + +// Ptr returns reference to SelfServiceRegistrationFlowState value +func (v SelfServiceRegistrationFlowState) Ptr() *SelfServiceRegistrationFlowState { + return &v +} + +type NullableSelfServiceRegistrationFlowState struct { + value *SelfServiceRegistrationFlowState + isSet bool +} + +func (v NullableSelfServiceRegistrationFlowState) Get() *SelfServiceRegistrationFlowState { + return v.value +} + +func (v *NullableSelfServiceRegistrationFlowState) Set(val *SelfServiceRegistrationFlowState) { + v.value = val + v.isSet = true +} + +func (v NullableSelfServiceRegistrationFlowState) IsSet() bool { + return v.isSet +} + +func (v *NullableSelfServiceRegistrationFlowState) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableSelfServiceRegistrationFlowState(val *SelfServiceRegistrationFlowState) *NullableSelfServiceRegistrationFlowState { + return &NullableSelfServiceRegistrationFlowState{value: val, isSet: true} +} + +func (v NullableSelfServiceRegistrationFlowState) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableSelfServiceRegistrationFlowState) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/client-go/model_self_service_settings_flow_state.go b/internal/client-go/model_self_service_settings_flow_state.go index 3a95e53bf169..9163efb643e5 100644 --- a/internal/client-go/model_self_service_settings_flow_state.go +++ b/internal/client-go/model_self_service_settings_flow_state.go @@ -1,13 +1,10 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - /* - * Ory Kratos API + * Ory Identities 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. + * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. * * API version: - * Contact: hi@ory.sh + * Contact: office@ory.sh */ // Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. @@ -22,7 +19,7 @@ import ( // SelfServiceSettingsFlowState show_form: No user data has been collected, or it is invalid, and thus the form should be shown. success: Indicates that the settings flow has been updated successfully with the provided data. Done will stay true when repeatedly checking. If set to true, done will revert back to false only when a flow with invalid (e.g. \"please use a valid phone number\") data was sent. type SelfServiceSettingsFlowState string -// List of selfServiceSettingsFlowState +// List of SelfServiceSettingsFlowState const ( SELFSERVICESETTINGSFLOWSTATE_SHOW_FORM SelfServiceSettingsFlowState = "show_form" SELFSERVICESETTINGSFLOWSTATE_SUCCESS SelfServiceSettingsFlowState = "success" @@ -45,7 +42,7 @@ func (v *SelfServiceSettingsFlowState) UnmarshalJSON(src []byte) error { return fmt.Errorf("%+v is not a valid SelfServiceSettingsFlowState", value) } -// Ptr returns reference to selfServiceSettingsFlowState value +// Ptr returns reference to SelfServiceSettingsFlowState value func (v SelfServiceSettingsFlowState) Ptr() *SelfServiceSettingsFlowState { return &v } diff --git a/internal/client-go/model_self_service_verification_flow_state.go b/internal/client-go/model_self_service_verification_flow_state.go index 03937f84bd45..a3b9691ab038 100644 --- a/internal/client-go/model_self_service_verification_flow_state.go +++ b/internal/client-go/model_self_service_verification_flow_state.go @@ -1,13 +1,10 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - /* - * Ory Kratos API + * Ory Identities 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. + * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. * * API version: - * Contact: hi@ory.sh + * Contact: office@ory.sh */ // Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. @@ -22,7 +19,7 @@ import ( // SelfServiceVerificationFlowState The state represents the state of the verification flow. choose_method: ask the user to choose a method (e.g. recover account via email) sent_email: the email has been sent to the user passed_challenge: the request was successful and the recovery challenge was passed. type SelfServiceVerificationFlowState string -// List of selfServiceVerificationFlowState +// List of SelfServiceVerificationFlowState const ( SELFSERVICEVERIFICATIONFLOWSTATE_CHOOSE_METHOD SelfServiceVerificationFlowState = "choose_method" SELFSERVICEVERIFICATIONFLOWSTATE_SENT_EMAIL SelfServiceVerificationFlowState = "sent_email" @@ -46,7 +43,7 @@ func (v *SelfServiceVerificationFlowState) UnmarshalJSON(src []byte) error { return fmt.Errorf("%+v is not a valid SelfServiceVerificationFlowState", value) } -// Ptr returns reference to selfServiceVerificationFlowState value +// Ptr returns reference to SelfServiceVerificationFlowState value func (v SelfServiceVerificationFlowState) Ptr() *SelfServiceVerificationFlowState { return &v } diff --git a/internal/client-go/model_settings_flow.go b/internal/client-go/model_settings_flow.go index a1dc0aa98dc6..fa5cd9317c54 100644 --- a/internal/client-go/model_settings_flow.go +++ b/internal/client-go/model_settings_flow.go @@ -32,8 +32,9 @@ type SettingsFlow struct { // 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. - ReturnTo *string `json:"return_to,omitempty"` - State SettingsFlowState `json:"state"` + ReturnTo *string `json:"return_to,omitempty"` + // State represents the state of this flow. It knows two states: show_form: No user data has been collected, or it is invalid, and thus the form should be shown. success: Indicates that the settings flow has been updated successfully with the provided data. Done will stay true when repeatedly checking. If set to true, done will revert back to false only when a flow with invalid (e.g. \"please use a valid phone number\") data was sent. + State interface{} `json:"state"` // The flow type can either be `api` or `browser`. Type string `json:"type"` Ui UiContainer `json:"ui"` @@ -43,7 +44,7 @@ type SettingsFlow struct { // 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 NewSettingsFlow(expiresAt time.Time, id string, identity Identity, issuedAt time.Time, requestUrl string, state SettingsFlowState, type_ string, ui UiContainer) *SettingsFlow { +func NewSettingsFlow(expiresAt time.Time, id string, identity Identity, issuedAt time.Time, requestUrl string, state interface{}, type_ string, ui UiContainer) *SettingsFlow { this := SettingsFlow{} this.ExpiresAt = expiresAt this.Id = id @@ -281,9 +282,10 @@ func (o *SettingsFlow) SetReturnTo(v string) { } // GetState returns the State field value -func (o *SettingsFlow) GetState() SettingsFlowState { +// If the value is explicit nil, the zero value for interface{} will be returned +func (o *SettingsFlow) GetState() interface{} { if o == nil { - var ret SettingsFlowState + var ret interface{} return ret } @@ -292,15 +294,16 @@ func (o *SettingsFlow) GetState() SettingsFlowState { // GetStateOk returns a tuple with the State field value // and a boolean to check if the value has been set. -func (o *SettingsFlow) GetStateOk() (*SettingsFlowState, bool) { - if o == nil { +// NOTE: If the value is an explicit nil, `nil, true` will be returned +func (o *SettingsFlow) GetStateOk() (*interface{}, bool) { + if o == nil || o.State == nil { return nil, false } return &o.State, true } // SetState sets field value -func (o *SettingsFlow) SetState(v SettingsFlowState) { +func (o *SettingsFlow) SetState(v interface{}) { o.State = v } @@ -378,7 +381,7 @@ func (o SettingsFlow) MarshalJSON() ([]byte, error) { if o.ReturnTo != nil { toSerialize["return_to"] = o.ReturnTo } - if true { + if o.State != nil { toSerialize["state"] = o.State } if true { diff --git a/internal/client-go/model_update_login_flow_body.go b/internal/client-go/model_update_login_flow_body.go index 1aa032062a4b..36033328e78d 100644 --- a/internal/client-go/model_update_login_flow_body.go +++ b/internal/client-go/model_update_login_flow_body.go @@ -18,6 +18,7 @@ import ( // UpdateLoginFlowBody - struct for UpdateLoginFlowBody type UpdateLoginFlowBody struct { + UpdateLoginFlowWithCodeMethod *UpdateLoginFlowWithCodeMethod UpdateLoginFlowWithLookupSecretMethod *UpdateLoginFlowWithLookupSecretMethod UpdateLoginFlowWithOidcMethod *UpdateLoginFlowWithOidcMethod UpdateLoginFlowWithPasswordMethod *UpdateLoginFlowWithPasswordMethod @@ -25,6 +26,13 @@ type UpdateLoginFlowBody struct { UpdateLoginFlowWithWebAuthnMethod *UpdateLoginFlowWithWebAuthnMethod } +// UpdateLoginFlowWithCodeMethodAsUpdateLoginFlowBody is a convenience function that returns UpdateLoginFlowWithCodeMethod wrapped in UpdateLoginFlowBody +func UpdateLoginFlowWithCodeMethodAsUpdateLoginFlowBody(v *UpdateLoginFlowWithCodeMethod) UpdateLoginFlowBody { + return UpdateLoginFlowBody{ + UpdateLoginFlowWithCodeMethod: v, + } +} + // UpdateLoginFlowWithLookupSecretMethodAsUpdateLoginFlowBody is a convenience function that returns UpdateLoginFlowWithLookupSecretMethod wrapped in UpdateLoginFlowBody func UpdateLoginFlowWithLookupSecretMethodAsUpdateLoginFlowBody(v *UpdateLoginFlowWithLookupSecretMethod) UpdateLoginFlowBody { return UpdateLoginFlowBody{ @@ -64,6 +72,19 @@ func UpdateLoginFlowWithWebAuthnMethodAsUpdateLoginFlowBody(v *UpdateLoginFlowWi func (dst *UpdateLoginFlowBody) UnmarshalJSON(data []byte) error { var err error match := 0 + // try to unmarshal data into UpdateLoginFlowWithCodeMethod + err = newStrictDecoder(data).Decode(&dst.UpdateLoginFlowWithCodeMethod) + if err == nil { + jsonUpdateLoginFlowWithCodeMethod, _ := json.Marshal(dst.UpdateLoginFlowWithCodeMethod) + if string(jsonUpdateLoginFlowWithCodeMethod) == "{}" { // empty struct + dst.UpdateLoginFlowWithCodeMethod = nil + } else { + match++ + } + } else { + dst.UpdateLoginFlowWithCodeMethod = nil + } + // try to unmarshal data into UpdateLoginFlowWithLookupSecretMethod err = newStrictDecoder(data).Decode(&dst.UpdateLoginFlowWithLookupSecretMethod) if err == nil { @@ -131,6 +152,7 @@ func (dst *UpdateLoginFlowBody) UnmarshalJSON(data []byte) error { if match > 1 { // more than 1 match // reset to nil + dst.UpdateLoginFlowWithCodeMethod = nil dst.UpdateLoginFlowWithLookupSecretMethod = nil dst.UpdateLoginFlowWithOidcMethod = nil dst.UpdateLoginFlowWithPasswordMethod = nil @@ -147,6 +169,10 @@ func (dst *UpdateLoginFlowBody) UnmarshalJSON(data []byte) error { // Marshal data from the first non-nil pointers in the struct to JSON func (src UpdateLoginFlowBody) MarshalJSON() ([]byte, error) { + if src.UpdateLoginFlowWithCodeMethod != nil { + return json.Marshal(&src.UpdateLoginFlowWithCodeMethod) + } + if src.UpdateLoginFlowWithLookupSecretMethod != nil { return json.Marshal(&src.UpdateLoginFlowWithLookupSecretMethod) } @@ -175,6 +201,10 @@ func (obj *UpdateLoginFlowBody) GetActualInstance() interface{} { if obj == nil { return nil } + if obj.UpdateLoginFlowWithCodeMethod != nil { + return obj.UpdateLoginFlowWithCodeMethod + } + if obj.UpdateLoginFlowWithLookupSecretMethod != nil { return obj.UpdateLoginFlowWithLookupSecretMethod } diff --git a/internal/client-go/model_update_login_flow_with_code_method.go b/internal/client-go/model_update_login_flow_with_code_method.go new file mode 100644 index 000000000000..bd97ab583ebc --- /dev/null +++ b/internal/client-go/model_update_login_flow_with_code_method.go @@ -0,0 +1,249 @@ +/* + * Ory Identities API + * + * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. + * + * API version: + * Contact: office@ory.sh + */ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +import ( + "encoding/json" +) + +// UpdateLoginFlowWithCodeMethod Update Login flow using the code method +type UpdateLoginFlowWithCodeMethod struct { + // Code is the 6 digits code sent to the user + Code *string `json:"code,omitempty"` + // CSRFToken is the anti-CSRF token + CsrfToken string `json:"csrf_token"` + // Identifier is the code identifier The identifier requires that the user has already completed the registration or settings with code flow. + Identifier *string `json:"identifier,omitempty"` + // Method should be set to \"code\" when logging in using the code strategy. + Method string `json:"method"` + // Resend is set when the user wants to resend the code + Resend *string `json:"resend,omitempty"` +} + +// NewUpdateLoginFlowWithCodeMethod instantiates a new UpdateLoginFlowWithCodeMethod 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 NewUpdateLoginFlowWithCodeMethod(csrfToken string, method string) *UpdateLoginFlowWithCodeMethod { + this := UpdateLoginFlowWithCodeMethod{} + this.CsrfToken = csrfToken + this.Method = method + return &this +} + +// NewUpdateLoginFlowWithCodeMethodWithDefaults instantiates a new UpdateLoginFlowWithCodeMethod 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 NewUpdateLoginFlowWithCodeMethodWithDefaults() *UpdateLoginFlowWithCodeMethod { + this := UpdateLoginFlowWithCodeMethod{} + return &this +} + +// GetCode returns the Code field value if set, zero value otherwise. +func (o *UpdateLoginFlowWithCodeMethod) GetCode() string { + if o == nil || o.Code == nil { + var ret string + return ret + } + return *o.Code +} + +// GetCodeOk returns a tuple with the Code field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UpdateLoginFlowWithCodeMethod) GetCodeOk() (*string, bool) { + if o == nil || o.Code == nil { + return nil, false + } + return o.Code, true +} + +// HasCode returns a boolean if a field has been set. +func (o *UpdateLoginFlowWithCodeMethod) HasCode() bool { + if o != nil && o.Code != nil { + return true + } + + return false +} + +// SetCode gets a reference to the given string and assigns it to the Code field. +func (o *UpdateLoginFlowWithCodeMethod) SetCode(v string) { + o.Code = &v +} + +// GetCsrfToken returns the CsrfToken field value +func (o *UpdateLoginFlowWithCodeMethod) GetCsrfToken() string { + if o == nil { + var ret string + return ret + } + + return o.CsrfToken +} + +// GetCsrfTokenOk returns a tuple with the CsrfToken field value +// and a boolean to check if the value has been set. +func (o *UpdateLoginFlowWithCodeMethod) GetCsrfTokenOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.CsrfToken, true +} + +// SetCsrfToken sets field value +func (o *UpdateLoginFlowWithCodeMethod) SetCsrfToken(v string) { + o.CsrfToken = v +} + +// GetIdentifier returns the Identifier field value if set, zero value otherwise. +func (o *UpdateLoginFlowWithCodeMethod) GetIdentifier() string { + if o == nil || o.Identifier == nil { + var ret string + return ret + } + return *o.Identifier +} + +// GetIdentifierOk returns a tuple with the Identifier field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UpdateLoginFlowWithCodeMethod) GetIdentifierOk() (*string, bool) { + if o == nil || o.Identifier == nil { + return nil, false + } + return o.Identifier, true +} + +// HasIdentifier returns a boolean if a field has been set. +func (o *UpdateLoginFlowWithCodeMethod) HasIdentifier() bool { + if o != nil && o.Identifier != nil { + return true + } + + return false +} + +// SetIdentifier gets a reference to the given string and assigns it to the Identifier field. +func (o *UpdateLoginFlowWithCodeMethod) SetIdentifier(v string) { + o.Identifier = &v +} + +// GetMethod returns the Method field value +func (o *UpdateLoginFlowWithCodeMethod) GetMethod() string { + if o == nil { + var ret string + return ret + } + + return o.Method +} + +// GetMethodOk returns a tuple with the Method field value +// and a boolean to check if the value has been set. +func (o *UpdateLoginFlowWithCodeMethod) GetMethodOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Method, true +} + +// SetMethod sets field value +func (o *UpdateLoginFlowWithCodeMethod) SetMethod(v string) { + o.Method = v +} + +// GetResend returns the Resend field value if set, zero value otherwise. +func (o *UpdateLoginFlowWithCodeMethod) GetResend() string { + if o == nil || o.Resend == nil { + var ret string + return ret + } + return *o.Resend +} + +// GetResendOk returns a tuple with the Resend field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UpdateLoginFlowWithCodeMethod) GetResendOk() (*string, bool) { + if o == nil || o.Resend == nil { + return nil, false + } + return o.Resend, true +} + +// HasResend returns a boolean if a field has been set. +func (o *UpdateLoginFlowWithCodeMethod) HasResend() bool { + if o != nil && o.Resend != nil { + return true + } + + return false +} + +// SetResend gets a reference to the given string and assigns it to the Resend field. +func (o *UpdateLoginFlowWithCodeMethod) SetResend(v string) { + o.Resend = &v +} + +func (o UpdateLoginFlowWithCodeMethod) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if o.Code != nil { + toSerialize["code"] = o.Code + } + if true { + toSerialize["csrf_token"] = o.CsrfToken + } + if o.Identifier != nil { + toSerialize["identifier"] = o.Identifier + } + if true { + toSerialize["method"] = o.Method + } + if o.Resend != nil { + toSerialize["resend"] = o.Resend + } + return json.Marshal(toSerialize) +} + +type NullableUpdateLoginFlowWithCodeMethod struct { + value *UpdateLoginFlowWithCodeMethod + isSet bool +} + +func (v NullableUpdateLoginFlowWithCodeMethod) Get() *UpdateLoginFlowWithCodeMethod { + return v.value +} + +func (v *NullableUpdateLoginFlowWithCodeMethod) Set(val *UpdateLoginFlowWithCodeMethod) { + v.value = val + v.isSet = true +} + +func (v NullableUpdateLoginFlowWithCodeMethod) IsSet() bool { + return v.isSet +} + +func (v *NullableUpdateLoginFlowWithCodeMethod) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableUpdateLoginFlowWithCodeMethod(val *UpdateLoginFlowWithCodeMethod) *NullableUpdateLoginFlowWithCodeMethod { + return &NullableUpdateLoginFlowWithCodeMethod{value: val, isSet: true} +} + +func (v NullableUpdateLoginFlowWithCodeMethod) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableUpdateLoginFlowWithCodeMethod) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/client-go/model_update_registration_flow_body.go b/internal/client-go/model_update_registration_flow_body.go index 1a662fc62416..0e36a95f635f 100644 --- a/internal/client-go/model_update_registration_flow_body.go +++ b/internal/client-go/model_update_registration_flow_body.go @@ -18,11 +18,19 @@ import ( // UpdateRegistrationFlowBody - Update Registration Request Body type UpdateRegistrationFlowBody struct { + UpdateRegistrationFlowWithCodeMethod *UpdateRegistrationFlowWithCodeMethod UpdateRegistrationFlowWithOidcMethod *UpdateRegistrationFlowWithOidcMethod UpdateRegistrationFlowWithPasswordMethod *UpdateRegistrationFlowWithPasswordMethod UpdateRegistrationFlowWithWebAuthnMethod *UpdateRegistrationFlowWithWebAuthnMethod } +// UpdateRegistrationFlowWithCodeMethodAsUpdateRegistrationFlowBody is a convenience function that returns UpdateRegistrationFlowWithCodeMethod wrapped in UpdateRegistrationFlowBody +func UpdateRegistrationFlowWithCodeMethodAsUpdateRegistrationFlowBody(v *UpdateRegistrationFlowWithCodeMethod) UpdateRegistrationFlowBody { + return UpdateRegistrationFlowBody{ + UpdateRegistrationFlowWithCodeMethod: v, + } +} + // UpdateRegistrationFlowWithOidcMethodAsUpdateRegistrationFlowBody is a convenience function that returns UpdateRegistrationFlowWithOidcMethod wrapped in UpdateRegistrationFlowBody func UpdateRegistrationFlowWithOidcMethodAsUpdateRegistrationFlowBody(v *UpdateRegistrationFlowWithOidcMethod) UpdateRegistrationFlowBody { return UpdateRegistrationFlowBody{ @@ -48,6 +56,19 @@ func UpdateRegistrationFlowWithWebAuthnMethodAsUpdateRegistrationFlowBody(v *Upd func (dst *UpdateRegistrationFlowBody) UnmarshalJSON(data []byte) error { var err error match := 0 + // try to unmarshal data into UpdateRegistrationFlowWithCodeMethod + err = newStrictDecoder(data).Decode(&dst.UpdateRegistrationFlowWithCodeMethod) + if err == nil { + jsonUpdateRegistrationFlowWithCodeMethod, _ := json.Marshal(dst.UpdateRegistrationFlowWithCodeMethod) + if string(jsonUpdateRegistrationFlowWithCodeMethod) == "{}" { // empty struct + dst.UpdateRegistrationFlowWithCodeMethod = nil + } else { + match++ + } + } else { + dst.UpdateRegistrationFlowWithCodeMethod = nil + } + // try to unmarshal data into UpdateRegistrationFlowWithOidcMethod err = newStrictDecoder(data).Decode(&dst.UpdateRegistrationFlowWithOidcMethod) if err == nil { @@ -89,6 +110,7 @@ func (dst *UpdateRegistrationFlowBody) UnmarshalJSON(data []byte) error { if match > 1 { // more than 1 match // reset to nil + dst.UpdateRegistrationFlowWithCodeMethod = nil dst.UpdateRegistrationFlowWithOidcMethod = nil dst.UpdateRegistrationFlowWithPasswordMethod = nil dst.UpdateRegistrationFlowWithWebAuthnMethod = nil @@ -103,6 +125,10 @@ func (dst *UpdateRegistrationFlowBody) UnmarshalJSON(data []byte) error { // Marshal data from the first non-nil pointers in the struct to JSON func (src UpdateRegistrationFlowBody) MarshalJSON() ([]byte, error) { + if src.UpdateRegistrationFlowWithCodeMethod != nil { + return json.Marshal(&src.UpdateRegistrationFlowWithCodeMethod) + } + if src.UpdateRegistrationFlowWithOidcMethod != nil { return json.Marshal(&src.UpdateRegistrationFlowWithOidcMethod) } @@ -123,6 +149,10 @@ func (obj *UpdateRegistrationFlowBody) GetActualInstance() interface{} { if obj == nil { return nil } + if obj.UpdateRegistrationFlowWithCodeMethod != nil { + return obj.UpdateRegistrationFlowWithCodeMethod + } + if obj.UpdateRegistrationFlowWithOidcMethod != nil { return obj.UpdateRegistrationFlowWithOidcMethod } diff --git a/internal/client-go/model_update_registration_flow_with_code_method.go b/internal/client-go/model_update_registration_flow_with_code_method.go new file mode 100644 index 000000000000..46b9126d666f --- /dev/null +++ b/internal/client-go/model_update_registration_flow_with_code_method.go @@ -0,0 +1,286 @@ +/* + * Ory Identities API + * + * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. + * + * API version: + * Contact: office@ory.sh + */ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +import ( + "encoding/json" +) + +// UpdateRegistrationFlowWithCodeMethod Update Registration Flow with Code Method +type UpdateRegistrationFlowWithCodeMethod struct { + // The OTP Code sent to the user + Code *string `json:"code,omitempty"` + // The CSRF Token + CsrfToken *string `json:"csrf_token,omitempty"` + // Method to use This field must be set to `code` when using the code method. + Method string `json:"method"` + // Resend restarts the flow with a new code + Resend *string `json:"resend,omitempty"` + // The identity's traits + Traits map[string]interface{} `json:"traits"` + // Transient data to pass along to any webhooks + TransientPayload map[string]interface{} `json:"transient_payload,omitempty"` +} + +// NewUpdateRegistrationFlowWithCodeMethod instantiates a new UpdateRegistrationFlowWithCodeMethod 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 NewUpdateRegistrationFlowWithCodeMethod(method string, traits map[string]interface{}) *UpdateRegistrationFlowWithCodeMethod { + this := UpdateRegistrationFlowWithCodeMethod{} + this.Method = method + this.Traits = traits + return &this +} + +// NewUpdateRegistrationFlowWithCodeMethodWithDefaults instantiates a new UpdateRegistrationFlowWithCodeMethod 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 NewUpdateRegistrationFlowWithCodeMethodWithDefaults() *UpdateRegistrationFlowWithCodeMethod { + this := UpdateRegistrationFlowWithCodeMethod{} + return &this +} + +// GetCode returns the Code field value if set, zero value otherwise. +func (o *UpdateRegistrationFlowWithCodeMethod) GetCode() string { + if o == nil || o.Code == nil { + var ret string + return ret + } + return *o.Code +} + +// GetCodeOk returns a tuple with the Code field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UpdateRegistrationFlowWithCodeMethod) GetCodeOk() (*string, bool) { + if o == nil || o.Code == nil { + return nil, false + } + return o.Code, true +} + +// HasCode returns a boolean if a field has been set. +func (o *UpdateRegistrationFlowWithCodeMethod) HasCode() bool { + if o != nil && o.Code != nil { + return true + } + + return false +} + +// SetCode gets a reference to the given string and assigns it to the Code field. +func (o *UpdateRegistrationFlowWithCodeMethod) SetCode(v string) { + o.Code = &v +} + +// GetCsrfToken returns the CsrfToken field value if set, zero value otherwise. +func (o *UpdateRegistrationFlowWithCodeMethod) GetCsrfToken() string { + if o == nil || o.CsrfToken == nil { + var ret string + return ret + } + return *o.CsrfToken +} + +// GetCsrfTokenOk returns a tuple with the CsrfToken field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UpdateRegistrationFlowWithCodeMethod) GetCsrfTokenOk() (*string, bool) { + if o == nil || o.CsrfToken == nil { + return nil, false + } + return o.CsrfToken, true +} + +// HasCsrfToken returns a boolean if a field has been set. +func (o *UpdateRegistrationFlowWithCodeMethod) HasCsrfToken() bool { + if o != nil && o.CsrfToken != nil { + return true + } + + return false +} + +// SetCsrfToken gets a reference to the given string and assigns it to the CsrfToken field. +func (o *UpdateRegistrationFlowWithCodeMethod) SetCsrfToken(v string) { + o.CsrfToken = &v +} + +// GetMethod returns the Method field value +func (o *UpdateRegistrationFlowWithCodeMethod) GetMethod() string { + if o == nil { + var ret string + return ret + } + + return o.Method +} + +// GetMethodOk returns a tuple with the Method field value +// and a boolean to check if the value has been set. +func (o *UpdateRegistrationFlowWithCodeMethod) GetMethodOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Method, true +} + +// SetMethod sets field value +func (o *UpdateRegistrationFlowWithCodeMethod) SetMethod(v string) { + o.Method = v +} + +// GetResend returns the Resend field value if set, zero value otherwise. +func (o *UpdateRegistrationFlowWithCodeMethod) GetResend() string { + if o == nil || o.Resend == nil { + var ret string + return ret + } + return *o.Resend +} + +// GetResendOk returns a tuple with the Resend field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UpdateRegistrationFlowWithCodeMethod) GetResendOk() (*string, bool) { + if o == nil || o.Resend == nil { + return nil, false + } + return o.Resend, true +} + +// HasResend returns a boolean if a field has been set. +func (o *UpdateRegistrationFlowWithCodeMethod) HasResend() bool { + if o != nil && o.Resend != nil { + return true + } + + return false +} + +// SetResend gets a reference to the given string and assigns it to the Resend field. +func (o *UpdateRegistrationFlowWithCodeMethod) SetResend(v string) { + o.Resend = &v +} + +// GetTraits returns the Traits field value +func (o *UpdateRegistrationFlowWithCodeMethod) GetTraits() map[string]interface{} { + if o == nil { + var ret map[string]interface{} + return ret + } + + return o.Traits +} + +// GetTraitsOk returns a tuple with the Traits field value +// and a boolean to check if the value has been set. +func (o *UpdateRegistrationFlowWithCodeMethod) GetTraitsOk() (map[string]interface{}, bool) { + if o == nil { + return nil, false + } + return o.Traits, true +} + +// SetTraits sets field value +func (o *UpdateRegistrationFlowWithCodeMethod) SetTraits(v map[string]interface{}) { + o.Traits = v +} + +// GetTransientPayload returns the TransientPayload field value if set, zero value otherwise. +func (o *UpdateRegistrationFlowWithCodeMethod) GetTransientPayload() map[string]interface{} { + if o == nil || o.TransientPayload == nil { + var ret map[string]interface{} + return ret + } + return o.TransientPayload +} + +// GetTransientPayloadOk returns a tuple with the TransientPayload field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UpdateRegistrationFlowWithCodeMethod) GetTransientPayloadOk() (map[string]interface{}, bool) { + if o == nil || o.TransientPayload == nil { + return nil, false + } + return o.TransientPayload, true +} + +// HasTransientPayload returns a boolean if a field has been set. +func (o *UpdateRegistrationFlowWithCodeMethod) HasTransientPayload() bool { + if o != nil && o.TransientPayload != nil { + return true + } + + return false +} + +// SetTransientPayload gets a reference to the given map[string]interface{} and assigns it to the TransientPayload field. +func (o *UpdateRegistrationFlowWithCodeMethod) SetTransientPayload(v map[string]interface{}) { + o.TransientPayload = v +} + +func (o UpdateRegistrationFlowWithCodeMethod) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if o.Code != nil { + toSerialize["code"] = o.Code + } + if o.CsrfToken != nil { + toSerialize["csrf_token"] = o.CsrfToken + } + if true { + toSerialize["method"] = o.Method + } + if o.Resend != nil { + toSerialize["resend"] = o.Resend + } + if true { + toSerialize["traits"] = o.Traits + } + if o.TransientPayload != nil { + toSerialize["transient_payload"] = o.TransientPayload + } + return json.Marshal(toSerialize) +} + +type NullableUpdateRegistrationFlowWithCodeMethod struct { + value *UpdateRegistrationFlowWithCodeMethod + isSet bool +} + +func (v NullableUpdateRegistrationFlowWithCodeMethod) Get() *UpdateRegistrationFlowWithCodeMethod { + return v.value +} + +func (v *NullableUpdateRegistrationFlowWithCodeMethod) Set(val *UpdateRegistrationFlowWithCodeMethod) { + v.value = val + v.isSet = true +} + +func (v NullableUpdateRegistrationFlowWithCodeMethod) IsSet() bool { + return v.isSet +} + +func (v *NullableUpdateRegistrationFlowWithCodeMethod) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableUpdateRegistrationFlowWithCodeMethod(val *UpdateRegistrationFlowWithCodeMethod) *NullableUpdateRegistrationFlowWithCodeMethod { + return &NullableUpdateRegistrationFlowWithCodeMethod{value: val, isSet: true} +} + +func (v NullableUpdateRegistrationFlowWithCodeMethod) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableUpdateRegistrationFlowWithCodeMethod) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/client-go/model_verification_flow.go b/internal/client-go/model_verification_flow.go index 5190da660254..c10870c9f841 100644 --- a/internal/client-go/model_verification_flow.go +++ b/internal/client-go/model_verification_flow.go @@ -29,8 +29,9 @@ type VerificationFlow struct { // 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,omitempty"` // ReturnTo contains the requested return_to URL. - ReturnTo *string `json:"return_to,omitempty"` - State VerificationFlowState `json:"state"` + ReturnTo *string `json:"return_to,omitempty"` + // State represents the state of this request: choose_method: ask the user to choose a method (e.g. verify your email) sent_email: the email has been sent to the user passed_challenge: the request was successful and the verification challenge was passed. + State interface{} `json:"state"` // The flow type can either be `api` or `browser`. Type string `json:"type"` Ui UiContainer `json:"ui"` @@ -40,7 +41,7 @@ type VerificationFlow struct { // 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 NewVerificationFlow(id string, state VerificationFlowState, type_ string, ui UiContainer) *VerificationFlow { +func NewVerificationFlow(id string, state interface{}, type_ string, ui UiContainer) *VerificationFlow { this := VerificationFlow{} this.Id = id this.State = state @@ -242,9 +243,10 @@ func (o *VerificationFlow) SetReturnTo(v string) { } // GetState returns the State field value -func (o *VerificationFlow) GetState() VerificationFlowState { +// If the value is explicit nil, the zero value for interface{} will be returned +func (o *VerificationFlow) GetState() interface{} { if o == nil { - var ret VerificationFlowState + var ret interface{} return ret } @@ -253,15 +255,16 @@ func (o *VerificationFlow) GetState() VerificationFlowState { // GetStateOk returns a tuple with the State field value // and a boolean to check if the value has been set. -func (o *VerificationFlow) GetStateOk() (*VerificationFlowState, bool) { - if o == nil { +// NOTE: If the value is an explicit nil, `nil, true` will be returned +func (o *VerificationFlow) GetStateOk() (*interface{}, bool) { + if o == nil || o.State == nil { return nil, false } return &o.State, true } // SetState sets field value -func (o *VerificationFlow) SetState(v VerificationFlowState) { +func (o *VerificationFlow) SetState(v interface{}) { o.State = v } @@ -333,7 +336,7 @@ func (o VerificationFlow) MarshalJSON() ([]byte, error) { if o.ReturnTo != nil { toSerialize["return_to"] = o.ReturnTo } - if true { + if o.State != nil { toSerialize["state"] = o.State } if true { diff --git a/internal/httpclient/.openapi-generator/FILES b/internal/httpclient/.openapi-generator/FILES index af0c731e5f92..7018bd681eac 100644 --- a/internal/httpclient/.openapi-generator/FILES +++ b/internal/httpclient/.openapi-generator/FILES @@ -35,6 +35,7 @@ docs/HealthStatus.md docs/Identity.md docs/IdentityApi.md docs/IdentityCredentials.md +docs/IdentityCredentialsCode.md docs/IdentityCredentialsOidc.md docs/IdentityCredentialsOidcProvider.md docs/IdentityCredentialsPassword.md @@ -53,6 +54,7 @@ docs/IsAlive200Response.md docs/IsReady503Response.md docs/JsonPatch.md docs/LoginFlow.md +docs/LoginFlowState.md docs/LogoutFlow.md docs/Message.md docs/MessageDispatch.md @@ -70,6 +72,7 @@ docs/RecoveryFlowState.md docs/RecoveryIdentityAddress.md docs/RecoveryLinkForIdentity.md docs/RegistrationFlow.md +docs/RegistrationFlowState.md docs/SelfServiceFlowExpiredError.md docs/Session.md docs/SessionAuthenticationMethod.md @@ -93,6 +96,7 @@ docs/UiNodeTextAttributes.md docs/UiText.md docs/UpdateIdentityBody.md docs/UpdateLoginFlowBody.md +docs/UpdateLoginFlowWithCodeMethod.md docs/UpdateLoginFlowWithLookupSecretMethod.md docs/UpdateLoginFlowWithOidcMethod.md docs/UpdateLoginFlowWithPasswordMethod.md @@ -102,6 +106,7 @@ docs/UpdateRecoveryFlowBody.md docs/UpdateRecoveryFlowWithCodeMethod.md docs/UpdateRecoveryFlowWithLinkMethod.md docs/UpdateRegistrationFlowBody.md +docs/UpdateRegistrationFlowWithCodeMethod.md docs/UpdateRegistrationFlowWithOidcMethod.md docs/UpdateRegistrationFlowWithPasswordMethod.md docs/UpdateRegistrationFlowWithWebAuthnMethod.md @@ -145,6 +150,7 @@ model_health_not_ready_status.go model_health_status.go model_identity.go model_identity_credentials.go +model_identity_credentials_code.go model_identity_credentials_oidc.go model_identity_credentials_oidc_provider.go model_identity_credentials_password.go @@ -163,6 +169,7 @@ model_is_alive_200_response.go model_is_ready_503_response.go model_json_patch.go model_login_flow.go +model_login_flow_state.go model_logout_flow.go model_message.go model_message_dispatch.go @@ -179,6 +186,7 @@ model_recovery_flow_state.go model_recovery_identity_address.go model_recovery_link_for_identity.go model_registration_flow.go +model_registration_flow_state.go model_self_service_flow_expired_error.go model_session.go model_session_authentication_method.go @@ -202,6 +210,7 @@ model_ui_node_text_attributes.go model_ui_text.go model_update_identity_body.go model_update_login_flow_body.go +model_update_login_flow_with_code_method.go model_update_login_flow_with_lookup_secret_method.go model_update_login_flow_with_oidc_method.go model_update_login_flow_with_password_method.go @@ -211,6 +220,7 @@ model_update_recovery_flow_body.go model_update_recovery_flow_with_code_method.go model_update_recovery_flow_with_link_method.go model_update_registration_flow_body.go +model_update_registration_flow_with_code_method.go model_update_registration_flow_with_oidc_method.go model_update_registration_flow_with_password_method.go model_update_registration_flow_with_web_authn_method.go diff --git a/internal/httpclient/README.md b/internal/httpclient/README.md index cb48b260e91f..084b578785ee 100644 --- a/internal/httpclient/README.md +++ b/internal/httpclient/README.md @@ -159,6 +159,7 @@ Class | Method | HTTP request | Description - [HealthStatus](docs/HealthStatus.md) - [Identity](docs/Identity.md) - [IdentityCredentials](docs/IdentityCredentials.md) + - [IdentityCredentialsCode](docs/IdentityCredentialsCode.md) - [IdentityCredentialsOidc](docs/IdentityCredentialsOidc.md) - [IdentityCredentialsOidcProvider](docs/IdentityCredentialsOidcProvider.md) - [IdentityCredentialsPassword](docs/IdentityCredentialsPassword.md) @@ -177,6 +178,7 @@ Class | Method | HTTP request | Description - [IsReady503Response](docs/IsReady503Response.md) - [JsonPatch](docs/JsonPatch.md) - [LoginFlow](docs/LoginFlow.md) + - [LoginFlowState](docs/LoginFlowState.md) - [LogoutFlow](docs/LogoutFlow.md) - [Message](docs/Message.md) - [MessageDispatch](docs/MessageDispatch.md) @@ -193,6 +195,7 @@ Class | Method | HTTP request | Description - [RecoveryIdentityAddress](docs/RecoveryIdentityAddress.md) - [RecoveryLinkForIdentity](docs/RecoveryLinkForIdentity.md) - [RegistrationFlow](docs/RegistrationFlow.md) + - [RegistrationFlowState](docs/RegistrationFlowState.md) - [SelfServiceFlowExpiredError](docs/SelfServiceFlowExpiredError.md) - [Session](docs/Session.md) - [SessionAuthenticationMethod](docs/SessionAuthenticationMethod.md) @@ -216,6 +219,7 @@ Class | Method | HTTP request | Description - [UiText](docs/UiText.md) - [UpdateIdentityBody](docs/UpdateIdentityBody.md) - [UpdateLoginFlowBody](docs/UpdateLoginFlowBody.md) + - [UpdateLoginFlowWithCodeMethod](docs/UpdateLoginFlowWithCodeMethod.md) - [UpdateLoginFlowWithLookupSecretMethod](docs/UpdateLoginFlowWithLookupSecretMethod.md) - [UpdateLoginFlowWithOidcMethod](docs/UpdateLoginFlowWithOidcMethod.md) - [UpdateLoginFlowWithPasswordMethod](docs/UpdateLoginFlowWithPasswordMethod.md) @@ -225,6 +229,7 @@ Class | Method | HTTP request | Description - [UpdateRecoveryFlowWithCodeMethod](docs/UpdateRecoveryFlowWithCodeMethod.md) - [UpdateRecoveryFlowWithLinkMethod](docs/UpdateRecoveryFlowWithLinkMethod.md) - [UpdateRegistrationFlowBody](docs/UpdateRegistrationFlowBody.md) + - [UpdateRegistrationFlowWithCodeMethod](docs/UpdateRegistrationFlowWithCodeMethod.md) - [UpdateRegistrationFlowWithOidcMethod](docs/UpdateRegistrationFlowWithOidcMethod.md) - [UpdateRegistrationFlowWithPasswordMethod](docs/UpdateRegistrationFlowWithPasswordMethod.md) - [UpdateRegistrationFlowWithWebAuthnMethod](docs/UpdateRegistrationFlowWithWebAuthnMethod.md) diff --git a/internal/httpclient/model_identity_credentials_code.go b/internal/httpclient/model_identity_credentials_code.go new file mode 100644 index 000000000000..f542b359639a --- /dev/null +++ b/internal/httpclient/model_identity_credentials_code.go @@ -0,0 +1,162 @@ +/* + * Ory Identities API + * + * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. + * + * API version: + * Contact: office@ory.sh + */ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +import ( + "encoding/json" + "time" +) + +// IdentityCredentialsCode CredentialsCode represents a one time login/registration code +type IdentityCredentialsCode struct { + AddressType *string `json:"address_type,omitempty"` + UsedAt NullableTime `json:"used_at,omitempty"` +} + +// NewIdentityCredentialsCode instantiates a new IdentityCredentialsCode 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 NewIdentityCredentialsCode() *IdentityCredentialsCode { + this := IdentityCredentialsCode{} + return &this +} + +// NewIdentityCredentialsCodeWithDefaults instantiates a new IdentityCredentialsCode 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 NewIdentityCredentialsCodeWithDefaults() *IdentityCredentialsCode { + this := IdentityCredentialsCode{} + return &this +} + +// GetAddressType returns the AddressType field value if set, zero value otherwise. +func (o *IdentityCredentialsCode) GetAddressType() string { + if o == nil || o.AddressType == nil { + var ret string + return ret + } + return *o.AddressType +} + +// GetAddressTypeOk returns a tuple with the AddressType field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *IdentityCredentialsCode) GetAddressTypeOk() (*string, bool) { + if o == nil || o.AddressType == nil { + return nil, false + } + return o.AddressType, true +} + +// HasAddressType returns a boolean if a field has been set. +func (o *IdentityCredentialsCode) HasAddressType() bool { + if o != nil && o.AddressType != nil { + return true + } + + return false +} + +// SetAddressType gets a reference to the given string and assigns it to the AddressType field. +func (o *IdentityCredentialsCode) SetAddressType(v string) { + o.AddressType = &v +} + +// GetUsedAt returns the UsedAt field value if set, zero value otherwise (both if not set or set to explicit null). +func (o *IdentityCredentialsCode) GetUsedAt() time.Time { + if o == nil || o.UsedAt.Get() == nil { + var ret time.Time + return ret + } + return *o.UsedAt.Get() +} + +// GetUsedAtOk returns a tuple with the UsedAt 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 *IdentityCredentialsCode) GetUsedAtOk() (*time.Time, bool) { + if o == nil { + return nil, false + } + return o.UsedAt.Get(), o.UsedAt.IsSet() +} + +// HasUsedAt returns a boolean if a field has been set. +func (o *IdentityCredentialsCode) HasUsedAt() bool { + if o != nil && o.UsedAt.IsSet() { + return true + } + + return false +} + +// SetUsedAt gets a reference to the given NullableTime and assigns it to the UsedAt field. +func (o *IdentityCredentialsCode) SetUsedAt(v time.Time) { + o.UsedAt.Set(&v) +} + +// SetUsedAtNil sets the value for UsedAt to be an explicit nil +func (o *IdentityCredentialsCode) SetUsedAtNil() { + o.UsedAt.Set(nil) +} + +// UnsetUsedAt ensures that no value is present for UsedAt, not even an explicit nil +func (o *IdentityCredentialsCode) UnsetUsedAt() { + o.UsedAt.Unset() +} + +func (o IdentityCredentialsCode) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if o.AddressType != nil { + toSerialize["address_type"] = o.AddressType + } + if o.UsedAt.IsSet() { + toSerialize["used_at"] = o.UsedAt.Get() + } + return json.Marshal(toSerialize) +} + +type NullableIdentityCredentialsCode struct { + value *IdentityCredentialsCode + isSet bool +} + +func (v NullableIdentityCredentialsCode) Get() *IdentityCredentialsCode { + return v.value +} + +func (v *NullableIdentityCredentialsCode) Set(val *IdentityCredentialsCode) { + v.value = val + v.isSet = true +} + +func (v NullableIdentityCredentialsCode) IsSet() bool { + return v.isSet +} + +func (v *NullableIdentityCredentialsCode) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableIdentityCredentialsCode(val *IdentityCredentialsCode) *NullableIdentityCredentialsCode { + return &NullableIdentityCredentialsCode{value: val, isSet: true} +} + +func (v NullableIdentityCredentialsCode) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableIdentityCredentialsCode) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/httpclient/model_identity_credentials_type.go b/internal/httpclient/model_identity_credentials_type.go index f02f3f19b898..a9d01c54e796 100644 --- a/internal/httpclient/model_identity_credentials_type.go +++ b/internal/httpclient/model_identity_credentials_type.go @@ -26,6 +26,7 @@ const ( IDENTITYCREDENTIALSTYPE_OIDC IdentityCredentialsType = "oidc" IDENTITYCREDENTIALSTYPE_WEBAUTHN IdentityCredentialsType = "webauthn" IDENTITYCREDENTIALSTYPE_LOOKUP_SECRET IdentityCredentialsType = "lookup_secret" + IDENTITYCREDENTIALSTYPE_CODE IdentityCredentialsType = "code" ) func (v *IdentityCredentialsType) UnmarshalJSON(src []byte) error { @@ -35,7 +36,7 @@ func (v *IdentityCredentialsType) UnmarshalJSON(src []byte) error { return err } enumTypeValue := IdentityCredentialsType(value) - for _, existing := range []IdentityCredentialsType{"password", "totp", "oidc", "webauthn", "lookup_secret"} { + for _, existing := range []IdentityCredentialsType{"password", "totp", "oidc", "webauthn", "lookup_secret", "code"} { if existing == enumTypeValue { *v = enumTypeValue return nil diff --git a/internal/httpclient/model_login_flow.go b/internal/httpclient/model_login_flow.go index 1b3f4b6c7dde..dc7c67ea2649 100644 --- a/internal/httpclient/model_login_flow.go +++ b/internal/httpclient/model_login_flow.go @@ -39,6 +39,8 @@ type LoginFlow struct { ReturnTo *string `json:"return_to,omitempty"` // SessionTokenExchangeCode holds the secret code that the client can use to retrieve a session token after the login flow has been completed. This is only set if the client has requested a session token exchange code, and if the flow is of type \"api\", and only on creating the login flow. SessionTokenExchangeCode *string `json:"session_token_exchange_code,omitempty"` + // State represents the state of this request: choose_method: ask the user to choose a method to sign in with sent_email: the email has been sent to the user passed_challenge: the request was successful and the login challenge was passed. + State interface{} `json:"state"` // The flow type can either be `api` or `browser`. Type string `json:"type"` Ui UiContainer `json:"ui"` @@ -50,12 +52,13 @@ type LoginFlow struct { // 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 NewLoginFlow(expiresAt time.Time, id string, issuedAt time.Time, requestUrl string, type_ string, ui UiContainer) *LoginFlow { +func NewLoginFlow(expiresAt time.Time, id string, issuedAt time.Time, requestUrl string, state interface{}, type_ string, ui UiContainer) *LoginFlow { this := LoginFlow{} this.ExpiresAt = expiresAt this.Id = id this.IssuedAt = issuedAt this.RequestUrl = requestUrl + this.State = state this.Type = type_ this.Ui = ui return &this @@ -421,6 +424,32 @@ func (o *LoginFlow) SetSessionTokenExchangeCode(v string) { o.SessionTokenExchangeCode = &v } +// GetState returns the State field value +// If the value is explicit nil, the zero value for interface{} will be returned +func (o *LoginFlow) GetState() interface{} { + if o == nil { + var ret interface{} + return ret + } + + return o.State +} + +// GetStateOk returns a tuple with the State field value +// 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 *LoginFlow) GetStateOk() (*interface{}, bool) { + if o == nil || o.State == nil { + return nil, false + } + return &o.State, true +} + +// SetState sets field value +func (o *LoginFlow) SetState(v interface{}) { + o.State = v +} + // GetType returns the Type field value func (o *LoginFlow) GetType() string { if o == nil { @@ -539,6 +568,9 @@ func (o LoginFlow) MarshalJSON() ([]byte, error) { if o.SessionTokenExchangeCode != nil { toSerialize["session_token_exchange_code"] = o.SessionTokenExchangeCode } + if o.State != nil { + toSerialize["state"] = o.State + } if true { toSerialize["type"] = o.Type } diff --git a/internal/httpclient/model_login_flow_state.go b/internal/httpclient/model_login_flow_state.go new file mode 100644 index 000000000000..ce5570b79032 --- /dev/null +++ b/internal/httpclient/model_login_flow_state.go @@ -0,0 +1,85 @@ +/* + * Ory Identities API + * + * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. + * + * API version: + * Contact: office@ory.sh + */ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +import ( + "encoding/json" + "fmt" +) + +// LoginFlowState The state represents the state of the login flow. choose_method: ask the user to choose a method (e.g. login account via email) sent_email: the email has been sent to the user passed_challenge: the request was successful and the login challenge was passed. +type LoginFlowState string + +// List of loginFlowState +const ( + LOGINFLOWSTATE_CHOOSE_METHOD LoginFlowState = "choose_method" + LOGINFLOWSTATE_SENT_EMAIL LoginFlowState = "sent_email" + LOGINFLOWSTATE_PASSED_CHALLENGE LoginFlowState = "passed_challenge" +) + +func (v *LoginFlowState) UnmarshalJSON(src []byte) error { + var value string + err := json.Unmarshal(src, &value) + if err != nil { + return err + } + enumTypeValue := LoginFlowState(value) + for _, existing := range []LoginFlowState{"choose_method", "sent_email", "passed_challenge"} { + if existing == enumTypeValue { + *v = enumTypeValue + return nil + } + } + + return fmt.Errorf("%+v is not a valid LoginFlowState", value) +} + +// Ptr returns reference to loginFlowState value +func (v LoginFlowState) Ptr() *LoginFlowState { + return &v +} + +type NullableLoginFlowState struct { + value *LoginFlowState + isSet bool +} + +func (v NullableLoginFlowState) Get() *LoginFlowState { + return v.value +} + +func (v *NullableLoginFlowState) Set(val *LoginFlowState) { + v.value = val + v.isSet = true +} + +func (v NullableLoginFlowState) IsSet() bool { + return v.isSet +} + +func (v *NullableLoginFlowState) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableLoginFlowState(val *LoginFlowState) *NullableLoginFlowState { + return &NullableLoginFlowState{value: val, isSet: true} +} + +func (v NullableLoginFlowState) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableLoginFlowState) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/httpclient/model_message.go b/internal/httpclient/model_message.go index 3a6f3f92362b..f0452185f169 100644 --- a/internal/httpclient/model_message.go +++ b/internal/httpclient/model_message.go @@ -28,7 +28,7 @@ type Message struct { SendCount int64 `json:"send_count"` Status CourierMessageStatus `json:"status"` Subject string `json:"subject"` - // recovery_invalid TypeRecoveryInvalid recovery_valid TypeRecoveryValid recovery_code_invalid TypeRecoveryCodeInvalid recovery_code_valid TypeRecoveryCodeValid verification_invalid TypeVerificationInvalid verification_valid TypeVerificationValid verification_code_invalid TypeVerificationCodeInvalid verification_code_valid TypeVerificationCodeValid otp TypeOTP stub TypeTestStub + // recovery_invalid TypeRecoveryInvalid recovery_valid TypeRecoveryValid recovery_code_invalid TypeRecoveryCodeInvalid recovery_code_valid TypeRecoveryCodeValid verification_invalid TypeVerificationInvalid verification_valid TypeVerificationValid verification_code_invalid TypeVerificationCodeInvalid verification_code_valid TypeVerificationCodeValid otp TypeOTP stub TypeTestStub login_code_valid TypeLoginCodeValid registration_code_valid TypeRegistrationCodeValid TemplateType string `json:"template_type"` Type CourierMessageType `json:"type"` // UpdatedAt is a helper struct field for gobuffalo.pop. diff --git a/internal/httpclient/model_recovery_flow.go b/internal/httpclient/model_recovery_flow.go index 6ae19ebd60e6..acf4ff667df3 100644 --- a/internal/httpclient/model_recovery_flow.go +++ b/internal/httpclient/model_recovery_flow.go @@ -29,8 +29,9 @@ type RecoveryFlow struct { // 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. - ReturnTo *string `json:"return_to,omitempty"` - State RecoveryFlowState `json:"state"` + ReturnTo *string `json:"return_to,omitempty"` + // State represents the state of this request: choose_method: ask the user to choose a method (e.g. recover account via email) sent_email: the email has been sent to the user passed_challenge: the request was successful and the recovery challenge was passed. + State interface{} `json:"state"` // The flow type can either be `api` or `browser`. Type string `json:"type"` Ui UiContainer `json:"ui"` @@ -40,7 +41,7 @@ type RecoveryFlow struct { // 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 NewRecoveryFlow(expiresAt time.Time, id string, issuedAt time.Time, requestUrl string, state RecoveryFlowState, type_ string, ui UiContainer) *RecoveryFlow { +func NewRecoveryFlow(expiresAt time.Time, id string, issuedAt time.Time, requestUrl string, state interface{}, type_ string, ui UiContainer) *RecoveryFlow { this := RecoveryFlow{} this.ExpiresAt = expiresAt this.Id = id @@ -221,9 +222,10 @@ func (o *RecoveryFlow) SetReturnTo(v string) { } // GetState returns the State field value -func (o *RecoveryFlow) GetState() RecoveryFlowState { +// If the value is explicit nil, the zero value for interface{} will be returned +func (o *RecoveryFlow) GetState() interface{} { if o == nil { - var ret RecoveryFlowState + var ret interface{} return ret } @@ -232,15 +234,16 @@ func (o *RecoveryFlow) GetState() RecoveryFlowState { // GetStateOk returns a tuple with the State field value // and a boolean to check if the value has been set. -func (o *RecoveryFlow) GetStateOk() (*RecoveryFlowState, bool) { - if o == nil { +// NOTE: If the value is an explicit nil, `nil, true` will be returned +func (o *RecoveryFlow) GetStateOk() (*interface{}, bool) { + if o == nil || o.State == nil { return nil, false } return &o.State, true } // SetState sets field value -func (o *RecoveryFlow) SetState(v RecoveryFlowState) { +func (o *RecoveryFlow) SetState(v interface{}) { o.State = v } @@ -312,7 +315,7 @@ func (o RecoveryFlow) MarshalJSON() ([]byte, error) { if o.ReturnTo != nil { toSerialize["return_to"] = o.ReturnTo } - if true { + if o.State != nil { toSerialize["state"] = o.State } if true { diff --git a/internal/httpclient/model_registration_flow.go b/internal/httpclient/model_registration_flow.go index fe9f697b5551..9b08288d6a16 100644 --- a/internal/httpclient/model_registration_flow.go +++ b/internal/httpclient/model_registration_flow.go @@ -34,6 +34,8 @@ type RegistrationFlow struct { ReturnTo *string `json:"return_to,omitempty"` // SessionTokenExchangeCode holds the secret code that the client can use to retrieve a session token after the flow has been completed. This is only set if the client has requested a session token exchange code, and if the flow is of type \"api\", and only on creating the flow. SessionTokenExchangeCode *string `json:"session_token_exchange_code,omitempty"` + // State represents the state of this request: choose_method: ask the user to choose a method (e.g. registration with email) sent_email: the email has been sent to the user passed_challenge: the request was successful and the registration challenge was passed. + State interface{} `json:"state"` // TransientPayload is used to pass data from the registration to a webhook TransientPayload map[string]interface{} `json:"transient_payload,omitempty"` // The flow type can either be `api` or `browser`. @@ -45,12 +47,13 @@ type RegistrationFlow struct { // 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 NewRegistrationFlow(expiresAt time.Time, id string, issuedAt time.Time, requestUrl string, type_ string, ui UiContainer) *RegistrationFlow { +func NewRegistrationFlow(expiresAt time.Time, id string, issuedAt time.Time, requestUrl string, state interface{}, type_ string, ui UiContainer) *RegistrationFlow { this := RegistrationFlow{} this.ExpiresAt = expiresAt this.Id = id this.IssuedAt = issuedAt this.RequestUrl = requestUrl + this.State = state this.Type = type_ this.Ui = ui return &this @@ -320,6 +323,32 @@ func (o *RegistrationFlow) SetSessionTokenExchangeCode(v string) { o.SessionTokenExchangeCode = &v } +// GetState returns the State field value +// If the value is explicit nil, the zero value for interface{} will be returned +func (o *RegistrationFlow) GetState() interface{} { + if o == nil { + var ret interface{} + return ret + } + + return o.State +} + +// GetStateOk returns a tuple with the State field value +// 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 *RegistrationFlow) GetStateOk() (*interface{}, bool) { + if o == nil || o.State == nil { + return nil, false + } + return &o.State, true +} + +// SetState sets field value +func (o *RegistrationFlow) SetState(v interface{}) { + o.State = v +} + // GetTransientPayload returns the TransientPayload field value if set, zero value otherwise. func (o *RegistrationFlow) GetTransientPayload() map[string]interface{} { if o == nil || o.TransientPayload == nil { @@ -429,6 +458,9 @@ func (o RegistrationFlow) MarshalJSON() ([]byte, error) { if o.SessionTokenExchangeCode != nil { toSerialize["session_token_exchange_code"] = o.SessionTokenExchangeCode } + if o.State != nil { + toSerialize["state"] = o.State + } if o.TransientPayload != nil { toSerialize["transient_payload"] = o.TransientPayload } diff --git a/internal/httpclient/model_registration_flow_state.go b/internal/httpclient/model_registration_flow_state.go new file mode 100644 index 000000000000..86f3fd38cff0 --- /dev/null +++ b/internal/httpclient/model_registration_flow_state.go @@ -0,0 +1,85 @@ +/* + * Ory Identities API + * + * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. + * + * API version: + * Contact: office@ory.sh + */ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +import ( + "encoding/json" + "fmt" +) + +// RegistrationFlowState choose_method: ask the user to choose a method (e.g. registration with email) sent_email: the email has been sent to the user passed_challenge: the request was successful and the registration challenge was passed. +type RegistrationFlowState string + +// List of registrationFlowState +const ( + REGISTRATIONFLOWSTATE_CHOOSE_METHOD RegistrationFlowState = "choose_method" + REGISTRATIONFLOWSTATE_SENT_EMAIL RegistrationFlowState = "sent_email" + REGISTRATIONFLOWSTATE_PASSED_CHALLENGE RegistrationFlowState = "passed_challenge" +) + +func (v *RegistrationFlowState) UnmarshalJSON(src []byte) error { + var value string + err := json.Unmarshal(src, &value) + if err != nil { + return err + } + enumTypeValue := RegistrationFlowState(value) + for _, existing := range []RegistrationFlowState{"choose_method", "sent_email", "passed_challenge"} { + if existing == enumTypeValue { + *v = enumTypeValue + return nil + } + } + + return fmt.Errorf("%+v is not a valid RegistrationFlowState", value) +} + +// Ptr returns reference to registrationFlowState value +func (v RegistrationFlowState) Ptr() *RegistrationFlowState { + return &v +} + +type NullableRegistrationFlowState struct { + value *RegistrationFlowState + isSet bool +} + +func (v NullableRegistrationFlowState) Get() *RegistrationFlowState { + return v.value +} + +func (v *NullableRegistrationFlowState) Set(val *RegistrationFlowState) { + v.value = val + v.isSet = true +} + +func (v NullableRegistrationFlowState) IsSet() bool { + return v.isSet +} + +func (v *NullableRegistrationFlowState) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableRegistrationFlowState(val *RegistrationFlowState) *NullableRegistrationFlowState { + return &NullableRegistrationFlowState{value: val, isSet: true} +} + +func (v NullableRegistrationFlowState) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableRegistrationFlowState) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/httpclient/model_settings_flow.go b/internal/httpclient/model_settings_flow.go index a1dc0aa98dc6..fa5cd9317c54 100644 --- a/internal/httpclient/model_settings_flow.go +++ b/internal/httpclient/model_settings_flow.go @@ -32,8 +32,9 @@ type SettingsFlow struct { // 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. - ReturnTo *string `json:"return_to,omitempty"` - State SettingsFlowState `json:"state"` + ReturnTo *string `json:"return_to,omitempty"` + // State represents the state of this flow. It knows two states: show_form: No user data has been collected, or it is invalid, and thus the form should be shown. success: Indicates that the settings flow has been updated successfully with the provided data. Done will stay true when repeatedly checking. If set to true, done will revert back to false only when a flow with invalid (e.g. \"please use a valid phone number\") data was sent. + State interface{} `json:"state"` // The flow type can either be `api` or `browser`. Type string `json:"type"` Ui UiContainer `json:"ui"` @@ -43,7 +44,7 @@ type SettingsFlow struct { // 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 NewSettingsFlow(expiresAt time.Time, id string, identity Identity, issuedAt time.Time, requestUrl string, state SettingsFlowState, type_ string, ui UiContainer) *SettingsFlow { +func NewSettingsFlow(expiresAt time.Time, id string, identity Identity, issuedAt time.Time, requestUrl string, state interface{}, type_ string, ui UiContainer) *SettingsFlow { this := SettingsFlow{} this.ExpiresAt = expiresAt this.Id = id @@ -281,9 +282,10 @@ func (o *SettingsFlow) SetReturnTo(v string) { } // GetState returns the State field value -func (o *SettingsFlow) GetState() SettingsFlowState { +// If the value is explicit nil, the zero value for interface{} will be returned +func (o *SettingsFlow) GetState() interface{} { if o == nil { - var ret SettingsFlowState + var ret interface{} return ret } @@ -292,15 +294,16 @@ func (o *SettingsFlow) GetState() SettingsFlowState { // GetStateOk returns a tuple with the State field value // and a boolean to check if the value has been set. -func (o *SettingsFlow) GetStateOk() (*SettingsFlowState, bool) { - if o == nil { +// NOTE: If the value is an explicit nil, `nil, true` will be returned +func (o *SettingsFlow) GetStateOk() (*interface{}, bool) { + if o == nil || o.State == nil { return nil, false } return &o.State, true } // SetState sets field value -func (o *SettingsFlow) SetState(v SettingsFlowState) { +func (o *SettingsFlow) SetState(v interface{}) { o.State = v } @@ -378,7 +381,7 @@ func (o SettingsFlow) MarshalJSON() ([]byte, error) { if o.ReturnTo != nil { toSerialize["return_to"] = o.ReturnTo } - if true { + if o.State != nil { toSerialize["state"] = o.State } if true { diff --git a/internal/httpclient/model_update_login_flow_body.go b/internal/httpclient/model_update_login_flow_body.go index 1aa032062a4b..36033328e78d 100644 --- a/internal/httpclient/model_update_login_flow_body.go +++ b/internal/httpclient/model_update_login_flow_body.go @@ -18,6 +18,7 @@ import ( // UpdateLoginFlowBody - struct for UpdateLoginFlowBody type UpdateLoginFlowBody struct { + UpdateLoginFlowWithCodeMethod *UpdateLoginFlowWithCodeMethod UpdateLoginFlowWithLookupSecretMethod *UpdateLoginFlowWithLookupSecretMethod UpdateLoginFlowWithOidcMethod *UpdateLoginFlowWithOidcMethod UpdateLoginFlowWithPasswordMethod *UpdateLoginFlowWithPasswordMethod @@ -25,6 +26,13 @@ type UpdateLoginFlowBody struct { UpdateLoginFlowWithWebAuthnMethod *UpdateLoginFlowWithWebAuthnMethod } +// UpdateLoginFlowWithCodeMethodAsUpdateLoginFlowBody is a convenience function that returns UpdateLoginFlowWithCodeMethod wrapped in UpdateLoginFlowBody +func UpdateLoginFlowWithCodeMethodAsUpdateLoginFlowBody(v *UpdateLoginFlowWithCodeMethod) UpdateLoginFlowBody { + return UpdateLoginFlowBody{ + UpdateLoginFlowWithCodeMethod: v, + } +} + // UpdateLoginFlowWithLookupSecretMethodAsUpdateLoginFlowBody is a convenience function that returns UpdateLoginFlowWithLookupSecretMethod wrapped in UpdateLoginFlowBody func UpdateLoginFlowWithLookupSecretMethodAsUpdateLoginFlowBody(v *UpdateLoginFlowWithLookupSecretMethod) UpdateLoginFlowBody { return UpdateLoginFlowBody{ @@ -64,6 +72,19 @@ func UpdateLoginFlowWithWebAuthnMethodAsUpdateLoginFlowBody(v *UpdateLoginFlowWi func (dst *UpdateLoginFlowBody) UnmarshalJSON(data []byte) error { var err error match := 0 + // try to unmarshal data into UpdateLoginFlowWithCodeMethod + err = newStrictDecoder(data).Decode(&dst.UpdateLoginFlowWithCodeMethod) + if err == nil { + jsonUpdateLoginFlowWithCodeMethod, _ := json.Marshal(dst.UpdateLoginFlowWithCodeMethod) + if string(jsonUpdateLoginFlowWithCodeMethod) == "{}" { // empty struct + dst.UpdateLoginFlowWithCodeMethod = nil + } else { + match++ + } + } else { + dst.UpdateLoginFlowWithCodeMethod = nil + } + // try to unmarshal data into UpdateLoginFlowWithLookupSecretMethod err = newStrictDecoder(data).Decode(&dst.UpdateLoginFlowWithLookupSecretMethod) if err == nil { @@ -131,6 +152,7 @@ func (dst *UpdateLoginFlowBody) UnmarshalJSON(data []byte) error { if match > 1 { // more than 1 match // reset to nil + dst.UpdateLoginFlowWithCodeMethod = nil dst.UpdateLoginFlowWithLookupSecretMethod = nil dst.UpdateLoginFlowWithOidcMethod = nil dst.UpdateLoginFlowWithPasswordMethod = nil @@ -147,6 +169,10 @@ func (dst *UpdateLoginFlowBody) UnmarshalJSON(data []byte) error { // Marshal data from the first non-nil pointers in the struct to JSON func (src UpdateLoginFlowBody) MarshalJSON() ([]byte, error) { + if src.UpdateLoginFlowWithCodeMethod != nil { + return json.Marshal(&src.UpdateLoginFlowWithCodeMethod) + } + if src.UpdateLoginFlowWithLookupSecretMethod != nil { return json.Marshal(&src.UpdateLoginFlowWithLookupSecretMethod) } @@ -175,6 +201,10 @@ func (obj *UpdateLoginFlowBody) GetActualInstance() interface{} { if obj == nil { return nil } + if obj.UpdateLoginFlowWithCodeMethod != nil { + return obj.UpdateLoginFlowWithCodeMethod + } + if obj.UpdateLoginFlowWithLookupSecretMethod != nil { return obj.UpdateLoginFlowWithLookupSecretMethod } diff --git a/internal/httpclient/model_update_login_flow_with_code_method.go b/internal/httpclient/model_update_login_flow_with_code_method.go new file mode 100644 index 000000000000..bd97ab583ebc --- /dev/null +++ b/internal/httpclient/model_update_login_flow_with_code_method.go @@ -0,0 +1,249 @@ +/* + * Ory Identities API + * + * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. + * + * API version: + * Contact: office@ory.sh + */ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +import ( + "encoding/json" +) + +// UpdateLoginFlowWithCodeMethod Update Login flow using the code method +type UpdateLoginFlowWithCodeMethod struct { + // Code is the 6 digits code sent to the user + Code *string `json:"code,omitempty"` + // CSRFToken is the anti-CSRF token + CsrfToken string `json:"csrf_token"` + // Identifier is the code identifier The identifier requires that the user has already completed the registration or settings with code flow. + Identifier *string `json:"identifier,omitempty"` + // Method should be set to \"code\" when logging in using the code strategy. + Method string `json:"method"` + // Resend is set when the user wants to resend the code + Resend *string `json:"resend,omitempty"` +} + +// NewUpdateLoginFlowWithCodeMethod instantiates a new UpdateLoginFlowWithCodeMethod 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 NewUpdateLoginFlowWithCodeMethod(csrfToken string, method string) *UpdateLoginFlowWithCodeMethod { + this := UpdateLoginFlowWithCodeMethod{} + this.CsrfToken = csrfToken + this.Method = method + return &this +} + +// NewUpdateLoginFlowWithCodeMethodWithDefaults instantiates a new UpdateLoginFlowWithCodeMethod 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 NewUpdateLoginFlowWithCodeMethodWithDefaults() *UpdateLoginFlowWithCodeMethod { + this := UpdateLoginFlowWithCodeMethod{} + return &this +} + +// GetCode returns the Code field value if set, zero value otherwise. +func (o *UpdateLoginFlowWithCodeMethod) GetCode() string { + if o == nil || o.Code == nil { + var ret string + return ret + } + return *o.Code +} + +// GetCodeOk returns a tuple with the Code field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UpdateLoginFlowWithCodeMethod) GetCodeOk() (*string, bool) { + if o == nil || o.Code == nil { + return nil, false + } + return o.Code, true +} + +// HasCode returns a boolean if a field has been set. +func (o *UpdateLoginFlowWithCodeMethod) HasCode() bool { + if o != nil && o.Code != nil { + return true + } + + return false +} + +// SetCode gets a reference to the given string and assigns it to the Code field. +func (o *UpdateLoginFlowWithCodeMethod) SetCode(v string) { + o.Code = &v +} + +// GetCsrfToken returns the CsrfToken field value +func (o *UpdateLoginFlowWithCodeMethod) GetCsrfToken() string { + if o == nil { + var ret string + return ret + } + + return o.CsrfToken +} + +// GetCsrfTokenOk returns a tuple with the CsrfToken field value +// and a boolean to check if the value has been set. +func (o *UpdateLoginFlowWithCodeMethod) GetCsrfTokenOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.CsrfToken, true +} + +// SetCsrfToken sets field value +func (o *UpdateLoginFlowWithCodeMethod) SetCsrfToken(v string) { + o.CsrfToken = v +} + +// GetIdentifier returns the Identifier field value if set, zero value otherwise. +func (o *UpdateLoginFlowWithCodeMethod) GetIdentifier() string { + if o == nil || o.Identifier == nil { + var ret string + return ret + } + return *o.Identifier +} + +// GetIdentifierOk returns a tuple with the Identifier field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UpdateLoginFlowWithCodeMethod) GetIdentifierOk() (*string, bool) { + if o == nil || o.Identifier == nil { + return nil, false + } + return o.Identifier, true +} + +// HasIdentifier returns a boolean if a field has been set. +func (o *UpdateLoginFlowWithCodeMethod) HasIdentifier() bool { + if o != nil && o.Identifier != nil { + return true + } + + return false +} + +// SetIdentifier gets a reference to the given string and assigns it to the Identifier field. +func (o *UpdateLoginFlowWithCodeMethod) SetIdentifier(v string) { + o.Identifier = &v +} + +// GetMethod returns the Method field value +func (o *UpdateLoginFlowWithCodeMethod) GetMethod() string { + if o == nil { + var ret string + return ret + } + + return o.Method +} + +// GetMethodOk returns a tuple with the Method field value +// and a boolean to check if the value has been set. +func (o *UpdateLoginFlowWithCodeMethod) GetMethodOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Method, true +} + +// SetMethod sets field value +func (o *UpdateLoginFlowWithCodeMethod) SetMethod(v string) { + o.Method = v +} + +// GetResend returns the Resend field value if set, zero value otherwise. +func (o *UpdateLoginFlowWithCodeMethod) GetResend() string { + if o == nil || o.Resend == nil { + var ret string + return ret + } + return *o.Resend +} + +// GetResendOk returns a tuple with the Resend field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UpdateLoginFlowWithCodeMethod) GetResendOk() (*string, bool) { + if o == nil || o.Resend == nil { + return nil, false + } + return o.Resend, true +} + +// HasResend returns a boolean if a field has been set. +func (o *UpdateLoginFlowWithCodeMethod) HasResend() bool { + if o != nil && o.Resend != nil { + return true + } + + return false +} + +// SetResend gets a reference to the given string and assigns it to the Resend field. +func (o *UpdateLoginFlowWithCodeMethod) SetResend(v string) { + o.Resend = &v +} + +func (o UpdateLoginFlowWithCodeMethod) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if o.Code != nil { + toSerialize["code"] = o.Code + } + if true { + toSerialize["csrf_token"] = o.CsrfToken + } + if o.Identifier != nil { + toSerialize["identifier"] = o.Identifier + } + if true { + toSerialize["method"] = o.Method + } + if o.Resend != nil { + toSerialize["resend"] = o.Resend + } + return json.Marshal(toSerialize) +} + +type NullableUpdateLoginFlowWithCodeMethod struct { + value *UpdateLoginFlowWithCodeMethod + isSet bool +} + +func (v NullableUpdateLoginFlowWithCodeMethod) Get() *UpdateLoginFlowWithCodeMethod { + return v.value +} + +func (v *NullableUpdateLoginFlowWithCodeMethod) Set(val *UpdateLoginFlowWithCodeMethod) { + v.value = val + v.isSet = true +} + +func (v NullableUpdateLoginFlowWithCodeMethod) IsSet() bool { + return v.isSet +} + +func (v *NullableUpdateLoginFlowWithCodeMethod) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableUpdateLoginFlowWithCodeMethod(val *UpdateLoginFlowWithCodeMethod) *NullableUpdateLoginFlowWithCodeMethod { + return &NullableUpdateLoginFlowWithCodeMethod{value: val, isSet: true} +} + +func (v NullableUpdateLoginFlowWithCodeMethod) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableUpdateLoginFlowWithCodeMethod) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/httpclient/model_update_registration_flow_body.go b/internal/httpclient/model_update_registration_flow_body.go index 1a662fc62416..0e36a95f635f 100644 --- a/internal/httpclient/model_update_registration_flow_body.go +++ b/internal/httpclient/model_update_registration_flow_body.go @@ -18,11 +18,19 @@ import ( // UpdateRegistrationFlowBody - Update Registration Request Body type UpdateRegistrationFlowBody struct { + UpdateRegistrationFlowWithCodeMethod *UpdateRegistrationFlowWithCodeMethod UpdateRegistrationFlowWithOidcMethod *UpdateRegistrationFlowWithOidcMethod UpdateRegistrationFlowWithPasswordMethod *UpdateRegistrationFlowWithPasswordMethod UpdateRegistrationFlowWithWebAuthnMethod *UpdateRegistrationFlowWithWebAuthnMethod } +// UpdateRegistrationFlowWithCodeMethodAsUpdateRegistrationFlowBody is a convenience function that returns UpdateRegistrationFlowWithCodeMethod wrapped in UpdateRegistrationFlowBody +func UpdateRegistrationFlowWithCodeMethodAsUpdateRegistrationFlowBody(v *UpdateRegistrationFlowWithCodeMethod) UpdateRegistrationFlowBody { + return UpdateRegistrationFlowBody{ + UpdateRegistrationFlowWithCodeMethod: v, + } +} + // UpdateRegistrationFlowWithOidcMethodAsUpdateRegistrationFlowBody is a convenience function that returns UpdateRegistrationFlowWithOidcMethod wrapped in UpdateRegistrationFlowBody func UpdateRegistrationFlowWithOidcMethodAsUpdateRegistrationFlowBody(v *UpdateRegistrationFlowWithOidcMethod) UpdateRegistrationFlowBody { return UpdateRegistrationFlowBody{ @@ -48,6 +56,19 @@ func UpdateRegistrationFlowWithWebAuthnMethodAsUpdateRegistrationFlowBody(v *Upd func (dst *UpdateRegistrationFlowBody) UnmarshalJSON(data []byte) error { var err error match := 0 + // try to unmarshal data into UpdateRegistrationFlowWithCodeMethod + err = newStrictDecoder(data).Decode(&dst.UpdateRegistrationFlowWithCodeMethod) + if err == nil { + jsonUpdateRegistrationFlowWithCodeMethod, _ := json.Marshal(dst.UpdateRegistrationFlowWithCodeMethod) + if string(jsonUpdateRegistrationFlowWithCodeMethod) == "{}" { // empty struct + dst.UpdateRegistrationFlowWithCodeMethod = nil + } else { + match++ + } + } else { + dst.UpdateRegistrationFlowWithCodeMethod = nil + } + // try to unmarshal data into UpdateRegistrationFlowWithOidcMethod err = newStrictDecoder(data).Decode(&dst.UpdateRegistrationFlowWithOidcMethod) if err == nil { @@ -89,6 +110,7 @@ func (dst *UpdateRegistrationFlowBody) UnmarshalJSON(data []byte) error { if match > 1 { // more than 1 match // reset to nil + dst.UpdateRegistrationFlowWithCodeMethod = nil dst.UpdateRegistrationFlowWithOidcMethod = nil dst.UpdateRegistrationFlowWithPasswordMethod = nil dst.UpdateRegistrationFlowWithWebAuthnMethod = nil @@ -103,6 +125,10 @@ func (dst *UpdateRegistrationFlowBody) UnmarshalJSON(data []byte) error { // Marshal data from the first non-nil pointers in the struct to JSON func (src UpdateRegistrationFlowBody) MarshalJSON() ([]byte, error) { + if src.UpdateRegistrationFlowWithCodeMethod != nil { + return json.Marshal(&src.UpdateRegistrationFlowWithCodeMethod) + } + if src.UpdateRegistrationFlowWithOidcMethod != nil { return json.Marshal(&src.UpdateRegistrationFlowWithOidcMethod) } @@ -123,6 +149,10 @@ func (obj *UpdateRegistrationFlowBody) GetActualInstance() interface{} { if obj == nil { return nil } + if obj.UpdateRegistrationFlowWithCodeMethod != nil { + return obj.UpdateRegistrationFlowWithCodeMethod + } + if obj.UpdateRegistrationFlowWithOidcMethod != nil { return obj.UpdateRegistrationFlowWithOidcMethod } diff --git a/internal/httpclient/model_update_registration_flow_with_code_method.go b/internal/httpclient/model_update_registration_flow_with_code_method.go new file mode 100644 index 000000000000..46b9126d666f --- /dev/null +++ b/internal/httpclient/model_update_registration_flow_with_code_method.go @@ -0,0 +1,286 @@ +/* + * Ory Identities API + * + * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. + * + * API version: + * Contact: office@ory.sh + */ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +import ( + "encoding/json" +) + +// UpdateRegistrationFlowWithCodeMethod Update Registration Flow with Code Method +type UpdateRegistrationFlowWithCodeMethod struct { + // The OTP Code sent to the user + Code *string `json:"code,omitempty"` + // The CSRF Token + CsrfToken *string `json:"csrf_token,omitempty"` + // Method to use This field must be set to `code` when using the code method. + Method string `json:"method"` + // Resend restarts the flow with a new code + Resend *string `json:"resend,omitempty"` + // The identity's traits + Traits map[string]interface{} `json:"traits"` + // Transient data to pass along to any webhooks + TransientPayload map[string]interface{} `json:"transient_payload,omitempty"` +} + +// NewUpdateRegistrationFlowWithCodeMethod instantiates a new UpdateRegistrationFlowWithCodeMethod 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 NewUpdateRegistrationFlowWithCodeMethod(method string, traits map[string]interface{}) *UpdateRegistrationFlowWithCodeMethod { + this := UpdateRegistrationFlowWithCodeMethod{} + this.Method = method + this.Traits = traits + return &this +} + +// NewUpdateRegistrationFlowWithCodeMethodWithDefaults instantiates a new UpdateRegistrationFlowWithCodeMethod 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 NewUpdateRegistrationFlowWithCodeMethodWithDefaults() *UpdateRegistrationFlowWithCodeMethod { + this := UpdateRegistrationFlowWithCodeMethod{} + return &this +} + +// GetCode returns the Code field value if set, zero value otherwise. +func (o *UpdateRegistrationFlowWithCodeMethod) GetCode() string { + if o == nil || o.Code == nil { + var ret string + return ret + } + return *o.Code +} + +// GetCodeOk returns a tuple with the Code field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UpdateRegistrationFlowWithCodeMethod) GetCodeOk() (*string, bool) { + if o == nil || o.Code == nil { + return nil, false + } + return o.Code, true +} + +// HasCode returns a boolean if a field has been set. +func (o *UpdateRegistrationFlowWithCodeMethod) HasCode() bool { + if o != nil && o.Code != nil { + return true + } + + return false +} + +// SetCode gets a reference to the given string and assigns it to the Code field. +func (o *UpdateRegistrationFlowWithCodeMethod) SetCode(v string) { + o.Code = &v +} + +// GetCsrfToken returns the CsrfToken field value if set, zero value otherwise. +func (o *UpdateRegistrationFlowWithCodeMethod) GetCsrfToken() string { + if o == nil || o.CsrfToken == nil { + var ret string + return ret + } + return *o.CsrfToken +} + +// GetCsrfTokenOk returns a tuple with the CsrfToken field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UpdateRegistrationFlowWithCodeMethod) GetCsrfTokenOk() (*string, bool) { + if o == nil || o.CsrfToken == nil { + return nil, false + } + return o.CsrfToken, true +} + +// HasCsrfToken returns a boolean if a field has been set. +func (o *UpdateRegistrationFlowWithCodeMethod) HasCsrfToken() bool { + if o != nil && o.CsrfToken != nil { + return true + } + + return false +} + +// SetCsrfToken gets a reference to the given string and assigns it to the CsrfToken field. +func (o *UpdateRegistrationFlowWithCodeMethod) SetCsrfToken(v string) { + o.CsrfToken = &v +} + +// GetMethod returns the Method field value +func (o *UpdateRegistrationFlowWithCodeMethod) GetMethod() string { + if o == nil { + var ret string + return ret + } + + return o.Method +} + +// GetMethodOk returns a tuple with the Method field value +// and a boolean to check if the value has been set. +func (o *UpdateRegistrationFlowWithCodeMethod) GetMethodOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Method, true +} + +// SetMethod sets field value +func (o *UpdateRegistrationFlowWithCodeMethod) SetMethod(v string) { + o.Method = v +} + +// GetResend returns the Resend field value if set, zero value otherwise. +func (o *UpdateRegistrationFlowWithCodeMethod) GetResend() string { + if o == nil || o.Resend == nil { + var ret string + return ret + } + return *o.Resend +} + +// GetResendOk returns a tuple with the Resend field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UpdateRegistrationFlowWithCodeMethod) GetResendOk() (*string, bool) { + if o == nil || o.Resend == nil { + return nil, false + } + return o.Resend, true +} + +// HasResend returns a boolean if a field has been set. +func (o *UpdateRegistrationFlowWithCodeMethod) HasResend() bool { + if o != nil && o.Resend != nil { + return true + } + + return false +} + +// SetResend gets a reference to the given string and assigns it to the Resend field. +func (o *UpdateRegistrationFlowWithCodeMethod) SetResend(v string) { + o.Resend = &v +} + +// GetTraits returns the Traits field value +func (o *UpdateRegistrationFlowWithCodeMethod) GetTraits() map[string]interface{} { + if o == nil { + var ret map[string]interface{} + return ret + } + + return o.Traits +} + +// GetTraitsOk returns a tuple with the Traits field value +// and a boolean to check if the value has been set. +func (o *UpdateRegistrationFlowWithCodeMethod) GetTraitsOk() (map[string]interface{}, bool) { + if o == nil { + return nil, false + } + return o.Traits, true +} + +// SetTraits sets field value +func (o *UpdateRegistrationFlowWithCodeMethod) SetTraits(v map[string]interface{}) { + o.Traits = v +} + +// GetTransientPayload returns the TransientPayload field value if set, zero value otherwise. +func (o *UpdateRegistrationFlowWithCodeMethod) GetTransientPayload() map[string]interface{} { + if o == nil || o.TransientPayload == nil { + var ret map[string]interface{} + return ret + } + return o.TransientPayload +} + +// GetTransientPayloadOk returns a tuple with the TransientPayload field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UpdateRegistrationFlowWithCodeMethod) GetTransientPayloadOk() (map[string]interface{}, bool) { + if o == nil || o.TransientPayload == nil { + return nil, false + } + return o.TransientPayload, true +} + +// HasTransientPayload returns a boolean if a field has been set. +func (o *UpdateRegistrationFlowWithCodeMethod) HasTransientPayload() bool { + if o != nil && o.TransientPayload != nil { + return true + } + + return false +} + +// SetTransientPayload gets a reference to the given map[string]interface{} and assigns it to the TransientPayload field. +func (o *UpdateRegistrationFlowWithCodeMethod) SetTransientPayload(v map[string]interface{}) { + o.TransientPayload = v +} + +func (o UpdateRegistrationFlowWithCodeMethod) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if o.Code != nil { + toSerialize["code"] = o.Code + } + if o.CsrfToken != nil { + toSerialize["csrf_token"] = o.CsrfToken + } + if true { + toSerialize["method"] = o.Method + } + if o.Resend != nil { + toSerialize["resend"] = o.Resend + } + if true { + toSerialize["traits"] = o.Traits + } + if o.TransientPayload != nil { + toSerialize["transient_payload"] = o.TransientPayload + } + return json.Marshal(toSerialize) +} + +type NullableUpdateRegistrationFlowWithCodeMethod struct { + value *UpdateRegistrationFlowWithCodeMethod + isSet bool +} + +func (v NullableUpdateRegistrationFlowWithCodeMethod) Get() *UpdateRegistrationFlowWithCodeMethod { + return v.value +} + +func (v *NullableUpdateRegistrationFlowWithCodeMethod) Set(val *UpdateRegistrationFlowWithCodeMethod) { + v.value = val + v.isSet = true +} + +func (v NullableUpdateRegistrationFlowWithCodeMethod) IsSet() bool { + return v.isSet +} + +func (v *NullableUpdateRegistrationFlowWithCodeMethod) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableUpdateRegistrationFlowWithCodeMethod(val *UpdateRegistrationFlowWithCodeMethod) *NullableUpdateRegistrationFlowWithCodeMethod { + return &NullableUpdateRegistrationFlowWithCodeMethod{value: val, isSet: true} +} + +func (v NullableUpdateRegistrationFlowWithCodeMethod) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableUpdateRegistrationFlowWithCodeMethod) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/httpclient/model_verification_flow.go b/internal/httpclient/model_verification_flow.go index 5190da660254..c10870c9f841 100644 --- a/internal/httpclient/model_verification_flow.go +++ b/internal/httpclient/model_verification_flow.go @@ -29,8 +29,9 @@ type VerificationFlow struct { // 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,omitempty"` // ReturnTo contains the requested return_to URL. - ReturnTo *string `json:"return_to,omitempty"` - State VerificationFlowState `json:"state"` + ReturnTo *string `json:"return_to,omitempty"` + // State represents the state of this request: choose_method: ask the user to choose a method (e.g. verify your email) sent_email: the email has been sent to the user passed_challenge: the request was successful and the verification challenge was passed. + State interface{} `json:"state"` // The flow type can either be `api` or `browser`. Type string `json:"type"` Ui UiContainer `json:"ui"` @@ -40,7 +41,7 @@ type VerificationFlow struct { // 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 NewVerificationFlow(id string, state VerificationFlowState, type_ string, ui UiContainer) *VerificationFlow { +func NewVerificationFlow(id string, state interface{}, type_ string, ui UiContainer) *VerificationFlow { this := VerificationFlow{} this.Id = id this.State = state @@ -242,9 +243,10 @@ func (o *VerificationFlow) SetReturnTo(v string) { } // GetState returns the State field value -func (o *VerificationFlow) GetState() VerificationFlowState { +// If the value is explicit nil, the zero value for interface{} will be returned +func (o *VerificationFlow) GetState() interface{} { if o == nil { - var ret VerificationFlowState + var ret interface{} return ret } @@ -253,15 +255,16 @@ func (o *VerificationFlow) GetState() VerificationFlowState { // GetStateOk returns a tuple with the State field value // and a boolean to check if the value has been set. -func (o *VerificationFlow) GetStateOk() (*VerificationFlowState, bool) { - if o == nil { +// NOTE: If the value is an explicit nil, `nil, true` will be returned +func (o *VerificationFlow) GetStateOk() (*interface{}, bool) { + if o == nil || o.State == nil { return nil, false } return &o.State, true } // SetState sets field value -func (o *VerificationFlow) SetState(v VerificationFlowState) { +func (o *VerificationFlow) SetState(v interface{}) { o.State = v } @@ -333,7 +336,7 @@ func (o VerificationFlow) MarshalJSON() ([]byte, error) { if o.ReturnTo != nil { toSerialize["return_to"] = o.ReturnTo } - if true { + if o.State != nil { toSerialize["state"] = o.State } if true { diff --git a/internal/testhelpers/courier.go b/internal/testhelpers/courier.go index 825ff4c0ec6d..fd9aa63f45d2 100644 --- a/internal/testhelpers/courier.go +++ b/internal/testhelpers/courier.go @@ -6,25 +6,38 @@ package testhelpers import ( "context" "regexp" + "sort" "strings" "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/ory/kratos/courier" + "github.com/ory/x/pagination/keysetpagination" ) -func CourierExpectMessage(t *testing.T, reg interface { +func CourierExpectMessage(ctx context.Context, t *testing.T, reg interface { courier.PersistenceProvider -}, recipient, subject string) *courier.Message { - message, err := reg.CourierPersister().LatestQueuedMessage(context.Background()) +}, recipient, subject string, +) *courier.Message { + messages, total, _, err := reg.CourierPersister().ListMessages(ctx, courier.ListCourierMessagesParameters{ + Recipient: recipient, + }, []keysetpagination.Option{}) require.NoError(t, err) + require.GreaterOrEqual(t, total, int64(1)) - assert.EqualValues(t, subject, strings.TrimSpace(message.Subject)) - assert.EqualValues(t, recipient, strings.TrimSpace(message.Recipient)) + sort.Slice(messages, func(i, j int) bool { + return messages[i].CreatedAt.After(messages[j].CreatedAt) + }) - return message + for _, m := range messages { + if strings.EqualFold(m.Recipient, recipient) && strings.EqualFold(m.Subject, subject) { + return &m + } + } + + require.Failf(t, "could not find courier messages with recipient %s and subject %s", recipient, subject) + return nil } func CourierExpectLinkInMessage(t *testing.T, message *courier.Message, offset int) string { diff --git a/persistence/reference.go b/persistence/reference.go index 215ceb4a7f3f..56a7ca1712df 100644 --- a/persistence/reference.go +++ b/persistence/reference.go @@ -51,6 +51,8 @@ type Persister interface { link.VerificationTokenPersister code.RecoveryCodePersister code.VerificationCodePersister + code.RegistrationCodePersister + code.LoginCodePersister CleanupDatabase(context.Context, time.Duration, time.Duration, int) error Close(context.Context) error diff --git a/persistence/sql/migratest/fixtures/identity/28ff0031-190b-4253-bd15-14308dec013e.json b/persistence/sql/migratest/fixtures/identity/28ff0031-190b-4253-bd15-14308dec013e.json new file mode 100644 index 000000000000..bed9cbb51ee4 --- /dev/null +++ b/persistence/sql/migratest/fixtures/identity/28ff0031-190b-4253-bd15-14308dec013e.json @@ -0,0 +1,17 @@ +{ + "id": "28ff0031-190b-4253-bd15-14308dec013e", + "schema_id": "default", + "schema_url": "https://www.ory.sh/schemas/ZGVmYXVsdA", + "state": "active", + "traits": { + "email": "bazbarbarfoo@ory.sh" + }, + "metadata_public": { + "foo": "bar" + }, + "metadata_admin": { + "baz": "bar" + }, + "created_at": "2013-10-07T08:23:19Z", + "updated_at": "2013-10-07T08:23:19Z" +} diff --git a/persistence/sql/migratest/fixtures/login_code/bd292366-af32-4ba6-bdf0-11d6d1a217f3.json b/persistence/sql/migratest/fixtures/login_code/bd292366-af32-4ba6-bdf0-11d6d1a217f3.json new file mode 100644 index 000000000000..e695ce9e3ecf --- /dev/null +++ b/persistence/sql/migratest/fixtures/login_code/bd292366-af32-4ba6-bdf0-11d6d1a217f3.json @@ -0,0 +1,6 @@ +{ + "id": "bd292366-af32-4ba6-bdf0-11d6d1a217f3", + "expires_at": "2022-08-18T08:28:18Z", + "issued_at": "2022-08-18T07:28:18Z", + "identity_id": "28ff0031-190b-4253-bd15-14308dec013e" +} diff --git a/persistence/sql/migratest/fixtures/login_flow/00b1517f-2467-4aaf-b0a5-82b4a27dcaf5.json b/persistence/sql/migratest/fixtures/login_flow/00b1517f-2467-4aaf-b0a5-82b4a27dcaf5.json new file mode 100644 index 000000000000..17f770efbe90 --- /dev/null +++ b/persistence/sql/migratest/fixtures/login_flow/00b1517f-2467-4aaf-b0a5-82b4a27dcaf5.json @@ -0,0 +1,18 @@ +{ + "id": "00b1517f-2467-4aaf-b0a5-82b4a27dcaf5", + "oauth2_login_challenge": "challenge data", + "type": "api", + "expires_at": "2013-10-07T08:23:19Z", + "issued_at": "2013-10-07T08:23:19Z", + "request_url": "http://kratos:4433/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login", + "ui": { + "action": "", + "method": "", + "nodes": null + }, + "created_at": "2013-10-07T08:23:19Z", + "updated_at": "2013-10-07T08:23:19Z", + "refresh": false, + "requested_aal": "aal1", + "state": "choose_method" +} 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 e48e54d97a6b..ce8841aa07ff 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 @@ -12,5 +12,6 @@ "created_at": "2013-10-07T08:23:19Z", "updated_at": "2013-10-07T08:23:19Z", "refresh": false, - "requested_aal": "aal1" + "requested_aal": "aal1", + "state": "" } 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 5f63a7ec006a..770f0b2e2c38 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 @@ -12,5 +12,6 @@ "created_at": "2013-10-07T08:23:19Z", "updated_at": "2013-10-07T08:23:19Z", "refresh": false, - "requested_aal": "aal2" + "requested_aal": "aal2", + "state": "" } 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 efbd0740cdfb..b6cd377d812f 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 @@ -12,5 +12,6 @@ "created_at": "2013-10-07T08:23:19Z", "updated_at": "2013-10-07T08:23:19Z", "refresh": false, - "requested_aal": "aal1" + "requested_aal": "aal1", + "state": "" } 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 index 7586d19409ab..effdc9f1f2a0 100644 --- 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 @@ -12,5 +12,6 @@ "created_at": "2013-10-07T08:23:19Z", "updated_at": "2013-10-07T08:23:19Z", "refresh": false, - "requested_aal": "aal2" + "requested_aal": "aal2", + "state": "" } 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 084b36a0c0b9..6eac76a4e91b 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 @@ -12,5 +12,6 @@ "created_at": "2013-10-07T08:23:19Z", "updated_at": "2013-10-07T08:23:19Z", "refresh": false, - "requested_aal": "aal2" + "requested_aal": "aal2", + "state": "" } 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 13dff119fce0..577b054917db 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 @@ -12,5 +12,6 @@ "created_at": "2013-10-07T08:23:19Z", "updated_at": "2013-10-07T08:23:19Z", "refresh": false, - "requested_aal": "aal1" + "requested_aal": "aal1", + "state": "" } 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 5f1529c393b3..6f0fae29f575 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 @@ -13,5 +13,6 @@ "created_at": "2013-10-07T08:23:19Z", "updated_at": "2013-10-07T08:23:19Z", "refresh": true, - "requested_aal": "aal1" + "requested_aal": "aal1", + "state": "" } 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 fe46265a6d2e..64a415dfba4a 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 @@ -12,5 +12,6 @@ "created_at": "2013-10-07T08:23:19Z", "updated_at": "2013-10-07T08:23:19Z", "refresh": false, - "requested_aal": "aal1" + "requested_aal": "aal1", + "state": "" } 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 85156c189e4d..e2ccb8f7616d 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 @@ -12,5 +12,6 @@ "created_at": "2013-10-07T08:23:19Z", "updated_at": "2013-10-07T08:23:19Z", "refresh": false, - "requested_aal": "aal1" + "requested_aal": "aal1", + "state": "" } 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 c38727386af7..863594687d00 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 @@ -12,5 +12,6 @@ "created_at": "2013-10-07T08:23:19Z", "updated_at": "2013-10-07T08:23:19Z", "refresh": false, - "requested_aal": "aal1" + "requested_aal": "aal1", + "state": "" } 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 eb8ec21e0e31..138f4838c466 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 @@ -12,5 +12,6 @@ "created_at": "2013-10-07T08:23:19Z", "updated_at": "2013-10-07T08:23:19Z", "refresh": false, - "requested_aal": "aal1" + "requested_aal": "aal1", + "state": "" } 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 418e16ebe69b..41bc0e84748f 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 @@ -12,5 +12,6 @@ "created_at": "2013-10-07T08:23:19Z", "updated_at": "2013-10-07T08:23:19Z", "refresh": false, - "requested_aal": "aal1" + "requested_aal": "aal1", + "state": "" } 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 84eda2f96615..ae28f38c8fe4 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 @@ -12,5 +12,6 @@ "created_at": "2013-10-07T08:23:19Z", "updated_at": "2013-10-07T08:23:19Z", "refresh": false, - "requested_aal": "aal1" + "requested_aal": "aal1", + "state": "" } diff --git a/persistence/sql/migratest/fixtures/login_flow/cccccccc-dda4-4700-9e42-35731f2af911.json b/persistence/sql/migratest/fixtures/login_flow/cccccccc-dda4-4700-9e42-35731f2af911.json index b3f93459b975..a2b9861acec7 100644 --- a/persistence/sql/migratest/fixtures/login_flow/cccccccc-dda4-4700-9e42-35731f2af911.json +++ b/persistence/sql/migratest/fixtures/login_flow/cccccccc-dda4-4700-9e42-35731f2af911.json @@ -13,5 +13,6 @@ "created_at": "2013-10-07T08:23:19Z", "updated_at": "2013-10-07T08:23:19Z", "refresh": false, - "requested_aal": "aal1" + "requested_aal": "aal1", + "state": "" } diff --git a/persistence/sql/migratest/fixtures/login_flow/cccccccc-dda4-4700-9e42-35731f2af91e.json b/persistence/sql/migratest/fixtures/login_flow/cccccccc-dda4-4700-9e42-35731f2af91e.json index 438fb4005e14..e2d58f6dc1fe 100644 --- a/persistence/sql/migratest/fixtures/login_flow/cccccccc-dda4-4700-9e42-35731f2af91e.json +++ b/persistence/sql/migratest/fixtures/login_flow/cccccccc-dda4-4700-9e42-35731f2af91e.json @@ -13,5 +13,6 @@ "created_at": "2013-10-07T08:23:19Z", "updated_at": "2013-10-07T08:23:19Z", "refresh": false, - "requested_aal": "aal1" + "requested_aal": "aal1", + "state": "" } 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 87ccb1d1dcd0..00a1a2d7c3e5 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 @@ -12,5 +12,6 @@ "created_at": "2013-10-07T08:23:19Z", "updated_at": "2013-10-07T08:23:19Z", "refresh": false, - "requested_aal": "aal1" + "requested_aal": "aal1", + "state": "" } diff --git a/persistence/sql/migratest/fixtures/registration_code/f1f66a69-ce02-4a12-9591-9e02dda30a0d.json b/persistence/sql/migratest/fixtures/registration_code/f1f66a69-ce02-4a12-9591-9e02dda30a0d.json new file mode 100644 index 000000000000..5e429ce3d9ca --- /dev/null +++ b/persistence/sql/migratest/fixtures/registration_code/f1f66a69-ce02-4a12-9591-9e02dda30a0d.json @@ -0,0 +1,5 @@ +{ + "id": "f1f66a69-ce02-4a12-9591-9e02dda30a0d", + "expires_at": "2022-08-18T08:28:18Z", + "issued_at": "2022-08-18T07:28:18Z" +} 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 1e649d64ad51..ccfcf94814a5 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 @@ -8,5 +8,6 @@ "action": "", "method": "", "nodes": null - } + }, + "state": "" } 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 7f90a694387d..5c110a3394f5 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 @@ -8,5 +8,6 @@ "action": "", "method": "", "nodes": null - } + }, + "state": "" } 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 dbc832d2aa71..8df52efff06b 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 @@ -8,5 +8,6 @@ "action": "", "method": "", "nodes": null - } + }, + "state": "" } 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 6b627d7541f9..d58beb9edffc 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 @@ -9,5 +9,6 @@ "action": "", "method": "", "nodes": null - } + }, + "state": "" } diff --git a/persistence/sql/migratest/fixtures/registration_flow/69c80296-36cd-4afc-921a-15369cac5bf0.json b/persistence/sql/migratest/fixtures/registration_flow/69c80296-36cd-4afc-921a-15369cac5bf0.json new file mode 100644 index 000000000000..6179619c71fe --- /dev/null +++ b/persistence/sql/migratest/fixtures/registration_flow/69c80296-36cd-4afc-921a-15369cac5bf0.json @@ -0,0 +1,14 @@ +{ + "id": "69c80296-36cd-4afc-921a-15369cac5bf0", + "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/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge=", + "active": "password", + "ui": { + "action": "", + "method": "", + "nodes": null + }, + "state": "choose_method" +} 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 6a1dcdac29dd..19104b6d9f26 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 @@ -9,5 +9,6 @@ "action": "", "method": "", "nodes": null - } + }, + "state": "" } 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 ed2e8512fde1..616af278cd82 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 @@ -9,5 +9,6 @@ "action": "", "method": "", "nodes": null - } + }, + "state": "" } 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 df3f9c392998..a1f323ba3c4d 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 @@ -9,5 +9,6 @@ "action": "", "method": "", "nodes": null - } + }, + "state": "" } 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 2195263f1574..1e6cc2579af2 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 @@ -9,5 +9,6 @@ "action": "", "method": "", "nodes": null - } + }, + "state": "" } 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 497f88de81b2..560741f9a18d 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 @@ -9,5 +9,6 @@ "action": "", "method": "", "nodes": null - } + }, + "state": "" } diff --git a/persistence/sql/migratest/fixtures/registration_flow/ef18b06e-4700-4021-9949-ef783cd86be1.json b/persistence/sql/migratest/fixtures/registration_flow/ef18b06e-4700-4021-9949-ef783cd86be1.json index 8947653d90e7..ce1272433edf 100644 --- a/persistence/sql/migratest/fixtures/registration_flow/ef18b06e-4700-4021-9949-ef783cd86be1.json +++ b/persistence/sql/migratest/fixtures/registration_flow/ef18b06e-4700-4021-9949-ef783cd86be1.json @@ -9,5 +9,6 @@ "action": "", "method": "", "nodes": null - } + }, + "state": "" } 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 index 6763bf5c63f5..4d1d58bdaf51 100644 --- 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 @@ -9,5 +9,6 @@ "action": "", "method": "", "nodes": null - } + }, + "state": "" } 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 d894073c5468..c7d1b8207a4e 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 @@ -9,5 +9,6 @@ "action": "", "method": "", "nodes": null - } + }, + "state": "" } diff --git a/persistence/sql/migratest/migration_test.go b/persistence/sql/migratest/migration_test.go index 36126f147935..798afd54dc79 100644 --- a/persistence/sql/migratest/migration_test.go +++ b/persistence/sql/migratest/migration_test.go @@ -73,7 +73,8 @@ func CompareWithFixture(t *testing.T, actual interface{}, prefix string, id stri func TestMigrations_SQLite(t *testing.T) { t.Parallel() sqlite, err := pop.NewConnection(&pop.ConnectionDetails{ - URL: "sqlite3://" + filepath.Join(os.TempDir(), x.NewUUID().String()) + ".sql?_fk=true"}) + URL: "sqlite3://" + filepath.Join(os.TempDir(), x.NewUUID().String()) + ".sql?_fk=true", + }) require.NoError(t, err) require.NoError(t, sqlite.Open()) @@ -105,7 +106,6 @@ func TestMigrations_Cockroach(t *testing.T) { } func testDatabase(t *testing.T, db string, c *pop.Connection) { - ctx := context.Background() l := logrusx.New("", "", logrusx.ForceLevel(logrus.ErrorLevel)) @@ -372,6 +372,40 @@ func testDatabase(t *testing.T, db string, c *pop.Connection) { migratest.ContainsExpectedIds(t, filepath.Join("fixtures", "recovery_code"), found) }) + t.Run("case=registration_code", func(t *testing.T) { + wg.Add(1) + defer wg.Done() + t.Parallel() + + var ids []code.RegistrationCode + require.NoError(t, c.All(&ids)) + require.NotEmpty(t, ids) + + var found []string + for _, id := range ids { + found = append(found, id.ID.String()) + CompareWithFixture(t, id, "registration_code", id.ID.String()) + } + migratest.ContainsExpectedIds(t, filepath.Join("fixtures", "registration_code"), found) + }) + + t.Run("case=login_code", func(t *testing.T) { + wg.Add(1) + defer wg.Done() + t.Parallel() + + var ids []code.LoginCode + require.NoError(t, c.All(&ids)) + require.NotEmpty(t, ids) + + var found []string + for _, id := range ids { + found = append(found, id.ID.String()) + CompareWithFixture(t, id, "login_code", id.ID.String()) + } + migratest.ContainsExpectedIds(t, filepath.Join("fixtures", "login_code"), found) + }) + t.Run("suite=constraints", func(t *testing.T) { // This is not really a parallel test, but we have to mark it parallel so the other tests run first. t.Parallel() diff --git a/persistence/sql/migratest/testdata/20230707133700_testdata.sql b/persistence/sql/migratest/testdata/20230707133700_testdata.sql new file mode 100644 index 000000000000..bcfc9bc12f58 --- /dev/null +++ b/persistence/sql/migratest/testdata/20230707133700_testdata.sql @@ -0,0 +1,30 @@ +INSERT INTO selfservice_login_flows (id,nid, request_url, issued_at, expires_at, active_method, csrf_token, created_at, + updated_at, forced, type, ui, internal_context, oauth2_login_challenge_data, state) +VALUES ('00b1517f-2467-4aaf-b0a5-82b4a27dcaf5', + '884f556e-eb3a-4b9f-bee3-11345642c6c0', + 'http://kratos:4433/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login/self-service/browser/flows/login', + '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, 'api', '{}', '{"foo":"bar"}', 'challenge data', 'choose_method'); + +INSERT INTO identities (id, nid, schema_id, traits, created_at, updated_at, metadata_public, metadata_admin, + available_aal) +VALUES ('28ff0031-190b-4253-bd15-14308dec013e', '884f556e-eb3a-4b9f-bee3-11345642c6c0', 'default', + '{"email":"bazbarbarfoo@ory.sh"}', '2013-10-07 08:23:19', '2013-10-07 08:23:19', '{"foo":"bar"}', '{"baz":"bar"}', + NULL); + +INSERT INTO identity_login_codes (id, code, address, address_type, used_at, expires_at, issued_at, selfservice_login_flow_id, identity_id, + created_at, updated_at, nid) +VALUES ('bd292366-af32-4ba6-bdf0-11d6d1a217f3', +'7eb71370d8497734ec78dfe613bf0f08967e206d2b5c2fc1243be823cfcd57a7', +'bazbarbarfoo@ory.com', +'email', +null, +'2022-08-18 08:28:18', +'2022-08-18 07:28:18', +'00b1517f-2467-4aaf-b0a5-82b4a27dcaf5', +'28ff0031-190b-4253-bd15-14308dec013e', +'2022-08-18 07:28:18', +'2022-08-18 07:28:18', +'884f556e-eb3a-4b9f-bee3-11345642c6c0' +) diff --git a/persistence/sql/migratest/testdata/20230707133701_testdata.sql b/persistence/sql/migratest/testdata/20230707133701_testdata.sql new file mode 100644 index 000000000000..8a256314ae95 --- /dev/null +++ b/persistence/sql/migratest/testdata/20230707133701_testdata.sql @@ -0,0 +1,23 @@ +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, state) +VALUES ('69c80296-36cd-4afc-921a-15369cac5bf0', '884f556e-eb3a-4b9f-bee3-11345642c6c0', + 'http://kratos:4433/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/self-service/browser/flows/registration?login_challenge/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', 'choose_method'); + +INSERT INTO identity_registration_codes (id, address, address_type, code, used_at, expires_at, issued_at, selfservice_registration_flow_id, + created_at, updated_at, nid) +VALUES ('f1f66a69-ce02-4a12-9591-9e02dda30a0d', +'example@example.com', +'email', +'7eb71370d8497734ec78dfe613bf0f08967e206d2b5c2fc1243be823cfcd57a7', +null, +'2022-08-18 08:28:18', +'2022-08-18 07:28:18', +'69c80296-36cd-4afc-921a-15369cac5bf0', +'2022-08-18 07:28:18', +'2022-08-18 07:28:18', +'884f556e-eb3a-4b9f-bee3-11345642c6c0' +) diff --git a/persistence/sql/migrations/sql/20230703143600000001_selfservice_registration_login_flows_state.down.sql b/persistence/sql/migrations/sql/20230703143600000001_selfservice_registration_login_flows_state.down.sql new file mode 100644 index 000000000000..ddd3c7bbfbc0 --- /dev/null +++ b/persistence/sql/migrations/sql/20230703143600000001_selfservice_registration_login_flows_state.down.sql @@ -0,0 +1,2 @@ +ALTER table selfservice_registration_flows DROP COLUMN state; +ALTER table selfservice_login_flows DROP COLUMN state; diff --git a/persistence/sql/migrations/sql/20230703143600000001_selfservice_registration_login_flows_state.up.sql b/persistence/sql/migrations/sql/20230703143600000001_selfservice_registration_login_flows_state.up.sql new file mode 100644 index 000000000000..26f4d0649508 --- /dev/null +++ b/persistence/sql/migrations/sql/20230703143600000001_selfservice_registration_login_flows_state.up.sql @@ -0,0 +1,2 @@ +ALTER table selfservice_login_flows ADD state VARCHAR(255) NULL; +ALTER table selfservice_registration_flows ADD state VARCHAR(255) NULL; diff --git a/persistence/sql/migrations/sql/20230707133700000000_identity_login_code.down.sql b/persistence/sql/migrations/sql/20230707133700000000_identity_login_code.down.sql new file mode 100644 index 000000000000..3738073d0aa9 --- /dev/null +++ b/persistence/sql/migrations/sql/20230707133700000000_identity_login_code.down.sql @@ -0,0 +1,3 @@ +DROP TABLE identity_login_codes; + +ALTER TABLE selfservice_login_flows DROP submit_count; diff --git a/persistence/sql/migrations/sql/20230707133700000000_identity_login_code.mysql.up.sql b/persistence/sql/migrations/sql/20230707133700000000_identity_login_code.mysql.up.sql new file mode 100644 index 000000000000..9ddc6c72d8ac --- /dev/null +++ b/persistence/sql/migrations/sql/20230707133700000000_identity_login_code.mysql.up.sql @@ -0,0 +1,29 @@ +CREATE TABLE identity_login_codes +( + id CHAR(36) NOT NULL PRIMARY KEY, + code VARCHAR(64) NOT NULL, -- HMACed value of the actual code + address VARCHAR(255) NOT NULL, + address_type CHAR(36) NOT NULL, + used_at timestamp NULL DEFAULT NULL, + expires_at timestamp NOT NULL DEFAULT '2000-01-01 00:00:00', + issued_at timestamp NOT NULL DEFAULT '2000-01-01 00:00:00', + selfservice_login_flow_id CHAR(36), + identity_id CHAR(36) NOT NULL, + created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + nid CHAR(36) NOT NULL, + CONSTRAINT identity_login_codes_selfservice_login_flows_id_fk + FOREIGN KEY (selfservice_login_flow_id) + REFERENCES selfservice_login_flows (id) + ON DELETE cascade, + CONSTRAINT identity_login_codes_networks_id_fk + FOREIGN KEY (nid) + REFERENCES networks (id) + ON UPDATE RESTRICT ON DELETE CASCADE +); + +CREATE INDEX identity_login_codes_nid_flow_id_idx ON identity_login_codes (nid, selfservice_login_flow_id); +CREATE INDEX identity_login_codes_id_nid_idx ON identity_login_codes (id, nid); + + +ALTER TABLE selfservice_login_flows ADD submit_count int NOT NULL DEFAULT 0; diff --git a/persistence/sql/migrations/sql/20230707133700000000_identity_login_code.up.sql b/persistence/sql/migrations/sql/20230707133700000000_identity_login_code.up.sql new file mode 100644 index 000000000000..7df0e9b00e21 --- /dev/null +++ b/persistence/sql/migrations/sql/20230707133700000000_identity_login_code.up.sql @@ -0,0 +1,28 @@ +CREATE TABLE identity_login_codes +( + id UUID NOT NULL PRIMARY KEY, + code VARCHAR(64) NOT NULL, -- HMACed value of the actual code + address VARCHAR(255) NOT NULL, + address_type CHAR(36) NOT NULL, + used_at timestamp NULL DEFAULT NULL, + expires_at timestamp NOT NULL DEFAULT '2000-01-01 00:00:00', + issued_at timestamp NOT NULL DEFAULT '2000-01-01 00:00:00', + selfservice_login_flow_id UUID NOT NULL, + identity_id UUID NOT NULL, + created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + nid UUID NOT NULL, + CONSTRAINT identity_login_codes_selfservice_login_flows_id_fk + FOREIGN KEY (selfservice_login_flow_id) + REFERENCES selfservice_login_flows (id) + ON DELETE cascade, + CONSTRAINT identity_login_codes_networks_id_fk + FOREIGN KEY (nid) + REFERENCES networks (id) + ON UPDATE RESTRICT ON DELETE CASCADE +); + +CREATE INDEX identity_login_codes_nid_flow_id_idx ON identity_login_codes (nid, selfservice_login_flow_id); +CREATE INDEX identity_login_codes_id_nid_idx ON identity_login_codes (id, nid); + +ALTER TABLE selfservice_login_flows ADD submit_count int NOT NULL DEFAULT 0; diff --git a/persistence/sql/migrations/sql/20230707133700000001_identity_registration_code.down.sql b/persistence/sql/migrations/sql/20230707133700000001_identity_registration_code.down.sql new file mode 100644 index 000000000000..d4211e92a776 --- /dev/null +++ b/persistence/sql/migrations/sql/20230707133700000001_identity_registration_code.down.sql @@ -0,0 +1,3 @@ +DROP TABLE identity_registration_codes; + +ALTER TABLE selfservice_registration_flows DROP submit_count; diff --git a/persistence/sql/migrations/sql/20230707133700000001_identity_registration_code.mysql.up.sql b/persistence/sql/migrations/sql/20230707133700000001_identity_registration_code.mysql.up.sql new file mode 100644 index 000000000000..36f049d58c1a --- /dev/null +++ b/persistence/sql/migrations/sql/20230707133700000001_identity_registration_code.mysql.up.sql @@ -0,0 +1,27 @@ +CREATE TABLE identity_registration_codes +( + id CHAR(36) NOT NULL PRIMARY KEY, + code VARCHAR(64) NOT NULL, -- HMACed value of the actual code + address VARCHAR(255) NOT NULL, + address_type CHAR(36) NOT NULL, + used_at timestamp NULL DEFAULT NULL, + expires_at timestamp NOT NULL DEFAULT '2000-01-01 00:00:00', + issued_at timestamp NOT NULL DEFAULT '2000-01-01 00:00:00', + selfservice_registration_flow_id CHAR(36), + created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + nid CHAR(36) NOT NULL, + CONSTRAINT identity_registration_codes_selfservice_registration_flows_id_fk + FOREIGN KEY (selfservice_registration_flow_id) + REFERENCES selfservice_registration_flows (id) + ON DELETE cascade, + CONSTRAINT identity_registration_codes_networks_id_fk + FOREIGN KEY (nid) + REFERENCES networks (id) + ON UPDATE RESTRICT ON DELETE CASCADE +); + +CREATE INDEX identity_registration_codes_nid_flow_id_idx ON identity_registration_codes (nid, selfservice_registration_flow_id); +CREATE INDEX identity_registration_codes_id_nid_idx ON identity_registration_codes (id, nid); + +ALTER TABLE selfservice_registration_flows ADD submit_count int NOT NULL DEFAULT 0; diff --git a/persistence/sql/migrations/sql/20230707133700000001_identity_registration_code.up.sql b/persistence/sql/migrations/sql/20230707133700000001_identity_registration_code.up.sql new file mode 100644 index 000000000000..0dc3a9879341 --- /dev/null +++ b/persistence/sql/migrations/sql/20230707133700000001_identity_registration_code.up.sql @@ -0,0 +1,27 @@ +CREATE TABLE identity_registration_codes +( + id UUID NOT NULL PRIMARY KEY, + code VARCHAR(64) NOT NULL, -- HMACed value of the actual code + address VARCHAR(255) NOT NULL, + address_type CHAR(36) NOT NULL, + used_at timestamp NULL DEFAULT NULL, + expires_at timestamp NOT NULL DEFAULT '2000-01-01 00:00:00', + issued_at timestamp NOT NULL DEFAULT '2000-01-01 00:00:00', + selfservice_registration_flow_id UUID NOT NULL, + created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + nid UUID NOT NULL, + CONSTRAINT identity_registration_codes_selfservice_registration_flows_id_fk + FOREIGN KEY (selfservice_registration_flow_id) + REFERENCES selfservice_registration_flows (id) + ON DELETE cascade, + CONSTRAINT identity_registration_codes_networks_id_fk + FOREIGN KEY (nid) + REFERENCES networks (id) + ON UPDATE RESTRICT ON DELETE CASCADE +); + +CREATE INDEX identity_registration_codes_nid_flow_id_idx ON identity_registration_codes (nid, selfservice_registration_flow_id); +CREATE INDEX identity_registration_codes_id_nid_idx ON identity_registration_codes (id, nid); + +ALTER TABLE selfservice_registration_flows ADD submit_count int NOT NULL DEFAULT 0; diff --git a/persistence/sql/migrations/sql/20230712173852000000_credential_types_code.down.sql b/persistence/sql/migrations/sql/20230712173852000000_credential_types_code.down.sql new file mode 100644 index 000000000000..84f10f939a12 --- /dev/null +++ b/persistence/sql/migrations/sql/20230712173852000000_credential_types_code.down.sql @@ -0,0 +1 @@ +DELETE FROM identity_credential_types WHERE name = 'code'; diff --git a/persistence/sql/migrations/sql/20230712173852000000_credential_types_code.up.sql b/persistence/sql/migrations/sql/20230712173852000000_credential_types_code.up.sql new file mode 100644 index 000000000000..47e0cf0b2b34 --- /dev/null +++ b/persistence/sql/migrations/sql/20230712173852000000_credential_types_code.up.sql @@ -0,0 +1 @@ +INSERT INTO identity_credential_types (id, name) SELECT '14f3b7e2-8725-4068-be39-8a796485fd97', 'code' WHERE NOT EXISTS ( SELECT * FROM identity_credential_types WHERE name = 'code'); diff --git a/persistence/sql/persister_code.go b/persistence/sql/persister_code.go new file mode 100644 index 000000000000..3b8103a36361 --- /dev/null +++ b/persistence/sql/persister_code.go @@ -0,0 +1,123 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package sql + +import ( + "context" + "crypto/subtle" + "fmt" + "time" + + "github.com/gobuffalo/pop/v6" + "github.com/gofrs/uuid" + "github.com/pkg/errors" + + "github.com/ory/kratos/selfservice/strategy/code" + "github.com/ory/x/sqlcon" +) + +type oneTimeCodeProvider interface { + GetID() uuid.UUID + Validate() error + TableName(ctx context.Context) string + GetHMACCode() string +} + +type codeOptions struct { + IdentityID *uuid.UUID +} + +type codeOption func(o *codeOptions) + +func withCheckIdentityID(id uuid.UUID) codeOption { + return func(o *codeOptions) { + o.IdentityID = &id + } +} + +func useOneTimeCode[P any, U interface { + *P + oneTimeCodeProvider +}](ctx context.Context, p *Persister, flowID uuid.UUID, userProvidedCode string, flowTableName string, foreignKeyName string, opts ...codeOption) (U, error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.useOneTimeCode") + defer span.End() + + o := new(codeOptions) + for _, opt := range opts { + opt(o) + } + + var target U + nid := p.NetworkID(ctx) + if err := p.Transaction(ctx, func(ctx context.Context, tx *pop.Connection) error { + //#nosec G201 -- TableName is static + if err := tx.RawQuery(fmt.Sprintf("UPDATE %s SET submit_count = submit_count + 1 WHERE id = ? AND nid = ?", flowTableName), flowID, nid).Exec(); err != nil { + return err + } + + var submitCount int + // Because MySQL does not support "RETURNING" clauses, but we need the updated `submit_count` later on. + //#nosec G201 -- TableName is static + if err := sqlcon.HandleError(tx.RawQuery(fmt.Sprintf("SELECT submit_count FROM %s WHERE id = ? AND nid = ?", flowTableName), flowID, nid).First(&submitCount)); err != nil { + if errors.Is(err, sqlcon.ErrNoRows) { + // Return no error, as that would roll back the transaction + return nil + } + return err + } + + // This check prevents parallel brute force attacks by checking the submit count inside this database + // transaction. If the flow has been submitted more than 5 times, the transaction is aborted (regardless of + // whether the code was correct or not) and we thus give no indication whether the supplied code was correct or + // not. For more explanation see [this comment](https://github.com/ory/kratos/pull/2645#discussion_r984732899). + if submitCount > 5 { + return errors.WithStack(code.ErrCodeSubmittedTooOften) + } + + var codes []U + codesQuery := tx.Where(fmt.Sprintf("nid = ? AND %s = ?", foreignKeyName), nid, flowID) + if o.IdentityID != nil { + codesQuery = codesQuery.Where("identity_id = ?", *o.IdentityID) + } + + if err := sqlcon.HandleError(codesQuery.All(&codes)); err != nil { + if errors.Is(err, sqlcon.ErrNoRows) { + // Return no error, as that would roll back the transaction and reset the submit count. + return nil + } + + return err + } + + secrets: + for _, secret := range p.r.Config().SecretsSession(ctx) { + suppliedCode := []byte(p.hmacValueWithSecret(ctx, userProvidedCode, secret)) + for i := range codes { + c := codes[i] + if subtle.ConstantTimeCompare([]byte(c.GetHMACCode()), suppliedCode) == 0 { + // Not the supplied code + continue + } + target = c + break secrets + } + } + + if target.Validate() != nil { + // Return no error, as that would roll back the transaction + return nil + } + + //#nosec G201 -- TableName is static + return tx.RawQuery(fmt.Sprintf("UPDATE %s SET used_at = ? WHERE id = ? AND nid = ?", target.TableName(ctx)), time.Now().UTC(), target.GetID(), nid).Exec() + }); err != nil { + return nil, sqlcon.HandleError(err) + } + + if err := target.Validate(); err != nil { + return nil, err + } + + return target, nil +} diff --git a/persistence/sql/persister_login.go b/persistence/sql/persister_login.go index 1f29a1860e35..ec1da55babbb 100644 --- a/persistence/sql/persister_login.go +++ b/persistence/sql/persister_login.go @@ -9,7 +9,6 @@ import ( "time" "github.com/gobuffalo/pop/v6" - "github.com/gofrs/uuid" "github.com/ory/x/sqlcon" diff --git a/persistence/sql/persister_login_code.go b/persistence/sql/persister_login_code.go new file mode 100644 index 000000000000..3d5dd027826d --- /dev/null +++ b/persistence/sql/persister_login_code.go @@ -0,0 +1,69 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package sql + +import ( + "context" + "time" + + "github.com/gofrs/uuid" + + "github.com/ory/kratos/selfservice/flow/login" + "github.com/ory/kratos/selfservice/strategy/code" + "github.com/ory/x/sqlcon" +) + +func (p *Persister) CreateLoginCode(ctx context.Context, params *code.CreateLoginCodeParams) (*code.LoginCode, error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateLoginCode") + defer span.End() + + now := time.Now().UTC() + loginCode := &code.LoginCode{ + IdentityID: params.IdentityID, + Address: params.Address, + AddressType: params.AddressType, + CodeHMAC: p.hmacValue(ctx, params.RawCode), + IssuedAt: now, + ExpiresAt: now.UTC().Add(p.r.Config().SelfServiceCodeMethodLifespan(ctx)), + FlowID: params.FlowID, + NID: p.NetworkID(ctx), + ID: uuid.Nil, + } + + if err := p.GetConnection(ctx).Create(loginCode); err != nil { + return nil, sqlcon.HandleError(err) + } + + return loginCode, nil +} + +func (p *Persister) UseLoginCode(ctx context.Context, flowID uuid.UUID, identityID uuid.UUID, userProvidedCode string) (*code.LoginCode, error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.UseLoginCode") + defer span.End() + + codeRow, err := useOneTimeCode[code.LoginCode, *code.LoginCode](ctx, p, flowID, userProvidedCode, new(login.Flow).TableName(ctx), "selfservice_login_flow_id", withCheckIdentityID(identityID)) + if err != nil { + return nil, err + } + + return codeRow, nil +} + +func (p *Persister) GetUsedLoginCode(ctx context.Context, flowID uuid.UUID) (*code.LoginCode, error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetUsedLoginCode") + defer span.End() + + var loginCode code.LoginCode + if err := p.Connection(ctx).Where("selfservice_login_flow_id = ? AND nid = ? AND used_at IS NOT NULL", flowID, p.NetworkID(ctx)).First(&loginCode); err != nil { + return nil, sqlcon.HandleError(err) + } + return &loginCode, nil +} + +func (p *Persister) DeleteLoginCodesOfFlow(ctx context.Context, flowID uuid.UUID) error { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteLoginCodesOfFlow") + defer span.End() + + return p.GetConnection(ctx).Where("selfservice_login_flow_id = ? AND nid = ?", flowID, p.NetworkID(ctx)).Delete(&code.LoginCode{}) +} diff --git a/persistence/sql/persister_recovery.go b/persistence/sql/persister_recovery.go index d34a6fabd435..8ac81cd009a5 100644 --- a/persistence/sql/persister_recovery.go +++ b/persistence/sql/persister_recovery.go @@ -5,7 +5,6 @@ package sql import ( "context" - "crypto/subtle" "fmt" "time" @@ -16,15 +15,15 @@ import ( "github.com/ory/kratos/identity" "github.com/ory/kratos/persistence/sql/update" - "github.com/ory/kratos/selfservice/flow" "github.com/ory/kratos/selfservice/flow/recovery" - "github.com/ory/kratos/selfservice/strategy/code" "github.com/ory/kratos/selfservice/strategy/link" "github.com/ory/x/sqlcon" ) -var _ recovery.FlowPersister = new(Persister) -var _ link.RecoveryTokenPersister = new(Persister) +var ( + _ recovery.FlowPersister = new(Persister) + _ link.RecoveryTokenPersister = new(Persister) +) func (p *Persister) CreateRecoveryFlow(ctx context.Context, r *recovery.Flow) error { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateRecoveryFlow") @@ -135,145 +134,3 @@ func (p *Persister) DeleteExpiredRecoveryFlows(ctx context.Context, expiresAt ti } return nil } - -func (p *Persister) CreateRecoveryCode(ctx context.Context, dto *code.CreateRecoveryCodeParams) (*code.RecoveryCode, error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateRecoveryCode") - defer span.End() - - now := time.Now() - - recoveryCode := &code.RecoveryCode{ - ID: uuid.Nil, - CodeHMAC: p.hmacValue(ctx, dto.RawCode), - ExpiresAt: now.UTC().Add(dto.ExpiresIn), - IssuedAt: now, - CodeType: dto.CodeType, - FlowID: dto.FlowID, - NID: p.NetworkID(ctx), - IdentityID: dto.IdentityID, - } - - if dto.RecoveryAddress != nil { - recoveryCode.RecoveryAddress = dto.RecoveryAddress - recoveryCode.RecoveryAddressID = uuid.NullUUID{ - UUID: dto.RecoveryAddress.ID, - Valid: true, - } - } - - // This should not create the request eagerly because otherwise we might accidentally create an address that isn't - // supposed to be in the database. - if err := p.GetConnection(ctx).Create(recoveryCode); err != nil { - return nil, err - } - - return recoveryCode, nil -} - -// UseRecoveryCode attempts to "use" the supplied code in the flow -// -// If the supplied code matched a code from the flow, no error is returned -// If an invalid code was submitted with this flow more than 5 times, an error is returned -// TODO: Extract the business logic to a new service/manager (https://github.com/ory/kratos/issues/2785) -func (p *Persister) UseRecoveryCode(ctx context.Context, fID uuid.UUID, codeVal string) (*code.RecoveryCode, error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.UseRecoveryCode") - defer span.End() - - var recoveryCode *code.RecoveryCode - - nid := p.NetworkID(ctx) - - flowTableName := new(recovery.Flow).TableName(ctx) - - if err := sqlcon.HandleError(p.Transaction(ctx, func(ctx context.Context, tx *pop.Connection) (err error) { - - //#nosec G201 -- TableName is static - if err := sqlcon.HandleError(tx.RawQuery(fmt.Sprintf("UPDATE %s SET submit_count = submit_count + 1 WHERE id = ? AND nid = ?", flowTableName), fID, nid).Exec()); err != nil { - return err - } - - var submitCount int - // Because MySQL does not support "RETURNING" clauses, but we need the updated `submit_count` later on. - //#nosec G201 -- TableName is static - if err := sqlcon.HandleError(tx.RawQuery(fmt.Sprintf("SELECT submit_count FROM %s WHERE id = ? AND nid = ?", flowTableName), fID, nid).First(&submitCount)); err != nil { - if errors.Is(err, sqlcon.ErrNoRows) { - // Return no error, as that would roll back the transaction - return nil - } - - return err - } - - // This check prevents parallel brute force attacks to generate the recovery code - // by checking the submit count inside this database transaction. - // If the flow has been submitted more than 5 times, the transaction is aborted (regardless of whether the code was correct or not) - // and we thus give no indication whether the supplied code was correct or not. See also https://github.com/ory/kratos/pull/2645#discussion_r984732899 - if submitCount > 5 { - return errors.WithStack(code.ErrCodeSubmittedTooOften) - } - - var recoveryCodes []code.RecoveryCode - if err = sqlcon.HandleError(tx.Where("nid = ? AND selfservice_recovery_flow_id = ?", nid, fID).All(&recoveryCodes)); err != nil { - if errors.Is(err, sqlcon.ErrNoRows) { - // Return no error, as that would roll back the transaction - return nil - } - - return err - } - - secrets: - for _, secret := range p.r.Config().SecretsSession(ctx) { - suppliedCode := []byte(p.hmacValueWithSecret(ctx, codeVal, secret)) - for i := range recoveryCodes { - code := recoveryCodes[i] - if subtle.ConstantTimeCompare([]byte(code.CodeHMAC), suppliedCode) == 0 { - // Not the supplied code - continue - } - recoveryCode = &code - break secrets - } - } - - if recoveryCode == nil || !recoveryCode.IsValid() { - // Return no error, as that would roll back the transaction - return nil - } - - var ra identity.RecoveryAddress - if err := tx.Where("id = ? AND nid = ?", recoveryCode.RecoveryAddressID, nid).First(&ra); err != nil { - if err = sqlcon.HandleError(err); !errors.Is(err, sqlcon.ErrNoRows) { - return err - } - } - recoveryCode.RecoveryAddress = &ra - - //#nosec G201 -- TableName is static - return sqlcon.HandleError(tx.RawQuery(fmt.Sprintf("UPDATE %s SET used_at = ? WHERE id = ? AND nid = ?", recoveryCode.TableName(ctx)), time.Now().UTC(), recoveryCode.ID, nid).Exec()) - })); err != nil { - return nil, err - } - - if recoveryCode == nil { - return nil, code.ErrCodeNotFound - } - - if recoveryCode.IsExpired() { - return nil, flow.NewFlowExpiredError(recoveryCode.ExpiresAt) - } - - if recoveryCode.WasUsed() { - return nil, code.ErrCodeAlreadyUsed - } - - return recoveryCode, nil -} - -func (p *Persister) DeleteRecoveryCodesOfFlow(ctx context.Context, fID uuid.UUID) error { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteRecoveryCodesOfFlow") - defer span.End() - - //#nosec G201 -- TableName is static - return p.GetConnection(ctx).RawQuery(fmt.Sprintf("DELETE FROM %s WHERE selfservice_recovery_flow_id = ? AND nid = ?", new(code.RecoveryCode).TableName(ctx)), fID, p.NetworkID(ctx)).Exec() -} diff --git a/persistence/sql/persister_recovery_code.go b/persistence/sql/persister_recovery_code.go new file mode 100644 index 000000000000..725b9578a205 --- /dev/null +++ b/persistence/sql/persister_recovery_code.go @@ -0,0 +1,84 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package sql + +import ( + "context" + "time" + + "github.com/gofrs/uuid" + "github.com/pkg/errors" + + "github.com/ory/kratos/identity" + "github.com/ory/kratos/selfservice/flow/recovery" + "github.com/ory/kratos/selfservice/strategy/code" + "github.com/ory/x/sqlcon" +) + +func (p *Persister) CreateRecoveryCode(ctx context.Context, params *code.CreateRecoveryCodeParams) (*code.RecoveryCode, error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateRecoveryCode") + defer span.End() + + now := time.Now() + recoveryCode := &code.RecoveryCode{ + ID: uuid.Nil, + CodeHMAC: p.hmacValue(ctx, params.RawCode), + ExpiresAt: now.UTC().Add(params.ExpiresIn), + IssuedAt: now, + CodeType: params.CodeType, + FlowID: params.FlowID, + NID: p.NetworkID(ctx), + IdentityID: params.IdentityID, + } + + if params.RecoveryAddress != nil { + recoveryCode.RecoveryAddress = params.RecoveryAddress + recoveryCode.RecoveryAddressID = uuid.NullUUID{ + UUID: params.RecoveryAddress.ID, + Valid: true, + } + } + + // This should not create the request eagerly because otherwise we might accidentally create an address that isn't + // supposed to be in the database. + if err := p.GetConnection(ctx).Create(recoveryCode); err != nil { + return nil, err + } + + return recoveryCode, nil +} + +// UseRecoveryCode attempts to "use" the supplied code in the flow +// +// If the supplied code matched a code from the flow, no error is returned +// If an invalid code was submitted with this flow more than 5 times, an error is returned +func (p *Persister) UseRecoveryCode(ctx context.Context, flowID uuid.UUID, userProvidedCode string) (*code.RecoveryCode, error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.UseRecoveryCode") + defer span.End() + + codeRow, err := useOneTimeCode[code.RecoveryCode, *code.RecoveryCode](ctx, p, flowID, userProvidedCode, new(recovery.Flow).TableName(ctx), "selfservice_recovery_flow_id") + if err != nil { + return nil, err + } + + var ra identity.RecoveryAddress + if err := sqlcon.HandleError(p.GetConnection(ctx).Where("id = ? AND nid = ?", codeRow.RecoveryAddressID, p.NetworkID(ctx)).First(&ra)); err != nil { + if errors.Is(err, sqlcon.ErrNoRows) { + // This is ok, it can happen when an administrator initiates account recovery. This works even if the + // user has no recovery address! + } else { + return nil, err + } + } + codeRow.RecoveryAddress = &ra + + return codeRow, nil +} + +func (p *Persister) DeleteRecoveryCodesOfFlow(ctx context.Context, flowID uuid.UUID) error { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteRecoveryCodesOfFlow") + defer span.End() + + return p.GetConnection(ctx).Where("selfservice_recovery_flow_id = ? AND nid = ?", flowID, p.NetworkID(ctx)).Delete(&code.RecoveryCode{}) +} diff --git a/persistence/sql/persister_registration_code.go b/persistence/sql/persister_registration_code.go new file mode 100644 index 000000000000..5c9ac909838c --- /dev/null +++ b/persistence/sql/persister_registration_code.go @@ -0,0 +1,76 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package sql + +import ( + "context" + "time" + + "github.com/bxcodec/faker/v3/support/slice" + "github.com/gofrs/uuid" + "github.com/pkg/errors" + + "github.com/ory/kratos/selfservice/flow/registration" + "github.com/ory/kratos/selfservice/strategy/code" + "github.com/ory/x/sqlcon" +) + +func (p *Persister) CreateRegistrationCode(ctx context.Context, params *code.CreateRegistrationCodeParams) (*code.RegistrationCode, error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateRegistrationCode") + defer span.End() + + now := time.Now().UTC() + registrationCode := &code.RegistrationCode{ + Address: params.Address, + AddressType: params.AddressType, + CodeHMAC: p.hmacValue(ctx, params.RawCode), + IssuedAt: now, + ExpiresAt: now.UTC().Add(p.r.Config().SelfServiceCodeMethodLifespan(ctx)), + FlowID: params.FlowID, + NID: p.NetworkID(ctx), + ID: uuid.Nil, + } + + if err := p.GetConnection(ctx).Create(registrationCode); err != nil { + return nil, sqlcon.HandleError(err) + } + + return registrationCode, nil +} + +func (p *Persister) UseRegistrationCode(ctx context.Context, flowID uuid.UUID, userProvidedCode string, addresses ...string) (*code.RegistrationCode, error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.UseRegistrationCode") + defer span.End() + + codeRow, err := useOneTimeCode[code.RegistrationCode, *code.RegistrationCode](ctx, p, flowID, userProvidedCode, new(registration.Flow).TableName(ctx), "selfservice_registration_flow_id") + if err != nil { + return nil, err + } + + // ensure that the identifiers extracted from the traits are contained in the registration code + if !slice.Contains(addresses, codeRow.Address) { + return nil, errors.WithStack(code.ErrCodeNotFound) + } + + return codeRow, nil +} + +func (p *Persister) GetUsedRegistrationCode(ctx context.Context, flowID uuid.UUID) (*code.RegistrationCode, error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetUsedRegistrationCode") + defer span.End() + + var registrationCode code.RegistrationCode + if err := p.Connection(ctx).Where("selfservice_registration_flow_id = ? AND used_at IS NOT NULL AND nid = ?", flowID, p.NetworkID(ctx)).First(®istrationCode); err != nil { + return nil, sqlcon.HandleError(err) + } + + return ®istrationCode, nil +} + +func (p *Persister) DeleteRegistrationCodesOfFlow(ctx context.Context, flowID uuid.UUID) error { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteRegistrationCodesOfFlow") + defer span.End() + + return p.GetConnection(ctx).Where("selfservice_registration_flow_id = ? AND nid = ?", flowID, p.NetworkID(ctx)).Delete(&code.RegistrationCode{}) +} diff --git a/persistence/sql/persister_verification.go b/persistence/sql/persister_verification.go index 30bc4ac56718..b2f19f94726b 100644 --- a/persistence/sql/persister_verification.go +++ b/persistence/sql/persister_verification.go @@ -5,13 +5,11 @@ package sql import ( "context" - "crypto/subtle" "fmt" "time" "github.com/pkg/errors" - "github.com/ory/herodot" "github.com/ory/kratos/identity" "github.com/ory/kratos/persistence/sql/update" @@ -21,7 +19,6 @@ import ( "github.com/ory/x/sqlcon" "github.com/ory/kratos/selfservice/flow/verification" - "github.com/ory/kratos/selfservice/strategy/code" "github.com/ory/kratos/selfservice/strategy/link" ) @@ -137,154 +134,3 @@ func (p *Persister) DeleteExpiredVerificationFlows(ctx context.Context, expiresA } return nil } -func (p *Persister) UseVerificationCode(ctx context.Context, fID uuid.UUID, codeVal string) (*code.VerificationCode, error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.UseVerificationCode") - defer span.End() - - var verificationCode *code.VerificationCode - - nid := p.NetworkID(ctx) - - flowTableName := new(verification.Flow).TableName(ctx) - - if err := sqlcon.HandleError(p.Transaction(ctx, func(ctx context.Context, tx *pop.Connection) (err error) { - - if err := sqlcon.HandleError( - tx.RawQuery( - //#nosec G201 -- TableName is static - fmt.Sprintf("UPDATE %s SET submit_count = submit_count + 1 WHERE id = ? AND nid = ?", flowTableName), - fID, - nid, - ).Exec(), - ); err != nil { - return err - } - - var submitCount int - // Because MySQL does not support "RETURNING" clauses, but we need the updated `submit_count` later on. - if err := sqlcon.HandleError( - tx.RawQuery( - //#nosec G201 -- TableName is static - fmt.Sprintf("SELECT submit_count FROM %s WHERE id = ? AND nid = ?", flowTableName), - fID, - nid, - ).First(&submitCount), - ); err != nil { - if errors.Is(err, sqlcon.ErrNoRows) { - // Return no error, as that would roll back the transaction - return nil - } - - return err - } - // This check prevents parallel brute force attacks to generate the verification code - // by checking the submit count inside this database transaction. - // If the flow has been submitted more than 5 times, the transaction is aborted (regardless of whether the code was correct or not) - // and we thus give no indication whether the supplied code was correct or not. See also https://github.com/ory/kratos/pull/2645#discussion_r984732899 - if submitCount > 5 { - return errors.WithStack(code.ErrCodeSubmittedTooOften) - } - - var verificationCodes []code.VerificationCode - if err = sqlcon.HandleError( - tx.Where("nid = ? AND selfservice_verification_flow_id = ?", nid, fID). - All(&verificationCodes), - ); err != nil { - if errors.Is(err, sqlcon.ErrNoRows) { - // Return no error, as that would roll back the transaction - return nil - } - - return err - } - - secrets: - for _, secret := range p.r.Config().SecretsSession(ctx) { - suppliedCode := []byte(p.hmacValueWithSecret(ctx, codeVal, secret)) - for i := range verificationCodes { - code := verificationCodes[i] - if subtle.ConstantTimeCompare([]byte(code.CodeHMAC), suppliedCode) == 0 { - // Not the supplied code - continue - } - verificationCode = &code - break secrets - } - } - - if verificationCode == nil || verificationCode.Validate() != nil { - // Return no error, as that would roll back the transaction - return nil - } - - var va identity.VerifiableAddress - if err := tx.Where("id = ? AND nid = ?", verificationCode.VerifiableAddressID, nid).First(&va); err != nil { - return sqlcon.HandleError(err) - } - - verificationCode.VerifiableAddress = &va - - //#nosec G201 -- TableName is static - return tx. - RawQuery( - fmt.Sprintf("UPDATE %s SET used_at = ? WHERE id = ? AND nid = ?", verificationCode.TableName(ctx)), - time.Now().UTC(), - verificationCode.ID, - nid, - ).Exec() - })); err != nil { - return nil, err - } - - if verificationCode == nil { - return nil, code.ErrCodeNotFound - } - - return verificationCode, nil -} - -func (p *Persister) CreateVerificationCode(ctx context.Context, c *code.CreateVerificationCodeParams) (*code.VerificationCode, error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateVerificationCode") - defer span.End() - - now := time.Now().UTC() - - verificationCode := &code.VerificationCode{ - ID: uuid.Nil, - CodeHMAC: p.hmacValue(ctx, c.RawCode), - ExpiresAt: now.Add(c.ExpiresIn), - IssuedAt: now, - FlowID: c.FlowID, - NID: p.NetworkID(ctx), - } - - if c.VerifiableAddress == nil { - return nil, errors.WithStack(herodot.ErrNotFound.WithReason("can't create a verification code without a verifiable address")) - } - - verificationCode.VerifiableAddress = c.VerifiableAddress - verificationCode.VerifiableAddressID = uuid.NullUUID{ - UUID: c.VerifiableAddress.ID, - Valid: true, - } - - // This should not create the request eagerly because otherwise we might accidentally create an address that isn't - // supposed to be in the database. - if err := p.GetConnection(ctx).Create(verificationCode); err != nil { - return nil, err - } - return verificationCode, nil -} - -func (p *Persister) DeleteVerificationCodesOfFlow(ctx context.Context, fID uuid.UUID) error { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteVerificationCodesOfFlow") - defer span.End() - - //#nosec G201 -- TableName is static - return p.GetConnection(ctx). - RawQuery( - fmt.Sprintf("DELETE FROM %s WHERE selfservice_verification_flow_id = ? AND nid = ?", new(code.VerificationCode).TableName(ctx)), - fID, - p.NetworkID(ctx), - ).Exec() -} diff --git a/persistence/sql/persister_verification_code.go b/persistence/sql/persister_verification_code.go new file mode 100644 index 000000000000..0b469bad07ce --- /dev/null +++ b/persistence/sql/persister_verification_code.go @@ -0,0 +1,77 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package sql + +import ( + "context" + "time" + + "github.com/gofrs/uuid" + "github.com/pkg/errors" + + "github.com/ory/herodot" + "github.com/ory/kratos/identity" + "github.com/ory/kratos/selfservice/flow/verification" + "github.com/ory/kratos/selfservice/strategy/code" + "github.com/ory/x/sqlcon" +) + +func (p *Persister) CreateVerificationCode(ctx context.Context, params *code.CreateVerificationCodeParams) (*code.VerificationCode, error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateVerificationCode") + defer span.End() + + now := time.Now().UTC() + verificationCode := &code.VerificationCode{ + ID: uuid.Nil, + CodeHMAC: p.hmacValue(ctx, params.RawCode), + ExpiresAt: now.Add(params.ExpiresIn), + IssuedAt: now, + FlowID: params.FlowID, + NID: p.NetworkID(ctx), + } + + if params.VerifiableAddress == nil { + return nil, errors.WithStack(herodot.ErrNotFound.WithReason("can't create a verification code without a verifiable address")) + } + + verificationCode.VerifiableAddress = params.VerifiableAddress + verificationCode.VerifiableAddressID = uuid.NullUUID{ + UUID: params.VerifiableAddress.ID, + Valid: true, + } + + // This should not create the request eagerly because otherwise we might accidentally create an address that isn't + // supposed to be in the database. + if err := p.GetConnection(ctx).Create(verificationCode); err != nil { + return nil, err + } + + return verificationCode, nil +} + +func (p *Persister) UseVerificationCode(ctx context.Context, flowID uuid.UUID, userProvidedCode string) (*code.VerificationCode, error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.UseVerificationCode") + defer span.End() + + codeRow, err := useOneTimeCode[code.VerificationCode, *code.VerificationCode](ctx, p, flowID, userProvidedCode, new(verification.Flow).TableName(ctx), "selfservice_verification_flow_id") + if err != nil { + return nil, err + } + + var va identity.VerifiableAddress + if err := p.Connection(ctx).Where("id = ? AND nid = ?", codeRow.VerifiableAddressID, p.NetworkID(ctx)).First(&va); err != nil { + // This should fail on not found errors too, because the verifiable address must exist for the flow to work. + return nil, sqlcon.HandleError(err) + } + codeRow.VerifiableAddress = &va + + return codeRow, nil +} + +func (p *Persister) DeleteVerificationCodesOfFlow(ctx context.Context, fID uuid.UUID) error { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteVerificationCodesOfFlow") + defer span.End() + + return p.GetConnection(ctx).Where("selfservice_verification_flow_id = ? AND nid = ?", fID, p.NetworkID(ctx)).Delete(&code.VerificationCode{}) +} diff --git a/schema/errors.go b/schema/errors.go index 73d144e0be9e..8cd74c5aec60 100644 --- a/schema/errors.go +++ b/schema/errors.go @@ -346,3 +346,43 @@ func NewNoWebAuthnCredentials() error { Messages: new(text.Messages).Add(text.NewErrorValidationSuchNoWebAuthnUser()), }) } + +func NewNoCodeAuthnCredentials() error { + return errors.WithStack(&ValidationError{ + ValidationError: &jsonschema.ValidationError{ + Message: `account does not exist or has not setup up sign in with code`, + InstancePtr: "#/", + }, + Messages: new(text.Messages).Add(text.NewErrorValidationNoCodeUser()), + }) +} + +func NewTraitsMismatch() error { + return errors.WithStack(&ValidationError{ + ValidationError: &jsonschema.ValidationError{ + Message: `the submitted form data has changed from the previous submission`, + InstancePtr: "#/", + }, + Messages: new(text.Messages).Add(text.NewErrorValidationTraitsMismatch()), + }) +} + +func NewRegistrationCodeInvalid() error { + return errors.WithStack(&ValidationError{ + ValidationError: &jsonschema.ValidationError{ + Message: `the provided code is invalid or has already been used`, + InstancePtr: "#/", + }, + Messages: new(text.Messages).Add(text.NewErrorValidationRegistrationCodeInvalidOrAlreadyUsed()), + }) +} + +func NewLoginCodeInvalid() error { + return errors.WithStack(&ValidationError{ + ValidationError: &jsonschema.ValidationError{ + Message: `the provided code is invalid or has already been used`, + InstancePtr: "#/", + }, + Messages: new(text.Messages).Add(text.NewErrorValidationLoginCodeInvalidOrAlreadyUsed()), + }) +} diff --git a/schema/extension.go b/schema/extension.go index 5955328c27df..5b605cfb91d4 100644 --- a/schema/extension.go +++ b/schema/extension.go @@ -30,6 +30,10 @@ type ( TOTP struct { AccountName bool `json:"account_name"` } `json:"totp"` + Code struct { + Identifier bool `json:"identifier"` + Via string `json:"via"` + } `json:"code"` } `json:"credentials"` Verification struct { Via string `json:"via"` diff --git a/selfservice/flow/error_test.go b/selfservice/flow/error_test.go index 6502244fba69..98b1ad32e9c4 100644 --- a/selfservice/flow/error_test.go +++ b/selfservice/flow/error_test.go @@ -52,6 +52,17 @@ type testFlow struct { // // required: true UI *container.Container `json:"ui" db:"ui"` + + // Flow State + // + // The state represents the state of the verification flow. + // + // - choose_method: ask the user to choose a method (e.g. recover account via email) + // - sent_email: the email has been sent to the user + // - passed_challenge: the request was successful and the recovery challenge was passed. + // + // required: true + State State `json:"state" db:"state"` } func (t *testFlow) GetID() uuid.UUID { @@ -74,6 +85,18 @@ func (t *testFlow) GetUI() *container.Container { return t.UI } +func (t *testFlow) GetState() State { + return t.State +} + +func (t *testFlow) GetFlowName() FlowName { + return FlowName("test") +} + +func (t *testFlow) SetState(state State) { + t.State = state +} + func newTestFlow(r *http.Request, flowType Type) Flow { id := x.NewUUID() requestURL := x.RequestURL(r).String() diff --git a/selfservice/flow/flow.go b/selfservice/flow/flow.go index c581b117ac04..be486e3723ae 100644 --- a/selfservice/flow/flow.go +++ b/selfservice/flow/flow.go @@ -38,6 +38,9 @@ type Flow interface { GetRequestURL() string AppendTo(*url.URL) *url.URL GetUI() *container.Container + GetState() State + SetState(State) + GetFlowName() FlowName } type FlowWithRedirect interface { diff --git a/selfservice/flow/login/flow.go b/selfservice/flow/login/flow.go index a0276175e2e4..e46698290819 100644 --- a/selfservice/flow/login/flow.go +++ b/selfservice/flow/login/flow.go @@ -124,8 +124,19 @@ type Flow struct { // This is only set if the client has requested a session token exchange code, and if the flow is of type "api", // and only on creating the login flow. SessionTokenExchangeCode string `json:"session_token_exchange_code,omitempty" faker:"-" db:"-"` + + // State represents the state of this request: + // + // - choose_method: ask the user to choose a method to sign in with + // - sent_email: the email has been sent to the user + // - passed_challenge: the request was successful and the login challenge was passed. + // + // required: true + State State `json:"state" faker:"-" db:"state"` } +var _ flow.Flow = new(Flow) + func NewFlow(conf *config.Config, exp time.Duration, csrf string, r *http.Request, flowType flow.Type) (*Flow, error) { now := time.Now().UTC() id := x.NewUUID() @@ -164,6 +175,7 @@ func NewFlow(conf *config.Config, exp time.Duration, csrf string, r *http.Reques r.URL.Query().Get("aal"), string(identity.AuthenticatorAssuranceLevel1)))), InternalContext: []byte("{}"), + State: flow.StateChooseMethod, }, nil } @@ -251,3 +263,15 @@ func (f *Flow) SecureRedirectToOpts(ctx context.Context, cfg config.Provider) (o x.SecureRedirectOverrideDefaultReturnTo(cfg.Config().SelfServiceFlowLoginReturnTo(ctx, f.Active.String())), } } + +func (f *Flow) GetState() flow.State { + return flow.State(f.State) +} + +func (f *Flow) GetFlowName() flow.FlowName { + return flow.LoginFlow +} + +func (f *Flow) SetState(state flow.State) { + f.State = State(state) +} diff --git a/selfservice/flow/login/hook.go b/selfservice/flow/login/hook.go index c04b8cd0b2e3..203a62fdf989 100644 --- a/selfservice/flow/login/hook.go +++ b/selfservice/flow/login/hook.go @@ -142,7 +142,6 @@ func (e *HookExecutor) PostLoginHook( x.SecureRedirectAllowSelfServiceURLs(c.SelfPublicURL(r.Context())), x.SecureRedirectOverrideDefaultReturnTo(c.SelfServiceFlowLoginReturnTo(r.Context(), a.Active.String())), ) - if err != nil { return err } diff --git a/selfservice/flow/login/sort.go b/selfservice/flow/login/sort.go index 74160b8d2566..9f1a144ffc2d 100644 --- a/selfservice/flow/login/sort.go +++ b/selfservice/flow/login/sort.go @@ -15,6 +15,7 @@ func sortNodes(ctx context.Context, n node.Nodes) error { node.OpenIDConnectGroup, node.DefaultGroup, node.WebAuthnGroup, + node.CodeGroup, node.PasswordGroup, node.TOTPGroup, node.LookupGroup, diff --git a/selfservice/flow/login/state.go b/selfservice/flow/login/state.go new file mode 100644 index 000000000000..576fad6d9f05 --- /dev/null +++ b/selfservice/flow/login/state.go @@ -0,0 +1,17 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package login + +import "github.com/ory/kratos/selfservice/flow" + +// Login Flow State +// +// The state represents the state of the login flow. +// +// - choose_method: ask the user to choose a method (e.g. login account via email) +// - sent_email: the email has been sent to the user +// - passed_challenge: the request was successful and the login challenge was passed. +// +// swagger:model loginFlowState +type State = flow.State diff --git a/selfservice/flow/name.go b/selfservice/flow/name.go new file mode 100644 index 000000000000..1b766c6662f6 --- /dev/null +++ b/selfservice/flow/name.go @@ -0,0 +1,28 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package flow + +// FlowName is the flow name. +// +// The flow name can be one of: +// - 'login' +// - 'registration' +// - 'settings' +// - 'recovery' +// - 'verification' +// +// swagger:ignore +type FlowName string + +const ( + LoginFlow FlowName = "login" + RegistrationFlow FlowName = "registration" + SettingsFlow FlowName = "settings" + RecoveryFlow FlowName = "recovery" + VerificationFlow FlowName = "verification" +) + +func (t Type) String() string { + return string(t) +} diff --git a/selfservice/flow/recovery/flow.go b/selfservice/flow/recovery/flow.go index 42770783fb42..3557c8652b8d 100644 --- a/selfservice/flow/recovery/flow.go +++ b/selfservice/flow/recovery/flow.go @@ -102,6 +102,8 @@ type Flow struct { DangerousSkipCSRFCheck bool `json:"-" faker:"-" db:"skip_csrf_check"` } +var _ flow.Flow = new(Flow) + func NewFlow(conf *config.Config, exp time.Duration, csrf string, r *http.Request, strategy Strategy, ft flow.Type) (*Flow, error) { now := time.Now().UTC() id := x.NewUUID() @@ -127,13 +129,13 @@ func NewFlow(conf *config.Config, exp time.Duration, csrf string, r *http.Reques Method: "POST", Action: flow.AppendFlowTo(urlx.AppendPaths(conf.SelfPublicURL(r.Context()), RouteSubmitFlow), id).String(), }, - State: StateChooseMethod, + State: flow.StateChooseMethod, CSRFToken: csrf, Type: ft, } if strategy != nil { - flow.Active = sqlxx.NullString(strategy.RecoveryNodeGroup()) + flow.Active = sqlxx.NullString(strategy.NodeGroup()) if err := strategy.PopulateRecoveryMethod(r, flow); err != nil { return nil, err } @@ -222,3 +224,15 @@ func (f *Flow) AfterSave(*pop.Connection) error { func (f *Flow) GetUI() *container.Container { return f.UI } + +func (f *Flow) GetState() State { + return f.State +} + +func (f *Flow) GetFlowName() flow.FlowName { + return flow.RecoveryFlow +} + +func (f *Flow) SetState(state State) { + f.State = state +} diff --git a/selfservice/flow/recovery/flow_test.go b/selfservice/flow/recovery/flow_test.go index c2a1eb56e11d..cab497c1b9a2 100644 --- a/selfservice/flow/recovery/flow_test.go +++ b/selfservice/flow/recovery/flow_test.go @@ -54,7 +54,7 @@ func TestFlow(t *testing.T) { }) } - assert.EqualValues(t, recovery.StateChooseMethod, + assert.EqualValues(t, flow.StateChooseMethod, must(recovery.NewFlow(conf, time.Hour, "", u, nil, flow.TypeBrowser)).State) t.Run("type=return_to", func(t *testing.T) { diff --git a/selfservice/flow/recovery/handler.go b/selfservice/flow/recovery/handler.go index 24aed7695bba..6c4fd21344a4 100644 --- a/selfservice/flow/recovery/handler.go +++ b/selfservice/flow/recovery/handler.go @@ -185,7 +185,6 @@ type createBrowserRecoveryFlow struct { // 400: errorGeneric // default: errorGeneric func (h *Handler) createBrowserRecoveryFlow(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { - if !h.d.Config().SelfServiceFlowRecoveryEnabled(r.Context()) { h.d.SelfServiceErrorManager().Forward(r.Context(), w, r, errors.WithStack(herodot.ErrBadRequest.WithReasonf("Recovery is not allowed because it was disabled."))) return @@ -430,12 +429,12 @@ func (h *Handler) updateRecoveryFlow(w http.ResponseWriter, r *http.Request, ps } else if errors.Is(err, flow.ErrCompletedByStrategy) { return } else if err != nil { - h.d.RecoveryFlowErrorHandler().WriteFlowError(w, r, f, ss.RecoveryNodeGroup(), err) + h.d.RecoveryFlowErrorHandler().WriteFlowError(w, r, f, ss.NodeGroup(), err) return } found = true - g = ss.RecoveryNodeGroup() + g = ss.NodeGroup() break } diff --git a/selfservice/flow/recovery/state.go b/selfservice/flow/recovery/state.go index 6b2ed0892b06..96ab9d29937e 100644 --- a/selfservice/flow/recovery/state.go +++ b/selfservice/flow/recovery/state.go @@ -3,6 +3,8 @@ package recovery +import "github.com/ory/kratos/selfservice/flow" + // Recovery Flow State // // The state represents the state of the recovery flow. @@ -12,33 +14,4 @@ package recovery // - passed_challenge: the request was successful and the recovery challenge was passed. // // swagger:model recoveryFlowState -type State string - -const ( - StateChooseMethod State = "choose_method" - StateEmailSent State = "sent_email" - StatePassedChallenge State = "passed_challenge" -) - -var states = []State{StateChooseMethod, StateEmailSent, StatePassedChallenge} - -func indexOf(current State) int { - for k, s := range states { - if s == current { - return k - } - } - return 0 -} - -func HasReachedState(expected, actual State) bool { - return indexOf(actual) >= indexOf(expected) -} - -func NextState(current State) State { - if current == StatePassedChallenge { - return StatePassedChallenge - } - - return states[indexOf(current)+1] -} +type State = flow.State diff --git a/selfservice/flow/recovery/strategy.go b/selfservice/flow/recovery/strategy.go index 28e28673f1d3..3594420167df 100644 --- a/selfservice/flow/recovery/strategy.go +++ b/selfservice/flow/recovery/strategy.go @@ -26,7 +26,7 @@ const ( type ( Strategy interface { RecoveryStrategyID() string - RecoveryNodeGroup() node.UiNodeGroup + NodeGroup() node.UiNodeGroup PopulateRecoveryMethod(*http.Request, *Flow) error Recover(w http.ResponseWriter, r *http.Request, f *Flow) (err error) } diff --git a/selfservice/flow/recovery/test/persistence.go b/selfservice/flow/recovery/test/persistence.go index 91e8a2c763b3..665dc84b9130 100644 --- a/selfservice/flow/recovery/test/persistence.go +++ b/selfservice/flow/recovery/test/persistence.go @@ -15,6 +15,7 @@ import ( "github.com/ory/kratos/driver/config" "github.com/ory/kratos/internal/testhelpers" "github.com/ory/kratos/persistence" + "github.com/ory/kratos/selfservice/flow" "github.com/ory/kratos/selfservice/flow/recovery" "github.com/ory/kratos/ui/node" "github.com/ory/kratos/x" @@ -24,8 +25,9 @@ import ( func TestFlowPersister(ctx context.Context, conf *config.Config, p interface { persistence.Persister -}) func(t *testing.T) { - var clearids = func(r *recovery.Flow) { +}, +) func(t *testing.T) { + clearids := func(r *recovery.Flow) { r.ID = uuid.UUID{} } @@ -38,10 +40,11 @@ func TestFlowPersister(ctx context.Context, conf *config.Config, p interface { require.Error(t, err) }) - var newFlow = func(t *testing.T) *recovery.Flow { + newFlow := func(t *testing.T) *recovery.Flow { var r recovery.Flow require.NoError(t, faker.FakeData(&r)) clearids(&r) + r.State = flow.StateShowForm return &r } @@ -61,6 +64,7 @@ func TestFlowPersister(ctx context.Context, conf *config.Config, p interface { t.Run("case=should create with set ids", func(t *testing.T) { var r recovery.Flow require.NoError(t, faker.FakeData(&r)) + r.State = flow.StateShowForm require.NoError(t, p.CreateRecoveryFlow(ctx, &r)) require.Equal(t, nid, r.NID) @@ -162,7 +166,6 @@ func TestFlowPersister(ctx context.Context, conf *config.Config, p interface { }) t.Run("case=handle network reference issues", func(t *testing.T) { - }) } } diff --git a/selfservice/flow/registration/flow.go b/selfservice/flow/registration/flow.go index b16bf2048ce5..39843a9e5b5c 100644 --- a/selfservice/flow/registration/flow.go +++ b/selfservice/flow/registration/flow.go @@ -115,8 +115,18 @@ type Flow struct { // This is only set if the client has requested a session token exchange code, and if the flow is of type "api", // and only on creating the flow. SessionTokenExchangeCode string `json:"session_token_exchange_code,omitempty" faker:"-" db:"-"` + + // State represents the state of this request: + // + // - choose_method: ask the user to choose a method (e.g. registration with email) + // - sent_email: the email has been sent to the user + // - passed_challenge: the request was successful and the registration challenge was passed. + // required: true + State State `json:"state" faker:"-" db:"state"` } +var _ flow.Flow = new(Flow) + func NewFlow(conf *config.Config, exp time.Duration, csrf string, r *http.Request, ft flow.Type) (*Flow, error) { now := time.Now().UTC() id := x.NewUUID() @@ -151,6 +161,7 @@ func NewFlow(conf *config.Config, exp time.Duration, csrf string, r *http.Reques CSRFToken: csrf, Type: ft, InternalContext: []byte("{}"), + State: flow.StateChooseMethod, }, nil } @@ -238,3 +249,15 @@ func (f *Flow) SecureRedirectToOpts(ctx context.Context, cfg config.Provider) (o x.SecureRedirectOverrideDefaultReturnTo(cfg.Config().SelfServiceFlowRegistrationReturnTo(ctx, f.Active.String())), } } + +func (f *Flow) GetState() State { + return f.State +} + +func (f *Flow) GetFlowName() flow.FlowName { + return flow.RegistrationFlow +} + +func (f *Flow) SetState(state State) { + f.State = state +} diff --git a/selfservice/flow/registration/sort.go b/selfservice/flow/registration/sort.go index db44e96274e3..15348dd56512 100644 --- a/selfservice/flow/registration/sort.go +++ b/selfservice/flow/registration/sort.go @@ -16,6 +16,7 @@ func SortNodes(ctx context.Context, n node.Nodes, schemaRef string) error { node.DefaultGroup, node.OpenIDConnectGroup, node.WebAuthnGroup, + node.CodeGroup, node.PasswordGroup, }), node.SortUpdateOrder(node.PasswordLoginOrder), diff --git a/selfservice/flow/registration/state.go b/selfservice/flow/registration/state.go new file mode 100644 index 000000000000..be50551d6850 --- /dev/null +++ b/selfservice/flow/registration/state.go @@ -0,0 +1,15 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package registration + +import "github.com/ory/kratos/selfservice/flow" + +// State represents the state of this request: +// +// - choose_method: ask the user to choose a method (e.g. registration with email) +// - sent_email: the email has been sent to the user +// - passed_challenge: the request was successful and the registration challenge was passed. +// +// swagger:model registrationFlowState +type State = flow.State diff --git a/selfservice/flow/request.go b/selfservice/flow/request.go index af1b31968caa..6c7bc9709525 100644 --- a/selfservice/flow/request.go +++ b/selfservice/flow/request.go @@ -10,6 +10,7 @@ import ( "strings" "github.com/ory/kratos/driver/config" + "github.com/ory/kratos/identity" "github.com/ory/kratos/selfservice/strategy" "github.com/ory/x/decoderx" @@ -25,6 +26,7 @@ var methodSchema []byte var ErrOriginHeaderNeedsBrowserFlow = herodot.ErrBadRequest. WithReasonf(`The HTTP Request Header included the "Origin" key, indicating that this request was made as part of an AJAX request in a Browser. The flow however was initiated as an API request. To prevent potential misuse and mitigate several attack vectors including CSRF, the request has been blocked. Please consult the documentation.`) + var ErrCookieHeaderNeedsBrowserFlow = herodot.ErrBadRequest. WithReasonf(`The HTTP Request Header included the "Cookie" key, indicating that this request was made by a Browser. The flow however was initiated as an API request. To prevent potential misuse and mitigate several attack vectors including CSRF, the request has been blocked. Please consult the documentation.`) @@ -76,9 +78,10 @@ func EnsureCSRF(reg interface { var dec = decoderx.NewHTTP() -func MethodEnabledAndAllowedFromRequest(r *http.Request, expected string, d interface { +func MethodEnabledAndAllowedFromRequest(r *http.Request, flow FlowName, expected string, d interface { config.Provider -}) error { +}, +) error { var method struct { Method string `json:"method" form:"method"` } @@ -96,17 +99,27 @@ func MethodEnabledAndAllowedFromRequest(r *http.Request, expected string, d inte return errors.WithStack(err) } - return MethodEnabledAndAllowed(r.Context(), expected, method.Method, d) + return MethodEnabledAndAllowed(r.Context(), flow, expected, method.Method, d) } -func MethodEnabledAndAllowed(ctx context.Context, expected, actual string, d interface { - config.Provider -}) error { +func MethodEnabledAndAllowed(ctx context.Context, flowName FlowName, expected, actual string, d config.Provider) error { if actual != expected { return errors.WithStack(ErrStrategyNotResponsible) } - if !d.Config().SelfServiceStrategy(ctx, expected).Enabled { + var ok bool + if strings.EqualFold(actual, identity.CredentialsTypeCodeAuth.String()) { + switch flowName { + case RegistrationFlow, LoginFlow: + ok = d.Config().SelfServiceCodeStrategy(ctx).PasswordlessEnabled + case VerificationFlow, RecoveryFlow: + ok = d.Config().SelfServiceCodeStrategy(ctx).Enabled + } + } else { + ok = d.Config().SelfServiceStrategy(ctx, expected).Enabled + } + + if !ok { return errors.WithStack(herodot.ErrNotFound.WithReason(strategy.EndpointDisabledMessage)) } diff --git a/selfservice/flow/request_test.go b/selfservice/flow/request_test.go index d240f9c15daf..17a7d9e2d0d3 100644 --- a/selfservice/flow/request_test.go +++ b/selfservice/flow/request_test.go @@ -55,7 +55,7 @@ func TestMethodEnabledAndAllowed(t *testing.T) { ctx := context.Background() conf, d := internal.NewFastRegistryWithMocks(t) ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if err := flow.MethodEnabledAndAllowedFromRequest(r, "password", d); err != nil { + if err := flow.MethodEnabledAndAllowedFromRequest(r, flow.LoginFlow, "password", d); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -91,3 +91,74 @@ func TestMethodEnabledAndAllowed(t *testing.T) { assert.Contains(t, string(body), "The requested resource could not be found") }) } + +func TestMethodCodeEnabledAndAllowed(t *testing.T) { + ctx := context.Background() + conf, d := internal.NewFastRegistryWithMocks(t) + + currentFlow := make(chan flow.FlowName, 1) + + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + f := <-currentFlow + if err := flow.MethodEnabledAndAllowedFromRequest(r, f, "code", d); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + w.WriteHeader(http.StatusNoContent) + })) + + t.Run("login code allowed", func(t *testing.T) { + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.passwordless_enabled", true) + currentFlow <- flow.LoginFlow + res, err := ts.Client().PostForm(ts.URL, url.Values{"method": {"code"}}) + require.NoError(t, err) + require.NoError(t, res.Body.Close()) + assert.Equal(t, http.StatusNoContent, res.StatusCode) + }) + + t.Run("login code not allowed", func(t *testing.T) { + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.passwordless_enabled", false) + currentFlow <- flow.LoginFlow + res, err := ts.Client().PostForm(ts.URL, url.Values{"method": {"code"}}) + require.NoError(t, err) + body, err := io.ReadAll(res.Body) + require.NoError(t, err) + require.NoError(t, res.Body.Close()) + assert.Equal(t, http.StatusInternalServerError, res.StatusCode) + assert.Contains(t, string(body), "The requested resource could not be found") + }) + + t.Run("registration code allowed", func(t *testing.T) { + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.passwordless_enabled", true) + currentFlow <- flow.RegistrationFlow + res, err := ts.Client().PostForm(ts.URL, url.Values{"method": {"code"}}) + require.NoError(t, err) + require.NoError(t, res.Body.Close()) + assert.Equal(t, http.StatusNoContent, res.StatusCode) + }) + + t.Run("registration code not allowed", func(t *testing.T) { + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.passwordless_enabled", false) + currentFlow <- flow.RegistrationFlow + res, err := ts.Client().PostForm(ts.URL, url.Values{"method": {"code"}}) + require.NoError(t, err) + body, err := io.ReadAll(res.Body) + require.NoError(t, err) + require.NoError(t, res.Body.Close()) + assert.Equal(t, http.StatusInternalServerError, res.StatusCode) + assert.Contains(t, string(body), "The requested resource could not be found") + }) + + t.Run("recovery and verification should still be allowed if registration and login is disabled", func(t *testing.T) { + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.passwordless_enabled", false) + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.enabled", true) + + for _, f := range []flow.FlowName{flow.RecoveryFlow, flow.VerificationFlow} { + currentFlow <- f + res, err := ts.Client().PostForm(ts.URL, url.Values{"method": {"code"}}) + require.NoError(t, err) + require.NoError(t, res.Body.Close()) + assert.Equal(t, http.StatusNoContent, res.StatusCode) + } + }) +} diff --git a/selfservice/flow/settings/flow.go b/selfservice/flow/settings/flow.go index ef69a03f042e..a96da053d766 100644 --- a/selfservice/flow/settings/flow.go +++ b/selfservice/flow/settings/flow.go @@ -121,6 +121,8 @@ type Flow struct { ContinueWithItems []flow.ContinueWith `json:"continue_with,omitempty" db:"-" faker:"-" ` } +var _ flow.Flow = new(Flow) + func MustNewFlow(conf *config.Config, exp time.Duration, r *http.Request, i *identity.Identity, ft flow.Type) *Flow { f, err := NewFlow(conf, exp, r, i, ft) if err != nil { @@ -153,7 +155,7 @@ func NewFlow(conf *config.Config, exp time.Duration, r *http.Request, i *identit IdentityID: i.ID, Identity: i, Type: ft, - State: StateShowForm, + State: flow.StateShowForm, UI: &container.Container{ Method: "POST", Action: flow.AppendFlowTo(urlx.AppendPaths(conf.SelfPublicURL(r.Context()), RouteSubmitFlow), id).String(), @@ -242,3 +244,15 @@ func (f *Flow) AddContinueWith(c flow.ContinueWith) { func (f *Flow) ContinueWith() []flow.ContinueWith { return f.ContinueWithItems } + +func (f *Flow) GetState() State { + return f.State +} + +func (f *Flow) GetFlowName() flow.FlowName { + return flow.SettingsFlow +} + +func (f *Flow) SetState(state State) { + f.State = state +} diff --git a/selfservice/flow/settings/hook.go b/selfservice/flow/settings/hook.go index 91c6b2c5122c..c5e35610c7a2 100644 --- a/selfservice/flow/settings/hook.go +++ b/selfservice/flow/settings/hook.go @@ -231,7 +231,7 @@ func (e *HookExecutor) PostSettingsHook(w http.ResponseWriter, r *http.Request, Debug("An identity's settings have been updated.") ctxUpdate.UpdateIdentity(i) - ctxUpdate.Flow.State = StateSuccess + ctxUpdate.Flow.State = flow.StateSuccess if hookOptions.cb != nil { if err := hookOptions.cb(ctxUpdate); err != nil { return err diff --git a/selfservice/flow/settings/state.go b/selfservice/flow/settings/state.go index b605cf7569d8..21cd22f303cc 100644 --- a/selfservice/flow/settings/state.go +++ b/selfservice/flow/settings/state.go @@ -3,6 +3,8 @@ package settings +import "github.com/ory/kratos/selfservice/flow" + // State represents the state of this flow. It knows two states: // // - show_form: No user data has been collected, or it is invalid, and thus the form should be shown. @@ -11,9 +13,4 @@ package settings // when a flow with invalid (e.g. "please use a valid phone number") data was sent. // // swagger:model settingsFlowState -type State string - -const ( - StateShowForm State = "show_form" - StateSuccess State = "success" -) +type State = flow.State diff --git a/selfservice/flow/settings/test/persistence.go b/selfservice/flow/settings/test/persistence.go index 82b56f74d6e5..62bce9c547bf 100644 --- a/selfservice/flow/settings/test/persistence.go +++ b/selfservice/flow/settings/test/persistence.go @@ -14,6 +14,7 @@ import ( "github.com/ory/kratos/internal/testhelpers" "github.com/ory/kratos/persistence" + "github.com/ory/kratos/selfservice/flow" "github.com/ory/kratos/selfservice/flow/settings" "github.com/ory/x/sqlcon" @@ -54,6 +55,7 @@ func TestFlowPersister(ctx context.Context, conf *config.Config, p persistence.P require.NoError(t, p.CreateIdentity(ctx, r.Identity)) require.NotZero(t, r.Identity.ID) r.IdentityID = r.Identity.ID + r.State = flow.StateShowForm return &r } @@ -106,6 +108,7 @@ func TestFlowPersister(ctx context.Context, conf *config.Config, p persistence.P t.Run("case=should create with set ids", func(t *testing.T) { var r settings.Flow require.NoError(t, faker.FakeData(&r)) + r.State = flow.StateShowForm require.NoError(t, p.CreateIdentity(ctx, r.Identity)) require.NoError(t, p.CreateSettingsFlow(ctx, &r)) @@ -146,6 +149,7 @@ func TestFlowPersister(ctx context.Context, conf *config.Config, p persistence.P clearids(&expected) expected.Identity = nil expected.IdentityID = uuid.Nil + expected.State = flow.StateShowForm err := p.CreateSettingsFlow(ctx, &expected) require.Errorf(t, err, "%+v", expected) }) @@ -201,7 +205,7 @@ func TestFlowPersister(ctx context.Context, conf *config.Config, p persistence.P require.NoError(t, p.CreateIdentity(ctx, &identity.Identity{ID: iid})) t.Run("sets id on creation", func(t *testing.T) { - expected := &settings.Flow{ID: id, IdentityID: iid, IssuedAt: time.Now(), ExpiresAt: time.Now().Add(time.Hour)} + expected := &settings.Flow{ID: id, IdentityID: iid, State: flow.StateShowForm, IssuedAt: time.Now(), ExpiresAt: time.Now().Add(time.Hour)} require.NoError(t, p.CreateSettingsFlow(ctx, expected)) assert.EqualValues(t, id, expected.ID) assert.EqualValues(t, nid, expected.NID) diff --git a/selfservice/flow/state.go b/selfservice/flow/state.go new file mode 100644 index 000000000000..76a0683fc19d --- /dev/null +++ b/selfservice/flow/state.go @@ -0,0 +1,100 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package flow + +import ( + "database/sql" + "database/sql/driver" + "encoding/json" + + "github.com/pkg/errors" +) + +// Flow State +// +// The state represents the state of the verification flow. +// +// - choose_method: ask the user to choose a method (e.g. recover account via email) +// - sent_email: the email has been sent to the user +// - passed_challenge: the request was successful and the recovery challenge was passed. +// - show_form: a form is shown to the user to perform the flow +// - success: the flow has been completed successfully +// +// swagger:enum selfServiceFlowState +type State string + +// #nosec G101 -- only a key constant +const ( + StateChooseMethod State = "choose_method" + StateEmailSent State = "sent_email" + StatePassedChallenge State = "passed_challenge" + StateShowForm State = "show_form" + StateSuccess State = "success" +) + +var states = []State{StateChooseMethod, StateEmailSent, StatePassedChallenge} + +func indexOf(current State) int { + for k, s := range states { + if s == current { + return k + } + } + return 0 +} + +func HasReachedState(expected, actual State) bool { + return indexOf(actual) >= indexOf(expected) +} + +func NextState(current State) State { + if current == StatePassedChallenge { + return StatePassedChallenge + } + + return states[indexOf(current)+1] +} + +// For some reason using sqlxx.NullString as the State type does not work here. +// Reimplementing the Scanner interface on type State does work and allows +// the state to be NULL in the database. + +// MarshalJSON returns m as the JSON encoding of m. +func (ns State) MarshalJSON() ([]byte, error) { + return json.Marshal(string(ns)) +} + +// UnmarshalJSON sets *m to a copy of data. +func (ns *State) UnmarshalJSON(data []byte) error { + if ns == nil { + return errors.New("json.RawMessage: UnmarshalJSON on nil pointer") + } + if len(data) == 0 { + return nil + } + return errors.WithStack(json.Unmarshal(data, (*string)(ns))) +} + +// Scan implements the Scanner interface. +func (ns *State) Scan(value interface{}) error { + var v sql.NullString + if err := (&v).Scan(value); err != nil { + return err + } + *ns = State(v.String) + return nil +} + +// Value implements the driver Valuer interface. +func (ns State) Value() (driver.Value, error) { + if len(ns) == 0 { + return sql.NullString{}.Value() + } + return sql.NullString{Valid: true, String: string(ns)}.Value() +} + +// String implements the Stringer interface. +func (ns State) String() string { + return string(ns) +} diff --git a/selfservice/flow/recovery/state_test.go b/selfservice/flow/state_test.go similarity index 97% rename from selfservice/flow/recovery/state_test.go rename to selfservice/flow/state_test.go index 160be6e74555..349e0425ed44 100644 --- a/selfservice/flow/recovery/state_test.go +++ b/selfservice/flow/state_test.go @@ -1,7 +1,7 @@ // Copyright © 2023 Ory Corp // SPDX-License-Identifier: Apache-2.0 -package recovery +package flow import ( "testing" diff --git a/selfservice/flow/verification/error.go b/selfservice/flow/verification/error.go index fd7542415fb1..b39875b233d0 100644 --- a/selfservice/flow/verification/error.go +++ b/selfservice/flow/verification/error.go @@ -26,9 +26,7 @@ import ( "github.com/ory/kratos/x" ) -var ( - ErrHookAbortFlow = errors.New("aborted verification hook execution") -) +var ErrHookAbortFlow = errors.New("aborted verification hook execution") type ( errorHandlerDependencies interface { diff --git a/selfservice/flow/verification/fake_strategy.go b/selfservice/flow/verification/fake_strategy.go index 58f6b1e5af5c..d497fb5111f3 100644 --- a/selfservice/flow/verification/fake_strategy.go +++ b/selfservice/flow/verification/fake_strategy.go @@ -13,6 +13,8 @@ import ( type FakeStrategy struct{} +var _ Strategy = new(FakeStrategy) + func (f FakeStrategy) VerificationStrategyID() string { return "fake" } @@ -32,3 +34,7 @@ func (f FakeStrategy) Verify(_ http.ResponseWriter, _ *http.Request, _ *Flow) (e func (f FakeStrategy) SendVerificationEmail(context.Context, *Flow, *identity.Identity, *identity.VerifiableAddress) error { return nil } + +func (f FakeStrategy) NodeGroup() node.UiNodeGroup { + return "fake" +} diff --git a/selfservice/flow/verification/flow.go b/selfservice/flow/verification/flow.go index 71a484f7d9c5..28a71e47a977 100644 --- a/selfservice/flow/verification/flow.go +++ b/selfservice/flow/verification/flow.go @@ -106,6 +106,8 @@ type OAuth2LoginChallengeParams struct { AMR session.AuthenticationMethods `db:"authentication_methods" json:"-"` } +var _ flow.Flow = new(Flow) + func (f *Flow) GetType() flow.Type { return f.Type } @@ -144,12 +146,12 @@ func NewFlow(conf *config.Config, exp time.Duration, csrf string, r *http.Reques Action: flow.AppendFlowTo(urlx.AppendPaths(conf.SelfPublicURL(r.Context()), RouteSubmitFlow), id).String(), }, CSRFToken: csrf, - State: StateChooseMethod, + State: flow.StateChooseMethod, Type: ft, } if strategy != nil { - f.Active = sqlxx.NullString(strategy.VerificationNodeGroup()) + f.Active = sqlxx.NullString(strategy.NodeGroup()) if err := strategy.PopulateVerificationMethod(r, f); err != nil { return nil, err } @@ -270,3 +272,15 @@ func (f *Flow) ContinueURL(ctx context.Context, config *config.Config) *url.URL } return returnTo } + +func (f *Flow) GetState() State { + return f.State +} + +func (f *Flow) GetFlowName() flow.FlowName { + return flow.VerificationFlow +} + +func (f *Flow) SetState(state State) { + f.State = state +} diff --git a/selfservice/flow/verification/flow_test.go b/selfservice/flow/verification/flow_test.go index fb21b707e387..3485f3454fc4 100644 --- a/selfservice/flow/verification/flow_test.go +++ b/selfservice/flow/verification/flow_test.go @@ -64,7 +64,7 @@ func TestFlow(t *testing.T) { require.NoError(t, err) }) - assert.EqualValues(t, verification.StateChooseMethod, + assert.EqualValues(t, flow.StateChooseMethod, must(verification.NewFlow(conf, time.Hour, "", u, nil, flow.TypeBrowser)).State) } @@ -207,5 +207,4 @@ func TestContinueURL(t *testing.T) { require.Equal(t, tc.expect, url.String()) }) } - } diff --git a/selfservice/flow/verification/handler.go b/selfservice/flow/verification/handler.go index 977cb7bd8616..83a21418e83b 100644 --- a/selfservice/flow/verification/handler.go +++ b/selfservice/flow/verification/handler.go @@ -427,12 +427,12 @@ func (h *Handler) updateVerificationFlow(w http.ResponseWriter, r *http.Request, } else if errors.Is(err, flow.ErrCompletedByStrategy) { return } else if err != nil { - h.d.VerificationFlowErrorHandler().WriteFlowError(w, r, f, ss.VerificationNodeGroup(), err) + h.d.VerificationFlowErrorHandler().WriteFlowError(w, r, f, ss.NodeGroup(), err) return } found = true - g = ss.VerificationNodeGroup() + g = ss.NodeGroup() break } diff --git a/selfservice/flow/verification/handler_test.go b/selfservice/flow/verification/handler_test.go index 092f659e4a36..6eb2b12f800b 100644 --- a/selfservice/flow/verification/handler_test.go +++ b/selfservice/flow/verification/handler_test.go @@ -23,6 +23,7 @@ import ( "github.com/ory/kratos/identity" "github.com/ory/kratos/internal" "github.com/ory/kratos/internal/testhelpers" + "github.com/ory/kratos/selfservice/flow" "github.com/ory/kratos/selfservice/flow/verification" "github.com/ory/kratos/session" "github.com/ory/kratos/x" @@ -203,6 +204,7 @@ func TestPostFlow(t *testing.T) { Type: "browser", ExpiresAt: time.Now().Add(1 * time.Hour), IssuedAt: time.Now(), + State: flow.StateChooseMethod, } require.NoError(t, reg.VerificationFlowPersister().CreateVerificationFlow(ctx, f)) @@ -227,6 +229,7 @@ func TestPostFlow(t *testing.T) { IdentityID: uuid.NullUUID{UUID: uuid.Must(uuid.NewV4()), Valid: true}, AMR: session.AuthenticationMethods{{Method: identity.CredentialsTypePassword}}, }, + State: flow.StatePassedChallenge, } require.NoError(t, reg.VerificationFlowPersister().CreateVerificationFlow(ctx, f)) @@ -254,6 +257,7 @@ func TestPostFlow(t *testing.T) { ExpiresAt: time.Now().Add(1 * time.Hour), IssuedAt: time.Now(), OAuth2LoginChallenge: hydra.FakeValidLoginChallenge, + State: flow.StateChooseMethod, } require.NoError(t, reg.VerificationFlowPersister().CreateVerificationFlow(ctx, f)) @@ -264,5 +268,4 @@ func TestPostFlow(t *testing.T) { assert.Equal(t, f.ID.String(), resp.Request.URL.Query().Get("flow")) }) }) - } diff --git a/selfservice/flow/verification/state.go b/selfservice/flow/verification/state.go index 9f11037cfeef..84aded971389 100644 --- a/selfservice/flow/verification/state.go +++ b/selfservice/flow/verification/state.go @@ -3,6 +3,8 @@ package verification +import "github.com/ory/kratos/selfservice/flow" + // Verification Flow State // // The state represents the state of the verification flow. @@ -12,33 +14,4 @@ package verification // - passed_challenge: the request was successful and the recovery challenge was passed. // // swagger:model verificationFlowState -type State string - -const ( - StateChooseMethod State = "choose_method" - StateEmailSent State = "sent_email" - StatePassedChallenge State = "passed_challenge" -) - -var states = []State{StateChooseMethod, StateEmailSent, StatePassedChallenge} - -func indexOf(current State) int { - for k, s := range states { - if s == current { - return k - } - } - return 0 -} - -func HasReachedState(expected, actual State) bool { - return indexOf(actual) >= indexOf(expected) -} - -func NextState(current State) State { - if current == StatePassedChallenge { - return StatePassedChallenge - } - - return states[indexOf(current)+1] -} +type State = flow.State diff --git a/selfservice/flow/verification/state_test.go b/selfservice/flow/verification/state_test.go deleted file mode 100644 index ab192d4db878..000000000000 --- a/selfservice/flow/verification/state_test.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright © 2023 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -package verification - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestState(t *testing.T) { - assert.EqualValues(t, StateEmailSent, NextState(StateChooseMethod)) - assert.EqualValues(t, StatePassedChallenge, NextState(StateEmailSent)) - assert.EqualValues(t, StatePassedChallenge, NextState(StatePassedChallenge)) - - assert.True(t, HasReachedState(StatePassedChallenge, StatePassedChallenge)) - assert.False(t, HasReachedState(StatePassedChallenge, StateEmailSent)) - assert.False(t, HasReachedState(StateEmailSent, StateChooseMethod)) -} diff --git a/selfservice/flow/verification/strategy.go b/selfservice/flow/verification/strategy.go index 9cb4ff848920..3d270bfb8732 100644 --- a/selfservice/flow/verification/strategy.go +++ b/selfservice/flow/verification/strategy.go @@ -26,7 +26,7 @@ const ( type ( Strategy interface { VerificationStrategyID() string - VerificationNodeGroup() node.UiNodeGroup + NodeGroup() node.UiNodeGroup PopulateVerificationMethod(*http.Request, *Flow) error Verify(w http.ResponseWriter, r *http.Request, f *Flow) (err error) SendVerificationEmail(context.Context, *Flow, *identity.Identity, *identity.VerifiableAddress) error diff --git a/selfservice/flow/verification/test/persistence.go b/selfservice/flow/verification/test/persistence.go index dac7f539e334..0358462029f7 100644 --- a/selfservice/flow/verification/test/persistence.go +++ b/selfservice/flow/verification/test/persistence.go @@ -15,6 +15,7 @@ import ( "github.com/ory/kratos/driver/config" "github.com/ory/kratos/internal/testhelpers" "github.com/ory/kratos/persistence" + "github.com/ory/kratos/selfservice/flow" "github.com/ory/kratos/selfservice/flow/verification" "github.com/ory/kratos/ui/node" "github.com/ory/kratos/x" @@ -24,8 +25,9 @@ import ( func TestFlowPersister(ctx context.Context, conf *config.Config, p interface { persistence.Persister -}) func(t *testing.T) { - var clearids = func(r *verification.Flow) { +}, +) func(t *testing.T) { + clearids := func(r *verification.Flow) { r.ID = uuid.UUID{} } @@ -39,10 +41,11 @@ func TestFlowPersister(ctx context.Context, conf *config.Config, p interface { require.Error(t, err) }) - var newFlow = func(t *testing.T) *verification.Flow { + newFlow := func(t *testing.T) *verification.Flow { var r verification.Flow require.NoError(t, faker.FakeData(&r)) clearids(&r) + r.State = flow.StateChooseMethod return &r } @@ -62,6 +65,7 @@ func TestFlowPersister(ctx context.Context, conf *config.Config, p interface { t.Run("case=should create with set ids", func(t *testing.T) { var r verification.Flow require.NoError(t, faker.FakeData(&r)) + r.State = flow.StateChooseMethod require.NoError(t, p.CreateVerificationFlow(ctx, &r)) require.Equal(t, nid, r.NID) diff --git a/selfservice/hook/code_address_verifier.go b/selfservice/hook/code_address_verifier.go new file mode 100644 index 000000000000..b222970cb9af --- /dev/null +++ b/selfservice/hook/code_address_verifier.go @@ -0,0 +1,53 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package hook + +import ( + "net/http" + + "github.com/ory/kratos/identity" + "github.com/ory/kratos/selfservice/flow/registration" + "github.com/ory/kratos/selfservice/strategy/code" +) + +type ( + codeAddressDependencies interface { + code.RegistrationCodePersistenceProvider + } + CodeAddressVerifier struct { + r codeAddressDependencies + } +) + +var _ registration.PostHookPrePersistExecutor = new(CodeAddressVerifier) + +func NewCodeAddressVerifier(r codeAddressDependencies) *CodeAddressVerifier { + return &CodeAddressVerifier{r: r} +} + +func (cv *CodeAddressVerifier) ExecutePostRegistrationPrePersistHook(w http.ResponseWriter, r *http.Request, a *registration.Flow, i *identity.Identity) error { + if a.Active != identity.CredentialsTypeCodeAuth { + return nil + } + + recoveryCode, err := cv.r.RegistrationCodePersister().GetUsedRegistrationCode(r.Context(), a.GetID()) + if err != nil { + return err + } + + if recoveryCode == nil { + return nil + } + + for idx := range i.VerifiableAddresses { + va := &i.VerifiableAddresses[idx] + if !va.Verified && recoveryCode.Address == va.Value { + va.Verified = true + va.Status = identity.VerifiableAddressStatusCompleted + break + } + } + + return nil +} diff --git a/selfservice/hook/code_address_verifier_test.go b/selfservice/hook/code_address_verifier_test.go new file mode 100644 index 000000000000..579432e60556 --- /dev/null +++ b/selfservice/hook/code_address_verifier_test.go @@ -0,0 +1,90 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package hook_test + +import ( + "context" + "net/http" + "strings" + "testing" + "time" + + "github.com/gofrs/uuid" + "github.com/stretchr/testify/require" + + "github.com/ory/kratos/identity" + "github.com/ory/kratos/internal" + "github.com/ory/kratos/internal/testhelpers" + "github.com/ory/kratos/selfservice/flow" + "github.com/ory/kratos/selfservice/flow/registration" + "github.com/ory/kratos/selfservice/hook" + "github.com/ory/kratos/selfservice/strategy/code" + "github.com/ory/kratos/x" + "github.com/ory/x/randx" +) + +func TestCodeAddressVerifier(t *testing.T) { + ctx := context.Background() + conf, reg := internal.NewFastRegistryWithMocks(t) + testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/code.schema.json") + verifier := hook.NewCodeAddressVerifier(reg) + + setup := func(t *testing.T) (address string, rf *registration.Flow) { + t.Helper() + address = testhelpers.RandomEmail() + rawCode := strings.ToLower(randx.MustString(16, randx.Alpha)) + + rf = ®istration.Flow{Active: identity.CredentialsTypeCodeAuth, Type: "browser", State: flow.StatePassedChallenge} + require.NoError(t, reg.RegistrationFlowPersister().CreateRegistrationFlow(ctx, rf)) + + _, err := reg.RegistrationCodePersister().CreateRegistrationCode(ctx, &code.CreateRegistrationCodeParams{ + Address: address, + AddressType: identity.CodeAddressTypeEmail, + RawCode: rawCode, + ExpiresIn: time.Hour, + FlowID: rf.ID, + }) + require.NoError(t, err) + + _, err = reg.RegistrationCodePersister().UseRegistrationCode(ctx, rf.ID, rawCode, address) + require.NoError(t, err) + + return + } + + setupIdentity := func(t *testing.T, address string) *identity.Identity { + t.Helper() + verifiableAddress := []identity.VerifiableAddress{{ID: uuid.UUID{}, Verified: false, Value: address, Via: identity.VerifiableAddressTypeEmail}} + id := &identity.Identity{ID: x.NewUUID(), VerifiableAddresses: verifiableAddress, Credentials: map[identity.CredentialsType]identity.Credentials{ + identity.CredentialsTypeCodeAuth: {Type: identity.CredentialsTypeCodeAuth, Identifiers: []string{address}}, + }} + + require.NoError(t, reg.PrivilegedIdentityPool().CreateIdentity(ctx, id)) + return id + } + + runHook := func(t *testing.T, id *identity.Identity, flow *registration.Flow) { + t.Helper() + + r := &http.Request{} + require.NoError(t, verifier.ExecutePostRegistrationPrePersistHook(nil, r, flow, id)) + } + + t.Run("case=should set the verifiable email address to verified", func(t *testing.T) { + address, flow := setup(t) + id := setupIdentity(t, address) + require.False(t, id.VerifiableAddresses[0].Verified) + runHook(t, id, flow) + require.True(t, id.VerifiableAddresses[0].Verified) + }) + + t.Run("case=should ignore verifiable email address that does not match the code", func(t *testing.T) { + _, flow := setup(t) + newEmail := testhelpers.RandomEmail() + id := setupIdentity(t, newEmail) + require.False(t, id.VerifiableAddresses[0].Verified) + runHook(t, id, flow) + require.False(t, id.VerifiableAddresses[0].Verified) + }) +} diff --git a/selfservice/hook/stub/code.schema.json b/selfservice/hook/stub/code.schema.json new file mode 100644 index 000000000000..71219c0b9db4 --- /dev/null +++ b/selfservice/hook/stub/code.schema.json @@ -0,0 +1,27 @@ +{ + "$id": "https://example.com/registration.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Person", + "type": "object", + "properties": { + "traits": { + "type": "object", + "properties": { + "email": { + "type": "string", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + }, + "code": { + "identifier": true, + "via": "email" + } + } + } + } + } + } + } +} diff --git a/selfservice/hook/verification.go b/selfservice/hook/verification.go index ba4d7e7d79a7..e72f833faabf 100644 --- a/selfservice/hook/verification.go +++ b/selfservice/hook/verification.go @@ -20,8 +20,10 @@ import ( "github.com/ory/x/otelx" ) -var _ registration.PostHookPostPersistExecutor = new(Verifier) -var _ settings.PostHookPostPersistExecutor = new(Verifier) +var ( + _ registration.PostHookPostPersistExecutor = new(Verifier) + _ settings.PostHookPostPersistExecutor = new(Verifier) +) type ( verifierDependencies interface { @@ -100,7 +102,7 @@ func (e *Verifier) do( flowCallback(verificationFlow) } - verificationFlow.State = verification.StateEmailSent + verificationFlow.State = flow.StateEmailSent if err := strategy.PopulateVerificationMethod(r, verificationFlow); err != nil { return err diff --git a/selfservice/hook/verification_test.go b/selfservice/hook/verification_test.go index 1013de192223..3d4195b6e0ba 100644 --- a/selfservice/hook/verification_test.go +++ b/selfservice/hook/verification_test.go @@ -22,7 +22,6 @@ import ( "github.com/ory/kratos/selfservice/flow" "github.com/ory/kratos/selfservice/flow/registration" "github.com/ory/kratos/selfservice/flow/settings" - "github.com/ory/kratos/selfservice/flow/verification" "github.com/ory/kratos/selfservice/hook" "github.com/ory/kratos/session" "github.com/ory/kratos/x" @@ -94,7 +93,7 @@ func TestVerifier(t *testing.T) { expectedVerificationFlow, err := reg.VerificationFlowPersister().GetVerificationFlow(ctx, fView.ID) require.NoError(t, err) - require.Equal(t, expectedVerificationFlow.State, verification.StateEmailSent) + require.Equal(t, expectedVerificationFlow.State, flow.StateEmailSent) messages, err := reg.CourierPersister().NextMessages(context.Background(), 12) require.NoError(t, err) @@ -110,7 +109,7 @@ func TestVerifier(t *testing.T) { // Email to baz@ory.sh is skipped because it is verified already. assert.NotContains(t, recipients, "baz@ory.sh") - //these addresses will be marked as sent and won't be sent again by the settings hook + // these addresses will be marked as sent and won't be sent again by the settings hook address1, err := reg.IdentityPool().FindVerifiableAddressByValue(context.Background(), identity.VerifiableAddressTypeEmail, "foo@ory.sh") require.NoError(t, err) assert.EqualValues(t, identity.VerifiableAddressStatusSent, address1.Status) diff --git a/selfservice/strategy/code/.schema/login.schema.json b/selfservice/strategy/code/.schema/login.schema.json new file mode 100644 index 000000000000..fa030cbd67a0 --- /dev/null +++ b/selfservice/strategy/code/.schema/login.schema.json @@ -0,0 +1,32 @@ +{ + "$id": "https://schemas.ory.sh/kratos/selfservice/strategy/code/login.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "method": { + "type": "string", + "enum": [ + "code" + ] + }, + "code": { + "type": "string" + }, + "identifier": { + "type": "string" + }, + "resend": { + "type": "string", + "enum": [ + "code" + ] + }, + "flow": { + "type": "string", + "format": "uuid" + }, + "csrf_token": { + "type": "string" + } + } +} diff --git a/selfservice/strategy/code/.schema/registration.schema.json b/selfservice/strategy/code/.schema/registration.schema.json new file mode 100644 index 000000000000..90f245c107c5 --- /dev/null +++ b/selfservice/strategy/code/.schema/registration.schema.json @@ -0,0 +1,32 @@ +{ + "$id": "https://schemas.ory.sh/kratos/selfservice/strategy/code/registration.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "method": { + "type": "string", + "enum": [ + "code" + ] + }, + "csrf_token": { + "type": "string" + }, + "code": { + "type": "string" + }, + "resend": { + "type": "string", + "enum": [ + "code" + ] + }, + "traits": { + "description": "This field will be overwritten in registration.go's decoder() method. Do not add anything to this field as it has no effect." + }, + "transient_payload": { + "type": "object", + "additionalProperties": true + } + } +} diff --git a/selfservice/strategy/code/.snapshots/TestVerification-description=should_set_all_the_correct_verification_payloads_after_submission.json b/selfservice/strategy/code/.snapshots/TestVerification-description=should_set_all_the_correct_verification_payloads_after_submission.json index a1993da4d3d0..42456da54dc5 100644 --- a/selfservice/strategy/code/.snapshots/TestVerification-description=should_set_all_the_correct_verification_payloads_after_submission.json +++ b/selfservice/strategy/code/.snapshots/TestVerification-description=should_set_all_the_correct_verification_payloads_after_submission.json @@ -1,4 +1,17 @@ [ + { + "type": "input", + "group": "code", + "attributes": { + "name": "method", + "type": "hidden", + "value": "code", + "disabled": false, + "node_type": "input" + }, + "messages": [], + "meta": {} + }, { "type": "input", "group": "code", @@ -18,19 +31,6 @@ } } }, - { - "type": "input", - "group": "code", - "attributes": { - "name": "method", - "type": "hidden", - "value": "code", - "disabled": false, - "node_type": "input" - }, - "messages": [], - "meta": {} - }, { "type": "input", "group": "code", diff --git a/selfservice/strategy/code/code_login.go b/selfservice/strategy/code/code_login.go new file mode 100644 index 000000000000..689d52f0cb4f --- /dev/null +++ b/selfservice/strategy/code/code_login.go @@ -0,0 +1,114 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package code + +import ( + "context" + "database/sql" + "time" + + "github.com/pkg/errors" + + "github.com/ory/kratos/selfservice/flow" + + "github.com/gofrs/uuid" + + "github.com/ory/kratos/identity" +) + +// swagger:ignore +type LoginCode struct { + // ID represents the tokens's unique ID. + // + // required: true + // type: string + // format: uuid + ID uuid.UUID `json:"id" db:"id" faker:"-"` + + // Address represents the address that the code was sent to. + // this can be an email address or a phone number. + Address string `json:"-" db:"address"` + + // AddressType represents the type of the address + // this can be an email address or a phone number. + AddressType identity.CodeAddressType `json:"-" db:"address_type"` + + // CodeHMAC represents the HMACed value of the verification code + CodeHMAC string `json:"-" db:"code"` + + // UsedAt is the timestamp of when the code was used or null if it wasn't yet + UsedAt sql.NullTime `json:"-" db:"used_at"` + + // ExpiresAt is the time (UTC) when the token expires. + // required: true + ExpiresAt time.Time `json:"expires_at" faker:"time_type" db:"expires_at"` + + // IssuedAt is the time (UTC) when the token was issued. + // required: true + IssuedAt time.Time `json:"issued_at" faker:"time_type" db:"issued_at"` + + // CreatedAt is a helper struct field for gobuffalo.pop. + CreatedAt time.Time `json:"-" faker:"-" db:"created_at"` + + // UpdatedAt is a helper struct field for gobuffalo.pop. + UpdatedAt time.Time `json:"-" faker:"-" db:"updated_at"` + + // FlowID is a helper struct field for gobuffalo.pop. + FlowID uuid.UUID `json:"-" faker:"-" db:"selfservice_login_flow_id"` + + NID uuid.UUID `json:"-" faker:"-" db:"nid"` + IdentityID uuid.UUID `json:"identity_id" faker:"-" db:"identity_id"` +} + +func (LoginCode) TableName(ctx context.Context) string { + return "identity_login_codes" +} + +func (f *LoginCode) Validate() error { + if f == nil { + return errors.WithStack(ErrCodeNotFound) + } + if f.ExpiresAt.Before(time.Now().UTC()) { + return errors.WithStack(flow.NewFlowExpiredError(f.ExpiresAt)) + } + if f.UsedAt.Valid { + return errors.WithStack(ErrCodeAlreadyUsed) + } + return nil +} + +func (f *LoginCode) GetHMACCode() string { + return f.CodeHMAC +} + +func (f *LoginCode) GetID() uuid.UUID { + return f.ID +} + +// swagger:ignore +type CreateLoginCodeParams struct { + // Address is the email address or phone number the code should be sent to. + // required: true + Address string + + // AddressType is the type of the address (email or phone number). + // required: true + AddressType identity.CodeAddressType + + // Code represents the recovery code + // required: true + RawCode string + + // ExpiresAt is the time (UTC) when the code expires. + // required: true + ExpiresIn time.Duration + + // FlowID is a helper struct field for gobuffalo.pop. + // required: true + FlowID uuid.UUID + + // IdentityID is the identity that this code is for + // required: true + IdentityID uuid.UUID +} diff --git a/selfservice/strategy/code/code_login_test.go b/selfservice/strategy/code/code_login_test.go new file mode 100644 index 000000000000..87b50155a15b --- /dev/null +++ b/selfservice/strategy/code/code_login_test.go @@ -0,0 +1,81 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package code_test + +import ( + "database/sql" + "net/http" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/ory/kratos/internal" + "github.com/ory/kratos/selfservice/flow" + "github.com/ory/kratos/selfservice/flow/login" + "github.com/ory/kratos/selfservice/strategy/code" + "github.com/ory/kratos/x" + "github.com/ory/x/urlx" +) + +func TestLoginCode(t *testing.T) { + conf, _ := internal.NewFastRegistryWithMocks(t) + + newCode := func(expiresIn time.Duration, f *login.Flow) *code.LoginCode { + return &code.LoginCode{ + ID: x.NewUUID(), + FlowID: f.ID, + ExpiresAt: time.Now().Add(expiresIn), + } + } + + req := &http.Request{URL: urlx.ParseOrPanic("https://www.ory.sh/")} + t.Run("method=Validate", func(t *testing.T) { + t.Parallel() + + t.Run("case=returns error if flow is expired", func(t *testing.T) { + f, err := login.NewFlow(conf, -time.Hour, "", req, flow.TypeBrowser) + require.NoError(t, err) + + c := newCode(-time.Hour, f) + expected := new(flow.ExpiredError) + require.ErrorAs(t, c.Validate(), &expected) + }) + t.Run("case=returns no error if flow is not expired", func(t *testing.T) { + f, err := login.NewFlow(conf, time.Hour, "", req, flow.TypeBrowser) + require.NoError(t, err) + + c := newCode(time.Hour, f) + require.NoError(t, c.Validate()) + }) + + t.Run("case=returns error if flow has been used", func(t *testing.T) { + f, err := login.NewFlow(conf, -time.Hour, "", req, flow.TypeBrowser) + require.NoError(t, err) + + c := newCode(time.Hour, f) + c.UsedAt = sql.NullTime{ + Time: time.Now(), + Valid: true, + } + require.ErrorIs(t, c.Validate(), code.ErrCodeAlreadyUsed) + }) + + t.Run("case=returns no error if flow has not been used", func(t *testing.T) { + f, err := login.NewFlow(conf, -time.Hour, "", req, flow.TypeBrowser) + require.NoError(t, err) + + c := newCode(time.Hour, f) + c.UsedAt = sql.NullTime{ + Valid: false, + } + require.NoError(t, c.Validate()) + }) + + t.Run("case=returns error if flow is nil", func(t *testing.T) { + var c *code.LoginCode + require.ErrorIs(t, c.Validate(), code.ErrCodeNotFound) + }) + }) +} diff --git a/selfservice/strategy/code/code_recovery.go b/selfservice/strategy/code/code_recovery.go index f87a9c398de7..8d0cbe926063 100644 --- a/selfservice/strategy/code/code_recovery.go +++ b/selfservice/strategy/code/code_recovery.go @@ -8,6 +8,10 @@ import ( "database/sql" "time" + "github.com/pkg/errors" + + "github.com/ory/kratos/selfservice/flow" + "github.com/gofrs/uuid" "github.com/ory/herodot" @@ -73,16 +77,25 @@ func (RecoveryCode) TableName(ctx context.Context) string { return "identity_recovery_codes" } -func (f RecoveryCode) IsExpired() bool { - return f.ExpiresAt.Before(time.Now()) +func (f *RecoveryCode) Validate() error { + if f == nil { + return errors.WithStack(ErrCodeNotFound) + } + if f.ExpiresAt.Before(time.Now().UTC()) { + return errors.WithStack(flow.NewFlowExpiredError(f.ExpiresAt)) + } + if f.UsedAt.Valid { + return errors.WithStack(ErrCodeAlreadyUsed) + } + return nil } -func (r RecoveryCode) WasUsed() bool { - return r.UsedAt.Valid +func (f *RecoveryCode) GetHMACCode() string { + return f.CodeHMAC } -func (f RecoveryCode) IsValid() bool { - return !f.IsExpired() && !f.WasUsed() +func (f *RecoveryCode) GetID() uuid.UUID { + return f.ID } type CreateRecoveryCodeParams struct { diff --git a/selfservice/strategy/code/code_recovery_test.go b/selfservice/strategy/code/code_recovery_test.go index 3aadf350bb8c..dc099f02cae0 100644 --- a/selfservice/strategy/code/code_recovery_test.go +++ b/selfservice/strategy/code/code_recovery_test.go @@ -34,26 +34,26 @@ func TestRecoveryCode(t *testing.T) { } req := &http.Request{URL: urlx.ParseOrPanic("https://www.ory.sh/")} + t.Run("method=Validate", func(t *testing.T) { + t.Parallel() - t.Run("method=IsExpired", func(t *testing.T) { - t.Run("case=returns true if flow is expired", func(t *testing.T) { + t.Run("case=returns error if flow is expired", func(t *testing.T) { f, err := recovery.NewFlow(conf, -time.Hour, "", req, nil, flow.TypeBrowser) require.NoError(t, err) c := newCode(-time.Hour, f) - require.True(t, c.IsExpired()) + expected := new(flow.ExpiredError) + require.ErrorAs(t, c.Validate(), &expected) }) - t.Run("case=returns false if flow is not expired", func(t *testing.T) { + t.Run("case=returns no error if flow is not expired", func(t *testing.T) { f, err := recovery.NewFlow(conf, time.Hour, "", req, nil, flow.TypeBrowser) require.NoError(t, err) c := newCode(time.Hour, f) - require.False(t, c.IsExpired()) + require.NoError(t, c.Validate()) }) - }) - t.Run("method=WasUsed", func(t *testing.T) { - t.Run("case=returns true if flow has been used", func(t *testing.T) { + t.Run("case=returns error if flow has been used", func(t *testing.T) { f, err := recovery.NewFlow(conf, -time.Hour, "", req, nil, flow.TypeBrowser) require.NoError(t, err) @@ -62,9 +62,10 @@ func TestRecoveryCode(t *testing.T) { Time: time.Now(), Valid: true, } - require.True(t, c.WasUsed()) + require.ErrorIs(t, c.Validate(), code.ErrCodeAlreadyUsed) }) - t.Run("case=returns false if flow has not been used", func(t *testing.T) { + + t.Run("case=returns no error if flow has not been used", func(t *testing.T) { f, err := recovery.NewFlow(conf, -time.Hour, "", req, nil, flow.TypeBrowser) require.NoError(t, err) @@ -72,7 +73,12 @@ func TestRecoveryCode(t *testing.T) { c.UsedAt = sql.NullTime{ Valid: false, } - require.False(t, c.WasUsed()) + require.NoError(t, c.Validate()) + }) + + t.Run("case=returns error if flow is nil", func(t *testing.T) { + var c *code.RecoveryCode + require.ErrorIs(t, c.Validate(), code.ErrCodeNotFound) }) }) } diff --git a/selfservice/strategy/code/code_registration.go b/selfservice/strategy/code/code_registration.go new file mode 100644 index 000000000000..d8691b54b224 --- /dev/null +++ b/selfservice/strategy/code/code_registration.go @@ -0,0 +1,109 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package code + +import ( + "context" + "database/sql" + "time" + + "github.com/pkg/errors" + + "github.com/ory/kratos/selfservice/flow" + + "github.com/gofrs/uuid" + + "github.com/ory/kratos/identity" +) + +// swagger:ignore +type RegistrationCode struct { + // ID represents the tokens's unique ID. + // + // required: true + // type: string + // format: uuid + ID uuid.UUID `json:"id" db:"id" faker:"-"` + + // Address represents the address that the code was sent to. + // this can be an email address or a phone number. + Address string `json:"-" db:"address"` + + // AddressType represents the type of the address + // this can be an email address or a phone number. + AddressType identity.CodeAddressType `json:"-" db:"address_type"` + + // CodeHMAC represents the HMACed value of the verification code + CodeHMAC string `json:"-" db:"code"` + + // UsedAt is the timestamp of when the code was used or null if it wasn't yet + UsedAt sql.NullTime `json:"-" db:"used_at"` + + // ExpiresAt is the time (UTC) when the token expires. + // required: true + ExpiresAt time.Time `json:"expires_at" faker:"time_type" db:"expires_at"` + + // IssuedAt is the time (UTC) when the token was issued. + // required: true + IssuedAt time.Time `json:"issued_at" faker:"time_type" db:"issued_at"` + + // CreatedAt is a helper struct field for gobuffalo.pop. + CreatedAt time.Time `json:"-" faker:"-" db:"created_at"` + + // UpdatedAt is a helper struct field for gobuffalo.pop. + UpdatedAt time.Time `json:"-" faker:"-" db:"updated_at"` + + // FlowID is a helper struct field for gobuffalo.pop. + FlowID uuid.UUID `json:"-" faker:"-" db:"selfservice_registration_flow_id"` + + NID uuid.UUID `json:"-" faker:"-" db:"nid"` +} + +func (RegistrationCode) TableName(ctx context.Context) string { + return "identity_registration_codes" +} + +func (f *RegistrationCode) Validate() error { + if f == nil { + return errors.WithStack(ErrCodeNotFound) + } + if f.ExpiresAt.Before(time.Now().UTC()) { + return errors.WithStack(flow.NewFlowExpiredError(f.ExpiresAt)) + } + if f.UsedAt.Valid { + return errors.WithStack(ErrCodeAlreadyUsed) + } + return nil +} + +func (f *RegistrationCode) GetHMACCode() string { + return f.CodeHMAC +} + +func (f *RegistrationCode) GetID() uuid.UUID { + return f.ID +} + +// swagger:ignore +type CreateRegistrationCodeParams struct { + // Address is the email address or phone number the code should be sent to. + // required: true + Address string + + // AddressType is the type of the address (email or phone number). + // required: true + AddressType identity.CodeAddressType + + // Code represents the recovery code + // required: true + RawCode string + + // ExpiresAt is the time (UTC) when the code expires. + // required: true + ExpiresIn time.Duration + + // FlowID is a helper struct field for gobuffalo.pop. + // required: true + FlowID uuid.UUID +} diff --git a/selfservice/strategy/code/code_registration_test.go b/selfservice/strategy/code/code_registration_test.go new file mode 100644 index 000000000000..034d9fcf2b92 --- /dev/null +++ b/selfservice/strategy/code/code_registration_test.go @@ -0,0 +1,80 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package code_test + +import ( + "database/sql" + "net/http" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/ory/kratos/internal" + "github.com/ory/kratos/selfservice/flow" + "github.com/ory/kratos/selfservice/flow/registration" + "github.com/ory/kratos/selfservice/strategy/code" + "github.com/ory/kratos/x" + "github.com/ory/x/urlx" +) + +func TestRegistrationCode(t *testing.T) { + conf, _ := internal.NewFastRegistryWithMocks(t) + newCode := func(expiresIn time.Duration, f *registration.Flow) *code.RegistrationCode { + return &code.RegistrationCode{ + ID: x.NewUUID(), + FlowID: f.ID, + ExpiresAt: time.Now().Add(expiresIn), + } + } + + req := &http.Request{URL: urlx.ParseOrPanic("https://www.ory.sh/")} + t.Run("method=Validate", func(t *testing.T) { + t.Parallel() + + t.Run("case=returns error if flow is expired", func(t *testing.T) { + f, err := registration.NewFlow(conf, -time.Hour, "", req, flow.TypeBrowser) + require.NoError(t, err) + + c := newCode(-time.Hour, f) + expected := new(flow.ExpiredError) + require.ErrorAs(t, c.Validate(), &expected) + }) + t.Run("case=returns no error if flow is not expired", func(t *testing.T) { + f, err := registration.NewFlow(conf, time.Hour, "", req, flow.TypeBrowser) + require.NoError(t, err) + + c := newCode(time.Hour, f) + require.NoError(t, c.Validate()) + }) + + t.Run("case=returns error if flow has been used", func(t *testing.T) { + f, err := registration.NewFlow(conf, -time.Hour, "", req, flow.TypeBrowser) + require.NoError(t, err) + + c := newCode(time.Hour, f) + c.UsedAt = sql.NullTime{ + Time: time.Now(), + Valid: true, + } + require.ErrorIs(t, c.Validate(), code.ErrCodeAlreadyUsed) + }) + + t.Run("case=returns no error if flow has not been used", func(t *testing.T) { + f, err := registration.NewFlow(conf, -time.Hour, "", req, flow.TypeBrowser) + require.NoError(t, err) + + c := newCode(time.Hour, f) + c.UsedAt = sql.NullTime{ + Valid: false, + } + require.NoError(t, c.Validate()) + }) + + t.Run("case=returns error if flow is nil", func(t *testing.T) { + var c *code.RegistrationCode + require.ErrorIs(t, c.Validate(), code.ErrCodeNotFound) + }) + }) +} diff --git a/selfservice/strategy/code/code_sender.go b/selfservice/strategy/code/code_sender.go index 5f48437131b5..d3667aea3b07 100644 --- a/selfservice/strategy/code/code_sender.go +++ b/selfservice/strategy/code/code_sender.go @@ -22,6 +22,7 @@ import ( "github.com/ory/kratos/courier" "github.com/ory/kratos/driver/config" "github.com/ory/kratos/identity" + "github.com/ory/kratos/selfservice/flow" "github.com/ory/kratos/selfservice/flow/recovery" "github.com/ory/kratos/selfservice/flow/verification" "github.com/ory/kratos/x" @@ -40,6 +41,8 @@ type ( RecoveryCodePersistenceProvider VerificationCodePersistenceProvider + RegistrationCodePersistenceProvider + LoginCodePersistenceProvider HTTPClient(ctx context.Context, opts ...httpx.ResilientOptions) *retryablehttp.Client } @@ -50,6 +53,10 @@ type ( Sender struct { deps senderDependencies } + Address struct { + To string + Via identity.CodeAddressType + } ) var ErrUnknownAddress = herodot.ErrNotFound.WithReason("recovery requested for unknown address") @@ -58,6 +65,97 @@ func NewSender(deps senderDependencies) *Sender { return &Sender{deps: deps} } +func (s *Sender) SendCode(ctx context.Context, f flow.Flow, id *identity.Identity, addresses ...Address) error { + s.deps.Logger(). + WithSensitiveField("address", addresses). + Debugf("Preparing %s code", f.GetFlowName()) + + // send to all addresses + for _, address := range addresses { + // We have to generate a unique code per address, or otherwise it is not possible to link which + // address was used to verify the code. + // + // See also [this discussion](https://github.com/ory/kratos/pull/3456#discussion_r1307560988). + rawCode := GenerateCode() + + switch f.GetFlowName() { + case flow.RegistrationFlow: + code, err := s.deps. + RegistrationCodePersister(). + CreateRegistrationCode(ctx, &CreateRegistrationCodeParams{ + AddressType: address.Via, + RawCode: rawCode, + ExpiresIn: s.deps.Config().SelfServiceCodeMethodLifespan(ctx), + FlowID: f.GetID(), + Address: address.To, + }) + if err != nil { + return err + } + model, err := x.StructToMap(id.Traits) + if err != nil { + return err + } + + emailModel := email.RegistrationCodeValidModel{ + To: address.To, + RegistrationCode: rawCode, + Traits: model, + } + + s.deps.Audit(). + WithField("registration_flow_id", code.FlowID). + WithField("registration_code_id", code.ID). + WithSensitiveField("registration_code", rawCode). + Info("Sending out registration email with code.") + + if err := s.send(ctx, string(address.Via), email.NewRegistrationCodeValid(s.deps, &emailModel)); err != nil { + return errors.WithStack(err) + } + + case flow.LoginFlow: + code, err := s.deps. + LoginCodePersister(). + CreateLoginCode(ctx, &CreateLoginCodeParams{ + AddressType: address.Via, + Address: address.To, + RawCode: rawCode, + ExpiresIn: s.deps.Config().SelfServiceCodeMethodLifespan(ctx), + FlowID: f.GetID(), + IdentityID: id.ID, + }) + if err != nil { + return err + } + + model, err := x.StructToMap(id) + if err != nil { + return err + } + + emailModel := email.LoginCodeValidModel{ + To: address.To, + LoginCode: rawCode, + Identity: model, + } + s.deps.Audit(). + WithField("login_flow_id", code.FlowID). + WithField("login_code_id", code.ID). + WithSensitiveField("login_code", rawCode). + Info("Sending out login email with code.") + + if err := s.send(ctx, string(address.Via), email.NewLoginCodeValid(s.deps, &emailModel)); err != nil { + return errors.WithStack(err) + } + + default: + return errors.WithStack(errors.New("received unknown flow type")) + + } + } + return nil +} + // SendRecoveryCode sends a recovery code to the specified address // // If the address does not exist in the store and dispatching invalid emails is enabled (CourierEnableInvalidDispatch is diff --git a/selfservice/strategy/code/code_sender_test.go b/selfservice/strategy/code/code_sender_test.go index 6b74bf4f1c53..e5ba75826eb5 100644 --- a/selfservice/strategy/code/code_sender_test.go +++ b/selfservice/strategy/code/code_sender_test.go @@ -48,7 +48,6 @@ func TestSender(t *testing.T) { require.NoError(t, reg.IdentityManager().Create(ctx, i)) t.Run("method=SendRecoveryCode", func(t *testing.T) { - recoveryCode := func(t *testing.T) { t.Helper() f, err := recovery.NewFlow(conf, time.Hour, "", u, code.NewStrategy(reg), flow.TypeBrowser) @@ -101,7 +100,6 @@ func TestSender(t *testing.T) { assert.Equal(t, messages[1].Subject, subject+" invalid") assert.Equal(t, messages[1].Body, body) }) - }) t.Run("method=SendVerificationCode", func(t *testing.T) { @@ -198,7 +196,6 @@ func TestSender(t *testing.T) { }, } { t.Run("strategy="+tc.flow, func(t *testing.T) { - conf.Set(ctx, tc.configKey, false) t.Cleanup(func() { @@ -214,5 +211,4 @@ func TestSender(t *testing.T) { }) } }) - } diff --git a/selfservice/strategy/code/verification_code.go b/selfservice/strategy/code/code_verification.go similarity index 93% rename from selfservice/strategy/code/verification_code.go rename to selfservice/strategy/code/code_verification.go index a4f204bae176..324766ebfa1c 100644 --- a/selfservice/strategy/code/verification_code.go +++ b/selfservice/strategy/code/code_verification.go @@ -62,6 +62,9 @@ func (VerificationCode) TableName(context.Context) string { // - If the code was already used `ErrCodeAlreadyUsed` is returnd // - Otherwise, `nil` is returned func (f *VerificationCode) Validate() error { + if f == nil { + return errors.WithStack(ErrCodeNotFound) + } if f.ExpiresAt.Before(time.Now().UTC()) { return errors.WithStack(flow.NewFlowExpiredError(f.ExpiresAt)) } @@ -71,6 +74,14 @@ func (f *VerificationCode) Validate() error { return nil } +func (f *VerificationCode) GetHMACCode() string { + return f.CodeHMAC +} + +func (f *VerificationCode) GetID() uuid.UUID { + return f.ID +} + type CreateVerificationCodeParams struct { // Code represents the recovery code RawCode string diff --git a/selfservice/strategy/code/code_verification_test.go b/selfservice/strategy/code/code_verification_test.go new file mode 100644 index 000000000000..3217b7dcbb00 --- /dev/null +++ b/selfservice/strategy/code/code_verification_test.go @@ -0,0 +1,81 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package code_test + +import ( + "database/sql" + "net/http" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/ory/kratos/internal" + "github.com/ory/kratos/selfservice/flow" + "github.com/ory/kratos/selfservice/flow/verification" + "github.com/ory/kratos/selfservice/strategy/code" + "github.com/ory/kratos/x" + "github.com/ory/x/urlx" +) + +func TestVerificationCode(t *testing.T) { + conf, _ := internal.NewFastRegistryWithMocks(t) + + newCode := func(expiresIn time.Duration, f *verification.Flow) *code.VerificationCode { + return &code.VerificationCode{ + ID: x.NewUUID(), + FlowID: f.ID, + ExpiresAt: time.Now().Add(expiresIn), + } + } + + req := &http.Request{URL: urlx.ParseOrPanic("https://www.ory.sh/")} + t.Run("method=Validate", func(t *testing.T) { + t.Parallel() + + t.Run("case=returns error if flow is expired", func(t *testing.T) { + f, err := verification.NewFlow(conf, -time.Hour, "", req, nil, flow.TypeBrowser) + require.NoError(t, err) + + c := newCode(-time.Hour, f) + expected := new(flow.ExpiredError) + require.ErrorAs(t, c.Validate(), &expected) + }) + t.Run("case=returns no error if flow is not expired", func(t *testing.T) { + f, err := verification.NewFlow(conf, time.Hour, "", req, nil, flow.TypeBrowser) + require.NoError(t, err) + + c := newCode(time.Hour, f) + require.NoError(t, c.Validate()) + }) + + t.Run("case=returns error if flow has been used", func(t *testing.T) { + f, err := verification.NewFlow(conf, -time.Hour, "", req, nil, flow.TypeBrowser) + require.NoError(t, err) + + c := newCode(time.Hour, f) + c.UsedAt = sql.NullTime{ + Time: time.Now(), + Valid: true, + } + require.ErrorIs(t, c.Validate(), code.ErrCodeAlreadyUsed) + }) + + t.Run("case=returns no error if flow has not been used", func(t *testing.T) { + f, err := verification.NewFlow(conf, -time.Hour, "", req, nil, flow.TypeBrowser) + require.NoError(t, err) + + c := newCode(time.Hour, f) + c.UsedAt = sql.NullTime{ + Valid: false, + } + require.NoError(t, c.Validate()) + }) + + t.Run("case=returns error if flow is nil", func(t *testing.T) { + var c *code.VerificationCode + require.ErrorIs(t, c.Validate(), code.ErrCodeNotFound) + }) + }) +} diff --git a/selfservice/strategy/code/persistence.go b/selfservice/strategy/code/persistence.go index b64a6bbfb0c8..ea5aaff682cc 100644 --- a/selfservice/strategy/code/persistence.go +++ b/selfservice/strategy/code/persistence.go @@ -29,4 +29,26 @@ type ( VerificationCodePersistenceProvider interface { VerificationCodePersister() VerificationCodePersister } + + RegistrationCodePersistenceProvider interface { + RegistrationCodePersister() RegistrationCodePersister + } + + RegistrationCodePersister interface { + CreateRegistrationCode(context.Context, *CreateRegistrationCodeParams) (*RegistrationCode, error) + UseRegistrationCode(ctx context.Context, flowID uuid.UUID, code string, addresses ...string) (*RegistrationCode, error) + DeleteRegistrationCodesOfFlow(ctx context.Context, flowID uuid.UUID) error + GetUsedRegistrationCode(ctx context.Context, flowID uuid.UUID) (*RegistrationCode, error) + } + + LoginCodePersistenceProvider interface { + LoginCodePersister() LoginCodePersister + } + + LoginCodePersister interface { + CreateLoginCode(context.Context, *CreateLoginCodeParams) (*LoginCode, error) + UseLoginCode(ctx context.Context, flowID uuid.UUID, identityID uuid.UUID, code string) (*LoginCode, error) + DeleteLoginCodesOfFlow(ctx context.Context, flowID uuid.UUID) error + GetUsedLoginCode(ctx context.Context, flowID uuid.UUID) (*LoginCode, error) + } ) diff --git a/selfservice/strategy/code/schema.go b/selfservice/strategy/code/schema.go index 69d5bd07393e..d3ec2c66cf81 100644 --- a/selfservice/strategy/code/schema.go +++ b/selfservice/strategy/code/schema.go @@ -12,3 +12,9 @@ var recoveryMethodSchema []byte //go:embed .schema/verification.schema.json var verificationMethodSchema []byte + +//go:embed .schema/login.schema.json +var loginMethodSchema []byte + +//go:embed .schema/registration.schema.json +var registrationSchema []byte diff --git a/selfservice/strategy/code/strategy.go b/selfservice/strategy/code/strategy.go index b35d8bda30ff..94c8de75e9b6 100644 --- a/selfservice/strategy/code/strategy.go +++ b/selfservice/strategy/code/strategy.go @@ -4,29 +4,51 @@ package code import ( + "net/http" + "strings" + + "github.com/pkg/errors" + + "github.com/ory/herodot" + "github.com/ory/kratos/continuity" "github.com/ory/kratos/courier" "github.com/ory/kratos/driver/config" "github.com/ory/kratos/identity" "github.com/ory/kratos/schema" "github.com/ory/kratos/selfservice/errorx" + "github.com/ory/kratos/selfservice/flow" + "github.com/ory/kratos/selfservice/flow/login" "github.com/ory/kratos/selfservice/flow/recovery" + "github.com/ory/kratos/selfservice/flow/registration" "github.com/ory/kratos/selfservice/flow/settings" "github.com/ory/kratos/selfservice/flow/verification" + "github.com/ory/kratos/selfservice/sessiontokenexchange" "github.com/ory/kratos/session" + "github.com/ory/kratos/text" "github.com/ory/kratos/ui/container" "github.com/ory/kratos/ui/node" "github.com/ory/kratos/x" "github.com/ory/x/decoderx" "github.com/ory/x/randx" + "github.com/ory/x/urlx" ) -var _ recovery.Strategy = new(Strategy) -var _ recovery.AdminHandler = new(Strategy) -var _ recovery.PublicHandler = new(Strategy) +var ( + _ recovery.Strategy = new(Strategy) + _ recovery.AdminHandler = new(Strategy) + _ recovery.PublicHandler = new(Strategy) +) -var _ verification.Strategy = new(Strategy) -var _ verification.AdminHandler = new(Strategy) -var _ verification.PublicHandler = new(Strategy) +var ( + _ verification.Strategy = new(Strategy) + _ verification.AdminHandler = new(Strategy) + _ verification.PublicHandler = new(Strategy) +) + +var ( + _ login.Strategy = new(Strategy) + _ registration.Strategy = new(Strategy) +) type ( // FlowMethod contains the configuration for this selfservice strategy. @@ -39,6 +61,7 @@ type ( x.CSRFTokenGeneratorProvider x.WriterProvider x.LoggingProvider + x.TracingProvider config.Provider @@ -65,31 +88,250 @@ type ( verification.StrategyProvider verification.HookExecutorProvider + login.StrategyProvider + login.FlowPersistenceProvider + + registration.StrategyProvider + registration.FlowPersistenceProvider + RecoveryCodePersistenceProvider VerificationCodePersistenceProvider SenderProvider + RegistrationCodePersistenceProvider + LoginCodePersistenceProvider + schema.IdentityTraitsProvider + + sessiontokenexchange.PersistenceProvider + + continuity.ManagementProvider } Strategy struct { deps strategyDependencies dx *decoderx.HTTP } + + codeIdentifier struct { + Identifier string `json:"identifier"` + } ) func NewStrategy(deps strategyDependencies) *Strategy { return &Strategy{deps: deps, dx: decoderx.NewHTTP()} } -func (s *Strategy) RecoveryNodeGroup() node.UiNodeGroup { - return node.CodeGroup +func (s *Strategy) ID() identity.CredentialsType { + return identity.CredentialsTypeCodeAuth } -func (s *Strategy) VerificationNodeGroup() node.UiNodeGroup { +func (s *Strategy) NodeGroup() node.UiNodeGroup { return node.CodeGroup } +func (s *Strategy) PopulateMethod(r *http.Request, f flow.Flow) error { + if string(f.GetState()) == "" { + f.SetState(flow.StateChooseMethod) + } + + f.GetUI().ResetMessages() + + nodes := f.GetUI().Nodes + + switch f.GetState() { + case flow.StateChooseMethod: + + if f.GetFlowName() == flow.VerificationFlow || f.GetFlowName() == flow.RecoveryFlow { + nodes.Append( + node.NewInputField("email", nil, node.CodeGroup, node.InputAttributeTypeEmail, node.WithRequiredInputAttribute). + WithMetaLabel(text.NewInfoNodeInputEmail()), + ) + } else if f.GetFlowName() == flow.LoginFlow { + // we use the identifier label here since we don't know what + // type of field the identifier is + nodes.Upsert( + node.NewInputField("identifier", nil, node.DefaultGroup, node.InputAttributeTypeText, node.WithRequiredInputAttribute). + WithMetaLabel(text.NewInfoNodeLabelID()), + ) + } else if f.GetFlowName() == flow.RegistrationFlow { + ds, err := s.deps.Config().DefaultIdentityTraitsSchemaURL(r.Context()) + if err != nil { + return err + } + + // set the traits on the default group so that the ui can render them + // this prevents having multiple of the same ui fields on the same ui form + traitNodes, err := container.NodesFromJSONSchema(r.Context(), node.CodeGroup, ds.String(), "", nil) + if err != nil { + return err + } + + for _, n := range traitNodes { + nodes.Append(n) + } + } + + var codeMetaLabel *text.Message + + switch f.GetFlowName() { + case flow.VerificationFlow, flow.RecoveryFlow: + codeMetaLabel = text.NewInfoNodeLabelSubmit() + case flow.LoginFlow: + codeMetaLabel = text.NewInfoSelfServiceLoginCode() + case flow.RegistrationFlow: + codeMetaLabel = text.NewInfoSelfServiceRegistrationRegisterCode() + } + + methodButton := node.NewInputField("method", s.ID(), node.CodeGroup, node.InputAttributeTypeSubmit). + WithMetaLabel(codeMetaLabel) + + nodes.Append(methodButton) + + f.GetUI().Nodes = nodes + + case flow.StateEmailSent: + // fresh ui node group + freshNodes := node.Nodes{} + var route string + var codeMetaLabel *text.Message + var message *text.Message + + var resendNode *node.Node + + switch f.GetFlowName() { + case flow.RecoveryFlow: + route = recovery.RouteSubmitFlow + codeMetaLabel = text.NewInfoNodeLabelRecoveryCode() + message = text.NewRecoveryEmailWithCodeSent() + + resendNode = node.NewInputField("email", nil, node.CodeGroup, node.InputAttributeTypeEmail, node.WithRequiredInputAttribute). + WithMetaLabel(text.NewInfoNodeResendOTP()) + case flow.VerificationFlow: + route = verification.RouteSubmitFlow + codeMetaLabel = text.NewInfoNodeLabelVerificationCode() + message = text.NewVerificationEmailWithCodeSent() + + case flow.LoginFlow: + route = login.RouteSubmitFlow + codeMetaLabel = text.NewInfoNodeLabelLoginCode() + message = text.NewLoginEmailWithCodeSent() + + // preserve the login identifier that were submitted + // so we can retry the code flow with the same data + for _, n := range f.GetUI().Nodes { + if n.Group == node.DefaultGroup { + freshNodes = append(freshNodes, n) + } + } + + resendNode = node.NewInputField("resend", "code", node.CodeGroup, node.InputAttributeTypeSubmit). + WithMetaLabel(text.NewInfoNodeResendOTP()) + + case flow.RegistrationFlow: + route = registration.RouteSubmitFlow + codeMetaLabel = text.NewInfoNodeLabelRegistrationCode() + message = text.NewRegistrationEmailWithCodeSent() + + // in the registration flow we need to preserve the trait fields that were submitted + // so we can retry the code flow with the same data + for _, n := range f.GetUI().Nodes { + if t, ok := n.Attributes.(*node.InputAttributes); ok && t.Type == node.InputAttributeTypeSubmit { + continue + } + + if n.Group == node.CodeGroup { + freshNodes = append(freshNodes, n) + } + } + + resendNode = node.NewInputField("resend", "code", node.CodeGroup, node.InputAttributeTypeSubmit). + WithMetaLabel(text.NewInfoNodeResendOTP()) + default: + return errors.WithStack(herodot.ErrBadRequest.WithReason("received an unexpected flow type")) + } + + // Hidden field Required for the re-send code button + // !!important!!: this field must be appended before the code submit button since upsert will replace the first node with the same name + freshNodes.Upsert( + node.NewInputField("method", s.NodeGroup(), node.CodeGroup, node.InputAttributeTypeHidden), + ) + + // code input field + freshNodes.Upsert(node.NewInputField("code", nil, node.CodeGroup, node.InputAttributeTypeText, node.WithRequiredInputAttribute). + WithMetaLabel(codeMetaLabel)) + + // code submit button + freshNodes. + Append(node.NewInputField("method", s.ID(), node.CodeGroup, node.InputAttributeTypeSubmit). + WithMetaLabel(text.NewInfoNodeLabelSubmit())) + + if resendNode != nil { + freshNodes.Append(resendNode) + } + + f.GetUI().Nodes = freshNodes + + f.GetUI().Method = "POST" + f.GetUI().Action = flow.AppendFlowTo(urlx.AppendPaths(s.deps.Config().SelfPublicURL(r.Context()), route), f.GetID()).String() + + // Set the request's CSRF token + if f.GetType() == flow.TypeBrowser { + f.GetUI().SetCSRF(s.deps.GenerateCSRFToken(r)) + } + + f.GetUI().Messages.Set(message) + + case flow.StatePassedChallenge: + fallthrough + default: + return errors.WithStack(herodot.ErrBadRequest.WithReason("received an unexpected flow state")) + } + + // no matter the flow type or state we need to set the CSRF token + if f.GetType() == flow.TypeBrowser { + f.GetUI().SetCSRF(s.deps.GenerateCSRFToken(r)) + } + return nil +} + +// NewCodeUINodes creates a fresh UI for the code flow. +// this is used with the `recovery`, `verification`, `registration` and `login` flows. +func (s *Strategy) NewCodeUINodes(r *http.Request, f flow.Flow, data any) error { + if err := s.PopulateMethod(r, f); err != nil { + return err + } + + prefix := "" // The login flow does not process traits + if f.GetFlowName() == flow.RegistrationFlow { + // The registration form does however + prefix = "traits" + } + + cont, err := container.NewFromStruct("", node.CodeGroup, data, prefix) + if err != nil { + return err + } + + for _, n := range cont.Nodes { + // we only set the value and not the whole field because we want to keep types from the initial form generation + f.GetUI().GetNodes().SetValueAttribute(n.ID(), n.Attributes.GetValue()) + } + + return nil +} + +func SetDefaultFlowState(f flow.Flow, resend string) { + // By Default the flow should be in the 'choose method' state. + if f.GetState() == "" { + f.SetState(flow.StateChooseMethod) + } + + if strings.EqualFold(resend, "code") { + f.SetState(flow.StateChooseMethod) + } +} + const CodeLength = 6 func GenerateCode() string { diff --git a/selfservice/strategy/code/strategy_login.go b/selfservice/strategy/code/strategy_login.go new file mode 100644 index 000000000000..264df98e2dd9 --- /dev/null +++ b/selfservice/strategy/code/strategy_login.go @@ -0,0 +1,279 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package code + +import ( + "context" + "net/http" + "strings" + + "github.com/gofrs/uuid" + "github.com/pkg/errors" + + "github.com/ory/herodot" + "github.com/ory/x/otelx" + + "github.com/ory/kratos/identity" + "github.com/ory/kratos/schema" + "github.com/ory/kratos/selfservice/flow" + "github.com/ory/kratos/selfservice/flow/login" + "github.com/ory/kratos/session" + "github.com/ory/kratos/text" + "github.com/ory/kratos/ui/node" + "github.com/ory/kratos/x" + "github.com/ory/x/decoderx" +) + +var _ login.Strategy = new(Strategy) + +// Update Login flow using the code method +// +// swagger:model updateLoginFlowWithCodeMethod +type updateLoginFlowWithCodeMethod struct { + // Method should be set to "code" when logging in using the code strategy. + // + // required: true + Method string `json:"method" form:"method"` + + // CSRFToken is the anti-CSRF token + // + // required: true + CSRFToken string `json:"csrf_token" form:"csrf_token"` + + // Code is the 6 digits code sent to the user + // + // required: false + Code string `json:"code" form:"code"` + + // Identifier is the code identifier + // The identifier requires that the user has already completed the registration or settings with code flow. + // required: false + Identifier string `json:"identifier" form:"identifier"` + + // Resend is set when the user wants to resend the code + // required: false + Resend string `json:"resend" form:"resend"` +} + +func (s *Strategy) RegisterLoginRoutes(*x.RouterPublic) {} + +func (s *Strategy) CompletedAuthenticationMethod(ctx context.Context) session.AuthenticationMethod { + return session.AuthenticationMethod{ + Method: identity.CredentialsTypeCodeAuth, + AAL: identity.AuthenticatorAssuranceLevel1, + } +} + +func (s *Strategy) HandleLoginError(r *http.Request, f *login.Flow, body *updateLoginFlowWithCodeMethod, err error) error { + if errors.Is(err, flow.ErrCompletedByStrategy) { + return err + } + + if f != nil { + email := "" + if body != nil { + email = body.Identifier + } + + f.UI.SetCSRF(s.deps.GenerateCSRFToken(r)) + f.UI.GetNodes().Upsert( + node.NewInputField("identifier", email, node.DefaultGroup, node.InputAttributeTypeText, node.WithRequiredInputAttribute). + WithMetaLabel(text.NewInfoNodeLabelID()), + ) + } + + return err +} + +func (s *Strategy) PopulateLoginMethod(r *http.Request, requestedAAL identity.AuthenticatorAssuranceLevel, lf *login.Flow) error { + return s.PopulateMethod(r, lf) +} + +func (s *Strategy) getIdentity(ctx context.Context, identifier string) (_ *identity.Identity, _ *identity.Credentials, err error) { + ctx, span := s.deps.Tracer(ctx).Tracer().Start(ctx, "selfservice.strategy.code.strategy.getIdentity") + defer otelx.End(span, &err) + + i, cred, err := s.deps.PrivilegedIdentityPool().FindByCredentialsIdentifier(ctx, s.ID(), identifier) + if err != nil { + return nil, nil, errors.WithStack(schema.NewNoCodeAuthnCredentials()) + } + + if len(cred.Identifiers) == 0 { + return nil, nil, errors.WithStack(schema.NewNoCodeAuthnCredentials()) + } + + return i, cred, nil +} + +func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, _ uuid.UUID) (_ *identity.Identity, err error) { + ctx, span := s.deps.Tracer(r.Context()).Tracer().Start(r.Context(), "selfservice.strategy.code.strategy.Login") + defer otelx.End(span, &err) + + if err := flow.MethodEnabledAndAllowedFromRequest(r, f.GetFlowName(), s.ID().String(), s.deps); err != nil { + return nil, err + } + + if err := login.CheckAAL(f, identity.AuthenticatorAssuranceLevel1); err != nil { + return nil, err + } + + var p updateLoginFlowWithCodeMethod + if err := s.dx.Decode(r, &p, + decoderx.HTTPDecoderSetValidatePayloads(true), + decoderx.HTTPKeepRequestBody(true), + decoderx.MustHTTPRawJSONSchemaCompiler(loginMethodSchema), + decoderx.HTTPDecoderAllowedMethods("POST"), + decoderx.HTTPDecoderJSONFollowsFormFormat()); err != nil { + return nil, s.HandleLoginError(r, f, &p, err) + } + + if err := flow.EnsureCSRF(s.deps, r, f.Type, s.deps.Config().DisableAPIFlowEnforcement(ctx), s.deps.GenerateCSRFToken, p.CSRFToken); err != nil { + return nil, s.HandleLoginError(r, f, &p, err) + } + + // By Default the flow should be in the 'choose method' state. + SetDefaultFlowState(f, p.Resend) + + switch f.GetState() { + case flow.StateChooseMethod: + if err := s.loginSendEmail(ctx, w, r, f, &p); err != nil { + return nil, s.HandleLoginError(r, f, &p, err) + } + return nil, nil + case flow.StateEmailSent: + i, err := s.loginVerifyCode(ctx, r, f, &p) + if err != nil { + return nil, s.HandleLoginError(r, f, &p, err) + } + return i, nil + case flow.StatePassedChallenge: + return nil, s.HandleLoginError(r, f, &p, errors.WithStack(schema.NewNoLoginStrategyResponsible())) + } + + return nil, s.HandleLoginError(r, f, &p, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Unexpected flow state: %s", f.GetState()))) +} + +func (s *Strategy) loginSendEmail(ctx context.Context, w http.ResponseWriter, r *http.Request, f *login.Flow, p *updateLoginFlowWithCodeMethod) (err error) { + ctx, span := s.deps.Tracer(ctx).Tracer().Start(ctx, "selfservice.strategy.code.strategy.loginSendEmail") + defer otelx.End(span, &err) + + if len(p.Identifier) == 0 { + return errors.WithStack(schema.NewRequiredError("#/identifier", "identifier")) + } + + p.Identifier = maybeNormalizeEmail(p.Identifier) + + // Step 1: Get the identity + i, _, err := s.getIdentity(ctx, p.Identifier) + if err != nil { + return err + } + + // Step 2: Delete any previous login codes for this flow ID + if err := s.deps.LoginCodePersister().DeleteLoginCodesOfFlow(ctx, f.GetID()); err != nil { + return errors.WithStack(err) + } + + addresses := []Address{{ + To: p.Identifier, + Via: identity.CodeAddressType(identity.AddressTypeEmail), + }} + + // kratos only supports `email` identifiers at the moment with the code method + // this is validated in the identity validation step above + if err := s.deps.CodeSender().SendCode(ctx, f, i, addresses...); err != nil { + return errors.WithStack(err) + } + + // sets the flow state to code sent + f.SetState(flow.NextState(f.GetState())) + + if err := s.NewCodeUINodes(r, f, &codeIdentifier{Identifier: p.Identifier}); err != nil { + return err + } + + f.Active = identity.CredentialsTypeCodeAuth + if err = s.deps.LoginFlowPersister().UpdateLoginFlow(ctx, f); err != nil { + return err + } + + if x.IsJSONRequest(r) { + s.deps.Writer().WriteCode(w, r, http.StatusBadRequest, f) + } else { + http.Redirect(w, r, f.AppendTo(s.deps.Config().SelfServiceFlowLoginUI(ctx)).String(), http.StatusSeeOther) + } + + // we return an error to the flow handler so that it does not continue execution of the hooks. + // we are not done with the login flow yet. The user needs to verify the code and then we need to persist the identity. + return errors.WithStack(flow.ErrCompletedByStrategy) +} + +// If identifier is an email, we lower case it because on mobile phones the first letter sometimes is capitalized. +func maybeNormalizeEmail(input string) string { + if strings.Contains(input, "@") { + return strings.ToLower(input) + } + return input +} + +func (s *Strategy) loginVerifyCode(ctx context.Context, r *http.Request, f *login.Flow, p *updateLoginFlowWithCodeMethod) (_ *identity.Identity, err error) { + ctx, span := s.deps.Tracer(ctx).Tracer().Start(ctx, "selfservice.strategy.code.strategy.loginVerifyCode") + defer otelx.End(span, &err) + + // we are in the second submission state of the flow + // we need to check the code and update the identity + if p.Code == "" { + return nil, errors.WithStack(schema.NewRequiredError("#/code", "code")) + } + + if len(p.Identifier) == 0 { + return nil, errors.WithStack(schema.NewRequiredError("#/identifier", "identifier")) + } + + p.Identifier = maybeNormalizeEmail(p.Identifier) + + // Step 1: Get the identity + i, _, err := s.getIdentity(ctx, p.Identifier) + if err != nil { + return nil, err + } + + loginCode, err := s.deps.LoginCodePersister().UseLoginCode(ctx, f.ID, i.ID, p.Code) + if err != nil { + if errors.Is(err, ErrCodeNotFound) { + return nil, schema.NewLoginCodeInvalid() + } + return nil, errors.WithStack(err) + } + + i, err = s.deps.PrivilegedIdentityPool().GetIdentity(ctx, loginCode.IdentityID, identity.ExpandDefault) + if err != nil { + return nil, errors.WithStack(err) + } + + // Step 2: The code was correct + f.Active = identity.CredentialsTypeCodeAuth + + // since nothing has errored yet, we can assume that the code is correct + // and we can update the login flow + f.SetState(flow.NextState(f.GetState())) + + if err := s.deps.LoginFlowPersister().UpdateLoginFlow(ctx, f); err != nil { + return nil, errors.WithStack(err) + } + + for idx := range i.VerifiableAddresses { + va := i.VerifiableAddresses[idx] + if !va.Verified && loginCode.Address == va.Value { + va.Verified = true + va.Status = identity.VerifiableAddressStatusCompleted + if err := s.deps.PrivilegedIdentityPool().UpdateVerifiableAddress(ctx, &va); err != nil { + return nil, err + } + break + } + } + + return i, nil +} diff --git a/selfservice/strategy/code/strategy_login_test.go b/selfservice/strategy/code/strategy_login_test.go new file mode 100644 index 000000000000..a371fdfbf5f6 --- /dev/null +++ b/selfservice/strategy/code/strategy_login_test.go @@ -0,0 +1,456 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package code_test + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "net/url" + "testing" + + "github.com/ory/x/stringsx" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tidwall/gjson" + + "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/session" + "github.com/ory/x/sqlxx" +) + +func TestLoginCodeStrategy(t *testing.T) { + ctx := context.Background() + conf, reg := internal.NewFastRegistryWithMocks(t) + testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/code.identity.schema.json") + conf.MustSet(ctx, fmt.Sprintf("%s.%s.enabled", config.ViperKeySelfServiceStrategyConfig, identity.CredentialsTypeCodeAuth.String()), false) + conf.MustSet(ctx, fmt.Sprintf("%s.%s.passwordless_enabled", config.ViperKeySelfServiceStrategyConfig, identity.CredentialsTypeCodeAuth.String()), true) + conf.MustSet(ctx, config.ViperKeySelfServiceBrowserDefaultReturnTo, "https://www.ory.sh") + conf.MustSet(ctx, config.ViperKeyURLsAllowedReturnToDomains, []string{"https://www.ory.sh"}) + + _ = testhelpers.NewLoginUIFlowEchoServer(t, reg) + _ = testhelpers.NewErrorTestServer(t, reg) + + public, _, _, _ := testhelpers.NewKratosServerWithCSRFAndRouters(t, reg) + + createIdentity := func(ctx context.Context, t *testing.T, moreIdentifiers ...string) *identity.Identity { + t.Helper() + i := identity.NewIdentity(config.DefaultIdentityTraitsSchemaID) + email := testhelpers.RandomEmail() + + ids := fmt.Sprintf(`"email":"%s"`, email) + for i, identifier := range moreIdentifiers { + ids = fmt.Sprintf(`%s,"email_%d":"%s"`, ids, i+1, identifier) + } + + i.Traits = identity.Traits(fmt.Sprintf(`{%s}`, ids)) + + credentials := map[identity.CredentialsType]identity.Credentials{ + identity.CredentialsTypePassword: {Identifiers: append([]string{email}, moreIdentifiers...), Type: identity.CredentialsTypePassword, Config: sqlxx.JSONRawMessage("{\"some\" : \"secret\"}")}, + identity.CredentialsTypeOIDC: {Type: identity.CredentialsTypeOIDC, Identifiers: append([]string{email}, moreIdentifiers...), Config: sqlxx.JSONRawMessage("{\"some\" : \"secret\"}")}, + identity.CredentialsTypeWebAuthn: {Type: identity.CredentialsTypeWebAuthn, Identifiers: append([]string{email}, moreIdentifiers...), Config: sqlxx.JSONRawMessage("{\"some\" : \"secret\", \"user_handle\": \"rVIFaWRcTTuQLkXFmQWpgA==\"}")}, + identity.CredentialsTypeCodeAuth: {Type: identity.CredentialsTypeCodeAuth, Identifiers: append([]string{email}, moreIdentifiers...), Config: sqlxx.JSONRawMessage("{\"address_type\": \"email\", \"used_at\": \"2023-07-26T16:59:06+02:00\"}")}, + } + i.Credentials = credentials + + var va []identity.VerifiableAddress + for _, identifier := range moreIdentifiers { + va = append(va, identity.VerifiableAddress{Value: identifier, Verified: false, Status: identity.VerifiableAddressStatusCompleted}) + } + + va = append(va, identity.VerifiableAddress{Value: email, Verified: true, Status: identity.VerifiableAddressStatusCompleted}) + + i.VerifiableAddresses = va + + require.NoError(t, reg.PrivilegedIdentityPool().CreateIdentity(ctx, i)) + return i + } + + type state struct { + flowID string + identity *identity.Identity + client *http.Client + loginCode string + identityEmail string + testServer *httptest.Server + } + + createLoginFlow := func(ctx context.Context, t *testing.T, public *httptest.Server, isSPA bool, moreIdentifiers ...string) *state { + t.Helper() + + identity := createIdentity(ctx, t, moreIdentifiers...) + + client := testhelpers.NewClientWithCookies(t) + client.Transport = testhelpers.NewTransportWithLogger(http.DefaultTransport, t).RoundTripper + clientInit := testhelpers.InitializeLoginFlowViaBrowser(t, client, public, false, isSPA, false, false) + + body, err := json.Marshal(clientInit) + require.NoError(t, err) + + csrfToken := gjson.GetBytes(body, "ui.nodes.#(attributes.name==csrf_token).attributes.value").String() + require.NotEmpty(t, csrfToken) + + loginEmail := gjson.Get(identity.Traits.String(), "email").String() + require.NotEmpty(t, loginEmail) + + return &state{ + flowID: clientInit.GetId(), + identity: identity, + identityEmail: loginEmail, + client: client, + testServer: public, + } + } + + type onSubmitAssertion func(t *testing.T, s *state, body string, res *http.Response) + + submitLogin := func(ctx context.Context, t *testing.T, s *state, isSPA bool, vals func(v *url.Values), mustHaveSession bool, submitAssertion onSubmitAssertion) *state { + t.Helper() + + lf, resp, err := testhelpers.NewSDKCustomClient(s.testServer, s.client).FrontendApi.GetLoginFlow(ctx).Id(s.flowID).Execute() + require.NoError(t, err) + require.EqualValues(t, http.StatusOK, resp.StatusCode) + + values := testhelpers.SDKFormFieldsToURLValues(lf.Ui.Nodes) + // we need to remove resend here + // since it is not required for the first request + // subsequent requests might need it later + values.Del("resend") + values.Set("method", "code") + vals(&values) + + body, resp := testhelpers.LoginMakeRequest(t, false, isSPA, lf, s.client, testhelpers.EncodeFormAsJSON(t, false, values)) + + if submitAssertion != nil { + submitAssertion(t, s, body, resp) + return s + } + + if mustHaveSession { + resp, err = s.client.Get(s.testServer.URL + session.RouteWhoami) + require.NoError(t, err) + require.EqualValues(t, http.StatusOK, resp.StatusCode) + } else { + // SPAs need to be informed that the login has not yet completed using status 400. + // Browser clients will redirect back to the login URL. + if isSPA { + require.EqualValues(t, http.StatusBadRequest, resp.StatusCode) + } else { + require.EqualValues(t, http.StatusOK, resp.StatusCode) + } + } + + return s + } + + for _, tc := range []struct { + d string + isSPA bool + }{ + { + d: "SPA client", + isSPA: true, + }, + { + d: "Browser client", + isSPA: false, + }, + } { + t.Run("test="+tc.d, func(t *testing.T) { + t.Run("case=email identifier should be case insensitive", func(t *testing.T) { + // create login flow + s := createLoginFlow(ctx, t, public, tc.isSPA) + + // submit email + s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + v.Set("identifier", stringsx.ToUpperInitial(s.identityEmail)) + }, false, nil) + + message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Login to your account") + assert.Contains(t, message.Body, "please login to your account by entering the following code") + + loginCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) + assert.NotEmpty(t, loginCode) + + // 3. Submit OTP + submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + v.Set("code", loginCode) + }, true, nil) + }) + + t.Run("case=should be able to log in with code", func(t *testing.T) { + // create login flow + s := createLoginFlow(ctx, t, public, tc.isSPA) + + // submit email + s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + v.Set("identifier", s.identityEmail) + }, false, nil) + + message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Login to your account") + assert.Contains(t, message.Body, "please login to your account by entering the following code") + + loginCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) + assert.NotEmpty(t, loginCode) + + // 3. Submit OTP + submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + v.Set("code", loginCode) + }, true, nil) + }) + + t.Run("case=should not be able to change submitted id on code submit", func(t *testing.T) { + // create login flow + s := createLoginFlow(ctx, t, public, tc.isSPA) + + // submit email + s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + v.Set("identifier", s.identityEmail) + }, false, nil) + + message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Login to your account") + assert.Contains(t, message.Body, "please login to your account by entering the following code") + + loginCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) + assert.NotEmpty(t, loginCode) + + // 3. Submit OTP + s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + v.Set("identifier", "not-"+s.identityEmail) + v.Set("code", loginCode) + }, false, func(t *testing.T, s *state, body string, resp *http.Response) { + if tc.isSPA { + require.EqualValues(t, http.StatusBadRequest, resp.StatusCode) + assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "account does not exist or has not setup sign in with code") + } else { + require.EqualValues(t, http.StatusOK, resp.StatusCode) + require.EqualValues(t, conf.SelfServiceFlowLoginUI(ctx).Path, resp.Request.URL.Path) + + lf, resp, err := testhelpers.NewSDKCustomClient(public, s.client).FrontendApi.GetLoginFlow(ctx).Id(s.flowID).Execute() + require.NoError(t, err) + require.EqualValues(t, http.StatusOK, resp.StatusCode) + body, err := json.Marshal(lf) + require.NoError(t, err) + assert.Contains(t, gjson.GetBytes(body, "ui.messages.0.text").String(), "account does not exist or has not setup sign in with code") + } + }) + }) + + t.Run("case=should not be able to proceed to code entry when the account is unknown", func(t *testing.T) { + s := createLoginFlow(ctx, t, public, tc.isSPA) + + // submit email + s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + v.Set("identifier", testhelpers.RandomEmail()) + }, false, func(t *testing.T, s *state, body string, resp *http.Response) { + if tc.isSPA { + require.EqualValues(t, http.StatusBadRequest, resp.StatusCode) + assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "account does not exist or has not setup sign in with code") + } else { + require.EqualValues(t, http.StatusOK, resp.StatusCode) + require.EqualValues(t, conf.SelfServiceFlowLoginUI(ctx).Path, resp.Request.URL.Path) + + lf, resp, err := testhelpers.NewSDKCustomClient(public, s.client).FrontendApi.GetLoginFlow(ctx).Id(s.flowID).Execute() + require.NoError(t, err) + require.EqualValues(t, http.StatusOK, resp.StatusCode) + body, err := json.Marshal(lf) + require.NoError(t, err) + assert.Contains(t, gjson.GetBytes(body, "ui.messages.0.text").String(), "account does not exist or has not setup sign in with code") + } + }) + }) + + t.Run("case=should not be able to use valid code after 5 attempts", func(t *testing.T) { + s := createLoginFlow(ctx, t, public, tc.isSPA) + + // submit email + s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + v.Set("identifier", s.identityEmail) + }, false, nil) + + message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Login to your account") + assert.Contains(t, message.Body, "please login to your account by entering the following code") + loginCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) + assert.NotEmpty(t, loginCode) + + for i := 0; i < 5; i++ { + // 3. Submit OTP + s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + v.Set("code", "111111") + v.Set("identifier", s.identityEmail) + }, false, func(t *testing.T, s *state, body string, resp *http.Response) { + if tc.isSPA { + require.EqualValues(t, http.StatusBadRequest, resp.StatusCode) + } else { + // in browser flows we redirect back to the login ui + require.Equal(t, http.StatusOK, resp.StatusCode, "%s", body) + } + assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "The login code is invalid or has already been used") + }) + } + + // 3. Submit OTP + s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + v.Set("code", loginCode) + v.Set("identifier", s.identityEmail) + }, false, func(t *testing.T, s *state, body string, resp *http.Response) { + if tc.isSPA { + require.EqualValues(t, http.StatusBadRequest, resp.StatusCode) + } else { + // in browser flows we redirect back to the login ui + require.Equal(t, http.StatusOK, resp.StatusCode, "%s", body) + } + assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "The request was submitted too often.") + }) + }) + + t.Run("case=code should expire", func(t *testing.T) { + ctx := context.Background() + + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.config.lifespan", "1ns") + + t.Cleanup(func() { + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.config.lifespan", "1h") + }) + + s := createLoginFlow(ctx, t, public, tc.isSPA) + + // submit email + s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + v.Set("identifier", s.identityEmail) + }, false, nil) + + message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Login to your account") + assert.Contains(t, message.Body, "please login to your account by entering the following code") + loginCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) + assert.NotEmpty(t, loginCode) + + submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + v.Set("code", loginCode) + v.Set("identifier", s.identityEmail) + }, false, func(t *testing.T, s *state, body string, resp *http.Response) { + if tc.isSPA { + require.EqualValues(t, http.StatusGone, resp.StatusCode) + require.Contains(t, gjson.Get(body, "error.reason").String(), "self-service flow expired 0.00 minutes ago") + } else { + // with browser clients we redirect back to the UI with a new flow id as a query parameter + require.Equal(t, http.StatusOK, resp.StatusCode) + require.Equal(t, conf.SelfServiceFlowLoginUI(ctx).Path, resp.Request.URL.Path) + lf, _, err := testhelpers.NewSDKCustomClient(public, s.client).FrontendApi.GetLoginFlow(ctx).Id(resp.Request.URL.Query().Get("flow")).Execute() + require.NoError(t, err) + require.EqualValues(t, http.StatusOK, resp.StatusCode) + + body, err := json.Marshal(lf) + require.NoError(t, err) + assert.Contains(t, gjson.GetBytes(body, "ui.messages.0.text").String(), "flow expired 0.00 minutes ago") + } + }) + }) + + t.Run("case=resend code should invalidate previous code", func(t *testing.T) { + ctx := context.Background() + + s := createLoginFlow(ctx, t, public, tc.isSPA) + + s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + v.Set("identifier", s.identityEmail) + }, false, nil) + + message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Login to your account") + assert.Contains(t, message.Body, "please login to your account by entering the following code") + loginCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) + assert.NotEmpty(t, loginCode) + + // resend code + s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + v.Set("resend", "code") + v.Set("identifier", s.identityEmail) + }, false, nil) + + message = testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Login to your account") + assert.Contains(t, message.Body, "please login to your account by entering the following code") + loginCode2 := testhelpers.CourierExpectCodeInMessage(t, message, 1) + assert.NotEmpty(t, loginCode2) + + assert.NotEqual(t, loginCode, loginCode2) + s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + v.Set("code", loginCode) + v.Set("identifier", s.identityEmail) + }, false, func(t *testing.T, s *state, body string, res *http.Response) { + if tc.isSPA { + require.EqualValues(t, http.StatusBadRequest, res.StatusCode) + } else { + require.EqualValues(t, http.StatusOK, res.StatusCode) + } + require.Contains(t, gjson.Get(body, "ui.messages").String(), "The login code is invalid or has already been used. Please try again") + }) + + s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + v.Set("code", loginCode2) + v.Set("identifier", s.identityEmail) + }, true, nil) + }) + + t.Run("case=on login with un-verified address, should verify it", func(t *testing.T) { + s := createLoginFlow(ctx, t, public, tc.isSPA, testhelpers.RandomEmail()) + + // we need to fetch only the first email + loginEmail := gjson.Get(s.identity.Traits.String(), "email_1").String() + require.NotEmpty(t, loginEmail) + + s.identityEmail = loginEmail + + var va *identity.VerifiableAddress + + for _, v := range s.identity.VerifiableAddresses { + if v.Value == loginEmail { + va = &v + break + } + } + + require.NotNil(t, va) + require.False(t, va.Verified) + + // submit email + s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + v.Set("identifier", s.identityEmail) + }, false, nil) + + message := testhelpers.CourierExpectMessage(ctx, t, reg, loginEmail, "Login to your account") + require.Contains(t, message.Body, "please login to your account by entering the following code") + + loginCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) + require.NotEmpty(t, loginCode) + + // Submit OTP + s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + v.Set("code", loginCode) + v.Set("identifier", s.identityEmail) + }, true, nil) + + id, err := reg.PrivilegedIdentityPool().GetIdentity(ctx, s.identity.ID, identity.ExpandEverything) + require.NoError(t, err) + + va = nil + + for _, v := range id.VerifiableAddresses { + if v.Value == loginEmail { + va = &v + break + } + } + + require.NotNil(t, va) + require.True(t, va.Verified) + }) + }) + } +} diff --git a/selfservice/strategy/code/strategy_recovery.go b/selfservice/strategy/code/strategy_recovery.go index d06c5e2c9009..e4b6fae22c55 100644 --- a/selfservice/strategy/code/strategy_recovery.go +++ b/selfservice/strategy/code/strategy_recovery.go @@ -177,23 +177,23 @@ func (s *Strategy) createRecoveryCodeForIdentity(w http.ResponseWriter, r *http. return } - flow, err := recovery.NewFlow(config, expiresIn, s.deps.GenerateCSRFToken(r), r, s, flow.TypeBrowser) + recoveryFlow, err := recovery.NewFlow(config, expiresIn, s.deps.GenerateCSRFToken(r), r, s, flow.TypeBrowser) if err != nil { s.deps.Writer().WriteError(w, r, err) return } - flow.DangerousSkipCSRFCheck = true - flow.State = recovery.StateEmailSent - flow.UI.Nodes = node.Nodes{} - flow.UI.Nodes.Append(node.NewInputField("code", nil, node.CodeGroup, node.InputAttributeTypeText, node.WithRequiredInputAttribute). + recoveryFlow.DangerousSkipCSRFCheck = true + recoveryFlow.State = flow.StateEmailSent + recoveryFlow.UI.Nodes = node.Nodes{} + recoveryFlow.UI.Nodes.Append(node.NewInputField("code", nil, node.CodeGroup, node.InputAttributeTypeText, node.WithRequiredInputAttribute). WithMetaLabel(text.NewInfoNodeLabelRecoveryCode()), ) - flow.UI.Nodes. + recoveryFlow.UI.Nodes. Append(node.NewInputField("method", s.RecoveryStrategyID(), node.CodeGroup, node.InputAttributeTypeSubmit). WithMetaLabel(text.NewInfoNodeLabelSubmit())) - if err := s.deps.RecoveryFlowPersister().CreateRecoveryFlow(ctx, flow); err != nil { + if err := s.deps.RecoveryFlowPersister().CreateRecoveryFlow(ctx, recoveryFlow); err != nil { s.deps.Writer().WriteError(w, r, err) return } @@ -213,7 +213,7 @@ func (s *Strategy) createRecoveryCodeForIdentity(w http.ResponseWriter, r *http. RawCode: rawCode, CodeType: RecoveryCodeTypeAdmin, ExpiresIn: expiresIn, - FlowID: flow.ID, + FlowID: recoveryFlow.ID, IdentityID: id.ID, }); err != nil { s.deps.Writer().WriteError(w, r, err) @@ -226,11 +226,11 @@ func (s *Strategy) createRecoveryCodeForIdentity(w http.ResponseWriter, r *http. Info("A recovery code has been created.") body := &recoveryCodeForIdentity{ - ExpiresAt: flow.ExpiresAt.UTC(), + ExpiresAt: recoveryFlow.ExpiresAt.UTC(), RecoveryLink: urlx.CopyWithQuery( s.deps.Config().SelfServiceFlowRecoveryUI(ctx), url.Values{ - "flow": {flow.ID.String()}, + "flow": {recoveryFlow.ID.String()}, }).String(), RecoveryCode: rawCode, } @@ -281,7 +281,7 @@ func (s Strategy) isCodeFlow(f *recovery.Flow) bool { if err != nil { return false } - return value == s.RecoveryNodeGroup().String() + return value == s.NodeGroup().String() } func (s *Strategy) Recover(w http.ResponseWriter, r *http.Request, f *recovery.Flow) (err error) { @@ -310,8 +310,8 @@ func (s *Strategy) Recover(w http.ResponseWriter, r *http.Request, f *recovery.F f.UI.ResetMessages() // If the email is present in the submission body, the user needs a new code via resend - if f.State != recovery.StateChooseMethod && len(body.Email) == 0 { - if err := flow.MethodEnabledAndAllowed(ctx, sID, sID, s.deps); err != nil { + if f.State != flow.StateChooseMethod && len(body.Email) == 0 { + if err := flow.MethodEnabledAndAllowed(ctx, flow.RecoveryFlow, sID, sID, s.deps); err != nil { return s.HandleRecoveryError(w, r, nil, body, err) } return s.recoveryUseCode(w, r, body, f) @@ -327,29 +327,29 @@ func (s *Strategy) Recover(w http.ResponseWriter, r *http.Request, f *recovery.F return errors.WithStack(flow.ErrCompletedByStrategy) } - if err := flow.MethodEnabledAndAllowed(ctx, sID, body.Method, s.deps); err != nil { + if err := flow.MethodEnabledAndAllowed(ctx, flow.RecoveryFlow, sID, body.Method, s.deps); err != nil { return s.HandleRecoveryError(w, r, nil, body, err) } - flow, err := s.deps.RecoveryFlowPersister().GetRecoveryFlow(ctx, x.ParseUUID(body.Flow)) + recoveryFlow, err := s.deps.RecoveryFlowPersister().GetRecoveryFlow(ctx, x.ParseUUID(body.Flow)) if err != nil { - return s.HandleRecoveryError(w, r, flow, body, err) + return s.HandleRecoveryError(w, r, recoveryFlow, body, err) } - if err := flow.Valid(); err != nil { - return s.HandleRecoveryError(w, r, flow, body, err) + if err := recoveryFlow.Valid(); err != nil { + return s.HandleRecoveryError(w, r, recoveryFlow, body, err) } - switch flow.State { - case recovery.StateChooseMethod: + switch recoveryFlow.State { + case flow.StateChooseMethod: fallthrough - case recovery.StateEmailSent: - return s.recoveryHandleFormSubmission(w, r, flow, body) - case recovery.StatePassedChallenge: + case flow.StateEmailSent: + return s.recoveryHandleFormSubmission(w, r, recoveryFlow, body) + case flow.StatePassedChallenge: // was already handled, do not allow retry - return s.retryRecoveryFlowWithMessage(w, r, flow.Type, text.NewErrorValidationRecoveryRetrySuccess()) + return s.retryRecoveryFlowWithMessage(w, r, recoveryFlow.Type, text.NewErrorValidationRecoveryRetrySuccess()) default: - return s.retryRecoveryFlowWithMessage(w, r, flow.Type, text.NewErrorValidationRecoveryStateFailure()) + return s.retryRecoveryFlowWithMessage(w, r, recoveryFlow.Type, text.NewErrorValidationRecoveryStateFailure()) } } @@ -357,7 +357,7 @@ func (s *Strategy) recoveryIssueSession(w http.ResponseWriter, r *http.Request, ctx := r.Context() f.UI.Messages.Clear() - f.State = recovery.StatePassedChallenge + f.State = flow.StatePassedChallenge f.SetCSRFToken(s.deps.CSRFHandler().RegenerateToken(w, r)) f.RecoveredIdentityID = uuid.NullUUID{ UUID: id.ID, @@ -539,13 +539,13 @@ func (s *Strategy) recoveryHandleFormSubmission(w http.ResponseWriter, r *http.R f.UI.SetCSRF(s.deps.GenerateCSRFToken(r)) - f.Active = sqlxx.NullString(s.RecoveryNodeGroup()) - f.State = recovery.StateEmailSent + f.Active = sqlxx.NullString(s.NodeGroup()) + f.State = flow.StateEmailSent f.UI.Messages.Set(text.NewRecoveryEmailWithCodeSent()) f.UI.Nodes.Append(node.NewInputField("code", nil, node.CodeGroup, node.InputAttributeTypeText, node.WithRequiredInputAttribute). WithMetaLabel(text.NewInfoNodeLabelRecoveryCode()), ) - f.UI.Nodes.Append(node.NewInputField("method", s.RecoveryNodeGroup(), node.CodeGroup, node.InputAttributeTypeHidden)) + f.UI.Nodes.Append(node.NewInputField("method", s.NodeGroup(), node.CodeGroup, node.InputAttributeTypeHidden)) f.UI. GetNodes(). diff --git a/selfservice/strategy/code/strategy_recovery_test.go b/selfservice/strategy/code/strategy_recovery_test.go index 2adbf97213d4..10d5ae6f5135 100644 --- a/selfservice/strategy/code/strategy_recovery_test.go +++ b/selfservice/strategy/code/strategy_recovery_test.go @@ -412,7 +412,7 @@ func TestRecovery(t *testing.T) { assert.Len(t, gjson.Get(recoverySubmissionResponse, "ui.messages").Array(), 1, "%s", recoverySubmissionResponse) assertx.EqualAsJSON(t, text.NewRecoveryEmailWithCodeSent(), json.RawMessage(gjson.Get(recoverySubmissionResponse, "ui.messages.0").Raw)) - message := testhelpers.CourierExpectMessage(t, reg, recoveryEmail, "Recover access to your account") + message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account") assert.Contains(t, message.Body, "please recover access to your account by entering the following code") recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) @@ -697,7 +697,7 @@ func TestRecovery(t *testing.T) { assert.Empty(t, gjson.Get(body, "ui.nodes.#(attributes.name==code).attributes.value").String(), "%s", body) assertx.EqualAsJSON(t, text.NewRecoveryEmailWithCodeSent(), json.RawMessage(gjson.Get(body, "ui.messages.0").Raw)) - message := testhelpers.CourierExpectMessage(t, reg, email, "Account access attempted") + message := testhelpers.CourierExpectMessage(ctx, t, reg, email, "Account access attempted") assert.Contains(t, message.Body, "If this was you, check if you signed up using a different address.") } @@ -734,7 +734,7 @@ func TestRecovery(t *testing.T) { addr, err := reg.IdentityPool().FindVerifiableAddressByValue(context.Background(), identity.VerifiableAddressTypeEmail, email) assert.NoError(t, err) - emailText := testhelpers.CourierExpectMessage(t, reg, email, "Recover access to your account") + emailText := testhelpers.CourierExpectMessage(ctx, t, reg, email, "Recover access to your account") recoveryCode := testhelpers.CourierExpectCodeInMessage(t, emailText, 1) // Deactivate the identity @@ -773,7 +773,7 @@ func TestRecovery(t *testing.T) { actual := expectSuccessfulRecovery(t, cl, RecoveryFlowTypeBrowser, func(v url.Values) { v.Set("email", email) }) - message := testhelpers.CourierExpectMessage(t, reg, email, "Recover access to your account") + message := testhelpers.CourierExpectMessage(ctx, t, reg, email, "Recover access to your account") recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) cl.CheckRedirect = func(req *http.Request, via []*http.Request) error { @@ -834,7 +834,7 @@ func TestRecovery(t *testing.T) { v.Set("email", recoveryEmail) }, http.StatusOK) - message := testhelpers.CourierExpectMessage(t, reg, recoveryEmail, "Recover access to your account") + message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account") recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) form := withCSRFToken(t, testCase.FlowType, actual, url.Values{ @@ -945,7 +945,7 @@ func TestRecovery(t *testing.T) { initialFlowId := gjson.Get(body, "id") - message := testhelpers.CourierExpectMessage(t, reg, recoveryEmail, "Recover access to your account") + message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account") assert.Contains(t, message.Body, "please recover access to your account by entering the following code") recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) @@ -1000,7 +1000,7 @@ func TestRecovery(t *testing.T) { assert.True(t, gjson.Get(body, "ui.nodes.#(attributes.name==code)").Exists()) assert.Equal(t, recoveryEmail, gjson.Get(body, "ui.nodes.#(attributes.name==email).attributes.value").String()) - message := testhelpers.CourierExpectMessage(t, reg, recoveryEmail, "Recover access to your account") + message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account") recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) submitRecoveryCode(t, c, body, RecoveryFlowTypeBrowser, recoveryCode, http.StatusOK) @@ -1019,14 +1019,14 @@ func TestRecovery(t *testing.T) { require.NotEmpty(t, action) assert.Equal(t, recoveryEmail, gjson.Get(body, "ui.nodes.#(attributes.name==email).attributes.value").String()) - message1 := testhelpers.CourierExpectMessage(t, reg, recoveryEmail, "Recover access to your account") + message1 := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account") recoveryCode1 := testhelpers.CourierExpectCodeInMessage(t, message1, 1) body = resendRecoveryCode(t, c, body, RecoveryFlowTypeBrowser, http.StatusOK) assert.True(t, gjson.Get(body, "ui.nodes.#(attributes.name==code)").Exists()) assert.Equal(t, recoveryEmail, gjson.Get(body, "ui.nodes.#(attributes.name==email).attributes.value").String()) - message2 := testhelpers.CourierExpectMessage(t, reg, recoveryEmail, "Recover access to your account") + message2 := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account") recoveryCode2 := testhelpers.CourierExpectCodeInMessage(t, message2, 1) body = submitRecoveryCode(t, c, body, RecoveryFlowTypeBrowser, recoveryCode1, http.StatusOK) @@ -1070,7 +1070,7 @@ func TestRecovery(t *testing.T) { v.Set("email", recoveryEmail) }) - message := testhelpers.CourierExpectMessage(t, reg, recoveryEmail, "Recover access to your account") + message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account") recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) action := gjson.Get(body, "ui.action").String() @@ -1102,7 +1102,7 @@ func TestRecovery(t *testing.T) { v.Set("email", recoveryEmail) }) - message := testhelpers.CourierExpectMessage(t, reg, recoveryEmail, "Recover access to your account") + message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account") recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) action := gjson.Get(body, "ui.action").String() diff --git a/selfservice/strategy/code/strategy_registration.go b/selfservice/strategy/code/strategy_registration.go new file mode 100644 index 000000000000..f4c97641f055 --- /dev/null +++ b/selfservice/strategy/code/strategy_registration.go @@ -0,0 +1,284 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package code + +import ( + "context" + "database/sql" + "encoding/json" + "net/http" + "strings" + + "github.com/ory/herodot" + "github.com/ory/x/otelx" + + "github.com/pkg/errors" + + "github.com/ory/kratos/identity" + "github.com/ory/kratos/schema" + "github.com/ory/kratos/selfservice/flow" + "github.com/ory/kratos/selfservice/flow/registration" + "github.com/ory/kratos/ui/container" + "github.com/ory/kratos/ui/node" + "github.com/ory/kratos/x" + "github.com/ory/x/urlx" +) + +var _ registration.Strategy = new(Strategy) + +// Update Registration Flow with Code Method +// +// swagger:model updateRegistrationFlowWithCodeMethod +type updateRegistrationFlowWithCodeMethod struct { + // The identity's traits + // + // required: true + Traits json.RawMessage `json:"traits" form:"traits"` + + // The OTP Code sent to the user + // + // required: false + Code string `json:"code" form:"code"` + + // The CSRF Token + CSRFToken string `json:"csrf_token" form:"csrf_token"` + + // Method to use + // + // This field must be set to `code` when using the code method. + // + // required: true + Method string `json:"method" form:"method"` + + // Transient data to pass along to any webhooks + // + // required: false + TransientPayload json.RawMessage `json:"transient_payload,omitempty" form:"transient_payload"` + + // Resend restarts the flow with a new code + // + // required: false + Resend string `json:"resend" form:"resend"` +} + +func (p *updateRegistrationFlowWithCodeMethod) GetResend() string { + return p.Resend +} + +func (s *Strategy) RegisterRegistrationRoutes(*x.RouterPublic) {} + +func (s *Strategy) HandleRegistrationError(ctx context.Context, r *http.Request, f *registration.Flow, body *updateRegistrationFlowWithCodeMethod, err error) error { + if errors.Is(err, flow.ErrCompletedByStrategy) { + return err + } + + if f != nil { + if body != nil { + action := f.AppendTo(urlx.AppendPaths(s.deps.Config().SelfPublicURL(ctx), registration.RouteSubmitFlow)).String() + for _, n := range container.NewFromJSON(action, node.CodeGroup, body.Traits, "traits").Nodes { + // we only set the value and not the whole field because we want to keep types from the initial form generation + f.UI.Nodes.SetValueAttribute(n.ID(), n.Attributes.GetValue()) + } + } + + f.UI.SetCSRF(s.deps.GenerateCSRFToken(r)) + } + + return err +} + +func (s *Strategy) PopulateRegistrationMethod(r *http.Request, rf *registration.Flow) error { + return s.PopulateMethod(r, rf) +} + +type options func(*identity.Identity) error + +func WithCredentials(via identity.CodeAddressType, usedAt sql.NullTime) options { + return func(i *identity.Identity) error { + return i.SetCredentialsWithConfig(identity.CredentialsTypeCodeAuth, identity.Credentials{Type: identity.CredentialsTypePassword, Identifiers: []string{}}, &identity.CredentialsCode{AddressType: via, UsedAt: usedAt}) + } +} + +func (s *Strategy) handleIdentityTraits(ctx context.Context, f *registration.Flow, traits json.RawMessage, transientPayload json.RawMessage, i *identity.Identity, opts ...options) error { + f.TransientPayload = transientPayload + if len(traits) == 0 { + traits = json.RawMessage("{}") + } + + // we explicitly set the Code credentials type + i.Traits = identity.Traits(traits) + if err := i.SetCredentialsWithConfig(s.ID(), identity.Credentials{Type: s.ID(), Identifiers: []string{}}, &identity.CredentialsCode{UsedAt: sql.NullTime{}}); err != nil { + return err + } + + for _, opt := range opts { + if err := opt(i); err != nil { + return err + } + } + + // Validate the identity + if err := s.deps.IdentityValidator().Validate(ctx, i); err != nil { + return err + } + + return nil +} + +func (s *Strategy) getCredentialsFromTraits(ctx context.Context, f *registration.Flow, i *identity.Identity, traits, transientPayload json.RawMessage) (*identity.Credentials, error) { + if err := s.handleIdentityTraits(ctx, f, traits, transientPayload, i); err != nil { + return nil, errors.WithStack(err) + } + + cred, ok := i.GetCredentials(identity.CredentialsTypeCodeAuth) + if !ok { + return nil, errors.WithStack(schema.NewMissingIdentifierError()) + } else if len(cred.Identifiers) == 0 { + return nil, errors.WithStack(schema.NewMissingIdentifierError()) + } + return cred, nil +} + +func (s *Strategy) Register(w http.ResponseWriter, r *http.Request, f *registration.Flow, i *identity.Identity) (err error) { + ctx, span := s.deps.Tracer(r.Context()).Tracer().Start(r.Context(), "selfservice.strategy.code.strategy.Register") + defer otelx.End(span, &err) + + if err := flow.MethodEnabledAndAllowedFromRequest(r, f.GetFlowName(), s.ID().String(), s.deps); err != nil { + return err + } + + var p updateRegistrationFlowWithCodeMethod + if err := registration.DecodeBody(&p, r, s.dx, s.deps.Config(), registrationSchema); err != nil { + return s.HandleRegistrationError(ctx, r, f, &p, err) + } + + if err := flow.EnsureCSRF(s.deps, r, f.Type, s.deps.Config().DisableAPIFlowEnforcement(ctx), s.deps.GenerateCSRFToken, p.CSRFToken); err != nil { + return s.HandleRegistrationError(ctx, r, f, &p, err) + } + + // By Default the flow should be in the 'choose method' state. + SetDefaultFlowState(f, p.Resend) + + switch f.GetState() { + case flow.StateChooseMethod: + return s.HandleRegistrationError(ctx, r, f, &p, s.registrationSendEmail(ctx, w, r, f, &p, i)) + case flow.StateEmailSent: + return s.HandleRegistrationError(ctx, r, f, &p, s.registrationVerifyCode(ctx, f, &p, i)) + case flow.StatePassedChallenge: + return s.HandleRegistrationError(ctx, r, f, &p, errors.WithStack(schema.NewNoRegistrationStrategyResponsible())) + } + + return s.HandleRegistrationError(ctx, r, f, &p, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Unexpected flow state: %s", f.GetState()))) +} + +func (s *Strategy) registrationSendEmail(ctx context.Context, w http.ResponseWriter, r *http.Request, f *registration.Flow, p *updateRegistrationFlowWithCodeMethod, i *identity.Identity) (err error) { + ctx, span := s.deps.Tracer(ctx).Tracer().Start(ctx, "selfservice.strategy.code.strategy.registrationSendEmail") + defer otelx.End(span, &err) + + if len(p.Traits) == 0 { + return errors.WithStack(schema.NewRequiredError("#/traits", "traits")) + } + + // Create the Registration code + + // Step 1: validate the identity's traits + cred, err := s.getCredentialsFromTraits(ctx, f, i, p.Traits, p.TransientPayload) + if err != nil { + return err + } + + // Step 2: Delete any previous registration codes for this flow ID + if err := s.deps.RegistrationCodePersister().DeleteRegistrationCodesOfFlow(ctx, f.ID); err != nil { + return errors.WithStack(err) + } + + // Step 3: Get the identity email and send the code + var addresses []Address + for _, identifier := range cred.Identifiers { + addresses = append(addresses, Address{To: identifier, Via: identity.AddressTypeEmail}) + } + // kratos only supports `email` identifiers at the moment with the code method + // this is validated in the identity validation step above + if err := s.deps.CodeSender().SendCode(ctx, f, i, addresses...); err != nil { + return errors.WithStack(err) + } + + // sets the flow state to code sent + f.SetState(flow.NextState(f.GetState())) + + // Step 4: Generate the UI for the `code` input form + // re-initialize the UI with a "clean" new state + // this should also provide a "resend" button and an option to change the email address + if err := s.NewCodeUINodes(r, f, p.Traits); err != nil { + return errors.WithStack(err) + } + + f.Active = identity.CredentialsTypeCodeAuth + if err := s.deps.RegistrationFlowPersister().UpdateRegistrationFlow(ctx, f); err != nil { + return errors.WithStack(err) + } + + if x.IsJSONRequest(r) { + s.deps.Writer().WriteCode(w, r, http.StatusBadRequest, f) + } else { + http.Redirect(w, r, f.AppendTo(s.deps.Config().SelfServiceFlowRegistrationUI(ctx)).String(), http.StatusSeeOther) + } + + // we return an error to the flow handler so that it does not continue execution of the hooks. + // we are not done with the registration flow yet. The user needs to verify the code and then we need to persist the identity. + return errors.WithStack(flow.ErrCompletedByStrategy) + +} + +func (s *Strategy) registrationVerifyCode(ctx context.Context, f *registration.Flow, p *updateRegistrationFlowWithCodeMethod, i *identity.Identity) (err error) { + ctx, span := s.deps.Tracer(ctx).Tracer().Start(ctx, "selfservice.strategy.code.strategy.registrationVerifyCode") + defer otelx.End(span, &err) + + if len(p.Code) == 0 { + return errors.WithStack(schema.NewRequiredError("#/code", "code")) + } + + if len(p.Traits) == 0 { + return errors.WithStack(schema.NewRequiredError("#/traits", "traits")) + } + + // Step 1: Re-validate the identity's traits + // this is important since the client could have switched out the identity's traits + // this method also returns the credentials for a temporary identity + cred, err := s.getCredentialsFromTraits(ctx, f, i, p.Traits, p.TransientPayload) + if err != nil { + return err + } + + // Step 2: Check if the flow traits match the identity traits + for _, n := range container.NewFromJSON("", node.DefaultGroup, p.Traits, "traits").Nodes { + if !strings.EqualFold(f.GetUI().GetNodes().Find(n.ID()).Attributes.GetValue().(string), n.Attributes.GetValue().(string)) { + return errors.WithStack(schema.NewTraitsMismatch()) + } + } + + // Step 3: Attempt to use the code + registrationCode, err := s.deps.RegistrationCodePersister().UseRegistrationCode(ctx, f.ID, p.Code, cred.Identifiers...) + if err != nil { + if errors.Is(err, ErrCodeNotFound) { + return errors.WithStack(schema.NewRegistrationCodeInvalid()) + } + return errors.WithStack(err) + } + + // Step 4: The code was correct, populate the Identity credentials and traits + if err := s.handleIdentityTraits(ctx, f, p.Traits, p.TransientPayload, i, WithCredentials(registrationCode.AddressType, registrationCode.UsedAt)); err != nil { + return errors.WithStack(err) + } + + // since nothing has errored yet, we can assume that the code is correct + // and we can update the registration flow + f.SetState(flow.NextState(f.GetState())) + + if err := s.deps.RegistrationFlowPersister().UpdateRegistrationFlow(ctx, f); err != nil { + return errors.WithStack(err) + } + + return nil +} diff --git a/selfservice/strategy/code/strategy_registration_test.go b/selfservice/strategy/code/strategy_registration_test.go new file mode 100644 index 000000000000..d787b2b3fa4e --- /dev/null +++ b/selfservice/strategy/code/strategy_registration_test.go @@ -0,0 +1,526 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package code_test + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "net/http/httptest" + "net/url" + "strings" + "testing" + + _ "embed" + + "github.com/gobuffalo/pop/v6" + "github.com/gofrs/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tidwall/gjson" + + "github.com/ory/kratos/driver" + "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/selfservice/flow/registration" + "github.com/ory/kratos/selfservice/strategy/code" +) + +type state struct { + flowID string + client *http.Client + email string + testServer *httptest.Server + resultIdentity *identity.Identity +} + +func TestRegistrationCodeStrategyDisabled(t *testing.T) { + ctx := context.Background() + conf, reg := internal.NewFastRegistryWithMocks(t) + testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/code.identity.schema.json") + conf.MustSet(ctx, fmt.Sprintf("%s.%s.enabled", config.ViperKeySelfServiceStrategyConfig, identity.CredentialsTypePassword.String()), false) + conf.MustSet(ctx, fmt.Sprintf("%s.%s.enabled", config.ViperKeySelfServiceStrategyConfig, identity.CredentialsTypeCodeAuth.String()), false) + conf.MustSet(ctx, fmt.Sprintf("%s.%s.passwordless_enabled", config.ViperKeySelfServiceStrategyConfig, identity.CredentialsTypeCodeAuth), false) + + _ = testhelpers.NewRegistrationUIFlowEchoServer(t, reg) + _ = testhelpers.NewErrorTestServer(t, reg) + + public, _, _, _ := testhelpers.NewKratosServerWithCSRFAndRouters(t, reg) + + client := testhelpers.NewClientWithCookies(t) + resp, err := client.Get(public.URL + registration.RouteInitBrowserFlow) + require.NoError(t, err) + require.EqualValues(t, http.StatusOK, resp.StatusCode) + + body, err := io.ReadAll(resp.Body) + require.NoError(t, err) + require.Falsef(t, gjson.GetBytes(body, "ui.nodes.#(attributes.value==code)").Exists(), "%s", body) + + // attempt to still submit the code form even though it doesn't exist + + payload := strings.NewReader(url.Values{ + "csrf_token": {gjson.GetBytes(body, "ui.nodes.#(attributes.name==csrf_token).attributes.value").String()}, + "method": {"code"}, + "traits.email": {testhelpers.RandomEmail()}, + }.Encode()) + req, err := http.NewRequestWithContext(ctx, "POST", public.URL+registration.RouteSubmitFlow+"?flow="+gjson.GetBytes(body, "id").String(), payload) + require.NoError(t, err) + + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + req.Header.Set("Accept", "application/json") + + resp, err = client.Do(req) + require.NoError(t, err) + require.Equal(t, http.StatusNotFound, resp.StatusCode) + body, err = io.ReadAll(resp.Body) + require.NoError(t, err) + require.Equal(t, "This endpoint was disabled by system administrator. Please check your url or contact the system administrator to enable it.", gjson.GetBytes(body, "error.reason").String()) +} + +func TestRegistrationCodeStrategy(t *testing.T) { + setup := func(ctx context.Context, t *testing.T) (*config.Config, *driver.RegistryDefault, *httptest.Server) { + conf, reg := internal.NewFastRegistryWithMocks(t) + testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/code.identity.schema.json") + conf.MustSet(ctx, fmt.Sprintf("%s.%s.enabled", config.ViperKeySelfServiceStrategyConfig, identity.CredentialsTypePassword.String()), false) + conf.MustSet(ctx, fmt.Sprintf("%s.%s.enabled", config.ViperKeySelfServiceStrategyConfig, identity.CredentialsTypeCodeAuth.String()), false) + conf.MustSet(ctx, fmt.Sprintf("%s.%s.passwordless_enabled", config.ViperKeySelfServiceStrategyConfig, identity.CredentialsTypeCodeAuth), true) + conf.MustSet(ctx, config.ViperKeySelfServiceBrowserDefaultReturnTo, "https://www.ory.sh") + conf.MustSet(ctx, config.ViperKeyURLsAllowedReturnToDomains, []string{"https://www.ory.sh"}) + conf.MustSet(ctx, config.ViperKeySelfServiceRegistrationAfter+".code.hooks", []map[string]interface{}{ + {"hook": "session"}, + }) + + _ = testhelpers.NewRegistrationUIFlowEchoServer(t, reg) + _ = testhelpers.NewErrorTestServer(t, reg) + + public, _, _, _ := testhelpers.NewKratosServerWithCSRFAndRouters(t, reg) + + return conf, reg, public + } + + createRegistrationFlow := func(ctx context.Context, t *testing.T, public *httptest.Server, isSPA bool) *state { + t.Helper() + + client := testhelpers.NewClientWithCookies(t) + client.Transport = testhelpers.NewTransportWithLogger(http.DefaultTransport, t).RoundTripper + clientInit := testhelpers.InitializeRegistrationFlowViaBrowser(t, client, public, isSPA, false, false) + + body, err := json.Marshal(clientInit) + require.NoError(t, err) + + csrfToken := gjson.GetBytes(body, "ui.nodes.#(attributes.name==csrf_token).attributes.value").String() + require.NotEmpty(t, csrfToken) + + require.Truef(t, gjson.GetBytes(body, "ui.nodes.#(attributes.name==traits.email)").Exists(), "%s", body) + require.Truef(t, gjson.GetBytes(body, "ui.nodes.#(attributes.value==code)").Exists(), "%s", body) + + return &state{ + client: client, + flowID: clientInit.GetId(), + testServer: public, + } + } + + type onSubmitAssertion func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) + + registerNewUser := func(ctx context.Context, t *testing.T, s *state, isSPA bool, submitAssertion onSubmitAssertion) *state { + t.Helper() + + if s.email == "" { + s.email = testhelpers.RandomEmail() + } + + rf, resp, err := testhelpers.NewSDKCustomClient(s.testServer, s.client).FrontendApi.GetRegistrationFlow(context.Background()).Id(s.flowID).Execute() + require.NoError(t, err) + require.EqualValues(t, http.StatusOK, resp.StatusCode) + + values := testhelpers.SDKFormFieldsToURLValues(rf.Ui.Nodes) + values.Set("traits.email", s.email) + values.Set("method", "code") + + body, resp := testhelpers.RegistrationMakeRequest(t, false, isSPA, rf, s.client, testhelpers.EncodeFormAsJSON(t, false, values)) + + if submitAssertion != nil { + submitAssertion(ctx, t, s, body, resp) + return s + } + + if isSPA { + require.EqualValues(t, http.StatusBadRequest, resp.StatusCode) + } else { + require.EqualValues(t, http.StatusOK, resp.StatusCode) + } + csrfToken := gjson.Get(body, "ui.nodes.#(attributes.name==csrf_token).attributes.value").String() + assert.NotEmptyf(t, csrfToken, "%s", body) + require.Equal(t, s.email, gjson.Get(body, "ui.nodes.#(attributes.name==traits.email).attributes.value").String()) + + return s + } + + submitOTP := func(ctx context.Context, t *testing.T, reg *driver.RegistryDefault, s *state, vals func(v *url.Values), isSPA bool, submitAssertion onSubmitAssertion) *state { + t.Helper() + + rf, resp, err := testhelpers.NewSDKCustomClient(s.testServer, s.client).FrontendApi.GetRegistrationFlow(context.Background()).Id(s.flowID).Execute() + require.NoError(t, err) + require.EqualValues(t, http.StatusOK, resp.StatusCode) + + values := testhelpers.SDKFormFieldsToURLValues(rf.Ui.Nodes) + // the sdk to values always adds resend which isn't what we always need here. + // so we delete it here. + // the custom vals func can add it again if needed. + values.Del("resend") + values.Set("traits.email", s.email) + vals(&values) + + body, resp := testhelpers.RegistrationMakeRequest(t, false, isSPA, rf, s.client, testhelpers.EncodeFormAsJSON(t, false, values)) + + if submitAssertion != nil { + submitAssertion(ctx, t, s, body, resp) + return s + } + + require.Equal(t, http.StatusOK, resp.StatusCode) + + verifiableAddress, err := reg.PrivilegedIdentityPool().FindVerifiableAddressByValue(ctx, identity.VerifiableAddressTypeEmail, s.email) + require.NoError(t, err) + require.Equal(t, strings.ToLower(s.email), verifiableAddress.Value) + + id, err := reg.PrivilegedIdentityPool().GetIdentityConfidential(ctx, verifiableAddress.IdentityID) + require.NoError(t, err) + require.NotNil(t, id.ID) + + _, ok := id.GetCredentials(identity.CredentialsTypeCodeAuth) + require.True(t, ok) + + s.resultIdentity = id + return s + } + + t.Run("test=different flows on the same configurations", func(t *testing.T) { + t.Parallel() + + ctx := context.Background() + _, reg, public := setup(ctx, t) + + for _, tc := range []struct { + d string + isSPA bool + }{ + { + d: "SPA client", + isSPA: true, + }, + { + d: "Browser client", + isSPA: false, + }, + } { + t.Run("flow="+tc.d, func(t *testing.T) { + t.Run("case=should be able to register with code identity credentials", func(t *testing.T) { + ctx := context.Background() + + // 1. Initiate flow + state := createRegistrationFlow(ctx, t, public, tc.isSPA) + + // 2. Submit Identifier (email) + state = registerNewUser(ctx, t, state, tc.isSPA, nil) + + message := testhelpers.CourierExpectMessage(ctx, t, reg, state.email, "Complete your account registration") + assert.Contains(t, message.Body, "please complete your account registration by entering the following code") + + registrationCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) + assert.NotEmpty(t, registrationCode) + + // 3. Submit OTP + state = submitOTP(ctx, t, reg, state, func(v *url.Values) { + v.Set("code", registrationCode) + }, tc.isSPA, nil) + }) + + t.Run("case=should normalize email address on sign up", func(t *testing.T) { + ctx := context.Background() + + // 1. Initiate flow + state := createRegistrationFlow(ctx, t, public, tc.isSPA) + sourceMail := testhelpers.RandomEmail() + state.email = strings.ToUpper(sourceMail) + assert.NotEqual(t, sourceMail, state.email) + + // 2. Submit Identifier (email) + state = registerNewUser(ctx, t, state, tc.isSPA, nil) + + message := testhelpers.CourierExpectMessage(ctx, t, reg, sourceMail, "Complete your account registration") + assert.Contains(t, message.Body, "please complete your account registration by entering the following code") + + registrationCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) + assert.NotEmpty(t, registrationCode) + + // 3. Submit OTP + state = submitOTP(ctx, t, reg, state, func(v *url.Values) { + v.Set("code", registrationCode) + }, tc.isSPA, nil) + + creds, ok := state.resultIdentity.GetCredentials(identity.CredentialsTypeCodeAuth) + require.True(t, ok) + require.Len(t, creds.Identifiers, 1) + assert.Equal(t, sourceMail, creds.Identifiers[0]) + }) + + t.Run("case=should be able to resend the code", func(t *testing.T) { + ctx := context.Background() + + s := createRegistrationFlow(ctx, t, public, tc.isSPA) + + s = registerNewUser(ctx, t, s, tc.isSPA, func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) { + if tc.isSPA { + require.EqualValues(t, http.StatusBadRequest, resp.StatusCode) + } else { + require.EqualValues(t, http.StatusOK, resp.StatusCode) + } + csrfToken := gjson.Get(body, "ui.nodes.#(attributes.name==csrf_token).attributes.value").String() + require.NotEmptyf(t, csrfToken, "%s", body) + require.Equal(t, s.email, gjson.Get(body, "ui.nodes.#(attributes.name==traits.email).attributes.value").String()) + + attr := gjson.Get(body, "ui.nodes.#(attributes.name==method)#").String() + require.NotEmpty(t, attr) + + val := gjson.Get(attr, "#(attributes.type==hidden).attributes.value").String() + require.Equal(t, "code", val) + }) + + message := testhelpers.CourierExpectMessage(ctx, t, reg, s.email, "Complete your account registration") + assert.Contains(t, message.Body, "please complete your account registration by entering the following code") + + registrationCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) + assert.NotEmpty(t, registrationCode) + + // resend code + s = submitOTP(ctx, t, reg, s, func(v *url.Values) { + v.Set("resend", "code") + }, tc.isSPA, func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) { + if tc.isSPA { + require.EqualValues(t, http.StatusBadRequest, resp.StatusCode) + } else { + require.Equal(t, http.StatusOK, resp.StatusCode) + } + csrfToken := gjson.Get(body, "ui.nodes.#(attributes.name==csrf_token).attributes.value").String() + require.NotEmptyf(t, csrfToken, "%s", body) + require.Containsf(t, gjson.Get(body, "ui.messages").String(), "An email containing a code has been sent to the email address you provided.", "%s", body) + }) + + // get the new code from email + message = testhelpers.CourierExpectMessage(ctx, t, reg, s.email, "Complete your account registration") + assert.Contains(t, message.Body, "please complete your account registration by entering the following code") + + registrationCode2 := testhelpers.CourierExpectCodeInMessage(t, message, 1) + assert.NotEmpty(t, registrationCode2) + + require.NotEqual(t, registrationCode, registrationCode2) + + // try submit old code + s = submitOTP(ctx, t, reg, s, func(v *url.Values) { + v.Set("code", registrationCode) + }, tc.isSPA, func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) { + if tc.isSPA { + require.Equal(t, http.StatusBadRequest, resp.StatusCode, "%s", body) + } else { + require.Equal(t, http.StatusOK, resp.StatusCode, "%s", body) + } + require.Contains(t, gjson.Get(body, "ui.messages").String(), "The registration code is invalid or has already been used. Please try again") + }) + + s = submitOTP(ctx, t, reg, s, func(v *url.Values) { + v.Set("code", registrationCode2) + }, tc.isSPA, nil) + }) + + t.Run("case=swapping out traits should not be possible on code submit", func(t *testing.T) { + ctx := context.Background() + + // 1. Initiate flow + s := createRegistrationFlow(ctx, t, public, tc.isSPA) + + // 2. Submit Identifier (email) + s = registerNewUser(ctx, t, s, tc.isSPA, nil) + + message := testhelpers.CourierExpectMessage(ctx, t, reg, s.email, "Complete your account registration") + assert.Contains(t, message.Body, "please complete your account registration by entering the following code") + + registrationCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) + assert.NotEmpty(t, registrationCode) + + s.email = "not-" + s.email // swap out email + + // 3. Submit OTP + s = submitOTP(ctx, t, reg, s, func(v *url.Values) { + v.Set("code", registrationCode) + }, tc.isSPA, func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) { + if tc.isSPA { + require.Equal(t, http.StatusBadRequest, resp.StatusCode, "%s", body) + } else { + require.Equal(t, http.StatusOK, resp.StatusCode, "%s", body) + } + require.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "The provided traits do not match the traits previously associated with this flow.") + }) + }) + + t.Run("case=code should not be able to use more than 5 times", func(t *testing.T) { + ctx := context.Background() + + // 1. Initiate flow + s := createRegistrationFlow(ctx, t, public, tc.isSPA) + + // 2. Submit Identifier (email) + s = registerNewUser(ctx, t, s, tc.isSPA, nil) + + reg.Persister().Transaction(ctx, func(ctx context.Context, connection *pop.Connection) error { + count, err := connection.RawQuery(fmt.Sprintf("SELECT * FROM %s WHERE selfservice_registration_flow_id = ?", new(code.RegistrationCode).TableName(ctx)), uuid.FromStringOrNil(s.flowID)).Count(new(code.RegistrationCode)) + require.NoError(t, err) + require.Equal(t, 1, count) + return nil + }) + + for i := 0; i < 5; i++ { + s = submitOTP(ctx, t, reg, s, func(v *url.Values) { + v.Set("code", "111111") + }, tc.isSPA, func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) { + if tc.isSPA { + require.Equal(t, http.StatusBadRequest, resp.StatusCode, "%s", body) + } else { + require.Equal(t, http.StatusOK, resp.StatusCode, "%s", body) + } + require.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "The registration code is invalid or has already been used") + }) + } + + s = submitOTP(ctx, t, reg, s, func(v *url.Values) { + v.Set("code", "111111") + }, tc.isSPA, func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) { + if tc.isSPA { + require.Equal(t, http.StatusBadRequest, resp.StatusCode, "%s", body) + } else { + require.Equal(t, http.StatusOK, resp.StatusCode, "%s", body) + } + require.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "The request was submitted too often.") + }) + }) + }) + } + }) + + t.Run("test=cases with different configs", func(t *testing.T) { + ctx := context.Background() + conf, reg, public := setup(ctx, t) + + for _, tc := range []struct { + d string + isSPA bool + }{ + { + d: "SPA client", + isSPA: true, + }, + { + d: "Browser client", + isSPA: false, + }, + } { + t.Run("test="+tc.d, func(t *testing.T) { + t.Run("case=should fail when schema does not contain the `code` extension", func(t *testing.T) { + testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/default.schema.json") + t.Cleanup(func() { + testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/code.identity.schema.json") + }) + + // 1. Initiate flow + s := createRegistrationFlow(ctx, t, public, tc.isSPA) + + // 2. Submit Identifier (email) + s = registerNewUser(ctx, t, s, tc.isSPA, func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) { + if tc.isSPA { + require.Equal(t, http.StatusBadRequest, resp.StatusCode) + require.Contains(t, gjson.Get(body, "ui.messages").String(), "Could not find any login identifiers") + } else { + // we expect a redirect to the registration page with the flow id + require.Equal(t, http.StatusOK, resp.StatusCode) + require.Equal(t, conf.SelfServiceFlowRegistrationUI(ctx).Path, resp.Request.URL.Path) + rf, resp, err := testhelpers.NewSDKCustomClient(public, s.client).FrontendApi.GetRegistrationFlow(ctx).Id(resp.Request.URL.Query().Get("flow")).Execute() + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode) + body, err := json.Marshal(rf) + require.NoError(t, err) + require.Contains(t, gjson.GetBytes(body, "ui.messages").String(), "Could not find any login identifiers") + + } + }) + }) + + t.Run("case=should have verifiable address even if after session hook is disabled", func(t *testing.T) { + // disable the after session hook + conf.MustSet(ctx, config.ViperKeySelfServiceRegistrationAfter+".code.hooks", []map[string]interface{}{}) + + t.Cleanup(func() { + conf.MustSet(ctx, config.ViperKeySelfServiceRegistrationAfter+".code.hooks", []map[string]interface{}{ + {"hook": "session"}, + }) + }) + + // 1. Initiate flow + state := createRegistrationFlow(ctx, t, public, tc.isSPA) + + // 2. Submit Identifier (email) + state = registerNewUser(ctx, t, state, tc.isSPA, nil) + + message := testhelpers.CourierExpectMessage(ctx, t, reg, state.email, "Complete your account registration") + assert.Contains(t, message.Body, "please complete your account registration by entering the following code") + + registrationCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) + assert.NotEmpty(t, registrationCode) + + // 3. Submit OTP + state = submitOTP(ctx, t, reg, state, func(v *url.Values) { + v.Set("code", registrationCode) + }, tc.isSPA, nil) + }) + + t.Run("case=code should expire", func(t *testing.T) { + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.config.lifespan", "10ns") + t.Cleanup(func() { + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.config.lifespan", "1h") + }) + + // 1. Initiate flow + s := createRegistrationFlow(ctx, t, public, tc.isSPA) + + // 2. Submit Identifier (email) + s = registerNewUser(ctx, t, s, tc.isSPA, nil) + + message := testhelpers.CourierExpectMessage(ctx, t, reg, s.email, "Complete your account registration") + assert.Contains(t, message.Body, "please complete your account registration by entering the following code") + + registrationCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) + assert.NotEmpty(t, registrationCode) + + s = submitOTP(ctx, t, reg, s, func(v *url.Values) { + v.Set("code", registrationCode) + }, tc.isSPA, func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) { + if tc.isSPA { + require.Equal(t, http.StatusGone, resp.StatusCode) + require.Containsf(t, gjson.Get(body, "error.reason").String(), "self-service flow expired 0.00 minutes ago", "%s", body) + } else { + // with browser clients we redirect back to the UI with a new flow id as a query parameter + require.Equal(t, http.StatusOK, resp.StatusCode) + require.Equal(t, conf.SelfServiceFlowRegistrationUI(ctx).Path, resp.Request.URL.Path) + require.NotEqual(t, s.flowID, resp.Request.URL.Query().Get("flow")) + } + }) + }) + }) + } + }) +} diff --git a/selfservice/strategy/code/strategy_verification.go b/selfservice/strategy/code/strategy_verification.go index 9a0902a404bb..c02e89105116 100644 --- a/selfservice/strategy/code/strategy_verification.go +++ b/selfservice/strategy/code/strategy_verification.go @@ -38,35 +38,7 @@ func (s *Strategy) RegisterAdminVerificationRoutes(admin *x.RouterAdmin) { // Otherwise, the default email input is added. // If the flow is a browser flow, the CSRF token is added to the UI. func (s *Strategy) PopulateVerificationMethod(r *http.Request, f *verification.Flow) error { - nodes := node.Nodes{} - switch f.State { - case verification.StateEmailSent: - nodes.Upsert( - node. - NewInputField("code", nil, node.CodeGroup, node.InputAttributeTypeText, node.WithRequiredInputAttribute). - WithMetaLabel(text.NewInfoNodeLabelVerificationCode()), - ) - // Required for the re-send code button - nodes.Append( - node.NewInputField("method", s.VerificationNodeGroup(), node.CodeGroup, node.InputAttributeTypeHidden), - ) - f.UI.Messages.Set(text.NewVerificationEmailWithCodeSent()) - default: - nodes.Upsert( - node.NewInputField("email", nil, node.CodeGroup, node.InputAttributeTypeEmail, node.WithRequiredInputAttribute). - WithMetaLabel(text.NewInfoNodeInputEmail()), - ) - } - nodes.Append( - node.NewInputField("method", s.VerificationStrategyID(), node.CodeGroup, node.InputAttributeTypeSubmit). - WithMetaLabel(text.NewInfoNodeLabelSubmit()), - ) - - f.UI.Nodes = nodes - if f.Type == flow.TypeBrowser { - f.UI.SetCSRF(s.deps.GenerateCSRFToken(r)) - } - return nil + return s.PopulateMethod(r, f) } func (s *Strategy) decodeVerification(r *http.Request) (*updateVerificationFlowWithCodeMethod, error) { @@ -156,7 +128,7 @@ func (s *Strategy) Verify(w http.ResponseWriter, r *http.Request, f *verificatio return s.handleVerificationError(w, r, nil, body, err) } - if err := flow.MethodEnabledAndAllowed(r.Context(), s.VerificationStrategyID(), string(body.getMethod()), s.deps); err != nil { + if err := flow.MethodEnabledAndAllowed(r.Context(), f.GetFlowName(), s.VerificationStrategyID(), string(body.getMethod()), s.deps); err != nil { return s.handleVerificationError(w, r, f, body, err) } @@ -165,11 +137,11 @@ func (s *Strategy) Verify(w http.ResponseWriter, r *http.Request, f *verificatio } switch f.State { - case verification.StateChooseMethod: + case flow.StateChooseMethod: fallthrough - case verification.StateEmailSent: + case flow.StateEmailSent: return s.verificationHandleFormSubmission(w, r, f, body) - case verification.StatePassedChallenge: + case flow.StatePassedChallenge: return s.retryVerificationFlowWithMessage(w, r, f.Type, text.NewErrorValidationVerificationRetrySuccess()) default: return s.retryVerificationFlowWithMessage(w, r, f.Type, text.NewErrorValidationVerificationStateFailure()) @@ -177,7 +149,6 @@ func (s *Strategy) Verify(w http.ResponseWriter, r *http.Request, f *verificatio } func (s *Strategy) handleLinkClick(w http.ResponseWriter, r *http.Request, f *verification.Flow, code string) error { - // Pre-fill the code if codeField := f.UI.Nodes.Find("code"); codeField != nil { codeField.Attributes.SetValue(code) @@ -230,7 +201,7 @@ func (s *Strategy) verificationHandleFormSubmission(w http.ResponseWriter, r *ht // Continue execution } - f.State = verification.StateEmailSent + f.State = flow.StateEmailSent if err := s.PopulateVerificationMethod(r, f); err != nil { return s.handleVerificationError(w, r, f, body, err) @@ -265,10 +236,6 @@ func (s *Strategy) verificationUseCode(w http.ResponseWriter, r *http.Request, c return s.retryVerificationFlowWithError(w, r, f.Type, err) } - if err := code.Validate(); err != nil { - return s.retryVerificationFlowWithError(w, r, f.Type, err) - } - i, err := s.deps.IdentityPool().GetIdentity(r.Context(), code.VerifiableAddress.IdentityID, identity.ExpandDefault) if err != nil { return s.retryVerificationFlowWithError(w, r, f.Type, err) @@ -294,7 +261,7 @@ func (s *Strategy) verificationUseCode(w http.ResponseWriter, r *http.Request, c Action: returnTo.String(), } - f.State = verification.StatePassedChallenge + f.State = flow.StatePassedChallenge // See https://github.com/ory/kratos/issues/1547 f.SetCSRFToken(flow.GetCSRFToken(s.deps, w, r, f.Type)) f.UI.Messages.Set(text.NewInfoSelfServiceVerificationSuccessful()) @@ -378,7 +345,6 @@ func (s *Strategy) retryVerificationFlowWithError(w http.ResponseWriter, r *http } func (s *Strategy) SendVerificationEmail(ctx context.Context, f *verification.Flow, i *identity.Identity, a *identity.VerifiableAddress) (err error) { - rawCode := GenerateCode() code, err := s.deps.VerificationCodePersister().CreateVerificationCode(ctx, &CreateVerificationCodeParams{ @@ -387,7 +353,6 @@ func (s *Strategy) SendVerificationEmail(ctx context.Context, f *verification.Fl VerifiableAddress: a, FlowID: f.ID, }) - if err != nil { return err } diff --git a/selfservice/strategy/code/strategy_verification_test.go b/selfservice/strategy/code/strategy_verification_test.go index b00bcda5c2bf..9be8cd08145d 100644 --- a/selfservice/strategy/code/strategy_verification_test.go +++ b/selfservice/strategy/code/strategy_verification_test.go @@ -43,7 +43,7 @@ func TestVerification(t *testing.T) { conf, reg := internal.NewFastRegistryWithMocks(t) initViper(t, ctx, conf) - var identityToVerify = &identity.Identity{ + identityToVerify := &identity.Identity{ ID: x.NewUUID(), Traits: identity.Traits(`{"email":"verifyme@ory.sh"}`), SchemaID: config.DefaultIdentityTraitsSchemaID, @@ -56,7 +56,7 @@ func TestVerification(t *testing.T) { }, } - var verificationEmail = gjson.GetBytes(identityToVerify.Traits, "email").String() + verificationEmail := gjson.GetBytes(identityToVerify.Traits, "email").String() _ = testhelpers.NewVerificationUIFlowEchoServer(t, reg) _ = testhelpers.NewLoginUIFlowEchoServer(t, reg) @@ -69,7 +69,7 @@ func TestVerification(t *testing.T) { require.NoError(t, reg.IdentityManager().Create(context.Background(), identityToVerify, identity.ManagerAllowWriteProtectedTraits)) - var expect = func(t *testing.T, hc *http.Client, isAPI, isSPA bool, values func(url.Values), c int) string { + expect := func(t *testing.T, hc *http.Client, isAPI, isSPA bool, values func(url.Values), c int) string { if hc == nil { hc = testhelpers.NewDebugClient(t) if !isAPI { @@ -82,15 +82,15 @@ func TestVerification(t *testing.T) { testhelpers.ExpectURL(isAPI || isSPA, public.URL+verification.RouteSubmitFlow, conf.SelfServiceFlowVerificationUI(ctx).String())) } - var expectValidationError = func(t *testing.T, hc *http.Client, isAPI, isSPA bool, values func(url.Values)) string { + expectValidationError := func(t *testing.T, hc *http.Client, isAPI, isSPA bool, values func(url.Values)) string { return expect(t, hc, isAPI, isSPA, values, testhelpers.ExpectStatusCode(isAPI || isSPA, http.StatusBadRequest, http.StatusOK)) } - var expectSuccess = func(t *testing.T, hc *http.Client, isAPI, isSPA bool, values func(url.Values)) string { + expectSuccess := func(t *testing.T, hc *http.Client, isAPI, isSPA bool, values func(url.Values)) string { return expect(t, hc, isAPI, isSPA, values, http.StatusOK) } - var submitVerificationCode = func(t *testing.T, body string, c *http.Client, code string) (string, *http.Response) { + submitVerificationCode := func(t *testing.T, body string, c *http.Client, code string) (string, *http.Response) { action := gjson.Get(body, "ui.action").String() require.NotEmpty(t, action, "%v", string(body)) csrfToken := extractCsrfToken([]byte(body)) @@ -135,14 +135,14 @@ func TestVerification(t *testing.T) { }) t.Run("description=should require an email to be sent", func(t *testing.T) { - var check = func(t *testing.T, actual string) { + check := func(t *testing.T, actual string) { assert.EqualValues(t, string(node.CodeGroup), gjson.Get(actual, "active").String(), "%s", actual) assert.EqualValues(t, "Property email is missing.", gjson.Get(actual, "ui.nodes.#(attributes.name==email).messages.0.text").String(), "%s", actual) } - var values = func(v url.Values) { + values := func(v url.Values) { v.Del("email") } @@ -160,7 +160,7 @@ func TestVerification(t *testing.T) { }) t.Run("description=should require a valid email to be sent", func(t *testing.T) { - var check = func(t *testing.T, actual string, value string) { + check := func(t *testing.T, actual string, value string) { assert.EqualValues(t, string(node.CodeGroup), gjson.Get(actual, "active").String(), "%s", actual) assert.EqualValues(t, fmt.Sprintf("%q is not valid \"email\"", value), gjson.Get(actual, "ui.nodes.#(attributes.name==email).messages.0.text").String(), @@ -168,7 +168,7 @@ func TestVerification(t *testing.T) { } for _, email := range []string{"\\", "asdf", "...", "aiacobelli.sec@gmail.com,alejandro.iacobelli@mercadolibre.com"} { - var values = func(v url.Values) { + values := func(v url.Values) { v.Set("email", email) } @@ -194,16 +194,16 @@ func TestVerification(t *testing.T) { }) var email string - var check = func(t *testing.T, actual string) { + check := func(t *testing.T, actual string) { assert.EqualValues(t, string(node.CodeGroup), gjson.Get(actual, "active").String(), "%s", actual) assert.EqualValues(t, email, gjson.Get(actual, "ui.nodes.#(attributes.name==email).attributes.value").String(), "%s", actual) assertx.EqualAsJSON(t, text.NewVerificationEmailWithCodeSent(), json.RawMessage(gjson.Get(actual, "ui.messages.0").Raw)) - message := testhelpers.CourierExpectMessage(t, reg, email, "Someone tried to verify this email address") + message := testhelpers.CourierExpectMessage(ctx, t, reg, email, "Someone tried to verify this email address") assert.Contains(t, message.Body, "If this was you, check if you signed up using a different address.") } - var values = func(v url.Values) { + values := func(v url.Values) { v.Set("email", email) } @@ -282,7 +282,7 @@ func TestVerification(t *testing.T) { v.Set("email", verificationEmail) }) - message := testhelpers.CourierExpectMessage(t, reg, verificationEmail, "Please verify your email address") + message := testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Please verify your email address") assert.Contains(t, message.Body, "please verify your account by entering the following code") code := testhelpers.CourierExpectCodeInMessage(t, message, 1) @@ -295,12 +295,12 @@ func TestVerification(t *testing.T) { }) t.Run("description=should verify an email address", func(t *testing.T) { - var check = func(t *testing.T, actual string) { + check := func(t *testing.T, actual string) { assert.EqualValues(t, string(node.CodeGroup), gjson.Get(actual, "active").String(), "%s", actual) assert.EqualValues(t, verificationEmail, gjson.Get(actual, "ui.nodes.#(attributes.name==email).attributes.value").String(), "%s", actual) assertx.EqualAsJSON(t, text.NewVerificationEmailWithCodeSent(), json.RawMessage(gjson.Get(actual, "ui.messages.0").Raw)) - message := testhelpers.CourierExpectMessage(t, reg, verificationEmail, "Please verify your email address") + message := testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Please verify your email address") assert.Contains(t, message.Body, "please verify your account by entering the following code") verificationLink := testhelpers.CourierExpectLinkInMessage(t, message, 1) @@ -335,7 +335,7 @@ func TestVerification(t *testing.T) { assert.True(t, time.Time(*address.VerifiedAt).Add(time.Second*5).After(time.Now())) } - var values = func(v url.Values) { + values := func(v url.Values) { v.Set("email", verificationEmail) } @@ -353,13 +353,12 @@ func TestVerification(t *testing.T) { }) t.Run("description=should verify an email address when the link is opened in another browser", func(t *testing.T) { - - var values = func(v url.Values) { + values := func(v url.Values) { v.Set("email", verificationEmail) } expectSuccess(t, nil, false, false, values) - message := testhelpers.CourierExpectMessage(t, reg, verificationEmail, "Please verify your email address") + message := testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Please verify your email address") verificationLink := testhelpers.CourierExpectLinkInMessage(t, message, 1) code := testhelpers.CourierExpectCodeInMessage(t, message, 1) @@ -377,7 +376,7 @@ func TestVerification(t *testing.T) { newValidFlow := func(t *testing.T, fType flow.Type, requestURL string) (*verification.Flow, *code.VerificationCode, string) { f, err := verification.NewFlow(conf, time.Hour, x.FakeCSRFToken, httptest.NewRequest("GET", requestURL, nil), code.NewStrategy(reg), fType) require.NoError(t, err) - f.State = verification.StateEmailSent + f.State = flow.StateEmailSent require.NoError(t, reg.VerificationFlowPersister().CreateVerificationFlow(context.Background(), f)) email := identity.NewVerifiableEmailAddress(verificationEmail, identityToVerify.ID) identityToVerify.VerifiableAddresses = append(identityToVerify.VerifiableAddresses, *email) @@ -422,7 +421,7 @@ func TestVerification(t *testing.T) { v.Set("email", verificationEmail) }) - message := testhelpers.CourierExpectMessage(t, reg, verificationEmail, "Please verify your email address") + message := testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Please verify your email address") assert.Contains(t, message.Body, "please verify your account by entering the following code") verificationLink := testhelpers.CourierExpectLinkInMessage(t, message, 1) @@ -459,7 +458,7 @@ func TestVerification(t *testing.T) { assert.Equal(t, text.ErrIDSelfServiceFlowReplaced, gjson.GetBytes(f2, "error.id").String()) }) - var resendVerificationCode = func(t *testing.T, client *http.Client, flow string, flowType string, statusCode int) string { + resendVerificationCode := func(t *testing.T, client *http.Client, flow string, flowType string, statusCode int) string { action := gjson.Get(flow, "ui.action").String() assert.NotEmpty(t, action) @@ -487,7 +486,7 @@ func TestVerification(t *testing.T) { v.Set("email", verificationEmail) }) - message := testhelpers.CourierExpectMessage(t, reg, verificationEmail, "Please verify your email address") + message := testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Please verify your email address") _ = testhelpers.CourierExpectCodeInMessage(t, message, 1) c := testhelpers.NewClientWithCookies(t) @@ -496,19 +495,18 @@ func TestVerification(t *testing.T) { assert.True(t, gjson.Get(body, "ui.nodes.#(attributes.name==code)").Exists()) assert.Equal(t, verificationEmail, gjson.Get(body, "ui.nodes.#(attributes.name==email).attributes.value").String()) - message = testhelpers.CourierExpectMessage(t, reg, verificationEmail, "Please verify your email address") + message = testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Please verify your email address") verificationCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) submitVerificationCode(t, body, c, verificationCode) }) t.Run("case=should not be able to use first code after resending code", func(t *testing.T) { - body := expectSuccess(t, nil, true, false, func(v url.Values) { v.Set("email", verificationEmail) }) - message := testhelpers.CourierExpectMessage(t, reg, verificationEmail, "Please verify your email address") + message := testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Please verify your email address") firstCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) c := testhelpers.NewClientWithCookies(t) @@ -517,7 +515,7 @@ func TestVerification(t *testing.T) { assert.True(t, gjson.Get(body, "ui.nodes.#(attributes.name==code)").Exists()) assert.Equal(t, verificationEmail, gjson.Get(body, "ui.nodes.#(attributes.name==email).attributes.value").String()) - message = testhelpers.CourierExpectMessage(t, reg, verificationEmail, "Please verify your email address") + message = testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Please verify your email address") secondCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) body, res := submitVerificationCode(t, body, c, firstCode) @@ -568,7 +566,7 @@ func TestVerification(t *testing.T) { body := expectSuccess(t, nil, true, false, func(v url.Values) { v.Set("email", verificationEmail) }) - message := testhelpers.CourierExpectMessage(t, reg, verificationEmail, "Please verify your email address") + message := testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Please verify your email address") code := testhelpers.CourierExpectCodeInMessage(t, message, 1) body, res := submitVerificationCode(t, body, c, code) @@ -578,7 +576,7 @@ func TestVerification(t *testing.T) { body = expectSuccess(t, nil, true, false, func(v url.Values) { v.Set("email", verificationEmail) }) - message = testhelpers.CourierExpectMessage(t, reg, verificationEmail, "Please verify your email address") + message = testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Please verify your email address") code = testhelpers.CourierExpectCodeInMessage(t, message, 1) body, res = submitVerificationCode(t, body, c, code) @@ -636,5 +634,4 @@ func TestVerification(t *testing.T) { }) } }) - } diff --git a/selfservice/strategy/code/stub/code.identity.schema.json b/selfservice/strategy/code/stub/code.identity.schema.json new file mode 100644 index 000000000000..f8d988c21af9 --- /dev/null +++ b/selfservice/strategy/code/stub/code.identity.schema.json @@ -0,0 +1,61 @@ +{ + "$id": "https://example.com/person.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": "Email", + "ory.sh/kratos": { + "credentials": { + "code": { + "identifier": true, + "via": "email" + } + }, + "verification": { + "via": "email" + } + } + }, + "email_0": { + "type": "string", + "format": "email", + "title": "Email", + "ory.sh/kratos": { + "credentials": { + "code": { + "identifier": true, + "via": "email" + } + }, + "verification": { + "via": "email" + } + } + }, + "email_1": { + "type": "string", + "format": "email", + "title": "Email", + "ory.sh/kratos": { + "credentials": { + "code": { + "identifier": true, + "via": "email" + } + }, + "verification": { + "via": "email" + } + } + } + } + } + } +} diff --git a/selfservice/strategy/code/test/persistence.go b/selfservice/strategy/code/test/persistence.go index cf8e25afc155..f505bcb9c185 100644 --- a/selfservice/strategy/code/test/persistence.go +++ b/selfservice/strategy/code/test/persistence.go @@ -10,6 +10,7 @@ import ( "github.com/ory/kratos/internal/testhelpers" "github.com/ory/kratos/persistence" + "github.com/ory/kratos/selfservice/flow" "github.com/ory/kratos/selfservice/strategy/code" "github.com/ory/x/randx" @@ -25,7 +26,8 @@ import ( func TestPersister(ctx context.Context, conf *config.Config, p interface { persistence.Persister -}) func(t *testing.T) { +}, +) func(t *testing.T) { return func(t *testing.T) { nid, p := testhelpers.NewNetworkUnlessExisting(t, ctx, p) @@ -33,10 +35,11 @@ func TestPersister(ctx context.Context, conf *config.Config, p interface { conf.MustSet(ctx, config.ViperKeySecretsDefault, []string{"secret-a", "secret-b"}) t.Run("code=recovery", func(t *testing.T) { - newRecoveryCodeDTO := func(t *testing.T, email string) (*code.CreateRecoveryCodeParams, *recovery.Flow, *identity.RecoveryAddress) { var f recovery.Flow require.NoError(t, faker.FakeData(&f)) + f.State = flow.StateChooseMethod + require.NoError(t, p.CreateRecoveryFlow(ctx, &f)) var i identity.Identity @@ -141,7 +144,6 @@ func TestPersister(ctx context.Context, conf *config.Config, p interface { count, err = p.GetConnection(ctx).Where("selfservice_recovery_flow_id = ?", f.ID).Count(&code.RecoveryCode{}) require.NoError(t, err) require.Equal(t, 0, count) - }) }) } diff --git a/selfservice/strategy/link/strategy.go b/selfservice/strategy/link/strategy.go index fa5e9218a1df..da66e1816bf5 100644 --- a/selfservice/strategy/link/strategy.go +++ b/selfservice/strategy/link/strategy.go @@ -19,13 +19,17 @@ import ( "github.com/ory/x/decoderx" ) -var _ recovery.Strategy = new(Strategy) -var _ recovery.AdminHandler = new(Strategy) -var _ recovery.PublicHandler = new(Strategy) +var ( + _ recovery.Strategy = new(Strategy) + _ recovery.AdminHandler = new(Strategy) + _ recovery.PublicHandler = new(Strategy) +) -var _ verification.Strategy = new(Strategy) -var _ verification.AdminHandler = new(Strategy) -var _ verification.PublicHandler = new(Strategy) +var ( + _ verification.Strategy = new(Strategy) + _ verification.AdminHandler = new(Strategy) + _ verification.PublicHandler = new(Strategy) +) type ( // FlowMethod contains the configuration for this selfservice strategy. @@ -83,10 +87,6 @@ func NewStrategy(d strategyDependencies) *Strategy { return &Strategy{d: d, dx: decoderx.NewHTTP()} } -func (s *Strategy) RecoveryNodeGroup() node.UiNodeGroup { - return node.LinkGroup -} - -func (s *Strategy) VerificationNodeGroup() node.UiNodeGroup { +func (s *Strategy) NodeGroup() node.UiNodeGroup { return node.LinkGroup } diff --git a/selfservice/strategy/link/strategy_recovery.go b/selfservice/strategy/link/strategy_recovery.go index 6ab3ff4ae904..da4f40ac9516 100644 --- a/selfservice/strategy/link/strategy_recovery.go +++ b/selfservice/strategy/link/strategy_recovery.go @@ -40,7 +40,6 @@ func (s *Strategy) RecoveryStrategyID() string { func (s *Strategy) RegisterPublicRecoveryRoutes(public *x.RouterPublic) { s.d.CSRFHandler().IgnorePath(RouteAdminCreateRecoveryLink) public.POST(RouteAdminCreateRecoveryLink, x.RedirectToAdminRoute(s.d)) - } func (s *Strategy) RegisterAdminRecoveryRoutes(admin *x.RouterAdmin) { @@ -198,7 +197,8 @@ func (s *Strategy) createRecoveryLinkForIdentity(w http.ResponseWriter, r *http. url.Values{ "token": {token.Token}, "flow": {req.ID.String()}, - }).String()}, + }).String(), + }, herodot.UnescapedHTML) } @@ -237,7 +237,7 @@ func (s *Strategy) Recover(w http.ResponseWriter, r *http.Request, f *recovery.F } if len(body.Token) > 0 { - if err := flow.MethodEnabledAndAllowed(r.Context(), s.RecoveryStrategyID(), s.RecoveryStrategyID(), s.d); err != nil { + if err := flow.MethodEnabledAndAllowed(r.Context(), f.GetFlowName(), s.RecoveryStrategyID(), s.RecoveryStrategyID(), s.d); err != nil { return s.HandleRecoveryError(w, r, nil, body, err) } @@ -253,7 +253,7 @@ func (s *Strategy) Recover(w http.ResponseWriter, r *http.Request, f *recovery.F return errors.WithStack(flow.ErrCompletedByStrategy) } - if err := flow.MethodEnabledAndAllowed(r.Context(), s.RecoveryStrategyID(), body.Method, s.d); err != nil { + if err := flow.MethodEnabledAndAllowed(r.Context(), f.GetFlowName(), s.RecoveryStrategyID(), body.Method, s.d); err != nil { return s.HandleRecoveryError(w, r, nil, body, err) } @@ -267,11 +267,11 @@ func (s *Strategy) Recover(w http.ResponseWriter, r *http.Request, f *recovery.F } switch req.State { - case recovery.StateChooseMethod: + case flow.StateChooseMethod: fallthrough - case recovery.StateEmailSent: + case flow.StateEmailSent: return s.recoveryHandleFormSubmission(w, r, req) - case recovery.StatePassedChallenge: + case flow.StatePassedChallenge: // was already handled, do not allow retry return s.retryRecoveryFlowWithMessage(w, r, req.Type, text.NewErrorValidationRecoveryRetrySuccess()) default: @@ -281,7 +281,7 @@ func (s *Strategy) Recover(w http.ResponseWriter, r *http.Request, f *recovery.F func (s *Strategy) recoveryIssueSession(w http.ResponseWriter, r *http.Request, f *recovery.Flow, id *identity.Identity) error { f.UI.Messages.Clear() - f.State = recovery.StatePassedChallenge + f.State = flow.StatePassedChallenge f.SetCSRFToken(s.d.CSRFHandler().RegenerateToken(w, r)) f.RecoveredIdentityID = uuid.NullUUID{ UUID: id.ID, @@ -455,8 +455,8 @@ func (s *Strategy) recoveryHandleFormSubmission(w http.ResponseWriter, r *http.R node.NewInputField("email", body.Email, node.LinkGroup, node.InputAttributeTypeEmail, node.WithRequiredInputAttribute).WithMetaLabel(text.NewInfoNodeInputEmail()), ) - f.Active = sqlxx.NullString(s.RecoveryNodeGroup()) - f.State = recovery.StateEmailSent + f.Active = sqlxx.NullString(s.NodeGroup()) + f.State = flow.StateEmailSent f.UI.Messages.Set(text.NewRecoveryEmailSent()) if err := s.d.RecoveryFlowPersister().UpdateRecoveryFlow(r.Context(), f); err != nil { return s.HandleRecoveryError(w, r, f, body, err) diff --git a/selfservice/strategy/link/strategy_recovery_test.go b/selfservice/strategy/link/strategy_recovery_test.go index 4af007577500..71518cda33be 100644 --- a/selfservice/strategy/link/strategy_recovery_test.go +++ b/selfservice/strategy/link/strategy_recovery_test.go @@ -61,9 +61,10 @@ func init() { } func createIdentityToRecover(t *testing.T, reg *driver.RegistryDefault, email string) *identity.Identity { - var id = &identity.Identity{ + id := &identity.Identity{ Credentials: map[identity.CredentialsType]identity.Credentials{ - "password": {Type: "password", Identifiers: []string{email}, Config: sqlxx.JSONRawMessage(`{"hashed_password":"foo"}`)}}, + "password": {Type: "password", Identifiers: []string{email}, Config: sqlxx.JSONRawMessage(`{"hashed_password":"foo"}`)}, + }, Traits: identity.Traits(fmt.Sprintf(`{"email":"%s"}`, email)), SchemaID: config.DefaultIdentityTraitsSchemaID, } @@ -273,7 +274,7 @@ func TestRecovery(t *testing.T) { public, _, publicRouter, _ := testhelpers.NewKratosServerWithCSRFAndRouters(t, reg) - var expect = func(t *testing.T, hc *http.Client, isAPI, isSPA bool, values func(url.Values), c int) string { + expect := func(t *testing.T, hc *http.Client, isAPI, isSPA bool, values func(url.Values), c int) string { if hc == nil { hc = testhelpers.NewDebugClient(t) if !isAPI { @@ -286,11 +287,11 @@ func TestRecovery(t *testing.T) { testhelpers.ExpectURL(isAPI || isSPA, public.URL+recovery.RouteSubmitFlow, conf.SelfServiceFlowRecoveryUI(ctx).String())) } - var expectValidationError = func(t *testing.T, hc *http.Client, isAPI, isSPA bool, values func(url.Values)) string { + expectValidationError := func(t *testing.T, hc *http.Client, isAPI, isSPA bool, values func(url.Values)) string { return expect(t, hc, isAPI, isSPA, values, testhelpers.ExpectStatusCode(isAPI || isSPA, http.StatusBadRequest, http.StatusOK)) } - var expectSuccess = func(t *testing.T, hc *http.Client, isAPI, isSPA bool, values func(url.Values)) string { + expectSuccess := func(t *testing.T, hc *http.Client, isAPI, isSPA bool, values func(url.Values)) string { return expect(t, hc, isAPI, isSPA, values, http.StatusOK) } @@ -311,14 +312,14 @@ func TestRecovery(t *testing.T) { }) t.Run("description=should require an email to be sent", func(t *testing.T) { - var check = func(t *testing.T, actual string) { + check := func(t *testing.T, actual string) { assert.EqualValues(t, node.LinkGroup, gjson.Get(actual, "active").String(), "%s", actual) assert.EqualValues(t, "Property email is missing.", gjson.Get(actual, "ui.nodes.#(attributes.name==email).messages.0.text").String(), "%s", actual) } - var values = func(v url.Values) { + values := func(v url.Values) { v.Del("email") } @@ -336,14 +337,14 @@ func TestRecovery(t *testing.T) { }) t.Run("description=should require a valid email to be sent", func(t *testing.T) { - var check = func(t *testing.T, actual string, value string) { + check := func(t *testing.T, actual string, value string) { assert.EqualValues(t, node.LinkGroup, gjson.Get(actual, "active").String(), "%s", actual) assert.EqualValues(t, fmt.Sprintf("%q is not valid \"email\"", value), gjson.Get(actual, "ui.nodes.#(attributes.name==email).messages.0.text").String(), "%s", actual) } for _, email := range []string{"\\", "asdf", "...", "aiacobelli.sec@gmail.com,alejandro.iacobelli@mercadolibre.com"} { - var values = func(v url.Values) { + values := func(v url.Values) { v.Set("email", email) } @@ -422,16 +423,16 @@ func TestRecovery(t *testing.T) { conf.Set(ctx, config.ViperKeySelfServiceRecoveryNotifyUnknownRecipients, false) }) var email string - var check = func(t *testing.T, actual string) { + check := func(t *testing.T, actual string) { assert.EqualValues(t, node.LinkGroup, gjson.Get(actual, "active").String(), "%s", actual) assert.EqualValues(t, email, gjson.Get(actual, "ui.nodes.#(attributes.name==email).attributes.value").String(), "%s", actual) assertx.EqualAsJSON(t, text.NewRecoveryEmailSent(), json.RawMessage(gjson.Get(actual, "ui.messages.0").Raw)) - message := testhelpers.CourierExpectMessage(t, reg, email, "Account access attempted") + message := testhelpers.CourierExpectMessage(ctx, t, reg, email, "Account access attempted") assert.Contains(t, message.Body, "If this was you, check if you signed up using a different address.") } - var values = func(v url.Values) { + values := func(v url.Values) { v.Set("email", email) } @@ -452,11 +453,11 @@ func TestRecovery(t *testing.T) { }) t.Run("description=should not be able to recover an inactive account", func(t *testing.T) { - var check = func(t *testing.T, recoverySubmissionResponse, recoveryEmail string, isAPI bool) { + check := func(t *testing.T, recoverySubmissionResponse, recoveryEmail string, isAPI bool) { addr, err := reg.IdentityPool().FindVerifiableAddressByValue(context.Background(), identity.VerifiableAddressTypeEmail, recoveryEmail) assert.NoError(t, err) - recoveryLink := testhelpers.CourierExpectLinkInMessage(t, testhelpers.CourierExpectMessage(t, reg, recoveryEmail, "Recover access to your account"), 1) + recoveryLink := testhelpers.CourierExpectLinkInMessage(t, testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account"), 1) cl := testhelpers.NewClientWithCookies(t) // Deactivate the identity @@ -503,7 +504,7 @@ func TestRecovery(t *testing.T) { }) t.Run("description=should recover an account", func(t *testing.T) { - var check = func(t *testing.T, recoverySubmissionResponse, recoveryEmail, returnTo string) { + check := func(t *testing.T, recoverySubmissionResponse, recoveryEmail, returnTo string) { addr, err := reg.IdentityPool().FindVerifiableAddressByValue(context.Background(), identity.VerifiableAddressTypeEmail, recoveryEmail) assert.NoError(t, err) assert.False(t, addr.Verified) @@ -515,7 +516,7 @@ func TestRecovery(t *testing.T) { require.Len(t, gjson.Get(recoverySubmissionResponse, "ui.messages").Array(), 1, "%s", recoverySubmissionResponse) assertx.EqualAsJSON(t, text.NewRecoveryEmailSent(), json.RawMessage(gjson.Get(recoverySubmissionResponse, "ui.messages.0").Raw)) - message := testhelpers.CourierExpectMessage(t, reg, recoveryEmail, "Recover access to your account") + message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account") assert.Contains(t, message.Body, "please recover access to your account by clicking the following link") recoveryLink := testhelpers.CourierExpectLinkInMessage(t, message, 1) @@ -634,8 +635,8 @@ func TestRecovery(t *testing.T) { }) t.Run("description=should recover an account and set the csrf cookies", func(t *testing.T) { - var check = func(t *testing.T, actual, recoveryEmail string, cl *http.Client, do func(*http.Client, *http.Request) (*http.Response, error)) { - message := testhelpers.CourierExpectMessage(t, reg, recoveryEmail, "Recover access to your account") + check := func(t *testing.T, actual, recoveryEmail string, cl *http.Client, do func(*http.Client, *http.Request) (*http.Response, error)) { + message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account") recoveryLink := testhelpers.CourierExpectLinkInMessage(t, message, 1) cl.CheckRedirect = func(req *http.Request, via []*http.Request) error { @@ -659,21 +660,21 @@ func TestRecovery(t *testing.T) { body := x.MustReadAll(actualRes.Body) require.NoError(t, actualRes.Body.Close()) assert.Equal(t, http.StatusOK, actualRes.StatusCode, "%s", body) - assert.Equal(t, string(recovery.StatePassedChallenge), gjson.GetBytes(body, "state").String(), "%s", body) + assert.Equal(t, string(flow.StatePassedChallenge), gjson.GetBytes(body, "state").String(), "%s", body) } email := x.NewUUID().String() + "@ory.sh" id := createIdentityToRecover(t, reg, email) t.Run("case=unauthenticated", func(t *testing.T) { - var values = func(v url.Values) { + values := func(v url.Values) { v.Set("email", email) } check(t, expectSuccess(t, nil, false, false, values), email, testhelpers.NewClientWithCookies(t), (*http.Client).Do) }) t.Run("case=already logged into another account", func(t *testing.T) { - var values = func(v url.Values) { + values := func(v url.Values) { v.Set("email", email) } @@ -684,7 +685,7 @@ func TestRecovery(t *testing.T) { }) t.Run("case=already logged into the account", func(t *testing.T) { - var values = func(v url.Values) { + values := func(v url.Values) { v.Set("email", email) } @@ -715,8 +716,8 @@ func TestRecovery(t *testing.T) { require.NoError(t, err) assert.True(t, actualSession.IsActive()) - var check = func(t *testing.T, actual string) { - message := testhelpers.CourierExpectMessage(t, reg, recoveryEmail, "Recover access to your account") + check := func(t *testing.T, actual string) { + message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account") recoveryLink := testhelpers.CourierExpectLinkInMessage(t, message, 1) cl := testhelpers.NewClientWithCookies(t) @@ -736,7 +737,7 @@ func TestRecovery(t *testing.T) { assert.False(t, actualSession.IsActive()) } - var values = func(v url.Values) { + values := func(v url.Values) { v.Set("email", recoveryEmail) } @@ -797,7 +798,7 @@ func TestRecovery(t *testing.T) { v.Set("email", recoveryEmail) }) - message := testhelpers.CourierExpectMessage(t, reg, recoveryEmail, "Recover access to your account") + message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account") assert.Contains(t, message.Body, "please recover access to your account by clicking the following link") recoveryLink := testhelpers.CourierExpectLinkInMessage(t, message, 1) @@ -833,8 +834,8 @@ func TestRecovery(t *testing.T) { recoveryEmail := testhelpers.RandomEmail() createIdentityToRecover(t, reg, recoveryEmail) - var check = func(t *testing.T, actual string) { - message := testhelpers.CourierExpectMessage(t, reg, recoveryEmail, "Recover access to your account") + check := func(t *testing.T, actual string) { + message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account") recoveryLink := testhelpers.CourierExpectLinkInMessage(t, message, 1) cl := testhelpers.NewClientWithCookies(t) @@ -850,7 +851,7 @@ func TestRecovery(t *testing.T) { assert.Contains(t, cookies, "ory_kratos_session") } - var values = func(v url.Values) { + values := func(v url.Values) { v.Set("email", recoveryEmail) } @@ -866,8 +867,8 @@ func TestRecovery(t *testing.T) { recoveryEmail := testhelpers.RandomEmail() createIdentityToRecover(t, reg, recoveryEmail) - var check = func(t *testing.T, actual string) { - message := testhelpers.CourierExpectMessage(t, reg, recoveryEmail, "Recover access to your account") + check := func(t *testing.T, actual string) { + message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account") recoveryLink := testhelpers.CourierExpectLinkInMessage(t, message, 1) cl := testhelpers.NewClientWithCookies(t) @@ -883,7 +884,7 @@ func TestRecovery(t *testing.T) { assert.NotContains(t, cookies, "ory_kratos_session") } - var values = func(v url.Values) { + values := func(v url.Values) { v.Set("email", recoveryEmail) } diff --git a/selfservice/strategy/link/strategy_verification.go b/selfservice/strategy/link/strategy_verification.go index e09ffb39f603..47271cd7191d 100644 --- a/selfservice/strategy/link/strategy_verification.go +++ b/selfservice/strategy/link/strategy_verification.go @@ -122,14 +122,14 @@ func (s *Strategy) Verify(w http.ResponseWriter, r *http.Request, f *verificatio } if len(body.Token) > 0 { - if err := flow.MethodEnabledAndAllowed(r.Context(), s.VerificationStrategyID(), s.VerificationStrategyID(), s.d); err != nil { + if err := flow.MethodEnabledAndAllowed(r.Context(), f.GetFlowName(), s.VerificationStrategyID(), s.VerificationStrategyID(), s.d); err != nil { return s.handleVerificationError(w, r, nil, body, err) } return s.verificationUseToken(w, r, body, f) } - if err := flow.MethodEnabledAndAllowed(r.Context(), s.VerificationStrategyID(), body.Method, s.d); err != nil { + if err := flow.MethodEnabledAndAllowed(r.Context(), f.GetFlowName(), s.VerificationStrategyID(), body.Method, s.d); err != nil { return s.handleVerificationError(w, r, f, body, err) } @@ -138,12 +138,12 @@ func (s *Strategy) Verify(w http.ResponseWriter, r *http.Request, f *verificatio } switch f.State { - case verification.StateChooseMethod: + case flow.StateChooseMethod: fallthrough - case verification.StateEmailSent: + case flow.StateEmailSent: // Do nothing (continue with execution after this switch statement) return s.verificationHandleFormSubmission(w, r, f) - case verification.StatePassedChallenge: + case flow.StatePassedChallenge: return s.retryVerificationFlowWithMessage(w, r, f.Type, text.NewErrorValidationVerificationRetrySuccess()) default: return s.retryVerificationFlowWithMessage(w, r, f.Type, text.NewErrorValidationVerificationStateFailure()) @@ -151,7 +151,6 @@ func (s *Strategy) Verify(w http.ResponseWriter, r *http.Request, f *verificatio } func (s *Strategy) verificationHandleFormSubmission(w http.ResponseWriter, r *http.Request, f *verification.Flow) error { - var body = new(verificationSubmitPayload) body, err := s.decodeVerification(r) if err != nil { return s.handleVerificationError(w, r, f, body, err) @@ -178,8 +177,8 @@ func (s *Strategy) verificationHandleFormSubmission(w http.ResponseWriter, r *ht node.NewInputField("email", body.Email, node.LinkGroup, node.InputAttributeTypeEmail, node.WithRequiredInputAttribute).WithMetaLabel(text.NewInfoNodeInputEmail()), ) - f.Active = sqlxx.NullString(s.VerificationNodeGroup()) - f.State = verification.StateEmailSent + f.Active = sqlxx.NullString(s.NodeGroup()) + f.State = flow.StateEmailSent f.UI.Messages.Set(text.NewVerificationEmailSent()) if err := s.d.VerificationFlowPersister().UpdateVerificationFlow(r.Context(), f); err != nil { return s.handleVerificationError(w, r, f, body, err) @@ -232,7 +231,7 @@ func (s *Strategy) verificationUseToken(w http.ResponseWriter, r *http.Request, Action: returnTo.String(), } f.UI.Messages.Clear() - f.State = verification.StatePassedChallenge + f.State = flow.StatePassedChallenge // See https://github.com/ory/kratos/issues/1547 f.SetCSRFToken(flow.GetCSRFToken(s.d, w, r, f.Type)) f.UI.Messages.Set(text.NewInfoSelfServiceVerificationSuccessful()) @@ -304,7 +303,6 @@ func (s *Strategy) retryVerificationFlowWithError(w http.ResponseWriter, r *http } func (s *Strategy) SendVerificationEmail(ctx context.Context, f *verification.Flow, i *identity.Identity, a *identity.VerifiableAddress) error { - token := NewSelfServiceVerificationToken(a, f, s.d.Config().SelfServiceLinkMethodLifespan(ctx)) if err := s.d.VerificationTokenPersister().CreateVerificationToken(ctx, token); err != nil { return err diff --git a/selfservice/strategy/link/strategy_verification_test.go b/selfservice/strategy/link/strategy_verification_test.go index 474107292f2f..c81834e32b91 100644 --- a/selfservice/strategy/link/strategy_verification_test.go +++ b/selfservice/strategy/link/strategy_verification_test.go @@ -41,15 +41,16 @@ func TestVerification(t *testing.T) { conf, reg := internal.NewFastRegistryWithMocks(t) initViper(t, conf) - var identityToVerify = &identity.Identity{ + identityToVerify := &identity.Identity{ ID: x.NewUUID(), Traits: identity.Traits(`{"email":"verifyme@ory.sh"}`), SchemaID: config.DefaultIdentityTraitsSchemaID, Credentials: map[identity.CredentialsType]identity.Credentials{ - "password": {Type: "password", Identifiers: []string{"recoverme@ory.sh"}, Config: sqlxx.JSONRawMessage(`{"hashed_password":"foo"}`)}}, + "password": {Type: "password", Identifiers: []string{"recoverme@ory.sh"}, Config: sqlxx.JSONRawMessage(`{"hashed_password":"foo"}`)}, + }, } - var verificationEmail = gjson.GetBytes(identityToVerify.Traits, "email").String() + verificationEmail := gjson.GetBytes(identityToVerify.Traits, "email").String() _ = testhelpers.NewVerificationUIFlowEchoServer(t, reg) _ = testhelpers.NewLoginUIFlowEchoServer(t, reg) @@ -62,7 +63,7 @@ func TestVerification(t *testing.T) { require.NoError(t, reg.IdentityManager().Create(context.Background(), identityToVerify, identity.ManagerAllowWriteProtectedTraits)) - var expect = func(t *testing.T, hc *http.Client, isAPI, isSPA bool, values func(url.Values), c int) string { + expect := func(t *testing.T, hc *http.Client, isAPI, isSPA bool, values func(url.Values), c int) string { if hc == nil { hc = testhelpers.NewDebugClient(t) if !isAPI { @@ -75,11 +76,11 @@ func TestVerification(t *testing.T) { testhelpers.ExpectURL(isAPI || isSPA, public.URL+verification.RouteSubmitFlow, conf.SelfServiceFlowVerificationUI(ctx).String())) } - var expectValidationError = func(t *testing.T, hc *http.Client, isAPI, isSPA bool, values func(url.Values)) string { + expectValidationError := func(t *testing.T, hc *http.Client, isAPI, isSPA bool, values func(url.Values)) string { return expect(t, hc, isAPI, isSPA, values, testhelpers.ExpectStatusCode(isAPI || isSPA, http.StatusBadRequest, http.StatusOK)) } - var expectSuccess = func(t *testing.T, hc *http.Client, isAPI, isSPA bool, values func(url.Values)) string { + expectSuccess := func(t *testing.T, hc *http.Client, isAPI, isSPA bool, values func(url.Values)) string { return expect(t, hc, isAPI, isSPA, values, http.StatusOK) } @@ -114,14 +115,14 @@ func TestVerification(t *testing.T) { }) t.Run("description=should require an email to be sent", func(t *testing.T) { - var check = func(t *testing.T, actual string) { + check := func(t *testing.T, actual string) { assert.EqualValues(t, string(node.LinkGroup), gjson.Get(actual, "active").String(), "%s", actual) assert.EqualValues(t, "Property email is missing.", gjson.Get(actual, "ui.nodes.#(attributes.name==email).messages.0.text").String(), "%s", actual) } - var values = func(v url.Values) { + values := func(v url.Values) { v.Del("email") } @@ -139,7 +140,7 @@ func TestVerification(t *testing.T) { }) t.Run("description=should require a valid email to be sent", func(t *testing.T) { - var check = func(t *testing.T, actual string, value string) { + check := func(t *testing.T, actual string, value string) { assert.EqualValues(t, string(node.LinkGroup), gjson.Get(actual, "active").String(), "%s", actual) assert.EqualValues(t, fmt.Sprintf("%q is not valid \"email\"", value), gjson.Get(actual, "ui.nodes.#(attributes.name==email).messages.0.text").String(), @@ -147,7 +148,7 @@ func TestVerification(t *testing.T) { } for _, email := range []string{"\\", "asdf", "...", "aiacobelli.sec@gmail.com,alejandro.iacobelli@mercadolibre.com"} { - var values = func(v url.Values) { + values := func(v url.Values) { v.Set("email", email) } @@ -172,16 +173,16 @@ func TestVerification(t *testing.T) { conf.Set(ctx, config.ViperKeySelfServiceVerificationNotifyUnknownRecipients, false) }) var email string - var check = func(t *testing.T, actual string) { + check := func(t *testing.T, actual string) { assert.EqualValues(t, string(node.LinkGroup), gjson.Get(actual, "active").String(), "%s", actual) assert.EqualValues(t, email, gjson.Get(actual, "ui.nodes.#(attributes.name==email).attributes.value").String(), "%s", actual) assertx.EqualAsJSON(t, text.NewVerificationEmailSent(), json.RawMessage(gjson.Get(actual, "ui.messages.0").Raw)) - message := testhelpers.CourierExpectMessage(t, reg, email, "Someone tried to verify this email address") + message := testhelpers.CourierExpectMessage(ctx, t, reg, email, "Someone tried to verify this email address") assert.Contains(t, message.Body, "If this was you, check if you signed up using a different address.") } - var values = func(v url.Values) { + values := func(v url.Values) { v.Set("email", email) } @@ -245,14 +246,14 @@ func TestVerification(t *testing.T) { v.Set("email", verificationEmail) }) - message := testhelpers.CourierExpectMessage(t, reg, verificationEmail, "Please verify your email address") + message := testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Please verify your email address") assert.Contains(t, message.Body, "Hi, please verify your account by clicking the following link") verificationLink := testhelpers.CourierExpectLinkInMessage(t, message, 1) time.Sleep(time.Millisecond * 201) - //Clear cookies as link might be opened in another browser + // Clear cookies as link might be opened in another browser c = testhelpers.NewClientWithCookies(t) res, err := c.Get(verificationLink) require.NoError(t, err) @@ -269,12 +270,12 @@ func TestVerification(t *testing.T) { }) t.Run("description=should verify an email address", func(t *testing.T) { - var check = func(t *testing.T, actual string) { + check := func(t *testing.T, actual string) { assert.EqualValues(t, string(node.LinkGroup), gjson.Get(actual, "active").String(), "%s", actual) assert.EqualValues(t, verificationEmail, gjson.Get(actual, "ui.nodes.#(attributes.name==email).attributes.value").String(), "%s", actual) assertx.EqualAsJSON(t, text.NewVerificationEmailSent(), json.RawMessage(gjson.Get(actual, "ui.messages.0").Raw)) - message := testhelpers.CourierExpectMessage(t, reg, verificationEmail, "Please verify your email address") + message := testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Please verify your email address") assert.Contains(t, message.Body, "please verify your account by clicking the following link") verificationLink := testhelpers.CourierExpectLinkInMessage(t, message, 1) @@ -304,7 +305,7 @@ func TestVerification(t *testing.T) { assert.True(t, time.Time(*address.VerifiedAt).Add(time.Second*5).After(time.Now())) } - var values = func(v url.Values) { + values := func(v url.Values) { v.Set("email", verificationEmail) } @@ -322,8 +323,8 @@ func TestVerification(t *testing.T) { }) t.Run("description=should verify an email address when the link is opened in another browser", func(t *testing.T) { - var check = func(t *testing.T, actual string) { - message := testhelpers.CourierExpectMessage(t, reg, verificationEmail, "Please verify your email address") + check := func(t *testing.T, actual string) { + message := testhelpers.CourierExpectMessage(ctx, t, reg, verificationEmail, "Please verify your email address") verificationLink := testhelpers.CourierExpectLinkInMessage(t, message, 1) cl := testhelpers.NewClientWithCookies(t) @@ -344,7 +345,7 @@ func TestVerification(t *testing.T) { assert.EqualValues(t, "passed_challenge", gjson.Get(actualBody, "state").String()) } - var values = func(v url.Values) { + values := func(v url.Values) { v.Set("email", verificationEmail) } @@ -354,7 +355,7 @@ func TestVerification(t *testing.T) { newValidFlow := func(t *testing.T, fType flow.Type, requestURL string) (*verification.Flow, *link.VerificationToken) { f, err := verification.NewFlow(conf, time.Hour, x.FakeCSRFToken, httptest.NewRequest("GET", requestURL, nil), nil, fType) require.NoError(t, err) - f.State = verification.StateEmailSent + f.State = flow.StateEmailSent require.NoError(t, reg.VerificationFlowPersister().CreateVerificationFlow(context.Background(), f)) email := identity.NewVerifiableEmailAddress(verificationEmail, identityToVerify.ID) identityToVerify.VerifiableAddresses = append(identityToVerify.VerifiableAddresses, *email) @@ -412,7 +413,6 @@ func TestVerification(t *testing.T) { }) t.Run("case=should not be able to use code from different flow", func(t *testing.T) { - f1, _ := newValidBrowserFlow(t, public.URL+verification.RouteInitBrowserFlow) _, t2 := newValidBrowserFlow(t, public.URL+verification.RouteInitBrowserFlow) diff --git a/selfservice/strategy/link/test/persistence.go b/selfservice/strategy/link/test/persistence.go index ae669a888453..63abe6179f18 100644 --- a/selfservice/strategy/link/test/persistence.go +++ b/selfservice/strategy/link/test/persistence.go @@ -10,6 +10,7 @@ import ( "github.com/ory/kratos/internal/testhelpers" "github.com/ory/kratos/persistence" + "github.com/ory/kratos/selfservice/flow" "github.com/ory/kratos/selfservice/strategy/link" "github.com/ory/x/sqlcon" @@ -29,7 +30,8 @@ import ( func TestPersister(ctx context.Context, conf *config.Config, p interface { persistence.Persister -}) func(t *testing.T) { +}, +) func(t *testing.T) { return func(t *testing.T) { nid, p := testhelpers.NewNetworkUnlessExisting(t, ctx, p) @@ -37,10 +39,10 @@ func TestPersister(ctx context.Context, conf *config.Config, p interface { conf.MustSet(ctx, config.ViperKeySecretsDefault, []string{"secret-a", "secret-b"}) t.Run("token=recovery", func(t *testing.T) { - newRecoveryToken := func(t *testing.T, email string) (*link.RecoveryToken, *recovery.Flow) { var req recovery.Flow require.NoError(t, faker.FakeData(&req)) + req.State = flow.StateChooseMethod require.NoError(t, p.CreateRecoveryFlow(ctx, &req)) var i identity.Identity @@ -122,13 +124,13 @@ func TestPersister(ctx context.Context, conf *config.Config, p interface { require.Error(t, err) }) }) - }) t.Run("token=verification", func(t *testing.T) { newVerificationToken := func(t *testing.T, email string) (*verification.Flow, *link.VerificationToken) { var f verification.Flow require.NoError(t, faker.FakeData(&f)) + f.State = flow.StateChooseMethod require.NoError(t, p.CreateVerificationFlow(ctx, &f)) var i identity.Identity diff --git a/selfservice/strategy/lookup/login.go b/selfservice/strategy/lookup/login.go index b5e5fddda7e8..75edc2181059 100644 --- a/selfservice/strategy/lookup/login.go +++ b/selfservice/strategy/lookup/login.go @@ -94,7 +94,7 @@ func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, return nil, err } - if err := flow.MethodEnabledAndAllowedFromRequest(r, s.ID().String(), s.d); err != nil { + if err := flow.MethodEnabledAndAllowedFromRequest(r, f.GetFlowName(), s.ID().String(), s.d); err != nil { return nil, err } diff --git a/selfservice/strategy/lookup/settings.go b/selfservice/strategy/lookup/settings.go index 261336ecdcbc..6f61966e353c 100644 --- a/selfservice/strategy/lookup/settings.go +++ b/selfservice/strategy/lookup/settings.go @@ -108,7 +108,7 @@ func (s *Strategy) Settings(w http.ResponseWriter, r *http.Request, f *settings. if p.RegenerateLookup || p.RevealLookup || p.ConfirmLookup || p.DisableLookup { // This method has only two submit buttons p.Method = s.SettingsStrategyID() - if err := flow.MethodEnabledAndAllowed(r.Context(), s.SettingsStrategyID(), p.Method, s.d); err != nil { + if err := flow.MethodEnabledAndAllowed(r.Context(), f.GetFlowName(), s.SettingsStrategyID(), p.Method, s.d); err != nil { return nil, s.handleSettingsError(w, r, ctxUpdate, &p, err) } } else { @@ -141,7 +141,7 @@ func (s *Strategy) continueSettingsFlow( ctxUpdate *settings.UpdateContext, p *updateSettingsFlowWithLookupMethod, ) error { if p.ConfirmLookup || p.RevealLookup || p.RegenerateLookup || p.DisableLookup { - if err := flow.MethodEnabledAndAllowed(r.Context(), s.SettingsStrategyID(), s.SettingsStrategyID(), s.d); err != nil { + if err := flow.MethodEnabledAndAllowed(r.Context(), flow.SettingsFlow, s.SettingsStrategyID(), s.SettingsStrategyID(), s.d); err != nil { return err } diff --git a/selfservice/strategy/lookup/settings_test.go b/selfservice/strategy/lookup/settings_test.go index 92a81e964971..fce2be4c0974 100644 --- a/selfservice/strategy/lookup/settings_test.go +++ b/selfservice/strategy/lookup/settings_test.go @@ -273,7 +273,7 @@ func TestCompleteSettings(t *testing.T) { t.Run("type=can not confirm without regenerate", func(t *testing.T) { id, codes := createIdentity(t, reg) - var payload = func(v url.Values) { + payload := func(v url.Values) { v.Set(node.LookupConfirm, "true") } @@ -310,7 +310,7 @@ func TestCompleteSettings(t *testing.T) { t.Run("type=regenerate but no confirmation", func(t *testing.T) { id, codes := createIdentity(t, reg) - var payload = func(v url.Values) { + payload := func(v url.Values) { v.Set(node.LookupRegenerate, "true") } @@ -363,13 +363,13 @@ func TestCompleteSettings(t *testing.T) { }, } { t.Run("credentials="+tc.d, func(t *testing.T) { - var payload = func(v url.Values) { + payload := func(v url.Values) { v.Del(node.LookupReveal) v.Del(node.LookupDisable) v.Set(node.LookupRegenerate, "true") } - var payloadConfirm = func(v url.Values) { + payloadConfirm := func(v url.Values) { v.Del(node.LookupRegenerate) v.Del(node.LookupDisable) v.Del(node.LookupReveal) @@ -401,7 +401,7 @@ func TestCompleteSettings(t *testing.T) { assert.Equal(t, http.StatusOK, res.StatusCode) assert.Contains(t, res.Request.URL.String(), publicTS.URL+settings.RouteSubmitFlow) - assert.EqualValues(t, settings.StateSuccess, json.RawMessage(gjson.Get(actual, "state").String())) + assert.EqualValues(t, flow.StateSuccess, json.RawMessage(gjson.Get(actual, "state").String())) checkIdentity(t, id, f) testhelpers.EnsureAAL(t, apiClient, publicTS, "aal2", string(identity.CredentialsTypeLookup)) @@ -427,7 +427,7 @@ func TestCompleteSettings(t *testing.T) { assert.Contains(t, res.Request.URL.String(), uiTS.URL) } - assert.EqualValues(t, settings.StateSuccess, json.RawMessage(gjson.Get(actual, "state").String())) + assert.EqualValues(t, flow.StateSuccess, json.RawMessage(gjson.Get(actual, "state").String())) checkIdentity(t, id, f) testhelpers.EnsureAAL(t, browserClient, publicTS, "aal2", string(identity.CredentialsTypeLookup)) } @@ -463,7 +463,7 @@ func TestCompleteSettings(t *testing.T) { }, } { t.Run("credentials="+tc.d, func(t *testing.T) { - var payloadConfirm = func(v url.Values) { + payloadConfirm := func(v url.Values) { v.Del(node.LookupRegenerate) v.Del(node.LookupReveal) v.Set(node.LookupDisable, "true") @@ -489,7 +489,7 @@ func TestCompleteSettings(t *testing.T) { assert.Equal(t, http.StatusOK, res.StatusCode) assert.Contains(t, res.Request.URL.String(), publicTS.URL+settings.RouteSubmitFlow) - assert.EqualValues(t, settings.StateSuccess, json.RawMessage(gjson.Get(actual, "state").String())) + assert.EqualValues(t, flow.StateSuccess, json.RawMessage(gjson.Get(actual, "state").String())) checkIdentity(t, id, f) testhelpers.EnsureAAL(t, apiClient, publicTS, "aal1") @@ -512,7 +512,7 @@ func TestCompleteSettings(t *testing.T) { assert.Contains(t, res.Request.URL.String(), uiTS.URL) } - assert.EqualValues(t, settings.StateSuccess, json.RawMessage(gjson.Get(actual, "state").String())) + assert.EqualValues(t, flow.StateSuccess, json.RawMessage(gjson.Get(actual, "state").String())) checkIdentity(t, id, f) testhelpers.EnsureAAL(t, browserClient, publicTS, "aal1") } diff --git a/selfservice/strategy/oidc/strategy.go b/selfservice/strategy/oidc/strategy.go index 2639868275c1..1b4f9ca56034 100644 --- a/selfservice/strategy/oidc/strategy.go +++ b/selfservice/strategy/oidc/strategy.go @@ -146,12 +146,15 @@ func generateState(flowID string) *State { Data: x.NewUUID().Bytes(), } } + func (s *State) setCode(code string) { s.Data = sha512.New().Sum([]byte(code)) } + func (s *State) codeMatches(code string) bool { return bytes.Equal(s.Data, sha512.New().Sum([]byte(code))) } + func parseState(s string) (*State, error) { raw, err := base64.RawURLEncoding.DecodeString(s) if err != nil { diff --git a/selfservice/strategy/oidc/strategy_login.go b/selfservice/strategy/oidc/strategy_login.go index 23f4ff60514a..24af92562f5c 100644 --- a/selfservice/strategy/oidc/strategy_login.go +++ b/selfservice/strategy/oidc/strategy_login.go @@ -167,12 +167,12 @@ func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, return nil, s.handleError(w, r, f, "", nil, errors.WithStack(herodot.ErrBadRequest.WithDebug(err.Error()).WithReasonf("Unable to parse HTTP form request: %s", err.Error()))) } - var pid = p.Provider // this can come from both url query and post body + pid := p.Provider // this can come from both url query and post body if pid == "" { return nil, errors.WithStack(flow.ErrStrategyNotResponsible) } - if err := flow.MethodEnabledAndAllowed(r.Context(), s.SettingsStrategyID(), s.SettingsStrategyID(), s.d); err != nil { + if err := flow.MethodEnabledAndAllowed(r.Context(), f.GetFlowName(), s.SettingsStrategyID(), s.SettingsStrategyID(), s.d); err != nil { return nil, s.handleError(w, r, f, pid, nil, err) } diff --git a/selfservice/strategy/oidc/strategy_registration.go b/selfservice/strategy/oidc/strategy_registration.go index 464f4ad5796f..debc45d770db 100644 --- a/selfservice/strategy/oidc/strategy_registration.go +++ b/selfservice/strategy/oidc/strategy_registration.go @@ -137,12 +137,12 @@ func (s *Strategy) Register(w http.ResponseWriter, r *http.Request, f *registrat f.TransientPayload = p.TransientPayload - var pid = p.Provider // this can come from both url query and post body + pid := p.Provider // this can come from both url query and post body if pid == "" { return errors.WithStack(flow.ErrStrategyNotResponsible) } - if err := flow.MethodEnabledAndAllowed(r.Context(), s.SettingsStrategyID(), s.SettingsStrategyID(), s.d); err != nil { + if err := flow.MethodEnabledAndAllowed(r.Context(), f.GetFlowName(), s.SettingsStrategyID(), s.SettingsStrategyID(), s.d); err != nil { return s.handleError(w, r, f, pid, nil, err) } diff --git a/selfservice/strategy/oidc/strategy_settings_test.go b/selfservice/strategy/oidc/strategy_settings_test.go index d7497e567ab3..69f2bc03a560 100644 --- a/selfservice/strategy/oidc/strategy_settings_test.go +++ b/selfservice/strategy/oidc/strategy_settings_test.go @@ -76,41 +76,59 @@ func TestSettingsStrategy(t *testing.T) { // Make test data for this test run unique testID := x.NewUUID().String() users := map[string]*identity.Identity{ - "password": {ID: x.NewUUID(), Traits: identity.Traits(`{"email":"john` + testID + `@doe.com"}`), + "password": { + ID: x.NewUUID(), Traits: identity.Traits(`{"email":"john` + testID + `@doe.com"}`), SchemaID: config.DefaultIdentityTraitsSchemaID, Credentials: map[identity.CredentialsType]identity.Credentials{ - "password": {Type: "password", + "password": { + Type: "password", Identifiers: []string{"john+" + testID + "@doe.com"}, - Config: sqlxx.JSONRawMessage(`{"hashed_password":"$argon2id$iammocked...."}`)}}, + Config: sqlxx.JSONRawMessage(`{"hashed_password":"$argon2id$iammocked...."}`), + }, + }, }, - "oryer": {ID: x.NewUUID(), Traits: identity.Traits(`{"email":"hackerman+` + testID + `@ory.sh"}`), + "oryer": { + ID: x.NewUUID(), Traits: identity.Traits(`{"email":"hackerman+` + testID + `@ory.sh"}`), SchemaID: config.DefaultIdentityTraitsSchemaID, Credentials: map[identity.CredentialsType]identity.Credentials{ - identity.CredentialsTypeOIDC: {Type: identity.CredentialsTypeOIDC, + identity.CredentialsTypeOIDC: { + Type: identity.CredentialsTypeOIDC, Identifiers: []string{"ory:hackerman+" + testID}, - Config: sqlxx.JSONRawMessage(`{"providers":[{"provider":"ory","subject":"hackerman+` + testID + `"}]}`)}}, + Config: sqlxx.JSONRawMessage(`{"providers":[{"provider":"ory","subject":"hackerman+` + testID + `"}]}`), + }, + }, }, - "githuber": {ID: x.NewUUID(), Traits: identity.Traits(`{"email":"hackerman+github+` + testID + `@ory.sh"}`), + "githuber": { + ID: x.NewUUID(), Traits: identity.Traits(`{"email":"hackerman+github+` + testID + `@ory.sh"}`), Credentials: map[identity.CredentialsType]identity.Credentials{ - identity.CredentialsTypeOIDC: {Type: identity.CredentialsTypeOIDC, + identity.CredentialsTypeOIDC: { + Type: identity.CredentialsTypeOIDC, Identifiers: []string{"ory:hackerman+github+" + testID, "github:hackerman+github+" + testID}, - Config: sqlxx.JSONRawMessage(`{"providers":[{"provider":"ory","subject":"hackerman+github+` + testID + `"},{"provider":"github","subject":"hackerman+github+` + testID + `"}]}`)}}, + Config: sqlxx.JSONRawMessage(`{"providers":[{"provider":"ory","subject":"hackerman+github+` + testID + `"},{"provider":"github","subject":"hackerman+github+` + testID + `"}]}`), + }, + }, SchemaID: config.DefaultIdentityTraitsSchemaID, }, - "multiuser": {ID: x.NewUUID(), Traits: identity.Traits(`{"email":"hackerman+multiuser+` + testID + `@ory.sh"}`), + "multiuser": { + ID: x.NewUUID(), Traits: identity.Traits(`{"email":"hackerman+multiuser+` + testID + `@ory.sh"}`), Credentials: map[identity.CredentialsType]identity.Credentials{ - "password": {Type: "password", + "password": { + Type: "password", Identifiers: []string{"hackerman+multiuser+" + testID + "@ory.sh"}, - Config: sqlxx.JSONRawMessage(`{"hashed_password":"$argon2id$iammocked...."}`)}, - identity.CredentialsTypeOIDC: {Type: identity.CredentialsTypeOIDC, + Config: sqlxx.JSONRawMessage(`{"hashed_password":"$argon2id$iammocked...."}`), + }, + identity.CredentialsTypeOIDC: { + Type: identity.CredentialsTypeOIDC, Identifiers: []string{"ory:hackerman+multiuser+" + testID, "google:hackerman+multiuser+" + testID}, - Config: sqlxx.JSONRawMessage(`{"providers":[{"provider":"ory","subject":"hackerman+multiuser+` + testID + `"},{"provider":"google","subject":"hackerman+multiuser+` + testID + `"}]}`)}}, + Config: sqlxx.JSONRawMessage(`{"providers":[{"provider":"ory","subject":"hackerman+multiuser+` + testID + `"},{"provider":"google","subject":"hackerman+multiuser+` + testID + `"}]}`), + }, + }, SchemaID: config.DefaultIdentityTraitsSchemaID, }, } agents := testhelpers.AddAndLoginIdentities(t, reg, publicTS, users) - var newProfileFlow = func(t *testing.T, client *http.Client, redirectTo string, exp time.Duration) *settings.Flow { + newProfileFlow := func(t *testing.T, client *http.Client, redirectTo string, exp time.Duration) *settings.Flow { req, err := reg.SettingsFlowPersister().GetSettingsFlow(context.Background(), x.ParseUUID(string(testhelpers.InitializeSettingsFlowViaBrowser(t, client, false, publicTS).Id))) require.NoError(t, err) @@ -131,7 +149,7 @@ func TestSettingsStrategy(t *testing.T) { } // does the same as new profile request but uses the SDK - var nprSDK = func(t *testing.T, client *http.Client, redirectTo string, exp time.Duration) *kratos.SettingsFlow { + nprSDK := func(t *testing.T, client *http.Client, redirectTo string, exp time.Duration) *kratos.SettingsFlow { return testhelpers.InitializeSettingsFlowViaBrowser(t, client, false, publicTS) } @@ -208,11 +226,11 @@ func TestSettingsStrategy(t *testing.T) { } }) - var action = func(req *kratos.SettingsFlow) string { + action := func(req *kratos.SettingsFlow) string { return req.Ui.Action } - var checkCredentials = func(t *testing.T, shouldExist bool, iid uuid.UUID, provider, subject string, expectTokens bool) { + checkCredentials := func(t *testing.T, shouldExist bool, iid uuid.UUID, provider, subject string, expectTokens bool) { actual, err := reg.PrivilegedIdentityPool().GetIdentityConfidential(context.Background(), iid) require.NoError(t, err) @@ -242,7 +260,7 @@ func TestSettingsStrategy(t *testing.T) { require.EqualValues(t, shouldExist, found) } - var reset = func(t *testing.T) func() { + reset := func(t *testing.T) func() { return func() { conf.MustSet(ctx, config.ViperKeySelfServiceSettingsPrivilegedAuthenticationAfter, time.Minute*5) agents = testhelpers.AddAndLoginIdentities(t, reg, publicTS, users) @@ -250,20 +268,20 @@ func TestSettingsStrategy(t *testing.T) { } t.Run("suite=unlink", func(t *testing.T) { - var unlink = func(t *testing.T, agent, provider string) (body []byte, res *http.Response, req *kratos.SettingsFlow) { + unlink := func(t *testing.T, agent, provider string) (body []byte, res *http.Response, req *kratos.SettingsFlow) { req = nprSDK(t, agents[agent], "", time.Hour) body, res = testhelpers.HTTPPostForm(t, agents[agent], action(req), &url.Values{"csrf_token": {x.FakeCSRFToken}, "unlink": {provider}}) return } - var unlinkInvalid = func(agent, provider, errorMessage string) func(t *testing.T) { + unlinkInvalid := func(agent, provider, errorMessage string) func(t *testing.T) { return func(t *testing.T) { body, res, req := unlink(t, agent, provider) assert.Contains(t, res.Request.URL.String(), uiTS.URL+"/settings?flow="+req.Id) - //assert.EqualValues(t, identity.CredentialsTypeOIDC.String(), gjson.GetBytes(body, "active").String()) + // assert.EqualValues(t, identity.CredentialsTypeOIDC.String(), gjson.GetBytes(body, "active").String()) // The original options to link google and github are still there t.Run("flow=fetch", func(t *testing.T) { @@ -302,7 +320,7 @@ func TestSettingsStrategy(t *testing.T) { t.Run("case=should not be able to unlink a connection without a privileged session", func(t *testing.T) { agent, provider := "githuber", "github" - var runUnauthed = func(t *testing.T) *kratos.SettingsFlow { + runUnauthed := func(t *testing.T) *kratos.SettingsFlow { conf.MustSet(ctx, config.ViperKeySelfServiceSettingsPrivilegedAuthenticationAfter, time.Millisecond) time.Sleep(time.Millisecond) t.Cleanup(reset(t)) @@ -311,7 +329,7 @@ func TestSettingsStrategy(t *testing.T) { rs, _, err := testhelpers.NewSDKCustomClient(publicTS, agents[agent]).FrontendApi.GetSettingsFlow(context.Background()).Id(req.Id).Execute() require.NoError(t, err) - require.EqualValues(t, settings.StateShowForm, rs.State) + require.EqualValues(t, flow.StateShowForm, rs.State) checkCredentials(t, true, users[agent].ID, provider, "hackerman+github+"+testID, false) @@ -340,19 +358,19 @@ func TestSettingsStrategy(t *testing.T) { }) t.Run("suite=link", func(t *testing.T) { - var link = func(t *testing.T, agent, provider string) (body []byte, res *http.Response, req *kratos.SettingsFlow) { + link := func(t *testing.T, agent, provider string) (body []byte, res *http.Response, req *kratos.SettingsFlow) { req = nprSDK(t, agents[agent], "", time.Hour) body, res = testhelpers.HTTPPostForm(t, agents[agent], action(req), &url.Values{"csrf_token": {x.FakeCSRFToken}, "link": {provider}}) return } - var linkInvalid = func(agent, provider string) func(t *testing.T) { + linkInvalid := func(agent, provider string) func(t *testing.T) { return func(t *testing.T) { body, res, req := link(t, agent, provider) assert.Contains(t, res.Request.URL.String(), uiTS.URL+"/settings?flow="+req.Id) - //assert.EqualValues(t, identity.CredentialsTypeOIDC.String(), gjson.GetBytes(body, "active").String()) + // assert.EqualValues(t, identity.CredentialsTypeOIDC.String(), gjson.GetBytes(body, "active").String()) assert.Contains(t, gjson.GetBytes(body, "ui.action").String(), publicTS.URL+settings.RouteSubmitFlow+"?flow=") // The original options to link google and github are still there @@ -427,7 +445,7 @@ func TestSettingsStrategy(t *testing.T) { updatedFlowSDK, _, err := testhelpers.NewSDKCustomClient(publicTS, agents[agent]).FrontendApi.GetSettingsFlow(context.Background()).Id(originalFlow.Id).Execute() require.NoError(t, err) - require.EqualValues(t, settings.StateSuccess, updatedFlowSDK.State) + require.EqualValues(t, flow.StateSuccess, updatedFlowSDK.State) t.Run("flow=original", func(t *testing.T) { snapshotx.SnapshotTExcept(t, originalFlow.Ui.Nodes, []string{"0.attributes.value", "1.attributes.value"}) @@ -454,7 +472,7 @@ func TestSettingsStrategy(t *testing.T) { rs, _, err := testhelpers.NewSDKCustomClient(publicTS, agents[agent]).FrontendApi.GetSettingsFlow(context.Background()).Id(req.Id).Execute() require.NoError(t, err) - require.EqualValues(t, settings.StateSuccess, rs.State) + require.EqualValues(t, flow.StateSuccess, rs.State) snapshotx.SnapshotTExcept(t, rs.Ui.Nodes, []string{"0.attributes.value", "1.attributes.value"}) @@ -529,7 +547,7 @@ func TestSettingsStrategy(t *testing.T) { agent, provider := "githuber", "google" subject = "hackerman+new+google+" + testID - var runUnauthed = func(t *testing.T) *kratos.SettingsFlow { + runUnauthed := func(t *testing.T) *kratos.SettingsFlow { conf.MustSet(ctx, config.ViperKeySelfServiceSettingsPrivilegedAuthenticationAfter, time.Millisecond) time.Sleep(time.Millisecond) t.Cleanup(reset(t)) @@ -538,7 +556,7 @@ func TestSettingsStrategy(t *testing.T) { rs, _, err := testhelpers.NewSDKCustomClient(publicTS, agents[agent]).FrontendApi.GetSettingsFlow(context.Background()).Id(req.Id).Execute() require.NoError(t, err) - require.EqualValues(t, settings.StateShowForm, rs.State) + require.EqualValues(t, flow.StateShowForm, rs.State) checkCredentials(t, false, users[agent].ID, provider, subject, true) @@ -675,10 +693,12 @@ func TestPopulateSettingsMethod(t *testing.T) { oidc.NewUnlinkNode("google"), }, withpw: true, - i: &identity.Credentials{Type: identity.CredentialsTypeOIDC, Identifiers: []string{ - "google:1234", + i: &identity.Credentials{ + Type: identity.CredentialsTypeOIDC, Identifiers: []string{ + "google:1234", + }, + Config: []byte(`{"providers":[{"provider":"google","subject":"1234"}]}`), }, - Config: []byte(`{"providers":[{"provider":"google","subject":"1234"}]}`)}, }, { c: defaultConfig, @@ -688,11 +708,13 @@ func TestPopulateSettingsMethod(t *testing.T) { oidc.NewUnlinkNode("google"), oidc.NewUnlinkNode("facebook"), }, - i: &identity.Credentials{Type: identity.CredentialsTypeOIDC, Identifiers: []string{ - "google:1234", - "facebook:1234", + i: &identity.Credentials{ + Type: identity.CredentialsTypeOIDC, Identifiers: []string{ + "google:1234", + "facebook:1234", + }, + Config: []byte(`{"providers":[{"provider":"google","subject":"1234"},{"provider":"facebook","subject":"1234"}]}`), }, - Config: []byte(`{"providers":[{"provider":"google","subject":"1234"},{"provider":"facebook","subject":"1234"}]}`)}, }, } { t.Run("iteration="+strconv.Itoa(k), func(t *testing.T) { diff --git a/selfservice/strategy/password/login.go b/selfservice/strategy/password/login.go index 30010b80eb54..7a56ebaf45d4 100644 --- a/selfservice/strategy/password/login.go +++ b/selfservice/strategy/password/login.go @@ -51,7 +51,7 @@ func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, return nil, err } - if err := flow.MethodEnabledAndAllowedFromRequest(r, s.ID().String(), s.d); err != nil { + if err := flow.MethodEnabledAndAllowedFromRequest(r, f.GetFlowName(), s.ID().String(), s.d); err != nil { return nil, err } diff --git a/selfservice/strategy/password/registration.go b/selfservice/strategy/password/registration.go index 5fa174f48cbc..b49ff630e458 100644 --- a/selfservice/strategy/password/registration.go +++ b/selfservice/strategy/password/registration.go @@ -78,7 +78,7 @@ func (s *Strategy) decode(p *UpdateRegistrationFlowWithPasswordMethod, r *http.R } func (s *Strategy) Register(w http.ResponseWriter, r *http.Request, f *registration.Flow, i *identity.Identity) (err error) { - if err := flow.MethodEnabledAndAllowedFromRequest(r, s.ID().String(), s.d); err != nil { + if err := flow.MethodEnabledAndAllowedFromRequest(r, f.GetFlowName(), s.ID().String(), s.d); err != nil { return err } diff --git a/selfservice/strategy/password/registration_test.go b/selfservice/strategy/password/registration_test.go index dacdef8c9ff2..1587888e0168 100644 --- a/selfservice/strategy/password/registration_test.go +++ b/selfservice/strategy/password/registration_test.go @@ -50,8 +50,8 @@ func newRegistrationRegistry(t *testing.T) *driver.RegistryDefault { } func TestRegistration(t *testing.T) { - ctx := context.Background() + t.Run("case=registration", func(t *testing.T) { reg := newRegistrationRegistry(t) conf := reg.Config() diff --git a/selfservice/strategy/password/settings.go b/selfservice/strategy/password/settings.go index 45e6bc045650..4ba0b115e53a 100644 --- a/selfservice/strategy/password/settings.go +++ b/selfservice/strategy/password/settings.go @@ -75,7 +75,7 @@ func (s *Strategy) Settings(w http.ResponseWriter, r *http.Request, f *settings. return ctxUpdate, s.handleSettingsError(w, r, ctxUpdate, &p, err) } - if err := flow.MethodEnabledAndAllowedFromRequest(r, s.SettingsStrategyID(), s.d); err != nil { + if err := flow.MethodEnabledAndAllowedFromRequest(r, f.GetFlowName(), s.SettingsStrategyID(), s.d); err != nil { return ctxUpdate, s.handleSettingsError(w, r, ctxUpdate, &p, err) } @@ -109,7 +109,7 @@ func (s *Strategy) continueSettingsFlow( w http.ResponseWriter, r *http.Request, ctxUpdate *settings.UpdateContext, p *updateSettingsFlowWithPasswordMethod, ) error { - if err := flow.MethodEnabledAndAllowed(r.Context(), s.SettingsStrategyID(), p.Method, s.d); err != nil { + if err := flow.MethodEnabledAndAllowed(r.Context(), flow.SettingsFlow, s.SettingsStrategyID(), p.Method, s.d); err != nil { return err } diff --git a/selfservice/strategy/password/strategy.go b/selfservice/strategy/password/strategy.go index 1e64544edee1..2993c428b701 100644 --- a/selfservice/strategy/password/strategy.go +++ b/selfservice/strategy/password/strategy.go @@ -26,9 +26,11 @@ import ( "github.com/ory/kratos/x" ) -var _ login.Strategy = new(Strategy) -var _ registration.Strategy = new(Strategy) -var _ identity.ActiveCredentialsCounter = new(Strategy) +var ( + _ login.Strategy = new(Strategy) + _ registration.Strategy = new(Strategy) + _ identity.ActiveCredentialsCounter = new(Strategy) +) type registrationStrategyDependencies interface { x.LoggingProvider diff --git a/selfservice/strategy/profile/strategy.go b/selfservice/strategy/profile/strategy.go index 5c4a68be9a78..e94d779aef61 100644 --- a/selfservice/strategy/profile/strategy.go +++ b/selfservice/strategy/profile/strategy.go @@ -116,7 +116,7 @@ func (s *Strategy) Settings(w http.ResponseWriter, r *http.Request, f *settings. return ctxUpdate, s.handleSettingsError(w, r, ctxUpdate, nil, &p, err) } - if err := flow.MethodEnabledAndAllowedFromRequest(r, s.SettingsStrategyID(), s.d); err != nil { + if err := flow.MethodEnabledAndAllowedFromRequest(r, f.GetFlowName(), s.SettingsStrategyID(), s.d); err != nil { return ctxUpdate, err } @@ -144,7 +144,7 @@ func (s *Strategy) Settings(w http.ResponseWriter, r *http.Request, f *settings. } func (s *Strategy) continueFlow(w http.ResponseWriter, r *http.Request, ctxUpdate *settings.UpdateContext, p *updateSettingsFlowWithProfileMethod) error { - if err := flow.MethodEnabledAndAllowed(r.Context(), s.SettingsStrategyID(), p.Method, s.d); err != nil { + if err := flow.MethodEnabledAndAllowed(r.Context(), flow.SettingsFlow, s.SettingsStrategyID(), p.Method, s.d); err != nil { return err } diff --git a/selfservice/strategy/profile/strategy_test.go b/selfservice/strategy/profile/strategy_test.go index bb09a2b925a0..f67407fe799f 100644 --- a/selfservice/strategy/profile/strategy_test.go +++ b/selfservice/strategy/profile/strategy_test.go @@ -32,6 +32,7 @@ import ( "github.com/ory/kratos/identity" "github.com/ory/kratos/internal" "github.com/ory/kratos/internal/testhelpers" + "github.com/ory/kratos/selfservice/flow" "github.com/ory/kratos/selfservice/flow/settings" "github.com/ory/kratos/x" "github.com/ory/x/assertx" @@ -189,7 +190,7 @@ func TestStrategyTraits(t *testing.T) { t.Run("description=hydrate the proper fields", func(t *testing.T) { setPrivileged(t) - var run = func(t *testing.T, id *identity.Identity, payload *kratos.SettingsFlow, route string) { + run := func(t *testing.T, id *identity.Identity, payload *kratos.SettingsFlow, route string) { assert.NotEmpty(t, payload.Identity) assert.Equal(t, id.ID.String(), string(payload.Identity.Id)) assert.JSONEq(t, string(id.Traits), x.MustEncodeJSON(t, payload.Identity.Traits)) @@ -230,7 +231,7 @@ func TestStrategyTraits(t *testing.T) { }) }) - var expectValidationError = func(t *testing.T, isAPI, isSPA bool, hc *http.Client, values func(url.Values)) string { + expectValidationError := func(t *testing.T, isAPI, isSPA bool, hc *http.Client, values func(url.Values)) string { return testhelpers.SubmitSettingsForm(t, isAPI, isSPA, hc, publicTS, values, testhelpers.ExpectStatusCode(isAPI || isSPA, http.StatusBadRequest, http.StatusOK), testhelpers.ExpectURL(isAPI || isSPA, publicTS.URL+settings.RouteSubmitFlow, conf.SelfServiceFlowSettingsUI(ctx).String())) @@ -239,7 +240,7 @@ func TestStrategyTraits(t *testing.T) { t.Run("description=should come back with form errors if some profile data is invalid", func(t *testing.T) { setPrivileged(t) - var check = func(t *testing.T, actual string) { + check := func(t *testing.T, actual string) { assert.NotEmpty(t, gjson.Get(actual, "ui.nodes.#(attributes.name==csrf_token).attributes.value").String(), "%s", actual) assert.Equal(t, "too-short", gjson.Get(actual, "ui.nodes.#(attributes.name==traits.should_long_string).attributes.value").String(), "%s", actual) assert.Equal(t, "bazbar", gjson.Get(actual, "ui.nodes.#(attributes.name==traits.stringy).attributes.value").String(), "%s", actual) @@ -247,7 +248,7 @@ func TestStrategyTraits(t *testing.T) { assert.Equal(t, "length must be >= 25, but got 9", gjson.Get(actual, "ui.nodes.#(attributes.name==traits.should_long_string).messages.0.text").String(), "%s", actual) } - var payload = func(v url.Values) { + payload := func(v url.Values) { v.Set("method", "profile") v.Set("traits.should_long_string", "too-short") v.Set("traits.stringy", "bazbar") @@ -298,7 +299,7 @@ func TestStrategyTraits(t *testing.T) { }) t.Run("description=should end up at the login endpoint if trying to update protected field without sudo mode", func(t *testing.T) { - var run = func(t *testing.T, config *kratos.SettingsFlow, isAPI bool, c *http.Client) *http.Response { + run := func(t *testing.T, config *kratos.SettingsFlow, isAPI bool, c *http.Client) *http.Response { time.Sleep(time.Millisecond) values := testhelpers.SDKFormFieldsToURLValues(config.Ui.Nodes) @@ -343,7 +344,7 @@ func TestStrategyTraits(t *testing.T) { defer res.Body.Close() assert.EqualValues(t, http.StatusOK, res.StatusCode, "%s", body) - assert.EqualValues(t, settings.StateSuccess, gjson.GetBytes(body, "state").String(), "%s", body) + assert.EqualValues(t, flow.StateSuccess, gjson.GetBytes(body, "state").String(), "%s", body) }) }) }) @@ -351,14 +352,14 @@ func TestStrategyTraits(t *testing.T) { t.Run("flow=fail first update", func(t *testing.T) { setPrivileged(t) - var check = func(t *testing.T, actual string) { - assert.EqualValues(t, settings.StateShowForm, gjson.Get(actual, "state").String(), "%s", actual) + check := func(t *testing.T, actual string) { + assert.EqualValues(t, flow.StateShowForm, gjson.Get(actual, "state").String(), "%s", actual) assert.Equal(t, "1", gjson.Get(actual, "ui.nodes.#(attributes.name==traits.should_big_number).attributes.value").String(), "%s", actual) assert.Equal(t, "must be >= 1200 but found 1", gjson.Get(actual, "ui.nodes.#(attributes.name==traits.should_big_number).messages.0.text").String(), "%s", actual) assert.Equal(t, "foobar", gjson.Get(actual, "ui.nodes.#(attributes.name==traits.stringy).attributes.value").String(), "%s", actual) // sanity check if original payload is still here } - var payload = func(v url.Values) { + payload := func(v url.Values) { v.Set("method", settings.StrategyProfile) v.Set("traits.should_big_number", "1") } @@ -379,8 +380,8 @@ func TestStrategyTraits(t *testing.T) { t.Run("flow=fail second update", func(t *testing.T) { setPrivileged(t) - var check = func(t *testing.T, actual string) { - assert.EqualValues(t, settings.StateShowForm, gjson.Get(actual, "state").String(), "%s", actual) + check := func(t *testing.T, actual string) { + assert.EqualValues(t, flow.StateShowForm, gjson.Get(actual, "state").String(), "%s", actual) assert.Empty(t, gjson.Get(actual, "ui.nodes.#(attributes.name==traits.should_big_number).messages.0.text").String(), "%s", actual) assert.Empty(t, gjson.Get(actual, "ui.nodes.#(attributes.name==traits.should_big_number).attributes.value").String(), "%s", actual) @@ -394,7 +395,7 @@ func TestStrategyTraits(t *testing.T) { assert.Equal(t, "foobar", gjson.Get(actual, "ui.nodes.#(attributes.name==traits.stringy).attributes.value").String(), "%s", actual) // sanity check if original payload is still here } - var payload = func(v url.Values) { + payload := func(v url.Values) { v.Set("method", settings.StrategyProfile) v.Del("traits.should_big_number") v.Set("traits.should_long_string", "short") @@ -414,7 +415,7 @@ func TestStrategyTraits(t *testing.T) { }) }) - var expectSuccess = func(t *testing.T, isAPI, isSPA bool, hc *http.Client, values func(url.Values)) string { + expectSuccess := func(t *testing.T, isAPI, isSPA bool, hc *http.Client, values func(url.Values)) string { return testhelpers.SubmitSettingsForm(t, isAPI, isSPA, hc, publicTS, values, http.StatusOK, testhelpers.ExpectURL(isAPI || isSPA, publicTS.URL+settings.RouteSubmitFlow, conf.SelfServiceFlowSettingsUI(ctx).String())) @@ -423,8 +424,8 @@ func TestStrategyTraits(t *testing.T) { t.Run("flow=succeed with final request", func(t *testing.T) { setPrivileged(t) - var check = func(t *testing.T, actual string) { - assert.EqualValues(t, settings.StateSuccess, gjson.Get(actual, "state").String(), "%s", actual) + check := func(t *testing.T, actual string) { + assert.EqualValues(t, flow.StateSuccess, gjson.Get(actual, "state").String(), "%s", actual) assert.Empty(t, gjson.Get(actual, "ui.nodes.#(attributes.name==traits.numby).attributes.errors").Value(), "%s", actual) assert.Empty(t, gjson.Get(actual, "ui.nodes.#(attributes.name==traits.should_big_number).attributes.errors").Value(), "%s", actual) @@ -435,7 +436,7 @@ func TestStrategyTraits(t *testing.T) { assert.Equal(t, "this is such a long string, amazing stuff!", gjson.Get(actual, "ui.nodes.#(attributes.name==traits.should_long_string).attributes.value").Value(), "%s", actual) } - var payload = func(newEmail string) func(v url.Values) { + payload := func(newEmail string) func(v url.Values) { return func(v url.Values) { v.Set("method", settings.StrategyProfile) v.Set("traits.email", newEmail) @@ -463,11 +464,11 @@ func TestStrategyTraits(t *testing.T) { t.Run("flow=try another update with invalid data", func(t *testing.T) { setPrivileged(t) - var check = func(t *testing.T, actual string) { - assert.EqualValues(t, settings.StateShowForm, gjson.Get(actual, "state").String(), "%s", actual) + check := func(t *testing.T, actual string) { + assert.EqualValues(t, flow.StateShowForm, gjson.Get(actual, "state").String(), "%s", actual) } - var payload = func(v url.Values) { + payload := func(v url.Values) { v.Set("method", settings.StrategyProfile) v.Set("traits.should_long_string", "short") } @@ -526,8 +527,8 @@ func TestStrategyTraits(t *testing.T) { conf.MustSet(ctx, config.HookStrategyKey(config.ViperKeySelfServiceSettingsAfter, settings.StrategyProfile), nil) }) - var check = func(t *testing.T, actual, newEmail string) { - assert.EqualValues(t, settings.StateSuccess, gjson.Get(actual, "state").String(), "%s", actual) + check := func(t *testing.T, actual, newEmail string) { + assert.EqualValues(t, flow.StateSuccess, gjson.Get(actual, "state").String(), "%s", actual) assert.Equal(t, newEmail, gjson.Get(actual, "ui.nodes.#(attributes.name==traits.email).attributes.value").Value(), "%s", actual) m, err := reg.CourierPersister().LatestQueuedMessage(context.Background()) @@ -535,7 +536,7 @@ func TestStrategyTraits(t *testing.T) { assert.Contains(t, m.Subject, "verify your email address") } - var payload = func(newEmail string) func(v url.Values) { + payload := func(newEmail string) func(v url.Values) { return func(v url.Values) { v.Set("method", settings.StrategyProfile) v.Set("traits.email", newEmail) @@ -564,8 +565,8 @@ func TestStrategyTraits(t *testing.T) { t.Run("description=should update protected field with sudo mode", func(t *testing.T) { setPrivileged(t) - var check = func(t *testing.T, newEmail string, actual string) { - assert.EqualValues(t, settings.StateSuccess, gjson.Get(actual, "state").String(), "%s", actual) + check := func(t *testing.T, newEmail string, actual string) { + assert.EqualValues(t, flow.StateSuccess, gjson.Get(actual, "state").String(), "%s", actual) assert.Empty(t, gjson.Get(actual, "ui.nodes.#(attributes.name==traits.numby).attributes.errors").Value(), "%s", actual) assert.Empty(t, gjson.Get(actual, "ui.nodes.#(attributes.name==traits.should_big_number).attributes.errors").Value(), "%s", actual) assert.Empty(t, gjson.Get(actual, "ui.nodes.#(attributes.name==traits.should_long_string).attributes.errors").Value(), "%s", actual) @@ -573,7 +574,7 @@ func TestStrategyTraits(t *testing.T) { assert.Equal(t, "foobar", gjson.Get(actual, "ui.nodes.#(attributes.name==traits.stringy).attributes.value").String(), "%s", actual) // sanity check if original payload is still here } - var payload = func(email string) func(v url.Values) { + payload := func(email string) func(v url.Values) { return func(v url.Values) { v.Set("method", settings.StrategyProfile) v.Set("traits.email", email) diff --git a/selfservice/strategy/totp/login.go b/selfservice/strategy/totp/login.go index e3840eba1b9b..bc9816d265f3 100644 --- a/selfservice/strategy/totp/login.go +++ b/selfservice/strategy/totp/login.go @@ -90,7 +90,7 @@ func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, return nil, err } - if err := flow.MethodEnabledAndAllowedFromRequest(r, s.ID().String(), s.d); err != nil { + if err := flow.MethodEnabledAndAllowedFromRequest(r, f.GetFlowName(), s.ID().String(), s.d); err != nil { return nil, err } diff --git a/selfservice/strategy/totp/settings.go b/selfservice/strategy/totp/settings.go index 928c288be365..0587e87e2d6a 100644 --- a/selfservice/strategy/totp/settings.go +++ b/selfservice/strategy/totp/settings.go @@ -94,10 +94,10 @@ func (s *Strategy) Settings(w http.ResponseWriter, r *http.Request, f *settings. if p.UnlinkTOTP { // This is a submit so we need to manually set the type to TOTP p.Method = s.SettingsStrategyID() - if err := flow.MethodEnabledAndAllowed(r.Context(), s.SettingsStrategyID(), p.Method, s.d); err != nil { + if err := flow.MethodEnabledAndAllowed(r.Context(), f.GetFlowName(), s.SettingsStrategyID(), p.Method, s.d); err != nil { return nil, s.handleSettingsError(w, r, ctxUpdate, &p, err) } - } else if err := flow.MethodEnabledAndAllowedFromRequest(r, s.SettingsStrategyID(), s.d); err != nil { + } else if err := flow.MethodEnabledAndAllowedFromRequest(r, f.GetFlowName(), s.SettingsStrategyID(), s.d); err != nil { return ctxUpdate, s.handleSettingsError(w, r, ctxUpdate, &p, err) } @@ -127,7 +127,7 @@ func (s *Strategy) continueSettingsFlow( w http.ResponseWriter, r *http.Request, ctxUpdate *settings.UpdateContext, p *updateSettingsFlowWithTotpMethod, ) error { - if err := flow.MethodEnabledAndAllowed(r.Context(), s.SettingsStrategyID(), p.Method, s.d); err != nil { + if err := flow.MethodEnabledAndAllowed(r.Context(), flow.SettingsFlow, s.SettingsStrategyID(), p.Method, s.d); err != nil { return err } diff --git a/selfservice/strategy/totp/settings_test.go b/selfservice/strategy/totp/settings_test.go index b9b294ffdf4e..0fd479f1b220 100644 --- a/selfservice/strategy/totp/settings_test.go +++ b/selfservice/strategy/totp/settings_test.go @@ -148,7 +148,7 @@ func TestCompleteSettings(t *testing.T) { }) id, _, key := createIdentity(t, reg) - var payload = func(v url.Values) { + payload := func(v url.Values) { v.Set("totp_unlink", "true") } @@ -190,7 +190,7 @@ func TestCompleteSettings(t *testing.T) { }) id := createIdentityWithoutTOTP(t, reg) - var payload = func(v url.Values) { + payload := func(v url.Values) { v.Set(node.TOTPCode, "111111") } @@ -225,7 +225,7 @@ func TestCompleteSettings(t *testing.T) { }) t.Run("type=unlink TOTP device", func(t *testing.T) { - var payload = func(v url.Values) { + payload := func(v url.Values) { v.Set("totp_unlink", "true") } @@ -239,7 +239,7 @@ func TestCompleteSettings(t *testing.T) { actual, res := doAPIFlow(t, payload, id) assert.Equal(t, http.StatusOK, res.StatusCode) assert.Contains(t, res.Request.URL.String(), publicTS.URL+settings.RouteSubmitFlow) - assert.EqualValues(t, settings.StateSuccess, gjson.Get(actual, "state").String(), actual) + assert.EqualValues(t, flow.StateSuccess, gjson.Get(actual, "state").String(), actual) checkIdentity(t, id) }) @@ -248,7 +248,7 @@ func TestCompleteSettings(t *testing.T) { actual, res := doBrowserFlow(t, true, payload, id) assert.Equal(t, http.StatusOK, res.StatusCode) assert.Contains(t, res.Request.URL.String(), publicTS.URL+settings.RouteSubmitFlow) - assert.EqualValues(t, settings.StateSuccess, gjson.Get(actual, "state").String(), actual) + assert.EqualValues(t, flow.StateSuccess, gjson.Get(actual, "state").String(), actual) checkIdentity(t, id) }) @@ -257,13 +257,13 @@ func TestCompleteSettings(t *testing.T) { actual, res := doBrowserFlow(t, false, payload, id) assert.Equal(t, http.StatusOK, res.StatusCode) assert.Contains(t, res.Request.URL.String(), uiTS.URL) - assert.EqualValues(t, settings.StateSuccess, gjson.Get(actual, "state").String(), actual) + assert.EqualValues(t, flow.StateSuccess, gjson.Get(actual, "state").String(), actual) checkIdentity(t, id) }) }) t.Run("type=set up TOTP device but code is incorrect", func(t *testing.T) { - var payload = func(v url.Values) { + payload := func(v url.Values) { v.Set(node.TOTPCode, "111111") } @@ -332,10 +332,10 @@ func TestCompleteSettings(t *testing.T) { if isAPI || isSPA { assert.Contains(t, res.Request.URL.String(), publicTS.URL+settings.RouteSubmitFlow) - assert.EqualValues(t, settings.StateSuccess, gjson.Get(actual, "state").String(), actual) + assert.EqualValues(t, flow.StateSuccess, gjson.Get(actual, "state").String(), actual) } else { assert.Contains(t, res.Request.URL.String(), uiTS.URL) - assert.EqualValues(t, settings.StateSuccess, gjson.Get(actual, "state").String(), actual) + assert.EqualValues(t, flow.StateSuccess, gjson.Get(actual, "state").String(), actual) } actualFlow, err := reg.SettingsFlowPersister().GetSettingsFlow(context.Background(), uuid.FromStringOrNil(f.Id)) 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 815e99cb456b..a12f8fc0e182 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 @@ -82,5 +82,6 @@ ] }, "refresh": false, - "requested_aal": "aal1" + "requested_aal": "aal1", + "state": "choose_method" } 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 815e99cb456b..a12f8fc0e182 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 @@ -82,5 +82,6 @@ ] }, "refresh": false, - "requested_aal": "aal1" + "requested_aal": "aal1", + "state": "choose_method" } diff --git a/selfservice/strategy/webauthn/login.go b/selfservice/strategy/webauthn/login.go index 58cf7b0f25a1..200fdcea2280 100644 --- a/selfservice/strategy/webauthn/login.go +++ b/selfservice/strategy/webauthn/login.go @@ -211,7 +211,7 @@ func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, return nil, flow.ErrStrategyNotResponsible } - if err := flow.MethodEnabledAndAllowed(r.Context(), s.SettingsStrategyID(), p.Method, s.d); err != nil { + if err := flow.MethodEnabledAndAllowed(r.Context(), f.GetFlowName(), s.SettingsStrategyID(), p.Method, s.d); err != nil { return nil, s.handleLoginError(r, f, err) } diff --git a/selfservice/strategy/webauthn/registration.go b/selfservice/strategy/webauthn/registration.go index fab8e2cb77c5..565125319634 100644 --- a/selfservice/strategy/webauthn/registration.go +++ b/selfservice/strategy/webauthn/registration.go @@ -113,7 +113,7 @@ func (s *Strategy) Register(w http.ResponseWriter, r *http.Request, f *registrat } p.Method = s.SettingsStrategyID() - if err := flow.MethodEnabledAndAllowed(r.Context(), s.SettingsStrategyID(), p.Method, s.d); err != nil { + if err := flow.MethodEnabledAndAllowed(r.Context(), f.GetFlowName(), s.SettingsStrategyID(), p.Method, s.d); err != nil { return s.handleRegistrationError(w, r, f, &p, err) } diff --git a/selfservice/strategy/webauthn/settings.go b/selfservice/strategy/webauthn/settings.go index ad00289c010a..51fbcf0f5adb 100644 --- a/selfservice/strategy/webauthn/settings.go +++ b/selfservice/strategy/webauthn/settings.go @@ -112,7 +112,7 @@ func (s *Strategy) Settings(w http.ResponseWriter, r *http.Request, f *settings. if len(p.Register+p.Remove) > 0 { // This method has only two submit buttons p.Method = s.SettingsStrategyID() - if err := flow.MethodEnabledAndAllowed(r.Context(), s.SettingsStrategyID(), p.Method, s.d); err != nil { + if err := flow.MethodEnabledAndAllowed(r.Context(), f.GetFlowName(), s.SettingsStrategyID(), p.Method, s.d); err != nil { return nil, s.handleSettingsError(w, r, ctxUpdate, &p, err) } } else { @@ -146,7 +146,7 @@ func (s *Strategy) continueSettingsFlow( ctxUpdate *settings.UpdateContext, p *updateSettingsFlowWithWebAuthnMethod, ) error { if len(p.Register+p.Remove) > 0 { - if err := flow.MethodEnabledAndAllowed(r.Context(), s.SettingsStrategyID(), s.SettingsStrategyID(), s.d); err != nil { + if err := flow.MethodEnabledAndAllowed(r.Context(), flow.SettingsFlow, s.SettingsStrategyID(), s.SettingsStrategyID(), s.d); err != nil { return err } diff --git a/selfservice/strategy/webauthn/settings_test.go b/selfservice/strategy/webauthn/settings_test.go index 04f571e7ab5e..27413df38b16 100644 --- a/selfservice/strategy/webauthn/settings_test.go +++ b/selfservice/strategy/webauthn/settings_test.go @@ -334,7 +334,7 @@ func TestCompleteSettings(t *testing.T) { } else { assert.Contains(t, res.Request.URL.String(), uiTS.URL) } - assert.EqualValues(t, settings.StateSuccess, gjson.Get(body, "state").String(), body) + assert.EqualValues(t, flow.StateSuccess, gjson.Get(body, "state").String(), body) actual, err := reg.Persister().GetIdentityConfidential(context.Background(), id.ID) require.NoError(t, err) @@ -386,7 +386,7 @@ func TestCompleteSettings(t *testing.T) { } t.Run("response", func(t *testing.T) { - assert.EqualValues(t, settings.StateShowForm, gjson.Get(body, "state").String(), body) + assert.EqualValues(t, flow.StateShowForm, gjson.Get(body, "state").String(), body) snapshotx.SnapshotTExcept(t, json.RawMessage(gjson.Get(body, "ui.nodes.#(attributes.name==webauthn_remove)").String()), nil) actual, err := reg.Persister().GetIdentityConfidential(context.Background(), id.ID) @@ -426,7 +426,7 @@ func TestCompleteSettings(t *testing.T) { } t.Run("response", func(t *testing.T) { - assert.EqualValues(t, settings.StateSuccess, gjson.Get(body, "state").String(), body) + assert.EqualValues(t, flow.StateSuccess, gjson.Get(body, "state").String(), body) actual, err := reg.Persister().GetIdentityConfidential(context.Background(), id.ID) require.NoError(t, err) _, ok := actual.GetCredentials(identity.CredentialsTypeWebAuthn) @@ -463,7 +463,7 @@ func TestCompleteSettings(t *testing.T) { } else { assert.Contains(t, res.Request.URL.String(), uiTS.URL) } - assert.EqualValues(t, settings.StateSuccess, gjson.Get(body, "state").String(), body) + assert.EqualValues(t, flow.StateSuccess, gjson.Get(body, "state").String(), body) } actual, err := reg.Persister().GetIdentityConfidential(context.Background(), id.ID) @@ -496,7 +496,7 @@ func TestCompleteSettings(t *testing.T) { } else { assert.Contains(t, res.Request.URL.String(), uiTS.URL) } - assert.EqualValues(t, settings.StateSuccess, json.RawMessage(gjson.Get(body, "state").String())) + assert.EqualValues(t, flow.StateSuccess, json.RawMessage(gjson.Get(body, "state").String())) actual, err := reg.Persister().GetIdentityConfidential(context.Background(), id.ID) require.NoError(t, err) diff --git a/spec/api.json b/spec/api.json old mode 100755 new mode 100644 index d1973e17f7fd..005fef8d643d --- a/spec/api.json +++ b/spec/api.json @@ -81,6 +81,9 @@ } }, "schemas": { + "CodeAddressType": { + "type": "string" + }, "DefaultError": {}, "Duration": { "description": "A Duration represents the elapsed time between two instants\nas an int64 nanosecond count. The representation limits the\nlargest representable duration to approximately 290 years.", @@ -906,6 +909,18 @@ }, "type": "object" }, + "identityCredentialsCode": { + "description": "CredentialsCode represents a one time login/registration code", + "properties": { + "address_type": { + "$ref": "#/components/schemas/CodeAddressType" + }, + "used_at": { + "$ref": "#/components/schemas/NullTime" + } + }, + "type": "object" + }, "identityCredentialsOidc": { "properties": { "providers": { @@ -956,7 +971,8 @@ "totp", "oidc", "webauthn", - "lookup_secret" + "lookup_secret", + "code" ], "title": "CredentialsType represents several different credential types, like password credentials, passwordless credentials,", "type": "string" @@ -1209,6 +1225,9 @@ "description": "SessionTokenExchangeCode holds the secret code that the client can use to retrieve a session token after the login flow has been completed.\nThis is only set if the client has requested a session token exchange code, and if the flow is of type \"api\",\nand only on creating the login flow.", "type": "string" }, + "state": { + "description": "State represents the state of this request:\n\nchoose_method: ask the user to choose a method to sign in with\nsent_email: the email has been sent to the user\npassed_challenge: the request was successful and the login challenge was passed." + }, "type": { "$ref": "#/components/schemas/selfServiceFlowType" }, @@ -1227,11 +1246,21 @@ "expires_at", "issued_at", "request_url", - "ui" + "ui", + "state" ], "title": "Login Flow", "type": "object" }, + "loginFlowState": { + "description": "The state represents the state of the login flow.\n\nchoose_method: ask the user to choose a method (e.g. login account via email)\nsent_email: the email has been sent to the user\npassed_challenge: the request was successful and the login challenge was passed.", + "enum": [ + "choose_method", + "sent_email", + "passed_challenge" + ], + "title": "Login Flow State" + }, "logoutFlow": { "description": "Logout Flow", "properties": { @@ -1285,7 +1314,7 @@ "type": "string" }, "template_type": { - "description": "\nrecovery_invalid TypeRecoveryInvalid\nrecovery_valid TypeRecoveryValid\nrecovery_code_invalid TypeRecoveryCodeInvalid\nrecovery_code_valid TypeRecoveryCodeValid\nverification_invalid TypeVerificationInvalid\nverification_valid TypeVerificationValid\nverification_code_invalid TypeVerificationCodeInvalid\nverification_code_valid TypeVerificationCodeValid\notp TypeOTP\nstub TypeTestStub", + "description": "\nrecovery_invalid TypeRecoveryInvalid\nrecovery_valid TypeRecoveryValid\nrecovery_code_invalid TypeRecoveryCodeInvalid\nrecovery_code_valid TypeRecoveryCodeValid\nverification_invalid TypeVerificationInvalid\nverification_valid TypeVerificationValid\nverification_code_invalid TypeVerificationCodeInvalid\nverification_code_valid TypeVerificationCodeValid\notp TypeOTP\nstub TypeTestStub\nlogin_code_valid TypeLoginCodeValid\nregistration_code_valid TypeRegistrationCodeValid", "enum": [ "recovery_invalid", "recovery_valid", @@ -1296,10 +1325,12 @@ "verification_code_invalid", "verification_code_valid", "otp", - "stub" + "stub", + "login_code_valid", + "registration_code_valid" ], "type": "string", - "x-go-enum-desc": "recovery_invalid TypeRecoveryInvalid\nrecovery_valid TypeRecoveryValid\nrecovery_code_invalid TypeRecoveryCodeInvalid\nrecovery_code_valid TypeRecoveryCodeValid\nverification_invalid TypeVerificationInvalid\nverification_valid TypeVerificationValid\nverification_code_invalid TypeVerificationCodeInvalid\nverification_code_valid TypeVerificationCodeValid\notp TypeOTP\nstub TypeTestStub" + "x-go-enum-desc": "recovery_invalid TypeRecoveryInvalid\nrecovery_valid TypeRecoveryValid\nrecovery_code_invalid TypeRecoveryCodeInvalid\nrecovery_code_valid TypeRecoveryCodeValid\nverification_invalid TypeVerificationInvalid\nverification_valid TypeVerificationValid\nverification_code_invalid TypeVerificationCodeInvalid\nverification_code_valid TypeVerificationCodeValid\notp TypeOTP\nstub TypeTestStub\nlogin_code_valid TypeLoginCodeValid\nregistration_code_valid TypeRegistrationCodeValid" }, "type": { "$ref": "#/components/schemas/courierMessageType" @@ -1504,7 +1535,7 @@ "type": "string" }, "state": { - "$ref": "#/components/schemas/recoveryFlowState" + "description": "State represents the state of this request:\n\nchoose_method: ask the user to choose a method (e.g. recover account via email)\nsent_email: the email has been sent to the user\npassed_challenge: the request was successful and the recovery challenge was passed." }, "type": { "$ref": "#/components/schemas/selfServiceFlowType" @@ -1532,8 +1563,7 @@ "sent_email", "passed_challenge" ], - "title": "Recovery Flow State", - "type": "string" + "title": "Recovery Flow State" }, "recoveryIdentityAddress": { "properties": { @@ -1623,6 +1653,9 @@ "description": "SessionTokenExchangeCode holds the secret code that the client can use to retrieve a session token after the flow has been completed.\nThis is only set if the client has requested a session token exchange code, and if the flow is of type \"api\",\nand only on creating the flow.", "type": "string" }, + "state": { + "description": "State represents the state of this request:\n\nchoose_method: ask the user to choose a method (e.g. registration with email)\nsent_email: the email has been sent to the user\npassed_challenge: the request was successful and the registration challenge was passed." + }, "transient_payload": { "description": "TransientPayload is used to pass data from the registration to a webhook", "type": "object" @@ -1640,10 +1673,20 @@ "expires_at", "issued_at", "request_url", - "ui" + "ui", + "state" ], "type": "object" }, + "registrationFlowState": { + "description": "choose_method: ask the user to choose a method (e.g. registration with email)\nsent_email: the email has been sent to the user\npassed_challenge: the request was successful and the registration challenge was passed.", + "enum": [ + "choose_method", + "sent_email", + "passed_challenge" + ], + "title": "State represents the state of this request:" + }, "selfServiceFlowExpiredError": { "description": "Is sent when a flow is expired", "properties": { @@ -1829,7 +1872,7 @@ "type": "string" }, "state": { - "$ref": "#/components/schemas/settingsFlowState" + "description": "State represents the state of this flow. It knows two states:\n\nshow_form: No user data has been collected, or it is invalid, and thus the form should be shown.\nsuccess: Indicates that the settings flow has been updated successfully with the provided data.\nDone will stay true when repeatedly checking. If set to true, done will revert back to false only\nwhen a flow with invalid (e.g. \"please use a valid phone number\") data was sent." }, "type": { "$ref": "#/components/schemas/selfServiceFlowType" @@ -1857,8 +1900,7 @@ "show_form", "success" ], - "title": "State represents the state of this flow. It knows two states:", - "type": "string" + "title": "State represents the state of this flow. It knows two states:" }, "successfulCodeExchangeResponse": { "description": "The Response for Registration Flows via API", @@ -2358,6 +2400,7 @@ "updateLoginFlowBody": { "discriminator": { "mapping": { + "code": "#/components/schemas/updateLoginFlowWithCodeMethod", "lookup_secret": "#/components/schemas/updateLoginFlowWithLookupSecretMethod", "oidc": "#/components/schemas/updateLoginFlowWithOidcMethod", "password": "#/components/schemas/updateLoginFlowWithPasswordMethod", @@ -2381,9 +2424,42 @@ }, { "$ref": "#/components/schemas/updateLoginFlowWithLookupSecretMethod" + }, + { + "$ref": "#/components/schemas/updateLoginFlowWithCodeMethod" } ] }, + "updateLoginFlowWithCodeMethod": { + "description": "Update Login flow using the code method", + "properties": { + "code": { + "description": "Code is the 6 digits code sent to the user", + "type": "string" + }, + "csrf_token": { + "description": "CSRFToken is the anti-CSRF token", + "type": "string" + }, + "identifier": { + "description": "Identifier is the code identifier\nThe identifier requires that the user has already completed the registration or settings with code flow.", + "type": "string" + }, + "method": { + "description": "Method should be set to \"code\" when logging in using the code strategy.", + "type": "string" + }, + "resend": { + "description": "Resend is set when the user wants to resend the code", + "type": "string" + } + }, + "required": [ + "method", + "csrf_token" + ], + "type": "object" + }, "updateLoginFlowWithLookupSecretMethod": { "description": "Update Login Flow with Lookup Secret Method", "properties": { @@ -2594,6 +2670,7 @@ "description": "Update Registration Request Body", "discriminator": { "mapping": { + "code": "#/components/schemas/updateRegistrationFlowWithCodeMethod", "oidc": "#/components/schemas/updateRegistrationFlowWithOidcMethod", "password": "#/components/schemas/updateRegistrationFlowWithPasswordMethod", "webauthn": "#/components/schemas/updateRegistrationFlowWithWebAuthnMethod" @@ -2609,9 +2686,46 @@ }, { "$ref": "#/components/schemas/updateRegistrationFlowWithWebAuthnMethod" + }, + { + "$ref": "#/components/schemas/updateRegistrationFlowWithCodeMethod" } ] }, + "updateRegistrationFlowWithCodeMethod": { + "description": "Update Registration Flow with Code Method", + "properties": { + "code": { + "description": "The OTP Code sent to the user", + "type": "string" + }, + "csrf_token": { + "description": "The CSRF Token", + "type": "string" + }, + "method": { + "description": "Method to use\n\nThis field must be set to `code` when using the code method.", + "type": "string" + }, + "resend": { + "description": "Resend restarts the flow with a new code", + "type": "string" + }, + "traits": { + "description": "The identity's traits", + "type": "object" + }, + "transient_payload": { + "description": "Transient data to pass along to any webhooks", + "type": "object" + } + }, + "required": [ + "traits", + "method" + ], + "type": "object" + }, "updateRegistrationFlowWithOidcMethod": { "description": "Update Registration Flow with OpenID Connect Method", "properties": { @@ -3064,7 +3178,7 @@ "type": "string" }, "state": { - "$ref": "#/components/schemas/verificationFlowState" + "description": "State represents the state of this request:\n\nchoose_method: ask the user to choose a method (e.g. verify your email)\nsent_email: the email has been sent to the user\npassed_challenge: the request was successful and the verification challenge was passed." }, "type": { "$ref": "#/components/schemas/selfServiceFlowType" @@ -3089,8 +3203,7 @@ "sent_email", "passed_challenge" ], - "title": "Verification Flow State", - "type": "string" + "title": "Verification Flow State" }, "version": { "properties": { @@ -3549,7 +3662,8 @@ "totp", "oidc", "webauthn", - "lookup_secret" + "lookup_secret", + "code" ], "type": "string" }, diff --git a/spec/swagger.json b/spec/swagger.json index 01ad8fb3bf27..368785b299a8 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -3076,6 +3076,9 @@ } }, "definitions": { + "CodeAddressType": { + "type": "string" + }, "DefaultError": {}, "Duration": { "description": "A Duration represents the elapsed time between two instants\nas an int64 nanosecond count. The representation limits the\nlargest representable duration to approximately 290 years.", @@ -3090,6 +3093,20 @@ "type": "object", "title": "JSONRawMessage represents a json.RawMessage that works well with JSON, SQL, and Swagger." }, + "NullTime": { + "description": "NullTime implements the Scanner interface so\nit can be used as a scan destination, similar to NullString.", + "type": "object", + "title": "NullTime represents a time.Time that may be null.", + "properties": { + "Time": { + "type": "string", + "format": "date-time" + }, + "Valid": { + "type": "boolean" + } + } + }, "OAuth2Client": { "type": "object", "title": "OAuth2Client OAuth 2.0 Clients are used to perform OAuth 2.0 and OpenID Connect flows. Usually, OAuth 2.0 clients are generated for applications which want to consume your OAuth 2.0 or OpenID Connect capabilities.", @@ -3847,6 +3864,18 @@ } } }, + "identityCredentialsCode": { + "description": "CredentialsCode represents a one time login/registration code", + "type": "object", + "properties": { + "address_type": { + "$ref": "#/definitions/CodeAddressType" + }, + "used_at": { + "$ref": "#/definitions/NullTime" + } + } + }, "identityCredentialsOidc": { "type": "object", "title": "CredentialsOIDC is contains the configuration for credentials of the type oidc.", @@ -4098,7 +4127,8 @@ "expires_at", "issued_at", "request_url", - "ui" + "ui", + "state" ], "properties": { "active": { @@ -4150,6 +4180,9 @@ "description": "SessionTokenExchangeCode holds the secret code that the client can use to retrieve a session token after the login flow has been completed.\nThis is only set if the client has requested a session token exchange code, and if the flow is of type \"api\",\nand only on creating the login flow.", "type": "string" }, + "state": { + "description": "State represents the state of this request:\n\nchoose_method: ask the user to choose a method to sign in with\nsent_email: the email has been sent to the user\npassed_challenge: the request was successful and the login challenge was passed." + }, "type": { "$ref": "#/definitions/selfServiceFlowType" }, @@ -4163,6 +4196,10 @@ } } }, + "loginFlowState": { + "description": "The state represents the state of the login flow.\n\nchoose_method: ask the user to choose a method (e.g. login account via email)\nsent_email: the email has been sent to the user\npassed_challenge: the request was successful and the login challenge was passed.", + "title": "Login Flow State" + }, "logoutFlow": { "description": "Logout Flow", "type": "object", @@ -4229,7 +4266,7 @@ "type": "string" }, "template_type": { - "description": "\nrecovery_invalid TypeRecoveryInvalid\nrecovery_valid TypeRecoveryValid\nrecovery_code_invalid TypeRecoveryCodeInvalid\nrecovery_code_valid TypeRecoveryCodeValid\nverification_invalid TypeVerificationInvalid\nverification_valid TypeVerificationValid\nverification_code_invalid TypeVerificationCodeInvalid\nverification_code_valid TypeVerificationCodeValid\notp TypeOTP\nstub TypeTestStub", + "description": "\nrecovery_invalid TypeRecoveryInvalid\nrecovery_valid TypeRecoveryValid\nrecovery_code_invalid TypeRecoveryCodeInvalid\nrecovery_code_valid TypeRecoveryCodeValid\nverification_invalid TypeVerificationInvalid\nverification_valid TypeVerificationValid\nverification_code_invalid TypeVerificationCodeInvalid\nverification_code_valid TypeVerificationCodeValid\notp TypeOTP\nstub TypeTestStub\nlogin_code_valid TypeLoginCodeValid\nregistration_code_valid TypeRegistrationCodeValid", "type": "string", "enum": [ "recovery_invalid", @@ -4241,9 +4278,11 @@ "verification_code_invalid", "verification_code_valid", "otp", - "stub" + "stub", + "login_code_valid", + "registration_code_valid" ], - "x-go-enum-desc": "recovery_invalid TypeRecoveryInvalid\nrecovery_valid TypeRecoveryValid\nrecovery_code_invalid TypeRecoveryCodeInvalid\nrecovery_code_valid TypeRecoveryCodeValid\nverification_invalid TypeVerificationInvalid\nverification_valid TypeVerificationValid\nverification_code_invalid TypeVerificationCodeInvalid\nverification_code_valid TypeVerificationCodeValid\notp TypeOTP\nstub TypeTestStub" + "x-go-enum-desc": "recovery_invalid TypeRecoveryInvalid\nrecovery_valid TypeRecoveryValid\nrecovery_code_invalid TypeRecoveryCodeInvalid\nrecovery_code_valid TypeRecoveryCodeValid\nverification_invalid TypeVerificationInvalid\nverification_valid TypeVerificationValid\nverification_code_invalid TypeVerificationCodeInvalid\nverification_code_valid TypeVerificationCodeValid\notp TypeOTP\nstub TypeTestStub\nlogin_code_valid TypeLoginCodeValid\nregistration_code_valid TypeRegistrationCodeValid" }, "type": { "$ref": "#/definitions/courierMessageType" @@ -4437,7 +4476,7 @@ "type": "string" }, "state": { - "$ref": "#/definitions/recoveryFlowState" + "description": "State represents the state of this request:\n\nchoose_method: ask the user to choose a method (e.g. recover account via email)\nsent_email: the email has been sent to the user\npassed_challenge: the request was successful and the recovery challenge was passed." }, "type": { "$ref": "#/definitions/selfServiceFlowType" @@ -4449,7 +4488,6 @@ }, "recoveryFlowState": { "description": "The state represents the state of the recovery flow.\n\nchoose_method: ask the user to choose a method (e.g. recover account via email)\nsent_email: the email has been sent to the user\npassed_challenge: the request was successful and the recovery challenge was passed.", - "type": "string", "title": "Recovery Flow State" }, "recoveryIdentityAddress": { @@ -4509,7 +4547,8 @@ "expires_at", "issued_at", "request_url", - "ui" + "ui", + "state" ], "properties": { "active": { @@ -4549,6 +4588,9 @@ "description": "SessionTokenExchangeCode holds the secret code that the client can use to retrieve a session token after the flow has been completed.\nThis is only set if the client has requested a session token exchange code, and if the flow is of type \"api\",\nand only on creating the flow.", "type": "string" }, + "state": { + "description": "State represents the state of this request:\n\nchoose_method: ask the user to choose a method (e.g. registration with email)\nsent_email: the email has been sent to the user\npassed_challenge: the request was successful and the registration challenge was passed." + }, "transient_payload": { "description": "TransientPayload is used to pass data from the registration to a webhook", "type": "object" @@ -4561,6 +4603,10 @@ } } }, + "registrationFlowState": { + "description": "choose_method: ask the user to choose a method (e.g. registration with email)\nsent_email: the email has been sent to the user\npassed_challenge: the request was successful and the registration challenge was passed.", + "title": "State represents the state of this request:" + }, "selfServiceFlowExpiredError": { "description": "Is sent when a flow is expired", "type": "object", @@ -4747,7 +4793,7 @@ "type": "string" }, "state": { - "$ref": "#/definitions/settingsFlowState" + "description": "State represents the state of this flow. It knows two states:\n\nshow_form: No user data has been collected, or it is invalid, and thus the form should be shown.\nsuccess: Indicates that the settings flow has been updated successfully with the provided data.\nDone will stay true when repeatedly checking. If set to true, done will revert back to false only\nwhen a flow with invalid (e.g. \"please use a valid phone number\") data was sent." }, "type": { "$ref": "#/definitions/selfServiceFlowType" @@ -4759,7 +4805,6 @@ }, "settingsFlowState": { "description": "show_form: No user data has been collected, or it is invalid, and thus the form should be shown.\nsuccess: Indicates that the settings flow has been updated successfully with the provided data.\nDone will stay true when repeatedly checking. If set to true, done will revert back to false only\nwhen a flow with invalid (e.g. \"please use a valid phone number\") data was sent.", - "type": "string", "title": "State represents the state of this flow. It knows two states:" }, "successfulCodeExchangeResponse": { @@ -5235,6 +5280,36 @@ "updateLoginFlowBody": { "type": "object" }, + "updateLoginFlowWithCodeMethod": { + "description": "Update Login flow using the code method", + "type": "object", + "required": [ + "method", + "csrf_token" + ], + "properties": { + "code": { + "description": "Code is the 6 digits code sent to the user", + "type": "string" + }, + "csrf_token": { + "description": "CSRFToken is the anti-CSRF token", + "type": "string" + }, + "identifier": { + "description": "Identifier is the code identifier\nThe identifier requires that the user has already completed the registration or settings with code flow.", + "type": "string" + }, + "method": { + "description": "Method should be set to \"code\" when logging in using the code strategy.", + "type": "string" + }, + "resend": { + "description": "Resend is set when the user wants to resend the code", + "type": "string" + } + } + }, "updateLoginFlowWithLookupSecretMethod": { "description": "Update Login Flow with Lookup Secret Method", "type": "object", @@ -5431,6 +5506,40 @@ "description": "Update Registration Request Body", "type": "object" }, + "updateRegistrationFlowWithCodeMethod": { + "description": "Update Registration Flow with Code Method", + "type": "object", + "required": [ + "traits", + "method" + ], + "properties": { + "code": { + "description": "The OTP Code sent to the user", + "type": "string" + }, + "csrf_token": { + "description": "The CSRF Token", + "type": "string" + }, + "method": { + "description": "Method to use\n\nThis field must be set to `code` when using the code method.", + "type": "string" + }, + "resend": { + "description": "Resend restarts the flow with a new code", + "type": "string" + }, + "traits": { + "description": "The identity's traits", + "type": "object" + }, + "transient_payload": { + "description": "Transient data to pass along to any webhooks", + "type": "object" + } + } + }, "updateRegistrationFlowWithOidcMethod": { "description": "Update Registration Flow with OpenID Connect Method", "type": "object", @@ -5844,7 +5953,7 @@ "type": "string" }, "state": { - "$ref": "#/definitions/verificationFlowState" + "description": "State represents the state of this request:\n\nchoose_method: ask the user to choose a method (e.g. verify your email)\nsent_email: the email has been sent to the user\npassed_challenge: the request was successful and the verification challenge was passed." }, "type": { "$ref": "#/definitions/selfServiceFlowType" @@ -5856,7 +5965,6 @@ }, "verificationFlowState": { "description": "The state represents the state of the verification flow.\n\nchoose_method: ask the user to choose a method (e.g. recover account via email)\nsent_email: the email has been sent to the user\npassed_challenge: the request was successful and the recovery challenge was passed.", - "type": "string", "title": "Verification Flow State" }, "version": { diff --git a/test/e2e/.go-version b/test/e2e/.go-version new file mode 100644 index 000000000000..6681c8c19ab4 --- /dev/null +++ b/test/e2e/.go-version @@ -0,0 +1 @@ +1.19.8 diff --git a/test/e2e/cypress/integration/profiles/code/login/error.spec.ts b/test/e2e/cypress/integration/profiles/code/login/error.spec.ts new file mode 100644 index 000000000000..46d8854c4e99 --- /dev/null +++ b/test/e2e/cypress/integration/profiles/code/login/error.spec.ts @@ -0,0 +1,176 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +import { appPrefix, APP_URL, gen } from "../../../../helpers" +import { routes as express } from "../../../../helpers/express" +import { routes as react } from "../../../../helpers/react" + +context("Login error messages with code method", () => { + ;[ + { + route: express.login, + app: "express" as "express", + profile: "code", + }, + { + route: react.login, + app: "react" as "react", + profile: "code", + }, + ].forEach(({ route, profile, app }) => { + describe(`for app ${app}`, () => { + before(() => { + cy.useConfigProfile(profile) + cy.deleteMail() + cy.proxy(app) + }) + + beforeEach(() => { + cy.deleteMail() + cy.clearAllCookies() + + const email = gen.email() + cy.wrap(email).as("email") + cy.registerWithCode({ email }) + + cy.deleteMail() + cy.clearAllCookies() + cy.visit(route) + }) + + it("should show error message when account identifier does not exist", () => { + const email = gen.email() + + cy.get('input[name="identifier"]').type(email) + cy.submitCodeForm() + + cy.url().should("contain", "login") + + cy.get('[data-testid="ui/message/4000035"]').should( + "contain", + "This account does not exist or has not setup sign in with code.", + ) + }) + + it("should show error message when code is invalid", () => { + cy.get("@email").then((email) => { + cy.get('input[name="identifier"]').clear().type(email.toString()) + }) + + cy.submitCodeForm() + + cy.url().should("contain", "login") + cy.get('[data-testid="ui/message/1010014"]').should( + "contain", + "An email containing a code has been sent to the email address you provided", + ) + + cy.get('input[name="code"]').type("invalid-code") + cy.submitCodeForm() + + cy.get('[data-testid="ui/message/4010008"]').should( + "contain", + "The login code is invalid or has already been used. Please try again.", + ) + }) + + it("should show error message when identifier has changed", () => { + cy.get("@email").then((email) => { + cy.get('input[name="identifier"]').type(email.toString()) + }) + + cy.submitCodeForm() + + cy.url().should("contain", "login") + cy.get('input[name="identifier"]').clear().type(gen.email()) + cy.get('input[name="code"]').type("invalid-code") + cy.submitCodeForm() + + cy.get('[data-testid="ui/message/4000035"]').should( + "contain", + "This account does not exist or has not setup sign in with code.", + ) + }) + + it("should show error message when required fields are missing", () => { + cy.get("@email").then((email) => { + cy.get('input[name="identifier"]').type(email.toString()) + }) + + cy.submitCodeForm() + cy.url().should("contain", "login") + + cy.removeAttribute(['input[name="code"]'], "required") + cy.submitCodeForm() + + cy.get('[data-testid="ui/message/4000002"]').should( + "contain", + "Property code is missing", + ) + + cy.get('input[name="code"]').type("invalid-code") + cy.removeAttribute(['input[name="identifier"]'], "required") + + cy.get('input[name="identifier"]').clear() + + cy.submitCodeForm() + cy.get('[data-testid="ui/message/4000002"]').should( + "contain", + "Property identifier is missing", + ) + }) + + it("should show error message when code is expired", () => { + cy.updateConfigFile((config) => { + config.selfservice.methods.code = { + passwordless_enabled: true, + config: { + lifespan: "1ns", + }, + } + return config + }).then(() => { + cy.visit(route) + }) + + cy.get("@email").then((email) => { + cy.get('input[name="identifier"]').type(email.toString()) + }) + cy.submitCodeForm() + + cy.url().should("contain", "login") + + cy.get("@email").then((email) => { + cy.getLoginCodeFromEmail(email.toString()).should((code) => { + cy.get('input[name="code"]').type(code) + }) + }) + + cy.submitCodeForm() + + // the react app does not show the error message for 410 errors + // it just creates a new flow + if (app === "express") { + cy.get('[data-testid="ui/message/4010001"]').should( + "contain", + "The login flow expired", + ) + } else { + cy.get("input[name=identifier]").should("be.visible") + } + + cy.noSession() + + cy.updateConfigFile((config) => { + config.selfservice.methods.code = { + passwordless_enabled: true, + config: { + lifespan: "1h", + }, + } + return config + }) + }) + }) + }) +}) diff --git a/test/e2e/cypress/integration/profiles/code/login/success.spec.ts b/test/e2e/cypress/integration/profiles/code/login/success.spec.ts new file mode 100644 index 000000000000..83cbbb605c20 --- /dev/null +++ b/test/e2e/cypress/integration/profiles/code/login/success.spec.ts @@ -0,0 +1,164 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +import { gen } from "../../../../helpers" +import { routes as express } from "../../../../helpers/express" +import { routes as react } from "../../../../helpers/react" + +context("Login success with code method", () => { + ;[ + { + route: express.login, + app: "express" as "express", + profile: "code", + }, + { + route: react.login, + app: "react" as "react", + profile: "code", + }, + ].forEach(({ route, profile, app }) => { + describe(`for app ${app}`, () => { + before(() => { + cy.deleteMail() + cy.useConfigProfile(profile) + cy.proxy(app) + cy.setPostCodeRegistrationHooks([]) + cy.setupHooks("login", "after", "code", []) + }) + + beforeEach(() => { + const email = gen.email() + cy.wrap(email).as("email") + cy.registerWithCode({ email }) + + cy.deleteMail() + cy.clearAllCookies() + cy.visit(route) + }) + + it("should be able to sign in with code", () => { + cy.get("@email").then((email) => { + cy.get('input[name="identifier"]').clear().type(email.toString()) + cy.submitCodeForm() + + cy.getLoginCodeFromEmail(email.toString()).should((code) => { + cy.get('input[name="code"]').type(code) + + cy.get("button[name=method][value=code]").click() + }) + + cy.location("pathname").should("not.contain", "login") + + cy.getSession().should((session) => { + const { identity } = session + expect(identity.id).to.not.be.empty + expect(identity.verifiable_addresses).to.have.length(1) + expect(identity.verifiable_addresses[0].status).to.equal( + "completed", + ) + expect(identity.traits.email).to.equal(email) + }) + }) + }) + + it("should be able to resend login code", () => { + cy.get("@email").then((email) => { + cy.get('input[name="identifier"]').clear().type(email.toString()) + cy.submitCodeForm() + + cy.getLoginCodeFromEmail(email.toString()).should((code) => { + cy.wrap(code).as("code1") + }) + + cy.get("button[name=resend]").click() + + cy.getLoginCodeFromEmail(email.toString()).should((code) => { + cy.wrap(code).as("code2") + }) + + cy.get("@code1").then((code1) => { + cy.get("@code2").then((code2) => { + expect(code1).to.not.equal(code2) + }) + }) + + // attempt to submit code 1 + cy.get("@code1").then((code1) => { + cy.get('input[name="code"]').clear().type(code1.toString()) + }) + + cy.get("button[name=method][value=code]").click() + + cy.get("[data-testid='ui/message/4010008']").contains( + "The login code is invalid or has already been used", + ) + + // attempt to submit code 2 + cy.get("@code2").then((code2) => { + cy.get('input[name="code"]').clear().type(code2.toString()) + }) + + cy.get('button[name="method"][value="code"]').click() + + if (app === "express") { + cy.get('a[href*="sessions"').click() + } + cy.getSession().should((session) => { + const { identity } = session + expect(identity.id).to.not.be.empty + expect(identity.verifiable_addresses).to.have.length(1) + expect(identity.verifiable_addresses[0].status).to.equal( + "completed", + ) + expect(identity.traits.email).to.equal(email) + }) + }) + }) + + it("should be able to login to un-verfied email", () => { + const email = gen.email() + const email2 = gen.email() + + // Setup complex schema + cy.setIdentitySchema( + "file://test/e2e/profiles/code/identity.complex.traits.schema.json", + ) + + cy.registerWithCode({ + email: email, + traits: { + "traits.username": Math.random().toString(36), + "traits.email2": email2, + }, + }) + + // There are verification emails from the registration process in the inbox that we need to deleted + // for the assertions below to pass. + cy.deleteMail({ atLeast: 1 }) + + cy.visit(route) + + cy.get('input[name="identifier"]').clear().type(email2) + cy.submitCodeForm() + + cy.getLoginCodeFromEmail(email2).should((code) => { + cy.get('input[name="code"]').type(code) + cy.get("button[name=method][value=code]").click() + }) + + cy.getSession({ expectAal: "aal1", expectMethods: ["code"] }).then( + (session) => { + expect(session.identity.verifiable_addresses).to.have.length(2) + expect(session.identity.verifiable_addresses[0].status).to.equal( + "completed", + ) + expect(session.identity.verifiable_addresses[1].status).to.equal( + "completed", + ) + }, + ) + }) + }) + }) +}) diff --git a/test/e2e/cypress/integration/profiles/code/registration/error.spec.ts b/test/e2e/cypress/integration/profiles/code/registration/error.spec.ts new file mode 100644 index 000000000000..a4d6596008dd --- /dev/null +++ b/test/e2e/cypress/integration/profiles/code/registration/error.spec.ts @@ -0,0 +1,144 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 +import { gen } from "../../../../helpers" +import { routes as express } from "../../../../helpers/express" +import { routes as react } from "../../../../helpers/react" + +context("Registration error messages with code method", () => { + ;[ + { + route: express.registration, + app: "express" as "express", + profile: "code", + }, + { + route: react.registration, + app: "react" as "react", + profile: "code", + }, + ].forEach(({ route, profile, app }) => { + describe(`for app ${app}`, () => { + before(() => { + cy.proxy(app) + cy.useConfigProfile(profile) + cy.deleteMail() + }) + + beforeEach(() => { + cy.deleteMail() + cy.clearAllCookies() + cy.visit(route) + }) + + it("should show error message when code is invalid", () => { + const email = gen.email() + + cy.get('input[name="traits.email"]').type(email) + cy.submitCodeForm() + + cy.get('[data-testid="ui/message/1040005"]').should( + "contain", + "An email containing a code has been sent to the email address you provided", + ) + + cy.get('input[name="code"]').type("invalid-code") + cy.submitCodeForm() + + cy.get('[data-testid="ui/message/4040003"]').should( + "contain", + "The registration code is invalid or has already been used. Please try again.", + ) + }) + + it("should show error message when traits have changed", () => { + const email = gen.email() + + cy.get('input[name="traits.email"]').type(email) + cy.submitCodeForm() + cy.get('[data-testid="ui/message/1040005"]').should( + "contain", + "An email containing a code has been sent to the email address you provided", + ) + + cy.get('input[name="traits.email"]') + .clear() + .type("changed-email@email.com") + cy.get('input[name="code"]').type("invalid-code") + cy.submitCodeForm() + + cy.get('[data-testid="ui/message/4000036"]').should( + "contain", + "The provided traits do not match the traits previously associated with this flow.", + ) + }) + + it("should show error message when required fields are missing", () => { + const email = gen.email() + + cy.get('input[name="traits.email"]').type(email) + cy.submitCodeForm() + cy.get('[data-testid="ui/message/1040005"]').should( + "contain", + "An email containing a code has been sent to the email address you provided", + ) + + cy.removeAttribute(['input[name="code"]'], "required") + + cy.submitCodeForm() + cy.get('[data-testid="ui/message/4000002"]').should( + "contain", + "Property code is missing", + ) + + cy.get('input[name="traits.email"]').clear() + cy.get('input[name="code"]').type("invalid-code") + cy.removeAttribute(['input[name="traits.email"]'], "required") + + cy.submitCodeForm() + cy.get('[data-testid="ui/message/4000002"]').should( + "contain", + "Property email is missing", + ) + }) + + it("should show error message when code is expired", () => { + cy.updateConfigFile((config) => { + config.selfservice.methods.code.config.lifespan = "1ns" + return config + }) + cy.visit(route) + + const email = gen.email() + cy.get('input[name="traits.email"]').type(email) + + cy.submitCodeForm() + cy.get('[data-testid="ui/message/1040005"]').should( + "contain", + "An email containing a code has been sent to the email address you provided", + ) + + cy.getRegistrationCodeFromEmail(email).should((code) => { + cy.get('input[name="code"]').type(code) + cy.submitCodeForm() + }) + + // in the react spa app we don't show the 410 gone error. we create a new flow. + if (app === "express") { + cy.get('[data-testid="ui/message/4040001"]').should( + "contain", + "The registration flow expired", + ) + } else { + cy.get('input[name="traits.email"]').should("be.visible") + } + + cy.noSession() + + cy.updateConfigFile((config) => { + config.selfservice.methods.code.config.lifespan = "1h" + return config + }) + }) + }) + }) +}) diff --git a/test/e2e/cypress/integration/profiles/code/registration/success.spec.ts b/test/e2e/cypress/integration/profiles/code/registration/success.spec.ts new file mode 100644 index 000000000000..299d5707a7d5 --- /dev/null +++ b/test/e2e/cypress/integration/profiles/code/registration/success.spec.ts @@ -0,0 +1,241 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +import { gen } from "../../../../helpers" +import { routes as express } from "../../../../helpers/express" +import { routes as react } from "../../../../helpers/react" + +context("Registration success with code method", () => { + ;[ + { + route: express.registration, + login: express.login, + recovery: express.recovery, + app: "express" as "express", + profile: "code", + }, + { + route: react.registration, + login: react.login, + recovery: react.recovery, + app: "react" as "react", + profile: "code", + }, + ].forEach(({ route, login, recovery, profile, app }) => { + describe(`for app ${app}`, () => { + before(() => { + cy.deleteMail() + cy.useConfigProfile(profile) + cy.proxy(app) + }) + + beforeEach(() => { + cy.deleteMail() + cy.clearAllCookies() + cy.visit(route) + }) + + it("should be able to resend the registration code", async () => { + const email = gen.email() + + cy.get(`input[name='traits.email']`).type(email) + + cy.submitCodeForm() + cy.get('[data-testid="ui/message/1040005"]').should( + "contain", + "An email containing a code has been sent to the email address you provided", + ) + + cy.getRegistrationCodeFromEmail(email).should((code) => + cy.wrap(code).as("code1"), + ) + + cy.get(`input[name='traits.email']`).should("have.value", email) + cy.get(`input[name='method'][value='code'][type='hidden']`).should( + "exist", + ) + cy.get(`button[name='resend'][value='code']`).click() + + cy.getRegistrationCodeFromEmail(email).should((code) => { + cy.wrap(code).as("code2") + }) + + cy.get("@code1").then((code1) => { + // previous code should not work + cy.get('input[name="code"]').clear().type(code1.toString()) + + cy.submitCodeForm() + cy.get('[data-testid="ui/message/4040003"]').should( + "contain.text", + "The registration code is invalid or has already been used. Please try again.", + ) + }) + + cy.get("@code2").then((code2) => { + cy.get('input[name="code"]').clear().type(code2.toString()) + cy.submitCodeForm() + }) + + cy.getSession().should((session) => { + const { identity } = session + expect(identity.id).to.not.be.empty + expect(identity.verifiable_addresses).to.have.length(1) + expect(identity.verifiable_addresses[0].status).to.equal("completed") + expect(identity.traits.email).to.equal(email) + }) + }) + + it("should sign up and be logged in with session hook", () => { + const email = gen.email() + + cy.get(` input[name='traits.email']`).type(email) + + cy.submitCodeForm() + cy.get('[data-testid="ui/message/1040005"]').should( + "contain", + "An email containing a code has been sent to the email address you provided", + ) + + cy.getRegistrationCodeFromEmail(email).should((code) => { + cy.get(`input[name=code]`).type(code) + cy.get("button[name=method][value=code]").click() + }) + + cy.getSession().should((session) => { + const { identity } = session + expect(identity.id).to.not.be.empty + expect(identity.verifiable_addresses).to.have.length(1) + expect(identity.verifiable_addresses[0].status).to.equal("completed") + expect(identity.traits.email).to.equal(email) + }) + }) + + it("should be able to sign up without session hook", () => { + cy.setPostCodeRegistrationHooks([]) + const email = gen.email() + + cy.get(`input[name='traits.email']`).type(email) + + cy.submitCodeForm() + cy.get('[data-testid="ui/message/1040005"]').should( + "contain", + "An email containing a code has been sent to the email address you provided", + ) + + cy.getRegistrationCodeFromEmail(email).should((code) => { + cy.get(`input[name=code]`).type(code) + cy.get("button[name=method][value=code]").click() + }) + + cy.visit(login) + cy.get(`input[name=identifier]`).type(email) + cy.get("button[name=method][value=code]").click() + + cy.getLoginCodeFromEmail(email).then((code) => { + cy.get(`input[name=code]`).type(code) + cy.get("button[name=method][value=code]").click() + }) + + cy.getSession().should((session) => { + const { identity } = session + expect(identity.id).to.not.be.empty + expect(identity.verifiable_addresses).to.have.length(1) + expect(identity.verifiable_addresses[0].status).to.equal("completed") + expect(identity.traits.email).to.equal(email) + }) + }) + + it("should be able to recover account when registered with code", () => { + const email = gen.email() + cy.registerWithCode({ email }) + + cy.clearAllCookies() + cy.visit(recovery) + + cy.get('input[name="email"]').type(email) + cy.get('button[name="method"][value="code"]').click() + + cy.recoveryEmailWithCode({ expect: { email } }) + cy.get('button[value="code"]').click() + + cy.getSession().should((session) => { + const { identity } = session + expect(identity.id).to.not.be.empty + expect(identity.traits.email).to.equal(email) + }) + }) + + // Try keep this test as the last one, as it updates the identity schema. + it("should be able to use multiple identifiers to signup with and sign in to", () => { + cy.setPostCodeRegistrationHooks([ + { + hook: "session", + }, + ]) + + // Setup complex schema + cy.setIdentitySchema( + "file://test/e2e/profiles/code/identity.complex.traits.schema.json", + ) + + cy.visit(route) + + cy.get(`input[name='traits.username']`).type(Math.random().toString(36)) + + const email = gen.email() + cy.get(`input[name='traits.email']`).type(email) + + const email2 = gen.email() + cy.get(`input[name='traits.email2']`).type(email2) + + cy.submitCodeForm() + cy.get('[data-testid="ui/message/1040005"]').should( + "contain", + "An email containing a code has been sent to the email address you provided", + ) + + // intentionally use email 1 to sign up for the account + cy.getRegistrationCodeFromEmail(email, { expectedCount: 1 }).should( + (code) => { + cy.get(`input[name=code]`).type(code) + cy.get("button[name=method][value=code]").click() + }, + ) + + cy.logout() + + // There are verification emails from the registration process in the inbox that we need to deleted + // for the assertions below to pass. + cy.deleteMail({ atLeast: 1 }) + + // Attempt to sign in with email 2 (should fail) + cy.visit(login) + cy.get(`input[name=identifier]`).type(email2) + + cy.get("button[name=method][value=code]").click() + + cy.getLoginCodeFromEmail(email2, { + expectedCount: 1, + }).should((code) => { + cy.get(`input[name=code]`).type(code) + cy.get("button[name=method][value=code]").click() + }) + + cy.getSession().should((session) => { + const { identity } = session + expect(identity.id).to.not.be.empty + expect(identity.verifiable_addresses).to.have.length(2) + expect( + identity.verifiable_addresses.filter((v) => v.value === email)[0] + .status, + ).to.equal("completed") + expect( + identity.verifiable_addresses.filter((v) => v.value === email2)[0] + .status, + ).to.equal("completed") + expect(identity.traits.email).to.equal(email) + }) + }) + }) + }) +}) diff --git a/test/e2e/cypress/support/commands.ts b/test/e2e/cypress/support/commands.ts index 9ab3ea5a41ff..d924827b5881 100644 --- a/test/e2e/cypress/support/commands.ts +++ b/test/e2e/cypress/support/commands.ts @@ -18,6 +18,7 @@ import dayjs from "dayjs" import YAML from "yamljs" import { Strategy } from "." import { OryKratosConfiguration } from "./config" +import { UiNode, UiNodeAttributes } from "@ory/kratos-client" const configFile = "kratos.generated.yml" @@ -221,6 +222,10 @@ Cypress.Commands.add("setPostPasswordRegistrationHooks", (hooks) => { cy.setupHooks("registration", "after", "password", hooks) }) +Cypress.Commands.add("setPostCodeRegistrationHooks", (hooks) => { + cy.setupHooks("registration", "after", "code", hooks) +}) + Cypress.Commands.add("shortLoginLifespan", ({} = {}) => { updateConfigFile((config) => { config.selfservice.flows.login.lifespan = "100ms" @@ -377,6 +382,83 @@ Cypress.Commands.add( }, ) +Cypress.Commands.add( + "registerWithCode", + ({ + email = gen.email(), + code = undefined, + traits = {}, + query = {}, + expectedMailCount = 1, + } = {}) => { + cy.clearAllCookies() + + cy.request({ + url: APP_URL + "/self-service/registration/browser", + method: "GET", + followRedirect: false, + headers: { + Accept: "application/json", + }, + qs: query || {}, + }).then(({ body, status }) => { + expect(status).to.eq(200) + const form = body.ui + return cy + .request({ + headers: { + Accept: "application/json", + }, + method: form.method, + body: mergeFields(form, { + method: "code", + "traits.email": email, + ...traits, + ...(code && { code }), + }), + url: form.action, + followRedirect: false, + failOnStatusCode: false, + }) + .then(({ body }) => { + if (!code) { + expect( + body.ui.nodes.find( + (f: UiNode) => + f.group === "code" && + "name" in f.attributes && + f.attributes.name === "traits.email", + ).attributes.value, + ).to.eq(email) + + return cy + .getRegistrationCodeFromEmail(email, { + expectedCount: expectedMailCount, + }) + .then((code) => { + return cy.request({ + headers: { + Accept: "application/json", + }, + method: form.method, + body: mergeFields(form, { + method: "code", + "traits.email": email, + code, + ...traits, + }), + url: form.action, + followRedirect: false, + }) + }) + } else { + expect(body.session).to.contain(email) + } + }) + }) + }, +) + Cypress.Commands.add( "registerApi", ({ email = gen.email(), password = gen.password(), fields = {} } = {}) => @@ -1105,7 +1187,7 @@ Cypress.Commands.add( Cypress.Commands.add( "verifyEmailButExpired", ({ expect: { email }, strategy = "code" }) => { - cy.getMail().then((message) => { + cy.getMail().should((message) => { expect(message.subject).to.equal("Please verify your email address") expect(message.fromAddress.trim()).to.equal("no-reply@ory.kratos.sh") @@ -1171,30 +1253,51 @@ Cypress.Commands.add("expectSettingsSaved", () => { ) }) -Cypress.Commands.add("getMail", ({ removeMail = true } = {}) => { - let tries = 0 - const req = () => - cy.request(`${MAIL_API}/mail`).then((response) => { - expect(response.body).to.have.property("mailItems") - const count = response.body.mailItems.length - if (count === 0 && tries < 100) { - tries++ - cy.wait(pollInterval) - return req() - } +Cypress.Commands.add( + "getMail", + ({ removeMail = true, expectedCount = 1, email = undefined } = {}) => { + let tries = 0 + const req = () => + cy.request(`${MAIL_API}/mail`).then((response) => { + expect(response.body).to.have.property("mailItems") + let count = response.body.mailItems.length + if (count === 0 && tries < 100) { + tries++ + cy.wait(pollInterval) + return req() + } - expect(count).to.equal(1) - if (removeMail) { - return cy - .deleteMail({ atLeast: count }) - .then(() => Promise.resolve(response.body.mailItems[0])) - } + let mailItem: any + if (email) { + const filtered = response.body.mailItems.filter((m: any) => + m.toAddresses.includes(email), + ) - return Promise.resolve(response.body.mailItems[0]) - }) + if (filtered.length === 0) { + tries++ + cy.wait(pollInterval) + return req() + } - return req() -}) + expect(filtered.length).to.equal(expectedCount) + mailItem = filtered[0] + } else { + expect(count).to.equal(expectedCount) + mailItem = response.body.mailItems[0] + } + + if (removeMail) { + return cy.deleteMail({ atLeast: count }).then(() => { + return Promise.resolve(mailItem) + }) + } + + return Promise.resolve(mailItem) + }) + + return req() + }, +) Cypress.Commands.add("clearAllCookies", () => { cy.clearCookies({ domain: null }) @@ -1210,6 +1313,11 @@ Cypress.Commands.add("submitProfileForm", () => { cy.get('[name="method"][value="profile"]:disabled').should("not.exist") }) +Cypress.Commands.add("submitCodeForm", () => { + cy.get('button[name="method"][value="code"]').click() + cy.get('button[name="method"][value="code"]:disabled').should("not.exist") +}) + Cypress.Commands.add("clickWebAuthButton", (type: string) => { cy.get('*[data-testid="node/script/webauthn_script"]').should("exist") cy.wait(500) // Wait for script to load @@ -1375,3 +1483,40 @@ Cypress.Commands.add("getVerificationCodeFromEmail", (email) => { return code }) }) + +Cypress.Commands.add("enableRegistrationViaCode", (enable: boolean = true) => { + cy.updateConfigFile((config) => { + config.selfservice.methods.code.passwordless_enabled = enable + return config + }) +}) + +Cypress.Commands.add("getRegistrationCodeFromEmail", (email, opts) => { + return cy + .getMail({ removeMail: true, email, ...opts }) + .should((message) => { + expect(message.subject).to.equal("Complete your account registration") + expect(message.toAddresses[0].trim()).to.equal(email) + }) + .then((message) => { + const code = extractRecoveryCode(message.body) + expect(code).to.not.be.undefined + expect(code.length).to.equal(6) + return code + }) +}) + +Cypress.Commands.add("getLoginCodeFromEmail", (email, opts) => { + return cy + .getMail({ removeMail: true, email, ...opts }) + .should((message) => { + expect(message.subject).to.equal("Login to your account") + expect(message.toAddresses[0].trim()).to.equal(email) + }) + .then((message) => { + const code = extractRecoveryCode(message.body) + expect(code).to.not.be.undefined + expect(code.length).to.equal(6) + return code + }) +}) diff --git a/test/e2e/cypress/support/config.d.ts b/test/e2e/cypress/support/config.d.ts index e2bb5294b91e..1bac43efd7b3 100644 --- a/test/e2e/cypress/support/config.d.ts +++ b/test/e2e/cypress/support/config.d.ts @@ -106,6 +106,8 @@ export type EnablesLinkMethod = boolean export type OverrideTheBaseURLWhichShouldBeUsedAsTheBaseForRecoveryAndVerificationLinks = string export type HowLongALinkIsValidFor = string +export type EnablesLoginWithCodeMethod = boolean +export type EnablesRegistrationWithCodeMethod = boolean export type EnablesCodeMethod = boolean export type HowLongACodeIsValidFor = string export type EnablesUsernameEmailAndPasswordMethod = boolean @@ -210,6 +212,7 @@ export type Provider = | "dingtalk" | "patreon" | "linkedin" + | "lark" export type OptionalStringWhichWillBeUsedWhenGeneratingLabelsForUIButtons = string /** @@ -260,6 +263,20 @@ export type DataSourceName = string * You can override certain or all message templates by pointing this key to the path where the templates are located. */ export type OverrideMessageTemplates = string +/** + * Defines how emails will be sent, either through SMTP (default) or HTTP. + */ +export type DeliveryStrategy = "smtp" | "http" +/** + * This URL will be used to send the emails to. + */ +export type HTTPAddressOfAPIEndpoint = string +/** + * Define which auth mechanism to use for auth with the HTTP email provider + */ +export type AuthMechanisms = + | WebHookAuthApiKeyProperties + | WebHookAuthBasicAuthProperties /** * This URI will be used to connect to the SMTP server. Use the scheme smtps for implicit TLS sessions or smtp for explicit StartTLS/cleartext sessions. Please note that TLS is always enforced with certificate trust verification by default for security reasons on both schemes. With the smtp scheme you can use the query parameter (`?disable_starttls=true`) to allow cleartext sessions or (`?disable_starttls=false`) to enforce StartTLS (default behaviour). Additionally, use the query parameter to allow (`?skip_ssl_verify=true`) or disallow (`?skip_ssl_verify=false`) self-signed TLS certificates (default behaviour) on both implicit and explicit TLS sessions. */ @@ -291,17 +308,21 @@ export type SMSSenderAddress = string /** * This URL will be used to connect to the SMS provider. */ -export type HTTPAddressOfAPIEndpoint = string +export type HTTPAddressOfAPIEndpoint1 = string /** * Define which auth mechanism to use for auth with the SMS provider */ -export type AuthMechanisms = +export type AuthMechanisms1 = | WebHookAuthApiKeyProperties | WebHookAuthBasicAuthProperties /** * 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. */ export type OAuth20ProviderURL = string +/** + * Override the return_to query parameter with the OAuth2 provider request URL when perfoming an OAuth2 login flow. + */ +export type PersistOAuth2RequestBetweenFlows = boolean /** * Disable request logging for /health/alive and /health/ready endpoints */ @@ -506,6 +527,7 @@ export interface OryKratosConfiguration2 { config?: LinkConfiguration } code?: { + passwordless_enabled?: boolean enabled?: EnablesCodeMethod config?: CodeConfiguration } @@ -674,15 +696,23 @@ export interface SelfServiceAfterRegistration { password?: SelfServiceAfterRegistrationMethod webauthn?: SelfServiceAfterRegistrationMethod oidc?: SelfServiceAfterRegistrationMethod + code?: SelfServiceAfterRegistrationMethod hooks?: SelfServiceHooks } export interface SelfServiceAfterRegistrationMethod { default_browser_return_url?: RedirectBrowsersToSetURLPerDefault - hooks?: (SelfServiceSessionIssuerHook | SelfServiceWebHook)[] + hooks?: ( + | SelfServiceSessionIssuerHook + | SelfServiceWebHook + | SelfServiceShowVerificationUIHook + )[] } export interface SelfServiceSessionIssuerHook { hook: "session" } +export interface SelfServiceShowVerificationUIHook { + hook: "show_verification_ui" +} export interface SelfServiceBeforeLogin { hooks?: SelfServiceHooks } @@ -691,6 +721,7 @@ export interface SelfServiceAfterLogin { password?: SelfServiceAfterDefaultLoginMethod webauthn?: SelfServiceAfterDefaultLoginMethod oidc?: SelfServiceAfterOIDCLoginMethod + code?: SelfServiceAfterDefaultLoginMethod hooks?: ( | SelfServiceWebHook | SelfServiceSessionRevokerHook @@ -868,6 +899,8 @@ export interface CourierConfiguration { * Defines the maximum number of times the sending of a message is retried after it failed before it is marked as abandoned */ message_retries?: number + delivery_strategy?: DeliveryStrategy + http?: HTTPConfiguration smtp: SMTPConfiguration sms?: SMSSenderConfiguration } @@ -892,6 +925,61 @@ export interface EmailCourierTemplate { } subject?: string } +/** + * Configures outgoing emails using HTTP. + */ +export interface HTTPConfiguration { + request_config?: HttpRequestConfig +} +export interface HttpRequestConfig { + url?: HTTPAddressOfAPIEndpoint + /** + * The HTTP method to use (GET, POST, etc). Defaults to POST. + */ + method?: string + /** + * The HTTP headers that must be applied to request + */ + headers?: { + [k: string]: string | undefined + } + /** + * URI pointing to the jsonnet template used for payload generation. Only used for those HTTP methods, which support HTTP body payloads + */ + body?: string + auth?: AuthMechanisms + additionalProperties?: false +} +export interface WebHookAuthApiKeyProperties { + type: "api_key" + config: { + /** + * The name of the api key + */ + name: string + /** + * The value of the api key + */ + value: string + /** + * How the api key should be transferred + */ + in: "header" | "cookie" + } +} +export interface WebHookAuthBasicAuthProperties { + type: "basic_auth" + config: { + /** + * user name for basic auth + */ + user: string + /** + * password for basic auth + */ + password: string + } +} /** * Configures outgoing emails using the SMTP protocol. */ @@ -920,7 +1008,7 @@ export interface SMSSenderConfiguration { enabled?: boolean from?: SMSSenderAddress request_config?: { - url: HTTPAddressOfAPIEndpoint + url: HTTPAddressOfAPIEndpoint1 /** * The HTTP method to use (GET, POST, etc). */ @@ -935,44 +1023,14 @@ export interface SMSSenderConfiguration { * URI pointing to the jsonnet template used for payload generation. Only used for those HTTP methods, which support HTTP body payloads */ body?: string - auth?: AuthMechanisms + auth?: AuthMechanisms1 additionalProperties?: false } } -export interface WebHookAuthApiKeyProperties { - type: "api_key" - config: { - /** - * The name of the api key - */ - name: string - /** - * The value of the api key - */ - value: string - /** - * How the api key should be transferred - */ - in: "header" | "cookie" - } -} -export interface WebHookAuthBasicAuthProperties { - type: "basic_auth" - config: { - /** - * user name for basic auth - */ - user: string - /** - * password for basic auth - */ - password: string - } -} export interface OAuth2ProviderConfiguration { url?: OAuth20ProviderURL headers?: HTTPRequestHeaders - override_return_to?: boolean + override_return_to?: PersistOAuth2RequestBetweenFlows } /** * These headers will be passed in HTTP request to the OAuth2 Provider. diff --git a/test/e2e/cypress/support/index.d.ts b/test/e2e/cypress/support/index.d.ts index c9a52a0c7e8e..47b66308c252 100644 --- a/test/e2e/cypress/support/index.d.ts +++ b/test/e2e/cypress/support/index.d.ts @@ -37,7 +37,7 @@ declare global { getSession(opts?: { expectAal?: "aal2" | "aal1" expectMethods?: Array< - "password" | "webauthn" | "lookup_secret" | "totp" + "password" | "webauthn" | "lookup_secret" | "totp" | "code" > }): Chainable @@ -70,6 +70,19 @@ declare global { fields?: { [key: string]: any } }): Chainable> + /** + * Register a user with a code + * + * @param opts + */ + registerWithCode(opts: { + email: string + code?: string + traits?: { [key: string]: any } + query?: { [key: string]: string } + expectedMailCount?: number + }): Chainable> + /** * Updates a user's settings using an API flow * @@ -89,7 +102,11 @@ declare global { * * @param opts */ - getMail(opts?: { removeMail: boolean }): Chainable + getMail(opts?: { + removeMail: boolean + expectedCount?: number + email?: string + }): Chainable performEmailVerification(opts?: { expect?: { email?: string; redirectTo?: string } @@ -166,7 +183,7 @@ declare global { | "verification" | "settings", phase: "before" | "after", - kind: "password" | "webauthn" | "oidc", + kind: "password" | "webauthn" | "oidc" | "code", hooks: Array<{ hook: string; config?: any }>, ): Chainable @@ -179,6 +196,15 @@ declare global { hooks: Array<{ hook: string; config?: any }>, ): Chainable + /** + * Sets the post code registration hook. + * + * @param hooks + */ + setPostCodeRegistrationHooks( + hooks: Array<{ hook: string; config?: any }>, + ): Chainable + /** * Submits a verification flow via the Browser * @@ -332,6 +358,11 @@ declare global { */ submitProfileForm(): Chainable + /** + * Submits a code form by clicking the button with method=code + */ + submitCodeForm(): Chainable + /** * Expect a CSRF error to occur * @@ -689,6 +720,28 @@ declare global { * Extracts a verification code from the received email */ getVerificationCodeFromEmail(email: string): Chainable + + /** + * Enables the registration code method + * @param enable + */ + enableRegistrationViaCode(enable: boolean): Chainable + + /** + * Extracts a registration code from the received email + */ + getRegistrationCodeFromEmail( + email: string, + opts?: { expectedCount: number; removeMail?: boolean }, + ): Chainable + + /** + * Extracts a login code from the received email + */ + getLoginCodeFromEmail( + email: string, + opts?: { expectedCount: number }, + ): Chainable } } } diff --git a/test/e2e/profiles/code/.kratos.yml b/test/e2e/profiles/code/.kratos.yml new file mode 100644 index 000000000000..ec69fb050fab --- /dev/null +++ b/test/e2e/profiles/code/.kratos.yml @@ -0,0 +1,48 @@ +selfservice: + flows: + settings: + ui_url: http://localhost:4455/settings + privileged_session_max_age: 5m + + logout: + after: + default_browser_return_url: http://localhost:4455/login + + registration: + ui_url: http://localhost:4455/registration + after: + code: + hooks: + - + hook: session + + login: + ui_url: http://localhost:4455/login + after: + code: + hooks: + - + hook: require_verified_address + error: + ui_url: http://localhost:4455/error + verification: + enabled: true + use: code + ui_url: http://localhost:4455/verification + recovery: + enabled: true + use: code + ui_url: http://localhost:4455/recovery + methods: + password: + enabled: false + code: + passwordless_enabled: true + enabled: true + config: + lifespan: 1h + +identity: + schemas: + - id: default + url: file://test/e2e/profiles/code/identity.traits.schema.json diff --git a/test/e2e/profiles/code/identity.code.only.traits.schema.json b/test/e2e/profiles/code/identity.code.only.traits.schema.json new file mode 100644 index 000000000000..97573e085d8c --- /dev/null +++ b/test/e2e/profiles/code/identity.code.only.traits.schema.json @@ -0,0 +1,31 @@ +{ + "$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": "Your E-Mail", + "minLength": 3, + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + }, + "code": { + "identifier": true, + "via": "email" + } + } + } + } + }, + "required": ["email"] + } + } +} diff --git a/test/e2e/profiles/code/identity.complex.traits.schema.json b/test/e2e/profiles/code/identity.complex.traits.schema.json new file mode 100644 index 000000000000..9eda33789066 --- /dev/null +++ b/test/e2e/profiles/code/identity.complex.traits.schema.json @@ -0,0 +1,77 @@ +{ + "$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": { + "username": { + "type": "string", + "title": "Your Username", + "minLength": 3, + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + } + } + }, + "email": { + "type": "string", + "format": "email", + "title": "Your E-Mail", + "minLength": 3, + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + }, + "webauthn": { + "identifier": true + }, + "code": { + "identifier": true, + "via": "email" + } + }, + "verification": { + "via": "email" + }, + "recovery": { + "via": "email" + } + } + }, + "email2": { + "type": "string", + "format": "email", + "title": "Your Second E-Mail", + "minLength": 3, + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + }, + "code": { + "identifier": true, + "via": "email" + } + }, + "verification": { + "via": "email" + }, + "recovery": { + "via": "email" + } + } + } + }, + "required": [ + "email" + ] + } + } +} diff --git a/test/e2e/profiles/code/identity.traits.schema.json b/test/e2e/profiles/code/identity.traits.schema.json new file mode 100644 index 000000000000..268ae57da51a --- /dev/null +++ b/test/e2e/profiles/code/identity.traits.schema.json @@ -0,0 +1,39 @@ +{ + "$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": "Your E-Mail", + "minLength": 3, + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + }, + "code": { + "identifier": true, + "via": "email" + } + }, + "verification": { + "via": "email" + }, + "recovery": { + "via": "email" + } + } + } + }, + "required": [ + "email" + ] + } + } +} diff --git a/test/e2e/run.sh b/test/e2e/run.sh index 6119a2b61f8b..3ea3e5bcab8e 100755 --- a/test/e2e/run.sh +++ b/test/e2e/run.sh @@ -136,8 +136,8 @@ prepare() { 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 19006 && exit 1 + nc -zv localhost 4456 && exit 1 nc -zv localhost 4458 && exit 1 nc -zv localhost 4744 && exit 1 nc -zv localhost 4745 && exit 1 @@ -273,7 +273,7 @@ run() { nc -zv localhost 4433 && exit 1 ls -la . - for profile in email mobile oidc recovery recovery-mfa verification mfa spa network passwordless webhooks oidc-provider oidc-provider-mfa; do + for profile in code email mobile oidc recovery recovery-mfa 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 cat "test/e2e/kratos.${profile}.yml" | envsubst | sponge "test/e2e/kratos.${profile}.yml" done diff --git a/text/id.go b/text/id.go index 0716ad991d8d..c0274db092ef 100644 --- a/text/id.go +++ b/text/id.go @@ -23,6 +23,8 @@ const ( InfoSelfServiceLoginContinueWebAuthn // 1010011 InfoSelfServiceLoginWebAuthnPasswordless // 1010012 InfoSelfServiceLoginContinue // 1010013 + InfoSelfServiceLoginEmailWithCodeSent // 1010014 + InfoSelfServiceLoginCode // 1010015 ) const ( @@ -34,11 +36,13 @@ const ( ) const ( - InfoSelfServiceRegistrationRoot ID = 1040000 + iota // 1040000 - InfoSelfServiceRegistration // 1040001 - InfoSelfServiceRegistrationWith // 1040002 - InfoSelfServiceRegistrationContinue // 1040003 - InfoSelfServiceRegistrationRegisterWebAuthn // 1040004 + InfoSelfServiceRegistrationRoot ID = 1040000 + iota // 1040000 + InfoSelfServiceRegistration // 1040001 + InfoSelfServiceRegistrationWith // 1040002 + InfoSelfServiceRegistrationContinue // 1040003 + InfoSelfServiceRegistrationRegisterWebAuthn // 1040004 + InfoSelfServiceRegistrationEmailWithCodeSent // 1040005 + InfoSelfServiceRegistrationRegisterCode // 1040006 ) const ( @@ -83,6 +87,8 @@ const ( InfoNodeLabelContinue // 1070009 InfoNodeLabelRecoveryCode // 1070010 InfoNodeLabelVerificationCode // 1070011 + InfoNodeLabelRegistrationCode // 1070012 + InfoNodeLabelLoginCode // 1070013 ) const ( @@ -128,21 +134,27 @@ const ( ErrorValidationPasswordMinLength ErrorValidationPasswordMaxLength ErrorValidationPasswordTooManyBreaches + ErrorValidationNoCodeUser + ErrorValidationTraitsMismatch ) const ( - ErrorValidationLogin ID = 4010000 + iota // 4010000 - ErrorValidationLoginFlowExpired // 4010001 - ErrorValidationLoginNoStrategyFound // 4010002 - ErrorValidationRegistrationNoStrategyFound // 4010003 - ErrorValidationSettingsNoStrategyFound // 4010004 - ErrorValidationRecoveryNoStrategyFound // 4010005 - ErrorValidationVerificationNoStrategyFound // 4010006 + ErrorValidationLogin ID = 4010000 + iota // 4010000 + ErrorValidationLoginFlowExpired // 4010001 + ErrorValidationLoginNoStrategyFound // 4010002 + ErrorValidationRegistrationNoStrategyFound // 4010003 + ErrorValidationSettingsNoStrategyFound // 4010004 + ErrorValidationRecoveryNoStrategyFound // 4010005 + ErrorValidationVerificationNoStrategyFound // 4010006 + ErrorValidationLoginRetrySuccess // 4010007 + ErrorValidationLoginCodeInvalidOrAlreadyUsed // 4010008 ) const ( - ErrorValidationRegistration ID = 4040000 + iota - ErrorValidationRegistrationFlowExpired + ErrorValidationRegistration ID = 4040000 + iota + ErrorValidationRegistrationFlowExpired // 4040001 + ErrorValidateionRegistrationRetrySuccess // 4040002 + ErrorValidationRegistrationCodeInvalidOrAlreadyUsed // 4040003 ) const ( diff --git a/text/message_login.go b/text/message_login.go index 8f69fa1989a8..d5f5243be71e 100644 --- a/text/message_login.go +++ b/text/message_login.go @@ -183,3 +183,38 @@ func NewInfoSelfServiceLoginContinue() *Message { Type: Info, } } + +func NewLoginEmailWithCodeSent() *Message { + return &Message{ + ID: InfoSelfServiceLoginEmailWithCodeSent, + Type: Info, + Text: "An email containing a code has been sent to the email address you provided. If you have not received an email, check the spelling of the address and retry the login.", + Context: context(nil), + } +} + +func NewErrorValidationLoginCodeInvalidOrAlreadyUsed() *Message { + return &Message{ + ID: ErrorValidationLoginCodeInvalidOrAlreadyUsed, + Text: "The login code is invalid or has already been used. Please try again.", + Type: Error, + Context: context(nil), + } +} + +func NewErrorValidationLoginRetrySuccessful() *Message { + return &Message{ + ID: ErrorValidationLoginRetrySuccess, + Type: Error, + Text: "The request was already completed successfully and can not be retried.", + Context: context(nil), + } +} + +func NewInfoSelfServiceLoginCode() *Message { + return &Message{ + ID: InfoSelfServiceLoginCode, + Type: Info, + Text: "Sign in with code", + } +} diff --git a/text/message_node.go b/text/message_node.go index f3712ea75b6d..d9f3a03a0009 100644 --- a/text/message_node.go +++ b/text/message_node.go @@ -27,6 +27,22 @@ func NewInfoNodeLabelRecoveryCode() *Message { } } +func NewInfoNodeLabelRegistrationCode() *Message { + return &Message{ + ID: InfoNodeLabelRegistrationCode, + Text: "Registration code", + Type: Info, + } +} + +func NewInfoNodeLabelLoginCode() *Message { + return &Message{ + ID: InfoNodeLabelLoginCode, + Text: "Login code", + Type: Info, + } +} + func NewInfoNodeInputPassword() *Message { return &Message{ ID: InfoNodeLabelInputPassword, diff --git a/text/message_registration.go b/text/message_registration.go index 96fd9d4326b5..06ee4b08df94 100644 --- a/text/message_registration.go +++ b/text/message_registration.go @@ -54,3 +54,38 @@ func NewInfoSelfServiceRegistrationRegisterWebAuthn() *Message { Type: Info, } } + +func NewRegistrationEmailWithCodeSent() *Message { + return &Message{ + ID: InfoSelfServiceRegistrationEmailWithCodeSent, + Type: Info, + Text: "An email containing a code has been sent to the email address you provided. If you have not received an email, check the spelling of the address and retry the registration.", + Context: context(nil), + } +} + +func NewErrorValidationRegistrationCodeInvalidOrAlreadyUsed() *Message { + return &Message{ + ID: ErrorValidationRegistrationCodeInvalidOrAlreadyUsed, + Text: "The registration code is invalid or has already been used. Please try again.", + Type: Error, + Context: context(nil), + } +} + +func NewErrorValidationRegistrationRetrySuccessful() *Message { + return &Message{ + ID: ErrorValidateionRegistrationRetrySuccess, + Type: Error, + Text: "The request was already completed successfully and can not be retried.", + Context: context(nil), + } +} + +func NewInfoSelfServiceRegistrationRegisterCode() *Message { + return &Message{ + ID: InfoSelfServiceRegistrationRegisterCode, + Text: "Sign up with code", + Type: Info, + } +} diff --git a/text/message_validation.go b/text/message_validation.go index 3467261bb68d..8fb2391bfdce 100644 --- a/text/message_validation.go +++ b/text/message_validation.go @@ -366,3 +366,21 @@ func NewErrorValidationSuchNoWebAuthnUser() *Message { Context: context(nil), } } + +func NewErrorValidationNoCodeUser() *Message { + return &Message{ + ID: ErrorValidationNoCodeUser, + Text: "This account does not exist or has not setup sign in with code.", + Type: Error, + Context: context(nil), + } +} + +func NewErrorValidationTraitsMismatch() *Message { + return &Message{ + ID: ErrorValidationTraitsMismatch, + Text: "The provided traits do not match the traits previously associated with this flow.", + Type: Error, + Context: context(nil), + } +} diff --git a/ui/container/container.go b/ui/container/container.go index 8c1b4a0b7a47..d80683cd2800 100644 --- a/ui/container/container.go +++ b/ui/container/container.go @@ -190,7 +190,7 @@ func (c *Container) ParseError(group node.UiNodeGroup, err error) error { default: // The pointer can be ignored because if there is an error, we'll just use // the empty field (global error). - var causes = e.Causes + causes := e.Causes if len(e.Causes) == 0 { pointer, _ := jsonschemax.JSONPointerToDotNotation(e.InstancePtr) c.AddMessage(group, translateValidationError(e), pointer) @@ -339,6 +339,7 @@ func (c *Container) AddMessage(group node.UiNodeGroup, err *text.Message, setFor func (c *Container) Scan(value interface{}) error { return sqlxx.JSONScan(c, value) } + func (c *Container) Value() (driver.Value, error) { return sqlxx.JSONValue(c) } diff --git a/x/xsql/sql.go b/x/xsql/sql.go index f2354d082ca1..7ee2591bcd74 100644 --- a/x/xsql/sql.go +++ b/x/xsql/sql.go @@ -28,6 +28,8 @@ import ( func CleanSQL(t testing.TB, c *pop.Connection) { ctx := context.Background() for _, table := range []string{ + new(code.LoginCode).TableName(ctx), + new(code.RegistrationCode).TableName(ctx), new(continuity.Container).TableName(ctx), new(courier.MessageDispatch).TableName(), new(courier.Message).TableName(ctx), From 5c17c38ea928a894c3caf53ca5fccf5303dd4e7d Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Tue, 29 Aug 2023 15:11:45 +0000 Subject: [PATCH 060/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f75b3b201d16..5a3bd52995cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-08-28)](#2023-08-28) +- [ (2023-08-29)](#2023-08-29) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) - [Features](#features) @@ -309,7 +309,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-08-28) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-08-29) ### Bug Fixes @@ -407,6 +407,18 @@ - Improve messages for easier i18n ([#3457](https://github.com/ory/kratos/issues/3457)) ([37f1657](https://github.com/ory/kratos/commit/37f16577d92ba88869bf15fb1ea54e819b062724)) +- Passwordless browser login and registration via code to email + ([#3378](https://github.com/ory/kratos/issues/3378)) + ([eaaf375](https://github.com/ory/kratos/commit/eaaf37519917612671238412a633847386d7c613)), + closes [#2029](https://github.com/ory/kratos/issues/2029) + [ory-corp/cloud#3573](https://github.com/ory-corp/cloud/issues/3573): + + This feature adds passwordless email code login. When a user signs up, or + signs in, a code is sent to their email address which they can use to complete + the authentication process. + + This feature is currently only working for browser facing APIs. + - Provide login hints when registration fails due to duplicate credentials/addresses ([#3430](https://github.com/ory/kratos/issues/3430)) ([8b28469](https://github.com/ory/kratos/commit/8b284697e4a26fb01ad57d2e9ebd8f714be49f33)): From 7e05b7db3c01efc96185ac18042e971e33da37c8 Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Tue, 29 Aug 2023 18:37:17 +0200 Subject: [PATCH 061/282] fix: remove `earliest_possible_extend` default in schema (#3464) --- embedx/config.schema.json | 1 - session/handler_test.go | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/embedx/config.schema.json b/embedx/config.schema.json index be8dddc87f9b..662cd3403800 100644 --- a/embedx/config.schema.json +++ b/embedx/config.schema.json @@ -2656,7 +2656,6 @@ "description": "Sets when a session can be extended. Settings this value to `24h` will prevent the session from being extended before until 24 hours before it expires. This setting prevents excessive writes to the database. We highly recommend setting this value.", "type": "string", "pattern": "^([0-9]+(ns|us|ms|s|m|h))+$", - "default": "24h", "examples": [ "1h", "1m", diff --git a/session/handler_test.go b/session/handler_test.go index 938f772a3c6d..352301a682ab 100644 --- a/session/handler_test.go +++ b/session/handler_test.go @@ -1008,8 +1008,9 @@ func TestHandlerRefreshSessionBySessionID(t *testing.T) { require.NoError(t, err) require.Equal(t, http.StatusOK, res.StatusCode) - s, err = reg.SessionPersister().GetSession(context.Background(), s.ID, ExpandNothing) + updatedSession, err := reg.SessionPersister().GetSession(context.Background(), s.ID, ExpandNothing) require.Nil(t, err) + require.True(t, s.ExpiresAt.Before(updatedSession.ExpiresAt)) }) t.Run("case=should return 400 when bad UUID is sent", func(t *testing.T) { From 0941bdb7eaeb00d7ead6015dc9c9ef40cd5fd3dd Mon Sep 17 00:00:00 2001 From: Patrik Date: Wed, 30 Aug 2023 09:49:13 +0200 Subject: [PATCH 062/282] chore: unify and improve message context (#3462) --- cmd/clidoc/main.go | 6 +- identity/.snapshots/TestToNode.json | 6 +- schema/errors.go | 39 +---- ...=fails_if_active_strategy_is_disabled.json | 4 +- ...=fails_if_active_strategy_is_disabled.json | 4 +- ...yload_is_set_when_identity_has_lookup.json | 2 - ...=should_pass_without_csrf_if_API_flow.json | 12 +- ...generate_but_no_confirmation-type=api.json | 12 +- ...rate_but_no_confirmation-type=browser.json | 12 +- ...generate_but_no_confirmation-type=spa.json | 12 +- .../strategy/password/registration_test.go | 6 +- ...payload_is_set_when_identity_has_totp.json | 2 - ...rity_key_for_passwordless_in_mfa_flow.json | 3 +- ...ebauthn_login_is_invalid-type=browser.json | 3 +- ...if_webauthn_login_is_invalid-type=spa.json | 3 +- ...swordless-case=webauthn_button_exists.json | 1 - ...device_is_shown_which_can_be_unlinked.json | 2 + ...ntial_available-type=browser-response.json | 4 +- ...redential_available-type=spa-response.json | 4 +- ...when_passwordless_is_disabled-browser.json | 1 - ...ist_when_passwordless_is_disabled-spa.json | 1 - ...n-case=webauthn_button_exists-browser.json | 1 - ...ation-case=webauthn_button_exists-spa.json | 1 - .../strategy/webauthn/registration_test.go | 2 +- .../email/registration/errors.spec.ts | 2 +- text/context.go | 4 +- text/message_login.go | 98 +++++------ text/message_node.go | 3 + text/message_recovery.go | 53 +++--- text/message_registration.go | 35 ++-- text/message_settings.go | 29 ++-- text/message_system.go | 10 +- text/message_validation.go | 164 ++++++++++-------- text/message_verification.go | 47 +++-- 34 files changed, 289 insertions(+), 299 deletions(-) diff --git a/cmd/clidoc/main.go b/cmd/clidoc/main.go index afdad6fcd3fe..023fb8026d6b 100644 --- a/cmd/clidoc/main.go +++ b/cmd/clidoc/main.go @@ -72,7 +72,7 @@ func init() { "NewInfoSelfServiceSettingsUpdateUnlinkOIDC": text.NewInfoSelfServiceSettingsUpdateUnlinkOIDC("{provider}"), "NewInfoSelfServiceRegisterWebAuthn": text.NewInfoSelfServiceSettingsRegisterWebAuthn(), "NewInfoSelfServiceRegisterWebAuthnDisplayName": text.NewInfoSelfServiceRegisterWebAuthnDisplayName(), - "NewInfoSelfServiceRemoveWebAuthn": text.NewInfoSelfServiceRemoveWebAuthn("{name}", aSecondAgo), + "NewInfoSelfServiceRemoveWebAuthn": text.NewInfoSelfServiceRemoveWebAuthn("{display_name}", aSecondAgo), "NewErrorValidationVerificationFlowExpired": text.NewErrorValidationVerificationFlowExpired(aSecondAgo), "NewInfoSelfServiceVerificationSuccessful": text.NewInfoSelfServiceVerificationSuccessful(), "NewVerificationEmailSent": text.NewVerificationEmailSent(), @@ -83,7 +83,7 @@ func init() { "NewErrorValidationVerificationCodeInvalidOrAlreadyUsed": text.NewErrorValidationVerificationCodeInvalidOrAlreadyUsed(), "NewErrorSystemGeneric": text.NewErrorSystemGeneric("{reason}"), "NewValidationErrorGeneric": text.NewValidationErrorGeneric("{reason}"), - "NewValidationErrorRequired": text.NewValidationErrorRequired("{field}"), + "NewValidationErrorRequired": text.NewValidationErrorRequired("{property}"), "NewErrorValidationMinLength": text.NewErrorValidationMinLength(5, 3), "NewErrorValidationMaxLength": text.NewErrorValidationMaxLength(5, 6), "NewErrorValidationInvalidFormat": text.NewErrorValidationInvalidFormat("{pattern}"), @@ -105,7 +105,7 @@ func init() { "NewErrorValidationPasswordTooManyBreaches": text.NewErrorValidationPasswordTooManyBreaches(101), "NewErrorValidationInvalidCredentials": text.NewErrorValidationInvalidCredentials(), "NewErrorValidationDuplicateCredentials": text.NewErrorValidationDuplicateCredentials(), - "NewErrorValidationDuplicateCredentialsWithHints": text.NewErrorValidationDuplicateCredentialsWithHints("{reason}", nil, nil, ""), + "NewErrorValidationDuplicateCredentialsWithHints": text.NewErrorValidationDuplicateCredentialsWithHints([]string{"{available_credential_types_list}"}, []string{"{available_oidc_providers_list}"}, "{credential_identifier_hint}"), "NewErrorValidationDuplicateCredentialsOnOIDCLink": text.NewErrorValidationDuplicateCredentialsOnOIDCLink(), "NewErrorValidationTOTPVerifierWrong": text.NewErrorValidationTOTPVerifierWrong(), "NewErrorValidationLookupAlreadyUsed": text.NewErrorValidationLookupAlreadyUsed(), diff --git a/identity/.snapshots/TestToNode.json b/identity/.snapshots/TestToNode.json index 2d9c6b3e9b2b..43295a2f2fa7 100644 --- a/identity/.snapshots/TestToNode.json +++ b/identity/.snapshots/TestToNode.json @@ -13,7 +13,8 @@ "text": "Secret was used at 2021-08-17 11:32:38 +0000 UTC", "type": "info", "context": { - "used_at": "2021-08-17T11:32:38Z" + "used_at": "2021-08-17T11:32:38Z", + "used_at_unix": 1629199958 } }, { @@ -37,7 +38,8 @@ "text": "Secret was used at 2021-08-17 11:32:48 +0000 UTC", "type": "info", "context": { - "used_at": "2021-08-17T11:32:48Z" + "used_at": "2021-08-17T11:32:48Z", + "used_at_unix": 1629199968 } } ] diff --git a/schema/errors.go b/schema/errors.go index 8cd74c5aec60..55957a10460c 100644 --- a/schema/errors.go +++ b/schema/errors.go @@ -5,10 +5,6 @@ package schema import ( "fmt" - "strings" - - "golang.org/x/text/cases" - "golang.org/x/text/language" "github.com/pkg/errors" @@ -146,39 +142,6 @@ type DuplicateCredentialsHinter interface { func NewDuplicateCredentialsError(err error) error { if hinter := DuplicateCredentialsHinter(nil); errors.As(err, &hinter) && hinter.HasHints() { - oidcProviders := make([]string, 0, len(hinter.AvailableOIDCProviders())) - for _, provider := range hinter.AvailableOIDCProviders() { - oidcProviders = append(oidcProviders, cases.Title(language.English).String(provider)) - } - - reason := "" - if hinter.IdentifierHint() != "" { - reason = fmt.Sprintf("You tried signing with %s which is already in use by another account.", hinter.IdentifierHint()) - } else { - reason = "You tried to sign up using an email, phone, or username that is already used by another account." - } - - if len(hinter.AvailableCredentials()) > 0 { - humanReadable := make([]string, 0, len(hinter.AvailableCredentials())) - for _, cred := range hinter.AvailableCredentials() { - switch cred { - case "password": - humanReadable = append(humanReadable, "your password") - case "oidc": - humanReadable = append(humanReadable, "social sign in") - case "webauthn": - humanReadable = append(humanReadable, "your PassKey or a security key") - } - } - - reason = fmt.Sprintf("%s You can sign in using %s.", reason, strings.Join(humanReadable, ", ")) - if len(hinter.AvailableOIDCProviders()) > 0 { - reason = fmt.Sprintf("%s Use one of the following social sign in providers: %s", reason, strings.Join(oidcProviders, ", ")) - } - } else if len(hinter.AvailableOIDCProviders()) > 0 { - reason = fmt.Sprintf("%s You can sign in using one of the following social sign in providers: %s.", reason, strings.Join(oidcProviders, ", ")) - } - return errors.WithStack(&ValidationError{ ValidationError: &jsonschema.ValidationError{ Message: `an account with the same identifier (email, phone, username, ...) exists already`, @@ -189,7 +152,7 @@ func NewDuplicateCredentialsError(err error) error { IdentifierHint: hinter.IdentifierHint(), }, }, - Messages: new(text.Messages).Add(text.NewErrorValidationDuplicateCredentialsWithHints(reason, hinter.AvailableCredentials(), hinter.AvailableOIDCProviders(), hinter.IdentifierHint())), + Messages: new(text.Messages).Add(text.NewErrorValidationDuplicateCredentialsWithHints(hinter.AvailableCredentials(), hinter.AvailableOIDCProviders(), hinter.IdentifierHint())), }) } diff --git a/selfservice/flow/recovery/.snapshots/TestHandleError-flow=api-case=fails_if_active_strategy_is_disabled.json b/selfservice/flow/recovery/.snapshots/TestHandleError-flow=api-case=fails_if_active_strategy_is_disabled.json index 4bb7e689fd5a..d6c78d8b8358 100644 --- a/selfservice/flow/recovery/.snapshots/TestHandleError-flow=api-case=fails_if_active_strategy_is_disabled.json +++ b/selfservice/flow/recovery/.snapshots/TestHandleError-flow=api-case=fails_if_active_strategy_is_disabled.json @@ -62,7 +62,9 @@ "id": 4000001, "text": "The active recovery strategy code is not enabled. Please enable it in the configuration.", "type": "error", - "context": {} + "context": { + "reason": "The active recovery strategy code is not enabled. Please enable it in the configuration." + } } ] }, diff --git a/selfservice/flow/recovery/.snapshots/TestHandleError-flow=spa-case=fails_if_active_strategy_is_disabled.json b/selfservice/flow/recovery/.snapshots/TestHandleError-flow=spa-case=fails_if_active_strategy_is_disabled.json index 7e6c9fd7f953..7a17de3f9374 100644 --- a/selfservice/flow/recovery/.snapshots/TestHandleError-flow=spa-case=fails_if_active_strategy_is_disabled.json +++ b/selfservice/flow/recovery/.snapshots/TestHandleError-flow=spa-case=fails_if_active_strategy_is_disabled.json @@ -62,7 +62,9 @@ "id": 4000001, "text": "The active recovery strategy code is not enabled. Please enable it in the configuration.", "type": "error", - "context": {} + "context": { + "reason": "The active recovery strategy code is not enabled. Please enable it in the configuration." + } } ] }, diff --git a/selfservice/strategy/lookup/.snapshots/TestCompleteLogin-case=lookup_payload_is_set_when_identity_has_lookup.json b/selfservice/strategy/lookup/.snapshots/TestCompleteLogin-case=lookup_payload_is_set_when_identity_has_lookup.json index b732a1221b9f..4de9e6d84166 100644 --- a/selfservice/strategy/lookup/.snapshots/TestCompleteLogin-case=lookup_payload_is_set_when_identity_has_lookup.json +++ b/selfservice/strategy/lookup/.snapshots/TestCompleteLogin-case=lookup_payload_is_set_when_identity_has_lookup.json @@ -25,7 +25,6 @@ "messages": [], "meta": { "label": { - "context": {}, "id": 1010007, "text": "Backup recovery code", "type": "info" @@ -45,7 +44,6 @@ "messages": [], "meta": { "label": { - "context": {}, "id": 1010010, "text": "Use backup recovery code", "type": "info" diff --git a/selfservice/strategy/lookup/.snapshots/TestCompleteSettings-case=should_pass_without_csrf_if_API_flow.json b/selfservice/strategy/lookup/.snapshots/TestCompleteSettings-case=should_pass_without_csrf_if_API_flow.json index 2a63830646d9..8b4fe733e80f 100644 --- a/selfservice/strategy/lookup/.snapshots/TestCompleteSettings-case=should_pass_without_csrf_if_API_flow.json +++ b/selfservice/strategy/lookup/.snapshots/TestCompleteSettings-case=should_pass_without_csrf_if_API_flow.json @@ -35,7 +35,8 @@ "text": "Secret was used at 2021-08-17 11:32:39 +0000 UTC", "type": "info", "context": { - "used_at": "2021-08-17T11:32:39Z" + "used_at": "2021-08-17T11:32:39Z", + "used_at_unix": 1629199959 } }, { @@ -59,7 +60,8 @@ "text": "Secret was used at 2021-08-17 11:32:42 +0000 UTC", "type": "info", "context": { - "used_at": "2021-08-17T11:32:42Z" + "used_at": "2021-08-17T11:32:42Z", + "used_at_unix": 1629199962 } }, { @@ -83,7 +85,8 @@ "text": "Secret was used at 2021-08-17 11:32:45 +0000 UTC", "type": "info", "context": { - "used_at": "2021-08-17T11:32:45Z" + "used_at": "2021-08-17T11:32:45Z", + "used_at_unix": 1629199965 } }, { @@ -107,7 +110,8 @@ "text": "Secret was used at 2021-08-17 11:32:48 +0000 UTC", "type": "info", "context": { - "used_at": "2021-08-17T11:32:48Z" + "used_at": "2021-08-17T11:32:48Z", + "used_at_unix": 1629199968 } }, { diff --git a/selfservice/strategy/lookup/.snapshots/TestCompleteSettings-type=regenerate_but_no_confirmation-type=api.json b/selfservice/strategy/lookup/.snapshots/TestCompleteSettings-type=regenerate_but_no_confirmation-type=api.json index 2a63830646d9..8b4fe733e80f 100644 --- a/selfservice/strategy/lookup/.snapshots/TestCompleteSettings-type=regenerate_but_no_confirmation-type=api.json +++ b/selfservice/strategy/lookup/.snapshots/TestCompleteSettings-type=regenerate_but_no_confirmation-type=api.json @@ -35,7 +35,8 @@ "text": "Secret was used at 2021-08-17 11:32:39 +0000 UTC", "type": "info", "context": { - "used_at": "2021-08-17T11:32:39Z" + "used_at": "2021-08-17T11:32:39Z", + "used_at_unix": 1629199959 } }, { @@ -59,7 +60,8 @@ "text": "Secret was used at 2021-08-17 11:32:42 +0000 UTC", "type": "info", "context": { - "used_at": "2021-08-17T11:32:42Z" + "used_at": "2021-08-17T11:32:42Z", + "used_at_unix": 1629199962 } }, { @@ -83,7 +85,8 @@ "text": "Secret was used at 2021-08-17 11:32:45 +0000 UTC", "type": "info", "context": { - "used_at": "2021-08-17T11:32:45Z" + "used_at": "2021-08-17T11:32:45Z", + "used_at_unix": 1629199965 } }, { @@ -107,7 +110,8 @@ "text": "Secret was used at 2021-08-17 11:32:48 +0000 UTC", "type": "info", "context": { - "used_at": "2021-08-17T11:32:48Z" + "used_at": "2021-08-17T11:32:48Z", + "used_at_unix": 1629199968 } }, { diff --git a/selfservice/strategy/lookup/.snapshots/TestCompleteSettings-type=regenerate_but_no_confirmation-type=browser.json b/selfservice/strategy/lookup/.snapshots/TestCompleteSettings-type=regenerate_but_no_confirmation-type=browser.json index 2a63830646d9..8b4fe733e80f 100644 --- a/selfservice/strategy/lookup/.snapshots/TestCompleteSettings-type=regenerate_but_no_confirmation-type=browser.json +++ b/selfservice/strategy/lookup/.snapshots/TestCompleteSettings-type=regenerate_but_no_confirmation-type=browser.json @@ -35,7 +35,8 @@ "text": "Secret was used at 2021-08-17 11:32:39 +0000 UTC", "type": "info", "context": { - "used_at": "2021-08-17T11:32:39Z" + "used_at": "2021-08-17T11:32:39Z", + "used_at_unix": 1629199959 } }, { @@ -59,7 +60,8 @@ "text": "Secret was used at 2021-08-17 11:32:42 +0000 UTC", "type": "info", "context": { - "used_at": "2021-08-17T11:32:42Z" + "used_at": "2021-08-17T11:32:42Z", + "used_at_unix": 1629199962 } }, { @@ -83,7 +85,8 @@ "text": "Secret was used at 2021-08-17 11:32:45 +0000 UTC", "type": "info", "context": { - "used_at": "2021-08-17T11:32:45Z" + "used_at": "2021-08-17T11:32:45Z", + "used_at_unix": 1629199965 } }, { @@ -107,7 +110,8 @@ "text": "Secret was used at 2021-08-17 11:32:48 +0000 UTC", "type": "info", "context": { - "used_at": "2021-08-17T11:32:48Z" + "used_at": "2021-08-17T11:32:48Z", + "used_at_unix": 1629199968 } }, { diff --git a/selfservice/strategy/lookup/.snapshots/TestCompleteSettings-type=regenerate_but_no_confirmation-type=spa.json b/selfservice/strategy/lookup/.snapshots/TestCompleteSettings-type=regenerate_but_no_confirmation-type=spa.json index 2a63830646d9..8b4fe733e80f 100644 --- a/selfservice/strategy/lookup/.snapshots/TestCompleteSettings-type=regenerate_but_no_confirmation-type=spa.json +++ b/selfservice/strategy/lookup/.snapshots/TestCompleteSettings-type=regenerate_but_no_confirmation-type=spa.json @@ -35,7 +35,8 @@ "text": "Secret was used at 2021-08-17 11:32:39 +0000 UTC", "type": "info", "context": { - "used_at": "2021-08-17T11:32:39Z" + "used_at": "2021-08-17T11:32:39Z", + "used_at_unix": 1629199959 } }, { @@ -59,7 +60,8 @@ "text": "Secret was used at 2021-08-17 11:32:42 +0000 UTC", "type": "info", "context": { - "used_at": "2021-08-17T11:32:42Z" + "used_at": "2021-08-17T11:32:42Z", + "used_at_unix": 1629199962 } }, { @@ -83,7 +85,8 @@ "text": "Secret was used at 2021-08-17 11:32:45 +0000 UTC", "type": "info", "context": { - "used_at": "2021-08-17T11:32:45Z" + "used_at": "2021-08-17T11:32:45Z", + "used_at_unix": 1629199965 } }, { @@ -107,7 +110,8 @@ "text": "Secret was used at 2021-08-17 11:32:48 +0000 UTC", "type": "info", "context": { - "used_at": "2021-08-17T11:32:48Z" + "used_at": "2021-08-17T11:32:48Z", + "used_at_unix": 1629199968 } }, { diff --git a/selfservice/strategy/password/registration_test.go b/selfservice/strategy/password/registration_test.go index 1587888e0168..2311741daad7 100644 --- a/selfservice/strategy/password/registration_test.go +++ b/selfservice/strategy/password/registration_test.go @@ -302,7 +302,7 @@ func TestRegistration(t *testing.T) { body := testhelpers.SubmitRegistrationForm(t, true, apiClient, publicTS, applyTransform(values, transform), false, http.StatusBadRequest, publicTS.URL+registration.RouteSubmitFlow) - assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "You tried signing with registration-identifier-8-api-duplicate-"+suffix+" which is already in use by another account. You can sign in using your password.", "%s", body) + assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "You tried signing in with registration-identifier-8-api-duplicate-"+suffix+" which is already in use by another account. You can sign in using your password.", "%s", body) }) t.Run("type=spa", func(t *testing.T) { @@ -314,7 +314,7 @@ func TestRegistration(t *testing.T) { _ = expectSuccessfulLogin(t, false, true, nil, values) body := registrationhelpers.ExpectValidationError(t, publicTS, conf, "spa", applyTransform(values, transform)) - assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "You tried signing with registration-identifier-8-spa-duplicate-"+suffix+" which is already in use by another account. You can sign in using your password.", "%s", body) + assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "You tried signing in with registration-identifier-8-spa-duplicate-"+suffix+" which is already in use by another account. You can sign in using your password.", "%s", body) }) t.Run("type=browser", func(t *testing.T) { @@ -326,7 +326,7 @@ func TestRegistration(t *testing.T) { _ = expectSuccessfulLogin(t, false, false, nil, values) body := registrationhelpers.ExpectValidationError(t, publicTS, conf, "browser", applyTransform(values, transform)) - assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "You tried signing with registration-identifier-8-browser-duplicate-"+suffix+" which is already in use by another account. You can sign in using your password.", "%s", body) + assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "You tried signing in with registration-identifier-8-browser-duplicate-"+suffix+" which is already in use by another account. You can sign in using your password.", "%s", body) }) } diff --git a/selfservice/strategy/totp/.snapshots/TestCompleteLogin-case=totp_payload_is_set_when_identity_has_totp.json b/selfservice/strategy/totp/.snapshots/TestCompleteLogin-case=totp_payload_is_set_when_identity_has_totp.json index ff40c45ad144..afae3de49f05 100644 --- a/selfservice/strategy/totp/.snapshots/TestCompleteLogin-case=totp_payload_is_set_when_identity_has_totp.json +++ b/selfservice/strategy/totp/.snapshots/TestCompleteLogin-case=totp_payload_is_set_when_identity_has_totp.json @@ -25,7 +25,6 @@ "messages": [], "meta": { "label": { - "context": {}, "id": 1010006, "text": "Authentication code", "type": "info" @@ -45,7 +44,6 @@ "messages": [], "meta": { "label": { - "context": {}, "id": 1010009, "text": "Use Authenticator", "type": "info" diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=mfa-case=can_not_use_security_key_for_passwordless_in_mfa_flow.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=mfa-case=can_not_use_security_key_for_passwordless_in_mfa_flow.json index 560d85d68d4c..4ca8cb394931 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=mfa-case=can_not_use_security_key_for_passwordless_in_mfa_flow.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=mfa-case=can_not_use_security_key_for_passwordless_in_mfa_flow.json @@ -2,7 +2,6 @@ { "id": 4000008, "text": "The provided authentication code is invalid, please try again.", - "type": "error", - "context": {} + "type": "error" } ] 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 a12f8fc0e182..49c3fede7254 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 @@ -76,8 +76,7 @@ "messages": [ { "text": "Prepare your WebAuthn device (e.g. security key, biometrics scanner, ...) and press continue.", - "type": "info", - "context": {} + "type": "info" } ] }, 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 a12f8fc0e182..49c3fede7254 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 @@ -76,8 +76,7 @@ "messages": [ { "text": "Prepare your WebAuthn device (e.g. security key, biometrics scanner, ...) and press continue.", - "type": "info", - "context": {} + "type": "info" } ] }, diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=passwordless-case=webauthn_button_exists.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=passwordless-case=webauthn_button_exists.json index 2b73efff9f55..0c402bfe2612 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=passwordless-case=webauthn_button_exists.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=passwordless-case=webauthn_button_exists.json @@ -44,7 +44,6 @@ "messages": [], "meta": { "label": { - "context": {}, "id": 1010001, "text": "Sign in with security key", "type": "info" diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=a_device_is_shown_which_can_be_unlinked.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=a_device_is_shown_which_can_be_unlinked.json index 43a740b43790..d27075b6063d 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=a_device_is_shown_which_can_be_unlinked.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=a_device_is_shown_which_can_be_unlinked.json @@ -26,6 +26,7 @@ "label": { "context": { "added_at": "0001-01-01T00:00:00Z", + "added_at_unix": -62135596800, "display_name": "bar" }, "id": 1050018, @@ -49,6 +50,7 @@ "label": { "context": { "added_at": "0001-01-01T00:00:00Z", + "added_at_unix": -62135596800, "display_name": "foo" }, "id": 1050018, diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=fails_to_remove_security_key_if_it_is_passwordless_and_the_last_credential_available-type=browser-response.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=fails_to_remove_security_key_if_it_is_passwordless_and_the_last_credential_available-type=browser-response.json index c3147ce1a714..ab452afa7ea9 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=fails_to_remove_security_key_if_it_is_passwordless_and_the_last_credential_available-type=browser-response.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=fails_to_remove_security_key_if_it_is_passwordless_and_the_last_credential_available-type=browser-response.json @@ -12,7 +12,9 @@ "id": 4000001, "text": "unable to remove this security key because it would lock you out of your account", "type": "error", - "context": {} + "context": { + "reason": "unable to remove this security key because it would lock you out of your account" + } } ], "meta": {} diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=fails_to_remove_security_key_if_it_is_passwordless_and_the_last_credential_available-type=spa-response.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=fails_to_remove_security_key_if_it_is_passwordless_and_the_last_credential_available-type=spa-response.json index c3147ce1a714..ab452afa7ea9 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=fails_to_remove_security_key_if_it_is_passwordless_and_the_last_credential_available-type=spa-response.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=fails_to_remove_security_key_if_it_is_passwordless_and_the_last_credential_available-type=spa-response.json @@ -12,7 +12,9 @@ "id": 4000001, "text": "unable to remove this security key because it would lock you out of your account", "type": "error", - "context": {} + "context": { + "reason": "unable to remove this security key because it would lock you out of your account" + } } ], "meta": {} diff --git a/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_does_not_exist_when_passwordless_is_disabled-browser.json b/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_does_not_exist_when_passwordless_is_disabled-browser.json index 3d16974da7c4..cd42a6256ce0 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_does_not_exist_when_passwordless_is_disabled-browser.json +++ b/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_does_not_exist_when_passwordless_is_disabled-browser.json @@ -70,7 +70,6 @@ "messages": [], "meta": { "label": { - "context": {}, "id": 1040001, "text": "Sign up", "type": "info" diff --git a/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_does_not_exist_when_passwordless_is_disabled-spa.json b/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_does_not_exist_when_passwordless_is_disabled-spa.json index 3d16974da7c4..cd42a6256ce0 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_does_not_exist_when_passwordless_is_disabled-spa.json +++ b/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_does_not_exist_when_passwordless_is_disabled-spa.json @@ -70,7 +70,6 @@ "messages": [], "meta": { "label": { - "context": {}, "id": 1040001, "text": "Sign up", "type": "info" diff --git a/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-browser.json b/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-browser.json index 09b1f9ed6449..f95c0ade36aa 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-browser.json +++ b/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-browser.json @@ -136,7 +136,6 @@ "messages": [], "meta": { "label": { - "context": {}, "id": 1040001, "text": "Sign up", "type": "info" diff --git a/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-spa.json b/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-spa.json index 09b1f9ed6449..f95c0ade36aa 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-spa.json +++ b/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-spa.json @@ -136,7 +136,6 @@ "messages": [], "meta": { "label": { - "context": {}, "id": 1040001, "text": "Sign up", "type": "info" diff --git a/selfservice/strategy/webauthn/registration_test.go b/selfservice/strategy/webauthn/registration_test.go index 7326cdfd04ab..cc20d431230c 100644 --- a/selfservice/strategy/webauthn/registration_test.go +++ b/selfservice/strategy/webauthn/registration_test.go @@ -393,7 +393,7 @@ func TestRegistration(t *testing.T) { actual, _, _ = makeRegistration(t, f, values(email)) assert.Contains(t, gjson.Get(actual, "ui.action").String(), publicTS.URL+registration.RouteSubmitFlow, "%s", actual) registrationhelpers.CheckFormContent(t, []byte(actual), node.WebAuthnRegisterTrigger, "csrf_token", "traits.username") - assert.Equal(t, "You tried signing with "+email+" which is already in use by another account. You can sign in using your password.", gjson.Get(actual, "ui.messages.0.text").String(), "%s", actual) + assert.Equal(t, "You tried signing in with "+email+" which is already in use by another account. You can sign in using your password.", gjson.Get(actual, "ui.messages.0.text").String(), "%s", actual) }) } }) diff --git a/test/e2e/cypress/integration/profiles/email/registration/errors.spec.ts b/test/e2e/cypress/integration/profiles/email/registration/errors.spec.ts index bf0712da054e..54617e8d7d2c 100644 --- a/test/e2e/cypress/integration/profiles/email/registration/errors.spec.ts +++ b/test/e2e/cypress/integration/profiles/email/registration/errors.spec.ts @@ -247,7 +247,7 @@ describe("Registration failures with email profile", () => { cy.submitPasswordForm() cy.get('[data-testid="ui/message/4000028"]').should( "contain.text", - "You tried signing with " + + "You tried signing in with " + email + " which is already in use by another account. You can sign in using your password.", ) diff --git a/text/context.go b/text/context.go index c47a7efa4565..a0f304ba7171 100644 --- a/text/context.go +++ b/text/context.go @@ -7,9 +7,9 @@ import ( "encoding/json" ) -func context(ctx map[string]interface{}) []byte { +func context(ctx map[string]any) []byte { if len(ctx) == 0 { - return []byte("{}") + panic("context must not be empty") } res, err := json.Marshal(ctx) if err != nil { diff --git a/text/message_login.go b/text/message_login.go index d5f5243be71e..a67d1f692c6a 100644 --- a/text/message_login.go +++ b/text/message_login.go @@ -10,91 +10,81 @@ import ( func NewInfoLoginReAuth() *Message { return &Message{ - ID: InfoSelfServiceLoginReAuth, - Type: Info, - Text: "Please confirm this action by verifying that it is you.", - Context: context(nil), + ID: InfoSelfServiceLoginReAuth, + Type: Info, + Text: "Please confirm this action by verifying that it is you.", } } func NewInfoLoginMFA() *Message { return &Message{ - ID: InfoSelfServiceLoginMFA, - Type: Info, - Text: "Please complete the second authentication challenge.", - Context: context(nil), + ID: InfoSelfServiceLoginMFA, + Type: Info, + Text: "Please complete the second authentication challenge.", } } func NewInfoLoginWebAuthnPasswordless() *Message { return &Message{ - ID: InfoSelfServiceLoginWebAuthnPasswordless, - Type: Info, - Text: "Prepare your WebAuthn device (e.g. security key, biometrics scanner, ...) and press continue.", - Context: context(nil), + ID: InfoSelfServiceLoginWebAuthnPasswordless, + Type: Info, + Text: "Prepare your WebAuthn device (e.g. security key, biometrics scanner, ...) and press continue.", } } func NewInfoLoginTOTPLabel() *Message { return &Message{ - ID: InfoSelfServiceLoginTOTPLabel, - Type: Info, - Text: "Authentication code", - Context: context(nil), + ID: InfoSelfServiceLoginTOTPLabel, + Type: Info, + Text: "Authentication code", } } func NewInfoLoginLookupLabel() *Message { return &Message{ - ID: InfoLoginLookupLabel, - Type: Info, - Text: "Backup recovery code", - Context: context(nil), + ID: InfoLoginLookupLabel, + Type: Info, + Text: "Backup recovery code", } } func NewInfoLogin() *Message { return &Message{ - ID: InfoSelfServiceLogin, - Text: "Sign in", - Type: Info, - Context: context(map[string]interface{}{}), + ID: InfoSelfServiceLogin, + Text: "Sign in", + Type: Info, } } func NewInfoLoginPasswordlessWebAuthn() *Message { return &Message{ - ID: InfoSelfServiceLogin, - Text: "Sign in with security key", - Type: Info, - Context: context(map[string]interface{}{}), + ID: InfoSelfServiceLogin, + Text: "Sign in with security key", + Type: Info, } } func NewInfoLoginTOTP() *Message { return &Message{ - ID: InfoLoginTOTP, - Text: "Use Authenticator", - Type: Info, - Context: context(map[string]interface{}{}), + ID: InfoLoginTOTP, + Text: "Use Authenticator", + Type: Info, } } func NewInfoLoginLookup() *Message { return &Message{ - ID: InfoLoginLookup, - Text: "Use backup recovery code", - Type: Info, - Context: context(map[string]interface{}{}), + ID: InfoLoginLookup, + Text: "Use backup recovery code", + Type: Info, } } func NewInfoLoginVerify() *Message { return &Message{ - ID: InfoSelfServiceLoginVerify, - Text: "Verify", - Type: Info, - Context: context(map[string]interface{}{}), + ID: InfoSelfServiceLoginVerify, + Text: "Verify", + Type: Info, } } @@ -103,7 +93,7 @@ func NewInfoLoginWith(provider string) *Message { ID: InfoSelfServiceLoginWith, Text: fmt.Sprintf("Sign in with %s", provider), Type: Info, - Context: context(map[string]interface{}{ + Context: context(map[string]any{ "provider": provider, }), } @@ -114,8 +104,9 @@ func NewErrorValidationLoginFlowExpired(expiredAt time.Time) *Message { ID: ErrorValidationLoginFlowExpired, Text: fmt.Sprintf("The login flow expired %.2f minutes ago, please try again.", Since(expiredAt).Minutes()), Type: Error, - Context: context(map[string]interface{}{ - "expired_at": expiredAt, + Context: context(map[string]any{ + "expired_at": expiredAt, + "expired_at_unix": expiredAt.Unix(), }), } } @@ -186,28 +177,25 @@ func NewInfoSelfServiceLoginContinue() *Message { func NewLoginEmailWithCodeSent() *Message { return &Message{ - ID: InfoSelfServiceLoginEmailWithCodeSent, - Type: Info, - Text: "An email containing a code has been sent to the email address you provided. If you have not received an email, check the spelling of the address and retry the login.", - Context: context(nil), + ID: InfoSelfServiceLoginEmailWithCodeSent, + Type: Info, + Text: "An email containing a code has been sent to the email address you provided. If you have not received an email, check the spelling of the address and retry the login.", } } func NewErrorValidationLoginCodeInvalidOrAlreadyUsed() *Message { return &Message{ - ID: ErrorValidationLoginCodeInvalidOrAlreadyUsed, - Text: "The login code is invalid or has already been used. Please try again.", - Type: Error, - Context: context(nil), + ID: ErrorValidationLoginCodeInvalidOrAlreadyUsed, + Text: "The login code is invalid or has already been used. Please try again.", + Type: Error, } } func NewErrorValidationLoginRetrySuccessful() *Message { return &Message{ - ID: ErrorValidationLoginRetrySuccess, - Type: Error, - Text: "The request was already completed successfully and can not be retried.", - Context: context(nil), + ID: ErrorValidationLoginRetrySuccess, + Type: Error, + Text: "The request was already completed successfully and can not be retried.", } } diff --git a/text/message_node.go b/text/message_node.go index d9f3a03a0009..3af122ae542b 100644 --- a/text/message_node.go +++ b/text/message_node.go @@ -56,6 +56,9 @@ func NewInfoNodeLabelGenerated(title string) *Message { ID: InfoNodeLabelGenerated, Text: title, Type: Info, + Context: context(map[string]any{ + "title": title, + }), } } diff --git a/text/message_recovery.go b/text/message_recovery.go index 94801365a555..d78e8b2adcd8 100644 --- a/text/message_recovery.go +++ b/text/message_recovery.go @@ -13,8 +13,9 @@ func NewErrorValidationRecoveryFlowExpired(expiredAt time.Time) *Message { ID: ErrorValidationRecoveryFlowExpired, Text: fmt.Sprintf("The recovery flow expired %.2f minutes ago, please try again.", Since(expiredAt).Minutes()), Type: Error, - Context: context(map[string]interface{}{ - "expired_at": expiredAt, + Context: context(map[string]any{ + "expired_at": expiredAt, + "expired_at_unix": expiredAt.Unix(), }), } } @@ -25,62 +26,58 @@ func NewRecoverySuccessful(privilegedSessionExpiresAt time.Time) *Message { ID: InfoSelfServiceRecoverySuccessful, Type: Success, Text: fmt.Sprintf("You successfully recovered your account. Please change your password or set up an alternative login method (e.g. social sign in) within the next %.2f minutes.", hasLeft.Minutes()), - Context: context(map[string]interface{}{ - "privilegedSessionExpiresAt": privilegedSessionExpiresAt, + Context: context(map[string]any{ + "privilegedSessionExpiresAt": privilegedSessionExpiresAt, + "privileged_session_expires_at": privilegedSessionExpiresAt, + "privileged_session_expires_at_unix": privilegedSessionExpiresAt.Unix(), }), } } func NewRecoveryEmailSent() *Message { return &Message{ - ID: InfoSelfServiceRecoveryEmailSent, - Type: Info, - Text: "An email containing a recovery link has been sent to the email address you provided. If you have not received an email, check the spelling of the address and make sure to use the address you registered with.", - Context: context(nil), + ID: InfoSelfServiceRecoveryEmailSent, + Type: Info, + Text: "An email containing a recovery link has been sent to the email address you provided. If you have not received an email, check the spelling of the address and make sure to use the address you registered with.", } } func NewRecoveryEmailWithCodeSent() *Message { return &Message{ - ID: InfoSelfServiceRecoveryEmailWithCodeSent, - Type: Info, - Text: "An email containing a recovery code has been sent to the email address you provided. If you have not received an email, check the spelling of the address and make sure to use the address you registered with.", - Context: context(nil), + ID: InfoSelfServiceRecoveryEmailWithCodeSent, + Type: Info, + Text: "An email containing a recovery code has been sent to the email address you provided. If you have not received an email, check the spelling of the address and make sure to use the address you registered with.", } } func NewErrorValidationRecoveryTokenInvalidOrAlreadyUsed() *Message { return &Message{ - ID: ErrorValidationRecoveryTokenInvalidOrAlreadyUsed, - Text: "The recovery token is invalid or has already been used. Please retry the flow.", - Type: Error, - Context: context(nil), + ID: ErrorValidationRecoveryTokenInvalidOrAlreadyUsed, + Text: "The recovery token is invalid or has already been used. Please retry the flow.", + Type: Error, } } func NewErrorValidationRecoveryCodeInvalidOrAlreadyUsed() *Message { return &Message{ - ID: ErrorValidationRecoveryCodeInvalidOrAlreadyUsed, - Text: "The recovery code is invalid or has already been used. Please try again.", - Type: Error, - Context: context(nil), + ID: ErrorValidationRecoveryCodeInvalidOrAlreadyUsed, + Text: "The recovery code is invalid or has already been used. Please try again.", + Type: Error, } } func NewErrorValidationRecoveryRetrySuccess() *Message { return &Message{ - ID: ErrorValidationRecoveryRetrySuccess, - Text: "The request was already completed successfully and can not be retried.", - Type: Error, - Context: context(nil), + ID: ErrorValidationRecoveryRetrySuccess, + Text: "The request was already completed successfully and can not be retried.", + Type: Error, } } func NewErrorValidationRecoveryStateFailure() *Message { return &Message{ - ID: ErrorValidationRecoveryStateFailure, - Text: "The recovery flow reached a failure state and must be retried.", - Type: Error, - Context: context(nil), + ID: ErrorValidationRecoveryStateFailure, + Text: "The recovery flow reached a failure state and must be retried.", + Type: Error, } } diff --git a/text/message_registration.go b/text/message_registration.go index 06ee4b08df94..2dcf807a4766 100644 --- a/text/message_registration.go +++ b/text/message_registration.go @@ -10,10 +10,9 @@ import ( func NewInfoRegistration() *Message { return &Message{ - ID: InfoSelfServiceRegistration, - Text: "Sign up", - Type: Info, - Context: context(map[string]interface{}{}), + ID: InfoSelfServiceRegistration, + Text: "Sign up", + Type: Info, } } @@ -22,7 +21,7 @@ func NewInfoRegistrationWith(provider string) *Message { ID: InfoSelfServiceRegistrationWith, Text: fmt.Sprintf("Sign up with %s", provider), Type: Info, - Context: context(map[string]interface{}{ + Context: context(map[string]any{ "provider": provider, }), } @@ -41,8 +40,9 @@ func NewErrorValidationRegistrationFlowExpired(expiredAt time.Time) *Message { ID: ErrorValidationRegistrationFlowExpired, Text: fmt.Sprintf("The registration flow expired %.2f minutes ago, please try again.", Since(expiredAt).Minutes()), Type: Error, - Context: context(map[string]interface{}{ - "expired_at": expiredAt, + Context: context(map[string]any{ + "expired_at": expiredAt, + "expired_at_unix": expiredAt.Unix(), }), } } @@ -57,28 +57,25 @@ func NewInfoSelfServiceRegistrationRegisterWebAuthn() *Message { func NewRegistrationEmailWithCodeSent() *Message { return &Message{ - ID: InfoSelfServiceRegistrationEmailWithCodeSent, - Type: Info, - Text: "An email containing a code has been sent to the email address you provided. If you have not received an email, check the spelling of the address and retry the registration.", - Context: context(nil), + ID: InfoSelfServiceRegistrationEmailWithCodeSent, + Type: Info, + Text: "An email containing a code has been sent to the email address you provided. If you have not received an email, check the spelling of the address and retry the registration.", } } func NewErrorValidationRegistrationCodeInvalidOrAlreadyUsed() *Message { return &Message{ - ID: ErrorValidationRegistrationCodeInvalidOrAlreadyUsed, - Text: "The registration code is invalid or has already been used. Please try again.", - Type: Error, - Context: context(nil), + ID: ErrorValidationRegistrationCodeInvalidOrAlreadyUsed, + Text: "The registration code is invalid or has already been used. Please try again.", + Type: Error, } } func NewErrorValidationRegistrationRetrySuccessful() *Message { return &Message{ - ID: ErrorValidateionRegistrationRetrySuccess, - Type: Error, - Text: "The request was already completed successfully and can not be retried.", - Context: context(nil), + ID: ErrorValidateionRegistrationRetrySuccess, + Type: Error, + Text: "The request was already completed successfully and can not be retried.", } } diff --git a/text/message_settings.go b/text/message_settings.go index cade5de855cb..9cfeb370c33c 100644 --- a/text/message_settings.go +++ b/text/message_settings.go @@ -14,8 +14,9 @@ func NewErrorValidationSettingsFlowExpired(expiredAt time.Time) *Message { ID: ErrorValidationSettingsFlowExpired, Text: fmt.Sprintf("The settings flow expired %.2f minutes ago, please try again.", Since(expiredAt).Minutes()), Type: Error, - Context: context(map[string]interface{}{ - "expired_at": expiredAt, + Context: context(map[string]any{ + "expired_at": expiredAt, + "expired_at_unix": expiredAt.Unix(), }), } } @@ -33,7 +34,7 @@ func NewInfoSelfServiceSettingsTOTPSecret(secret string) *Message { ID: InfoSelfServiceSettingsTOTPSecret, Text: secret, Type: Info, - Context: context(map[string]interface{}{ + Context: context(map[string]any{ "secret": secret, }), } @@ -94,12 +95,12 @@ func NewInfoSelfServiceSettingsLookupConfirm() *Message { } } -func NewInfoSelfServiceSettingsLookupSecretList(secrets []string, raw interface{}) *Message { +func NewInfoSelfServiceSettingsLookupSecretList(secrets []string, raw any) *Message { return &Message{ ID: InfoSelfServiceSettingsLookupSecretList, Text: strings.Join(secrets, ", "), Type: Info, - Context: context(map[string]interface{}{ + Context: context(map[string]any{ "secrets": raw, }), } @@ -109,7 +110,7 @@ func NewInfoSelfServiceSettingsLookupSecret(secret string) *Message { ID: InfoSelfServiceSettingsLookupSecret, Text: secret, Type: Info, - Context: context(map[string]interface{}{ + Context: context(map[string]any{ "secret": secret, }), } @@ -120,8 +121,9 @@ func NewInfoSelfServiceSettingsLookupSecretUsed(usedAt time.Time) *Message { ID: InfoSelfServiceSettingsLookupSecretUsed, Text: fmt.Sprintf("Secret was used at %s", usedAt), Type: Info, - Context: context(map[string]interface{}{ - "used_at": usedAt, + Context: context(map[string]any{ + "used_at": usedAt, + "used_at_unix": usedAt.Unix(), }), } } @@ -139,7 +141,7 @@ func NewInfoSelfServiceSettingsUpdateLinkOIDC(provider string) *Message { ID: InfoSelfServiceSettingsUpdateLinkOidc, Text: fmt.Sprintf("Link %s", provider), Type: Info, - Context: context(map[string]interface{}{ + Context: context(map[string]any{ "provider": provider, }), } @@ -150,7 +152,7 @@ func NewInfoSelfServiceSettingsUpdateUnlinkOIDC(provider string) *Message { ID: InfoSelfServiceSettingsUpdateUnlinkOidc, Text: fmt.Sprintf("Unlink %s", provider), Type: Info, - Context: context(map[string]interface{}{ + Context: context(map[string]any{ "provider": provider, }), } @@ -177,9 +179,10 @@ func NewInfoSelfServiceRemoveWebAuthn(name string, createdAt time.Time) *Message ID: InfoSelfServiceSettingsRemoveWebAuthn, Text: fmt.Sprintf("Remove security key \"%s\"", name), Type: Info, - Context: context(map[string]interface{}{ - "display_name": name, - "added_at": createdAt, + Context: context(map[string]any{ + "display_name": name, + "added_at": createdAt, + "added_at_unix": createdAt.Unix(), }), } } diff --git a/text/message_system.go b/text/message_system.go index a09f5e16de13..d94ce73f9872 100644 --- a/text/message_system.go +++ b/text/message_system.go @@ -5,9 +5,11 @@ package text func NewErrorSystemGeneric(reason string) *Message { return &Message{ - ID: ErrorSystemGeneric, - Text: reason, - Type: Error, - Context: context(nil), + ID: ErrorSystemGeneric, + Text: reason, + Type: Error, + Context: context(map[string]any{ + "reason": reason, + }), } } diff --git a/text/message_validation.go b/text/message_validation.go index 8fb2391bfdce..205c27304cdb 100644 --- a/text/message_validation.go +++ b/text/message_validation.go @@ -6,14 +6,21 @@ package text import ( "fmt" "strings" + + "golang.org/x/text/cases" + "golang.org/x/text/language" + + "golang.org/x/exp/maps" ) func NewValidationErrorGeneric(reason string) *Message { return &Message{ - ID: ErrorValidationGeneric, - Text: reason, - Type: Error, - Context: context(nil), + ID: ErrorValidationGeneric, + Text: reason, + Type: Error, + Context: context(map[string]any{ + "reason": reason, + }), } } @@ -184,10 +191,9 @@ func NewErrorValidationConst(expected any) *Message { func NewErrorValidationConstGeneric() *Message { return &Message{ - ID: ErrorValidationConstGeneric, - Text: "const failed", - Type: Error, - Context: context(nil), + ID: ErrorValidationConstGeneric, + Text: "const failed", + Type: Error, } } @@ -204,10 +210,9 @@ func NewErrorValidationPasswordPolicyViolationGeneric(reason string) *Message { func NewErrorValidationPasswordIdentifierTooSimilar() *Message { return &Message{ - ID: ErrorValidationPasswordIdentifierTooSimilar, - Text: "The password can not be used because it is too similar to the identifier.", - Type: Error, - Context: context(nil), + ID: ErrorValidationPasswordIdentifierTooSimilar, + Text: "The password can not be used because it is too similar to the identifier.", + Type: Error, } } @@ -248,23 +253,56 @@ func NewErrorValidationPasswordTooManyBreaches(breaches int64) *Message { func NewErrorValidationInvalidCredentials() *Message { return &Message{ - ID: ErrorValidationInvalidCredentials, - Text: "The provided credentials are invalid, check for spelling mistakes in your password or username, email address, or phone number.", - Type: Error, - Context: context(nil), + ID: ErrorValidationInvalidCredentials, + Text: "The provided credentials are invalid, check for spelling mistakes in your password or username, email address, or phone number.", + Type: Error, } } func NewErrorValidationDuplicateCredentials() *Message { return &Message{ - ID: ErrorValidationDuplicateCredentials, - Text: "An account with the same identifier (email, phone, username, ...) exists already.", - Type: Error, - Context: context(nil), + ID: ErrorValidationDuplicateCredentials, + Text: "An account with the same identifier (email, phone, username, ...) exists already.", + Type: Error, } } -func NewErrorValidationDuplicateCredentialsWithHints(reason string, availableCredentialTypes []string, availableOIDCProviders []string, credentialIdentifierHint string) *Message { +func NewErrorValidationDuplicateCredentialsWithHints(availableCredentialTypes []string, availableOIDCProviders []string, credentialIdentifierHint string) *Message { + identifier := credentialIdentifierHint + if identifier == "" { + identifier = "an email, phone, or username" + } + oidcProviders := make([]string, 0, len(availableOIDCProviders)) + for _, provider := range availableOIDCProviders { + oidcProviders = append(oidcProviders, cases.Title(language.English).String(provider)) + } + + reason := fmt.Sprintf("You tried signing in with %s which is already in use by another account.", identifier) + if len(availableCredentialTypes) > 0 { + humanReadable := make(map[string]struct{}, len(availableCredentialTypes)) + for _, cred := range availableCredentialTypes { + switch cred { + case "password": + humanReadable["your password"] = struct{}{} + case "oidc": + humanReadable["social sign in"] = struct{}{} + case "webauthn": + humanReadable["your PassKey or a security key"] = struct{}{} + } + } + if len(humanReadable) == 0 { + // show at least some hint + // also our example message generation tool runs into this case + for _, cred := range availableCredentialTypes { + humanReadable[cred] = struct{}{} + } + } + reason += fmt.Sprintf(" You can sign in using %s.", strings.Join(maps.Keys(humanReadable), ", ")) + } + if len(oidcProviders) > 0 { + reason += fmt.Sprintf(" You can sign in using one of the following social sign in providers: %s.", strings.Join(oidcProviders, ", ")) + } + return &Message{ ID: ErrorValidationDuplicateCredentialsWithHints, Text: reason, @@ -279,108 +317,96 @@ func NewErrorValidationDuplicateCredentialsWithHints(reason string, availableCre func NewErrorValidationDuplicateCredentialsOnOIDCLink() *Message { return &Message{ - ID: ErrorValidationDuplicateCredentialsOnOIDCLink, - Text: "An account with the same identifier (email, phone, username, ...) exists already. Please sign in to your existing account and link your social profile in the settings page.", - Type: Error, - Context: context(nil), + ID: ErrorValidationDuplicateCredentialsOnOIDCLink, + Text: "An account with the same identifier (email, phone, username, ...) exists already. Please sign in to your existing account and link your social profile in the settings page.", + Type: Error, } } func NewErrorValidationTOTPVerifierWrong() *Message { return &Message{ - ID: ErrorValidationTOTPVerifierWrong, - Text: "The provided authentication code is invalid, please try again.", - Type: Error, - Context: context(nil), + ID: ErrorValidationTOTPVerifierWrong, + Text: "The provided authentication code is invalid, please try again.", + Type: Error, } } func NewErrorValidationLookupAlreadyUsed() *Message { return &Message{ - ID: ErrorValidationLookupAlreadyUsed, - Text: "This backup recovery code has already been used.", - Type: Error, - Context: context(nil), + ID: ErrorValidationLookupAlreadyUsed, + Text: "This backup recovery code has already been used.", + Type: Error, } } func NewErrorValidationLookupInvalid() *Message { return &Message{ - ID: ErrorValidationLookupInvalid, - Text: "The backup recovery code is not valid.", - Type: Error, - Context: context(nil), + ID: ErrorValidationLookupInvalid, + Text: "The backup recovery code is not valid.", + Type: Error, } } func NewErrorValidationIdentifierMissing() *Message { return &Message{ - ID: ErrorValidationIdentifierMissing, - Text: "Could not find any login identifiers. Did you forget to set them? This could also be caused by a server misconfiguration.", - Type: Error, - Context: context(nil), + ID: ErrorValidationIdentifierMissing, + Text: "Could not find any login identifiers. Did you forget to set them? This could also be caused by a server misconfiguration.", + Type: Error, } } func NewErrorValidationAddressNotVerified() *Message { return &Message{ - ID: ErrorValidationAddressNotVerified, - Text: "Account not active yet. Did you forget to verify your email address?", - Type: Error, - Context: context(nil), + ID: ErrorValidationAddressNotVerified, + Text: "Account not active yet. Did you forget to verify your email address?", + Type: Error, } } func NewErrorValidationNoTOTPDevice() *Message { return &Message{ - ID: ErrorValidationNoTOTPDevice, - Text: "You have no TOTP device set up.", - Type: Error, - Context: context(nil), + ID: ErrorValidationNoTOTPDevice, + Text: "You have no TOTP device set up.", + Type: Error, } } func NewErrorValidationNoLookup() *Message { return &Message{ - ID: ErrorValidationNoLookup, - Text: "You have no backup recovery codes set up.", - Type: Error, - Context: context(nil), + ID: ErrorValidationNoLookup, + Text: "You have no backup recovery codes set up.", + Type: Error, } } func NewErrorValidationNoWebAuthnDevice() *Message { return &Message{ - ID: ErrorValidationNoWebAuthnDevice, - Text: "You have no WebAuthn device set up.", - Type: Error, - Context: context(nil), + ID: ErrorValidationNoWebAuthnDevice, + Text: "You have no WebAuthn device set up.", + Type: Error, } } func NewErrorValidationSuchNoWebAuthnUser() *Message { return &Message{ - ID: ErrorValidationSuchNoWebAuthnUser, - Text: "This account does not exist or has no security key set up.", - Type: Error, - Context: context(nil), + ID: ErrorValidationSuchNoWebAuthnUser, + Text: "This account does not exist or has no security key set up.", + Type: Error, } } func NewErrorValidationNoCodeUser() *Message { return &Message{ - ID: ErrorValidationNoCodeUser, - Text: "This account does not exist or has not setup sign in with code.", - Type: Error, - Context: context(nil), + ID: ErrorValidationNoCodeUser, + Text: "This account does not exist or has not setup sign in with code.", + Type: Error, } } func NewErrorValidationTraitsMismatch() *Message { return &Message{ - ID: ErrorValidationTraitsMismatch, - Text: "The provided traits do not match the traits previously associated with this flow.", - Type: Error, - Context: context(nil), + ID: ErrorValidationTraitsMismatch, + Text: "The provided traits do not match the traits previously associated with this flow.", + Type: Error, } } diff --git a/text/message_verification.go b/text/message_verification.go index fccec0b0d521..37064e2d0f6c 100644 --- a/text/message_verification.go +++ b/text/message_verification.go @@ -13,8 +13,9 @@ func NewErrorValidationVerificationFlowExpired(expiredAt time.Time) *Message { ID: ErrorValidationVerificationFlowExpired, Text: fmt.Sprintf("The verification flow expired %.2f minutes ago, please try again.", Since(expiredAt).Minutes()), Type: Error, - Context: context(map[string]interface{}{ - "expired_at": expiredAt, + Context: context(map[string]any{ + "expired_at": expiredAt, + "expired_at_unix": expiredAt.Unix(), }), } } @@ -29,54 +30,48 @@ func NewInfoSelfServiceVerificationSuccessful() *Message { func NewVerificationEmailSent() *Message { return &Message{ - ID: InfoSelfServiceVerificationEmailSent, - Type: Info, - Text: "An email containing a verification link has been sent to the email address you provided. If you have not received an email, check the spelling of the address and make sure to use the address you registered with.", - Context: context(nil), + ID: InfoSelfServiceVerificationEmailSent, + Type: Info, + Text: "An email containing a verification link has been sent to the email address you provided. If you have not received an email, check the spelling of the address and make sure to use the address you registered with.", } } func NewErrorValidationVerificationTokenInvalidOrAlreadyUsed() *Message { return &Message{ - ID: ErrorValidationVerificationTokenInvalidOrAlreadyUsed, - Text: "The verification token is invalid or has already been used. Please retry the flow.", - Type: Error, - Context: context(nil), + ID: ErrorValidationVerificationTokenInvalidOrAlreadyUsed, + Text: "The verification token is invalid or has already been used. Please retry the flow.", + Type: Error, } } func NewErrorValidationVerificationRetrySuccess() *Message { return &Message{ - ID: ErrorValidationVerificationRetrySuccess, - Text: "The request was already completed successfully and can not be retried.", - Type: Error, - Context: context(nil), + ID: ErrorValidationVerificationRetrySuccess, + Text: "The request was already completed successfully and can not be retried.", + Type: Error, } } func NewErrorValidationVerificationStateFailure() *Message { return &Message{ - ID: ErrorValidationVerificationStateFailure, - Text: "The verification flow reached a failure state and must be retried.", - Type: Error, - Context: context(nil), + ID: ErrorValidationVerificationStateFailure, + Text: "The verification flow reached a failure state and must be retried.", + Type: Error, } } func NewErrorValidationVerificationCodeInvalidOrAlreadyUsed() *Message { return &Message{ - ID: ErrorValidationVerificationCodeInvalidOrAlreadyUsed, - Text: "The verification code is invalid or has already been used. Please try again.", - Type: Error, - Context: context(nil), + ID: ErrorValidationVerificationCodeInvalidOrAlreadyUsed, + Text: "The verification code is invalid or has already been used. Please try again.", + Type: Error, } } func NewVerificationEmailWithCodeSent() *Message { return &Message{ - ID: InfoSelfServiceVerificationEmailWithCodeSent, - Type: Info, - Text: "An email containing a verification code has been sent to the email address you provided. If you have not received an email, check the spelling of the address and make sure to use the address you registered with.", - Context: context(nil), + ID: InfoSelfServiceVerificationEmailWithCodeSent, + Type: Info, + Text: "An email containing a verification code has been sent to the email address you provided. If you have not received an email, check the spelling of the address and make sure to use the address you registered with.", } } From ea914834e6bb626de2977e228af2b40935ccc980 Mon Sep 17 00:00:00 2001 From: Patrik Date: Wed, 30 Aug 2023 11:06:02 +0200 Subject: [PATCH 063/282] feat: added various new text messages To improve i18n and message customization, we added a bunch of new messages. Integrations that do message customization should probably handle those new message codes: - 1010014 - 1010015 - 1040005 - 1040006 - 1070012 - 1070013 - 4000028 - 4000029 - 4000030 - 4000031 - 4000032 - 4000033 - 4000034 - 4000035 - 4000036 - 4010007 - 4010008 - 4040002 - 4040003 Additionally, these messages got more context: - 1050014 - 1050018 - 1070002 - 4000001 - 4000003 - 4000004 - 4000017 - 4000018 - 4000019 - 4000020 - 4000021 - 4000022 - 4000023 - 4000024 - 4000025 - 4000026 - 4010001 - 4040001 - 4050001 - 4060005 - 4070005 - 5000001 From ed0860680b0c11141e61bb7e4dbde7817b4886ef Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Wed, 30 Aug 2023 10:32:22 +0000 Subject: [PATCH 064/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a3bd52995cc..38d4992df046 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-08-29)](#2023-08-29) +- [ (2023-08-30)](#2023-08-30) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) - [Features](#features) @@ -309,7 +309,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-08-29) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-08-30) ### Bug Fixes @@ -368,6 +368,9 @@ - Registration with verification ([#3451](https://github.com/ory/kratos/issues/3451)) ([77c3196](https://github.com/ory/kratos/commit/77c3196fd60c5927b84e9a7f6546f80ac2d78ee5)) +- Remove `earliest_possible_extend` default in schema + ([#3464](https://github.com/ory/kratos/issues/3464)) + ([7e05b7d](https://github.com/ory/kratos/commit/7e05b7db3c01efc96185ac18042e971e33da37c8)) - Remove requirement for smtp section ([#3405](https://github.com/ory/kratos/issues/3405)) ([59a3f14](https://github.com/ory/kratos/commit/59a3f1469b8412e49846a500493cb02fc6eb34b1)) @@ -390,6 +393,58 @@ - Add OpenTelemetry span for password hash comparison ([#3383](https://github.com/ory/kratos/issues/3383)) ([e3fcf0c](https://github.com/ory/kratos/commit/e3fcf0c31db9742ed61bcf783e37ee119ed19d42)) +- Added various new text messages + ([ea91483](https://github.com/ory/kratos/commit/ea914834e6bb626de2977e228af2b40935ccc980)): + + To improve i18n and message customization, we added a bunch of new messages. + Integrations that do message customization should probably handle those new + message codes: + + - 1010014 + - 1010015 + - 1040005 + - 1040006 + - 1070012 + - 1070013 + - 4000028 + - 4000029 + - 4000030 + - 4000031 + - 4000032 + - 4000033 + - 4000034 + - 4000035 + - 4000036 + - 4010007 + - 4010008 + - 4040002 + - 4040003 + + Additionally, these messages got more context: + + - 1050014 + - 1050018 + - 1070002 + - 4000001 + - 4000003 + - 4000004 + - 4000017 + - 4000018 + - 4000019 + - 4000020 + - 4000021 + - 4000022 + - 4000023 + - 4000024 + - 4000025 + - 4000026 + - 4010001 + - 4040001 + - 4050001 + - 4060005 + - 4070005 + - 5000001 + - Allow extra migrations in NewPersister ([96c1ff7](https://github.com/ory/kratos/commit/96c1ff7747ea38e23a3892f74b75ee555ed49c88)) - Allow marking OIDC provider-verified addresses as verified during registration From dfcbe226bc53b91f3a6c9837496a159b85c2e68a Mon Sep 17 00:00:00 2001 From: Patrik Date: Wed, 30 Aug 2023 18:19:08 +0200 Subject: [PATCH 065/282] fix: remove duplicate message ID usage (#3468) --- cmd/clidoc/main.go | 8 ++++++-- ...gin-flow=passwordless-case=webauthn_button_exists.json | 4 ++-- selfservice/strategy/webauthn/login.go | 2 +- text/message_login.go | 8 -------- 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/cmd/clidoc/main.go b/cmd/clidoc/main.go index 023fb8026d6b..a9e96b909922 100644 --- a/cmd/clidoc/main.go +++ b/cmd/clidoc/main.go @@ -70,7 +70,6 @@ func init() { "NewInfoSelfServiceSettingsLookupSecretsLabel": text.NewInfoSelfServiceSettingsLookupSecretsLabel(), "NewInfoSelfServiceSettingsUpdateLinkOIDC": text.NewInfoSelfServiceSettingsUpdateLinkOIDC("{provider}"), "NewInfoSelfServiceSettingsUpdateUnlinkOIDC": text.NewInfoSelfServiceSettingsUpdateUnlinkOIDC("{provider}"), - "NewInfoSelfServiceRegisterWebAuthn": text.NewInfoSelfServiceSettingsRegisterWebAuthn(), "NewInfoSelfServiceRegisterWebAuthnDisplayName": text.NewInfoSelfServiceRegisterWebAuthnDisplayName(), "NewInfoSelfServiceRemoveWebAuthn": text.NewInfoSelfServiceRemoveWebAuthn("{display_name}", aSecondAgo), "NewErrorValidationVerificationFlowExpired": text.NewErrorValidationVerificationFlowExpired(aSecondAgo), @@ -149,7 +148,6 @@ func init() { "NewInfoSelfServiceSettingsRegisterWebAuthn": text.NewInfoSelfServiceSettingsRegisterWebAuthn(), "NewInfoLoginWebAuthnPasswordless": text.NewInfoLoginWebAuthnPasswordless(), "NewInfoSelfServiceRegistrationRegisterWebAuthn": text.NewInfoSelfServiceRegistrationRegisterWebAuthn(), - "NewInfoLoginPasswordlessWebAuthn": text.NewInfoLoginPasswordlessWebAuthn(), "NewInfoSelfServiceContinueLoginWebAuthn": text.NewInfoSelfServiceContinueLoginWebAuthn(), "NewInfoSelfServiceLoginContinue": text.NewInfoSelfServiceLoginContinue(), "NewErrorValidationSuchNoWebAuthnUser": text.NewErrorValidationSuchNoWebAuthnUser(), @@ -180,6 +178,12 @@ func main() { } sortedMessages := sortMessages() + for i := 1; i < len(sortedMessages); i++ { + if sortedMessages[i].ID == sortedMessages[i-1].ID { + _, _ = fmt.Fprintf(os.Stderr, "Message ID %d is used more than once: %q %q\n", sortedMessages[i].ID, sortedMessages[i].Text, sortedMessages[i-1].Text) + os.Exit(1) + } + } if err := writeMessages(filepath.Join(os.Args[2], "concepts/ui-user-interface.mdx"), sortedMessages); err != nil { _, _ = fmt.Fprintf(os.Stderr, "Unable to generate message table: %+v\n", err) diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=passwordless-case=webauthn_button_exists.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=passwordless-case=webauthn_button_exists.json index 0c402bfe2612..2405a57aaf04 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=passwordless-case=webauthn_button_exists.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=passwordless-case=webauthn_button_exists.json @@ -44,8 +44,8 @@ "messages": [], "meta": { "label": { - "id": 1010001, - "text": "Sign in with security key", + "id": 1010008, + "text": "Use security key", "type": "info" } }, diff --git a/selfservice/strategy/webauthn/login.go b/selfservice/strategy/webauthn/login.go index 200fdcea2280..7b968c704151 100644 --- a/selfservice/strategy/webauthn/login.go +++ b/selfservice/strategy/webauthn/login.go @@ -92,7 +92,7 @@ func (s *Strategy) populateLoginMethodForPasswordless(r *http.Request, sr *login sr.UI.SetCSRF(s.d.GenerateCSRFToken(r)) sr.UI.SetNode(node.NewInputField("identifier", "", node.DefaultGroup, node.InputAttributeTypeText, node.WithRequiredInputAttribute).WithMetaLabel(text.NewInfoNodeLabelID())) - sr.UI.GetNodes().Append(node.NewInputField("method", "webauthn", node.WebAuthnGroup, node.InputAttributeTypeSubmit).WithMetaLabel(text.NewInfoLoginPasswordlessWebAuthn())) + sr.UI.GetNodes().Append(node.NewInputField("method", "webauthn", node.WebAuthnGroup, node.InputAttributeTypeSubmit).WithMetaLabel(text.NewInfoSelfServiceLoginWebAuthn())) return nil } diff --git a/text/message_login.go b/text/message_login.go index a67d1f692c6a..3afa27da46bf 100644 --- a/text/message_login.go +++ b/text/message_login.go @@ -56,14 +56,6 @@ func NewInfoLogin() *Message { } } -func NewInfoLoginPasswordlessWebAuthn() *Message { - return &Message{ - ID: InfoSelfServiceLogin, - Text: "Sign in with security key", - Type: Info, - } -} - func NewInfoLoginTOTP() *Message { return &Message{ ID: InfoLoginTOTP, From 69b43b79f46ba7ea30ba6d4f4091ad1bd368409c Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Wed, 30 Aug 2023 17:50:55 +0000 Subject: [PATCH 066/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38d4992df046..d37d85032eca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -371,6 +371,9 @@ - Remove `earliest_possible_extend` default in schema ([#3464](https://github.com/ory/kratos/issues/3464)) ([7e05b7d](https://github.com/ory/kratos/commit/7e05b7db3c01efc96185ac18042e971e33da37c8)) +- Remove duplicate message ID usage + ([#3468](https://github.com/ory/kratos/issues/3468)) + ([dfcbe22](https://github.com/ory/kratos/commit/dfcbe226bc53b91f3a6c9837496a159b85c2e68a)) - Remove requirement for smtp section ([#3405](https://github.com/ory/kratos/issues/3405)) ([59a3f14](https://github.com/ory/kratos/commit/59a3f1469b8412e49846a500493cb02fc6eb34b1)) From 7ae02ba697f68c9cfae5fe8f696b2c55a3ba9ddc Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Thu, 31 Aug 2023 13:09:41 +0200 Subject: [PATCH 067/282] fix: mark identity as optional in session struct (#3463) The identity is not always available in the session struct, for example when AAL2 is required. Closes #3461 --- internal/client-go/model_session.go | 35 +++++++++++++++++----------- internal/httpclient/model_session.go | 35 +++++++++++++++++----------- session/session.go | 7 +++++- spec/api.json | 3 +-- spec/swagger.json | 3 +-- 5 files changed, 50 insertions(+), 33 deletions(-) diff --git a/internal/client-go/model_session.go b/internal/client-go/model_session.go index 41cd1113cac6..0ded40302a1c 100644 --- a/internal/client-go/model_session.go +++ b/internal/client-go/model_session.go @@ -30,8 +30,8 @@ type Session struct { // The Session Expiry When this session expires at. ExpiresAt *time.Time `json:"expires_at,omitempty"` // Session ID - Id string `json:"id"` - Identity Identity `json:"identity"` + Id string `json:"id"` + Identity *Identity `json:"identity,omitempty"` // The Session Issuance Timestamp When this session was issued at. Usually equal or close to `authenticated_at`. IssuedAt *time.Time `json:"issued_at,omitempty"` } @@ -40,10 +40,9 @@ type Session struct { // 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 NewSession(id string, identity Identity) *Session { +func NewSession(id string) *Session { this := Session{} this.Id = id - this.Identity = identity return &this } @@ -271,28 +270,36 @@ func (o *Session) SetId(v string) { o.Id = v } -// GetIdentity returns the Identity field value +// GetIdentity returns the Identity field value if set, zero value otherwise. func (o *Session) GetIdentity() Identity { - if o == nil { + if o == nil || o.Identity == nil { var ret Identity return ret } - - return o.Identity + return *o.Identity } -// GetIdentityOk returns a tuple with the Identity field value +// GetIdentityOk returns a tuple with the Identity field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *Session) GetIdentityOk() (*Identity, bool) { - if o == nil { + if o == nil || o.Identity == nil { return nil, false } - return &o.Identity, true + return o.Identity, true +} + +// HasIdentity returns a boolean if a field has been set. +func (o *Session) HasIdentity() bool { + if o != nil && o.Identity != nil { + return true + } + + return false } -// SetIdentity sets field value +// SetIdentity gets a reference to the given Identity and assigns it to the Identity field. func (o *Session) SetIdentity(v Identity) { - o.Identity = v + o.Identity = &v } // GetIssuedAt returns the IssuedAt field value if set, zero value otherwise. @@ -350,7 +357,7 @@ func (o Session) MarshalJSON() ([]byte, error) { if true { toSerialize["id"] = o.Id } - if true { + if o.Identity != nil { toSerialize["identity"] = o.Identity } if o.IssuedAt != nil { diff --git a/internal/httpclient/model_session.go b/internal/httpclient/model_session.go index 41cd1113cac6..0ded40302a1c 100644 --- a/internal/httpclient/model_session.go +++ b/internal/httpclient/model_session.go @@ -30,8 +30,8 @@ type Session struct { // The Session Expiry When this session expires at. ExpiresAt *time.Time `json:"expires_at,omitempty"` // Session ID - Id string `json:"id"` - Identity Identity `json:"identity"` + Id string `json:"id"` + Identity *Identity `json:"identity,omitempty"` // The Session Issuance Timestamp When this session was issued at. Usually equal or close to `authenticated_at`. IssuedAt *time.Time `json:"issued_at,omitempty"` } @@ -40,10 +40,9 @@ type Session struct { // 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 NewSession(id string, identity Identity) *Session { +func NewSession(id string) *Session { this := Session{} this.Id = id - this.Identity = identity return &this } @@ -271,28 +270,36 @@ func (o *Session) SetId(v string) { o.Id = v } -// GetIdentity returns the Identity field value +// GetIdentity returns the Identity field value if set, zero value otherwise. func (o *Session) GetIdentity() Identity { - if o == nil { + if o == nil || o.Identity == nil { var ret Identity return ret } - - return o.Identity + return *o.Identity } -// GetIdentityOk returns a tuple with the Identity field value +// GetIdentityOk returns a tuple with the Identity field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *Session) GetIdentityOk() (*Identity, bool) { - if o == nil { + if o == nil || o.Identity == nil { return nil, false } - return &o.Identity, true + return o.Identity, true +} + +// HasIdentity returns a boolean if a field has been set. +func (o *Session) HasIdentity() bool { + if o != nil && o.Identity != nil { + return true + } + + return false } -// SetIdentity sets field value +// SetIdentity gets a reference to the given Identity and assigns it to the Identity field. func (o *Session) SetIdentity(v Identity) { - o.Identity = v + o.Identity = &v } // GetIssuedAt returns the IssuedAt field value if set, zero value otherwise. @@ -350,7 +357,7 @@ func (o Session) MarshalJSON() ([]byte, error) { if true { toSerialize["id"] = o.Id } - if true { + if o.Identity != nil { toSerialize["identity"] = o.Identity } if o.IssuedAt != nil { diff --git a/session/session.go b/session/session.go index f915fd0aad02..41b811b146b9 100644 --- a/session/session.go +++ b/session/session.go @@ -120,7 +120,12 @@ type Session struct { // Use this token to log out a user. LogoutToken string `json:"-" db:"logout_token"` - // required: true + // The Session Identity + // + // The identity that authenticated this session. + // + // If 2FA is required for the user, and the authentication process only solved the first factor, this field will be + // null until the session has been fully authenticated with the second factor. Identity *identity.Identity `json:"identity" faker:"identity" db:"-" belongs_to:"identities" fk_id:"IdentityID"` // Devices has history of all endpoints where the session was used diff --git a/spec/api.json b/spec/api.json index 005fef8d643d..6481b5b22cbf 100644 --- a/spec/api.json +++ b/spec/api.json @@ -1759,8 +1759,7 @@ } }, "required": [ - "id", - "identity" + "id" ], "type": "object" }, diff --git a/spec/swagger.json b/spec/swagger.json index 368785b299a8..d48afb33998b 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -4638,8 +4638,7 @@ "description": "A Session", "type": "object", "required": [ - "id", - "identity" + "id" ], "properties": { "active": { From bafc47d0940ede59ac5163434718d209385107e2 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Thu, 31 Aug 2023 12:45:20 +0000 Subject: [PATCH 068/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d37d85032eca..a04142814433 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-08-30)](#2023-08-30) +- [ (2023-08-31)](#2023-08-31) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) - [Features](#features) @@ -309,7 +309,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-08-30) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-08-31) ### Bug Fixes @@ -347,6 +347,14 @@ - False-positives for requiring re-authentication on update ([#3421](https://github.com/ory/kratos/issues/3421)) ([ce8139f](https://github.com/ory/kratos/commit/ce8139f2325a8317388cbcaaa98f3f83d626657b)) +- Mark identity as optional in session struct + ([#3463](https://github.com/ory/kratos/issues/3463)) + ([7ae02ba](https://github.com/ory/kratos/commit/7ae02ba697f68c9cfae5fe8f696b2c55a3ba9ddc)), + closes [#3461](https://github.com/ory/kratos/issues/3461): + + The identity is not always available in the session struct, for example when + AAL2 is required. + - Pass context ([#3452](https://github.com/ory/kratos/issues/3452)) ([c492bdc](https://github.com/ory/kratos/commit/c492bdcd0c5dbdf527ae523d879a6c1eeb9c4cdf)) - Properly normalize OIDC verified emails From a28b523238743f3873b51479eea3b86d684092f9 Mon Sep 17 00:00:00 2001 From: Henning Perl Date: Thu, 31 Aug 2023 15:33:29 +0200 Subject: [PATCH 069/282] fix: issue session after verification after registration with OIDC SSO (#3467) --- selfservice/flow/registration/hook.go | 4 ++- selfservice/flow/verification/handler.go | 11 +++++++ selfservice/flow/verification/handler_test.go | 10 +++--- selfservice/hook/session_issuer.go | 6 ---- selfservice/hook/session_issuer_test.go | 31 +++++++++++++------ 5 files changed, 40 insertions(+), 22 deletions(-) diff --git a/selfservice/flow/registration/hook.go b/selfservice/flow/registration/hook.go index 83299d944262..426d81101dd6 100644 --- a/selfservice/flow/registration/hook.go +++ b/selfservice/flow/registration/hook.go @@ -172,7 +172,9 @@ func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Reque return err } - if err != nil { + // We persist the session here so that subsequent hooks (like verification) can use it. + s.AuthenticatedAt = time.Now().UTC() + if err := e.d.SessionPersister().UpsertSession(r.Context(), s); err != nil { return err } diff --git a/selfservice/flow/verification/handler.go b/selfservice/flow/verification/handler.go index 83a21418e83b..6e0852006f22 100644 --- a/selfservice/flow/verification/handler.go +++ b/selfservice/flow/verification/handler.go @@ -463,6 +463,17 @@ func (h *Handler) updateVerificationFlow(w http.ResponseWriter, r *http.Request, return } + sess, err := h.d.SessionPersister().GetSession(ctx, f.SessionID.UUID, session.ExpandDefault) + if err != nil { + h.d.VerificationFlowErrorHandler().WriteFlowError(w, r, f, node.DefaultGroup, err) + return + } + err = h.d.SessionManager().IssueCookie(ctx, w, r, sess) + if err != nil { + h.d.VerificationFlowErrorHandler().WriteFlowError(w, r, f, node.DefaultGroup, err) + return + } + http.Redirect(w, r, callbackURL, http.StatusSeeOther) return } diff --git a/selfservice/flow/verification/handler_test.go b/selfservice/flow/verification/handler_test.go index 6eb2b12f800b..266cc9022431 100644 --- a/selfservice/flow/verification/handler_test.go +++ b/selfservice/flow/verification/handler_test.go @@ -20,12 +20,10 @@ import ( "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/selfservice/flow" "github.com/ory/kratos/selfservice/flow/verification" - "github.com/ory/kratos/session" "github.com/ory/kratos/x" ) @@ -218,6 +216,8 @@ func TestPostFlow(t *testing.T) { t.Run("suite=with OIDC login challenge", func(t *testing.T) { t.Run("case=succeeds with a session", func(t *testing.T) { + s := testhelpers.CreateSession(t, reg) + f := &verification.Flow{ ID: uuid.Must(uuid.NewV4()), Type: "browser", @@ -225,9 +225,9 @@ func TestPostFlow(t *testing.T) { IssuedAt: time.Now(), OAuth2LoginChallenge: hydra.FakeValidLoginChallenge, OAuth2LoginChallengeParams: verification.OAuth2LoginChallengeParams{ - SessionID: uuid.NullUUID{UUID: uuid.Must(uuid.NewV4()), Valid: true}, - IdentityID: uuid.NullUUID{UUID: uuid.Must(uuid.NewV4()), Valid: true}, - AMR: session.AuthenticationMethods{{Method: identity.CredentialsTypePassword}}, + SessionID: uuid.NullUUID{UUID: s.ID, Valid: true}, + IdentityID: uuid.NullUUID{UUID: s.IdentityID, Valid: true}, + AMR: s.AMR, }, State: flow.StatePassedChallenge, } diff --git a/selfservice/hook/session_issuer.go b/selfservice/hook/session_issuer.go index 804e7977bf3e..999403d53ace 100644 --- a/selfservice/hook/session_issuer.go +++ b/selfservice/hook/session_issuer.go @@ -6,7 +6,6 @@ package hook import ( "context" "net/http" - "time" "github.com/ory/kratos/identity" "github.com/ory/kratos/ui/node" @@ -53,11 +52,6 @@ func (e *SessionIssuer) ExecutePostRegistrationPostPersistHook(w http.ResponseWr } func (e *SessionIssuer) executePostRegistrationPostPersistHook(w http.ResponseWriter, r *http.Request, a *registration.Flow, s *session.Session) error { - s.AuthenticatedAt = time.Now().UTC() - if err := e.r.SessionPersister().UpsertSession(r.Context(), s); err != nil { - return err - } - if a.Type == flow.TypeAPI { if s.AuthenticatedVia(identity.CredentialsTypeOIDC) { if handled, err := e.r.SessionManager().MaybeRedirectAPICodeFlow(w, r, a, s.ID, node.OpenIDConnectGroup); err != nil { diff --git a/selfservice/hook/session_issuer_test.go b/selfservice/hook/session_issuer_test.go index d11a0fa18413..db62ab2d643d 100644 --- a/selfservice/hook/session_issuer_test.go +++ b/selfservice/hook/session_issuer_test.go @@ -39,21 +39,17 @@ func TestSessionIssuer(t *testing.T) { t.Run("method=sign-up", func(t *testing.T) { t.Run("flow=browser", func(t *testing.T) { w := httptest.NewRecorder() - sid := x.NewUUID() - - i := identity.NewIdentity(config.DefaultIdentityTraitsSchemaID) - require.NoError(t, reg.PrivilegedIdentityPool().CreateIdentity(context.Background(), i)) - + s := testhelpers.CreateSession(t, reg) f := ®istration.Flow{Type: flow.TypeBrowser} require.NoError(t, h.ExecutePostRegistrationPostPersistHook(w, &r, - f, &session.Session{ID: sid, Identity: i, Token: randx.MustString(12, randx.AlphaLowerNum)})) + f, &session.Session{ID: s.ID, Identity: s.Identity, Token: randx.MustString(12, randx.AlphaLowerNum)})) require.Empty(t, f.ContinueWithItems) - got, err := reg.SessionPersister().GetSession(context.Background(), sid, session.ExpandNothing) + got, err := reg.SessionPersister().GetSession(context.Background(), s.ID, session.ExpandNothing) require.NoError(t, err) - assert.Equal(t, sid, got.ID) + assert.Equal(t, s.ID, got.ID) assert.True(t, got.AuthenticatedAt.After(time.Now().Add(-time.Minute))) assert.Contains(t, w.Header().Get("Set-Cookie"), config.DefaultSessionCookieName) @@ -63,10 +59,17 @@ func TestSessionIssuer(t *testing.T) { w := httptest.NewRecorder() i := identity.NewIdentity(config.DefaultIdentityTraitsSchemaID) - s := &session.Session{ID: x.NewUUID(), Identity: i, Token: randx.MustString(12, randx.AlphaLowerNum), LogoutToken: randx.MustString(12, randx.AlphaLowerNum)} + s := &session.Session{ + ID: x.NewUUID(), + Identity: i, + Token: randx.MustString(12, randx.AlphaLowerNum), + LogoutToken: randx.MustString(12, randx.AlphaLowerNum), + AuthenticatedAt: time.Now().UTC(), + } f := ®istration.Flow{Type: flow.TypeAPI} require.NoError(t, reg.PrivilegedIdentityPool().CreateIdentity(context.Background(), i)) + require.NoError(t, reg.SessionPersister().UpsertSession(ctx, s)) err := h.ExecutePostRegistrationPostPersistHook(w, &http.Request{Header: http.Header{"Accept": {"application/json"}}}, f, s) require.ErrorIs(t, err, registration.ErrHookAbortFlow, "%+v", err) @@ -92,10 +95,18 @@ func TestSessionIssuer(t *testing.T) { w := httptest.NewRecorder() i := identity.NewIdentity(config.DefaultIdentityTraitsSchemaID) - s := &session.Session{ID: x.NewUUID(), Identity: i, Token: randx.MustString(12, randx.AlphaLowerNum), LogoutToken: randx.MustString(12, randx.AlphaLowerNum)} + s := &session.Session{ + ID: x.NewUUID(), + Identity: i, + Token: randx.MustString(12, randx.AlphaLowerNum), + LogoutToken: randx.MustString(12, randx.AlphaLowerNum), + AuthenticatedAt: time.Now().UTC(), + } f := ®istration.Flow{Type: flow.TypeBrowser} require.NoError(t, reg.PrivilegedIdentityPool().CreateIdentity(context.Background(), i)) + require.NoError(t, reg.SessionPersister().UpsertSession(ctx, s)) + err := h.ExecutePostRegistrationPostPersistHook(w, &http.Request{Header: http.Header{"Accept": {"application/json"}}}, f, s) require.ErrorIs(t, err, registration.ErrHookAbortFlow, "%+v", err) require.Empty(t, f.ContinueWithItems) From 085d5002df27d455057d33bd2d93dfbca0de4872 Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Fri, 1 Sep 2023 13:39:41 +0200 Subject: [PATCH 070/282] feat: add GetID member functions to RecoveryAddress and Credentials (#3474) --- identity/credentials.go | 4 ++++ identity/identity_recovery.go | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/identity/credentials.go b/identity/credentials.go index 6ccbe867c89a..c323f7dcc790 100644 --- a/identity/credentials.go +++ b/identity/credentials.go @@ -189,6 +189,10 @@ func (c Credentials) TableName(context.Context) string { return "identity_credentials" } +func (c Credentials) GetID() uuid.UUID { + return c.ID +} + type ( // swagger:ignore CredentialIdentifier struct { diff --git a/identity/identity_recovery.go b/identity/identity_recovery.go index 3c3534558db3..1dda54a96f11 100644 --- a/identity/identity_recovery.go +++ b/identity/identity_recovery.go @@ -59,6 +59,10 @@ func (a RecoveryAddress) ValidateNID() error { return nil } +func (a RecoveryAddress) GetID() uuid.UUID { + return a.ID +} + // Hash returns a unique string representation for the recovery address. func (a RecoveryAddress) Hash() string { return fmt.Sprintf("%v|%v|%v|%v", a.Value, a.Via, a.IdentityID, a.NID) From 70a617194d61763f4b75691b22cfa76ba71ab019 Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Thu, 7 Sep 2023 16:33:02 +0200 Subject: [PATCH 071/282] test: fix e2e failures and speed up e2e tests (#3483) --- .github/workflows/ci.yaml | 1 + .../profiles/email/login/ui.spec.ts | 14 +- .../profiles/email/settings/ui.spec.ts | 13 +- .../integration/profiles/mfa/totp.spec.ts | 7 +- .../profiles/oidc/settings/success.spec.ts | 9 +- .../profiles/recovery/code/errors.spec.ts | 15 +- .../profiles/recovery/code/success.spec.ts | 33 ++--- .../profiles/recovery/link/errors.spec.ts | 18 ++- .../profiles/recovery/link/success.spec.ts | 29 ++-- .../recovery/return-to/success.spec.ts | 20 +-- .../recovery/settings/success.spec.ts | 12 +- .../verification/login/errors.spec.ts | 2 +- .../verification/login/success.spec.ts | 2 +- .../verification/registration/errors.spec.ts | 13 +- .../verification/registration/success.spec.ts | 2 +- .../verification/settings/error.spec.ts | 2 +- .../verification/verify/errors.spec.ts | 13 +- .../verification/verify/success.spec.ts | 19 +-- test/e2e/cypress/support/commands.ts | 11 +- test/e2e/cypress/support/configHelpers.ts | 135 ++++++++++++++++++ test/e2e/cypress/support/index.d.ts | 3 + test/e2e/run.sh | 7 +- 22 files changed, 289 insertions(+), 91 deletions(-) create mode 100644 test/e2e/cypress/support/configHelpers.ts diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c9a0037ee449..2e0dc2ca047f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -137,6 +137,7 @@ jobs: TEST_DATABASE_MYSQL: "mysql://root:test@(localhost:3306)/mysql?parseTime=true&multiStatements=true" TEST_DATABASE_COCKROACHDB: "cockroach://root@localhost:26257/defaultdb?sslmode=disable" strategy: + fail-fast: false matrix: database: ["postgres", "cockroach", "sqlite", "mysql"] steps: diff --git a/test/e2e/cypress/integration/profiles/email/login/ui.spec.ts b/test/e2e/cypress/integration/profiles/email/login/ui.spec.ts index 199a15147a9d..8255e9e3b23d 100644 --- a/test/e2e/cypress/integration/profiles/email/login/ui.spec.ts +++ b/test/e2e/cypress/integration/profiles/email/login/ui.spec.ts @@ -32,9 +32,17 @@ context("UI tests using the email profile", () => { cy.get(`${appPrefix(app)}input[name="identifier"]`) .parent() .should("contain.text", "ID") - cy.get('input[name="password"]') - .parent() - .should("contain.text", "Password") + + if (app === "express") { + cy.get('[data-testid="node/input/password"]').should( + "contain.text", + "Password", + ) + } else { + cy.get('input[name="password"]') + .parent() + .should("contain.text", "Password") + } cy.get('button[value="password"]').should("contain.text", "Sign in") }) diff --git a/test/e2e/cypress/integration/profiles/email/settings/ui.spec.ts b/test/e2e/cypress/integration/profiles/email/settings/ui.spec.ts index b68a9a591dcc..7acf65740f7e 100644 --- a/test/e2e/cypress/integration/profiles/email/settings/ui.spec.ts +++ b/test/e2e/cypress/integration/profiles/email/settings/ui.spec.ts @@ -49,9 +49,16 @@ context("Settings errors with email profile", () => { cy.get('input[name="traits.website"]') .parent() .should("contain.text", "Your website") - cy.get('input[name="password"]') - .parent() - .should("contain.text", "Password") + if (app === "express") { + cy.get('[data-testid="node/input/password"]').should( + "contain.text", + "Password", + ) + } else { + cy.get('input[name="password"]') + .parent() + .should("contain.text", "Password") + } cy.get('button[value="profile"]').should("contain.text", "Save") cy.get('button[value="password"]').should("contain.text", "Save") }) diff --git a/test/e2e/cypress/integration/profiles/mfa/totp.spec.ts b/test/e2e/cypress/integration/profiles/mfa/totp.spec.ts index c4c3167ab3cf..24e25fbd3dc6 100644 --- a/test/e2e/cypress/integration/profiles/mfa/totp.spec.ts +++ b/test/e2e/cypress/integration/profiles/mfa/totp.spec.ts @@ -33,8 +33,9 @@ context("2FA TOTP", () => { let password = gen.password() beforeEach(() => { - cy.longPrivilegedSessionTime() - cy.useLaxAal() + cy.useConfig((builder) => + builder.longPrivilegedSessionTime().useLaxAal(), + ) email = gen.email() password = gen.password() @@ -276,7 +277,7 @@ context("2FA TOTP", () => { expect(loc.search).to.not.include("aal") expect(loc.search).to.not.include("refresh") }) - cy.get("h2").should("contain.text", "Sign In") + cy.get("h2").contains(/Sign in/i) cy.noSession() }) diff --git a/test/e2e/cypress/integration/profiles/oidc/settings/success.spec.ts b/test/e2e/cypress/integration/profiles/oidc/settings/success.spec.ts index c6199ab03902..69f8e0f7d737 100644 --- a/test/e2e/cypress/integration/profiles/oidc/settings/success.spec.ts +++ b/test/e2e/cypress/integration/profiles/oidc/settings/success.spec.ts @@ -66,9 +66,12 @@ context("Social Sign In Settings Success", () => { describe("oidc", () => { beforeEach(() => { - cy.longRecoveryLifespan() - cy.longVerificationLifespan() - cy.longPrivilegedSessionTime() + cy.useConfig((builder) => + builder + .longRecoveryLifespan() + .longVerificationLifespan() + .longPrivilegedSessionTime(), + ) }) it("should show the correct options", () => { diff --git a/test/e2e/cypress/integration/profiles/recovery/code/errors.spec.ts b/test/e2e/cypress/integration/profiles/recovery/code/errors.spec.ts index 3aff9794046a..f0e28989aed2 100644 --- a/test/e2e/cypress/integration/profiles/recovery/code/errors.spec.ts +++ b/test/e2e/cypress/integration/profiles/recovery/code/errors.spec.ts @@ -27,12 +27,15 @@ context("Account Recovery Errors", () => { beforeEach(() => { cy.deleteMail() - cy.longRecoveryLifespan() - cy.longCodeLifespan() - cy.disableVerification() - cy.enableRecovery() - cy.useRecoveryStrategy("code") - cy.notifyUnknownRecipients("recovery", false) + cy.useConfig((builder) => + builder + .longRecoveryLifespan() + .longCodeLifespan() + .disableVerification() + .enableRecovery() + .useRecoveryStrategy("code") + .notifyUnknownRecipients("recovery", false), + ) }) it("should invalidate flow if wrong code is submitted too often", () => { diff --git a/test/e2e/cypress/integration/profiles/recovery/code/success.spec.ts b/test/e2e/cypress/integration/profiles/recovery/code/success.spec.ts index f4abe4e41890..a27bca61d967 100644 --- a/test/e2e/cypress/integration/profiles/recovery/code/success.spec.ts +++ b/test/e2e/cypress/integration/profiles/recovery/code/success.spec.ts @@ -31,12 +31,15 @@ context("Account Recovery With Code Success", () => { beforeEach(() => { cy.deleteMail() - cy.longRecoveryLifespan() - cy.longLinkLifespan() - cy.disableVerification() - cy.enableRecovery() - cy.useRecoveryStrategy("code") - cy.notifyUnknownRecipients("recovery", false) + + cy.useConfig((builder) => + builder + .longRecoveryLifespan() + .disableVerification() + .enableRecovery() + .useRecoveryStrategy("code") + .notifyUnknownRecipients("recovery", false), + ) identity = gen.identityWithWebsite() cy.registerApi(identity) @@ -85,8 +88,6 @@ context("Account Recovery With Code Success", () => { }) it("should recover account with correct code after entering wrong code", () => { - const identity = gen.identityWithWebsite() - cy.registerApi(identity) cy.visit(recovery) cy.get(appPrefix(app) + "input[name='email']").type(identity.email) cy.get("button[value='code']").click() @@ -117,8 +118,6 @@ context("Account Recovery With Code Success", () => { }) it("should recover account after resending code", () => { - const identity = gen.identityWithWebsite() - cy.registerApi(identity) cy.visit(recovery) cy.get(appPrefix(app) + "input[name='email']").type(identity.email) cy.get("button[value='code']").click() @@ -170,12 +169,14 @@ context("Account Recovery With Code Success", () => { cy.useConfigProfile("recovery") cy.proxy(app) - cy.deleteMail() - cy.longRecoveryLifespan() - cy.longCodeLifespan() - cy.disableVerification() - cy.enableRecovery() - cy.useRecoveryStrategy("code") + cy.useConfig((builder) => + builder + .longRecoveryLifespan() + .longCodeLifespan() + .disableVerification() + .enableRecovery() + .useRecoveryStrategy("code"), + ) const identity = gen.identityWithWebsite() cy.registerApi(identity) diff --git a/test/e2e/cypress/integration/profiles/recovery/link/errors.spec.ts b/test/e2e/cypress/integration/profiles/recovery/link/errors.spec.ts index e59e6e37207c..97d72d3221de 100644 --- a/test/e2e/cypress/integration/profiles/recovery/link/errors.spec.ts +++ b/test/e2e/cypress/integration/profiles/recovery/link/errors.spec.ts @@ -27,14 +27,18 @@ context("Account Recovery Errors", () => { beforeEach(() => { cy.deleteMail() - cy.longRecoveryLifespan() - cy.longLinkLifespan() - cy.disableVerification() - cy.enableRecovery() - cy.useRecoveryStrategy("link") - cy.disableRecoveryStrategy("code") cy.clearAllCookies() - cy.notifyUnknownRecipients("verification", false) + + cy.useConfig((builder) => + builder + .longRecoveryLifespan() + .longLinkLifespan() + .disableVerification() + .enableRecovery() + .useRecoveryStrategy("link") + .disableRecoveryStrategy("code") + .notifyUnknownRecipients("verification", false), + ) }) it("responds with a HTML response on link click of an API flow if the link is expired", () => { diff --git a/test/e2e/cypress/integration/profiles/recovery/link/success.spec.ts b/test/e2e/cypress/integration/profiles/recovery/link/success.spec.ts index 8dec47a474de..fc4137200b59 100644 --- a/test/e2e/cypress/integration/profiles/recovery/link/success.spec.ts +++ b/test/e2e/cypress/integration/profiles/recovery/link/success.spec.ts @@ -31,11 +31,15 @@ context("Account Recovery Success", () => { beforeEach(() => { cy.deleteMail() - cy.longRecoveryLifespan() - cy.longLinkLifespan() - cy.disableVerification() - cy.enableRecovery() - cy.useRecoveryStrategy("link") + + cy.useConfig((builder) => + builder + .longRecoveryLifespan() + .longLinkLifespan() + .disableVerification() + .enableRecovery() + .useRecoveryStrategy("link"), + ) identity = gen.identityWithWebsite() cy.registerApi(identity) @@ -93,10 +97,14 @@ context("Account Recovery Success", () => { cy.proxy(app) cy.deleteMail() - cy.longRecoveryLifespan() - cy.longLinkLifespan() - cy.disableVerification() - cy.enableRecovery() + + cy.useConfig((builder) => + builder + .longRecoveryLifespan() + .longLinkLifespan() + .disableVerification() + .enableRecovery(), + ) const identity = gen.identityWithWebsite() cy.registerApi(identity) @@ -123,7 +131,8 @@ context("Account Recovery Success", () => { cy.proxy(app) cy.deleteMail() - cy.disableVerification() + + cy.useConfig((builder) => builder.disableVerification()) const identity1 = gen.identityWithWebsite() cy.registerApi(identity1) diff --git a/test/e2e/cypress/integration/profiles/recovery/return-to/success.spec.ts b/test/e2e/cypress/integration/profiles/recovery/return-to/success.spec.ts index 2029d2758a1b..0fa3f12a9524 100644 --- a/test/e2e/cypress/integration/profiles/recovery/return-to/success.spec.ts +++ b/test/e2e/cypress/integration/profiles/recovery/return-to/success.spec.ts @@ -33,14 +33,18 @@ context("Recovery with `return_to`", () => { beforeEach(() => { cy.deleteMail() - cy.longRecoveryLifespan() - cy.disableVerification() - cy.enableRecovery() - cy.useRecoveryStrategy("code") - cy.notifyUnknownRecipients("recovery", false) + + cy.useConfig((builder) => + builder + .longRecoveryLifespan() + .disableVerification() + .enableRecovery() + .useRecoveryStrategy("code") + .notifyUnknownRecipients("recovery", false) + .longPrivilegedSessionTime() + .requireStrictAal(), + ) cy.clearAllCookies() - cy.longPrivilegedSessionTime() - cy.requireStrictAal() identity = gen.identityWithWebsite() cy.registerApi(identity) }) @@ -80,8 +84,6 @@ context("Recovery with `return_to`", () => { }) it("should return to the `return_to` url even with mfa enabled after successful account recovery and settings update", () => { - cy.requireStrictAal() - cy.visit(settings) cy.get('input[name="identifier"]').type(identity.email) cy.get('input[name="password"]').type(identity.password) diff --git a/test/e2e/cypress/integration/profiles/recovery/settings/success.spec.ts b/test/e2e/cypress/integration/profiles/recovery/settings/success.spec.ts index e99933ed1eb6..f7e5188de72b 100644 --- a/test/e2e/cypress/integration/profiles/recovery/settings/success.spec.ts +++ b/test/e2e/cypress/integration/profiles/recovery/settings/success.spec.ts @@ -31,10 +31,14 @@ context("Account Recovery Success", () => { beforeEach(() => { cy.deleteMail() - cy.longRecoveryLifespan() - cy.longLinkLifespan() - cy.disableVerification() - cy.enableRecovery() + + cy.useConfig((builder) => + builder + .longRecoveryLifespan() + .longLinkLifespan() + .disableVerification() + .enableRecovery(), + ) identity = gen.identityWithWebsite() cy.registerApi(identity) diff --git a/test/e2e/cypress/integration/profiles/verification/login/errors.spec.ts b/test/e2e/cypress/integration/profiles/verification/login/errors.spec.ts index d7cda1182761..55d246625da9 100644 --- a/test/e2e/cypress/integration/profiles/verification/login/errors.spec.ts +++ b/test/e2e/cypress/integration/profiles/verification/login/errors.spec.ts @@ -22,7 +22,7 @@ context("Account Verification Login Errors", () => { before(() => { cy.deleteMail() cy.useConfigProfile(profile) - cy.enableLoginForVerifiedAddressOnly() + cy.useConfig((builder) => builder.enableLoginForVerifiedAddressOnly()) cy.proxy(app) }) diff --git a/test/e2e/cypress/integration/profiles/verification/login/success.spec.ts b/test/e2e/cypress/integration/profiles/verification/login/success.spec.ts index b25247343ccf..a7a57c7ceacd 100644 --- a/test/e2e/cypress/integration/profiles/verification/login/success.spec.ts +++ b/test/e2e/cypress/integration/profiles/verification/login/success.spec.ts @@ -22,7 +22,7 @@ context("Account Verification Login Success", () => { before(() => { cy.deleteMail() cy.useConfigProfile(profile) - cy.enableLoginForVerifiedAddressOnly() + cy.useConfig((builder) => builder.enableLoginForVerifiedAddressOnly()) cy.proxy(app) }) diff --git a/test/e2e/cypress/integration/profiles/verification/registration/errors.spec.ts b/test/e2e/cypress/integration/profiles/verification/registration/errors.spec.ts index 8ffa93362208..74b0ad72231c 100644 --- a/test/e2e/cypress/integration/profiles/verification/registration/errors.spec.ts +++ b/test/e2e/cypress/integration/profiles/verification/registration/errors.spec.ts @@ -34,11 +34,13 @@ context("Account Verification Registration Errors", () => { let identity beforeEach(() => { - cy.enableVerification() - cy.disableRecovery() - cy.shortCodeLifespan() - cy.longVerificationLifespan() - + cy.useConfig((builder) => + builder + .enableVerification() + .disableRecovery() + .shortCodeLifespan() + .longVerificationLifespan(), + ) cy.deleteMail() identity = gen.identityWithWebsite() @@ -47,7 +49,6 @@ context("Account Verification Registration Errors", () => { }) it("is unable to verify the email address if the code is no longer valid and resend the code", () => { - cy.shortCodeLifespan() cy.verifyEmailButExpired({ expect: { email: identity.email }, }) diff --git a/test/e2e/cypress/integration/profiles/verification/registration/success.spec.ts b/test/e2e/cypress/integration/profiles/verification/registration/success.spec.ts index b8bd60c06733..eac70c02e597 100644 --- a/test/e2e/cypress/integration/profiles/verification/registration/success.spec.ts +++ b/test/e2e/cypress/integration/profiles/verification/registration/success.spec.ts @@ -27,7 +27,7 @@ context("Account Verification Registration Success", () => { }) beforeEach(() => { - cy.longVerificationLifespan() + cy.useConfig((builder) => builder.longVerificationLifespan()) cy.deleteMail() }) diff --git a/test/e2e/cypress/integration/profiles/verification/settings/error.spec.ts b/test/e2e/cypress/integration/profiles/verification/settings/error.spec.ts index 23580fe0ea8d..128234a2d570 100644 --- a/test/e2e/cypress/integration/profiles/verification/settings/error.spec.ts +++ b/test/e2e/cypress/integration/profiles/verification/settings/error.spec.ts @@ -41,7 +41,7 @@ context("Account Verification Settings Error", () => { }) beforeEach(() => { - cy.longCodeLifespan() + cy.useConfig((builder) => builder.longCodeLifespan()) identity = gen.identityWithWebsite() cy.clearAllCookies() cy.registerApi(identity) diff --git a/test/e2e/cypress/integration/profiles/verification/verify/errors.spec.ts b/test/e2e/cypress/integration/profiles/verification/verify/errors.spec.ts index 85588e075072..0b47b0838f92 100644 --- a/test/e2e/cypress/integration/profiles/verification/verify/errors.spec.ts +++ b/test/e2e/cypress/integration/profiles/verification/verify/errors.spec.ts @@ -38,11 +38,14 @@ context("Account Verification Error", () => { let identity beforeEach(() => { cy.clearAllCookies() - cy.longVerificationLifespan() - cy.longLifespan(s) - cy.useVerificationStrategy(s) - cy.resetCourierTemplates("verification") - cy.notifyUnknownRecipients("verification", false) + + cy.useConfig((builder) => + builder + .longVerificationLifespan() + .longLifespan(s) + .useVerificationStrategy(s) + .notifyUnknownRecipients("verification", false), + ) identity = gen.identity() cy.registerApi(identity) diff --git a/test/e2e/cypress/integration/profiles/verification/verify/success.spec.ts b/test/e2e/cypress/integration/profiles/verification/verify/success.spec.ts index 4f460638e838..ae39cdbc0d83 100644 --- a/test/e2e/cypress/integration/profiles/verification/verify/success.spec.ts +++ b/test/e2e/cypress/integration/profiles/verification/verify/success.spec.ts @@ -20,19 +20,20 @@ context("Account Verification Settings Success", () => { }, ].forEach(({ profile, verification, app }) => { describe(`for app ${app}`, () => { + before(() => { + cy.useConfigProfile(profile) + cy.proxy(app) + }) for (let s of ["code", "link"] as Strategy[]) { describe(`for strategy ${s}`, () => { - before(() => { - cy.deleteMail() - cy.useConfigProfile(profile) - cy.proxy(app) - }) - let identity beforeEach(() => { - cy.useVerificationStrategy(s) - cy.notifyUnknownRecipients("verification", false) + cy.useConfig((builder) => + builder + .useVerificationStrategy(s) + .notifyUnknownRecipients("verification", false), + ) identity = gen.identity() cy.register(identity) cy.deleteMail({ atLeast: 1 }) // clean up registration email @@ -53,7 +54,7 @@ context("Account Verification Settings Success", () => { }) it("should request verification for an email that does not exist yet", () => { - cy.notifyUnknownRecipients("verification") + cy.notifyUnknownRecipients("verification", true) const email = `not-${identity.email}` cy.get('input[name="email"]').type(email) cy.get(`button[value="${s}"]`).click() diff --git a/test/e2e/cypress/support/commands.ts b/test/e2e/cypress/support/commands.ts index d924827b5881..c2aa9e98bbc6 100644 --- a/test/e2e/cypress/support/commands.ts +++ b/test/e2e/cypress/support/commands.ts @@ -19,6 +19,7 @@ import YAML from "yamljs" import { Strategy } from "." import { OryKratosConfiguration } from "./config" import { UiNode, UiNodeAttributes } from "@ory/kratos-client" +import { ConfigBuilder } from "./configHelpers" const configFile = "kratos.generated.yml" @@ -866,7 +867,6 @@ Cypress.Commands.add( cy.visit(cookieUrl) cy.clearAllCookies() - cy.longPrivilegedSessionTime() cy.request({ url: APP_URL + "/self-service/login/browser", followRedirect: false, @@ -900,7 +900,7 @@ Cypress.Commands.add( expectSession, }) if (expectSession) { - expect(status).to.eq(200, body) + expect(status).to.eq(200, JSON.stringify(body)) return cy.getSession() } else { expect(status).to.not.eq(200, body) @@ -1520,3 +1520,10 @@ Cypress.Commands.add("getLoginCodeFromEmail", (email, opts) => { return code }) }) + +Cypress.Commands.add("useConfig", (cb) => { + cy.updateConfigFile((config) => { + const builder = cb(new ConfigBuilder(config)) + return builder.build() + }) +}) diff --git a/test/e2e/cypress/support/configHelpers.ts b/test/e2e/cypress/support/configHelpers.ts new file mode 100644 index 000000000000..545bff2449c3 --- /dev/null +++ b/test/e2e/cypress/support/configHelpers.ts @@ -0,0 +1,135 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +import { OryKratosConfiguration } from "./config" + +export class ConfigBuilder { + constructor(readonly config: OryKratosConfiguration) {} + + public build() { + return this.config + } + + public longRecoveryLifespan() { + this.config.selfservice.flows.recovery.lifespan = "1h" + return this + } + + public longLinkLifespan() { + this.config.selfservice.methods.link.config.lifespan = "1m" + return this + } + + public disableVerification() { + this.config.selfservice.flows.verification.enabled = false + return this + } + + public enableRecovery() { + if (!this.config.selfservice.flows.recovery) { + this.config.selfservice.flows.recovery = {} + } + this.config.selfservice.flows.recovery.enabled = true + return this + } + + public disableRecovery() { + this.config.selfservice.flows.recovery.enabled = false + return this + } + + public enableVerification() { + this.config.selfservice.flows.verification.enabled = true + return this + } + + public useRecoveryStrategy(strategy: "link" | "code") { + if (!this.config.selfservice.flows.recovery) { + this.config.selfservice.flows.recovery = {} + } + this.config.selfservice.flows.recovery.use = strategy + if (!this.config.selfservice.methods[strategy]) { + this.config.selfservice.methods[strategy] = {} + } + this.config.selfservice.methods[strategy].enabled = true + return this + } + + public disableRecoveryStrategy(strategy: "link" | "code") { + this.config.selfservice.methods[strategy].enabled = false + return this + } + + public notifyUnknownRecipients( + flow: "recovery" | "verification", + value: boolean, + ) { + this.config.selfservice.flows[flow].notify_unknown_recipients = value + return this + } + + public longCodeLifespan() { + this.config.selfservice.methods.code.config.lifespan = "1m" + return this + } + + public shortCodeLifespan() { + this.config.selfservice.methods.code.config.lifespan = "1ms" + return this + } + + public longPrivilegedSessionTime() { + this.config.selfservice.flows.settings.privileged_session_max_age = "5m" + return this + } + + public requireStrictAal() { + this.config.selfservice.flows.settings.required_aal = "highest_available" + this.config.session.whoami.required_aal = "highest_available" + return this + } + + public enableLoginForVerifiedAddressOnly() { + this.config.selfservice.flows.login["after"] = { + password: { hooks: [{ hook: "require_verified_address" }] }, + } + return this + } + + public longVerificationLifespan() { + this.config.selfservice.flows.verification.lifespan = "1m" + return this + } + + public longLifespan(strategy: "link" | "code") { + this.config.selfservice.methods[strategy].config.lifespan = "1m" + return this + } + + public useVerificationStrategy(strategy: "link" | "code") { + this.config.selfservice.flows.verification.use = strategy + if (!this.config.selfservice.methods[strategy]) { + this.config.selfservice.methods[strategy] = {} + } + this.config.selfservice.methods[strategy].enabled = true + return this + } + + public resetCourierTemplates( + type: "recovery" | "verification" | "recovery_code" | "verification_code", + ) { + if ( + this.config.courier?.templates && + type in this.config.courier.templates + ) { + delete this.config.courier.templates[type] + } + return this + } + + public useLaxAal() { + this.config.selfservice.flows.settings.required_aal = "aal1" + this.config.session.whoami.required_aal = "aal1" + return this + } +} diff --git a/test/e2e/cypress/support/index.d.ts b/test/e2e/cypress/support/index.d.ts index 47b66308c252..180e93260c41 100644 --- a/test/e2e/cypress/support/index.d.ts +++ b/test/e2e/cypress/support/index.d.ts @@ -3,6 +3,7 @@ import { Session as KratosSession } from "@ory/kratos-client" import { OryKratosConfiguration } from "./config" +import { ConfigBuilder } from "./configHelpers" export interface MailMessage { fromAddress: string @@ -742,6 +743,8 @@ declare global { email: string, opts?: { expectedCount: number }, ): Chainable + + useConfig(cb: (config: ConfigBuilder) => ConfigBuilder): Chainable } } } diff --git a/test/e2e/run.sh b/test/e2e/run.sh index 3ea3e5bcab8e..553dcda30a79 100755 --- a/test/e2e/run.sh +++ b/test/e2e/run.sh @@ -80,6 +80,7 @@ cleanup() { } prepare() { + echo "::group::prepare" if [[ "${nokill}" == "no" ]]; then cleanup fi @@ -261,9 +262,12 @@ prepare() { env | grep CYPRESS_ >> test/e2e/playwright/playwright.env echo LOG_LEAK_SENSITIVE_VALUES=true >> test/e2e/playwright/playwright.env echo DEV_DISABLE_API_FLOW_ENFORCEMENT=true >> test/e2e/playwright/playwright.env + + echo "::endgroup::" } run() { + echo "::group::run-prep" killall modd || true killall kratos || true @@ -281,7 +285,7 @@ run() { (modd -f test/e2e/modd.conf >"${base}/test/e2e/kratos.e2e.log" 2>&1 &) - npm run wait-on -- -v -l -t 300000 http-get://localhost:4434/health/ready \ + npm run wait-on -- -l -t 300000 http-get://localhost:4434/health/ready \ http-get://localhost:4444/.well-known/openid-configuration \ http-get://localhost:4455/health/ready \ http-get://localhost:4445/health/ready \ @@ -291,6 +295,7 @@ run() { http-get://localhost:4437/mail \ http-get://localhost:4458/ \ http-get://localhost:4459/health + echo "::endgroup::" if [[ $dev == "yes" ]]; then (cd test/e2e; npm run test:watch --) From 8ca3adcb8a5db2906fbeb92f4b74aa4242fabdef Mon Sep 17 00:00:00 2001 From: Jakub Pogorzelski <8654187+jpogorzelski@users.noreply.github.com> Date: Fri, 8 Sep 2023 10:01:02 +0200 Subject: [PATCH 072/282] docs: update link to hashed password formats (#3484) --- identity/handler.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/identity/handler.go b/identity/handler.go index 7c32e56fa058..795824fcf046 100644 --- a/identity/handler.go +++ b/identity/handler.go @@ -344,7 +344,7 @@ type AdminIdentityImportCredentialsPassword struct { // // swagger:model identityWithCredentialsPasswordConfig type AdminIdentityImportCredentialsPasswordConfig struct { - // The hashed password in [PHC format]( https://www.ory.sh/docs/kratos/concepts/credentials/username-email-password#hashed-password-format) + // The hashed password in [PHC format](https://www.ory.sh/docs/kratos/manage-identities/import-user-accounts-identities#hashed-passwords) HashedPassword string `json:"hashed_password"` // The password in plain text if no hash is available. From 56821272a2ef77b690f5b8a32de9fcc6a8867c0c Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Fri, 8 Sep 2023 08:03:24 +0000 Subject: [PATCH 073/282] autogen(openapi): regenerate swagger spec and internal client [skip ci] --- .../model_identity_with_credentials_password_config.go | 2 +- .../model_identity_with_credentials_password_config.go | 2 +- spec/api.json | 2 +- spec/swagger.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/client-go/model_identity_with_credentials_password_config.go b/internal/client-go/model_identity_with_credentials_password_config.go index 317bdd9d753f..754d59460f83 100644 --- a/internal/client-go/model_identity_with_credentials_password_config.go +++ b/internal/client-go/model_identity_with_credentials_password_config.go @@ -17,7 +17,7 @@ import ( // IdentityWithCredentialsPasswordConfig Create Identity and Import Password Credentials Configuration type IdentityWithCredentialsPasswordConfig struct { - // The hashed password in [PHC format]( https://www.ory.sh/docs/kratos/concepts/credentials/username-email-password#hashed-password-format) + // The hashed password in [PHC format](https://www.ory.sh/docs/kratos/manage-identities/import-user-accounts-identities#hashed-passwords) HashedPassword *string `json:"hashed_password,omitempty"` // The password in plain text if no hash is available. Password *string `json:"password,omitempty"` diff --git a/internal/httpclient/model_identity_with_credentials_password_config.go b/internal/httpclient/model_identity_with_credentials_password_config.go index 317bdd9d753f..754d59460f83 100644 --- a/internal/httpclient/model_identity_with_credentials_password_config.go +++ b/internal/httpclient/model_identity_with_credentials_password_config.go @@ -17,7 +17,7 @@ import ( // IdentityWithCredentialsPasswordConfig Create Identity and Import Password Credentials Configuration type IdentityWithCredentialsPasswordConfig struct { - // The hashed password in [PHC format]( https://www.ory.sh/docs/kratos/concepts/credentials/username-email-password#hashed-password-format) + // The hashed password in [PHC format](https://www.ory.sh/docs/kratos/manage-identities/import-user-accounts-identities#hashed-passwords) HashedPassword *string `json:"hashed_password,omitempty"` // The password in plain text if no hash is available. Password *string `json:"password,omitempty"` diff --git a/spec/api.json b/spec/api.json index 6481b5b22cbf..1a3863418a38 100644 --- a/spec/api.json +++ b/spec/api.json @@ -1127,7 +1127,7 @@ "description": "Create Identity and Import Password Credentials Configuration", "properties": { "hashed_password": { - "description": "The hashed password in [PHC format]( https://www.ory.sh/docs/kratos/concepts/credentials/username-email-password#hashed-password-format)", + "description": "The hashed password in [PHC format](https://www.ory.sh/docs/kratos/manage-identities/import-user-accounts-identities#hashed-passwords)", "type": "string" }, "password": { diff --git a/spec/swagger.json b/spec/swagger.json index d48afb33998b..e2817e8a5af2 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -4072,7 +4072,7 @@ "type": "object", "properties": { "hashed_password": { - "description": "The hashed password in [PHC format]( https://www.ory.sh/docs/kratos/concepts/credentials/username-email-password#hashed-password-format)", + "description": "The hashed password in [PHC format](https://www.ory.sh/docs/kratos/manage-identities/import-user-accounts-identities#hashed-passwords)", "type": "string" }, "password": { From 3a577269980213e4415fd5fa713882990e2e7640 Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Fri, 8 Sep 2023 11:05:26 +0300 Subject: [PATCH 074/282] fix: use registry client for schema loading (#3471) --- schema/handler.go | 30 ++++++++++++++++++++++-------- schema/handler_test.go | 4 ++-- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/schema/handler.go b/schema/handler.go index 3d81f34da602..74056cae1d95 100644 --- a/schema/handler.go +++ b/schema/handler.go @@ -4,6 +4,7 @@ package schema import ( + "context" "encoding/base64" "encoding/json" "fmt" @@ -12,6 +13,8 @@ import ( "os" "strings" + "github.com/ory/x/otelx" + "github.com/ory/x/pagination/migrationpagination" "github.com/ory/x/urlx" @@ -33,6 +36,8 @@ type ( IdentityTraitsProvider x.CSRFProvider config.Provider + x.TracingProvider + x.HTTPClientProvider } Handler struct { r handlerDependencies @@ -102,7 +107,10 @@ type getIdentitySchema struct { // 404: errorGeneric // default: errorGeneric func (h *Handler) getIdentitySchema(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - ss, err := h.r.IdentityTraitsSchemas(r.Context()) + ctx, span := h.r.Tracer(r.Context()).Tracer().Start(r.Context(), "schema.Handler.getIdentitySchema") + defer span.End() + + ss, err := h.r.IdentityTraitsSchemas(ctx) if err != nil { h.r.Writer().WriteError(w, r, errors.WithStack(herodot.ErrInternalServerError.WithWrap(err))) return @@ -123,7 +131,7 @@ func (h *Handler) getIdentitySchema(w http.ResponseWriter, r *http.Request, ps h } } - src, err := ReadSchema(s) + src, err := h.ReadSchema(ctx, s) if err != nil { h.r.Writer().WriteError(w, r, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("The file for this JSON Schema ID could not be found or opened. This is a configuration issue.").WithDebugf("%+v", err))) return @@ -190,6 +198,9 @@ type identitySchemasResponse struct { // 200: identitySchemas // default: errorGeneric func (h *Handler) getAll(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + ctx, span := h.r.Tracer(r.Context()).Tracer().Start(r.Context(), "schema.Handler.getAll") + defer span.End() + page, itemsPerPage := x.ParsePagination(r) allSchemas, err := h.r.IdentityTraitsSchemas(r.Context()) @@ -203,7 +214,7 @@ func (h *Handler) getAll(w http.ResponseWriter, r *http.Request, ps httprouter.P var ss IdentitySchemas for k := range schemas { schema := schemas[k] - src, err := ReadSchema(&schema) + src, err := h.ReadSchema(ctx, &schema) if err != nil { h.r.Writer().WriteError(w, r, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("The file for this JSON Schema ID could not be found or opened. This is a configuration issue.").WithDebugf("%+v", err))) return @@ -226,22 +237,25 @@ func (h *Handler) getAll(w http.ResponseWriter, r *http.Request, ps httprouter.P h.r.Writer().Write(w, r, ss) } -func ReadSchema(schema *Schema) (src io.ReadCloser, err error) { +func (h *Handler) ReadSchema(ctx context.Context, schema *Schema) (src io.ReadCloser, err error) { + ctx, span := h.r.Tracer(ctx).Tracer().Start(ctx, "schema.Handler.ReadSchema") + defer otelx.End(span, &err) + if schema.URL.Scheme == "file" { src, err = os.Open(schema.URL.Host + schema.URL.Path) if err != nil { - return nil, errors.WithStack(err) + return nil, errors.WithStack(herodot.ErrInternalServerError.WithWrap(err).WithReason("Unable to fetch identity schema.")) } } else if schema.URL.Scheme == "base64" { data, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(schema.RawURL, "base64://")) if err != nil { - return nil, errors.WithStack(err) + return nil, errors.WithStack(herodot.ErrInternalServerError.WithWrap(err).WithReason("Unable to fetch identity schema.")) } src = io.NopCloser(strings.NewReader(string(data))) } else { - resp, err := http.Get(schema.URL.String()) + resp, err := h.r.HTTPClient(ctx).Get(schema.URL.String()) if err != nil { - return nil, errors.WithStack(err) + return nil, errors.WithStack(herodot.ErrInternalServerError.WithWrap(err).WithReason("Unable to fetch identity schema.")) } src = resp.Body } diff --git a/schema/handler_test.go b/schema/handler_test.go index b88cdd55df46..a5bdf06a5a83 100644 --- a/schema/handler_test.go +++ b/schema/handler_test.go @@ -265,11 +265,11 @@ func TestHandler(t *testing.T) { }, }) - src, err := schema.ReadSchema(&schemas[0]) + src, err := reg.SchemaHandler().ReadSchema(ctx, &schemas[0]) require.NoError(t, err) defer src.Close() - src, err = schema.ReadSchema(&schemas[1]) + src, err = reg.SchemaHandler().ReadSchema(ctx, &schemas[1]) require.NoError(t, err) defer src.Close() }) From 7aa2e293175d0f4b6c13552cc3781f54f8caf3a0 Mon Sep 17 00:00:00 2001 From: Alano Terblanche <18033717+Benehiko@users.noreply.github.com> Date: Fri, 8 Sep 2023 10:09:13 +0200 Subject: [PATCH 075/282] fix: code method on registration and 2fa (#3481) --- selfservice/strategy/code/strategy_login.go | 3 ++ .../strategy/code/strategy_login_test.go | 44 ++++++++++++++++++- .../strategy/code/strategy_registration.go | 4 +- .../code/strategy_registration_test.go | 30 +++++++++++++ .../code/stub/code.identity.schema.json | 8 +++- .../profiles/code/login/error.spec.ts | 2 +- .../profiles/code/login/success.spec.ts | 2 +- .../profiles/code/registration/error.spec.ts | 7 +++ .../code/registration/success.spec.ts | 7 ++- .../profiles/email/login/ui.spec.ts | 13 ++---- .../profiles/email/settings/ui.spec.ts | 15 +++---- .../integration/profiles/mfa/totp.spec.ts | 1 - .../profiles/code/identity.traits.schema.json | 9 ++-- 13 files changed, 112 insertions(+), 33 deletions(-) diff --git a/selfservice/strategy/code/strategy_login.go b/selfservice/strategy/code/strategy_login.go index 264df98e2dd9..7be603861c8b 100644 --- a/selfservice/strategy/code/strategy_login.go +++ b/selfservice/strategy/code/strategy_login.go @@ -87,6 +87,9 @@ func (s *Strategy) HandleLoginError(r *http.Request, f *login.Flow, body *update } func (s *Strategy) PopulateLoginMethod(r *http.Request, requestedAAL identity.AuthenticatorAssuranceLevel, lf *login.Flow) error { + if requestedAAL > identity.AuthenticatorAssuranceLevel1 { + return nil + } return s.PopulateMethod(r, lf) } diff --git a/selfservice/strategy/code/strategy_login_test.go b/selfservice/strategy/code/strategy_login_test.go index a371fdfbf5f6..fac277d0d68a 100644 --- a/selfservice/strategy/code/strategy_login_test.go +++ b/selfservice/strategy/code/strategy_login_test.go @@ -50,7 +50,7 @@ func TestLoginCodeStrategy(t *testing.T) { ids = fmt.Sprintf(`%s,"email_%d":"%s"`, ids, i+1, identifier) } - i.Traits = identity.Traits(fmt.Sprintf(`{%s}`, ids)) + i.Traits = identity.Traits(fmt.Sprintf(`{"tos": true, %s}`, ids)) credentials := map[identity.CredentialsType]identity.Credentials{ identity.CredentialsTypePassword: {Identifiers: append([]string{email}, moreIdentifiers...), Type: identity.CredentialsTypePassword, Config: sqlxx.JSONRawMessage("{\"some\" : \"secret\"}")}, @@ -451,6 +451,48 @@ func TestLoginCodeStrategy(t *testing.T) { require.NotNil(t, va) require.True(t, va.Verified) }) + + t.Run("case=should not populate on 2FA request", func(t *testing.T) { + ctx := context.Background() + + // enable webauthn 2FA method + conf.MustSet(ctx, fmt.Sprintf("%s.%s.enabled", config.ViperKeySelfServiceStrategyConfig, "webauthn"), true) + conf.MustSet(ctx, config.ViperKeySessionWhoAmIAAL, config.HighestAvailableAAL) + + t.Cleanup(func() { + conf.MustSet(ctx, fmt.Sprintf("%s.%s.enabled", config.ViperKeySelfServiceStrategyConfig, "webauthn"), false) + conf.MustSet(ctx, config.ViperKeySessionWhoAmIAAL, "aal1") + }) + + s := createLoginFlow(ctx, t, public, tc.isSPA) + + // submit email + s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + v.Set("identifier", s.identityEmail) + }, false, nil) + + message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Login to your account") + assert.Contains(t, message.Body, "please login to your account by entering the following code") + + loginCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) + assert.NotEmpty(t, loginCode) + + // 3. Submit OTP + s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + v.Set("code", loginCode) + }, false, func(t *testing.T, s *state, body string, res *http.Response) { + if tc.isSPA { + require.EqualValues(t, http.StatusOK, res.StatusCode) + } else { + require.EqualValues(t, http.StatusOK, res.StatusCode) + } + }) + + clientInit := testhelpers.InitializeLoginFlowViaBrowser(t, s.client, public, false, tc.isSPA, false, false, testhelpers.InitFlowWithAAL("aal2")) + body, err := json.Marshal(clientInit) + require.NoError(t, err) + require.Len(t, gjson.GetBytes(body, "ui.nodes.#(group==code)").Array(), 0, "should not populate code field on 2fa request") + }) }) } } diff --git a/selfservice/strategy/code/strategy_registration.go b/selfservice/strategy/code/strategy_registration.go index f4c97641f055..4d728426348f 100644 --- a/selfservice/strategy/code/strategy_registration.go +++ b/selfservice/strategy/code/strategy_registration.go @@ -8,7 +8,6 @@ import ( "database/sql" "encoding/json" "net/http" - "strings" "github.com/ory/herodot" "github.com/ory/x/otelx" @@ -228,7 +227,6 @@ func (s *Strategy) registrationSendEmail(ctx context.Context, w http.ResponseWri // we return an error to the flow handler so that it does not continue execution of the hooks. // we are not done with the registration flow yet. The user needs to verify the code and then we need to persist the identity. return errors.WithStack(flow.ErrCompletedByStrategy) - } func (s *Strategy) registrationVerifyCode(ctx context.Context, f *registration.Flow, p *updateRegistrationFlowWithCodeMethod, i *identity.Identity) (err error) { @@ -253,7 +251,7 @@ func (s *Strategy) registrationVerifyCode(ctx context.Context, f *registration.F // Step 2: Check if the flow traits match the identity traits for _, n := range container.NewFromJSON("", node.DefaultGroup, p.Traits, "traits").Nodes { - if !strings.EqualFold(f.GetUI().GetNodes().Find(n.ID()).Attributes.GetValue().(string), n.Attributes.GetValue().(string)) { + if f.GetUI().GetNodes().Find(n.ID()).Attributes.GetValue() != n.Attributes.GetValue() { return errors.WithStack(schema.NewTraitsMismatch()) } } diff --git a/selfservice/strategy/code/strategy_registration_test.go b/selfservice/strategy/code/strategy_registration_test.go index d787b2b3fa4e..2e4fe674fff0 100644 --- a/selfservice/strategy/code/strategy_registration_test.go +++ b/selfservice/strategy/code/strategy_registration_test.go @@ -141,6 +141,7 @@ func TestRegistrationCodeStrategy(t *testing.T) { values := testhelpers.SDKFormFieldsToURLValues(rf.Ui.Nodes) values.Set("traits.email", s.email) + values.Set("traits.tos", "1") values.Set("method", "code") body, resp := testhelpers.RegistrationMakeRequest(t, false, isSPA, rf, s.client, testhelpers.EncodeFormAsJSON(t, false, values)) @@ -175,6 +176,7 @@ func TestRegistrationCodeStrategy(t *testing.T) { // the custom vals func can add it again if needed. values.Del("resend") values.Set("traits.email", s.email) + values.Set("traits.tos", "1") vals(&values) body, resp := testhelpers.RegistrationMakeRequest(t, false, isSPA, rf, s.client, testhelpers.EncodeFormAsJSON(t, false, values)) @@ -355,10 +357,38 @@ func TestRegistrationCodeStrategy(t *testing.T) { assert.NotEmpty(t, registrationCode) s.email = "not-" + s.email // swap out email + // 3. Submit OTP + s = submitOTP(ctx, t, reg, s, func(v *url.Values) { + v.Set("code", registrationCode) + }, tc.isSPA, func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) { + if tc.isSPA { + require.Equal(t, http.StatusBadRequest, resp.StatusCode, "%s", body) + } else { + require.Equal(t, http.StatusOK, resp.StatusCode, "%s", body) + } + require.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "The provided traits do not match the traits previously associated with this flow.") + }) + }) + + t.Run("case=swapping out traits that aren't strings should not be possible on code submit", func(t *testing.T) { + ctx := context.Background() + + // 1. Initiate flow + s := createRegistrationFlow(ctx, t, public, tc.isSPA) + + // 2. Submit Identifier (email) + s = registerNewUser(ctx, t, s, tc.isSPA, nil) + + message := testhelpers.CourierExpectMessage(ctx, t, reg, s.email, "Complete your account registration") + assert.Contains(t, message.Body, "please complete your account registration by entering the following code") + + registrationCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) + assert.NotEmpty(t, registrationCode) // 3. Submit OTP s = submitOTP(ctx, t, reg, s, func(v *url.Values) { v.Set("code", registrationCode) + v.Set("traits.tos", "0") }, tc.isSPA, func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) { if tc.isSPA { require.Equal(t, http.StatusBadRequest, resp.StatusCode, "%s", body) diff --git a/selfservice/strategy/code/stub/code.identity.schema.json b/selfservice/strategy/code/stub/code.identity.schema.json index f8d988c21af9..f6907db3d9ed 100644 --- a/selfservice/strategy/code/stub/code.identity.schema.json +++ b/selfservice/strategy/code/stub/code.identity.schema.json @@ -54,8 +54,14 @@ "via": "email" } } + }, + "tos": { + "type": "boolean", + "title": "Tos", + "description": "Please accept the terms and conditions" } - } + }, + "required": ["email", "tos"] } } } diff --git a/test/e2e/cypress/integration/profiles/code/login/error.spec.ts b/test/e2e/cypress/integration/profiles/code/login/error.spec.ts index 46d8854c4e99..899eafb0514a 100644 --- a/test/e2e/cypress/integration/profiles/code/login/error.spec.ts +++ b/test/e2e/cypress/integration/profiles/code/login/error.spec.ts @@ -31,7 +31,7 @@ context("Login error messages with code method", () => { const email = gen.email() cy.wrap(email).as("email") - cy.registerWithCode({ email }) + cy.registerWithCode({ email, traits: { "traits.tos": 1 } }) cy.deleteMail() cy.clearAllCookies() diff --git a/test/e2e/cypress/integration/profiles/code/login/success.spec.ts b/test/e2e/cypress/integration/profiles/code/login/success.spec.ts index 83cbbb605c20..2f882717edbd 100644 --- a/test/e2e/cypress/integration/profiles/code/login/success.spec.ts +++ b/test/e2e/cypress/integration/profiles/code/login/success.spec.ts @@ -30,7 +30,7 @@ context("Login success with code method", () => { beforeEach(() => { const email = gen.email() cy.wrap(email).as("email") - cy.registerWithCode({ email }) + cy.registerWithCode({ email, traits: { "traits.tos": 1 } }) cy.deleteMail() cy.clearAllCookies() diff --git a/test/e2e/cypress/integration/profiles/code/registration/error.spec.ts b/test/e2e/cypress/integration/profiles/code/registration/error.spec.ts index a4d6596008dd..b96e7b726380 100644 --- a/test/e2e/cypress/integration/profiles/code/registration/error.spec.ts +++ b/test/e2e/cypress/integration/profiles/code/registration/error.spec.ts @@ -34,6 +34,8 @@ context("Registration error messages with code method", () => { const email = gen.email() cy.get('input[name="traits.email"]').type(email) + cy.get('[name="traits.tos"] + label').click() + cy.submitCodeForm() cy.get('[data-testid="ui/message/1040005"]').should( @@ -54,6 +56,8 @@ context("Registration error messages with code method", () => { const email = gen.email() cy.get('input[name="traits.email"]').type(email) + cy.get('[name="traits.tos"] + label').click() + cy.submitCodeForm() cy.get('[data-testid="ui/message/1040005"]').should( "contain", @@ -76,6 +80,8 @@ context("Registration error messages with code method", () => { const email = gen.email() cy.get('input[name="traits.email"]').type(email) + cy.get('[name="traits.tos"] + label').click() + cy.submitCodeForm() cy.get('[data-testid="ui/message/1040005"]').should( "contain", @@ -110,6 +116,7 @@ context("Registration error messages with code method", () => { const email = gen.email() cy.get('input[name="traits.email"]').type(email) + cy.get('[name="traits.tos"] + label').click() cy.submitCodeForm() cy.get('[data-testid="ui/message/1040005"]').should( diff --git a/test/e2e/cypress/integration/profiles/code/registration/success.spec.ts b/test/e2e/cypress/integration/profiles/code/registration/success.spec.ts index 299d5707a7d5..4ce2d0703b1d 100644 --- a/test/e2e/cypress/integration/profiles/code/registration/success.spec.ts +++ b/test/e2e/cypress/integration/profiles/code/registration/success.spec.ts @@ -39,6 +39,7 @@ context("Registration success with code method", () => { const email = gen.email() cy.get(`input[name='traits.email']`).type(email) + cy.get(`[name='traits.tos'] + label`).click() cy.submitCodeForm() cy.get('[data-testid="ui/message/1040005"]').should( @@ -88,7 +89,8 @@ context("Registration success with code method", () => { it("should sign up and be logged in with session hook", () => { const email = gen.email() - cy.get(` input[name='traits.email']`).type(email) + cy.get(`input[name='traits.email']`).type(email) + cy.get(`[name='traits.tos'] + label`).click() cy.submitCodeForm() cy.get('[data-testid="ui/message/1040005"]').should( @@ -115,6 +117,7 @@ context("Registration success with code method", () => { const email = gen.email() cy.get(`input[name='traits.email']`).type(email) + cy.get(`[name='traits.tos'] + label`).click() cy.submitCodeForm() cy.get('[data-testid="ui/message/1040005"]').should( @@ -147,7 +150,7 @@ context("Registration success with code method", () => { it("should be able to recover account when registered with code", () => { const email = gen.email() - cy.registerWithCode({ email }) + cy.registerWithCode({ email, traits: { "traits.tos": 1 } }) cy.clearAllCookies() cy.visit(recovery) diff --git a/test/e2e/cypress/integration/profiles/email/login/ui.spec.ts b/test/e2e/cypress/integration/profiles/email/login/ui.spec.ts index 8255e9e3b23d..8792dd14cb64 100644 --- a/test/e2e/cypress/integration/profiles/email/login/ui.spec.ts +++ b/test/e2e/cypress/integration/profiles/email/login/ui.spec.ts @@ -33,16 +33,9 @@ context("UI tests using the email profile", () => { .parent() .should("contain.text", "ID") - if (app === "express") { - cy.get('[data-testid="node/input/password"]').should( - "contain.text", - "Password", - ) - } else { - cy.get('input[name="password"]') - .parent() - .should("contain.text", "Password") - } + cy.get('input[name="password"]') + .parentsUntil("label") + .should("contain.text", "Password") cy.get('button[value="password"]').should("contain.text", "Sign in") }) diff --git a/test/e2e/cypress/integration/profiles/email/settings/ui.spec.ts b/test/e2e/cypress/integration/profiles/email/settings/ui.spec.ts index 7acf65740f7e..6a0cfd1071f4 100644 --- a/test/e2e/cypress/integration/profiles/email/settings/ui.spec.ts +++ b/test/e2e/cypress/integration/profiles/email/settings/ui.spec.ts @@ -49,16 +49,11 @@ context("Settings errors with email profile", () => { cy.get('input[name="traits.website"]') .parent() .should("contain.text", "Your website") - if (app === "express") { - cy.get('[data-testid="node/input/password"]').should( - "contain.text", - "Password", - ) - } else { - cy.get('input[name="password"]') - .parent() - .should("contain.text", "Password") - } + + cy.get('input[name="password"]') + .parentsUntil("label") + .should("contain.text", "Password") + cy.get('button[value="profile"]').should("contain.text", "Save") cy.get('button[value="password"]').should("contain.text", "Save") }) diff --git a/test/e2e/cypress/integration/profiles/mfa/totp.spec.ts b/test/e2e/cypress/integration/profiles/mfa/totp.spec.ts index 24e25fbd3dc6..a193bcb6ceed 100644 --- a/test/e2e/cypress/integration/profiles/mfa/totp.spec.ts +++ b/test/e2e/cypress/integration/profiles/mfa/totp.spec.ts @@ -277,7 +277,6 @@ context("2FA TOTP", () => { expect(loc.search).to.not.include("aal") expect(loc.search).to.not.include("refresh") }) - cy.get("h2").contains(/Sign in/i) cy.noSession() }) diff --git a/test/e2e/profiles/code/identity.traits.schema.json b/test/e2e/profiles/code/identity.traits.schema.json index 268ae57da51a..ef8f80f5cd79 100644 --- a/test/e2e/profiles/code/identity.traits.schema.json +++ b/test/e2e/profiles/code/identity.traits.schema.json @@ -29,11 +29,14 @@ "via": "email" } } + }, + "tos": { + "type": "boolean", + "title": "Accept Terms of Service", + "description": "In order to sign up, you have to accept our terms of service." } }, - "required": [ - "email" - ] + "required": ["email", "tos"] } } } From 1e8b1aeb4bf866892788986f62a31255372de999 Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Fri, 8 Sep 2023 11:12:28 +0300 Subject: [PATCH 076/282] fix: identity list pagination in CLI command and SDK (#3482) Adds correct pagination parameters to the SDK methods for listing identities and sessions. BREAKING CHANGE: Pagination parameters for the `list identities` CLI command have changed from arguments to flags `--page-token` and `page-size`: ``` - kratos list identities 1 100 + kratos list identities --page-size 100 --page-token ... ``` Furthermore, the JSON / JSON pretty output of `list identities` has changed: ```patch -[ - { "id": "..." }, - { /* ... */ }, - // ... -] +{ + "identities": [ + {"id": "..."}, + { /* ... */ }, + // ... + ], + "next_page_token": "..." +} ``` Closes https://github.com/ory/sdk/issues/284 Closes https://github.com/ory/kratos/pull/3480 --- cmd/identities/definitions.go | 20 ++- cmd/identities/get.go | 2 +- cmd/identities/import.go | 2 +- cmd/identities/list.go | 36 +++-- cmd/identities/list_test.go | 41 +++-- go.mod | 5 +- go.sum | 6 +- internal/client-go/.openapi-generator/FILES | 2 - internal/client-go/README.md | 1 - internal/client-go/api_frontend.go | 16 ++ internal/client-go/api_identity.go | 48 ++++++ internal/httpclient/.openapi-generator/FILES | 2 - internal/httpclient/README.md | 1 - internal/httpclient/api_frontend.go | 16 ++ internal/httpclient/api_identity.go | 48 ++++++ internal/httpclient/model_pagination.go | 160 ------------------- session/handler.go | 2 +- spec/api.json | 124 ++++++++++---- spec/swagger.json | 110 +++++++++---- x/pagination.go | 31 +--- 20 files changed, 379 insertions(+), 294 deletions(-) delete mode 100644 internal/httpclient/model_pagination.go diff --git a/cmd/identities/definitions.go b/cmd/identities/definitions.go index 9f2cafb12775..956266e70aa3 100644 --- a/cmd/identities/definitions.go +++ b/cmd/identities/definitions.go @@ -14,7 +14,9 @@ import ( type ( outputIdentity kratos.Identity outputIdentityCollection struct { - identities []kratos.Identity + Identities []kratos.Identity `json:"identities"` + NextPageToken string `json:"next_page_token"` + includePageToken bool } ) @@ -61,17 +63,23 @@ func (outputIdentityCollection) Header() []string { } func (c outputIdentityCollection) Table() [][]string { - rows := make([][]string, len(c.identities)) - for i, ident := range c.identities { + rows := make([][]string, len(c.Identities)) + for i, ident := range c.Identities { rows[i] = outputIdentity(ident).Columns() } - return rows + return append(rows, + []string{""}, + []string{"NEXT PAGE TOKEN", c.NextPageToken}, + ) } func (c outputIdentityCollection) Interface() interface{} { - return c.identities + if c.includePageToken { + return c + } + return c.Identities } func (c *outputIdentityCollection) Len() int { - return len(c.identities) + return len(c.Identities) } diff --git a/cmd/identities/get.go b/cmd/identities/get.go index 185c272a3324..677ac3bc9121 100644 --- a/cmd/identities/get.go +++ b/cmd/identities/get.go @@ -82,7 +82,7 @@ func NewGetIdentityCmd() *cobra.Command { if len(identities) == 1 { cmdx.PrintRow(cmd, (*outputIdentity)(&identities[0])) } else if len(identities) > 1 { - cmdx.PrintTable(cmd, &outputIdentityCollection{identities}) + cmdx.PrintTable(cmd, &outputIdentityCollection{Identities: identities, includePageToken: false}) } cmdx.PrintErrors(cmd, failed) diff --git a/cmd/identities/import.go b/cmd/identities/import.go index 99b9d08c196d..1de8a22de385 100644 --- a/cmd/identities/import.go +++ b/cmd/identities/import.go @@ -84,7 +84,7 @@ Files can contain only a single or an array of identities. The validity of files if len(imported) == 1 { cmdx.PrintRow(cmd, (*outputIdentity)(&imported[0])) } else { - cmdx.PrintTable(cmd, &outputIdentityCollection{identities: imported}) + cmdx.PrintTable(cmd, &outputIdentityCollection{Identities: imported}) } cmdx.PrintErrors(cmd, failed) diff --git a/cmd/identities/list.go b/cmd/identities/list.go index d82d8345d26c..221a5a839715 100644 --- a/cmd/identities/list.go +++ b/cmd/identities/list.go @@ -6,6 +6,8 @@ package identities import ( "github.com/spf13/cobra" + "github.com/ory/x/pagination/keysetpagination" + "github.com/ory/kratos/cmd/cliclient" "github.com/ory/x/cmdx" ) @@ -23,13 +25,12 @@ func NewListCmd() *cobra.Command { } func NewListIdentitiesCmd() *cobra.Command { - return &cobra.Command{ - Use: "identities [ ]", + c := &cobra.Command{ + Use: "identities", Short: "List identities", - Long: "List identities (paginated)", - Example: "{{ .CommandPath }} 100 1", + Long: "Return a list of identities.", + Example: "{{ .CommandPath }} --page-size 100", Args: cmdx.ZeroOrTwoArgs, - Aliases: []string{"ls"}, RunE: func(cmd *cobra.Command, args []string) error { c, err := cliclient.NewClient(cmd) if err != nil { @@ -37,23 +38,28 @@ func NewListIdentitiesCmd() *cobra.Command { } req := c.IdentityApi.ListIdentities(cmd.Context()) - if len(args) == 2 { - page, perPage, err := cmdx.ParsePaginationArgs(cmd, args[0], args[1]) - if err != nil { - return err - } - - req = req.Page(page) - req = req.PerPage(perPage) + page, perPage, err := cmdx.ParseTokenPaginationArgs(cmd) + if err != nil { + return err } - identities, _, err := req.Execute() + req = req.PageToken(page) + req = req.PageSize(int64(perPage)) + + identities, res, err := req.Execute() if err != nil { return cmdx.PrintOpenAPIError(cmd, err) } - cmdx.PrintTable(cmd, &outputIdentityCollection{identities: identities}) + pages := keysetpagination.ParseHeader(res) + cmdx.PrintTable(cmd, &outputIdentityCollection{ + Identities: identities, + NextPageToken: pages.NextToken, + includePageToken: true, + }) return nil }, } + cmdx.RegisterTokenPaginationFlags(c) + return c } diff --git a/cmd/identities/list_test.go b/cmd/identities/list_test.go index f26a69e186ce..e8f0c2769203 100644 --- a/cmd/identities/list_test.go +++ b/cmd/identities/list_test.go @@ -5,9 +5,10 @@ package identities_test import ( "context" - "strings" "testing" + "github.com/tidwall/gjson" + "github.com/ory/kratos/cmd/identities" "github.com/ory/x/cmdx" @@ -21,7 +22,6 @@ import ( func TestListCmd(t *testing.T) { c := identities.NewListIdentitiesCmd() reg := setup(t, c) - require.NoError(t, c.Flags().Set(cmdx.FlagQuiet, "true")) var deleteIdentities = func(t *testing.T, is []*identity.Identity) { for _, i := range is { @@ -31,9 +31,13 @@ func TestListCmd(t *testing.T) { t.Run("case=lists all identities with default pagination", func(t *testing.T) { is, ids := makeIdentities(t, reg, 5) - defer deleteIdentities(t, is) + require.NoError(t, c.Flags().Set(cmdx.FlagQuiet, "true")) + t.Cleanup(func() { + require.NoError(t, c.Flags().Set(cmdx.FlagQuiet, "false")) + deleteIdentities(t, is) + }) - stdOut := execNoErr(t, c) + stdOut := cmdx.ExecNoErr(t, c) for _, i := range ids { assert.Contains(t, stdOut, i) @@ -41,15 +45,30 @@ func TestListCmd(t *testing.T) { }) t.Run("case=lists all identities with pagination", func(t *testing.T) { - is, ids := makeIdentities(t, reg, 6) - defer deleteIdentities(t, is) + is, ids := makeIdentities(t, reg, 10) + t.Cleanup(func() { + deleteIdentities(t, is) + }) - stdoutP1 := execNoErr(t, c, "0", "3") - stdoutP2 := execNoErr(t, c, "1", "3") + first := cmdx.ExecNoErr(t, c, "--format", "json-pretty", "--page-size", "2") + nextPageToken := gjson.Get(first, "next_page_token").String() + results := gjson.Get(first, "identities").Array() + for nextPageToken != "" { + next := cmdx.ExecNoErr(t, c, "--format", "json-pretty", "--page-size", "2", "--page-token", nextPageToken) + results = append(results, gjson.Get(next, "identities").Array()...) + nextPageToken = gjson.Get(next, "next_page_token").String() + } - for _, id := range ids { - // exactly one of page 1 and 2 should contain the id - assert.True(t, strings.Contains(stdoutP1, id) != strings.Contains(stdoutP2, id), "%s \n %s", stdoutP1, stdoutP2) + assert.Len(t, results, len(ids)) + for _, expected := range ids { + var found bool + for _, actual := range results { + if actual.Get("id").String() == expected { + found = true + break + } + } + require.True(t, found, "could not find id: %s", expected) } }) } diff --git a/go.mod b/go.mod index b7a72b85f39b..42dd913f3abb 100644 --- a/go.mod +++ b/go.mod @@ -76,7 +76,7 @@ require ( github.com/ory/jsonschema/v3 v3.0.8 github.com/ory/mail/v3 v3.0.0 github.com/ory/nosurf v1.2.7 - github.com/ory/x v0.0.583 + github.com/ory/x v0.0.588 github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 github.com/pkg/errors v0.9.1 github.com/pquerna/otp v1.4.0 @@ -97,6 +97,7 @@ require ( go.opentelemetry.io/otel v1.11.1 go.opentelemetry.io/otel/trace v1.11.1 golang.org/x/crypto v0.12.0 + golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 golang.org/x/net v0.14.0 golang.org/x/oauth2 v0.11.0 golang.org/x/sync v0.1.0 @@ -250,6 +251,7 @@ require ( github.com/openzipkin/zipkin-go v0.4.1 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.7 // indirect + github.com/peterhellberg/link v1.2.0 // indirect github.com/philhofer/fwd v1.1.2 // indirect github.com/pkg/profile v1.7.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -298,7 +300,6 @@ require ( go.opentelemetry.io/otel/metric v0.33.0 // indirect go.opentelemetry.io/otel/sdk v1.11.1 // indirect go.opentelemetry.io/proto/otlp v0.19.0 // indirect - golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect golang.org/x/mod v0.10.0 // indirect golang.org/x/sys v0.11.0 // indirect golang.org/x/term v0.11.0 // indirect diff --git a/go.sum b/go.sum index 5422e5e53752..60ddbe374068 100644 --- a/go.sum +++ b/go.sum @@ -816,8 +816,8 @@ github.com/ory/nosurf v1.2.7 h1:YrHrbSensQyU6r6HT/V5+HPdVEgrOTMJiLoJABSBOp4= github.com/ory/nosurf v1.2.7/go.mod h1:d4L3ZBa7Amv55bqxCBtCs63wSlyaiCkWVl4vKf3OUxA= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2 h1:zm6sDvHy/U9XrGpixwHiuAwpp0Ock6khSVHkrv6lQQU= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/ory/x v0.0.583 h1:z6xkrTip16ytAcEvL+nRdK0J+jPWyBeo8qpFOAErZ1g= -github.com/ory/x v0.0.583/go.mod h1:tgk6em/hJrDRmWAlM2g1hSNnE6rmCOk4eQ/q53/2kZc= +github.com/ory/x v0.0.588 h1:3qoC1d7qTKnMLwS3Os7KVbDLeSOUHXON8hUFuGUoScQ= +github.com/ory/x v0.0.588/go.mod h1:ksLBEd6iW6czGpE6eNA0gCIxO1FFeqIxCZgsgwNrzMM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -826,6 +826,8 @@ github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3v github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us= github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= +github.com/peterhellberg/link v1.2.0 h1:UA5pg3Gp/E0F2WdX7GERiNrPQrM1K6CVJUUWfHa4t6c= +github.com/peterhellberg/link v1.2.0/go.mod h1:gYfAh+oJgQu2SrZHg5hROVRQe1ICoK0/HHJTcE0edxc= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= diff --git a/internal/client-go/.openapi-generator/FILES b/internal/client-go/.openapi-generator/FILES index 959499576b3d..c36bd85082c4 100644 --- a/internal/client-go/.openapi-generator/FILES +++ b/internal/client-go/.openapi-generator/FILES @@ -62,7 +62,6 @@ docs/NeedsPrivilegedSessionError.md docs/OAuth2Client.md docs/OAuth2ConsentRequestOpenIDConnectContext.md docs/OAuth2LoginRequest.md -docs/Pagination.md docs/PatchIdentitiesBody.md docs/PerformNativeLogoutBody.md docs/RecoveryCodeForIdentity.md @@ -176,7 +175,6 @@ model_needs_privileged_session_error.go model_o_auth2_client.go model_o_auth2_consent_request_open_id_connect_context.go model_o_auth2_login_request.go -model_pagination.go model_patch_identities_body.go model_perform_native_logout_body.go model_recovery_code_for_identity.go diff --git a/internal/client-go/README.md b/internal/client-go/README.md index 084b578785ee..17418c7742f8 100644 --- a/internal/client-go/README.md +++ b/internal/client-go/README.md @@ -186,7 +186,6 @@ Class | Method | HTTP request | Description - [OAuth2Client](docs/OAuth2Client.md) - [OAuth2ConsentRequestOpenIDConnectContext](docs/OAuth2ConsentRequestOpenIDConnectContext.md) - [OAuth2LoginRequest](docs/OAuth2LoginRequest.md) - - [Pagination](docs/Pagination.md) - [PatchIdentitiesBody](docs/PatchIdentitiesBody.md) - [PerformNativeLogoutBody](docs/PerformNativeLogoutBody.md) - [RecoveryCodeForIdentity](docs/RecoveryCodeForIdentity.md) diff --git a/internal/client-go/api_frontend.go b/internal/client-go/api_frontend.go index ac8cadd1a4b3..e3dc0fcf14f1 100644 --- a/internal/client-go/api_frontend.go +++ b/internal/client-go/api_frontend.go @@ -4172,6 +4172,8 @@ type FrontendApiApiListMySessionsRequest struct { ApiService FrontendApi perPage *int64 page *int64 + pageSize *int64 + pageToken *string xSessionToken *string cookie *string } @@ -4184,6 +4186,14 @@ func (r FrontendApiApiListMySessionsRequest) Page(page int64) FrontendApiApiList r.page = &page return r } +func (r FrontendApiApiListMySessionsRequest) PageSize(pageSize int64) FrontendApiApiListMySessionsRequest { + r.pageSize = &pageSize + return r +} +func (r FrontendApiApiListMySessionsRequest) PageToken(pageToken string) FrontendApiApiListMySessionsRequest { + r.pageToken = &pageToken + return r +} func (r FrontendApiApiListMySessionsRequest) XSessionToken(xSessionToken string) FrontendApiApiListMySessionsRequest { r.xSessionToken = &xSessionToken return r @@ -4243,6 +4253,12 @@ func (a *FrontendApiService) ListMySessionsExecute(r FrontendApiApiListMySession if r.page != nil { localVarQueryParams.Add("page", parameterToString(*r.page, "")) } + if r.pageSize != nil { + localVarQueryParams.Add("page_size", parameterToString(*r.pageSize, "")) + } + if r.pageToken != nil { + localVarQueryParams.Add("page_token", parameterToString(*r.pageToken, "")) + } // to determine the Content-Type header localVarHTTPContentTypes := []string{} diff --git a/internal/client-go/api_identity.go b/internal/client-go/api_identity.go index 52a30f8e99b6..864934fef723 100644 --- a/internal/client-go/api_identity.go +++ b/internal/client-go/api_identity.go @@ -2049,6 +2049,8 @@ type IdentityApiApiListIdentitiesRequest struct { ApiService IdentityApi perPage *int64 page *int64 + pageSize *int64 + pageToken *string credentialsIdentifier *string } @@ -2060,6 +2062,14 @@ func (r IdentityApiApiListIdentitiesRequest) Page(page int64) IdentityApiApiList r.page = &page return r } +func (r IdentityApiApiListIdentitiesRequest) PageSize(pageSize int64) IdentityApiApiListIdentitiesRequest { + r.pageSize = &pageSize + return r +} +func (r IdentityApiApiListIdentitiesRequest) PageToken(pageToken string) IdentityApiApiListIdentitiesRequest { + r.pageToken = &pageToken + return r +} func (r IdentityApiApiListIdentitiesRequest) CredentialsIdentifier(credentialsIdentifier string) IdentityApiApiListIdentitiesRequest { r.credentialsIdentifier = &credentialsIdentifier return r @@ -2113,6 +2123,12 @@ func (a *IdentityApiService) ListIdentitiesExecute(r IdentityApiApiListIdentitie if r.page != nil { localVarQueryParams.Add("page", parameterToString(*r.page, "")) } + if r.pageSize != nil { + localVarQueryParams.Add("page_size", parameterToString(*r.pageSize, "")) + } + if r.pageToken != nil { + localVarQueryParams.Add("page_token", parameterToString(*r.pageToken, "")) + } if r.credentialsIdentifier != nil { localVarQueryParams.Add("credentials_identifier", parameterToString(*r.credentialsIdentifier, "")) } @@ -2196,6 +2212,8 @@ type IdentityApiApiListIdentitySchemasRequest struct { ApiService IdentityApi perPage *int64 page *int64 + pageSize *int64 + pageToken *string } func (r IdentityApiApiListIdentitySchemasRequest) PerPage(perPage int64) IdentityApiApiListIdentitySchemasRequest { @@ -2206,6 +2224,14 @@ func (r IdentityApiApiListIdentitySchemasRequest) Page(page int64) IdentityApiAp r.page = &page return r } +func (r IdentityApiApiListIdentitySchemasRequest) PageSize(pageSize int64) IdentityApiApiListIdentitySchemasRequest { + r.pageSize = &pageSize + return r +} +func (r IdentityApiApiListIdentitySchemasRequest) PageToken(pageToken string) IdentityApiApiListIdentitySchemasRequest { + r.pageToken = &pageToken + return r +} func (r IdentityApiApiListIdentitySchemasRequest) Execute() ([]IdentitySchemaContainer, *http.Response, error) { return r.ApiService.ListIdentitySchemasExecute(r) @@ -2255,6 +2281,12 @@ func (a *IdentityApiService) ListIdentitySchemasExecute(r IdentityApiApiListIden if r.page != nil { localVarQueryParams.Add("page", parameterToString(*r.page, "")) } + if r.pageSize != nil { + localVarQueryParams.Add("page_size", parameterToString(*r.pageSize, "")) + } + if r.pageToken != nil { + localVarQueryParams.Add("page_token", parameterToString(*r.pageToken, "")) + } // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -2322,6 +2354,8 @@ type IdentityApiApiListIdentitySessionsRequest struct { id string perPage *int64 page *int64 + pageSize *int64 + pageToken *string active *bool } @@ -2333,6 +2367,14 @@ func (r IdentityApiApiListIdentitySessionsRequest) Page(page int64) IdentityApiA r.page = &page return r } +func (r IdentityApiApiListIdentitySessionsRequest) PageSize(pageSize int64) IdentityApiApiListIdentitySessionsRequest { + r.pageSize = &pageSize + return r +} +func (r IdentityApiApiListIdentitySessionsRequest) PageToken(pageToken string) IdentityApiApiListIdentitySessionsRequest { + r.pageToken = &pageToken + return r +} func (r IdentityApiApiListIdentitySessionsRequest) Active(active bool) IdentityApiApiListIdentitySessionsRequest { r.active = &active return r @@ -2389,6 +2431,12 @@ func (a *IdentityApiService) ListIdentitySessionsExecute(r IdentityApiApiListIde if r.page != nil { localVarQueryParams.Add("page", parameterToString(*r.page, "")) } + if r.pageSize != nil { + localVarQueryParams.Add("page_size", parameterToString(*r.pageSize, "")) + } + if r.pageToken != nil { + localVarQueryParams.Add("page_token", parameterToString(*r.pageToken, "")) + } if r.active != nil { localVarQueryParams.Add("active", parameterToString(*r.active, "")) } diff --git a/internal/httpclient/.openapi-generator/FILES b/internal/httpclient/.openapi-generator/FILES index 7018bd681eac..908e0021b70e 100644 --- a/internal/httpclient/.openapi-generator/FILES +++ b/internal/httpclient/.openapi-generator/FILES @@ -63,7 +63,6 @@ docs/NeedsPrivilegedSessionError.md docs/OAuth2Client.md docs/OAuth2ConsentRequestOpenIDConnectContext.md docs/OAuth2LoginRequest.md -docs/Pagination.md docs/PatchIdentitiesBody.md docs/PerformNativeLogoutBody.md docs/RecoveryCodeForIdentity.md @@ -177,7 +176,6 @@ model_needs_privileged_session_error.go model_o_auth2_client.go model_o_auth2_consent_request_open_id_connect_context.go model_o_auth2_login_request.go -model_pagination.go model_patch_identities_body.go model_perform_native_logout_body.go model_recovery_code_for_identity.go diff --git a/internal/httpclient/README.md b/internal/httpclient/README.md index 084b578785ee..17418c7742f8 100644 --- a/internal/httpclient/README.md +++ b/internal/httpclient/README.md @@ -186,7 +186,6 @@ Class | Method | HTTP request | Description - [OAuth2Client](docs/OAuth2Client.md) - [OAuth2ConsentRequestOpenIDConnectContext](docs/OAuth2ConsentRequestOpenIDConnectContext.md) - [OAuth2LoginRequest](docs/OAuth2LoginRequest.md) - - [Pagination](docs/Pagination.md) - [PatchIdentitiesBody](docs/PatchIdentitiesBody.md) - [PerformNativeLogoutBody](docs/PerformNativeLogoutBody.md) - [RecoveryCodeForIdentity](docs/RecoveryCodeForIdentity.md) diff --git a/internal/httpclient/api_frontend.go b/internal/httpclient/api_frontend.go index ac8cadd1a4b3..e3dc0fcf14f1 100644 --- a/internal/httpclient/api_frontend.go +++ b/internal/httpclient/api_frontend.go @@ -4172,6 +4172,8 @@ type FrontendApiApiListMySessionsRequest struct { ApiService FrontendApi perPage *int64 page *int64 + pageSize *int64 + pageToken *string xSessionToken *string cookie *string } @@ -4184,6 +4186,14 @@ func (r FrontendApiApiListMySessionsRequest) Page(page int64) FrontendApiApiList r.page = &page return r } +func (r FrontendApiApiListMySessionsRequest) PageSize(pageSize int64) FrontendApiApiListMySessionsRequest { + r.pageSize = &pageSize + return r +} +func (r FrontendApiApiListMySessionsRequest) PageToken(pageToken string) FrontendApiApiListMySessionsRequest { + r.pageToken = &pageToken + return r +} func (r FrontendApiApiListMySessionsRequest) XSessionToken(xSessionToken string) FrontendApiApiListMySessionsRequest { r.xSessionToken = &xSessionToken return r @@ -4243,6 +4253,12 @@ func (a *FrontendApiService) ListMySessionsExecute(r FrontendApiApiListMySession if r.page != nil { localVarQueryParams.Add("page", parameterToString(*r.page, "")) } + if r.pageSize != nil { + localVarQueryParams.Add("page_size", parameterToString(*r.pageSize, "")) + } + if r.pageToken != nil { + localVarQueryParams.Add("page_token", parameterToString(*r.pageToken, "")) + } // to determine the Content-Type header localVarHTTPContentTypes := []string{} diff --git a/internal/httpclient/api_identity.go b/internal/httpclient/api_identity.go index 52a30f8e99b6..864934fef723 100644 --- a/internal/httpclient/api_identity.go +++ b/internal/httpclient/api_identity.go @@ -2049,6 +2049,8 @@ type IdentityApiApiListIdentitiesRequest struct { ApiService IdentityApi perPage *int64 page *int64 + pageSize *int64 + pageToken *string credentialsIdentifier *string } @@ -2060,6 +2062,14 @@ func (r IdentityApiApiListIdentitiesRequest) Page(page int64) IdentityApiApiList r.page = &page return r } +func (r IdentityApiApiListIdentitiesRequest) PageSize(pageSize int64) IdentityApiApiListIdentitiesRequest { + r.pageSize = &pageSize + return r +} +func (r IdentityApiApiListIdentitiesRequest) PageToken(pageToken string) IdentityApiApiListIdentitiesRequest { + r.pageToken = &pageToken + return r +} func (r IdentityApiApiListIdentitiesRequest) CredentialsIdentifier(credentialsIdentifier string) IdentityApiApiListIdentitiesRequest { r.credentialsIdentifier = &credentialsIdentifier return r @@ -2113,6 +2123,12 @@ func (a *IdentityApiService) ListIdentitiesExecute(r IdentityApiApiListIdentitie if r.page != nil { localVarQueryParams.Add("page", parameterToString(*r.page, "")) } + if r.pageSize != nil { + localVarQueryParams.Add("page_size", parameterToString(*r.pageSize, "")) + } + if r.pageToken != nil { + localVarQueryParams.Add("page_token", parameterToString(*r.pageToken, "")) + } if r.credentialsIdentifier != nil { localVarQueryParams.Add("credentials_identifier", parameterToString(*r.credentialsIdentifier, "")) } @@ -2196,6 +2212,8 @@ type IdentityApiApiListIdentitySchemasRequest struct { ApiService IdentityApi perPage *int64 page *int64 + pageSize *int64 + pageToken *string } func (r IdentityApiApiListIdentitySchemasRequest) PerPage(perPage int64) IdentityApiApiListIdentitySchemasRequest { @@ -2206,6 +2224,14 @@ func (r IdentityApiApiListIdentitySchemasRequest) Page(page int64) IdentityApiAp r.page = &page return r } +func (r IdentityApiApiListIdentitySchemasRequest) PageSize(pageSize int64) IdentityApiApiListIdentitySchemasRequest { + r.pageSize = &pageSize + return r +} +func (r IdentityApiApiListIdentitySchemasRequest) PageToken(pageToken string) IdentityApiApiListIdentitySchemasRequest { + r.pageToken = &pageToken + return r +} func (r IdentityApiApiListIdentitySchemasRequest) Execute() ([]IdentitySchemaContainer, *http.Response, error) { return r.ApiService.ListIdentitySchemasExecute(r) @@ -2255,6 +2281,12 @@ func (a *IdentityApiService) ListIdentitySchemasExecute(r IdentityApiApiListIden if r.page != nil { localVarQueryParams.Add("page", parameterToString(*r.page, "")) } + if r.pageSize != nil { + localVarQueryParams.Add("page_size", parameterToString(*r.pageSize, "")) + } + if r.pageToken != nil { + localVarQueryParams.Add("page_token", parameterToString(*r.pageToken, "")) + } // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -2322,6 +2354,8 @@ type IdentityApiApiListIdentitySessionsRequest struct { id string perPage *int64 page *int64 + pageSize *int64 + pageToken *string active *bool } @@ -2333,6 +2367,14 @@ func (r IdentityApiApiListIdentitySessionsRequest) Page(page int64) IdentityApiA r.page = &page return r } +func (r IdentityApiApiListIdentitySessionsRequest) PageSize(pageSize int64) IdentityApiApiListIdentitySessionsRequest { + r.pageSize = &pageSize + return r +} +func (r IdentityApiApiListIdentitySessionsRequest) PageToken(pageToken string) IdentityApiApiListIdentitySessionsRequest { + r.pageToken = &pageToken + return r +} func (r IdentityApiApiListIdentitySessionsRequest) Active(active bool) IdentityApiApiListIdentitySessionsRequest { r.active = &active return r @@ -2389,6 +2431,12 @@ func (a *IdentityApiService) ListIdentitySessionsExecute(r IdentityApiApiListIde if r.page != nil { localVarQueryParams.Add("page", parameterToString(*r.page, "")) } + if r.pageSize != nil { + localVarQueryParams.Add("page_size", parameterToString(*r.pageSize, "")) + } + if r.pageToken != nil { + localVarQueryParams.Add("page_token", parameterToString(*r.pageToken, "")) + } if r.active != nil { localVarQueryParams.Add("active", parameterToString(*r.active, "")) } diff --git a/internal/httpclient/model_pagination.go b/internal/httpclient/model_pagination.go deleted file mode 100644 index f5154c7eea47..000000000000 --- a/internal/httpclient/model_pagination.go +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Ory Identities API - * - * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. - * - * API version: - * Contact: office@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// Pagination struct for Pagination -type Pagination struct { - // Pagination Page This value is currently an integer, but it is not sequential. The value is not the page number, but a reference. The next page can be any number and some numbers might return an empty list. For example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist. - Page *int64 `json:"page,omitempty"` - // Items per Page This is the number of items per page. - PerPage *int64 `json:"per_page,omitempty"` -} - -// NewPagination instantiates a new Pagination 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 NewPagination() *Pagination { - this := Pagination{} - var page int64 = 1 - this.Page = &page - var perPage int64 = 250 - this.PerPage = &perPage - return &this -} - -// NewPaginationWithDefaults instantiates a new Pagination 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 NewPaginationWithDefaults() *Pagination { - this := Pagination{} - var page int64 = 1 - this.Page = &page - var perPage int64 = 250 - this.PerPage = &perPage - return &this -} - -// GetPage returns the Page field value if set, zero value otherwise. -func (o *Pagination) GetPage() int64 { - if o == nil || o.Page == nil { - var ret int64 - return ret - } - return *o.Page -} - -// GetPageOk returns a tuple with the Page field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *Pagination) GetPageOk() (*int64, bool) { - if o == nil || o.Page == nil { - return nil, false - } - return o.Page, true -} - -// HasPage returns a boolean if a field has been set. -func (o *Pagination) HasPage() bool { - if o != nil && o.Page != nil { - return true - } - - return false -} - -// SetPage gets a reference to the given int64 and assigns it to the Page field. -func (o *Pagination) SetPage(v int64) { - o.Page = &v -} - -// GetPerPage returns the PerPage field value if set, zero value otherwise. -func (o *Pagination) GetPerPage() int64 { - if o == nil || o.PerPage == nil { - var ret int64 - return ret - } - return *o.PerPage -} - -// GetPerPageOk returns a tuple with the PerPage field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *Pagination) GetPerPageOk() (*int64, bool) { - if o == nil || o.PerPage == nil { - return nil, false - } - return o.PerPage, true -} - -// HasPerPage returns a boolean if a field has been set. -func (o *Pagination) HasPerPage() bool { - if o != nil && o.PerPage != nil { - return true - } - - return false -} - -// SetPerPage gets a reference to the given int64 and assigns it to the PerPage field. -func (o *Pagination) SetPerPage(v int64) { - o.PerPage = &v -} - -func (o Pagination) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.Page != nil { - toSerialize["page"] = o.Page - } - if o.PerPage != nil { - toSerialize["per_page"] = o.PerPage - } - return json.Marshal(toSerialize) -} - -type NullablePagination struct { - value *Pagination - isSet bool -} - -func (v NullablePagination) Get() *Pagination { - return v.value -} - -func (v *NullablePagination) Set(val *Pagination) { - v.value = val - v.isSet = true -} - -func (v NullablePagination) IsSet() bool { - return v.isSet -} - -func (v *NullablePagination) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullablePagination(val *Pagination) *NullablePagination { - return &NullablePagination{value: val, isSet: true} -} - -func (v NullablePagination) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullablePagination) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/session/handler.go b/session/handler.go index a3f706859c22..fb0ae50d8c81 100644 --- a/session/handler.go +++ b/session/handler.go @@ -733,7 +733,7 @@ func (h *Handler) deleteMySession(w http.ResponseWriter, r *http.Request, ps htt //nolint:deadcode,unused //lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type listMySessionsParameters struct { - x.PaginationParams + migrationpagination.RequestParameters // Set the Session Token when calling from non-browser clients. A session token has a format of `MP2YWEMeM8MxjkGKpH4dqOQ4Q4DlSPaj`. // diff --git a/spec/api.json b/spec/api.json index 1a3863418a38..f1e8897dafee 100644 --- a/spec/api.json +++ b/spec/api.json @@ -1434,26 +1434,6 @@ "title": "NullTime implements sql.NullTime functionality.", "type": "string" }, - "pagination": { - "properties": { - "page": { - "default": 1, - "description": "Pagination Page\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.", - "format": "int64", - "minimum": 1, - "type": "integer" - }, - "per_page": { - "default": 250, - "description": "Items per Page\n\nThis is the number of items per page.", - "format": "int64", - "maximum": 1000, - "minimum": 1, - "type": "integer" - } - }, - "type": "object" - }, "patchIdentitiesBody": { "description": "Patch Identities Body", "properties": { @@ -3402,7 +3382,7 @@ "operationId": "listIdentities", "parameters": [ { - "description": "Items per Page\n\nThis is the number of items per page.", + "description": "Deprecated Items per Page\n\nDEPRECATED: Please use `page_token` instead. This parameter will be removed in the future.\n\nThis is the number of items per page.", "in": "query", "name": "per_page", "schema": { @@ -3414,7 +3394,7 @@ } }, { - "description": "Pagination Page\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.\nThe first page can be retrieved by omitting this parameter. Following page pointers will be returned in the\n`Link` header.", + "description": "Deprecated Pagination Page\n\nDEPRECATED: Please use `page_token` instead. This parameter will be removed in the future.\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.\nThe first page can be retrieved by omitting this parameter. Following page pointers will be returned in the\n`Link` header.", "in": "query", "name": "page", "schema": { @@ -3422,6 +3402,28 @@ "type": "integer" } }, + { + "description": "Page Size\n\nThis is the number of items per page to return. For details on pagination please head over to the\n[pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination).", + "in": "query", + "name": "page_size", + "schema": { + "default": 250, + "format": "int64", + "maximum": 500, + "minimum": 1, + "type": "integer" + } + }, + { + "description": "Next Page Token\n\nThe next page token. For details on pagination please head over to the\n[pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination).", + "in": "query", + "name": "page_token", + "schema": { + "default": "1", + "minimum": 1, + "type": "string" + } + }, { "description": "CredentialsIdentifier is the identifier (username, email) of the credentials to look up.", "in": "query", @@ -4025,7 +4027,7 @@ "operationId": "listIdentitySessions", "parameters": [ { - "description": "Items per Page\n\nThis is the number of items per page.", + "description": "Deprecated Items per Page\n\nDEPRECATED: Please use `page_token` instead. This parameter will be removed in the future.\n\nThis is the number of items per page.", "in": "query", "name": "per_page", "schema": { @@ -4037,7 +4039,7 @@ } }, { - "description": "Pagination Page\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.\nThe first page can be retrieved by omitting this parameter. Following page pointers will be returned in the\n`Link` header.", + "description": "Deprecated Pagination Page\n\nDEPRECATED: Please use `page_token` instead. This parameter will be removed in the future.\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.\nThe first page can be retrieved by omitting this parameter. Following page pointers will be returned in the\n`Link` header.", "in": "query", "name": "page", "schema": { @@ -4045,6 +4047,28 @@ "type": "integer" } }, + { + "description": "Page Size\n\nThis is the number of items per page to return. For details on pagination please head over to the\n[pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination).", + "in": "query", + "name": "page_size", + "schema": { + "default": 250, + "format": "int64", + "maximum": 500, + "minimum": 1, + "type": "integer" + } + }, + { + "description": "Next Page Token\n\nThe next page token. For details on pagination please head over to the\n[pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination).", + "in": "query", + "name": "page_token", + "schema": { + "default": "1", + "minimum": 1, + "type": "string" + } + }, { "description": "ID is the identity's ID.", "in": "path", @@ -4638,7 +4662,7 @@ "operationId": "listIdentitySchemas", "parameters": [ { - "description": "Items per Page\n\nThis is the number of items per page.", + "description": "Deprecated Items per Page\n\nDEPRECATED: Please use `page_token` instead. This parameter will be removed in the future.\n\nThis is the number of items per page.", "in": "query", "name": "per_page", "schema": { @@ -4650,13 +4674,35 @@ } }, { - "description": "Pagination Page\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.\nThe first page can be retrieved by omitting this parameter. Following page pointers will be returned in the\n`Link` header.", + "description": "Deprecated Pagination Page\n\nDEPRECATED: Please use `page_token` instead. This parameter will be removed in the future.\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.\nThe first page can be retrieved by omitting this parameter. Following page pointers will be returned in the\n`Link` header.", "in": "query", "name": "page", "schema": { "format": "int64", "type": "integer" } + }, + { + "description": "Page Size\n\nThis is the number of items per page to return. For details on pagination please head over to the\n[pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination).", + "in": "query", + "name": "page_size", + "schema": { + "default": 250, + "format": "int64", + "maximum": 500, + "minimum": 1, + "type": "integer" + } + }, + { + "description": "Next Page Token\n\nThe next page token. For details on pagination please head over to the\n[pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination).", + "in": "query", + "name": "page_token", + "schema": { + "default": "1", + "minimum": 1, + "type": "string" + } } ], "responses": { @@ -6601,7 +6647,7 @@ "operationId": "listMySessions", "parameters": [ { - "description": "Items per Page\n\nThis is the number of items per page.", + "description": "Deprecated Items per Page\n\nDEPRECATED: Please use `page_token` instead. This parameter will be removed in the future.\n\nThis is the number of items per page.", "in": "query", "name": "per_page", "schema": { @@ -6613,16 +6659,36 @@ } }, { - "description": "Pagination Page\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.", + "description": "Deprecated Pagination Page\n\nDEPRECATED: Please use `page_token` instead. This parameter will be removed in the future.\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.\nThe first page can be retrieved by omitting this parameter. Following page pointers will be returned in the\n`Link` header.", "in": "query", "name": "page", "schema": { - "default": 1, "format": "int64", + "type": "integer" + } + }, + { + "description": "Page Size\n\nThis is the number of items per page to return. For details on pagination please head over to the\n[pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination).", + "in": "query", + "name": "page_size", + "schema": { + "default": 250, + "format": "int64", + "maximum": 500, "minimum": 1, "type": "integer" } }, + { + "description": "Next Page Token\n\nThe next page token. For details on pagination please head over to the\n[pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination).", + "in": "query", + "name": "page_token", + "schema": { + "default": "1", + "minimum": 1, + "type": "string" + } + }, { "description": "Set the Session Token when calling from non-browser clients. A session token has a format of `MP2YWEMeM8MxjkGKpH4dqOQ4Q4DlSPaj`.", "in": "header", diff --git a/spec/swagger.json b/spec/swagger.json index e2817e8a5af2..a364c11770c2 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -191,17 +191,35 @@ "type": "integer", "format": "int64", "default": 250, - "description": "Items per Page\n\nThis is the number of items per page.", + "description": "Deprecated Items per Page\n\nDEPRECATED: Please use `page_token` instead. This parameter will be removed in the future.\n\nThis is the number of items per page.", "name": "per_page", "in": "query" }, { "type": "integer", "format": "int64", - "description": "Pagination Page\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.\nThe first page can be retrieved by omitting this parameter. Following page pointers will be returned in the\n`Link` header.", + "description": "Deprecated Pagination Page\n\nDEPRECATED: Please use `page_token` instead. This parameter will be removed in the future.\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.\nThe first page can be retrieved by omitting this parameter. Following page pointers will be returned in the\n`Link` header.", "name": "page", "in": "query" }, + { + "maximum": 500, + "minimum": 1, + "type": "integer", + "format": "int64", + "default": 250, + "description": "Page Size\n\nThis is the number of items per page to return. For details on pagination please head over to the\n[pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination).", + "name": "page_size", + "in": "query" + }, + { + "minimum": 1, + "type": "string", + "default": "1", + "description": "Next Page Token\n\nThe next page token. For details on pagination please head over to the\n[pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination).", + "name": "page_token", + "in": "query" + }, { "type": "string", "description": "CredentialsIdentifier is the identifier (username, email) of the credentials to look up.", @@ -676,17 +694,35 @@ "type": "integer", "format": "int64", "default": 250, - "description": "Items per Page\n\nThis is the number of items per page.", + "description": "Deprecated Items per Page\n\nDEPRECATED: Please use `page_token` instead. This parameter will be removed in the future.\n\nThis is the number of items per page.", "name": "per_page", "in": "query" }, { "type": "integer", "format": "int64", - "description": "Pagination Page\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.\nThe first page can be retrieved by omitting this parameter. Following page pointers will be returned in the\n`Link` header.", + "description": "Deprecated Pagination Page\n\nDEPRECATED: Please use `page_token` instead. This parameter will be removed in the future.\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.\nThe first page can be retrieved by omitting this parameter. Following page pointers will be returned in the\n`Link` header.", "name": "page", "in": "query" }, + { + "maximum": 500, + "minimum": 1, + "type": "integer", + "format": "int64", + "default": 250, + "description": "Page Size\n\nThis is the number of items per page to return. For details on pagination please head over to the\n[pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination).", + "name": "page_size", + "in": "query" + }, + { + "minimum": 1, + "type": "string", + "default": "1", + "description": "Next Page Token\n\nThe next page token. For details on pagination please head over to the\n[pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination).", + "name": "page_token", + "in": "query" + }, { "type": "string", "description": "ID is the identity's ID.", @@ -1222,16 +1258,34 @@ "type": "integer", "format": "int64", "default": 250, - "description": "Items per Page\n\nThis is the number of items per page.", + "description": "Deprecated Items per Page\n\nDEPRECATED: Please use `page_token` instead. This parameter will be removed in the future.\n\nThis is the number of items per page.", "name": "per_page", "in": "query" }, { "type": "integer", "format": "int64", - "description": "Pagination Page\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.\nThe first page can be retrieved by omitting this parameter. Following page pointers will be returned in the\n`Link` header.", + "description": "Deprecated Pagination Page\n\nDEPRECATED: Please use `page_token` instead. This parameter will be removed in the future.\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.\nThe first page can be retrieved by omitting this parameter. Following page pointers will be returned in the\n`Link` header.", "name": "page", "in": "query" + }, + { + "maximum": 500, + "minimum": 1, + "type": "integer", + "format": "int64", + "default": 250, + "description": "Page Size\n\nThis is the number of items per page to return. For details on pagination please head over to the\n[pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination).", + "name": "page_size", + "in": "query" + }, + { + "minimum": 1, + "type": "string", + "default": "1", + "description": "Next Page Token\n\nThe next page token. For details on pagination please head over to the\n[pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination).", + "name": "page_token", + "in": "query" } ], "responses": { @@ -2771,19 +2825,35 @@ "type": "integer", "format": "int64", "default": 250, - "description": "Items per Page\n\nThis is the number of items per page.", + "description": "Deprecated Items per Page\n\nDEPRECATED: Please use `page_token` instead. This parameter will be removed in the future.\n\nThis is the number of items per page.", "name": "per_page", "in": "query" }, { - "minimum": 1, "type": "integer", "format": "int64", - "default": 1, - "description": "Pagination Page\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.", + "description": "Deprecated Pagination Page\n\nDEPRECATED: Please use `page_token` instead. This parameter will be removed in the future.\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.\nThe first page can be retrieved by omitting this parameter. Following page pointers will be returned in the\n`Link` header.", "name": "page", "in": "query" }, + { + "maximum": 500, + "minimum": 1, + "type": "integer", + "format": "int64", + "default": 250, + "description": "Page Size\n\nThis is the number of items per page to return. For details on pagination please head over to the\n[pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination).", + "name": "page_size", + "in": "query" + }, + { + "minimum": 1, + "type": "string", + "default": "1", + "description": "Next Page Token\n\nThe next page token. For details on pagination please head over to the\n[pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination).", + "name": "page_token", + "in": "query" + }, { "type": "string", "description": "Set the Session Token when calling from non-browser clients. A session token has a format of `MP2YWEMeM8MxjkGKpH4dqOQ4Q4DlSPaj`.", @@ -4364,26 +4434,6 @@ "format": "date-time", "title": "NullTime implements sql.NullTime functionality." }, - "pagination": { - "type": "object", - "properties": { - "page": { - "description": "Pagination Page\n\nThis value is currently an integer, but it is not sequential. The value is not the page number, but a\nreference. The next page can be any number and some numbers might return an empty list.\n\nFor example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist.", - "type": "integer", - "format": "int64", - "default": 1, - "minimum": 1 - }, - "per_page": { - "description": "Items per Page\n\nThis is the number of items per page.", - "type": "integer", - "format": "int64", - "default": 250, - "maximum": 1000, - "minimum": 1 - } - } - }, "patchIdentitiesBody": { "description": "Patch Identities Body", "type": "object", diff --git a/x/pagination.go b/x/pagination.go index a37a00bca321..c19ed06450e0 100644 --- a/x/pagination.go +++ b/x/pagination.go @@ -8,42 +8,13 @@ import ( "net/url" "github.com/ory/x/pagination/migrationpagination" - - "github.com/ory/x/pagination/pagepagination" ) -// swagger:model pagination -type PaginationParams struct { - // Items per Page - // - // This is the number of items per page. - // - // required: false - // in: query - // default: 250 - // min: 1 - // max: 1000 - PerPage int `json:"per_page"` - - // Pagination Page - // - // This value is currently an integer, but it is not sequential. The value is not the page number, but a - // reference. The next page can be any number and some numbers might return an empty list. - // - // For example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist. - // - // required: false - // in: query - // default: 1 - // min: 1 - Page int `json:"page"` -} - // ParsePagination parses limit and page from *http.Request with given limits and defaults. func ParsePagination(r *http.Request) (page, itemsPerPage int) { return migrationpagination.NewDefaultPaginator().ParsePagination(r) } func PaginationHeader(w http.ResponseWriter, u *url.URL, total int64, page, itemsPerPage int) { - pagepagination.PaginationHeader(w, u, total, page, itemsPerPage) + migrationpagination.PaginationHeader(w, u, total, page, itemsPerPage) } From aa0c36c97b4b5d18e5bd8eb469b946504149a22a Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Fri, 8 Sep 2023 09:28:18 +0000 Subject: [PATCH 077/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 102 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 80 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a04142814433..c5ce772a852a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,11 +5,12 @@ **Table of Contents** -- [ (2023-08-31)](#2023-08-31) - - [Bug Fixes](#bug-fixes) - - [Documentation](#documentation) - - [Features](#features) - - [Tests](#tests) +- [ (2023-09-08)](#2023-09-08) + - [Breaking Changes](#breaking-changes) + - [Bug Fixes](#bug-fixes) + - [Documentation](#documentation) + - [Features](#features) + - [Tests](#tests) - [1.0.0 (2023-07-12)](#100-2023-07-12) - [Bug Fixes](#bug-fixes-1) - [Code Generation](#code-generation) @@ -18,7 +19,7 @@ - [Tests](#tests-1) - [Unclassified](#unclassified) - [0.13.0 (2023-04-18)](#0130-2023-04-18) - - [Breaking Changes](#breaking-changes) + - [Breaking Changes](#breaking-changes-1) - [Bug Fixes](#bug-fixes-2) - [Code Generation](#code-generation-1) - [Code Refactoring](#code-refactoring) @@ -27,14 +28,14 @@ - [Tests](#tests-2) - [Unclassified](#unclassified-1) - [0.11.1 (2023-01-14)](#0111-2023-01-14) - - [Breaking Changes](#breaking-changes-1) + - [Breaking Changes](#breaking-changes-2) - [Bug Fixes](#bug-fixes-3) - [Code Generation](#code-generation-2) - [Documentation](#documentation-3) - [Features](#features-3) - [Tests](#tests-3) - [0.11.0 (2022-12-02)](#0110-2022-12-02) - - [Breaking Changes](#breaking-changes-2) + - [Breaking Changes](#breaking-changes-3) - [Bug Fixes](#bug-fixes-4) - [Code Generation](#code-generation-3) - [Code Refactoring](#code-refactoring-1) @@ -47,7 +48,7 @@ - [Bug Fixes](#bug-fixes-5) - [Code Generation](#code-generation-4) - [0.10.0 (2022-05-30)](#0100-2022-05-30) - - [Breaking Changes](#breaking-changes-3) + - [Breaking Changes](#breaking-changes-4) - [Bug Fixes](#bug-fixes-6) - [Code Generation](#code-generation-5) - [Code Refactoring](#code-refactoring-2) @@ -56,7 +57,7 @@ - [Tests](#tests-5) - [Unclassified](#unclassified-3) - [0.9.0-alpha.3 (2022-03-25)](#090-alpha3-2022-03-25) - - [Breaking Changes](#breaking-changes-4) + - [Breaking Changes](#breaking-changes-5) - [Bug Fixes](#bug-fixes-7) - [Code Generation](#code-generation-6) - [Documentation](#documentation-6) @@ -64,7 +65,7 @@ - [Bug Fixes](#bug-fixes-8) - [Code Generation](#code-generation-7) - [0.9.0-alpha.1 (2022-03-21)](#090-alpha1-2022-03-21) - - [Breaking Changes](#breaking-changes-5) + - [Breaking Changes](#breaking-changes-6) - [Bug Fixes](#bug-fixes-9) - [Code Generation](#code-generation-8) - [Code Refactoring](#code-refactoring-3) @@ -73,7 +74,7 @@ - [Tests](#tests-6) - [Unclassified](#unclassified-4) - [0.8.3-alpha.1.pre.0 (2022-01-21)](#083-alpha1pre0-2022-01-21) - - [Breaking Changes](#breaking-changes-6) + - [Breaking Changes](#breaking-changes-7) - [Bug Fixes](#bug-fixes-10) - [Code Generation](#code-generation-9) - [Code Refactoring](#code-refactoring-4) @@ -91,7 +92,7 @@ - [Features](#features-8) - [Tests](#tests-8) - [0.8.0-alpha.4.pre.0 (2021-11-09)](#080-alpha4pre0-2021-11-09) - - [Breaking Changes](#breaking-changes-7) + - [Breaking Changes](#breaking-changes-8) - [Bug Fixes](#bug-fixes-13) - [Code Generation](#code-generation-12) - [Documentation](#documentation-11) @@ -103,7 +104,7 @@ - [0.8.0-alpha.2 (2021-10-28)](#080-alpha2-2021-10-28) - [Code Generation](#code-generation-14) - [0.8.0-alpha.1 (2021-10-27)](#080-alpha1-2021-10-27) - - [Breaking Changes](#breaking-changes-8) + - [Breaking Changes](#breaking-changes-9) - [Bug Fixes](#bug-fixes-15) - [Code Generation](#code-generation-15) - [Code Refactoring](#code-refactoring-5) @@ -133,7 +134,7 @@ - [Documentation](#documentation-15) - [Tests](#tests-12) - [0.7.0-alpha.1 (2021-07-13)](#070-alpha1-2021-07-13) - - [Breaking Changes](#breaking-changes-9) + - [Breaking Changes](#breaking-changes-10) - [Bug Fixes](#bug-fixes-19) - [Code Generation](#code-generation-21) - [Code Refactoring](#code-refactoring-6) @@ -142,7 +143,7 @@ - [Tests](#tests-13) - [Unclassified](#unclassified-6) - [0.6.3-alpha.1 (2021-05-17)](#063-alpha1-2021-05-17) - - [Breaking Changes](#breaking-changes-10) + - [Breaking Changes](#breaking-changes-11) - [Bug Fixes](#bug-fixes-20) - [Code Generation](#code-generation-22) - [Code Refactoring](#code-refactoring-7) @@ -157,7 +158,7 @@ - [Code Generation](#code-generation-25) - [Features](#features-15) - [0.6.0-alpha.1 (2021-05-05)](#060-alpha1-2021-05-05) - - [Breaking Changes](#breaking-changes-11) + - [Breaking Changes](#breaking-changes-12) - [Bug Fixes](#bug-fixes-22) - [Code Generation](#code-generation-26) - [Code Refactoring](#code-refactoring-8) @@ -197,7 +198,7 @@ - [Tests](#tests-18) - [Unclassified](#unclassified-9) - [0.5.0-alpha.1 (2020-10-15)](#050-alpha1-2020-10-15) - - [Breaking Changes](#breaking-changes-12) + - [Breaking Changes](#breaking-changes-13) - [Bug Fixes](#bug-fixes-28) - [Code Generation](#code-generation-32) - [Code Refactoring](#code-refactoring-10) @@ -222,7 +223,7 @@ - [Bug Fixes](#bug-fixes-33) - [Code Generation](#code-generation-37) - [0.4.0-alpha.1 (2020-07-08)](#040-alpha1-2020-07-08) - - [Breaking Changes](#breaking-changes-13) + - [Breaking Changes](#breaking-changes-14) - [Bug Fixes](#bug-fixes-34) - [Code Generation](#code-generation-38) - [Code Refactoring](#code-refactoring-11) @@ -230,7 +231,7 @@ - [Features](#features-22) - [Unclassified](#unclassified-11) - [0.3.0-alpha.1 (2020-05-15)](#030-alpha1-2020-05-15) - - [Breaking Changes](#breaking-changes-14) + - [Breaking Changes](#breaking-changes-15) - [Bug Fixes](#bug-fixes-35) - [Chores](#chores) - [Code Refactoring](#code-refactoring-12) @@ -241,7 +242,7 @@ - [Chores](#chores-1) - [Documentation](#documentation-28) - [0.2.0-alpha.2 (2020-05-04)](#020-alpha2-2020-05-04) - - [Breaking Changes](#breaking-changes-15) + - [Breaking Changes](#breaking-changes-16) - [Bug Fixes](#bug-fixes-36) - [Chores](#chores-2) - [Code Refactoring](#code-refactoring-13) @@ -309,7 +310,38 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-08-31) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-09-08) + +## Breaking Changes + +Pagination parameters for the `list identities` CLI command have changed from +arguments to flags `--page-token` and `page-size`: + +``` +- kratos list identities 1 100 ++ kratos list identities --page-size 100 --page-token ... +``` + +Furthermore, the JSON / JSON pretty output of `list identities` has changed: + +```patch +-[ +- { "id": "..." }, +- { /* ... */ }, +- // ... +-] ++{ ++ "identities": [ ++ {"id": "..."}, ++ { /* ... */ }, ++ // ... ++ ], ++ "next_page_token": "..." ++} +``` + +Closes https://github.com/ory/sdk/issues/284 Closes +https://github.com/ory/kratos/pull/3480 ### Bug Fixes @@ -338,6 +370,9 @@ Fixes https://github.com/ory/kratos/issues/3321 +- Code method on registration and 2fa + ([#3481](https://github.com/ory/kratos/issues/3481)) + ([7aa2e29](https://github.com/ory/kratos/commit/7aa2e293175d0f4b6c13552cc3781f54f8caf3a0)) - Don't require session for OIDC verification ([#3443](https://github.com/ory/kratos/issues/3443)) ([e08f831](https://github.com/ory/kratos/commit/e08f831c2715e515bf58dc2dbb47fc3576421a5c)) @@ -347,6 +382,16 @@ - False-positives for requiring re-authentication on update ([#3421](https://github.com/ory/kratos/issues/3421)) ([ce8139f](https://github.com/ory/kratos/commit/ce8139f2325a8317388cbcaaa98f3f83d626657b)) +- Identity list pagination in CLI command and SDK + ([#3482](https://github.com/ory/kratos/issues/3482)) + ([1e8b1ae](https://github.com/ory/kratos/commit/1e8b1aeb4bf866892788986f62a31255372de999)): + + Adds correct pagination parameters to the SDK methods for listing identities + and sessions. + +- Issue session after verification after registration with OIDC SSO + ([#3467](https://github.com/ory/kratos/issues/3467)) + ([a28b523](https://github.com/ory/kratos/commit/a28b523238743f3873b51479eea3b86d684092f9)) - Mark identity as optional in session struct ([#3463](https://github.com/ory/kratos/issues/3463)) ([7ae02ba](https://github.com/ory/kratos/commit/7ae02ba697f68c9cfae5fe8f696b2c55a3ba9ddc)), @@ -390,6 +435,9 @@ ([ca34e9b](https://github.com/ory/kratos/commit/ca34e9b744482b41d65082f3bed52e9c4ebd7ba4)) - Type-assert all interfaces that WebHook implements ([ffda1a0](https://github.com/ory/kratos/commit/ffda1a0dab661c5f11ad849b9287094313561b79)) +- Use registry client for schema loading + ([#3471](https://github.com/ory/kratos/issues/3471)) + ([3a57726](https://github.com/ory/kratos/commit/3a577269980213e4415fd5fa713882990e2e7640)) ### Documentation @@ -399,8 +447,15 @@ See https://github.com/ory/kratos/discussions/3388 +- Update link to hashed password formats + ([#3484](https://github.com/ory/kratos/issues/3484)) + ([8ca3adc](https://github.com/ory/kratos/commit/8ca3adcb8a5db2906fbeb92f4b74aa4242fabdef)) + ### Features +- Add GetID member functions to RecoveryAddress and Credentials + ([#3474](https://github.com/ory/kratos/issues/3474)) + ([085d500](https://github.com/ory/kratos/commit/085d5002df27d455057d33bd2d93dfbca0de4872)) - Add OpenTelemetry span for password hash comparison ([#3383](https://github.com/ory/kratos/issues/3383)) ([e3fcf0c](https://github.com/ory/kratos/commit/e3fcf0c31db9742ed61bcf783e37ee119ed19d42)) @@ -526,6 +581,9 @@ - **e2e:** Logout return_to ([#3418](https://github.com/ory/kratos/issues/3418)) ([c348c12](https://github.com/ory/kratos/commit/c348c12ab3c9cdb4ce8159fe774ed179ff6a4d8a)) +- Fix e2e failures and speed up e2e tests + ([#3483](https://github.com/ory/kratos/issues/3483)) + ([70a6171](https://github.com/ory/kratos/commit/70a617194d61763f4b75691b22cfa76ba71ab019)) # [1.0.0](https://github.com/ory/kratos/compare/v0.13.0...v1.0.0) (2023-07-12) From fc303040b71139f512fd1491ce30f80837b940b9 Mon Sep 17 00:00:00 2001 From: Henning Perl Date: Mon, 11 Sep 2023 13:49:41 +0200 Subject: [PATCH 078/282] feat: support auth_type parameter (#3487) The Facebook OIDC provider supports an auth_type parameter that when set to "reauthenticate" will force the user to reauthenticate (similar to `prompt=login` for other Providers). --- selfservice/strategy/oidc/.schema/link.schema.json | 4 ++++ selfservice/strategy/oidc/provider.go | 2 ++ selfservice/strategy/oidc/strategy_test.go | 2 ++ 3 files changed, 8 insertions(+) diff --git a/selfservice/strategy/oidc/.schema/link.schema.json b/selfservice/strategy/oidc/.schema/link.schema.json index f813f76eef1a..c8f82c05c568 100644 --- a/selfservice/strategy/oidc/.schema/link.schema.json +++ b/selfservice/strategy/oidc/.schema/link.schema.json @@ -33,6 +33,10 @@ "description": "The prompt specifies whether the Authorization Server prompts the End-User for reauthentication and consent (for example, select_account).", "type": "string" }, + "auth_type": { + "description": "The `auth_type` parameter specifies the requested authentication features (as a comma-separated list).", + "type": "string" + }, "additionalProperties": false } } diff --git a/selfservice/strategy/oidc/provider.go b/selfservice/strategy/oidc/provider.go index ddef8dc10901..6537abbe4d6d 100644 --- a/selfservice/strategy/oidc/provider.go +++ b/selfservice/strategy/oidc/provider.go @@ -76,6 +76,7 @@ func (c *Claims) Validate() error { // - `login_hint` (string): The `login_hint` parameter suppresses the account chooser and either pre-fills the email box on the sign-in form, or selects the proper session. // - `hd` (string): The `hd` parameter limits the login/registration process to a Google Organization, e.g. `mycollege.edu`. // - `prompt` (string): The `prompt` specifies whether the Authorization Server prompts the End-User for reauthentication and consent, e.g. `select_account`. +// - `auth_type` (string): The `auth_type` parameter specifies the requested authentication features (as a comma-separated list), e.g. `reauthenticate`. func UpstreamParameters(provider Provider, upstreamParameters map[string]string) []oauth2.AuthCodeOption { // validation of upstream parameters are already handled in the `oidc/.schema/link.schema.json` and `oidc/.schema/settings.schema.json` file. // `upstreamParameters` will always only contain allowed parameters based on the configuration. @@ -85,6 +86,7 @@ func UpstreamParameters(provider Provider, upstreamParameters map[string]string) "login_hint": {}, "hd": {}, "prompt": {}, + "auth_type": {}, } var params []oauth2.AuthCodeOption diff --git a/selfservice/strategy/oidc/strategy_test.go b/selfservice/strategy/oidc/strategy_test.go index 0969caa38da5..aaf1f2ba818c 100644 --- a/selfservice/strategy/oidc/strategy_test.go +++ b/selfservice/strategy/oidc/strategy_test.go @@ -730,6 +730,7 @@ func TestStrategy(t *testing.T) { fv.Set("upstream_parameters.login_hint", "oidc-upstream-parameters@ory.sh") fv.Set("upstream_parameters.hd", "ory.sh") fv.Set("upstream_parameters.prompt", "select_account") + fv.Set("upstream_parameters.auth_type", "reauthenticate") res, err := c.PostForm(action, fv) require.NoError(t, err) @@ -741,6 +742,7 @@ func TestStrategy(t *testing.T) { require.Equal(t, "oidc-upstream-parameters@ory.sh", loc.Query().Get("login_hint")) require.Equal(t, "ory.sh", loc.Query().Get("hd")) require.Equal(t, "select_account", loc.Query().Get("prompt")) + require.Equal(t, "reauthenticate", loc.Query().Get("auth_type")) }) t.Run("case=should pass when logging in", func(t *testing.T) { From f561013dd737dadcc82c4ec049fde12861e91e43 Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Tue, 12 Sep 2023 14:47:06 +0200 Subject: [PATCH 079/282] feat: support native social sign using apple sdk (#3476) --- go.mod | 3 + go.sum | 18 ++ ...odel_update_login_flow_with_oidc_method.go | 74 ++++++ ...date_registration_flow_with_oidc_method.go | 74 ++++++ ...odel_update_login_flow_with_oidc_method.go | 74 ++++++ ...date_registration_flow_with_oidc_method.go | 74 ++++++ selfservice/flow/login/flow.go | 6 + selfservice/flow/login/hook.go | 5 +- selfservice/flow/registration/flow.go | 5 + selfservice/flow/registration/hook.go | 5 +- selfservice/hook/session_issuer.go | 4 +- .../strategy/oidc/.schema/link.schema.json | 8 + selfservice/strategy/oidc/provider.go | 10 + selfservice/strategy/oidc/provider_apple.go | 30 ++- .../strategy/oidc/provider_apple_test.go | 105 +++++++++ selfservice/strategy/oidc/provider_auth0.go | 2 +- selfservice/strategy/oidc/provider_config.go | 79 +++---- .../strategy/oidc/provider_dingtalk.go | 2 +- selfservice/strategy/oidc/provider_discord.go | 2 +- .../strategy/oidc/provider_facebook.go | 2 +- .../strategy/oidc/provider_generic_oidc.go | 2 +- selfservice/strategy/oidc/provider_github.go | 2 +- .../strategy/oidc/provider_github_app.go | 2 +- selfservice/strategy/oidc/provider_gitlab.go | 2 +- selfservice/strategy/oidc/provider_google.go | 2 +- selfservice/strategy/oidc/provider_lark.go | 2 +- .../strategy/oidc/provider_linkedin.go | 2 +- .../strategy/oidc/provider_microsoft.go | 2 +- selfservice/strategy/oidc/provider_netid.go | 2 +- selfservice/strategy/oidc/provider_patreon.go | 2 +- selfservice/strategy/oidc/provider_slack.go | 2 +- selfservice/strategy/oidc/provider_spotify.go | 2 +- selfservice/strategy/oidc/provider_test.go | 35 +++ selfservice/strategy/oidc/provider_vk.go | 2 +- selfservice/strategy/oidc/provider_yandex.go | 2 +- selfservice/strategy/oidc/strategy.go | 38 ++- .../strategy/oidc/strategy_helper_test.go | 13 +- selfservice/strategy/oidc/strategy_login.go | 41 +++- .../strategy/oidc/strategy_registration.go | 81 +++++-- selfservice/strategy/oidc/strategy_test.go | 219 ++++++++++++++++++ selfservice/strategy/oidc/stub/jwk.json | 14 ++ .../strategy/oidc/stub/jwks_public.json | 12 + .../strategy/oidc/stub/jwks_public2.json | 12 + spec/api.json | 16 ++ spec/swagger.json | 16 ++ 45 files changed, 1014 insertions(+), 93 deletions(-) create mode 100644 selfservice/strategy/oidc/stub/jwk.json create mode 100644 selfservice/strategy/oidc/stub/jwks_public.json create mode 100644 selfservice/strategy/oidc/stub/jwks_public2.json diff --git a/go.mod b/go.mod index 42dd913f3abb..8d674ff157d0 100644 --- a/go.mod +++ b/go.mod @@ -140,6 +140,7 @@ require ( github.com/fatih/structs v1.1.0 // indirect github.com/felixge/fgprof v0.9.3 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect + github.com/form3tech-oss/jwt-go v3.2.5+incompatible // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fxamacker/cbor/v2 v2.4.0 // indirect github.com/go-crypt/x v0.2.1 // indirect @@ -171,6 +172,7 @@ require ( github.com/goccy/go-yaml v1.9.6 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/golang/glog v1.1.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/btree v1.0.1 // indirect @@ -260,6 +262,7 @@ require ( github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect + github.com/rakutentech/jwk-go v1.1.3 // indirect github.com/rjeczalik/notify v0.0.0-20181126183243-629144ba06a1 // indirect github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/seatgeek/logrus-gelf-formatter v0.0.0-20210414080842-5b05eb8ff761 // indirect diff --git a/go.sum b/go.sum index 60ddbe374068..87fe4c8ce7b9 100644 --- a/go.sum +++ b/go.sum @@ -200,8 +200,11 @@ github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNu github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/form3tech-oss/jwt-go v3.2.5+incompatible h1:/l4kBbb4/vGSsdtB5nUe8L7B9mImVMaBPw9L/0TBHU8= +github.com/form3tech-oss/jwt-go v3.2.5+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88= @@ -357,6 +360,8 @@ github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRx github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/gddo v0.0.0-20190904175337-72a348e765d2 h1:xisWqjiKEff2B0KfFYGpCqc3M3zdTz+OHQHRc09FeYk= @@ -525,6 +530,7 @@ github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= @@ -784,6 +790,10 @@ github.com/ogier/pflag v0.0.1 h1:RW6JSWSu/RkSatfcLtogGfFgpim5p7ARQ10ECk5O750= github.com/ogier/pflag v0.0.1/go.mod h1:zkFki7tvTa0tafRvTBIZTvzYyAu6kQhPZFnshFFPE+g= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= @@ -879,6 +889,8 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/rakutentech/jwk-go v1.1.3 h1:PiLwepKyUaW+QFG3ki78DIO2+b4IVK3nMhlxM70zrQ4= +github.com/rakutentech/jwk-go v1.1.3/go.mod h1:LtzSv4/+Iti1nnNeVQiP6l5cI74GBStbhyXCYvgPZFk= github.com/rjeczalik/notify v0.0.0-20181126183243-629144ba06a1 h1:FLWDC+iIP9BWgYKvWKKtOUZux35LIQNAuIzp/63RQJU= github.com/rjeczalik/notify v0.0.0-20181126183243-629144ba06a1/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= @@ -1101,6 +1113,7 @@ golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= @@ -1158,6 +1171,7 @@ golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1242,6 +1256,7 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1265,6 +1280,7 @@ golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1549,6 +1565,7 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 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/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/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= @@ -1561,6 +1578,7 @@ gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 h1:6D+BvnJ/j6e222UW gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473/go.mod h1:N1eN2tsCx0Ydtgjl4cqmbRCsY4/+z4cYDeqwZTk6zog= gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= gopkg.in/square/go-jose.v2 v2.6.0/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.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/internal/client-go/model_update_login_flow_with_oidc_method.go b/internal/client-go/model_update_login_flow_with_oidc_method.go index f11ccd730c61..c196eb2121da 100644 --- a/internal/client-go/model_update_login_flow_with_oidc_method.go +++ b/internal/client-go/model_update_login_flow_with_oidc_method.go @@ -19,6 +19,10 @@ import ( type UpdateLoginFlowWithOidcMethod struct { // The CSRF Token CsrfToken *string `json:"csrf_token,omitempty"` + // IDToken is an optional id token provided by an OIDC provider If submitted, it is verified using the OIDC provider's public key set and the claims are used to populate the OIDC credentials of the identity. If the OIDC provider does not store additional claims (such as name, etc.) in the IDToken itself, you can use the `traits` field to populate the identity's traits. Note, that Apple only includes the users email in the IDToken. Supported providers are Apple + IdToken *string `json:"id_token,omitempty"` + // IDTokenNonce is the nonce, used when generating the IDToken. If the provider supports nonce validation, the nonce will be validated against this value and required. + IdTokenNonce *string `json:"id_token_nonce,omitempty"` // Method to use This field must be set to `oidc` when using the oidc method. Method string `json:"method"` // The provider to register with @@ -80,6 +84,70 @@ func (o *UpdateLoginFlowWithOidcMethod) SetCsrfToken(v string) { o.CsrfToken = &v } +// GetIdToken returns the IdToken field value if set, zero value otherwise. +func (o *UpdateLoginFlowWithOidcMethod) GetIdToken() string { + if o == nil || o.IdToken == nil { + var ret string + return ret + } + return *o.IdToken +} + +// GetIdTokenOk returns a tuple with the IdToken field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UpdateLoginFlowWithOidcMethod) GetIdTokenOk() (*string, bool) { + if o == nil || o.IdToken == nil { + return nil, false + } + return o.IdToken, true +} + +// HasIdToken returns a boolean if a field has been set. +func (o *UpdateLoginFlowWithOidcMethod) HasIdToken() bool { + if o != nil && o.IdToken != nil { + return true + } + + return false +} + +// SetIdToken gets a reference to the given string and assigns it to the IdToken field. +func (o *UpdateLoginFlowWithOidcMethod) SetIdToken(v string) { + o.IdToken = &v +} + +// GetIdTokenNonce returns the IdTokenNonce field value if set, zero value otherwise. +func (o *UpdateLoginFlowWithOidcMethod) GetIdTokenNonce() string { + if o == nil || o.IdTokenNonce == nil { + var ret string + return ret + } + return *o.IdTokenNonce +} + +// GetIdTokenNonceOk returns a tuple with the IdTokenNonce field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UpdateLoginFlowWithOidcMethod) GetIdTokenNonceOk() (*string, bool) { + if o == nil || o.IdTokenNonce == nil { + return nil, false + } + return o.IdTokenNonce, true +} + +// HasIdTokenNonce returns a boolean if a field has been set. +func (o *UpdateLoginFlowWithOidcMethod) HasIdTokenNonce() bool { + if o != nil && o.IdTokenNonce != nil { + return true + } + + return false +} + +// SetIdTokenNonce gets a reference to the given string and assigns it to the IdTokenNonce field. +func (o *UpdateLoginFlowWithOidcMethod) SetIdTokenNonce(v string) { + o.IdTokenNonce = &v +} + // GetMethod returns the Method field value func (o *UpdateLoginFlowWithOidcMethod) GetMethod() string { if o == nil { @@ -197,6 +265,12 @@ func (o UpdateLoginFlowWithOidcMethod) MarshalJSON() ([]byte, error) { if o.CsrfToken != nil { toSerialize["csrf_token"] = o.CsrfToken } + if o.IdToken != nil { + toSerialize["id_token"] = o.IdToken + } + if o.IdTokenNonce != nil { + toSerialize["id_token_nonce"] = o.IdTokenNonce + } if true { toSerialize["method"] = o.Method } diff --git a/internal/client-go/model_update_registration_flow_with_oidc_method.go b/internal/client-go/model_update_registration_flow_with_oidc_method.go index 8f7d7a190b88..509e978a0627 100644 --- a/internal/client-go/model_update_registration_flow_with_oidc_method.go +++ b/internal/client-go/model_update_registration_flow_with_oidc_method.go @@ -19,6 +19,10 @@ import ( type UpdateRegistrationFlowWithOidcMethod struct { // The CSRF Token CsrfToken *string `json:"csrf_token,omitempty"` + // IDToken is an optional id token provided by an OIDC provider If submitted, it is verified using the OIDC provider's public key set and the claims are used to populate the OIDC credentials of the identity. If the OIDC provider does not store additional claims (such as name, etc.) in the IDToken itself, you can use the `traits` field to populate the identity's traits. Note, that Apple only includes the users email in the IDToken. Supported providers are Apple + IdToken *string `json:"id_token,omitempty"` + // IDTokenNonce is the nonce, used when generating the IDToken. If the provider supports nonce validation, the nonce will be validated against this value and is required. + IdTokenNonce *string `json:"id_token_nonce,omitempty"` // Method to use This field must be set to `oidc` when using the oidc method. Method string `json:"method"` // The provider to register with @@ -82,6 +86,70 @@ func (o *UpdateRegistrationFlowWithOidcMethod) SetCsrfToken(v string) { o.CsrfToken = &v } +// GetIdToken returns the IdToken field value if set, zero value otherwise. +func (o *UpdateRegistrationFlowWithOidcMethod) GetIdToken() string { + if o == nil || o.IdToken == nil { + var ret string + return ret + } + return *o.IdToken +} + +// GetIdTokenOk returns a tuple with the IdToken field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UpdateRegistrationFlowWithOidcMethod) GetIdTokenOk() (*string, bool) { + if o == nil || o.IdToken == nil { + return nil, false + } + return o.IdToken, true +} + +// HasIdToken returns a boolean if a field has been set. +func (o *UpdateRegistrationFlowWithOidcMethod) HasIdToken() bool { + if o != nil && o.IdToken != nil { + return true + } + + return false +} + +// SetIdToken gets a reference to the given string and assigns it to the IdToken field. +func (o *UpdateRegistrationFlowWithOidcMethod) SetIdToken(v string) { + o.IdToken = &v +} + +// GetIdTokenNonce returns the IdTokenNonce field value if set, zero value otherwise. +func (o *UpdateRegistrationFlowWithOidcMethod) GetIdTokenNonce() string { + if o == nil || o.IdTokenNonce == nil { + var ret string + return ret + } + return *o.IdTokenNonce +} + +// GetIdTokenNonceOk returns a tuple with the IdTokenNonce field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UpdateRegistrationFlowWithOidcMethod) GetIdTokenNonceOk() (*string, bool) { + if o == nil || o.IdTokenNonce == nil { + return nil, false + } + return o.IdTokenNonce, true +} + +// HasIdTokenNonce returns a boolean if a field has been set. +func (o *UpdateRegistrationFlowWithOidcMethod) HasIdTokenNonce() bool { + if o != nil && o.IdTokenNonce != nil { + return true + } + + return false +} + +// SetIdTokenNonce gets a reference to the given string and assigns it to the IdTokenNonce field. +func (o *UpdateRegistrationFlowWithOidcMethod) SetIdTokenNonce(v string) { + o.IdTokenNonce = &v +} + // GetMethod returns the Method field value func (o *UpdateRegistrationFlowWithOidcMethod) GetMethod() string { if o == nil { @@ -231,6 +299,12 @@ func (o UpdateRegistrationFlowWithOidcMethod) MarshalJSON() ([]byte, error) { if o.CsrfToken != nil { toSerialize["csrf_token"] = o.CsrfToken } + if o.IdToken != nil { + toSerialize["id_token"] = o.IdToken + } + if o.IdTokenNonce != nil { + toSerialize["id_token_nonce"] = o.IdTokenNonce + } if true { toSerialize["method"] = o.Method } diff --git a/internal/httpclient/model_update_login_flow_with_oidc_method.go b/internal/httpclient/model_update_login_flow_with_oidc_method.go index f11ccd730c61..c196eb2121da 100644 --- a/internal/httpclient/model_update_login_flow_with_oidc_method.go +++ b/internal/httpclient/model_update_login_flow_with_oidc_method.go @@ -19,6 +19,10 @@ import ( type UpdateLoginFlowWithOidcMethod struct { // The CSRF Token CsrfToken *string `json:"csrf_token,omitempty"` + // IDToken is an optional id token provided by an OIDC provider If submitted, it is verified using the OIDC provider's public key set and the claims are used to populate the OIDC credentials of the identity. If the OIDC provider does not store additional claims (such as name, etc.) in the IDToken itself, you can use the `traits` field to populate the identity's traits. Note, that Apple only includes the users email in the IDToken. Supported providers are Apple + IdToken *string `json:"id_token,omitempty"` + // IDTokenNonce is the nonce, used when generating the IDToken. If the provider supports nonce validation, the nonce will be validated against this value and required. + IdTokenNonce *string `json:"id_token_nonce,omitempty"` // Method to use This field must be set to `oidc` when using the oidc method. Method string `json:"method"` // The provider to register with @@ -80,6 +84,70 @@ func (o *UpdateLoginFlowWithOidcMethod) SetCsrfToken(v string) { o.CsrfToken = &v } +// GetIdToken returns the IdToken field value if set, zero value otherwise. +func (o *UpdateLoginFlowWithOidcMethod) GetIdToken() string { + if o == nil || o.IdToken == nil { + var ret string + return ret + } + return *o.IdToken +} + +// GetIdTokenOk returns a tuple with the IdToken field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UpdateLoginFlowWithOidcMethod) GetIdTokenOk() (*string, bool) { + if o == nil || o.IdToken == nil { + return nil, false + } + return o.IdToken, true +} + +// HasIdToken returns a boolean if a field has been set. +func (o *UpdateLoginFlowWithOidcMethod) HasIdToken() bool { + if o != nil && o.IdToken != nil { + return true + } + + return false +} + +// SetIdToken gets a reference to the given string and assigns it to the IdToken field. +func (o *UpdateLoginFlowWithOidcMethod) SetIdToken(v string) { + o.IdToken = &v +} + +// GetIdTokenNonce returns the IdTokenNonce field value if set, zero value otherwise. +func (o *UpdateLoginFlowWithOidcMethod) GetIdTokenNonce() string { + if o == nil || o.IdTokenNonce == nil { + var ret string + return ret + } + return *o.IdTokenNonce +} + +// GetIdTokenNonceOk returns a tuple with the IdTokenNonce field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UpdateLoginFlowWithOidcMethod) GetIdTokenNonceOk() (*string, bool) { + if o == nil || o.IdTokenNonce == nil { + return nil, false + } + return o.IdTokenNonce, true +} + +// HasIdTokenNonce returns a boolean if a field has been set. +func (o *UpdateLoginFlowWithOidcMethod) HasIdTokenNonce() bool { + if o != nil && o.IdTokenNonce != nil { + return true + } + + return false +} + +// SetIdTokenNonce gets a reference to the given string and assigns it to the IdTokenNonce field. +func (o *UpdateLoginFlowWithOidcMethod) SetIdTokenNonce(v string) { + o.IdTokenNonce = &v +} + // GetMethod returns the Method field value func (o *UpdateLoginFlowWithOidcMethod) GetMethod() string { if o == nil { @@ -197,6 +265,12 @@ func (o UpdateLoginFlowWithOidcMethod) MarshalJSON() ([]byte, error) { if o.CsrfToken != nil { toSerialize["csrf_token"] = o.CsrfToken } + if o.IdToken != nil { + toSerialize["id_token"] = o.IdToken + } + if o.IdTokenNonce != nil { + toSerialize["id_token_nonce"] = o.IdTokenNonce + } if true { toSerialize["method"] = o.Method } diff --git a/internal/httpclient/model_update_registration_flow_with_oidc_method.go b/internal/httpclient/model_update_registration_flow_with_oidc_method.go index 8f7d7a190b88..509e978a0627 100644 --- a/internal/httpclient/model_update_registration_flow_with_oidc_method.go +++ b/internal/httpclient/model_update_registration_flow_with_oidc_method.go @@ -19,6 +19,10 @@ import ( type UpdateRegistrationFlowWithOidcMethod struct { // The CSRF Token CsrfToken *string `json:"csrf_token,omitempty"` + // IDToken is an optional id token provided by an OIDC provider If submitted, it is verified using the OIDC provider's public key set and the claims are used to populate the OIDC credentials of the identity. If the OIDC provider does not store additional claims (such as name, etc.) in the IDToken itself, you can use the `traits` field to populate the identity's traits. Note, that Apple only includes the users email in the IDToken. Supported providers are Apple + IdToken *string `json:"id_token,omitempty"` + // IDTokenNonce is the nonce, used when generating the IDToken. If the provider supports nonce validation, the nonce will be validated against this value and is required. + IdTokenNonce *string `json:"id_token_nonce,omitempty"` // Method to use This field must be set to `oidc` when using the oidc method. Method string `json:"method"` // The provider to register with @@ -82,6 +86,70 @@ func (o *UpdateRegistrationFlowWithOidcMethod) SetCsrfToken(v string) { o.CsrfToken = &v } +// GetIdToken returns the IdToken field value if set, zero value otherwise. +func (o *UpdateRegistrationFlowWithOidcMethod) GetIdToken() string { + if o == nil || o.IdToken == nil { + var ret string + return ret + } + return *o.IdToken +} + +// GetIdTokenOk returns a tuple with the IdToken field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UpdateRegistrationFlowWithOidcMethod) GetIdTokenOk() (*string, bool) { + if o == nil || o.IdToken == nil { + return nil, false + } + return o.IdToken, true +} + +// HasIdToken returns a boolean if a field has been set. +func (o *UpdateRegistrationFlowWithOidcMethod) HasIdToken() bool { + if o != nil && o.IdToken != nil { + return true + } + + return false +} + +// SetIdToken gets a reference to the given string and assigns it to the IdToken field. +func (o *UpdateRegistrationFlowWithOidcMethod) SetIdToken(v string) { + o.IdToken = &v +} + +// GetIdTokenNonce returns the IdTokenNonce field value if set, zero value otherwise. +func (o *UpdateRegistrationFlowWithOidcMethod) GetIdTokenNonce() string { + if o == nil || o.IdTokenNonce == nil { + var ret string + return ret + } + return *o.IdTokenNonce +} + +// GetIdTokenNonceOk returns a tuple with the IdTokenNonce field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UpdateRegistrationFlowWithOidcMethod) GetIdTokenNonceOk() (*string, bool) { + if o == nil || o.IdTokenNonce == nil { + return nil, false + } + return o.IdTokenNonce, true +} + +// HasIdTokenNonce returns a boolean if a field has been set. +func (o *UpdateRegistrationFlowWithOidcMethod) HasIdTokenNonce() bool { + if o != nil && o.IdTokenNonce != nil { + return true + } + + return false +} + +// SetIdTokenNonce gets a reference to the given string and assigns it to the IdTokenNonce field. +func (o *UpdateRegistrationFlowWithOidcMethod) SetIdTokenNonce(v string) { + o.IdTokenNonce = &v +} + // GetMethod returns the Method field value func (o *UpdateRegistrationFlowWithOidcMethod) GetMethod() string { if o == nil { @@ -231,6 +299,12 @@ func (o UpdateRegistrationFlowWithOidcMethod) MarshalJSON() ([]byte, error) { if o.CsrfToken != nil { toSerialize["csrf_token"] = o.CsrfToken } + if o.IdToken != nil { + toSerialize["id_token"] = o.IdToken + } + if o.IdTokenNonce != nil { + toSerialize["id_token_nonce"] = o.IdTokenNonce + } if true { toSerialize["method"] = o.Method } diff --git a/selfservice/flow/login/flow.go b/selfservice/flow/login/flow.go index e46698290819..6e7426bd578c 100644 --- a/selfservice/flow/login/flow.go +++ b/selfservice/flow/login/flow.go @@ -133,6 +133,12 @@ type Flow struct { // // required: true State State `json:"state" faker:"-" db:"state"` + + // Only used internally + IDToken string `json:"-" db:"-"` + + // Only used internally + RawIDTokenNonce string `json:"-" db:"-"` } var _ flow.Flow = new(Flow) diff --git a/selfservice/flow/login/hook.go b/selfservice/flow/login/hook.go index 203a62fdf989..b8ce1d15d3b0 100644 --- a/selfservice/flow/login/hook.go +++ b/selfservice/flow/login/hook.go @@ -199,7 +199,10 @@ func (e *HookExecutor) PostLoginHook( Method: a.Active.String(), SSOProvider: provider, })) - if handled, err := e.d.SessionManager().MaybeRedirectAPICodeFlow(w, r, a, s.ID, g); err != nil { + if a.IDToken != "" { + // We don't want to redirect with the code, if the flow was submitted with an ID token. + // This is the case for Sign in with native Apple SDK or Google SDK. + } else if handled, err := e.d.SessionManager().MaybeRedirectAPICodeFlow(w, r, a, s.ID, g); err != nil { return errors.WithStack(err) } else if handled { return nil diff --git a/selfservice/flow/registration/flow.go b/selfservice/flow/registration/flow.go index 39843a9e5b5c..085cf353c8be 100644 --- a/selfservice/flow/registration/flow.go +++ b/selfservice/flow/registration/flow.go @@ -123,6 +123,11 @@ type Flow struct { // - passed_challenge: the request was successful and the registration challenge was passed. // required: true State State `json:"state" faker:"-" db:"state"` + + // only used internally + IDToken string `json:"-" faker:"-" db:"-"` + // Only used internally + RawIDTokenNonce string `json:"-" db:"-"` } var _ flow.Flow = new(Flow) diff --git a/selfservice/flow/registration/hook.go b/selfservice/flow/registration/hook.go index 426d81101dd6..a10d2a4daa07 100644 --- a/selfservice/flow/registration/hook.go +++ b/selfservice/flow/registration/hook.go @@ -227,7 +227,10 @@ func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Reque Debug("Post registration execution hooks completed successfully.") if a.Type == flow.TypeAPI || x.IsJSONRequest(r) { - if handled, err := e.d.SessionManager().MaybeRedirectAPICodeFlow(w, r, a, s.ID, ct.ToUiNodeGroup()); err != nil { + if a.IDToken != "" { + // We don't want to redirect with the code, if the flow was submitted with an ID token. + // This is the case for Sign in with native Apple SDK or Google SDK. + } else if handled, err := e.d.SessionManager().MaybeRedirectAPICodeFlow(w, r, a, s.ID, ct.ToUiNodeGroup()); err != nil { return errors.WithStack(err) } else if handled { return nil diff --git a/selfservice/hook/session_issuer.go b/selfservice/hook/session_issuer.go index 999403d53ace..06e8f0e59693 100644 --- a/selfservice/hook/session_issuer.go +++ b/selfservice/hook/session_issuer.go @@ -53,7 +53,9 @@ func (e *SessionIssuer) ExecutePostRegistrationPostPersistHook(w http.ResponseWr func (e *SessionIssuer) executePostRegistrationPostPersistHook(w http.ResponseWriter, r *http.Request, a *registration.Flow, s *session.Session) error { if a.Type == flow.TypeAPI { - if s.AuthenticatedVia(identity.CredentialsTypeOIDC) { + // We don't want to redirect with the code, if the flow was submitted with an ID token. + // This is the case for Sign in with native Apple SDK or Google SDK. + if s.AuthenticatedVia(identity.CredentialsTypeOIDC) && a.IDToken == "" { if handled, err := e.r.SessionManager().MaybeRedirectAPICodeFlow(w, r, a, s.ID, node.OpenIDConnectGroup); err != nil { return errors.WithStack(err) } else if handled { diff --git a/selfservice/strategy/oidc/.schema/link.schema.json b/selfservice/strategy/oidc/.schema/link.schema.json index c8f82c05c568..1c174841244e 100644 --- a/selfservice/strategy/oidc/.schema/link.schema.json +++ b/selfservice/strategy/oidc/.schema/link.schema.json @@ -39,6 +39,14 @@ }, "additionalProperties": false } + }, + "id_token": { + "type": "string", + "description": "An optional id token provided by an OIDC provider" + }, + "id_token_nonce": { + "type": "string", + "description": "The nonce used when requesting the id_token from the provider. Required, if an id_token is given and the provider supports it." } } } diff --git a/selfservice/strategy/oidc/provider.go b/selfservice/strategy/oidc/provider.go index 6537abbe4d6d..4fe9a028c11e 100644 --- a/selfservice/strategy/oidc/provider.go +++ b/selfservice/strategy/oidc/provider.go @@ -27,6 +27,14 @@ type TokenExchanger interface { Exchange(ctx context.Context, code string, opts ...oauth2.AuthCodeOption) (*oauth2.Token, error) } +type IDTokenVerifier interface { + Verify(ctx context.Context, rawIDToken string) (*Claims, error) +} + +type NonceValidationSkipper interface { + CanSkipNonce(*Claims) bool +} + // ConvertibleBoolean is used as Apple casually sends the email_verified field as a string. type Claims struct { Issuer string `json:"iss,omitempty"` @@ -52,6 +60,8 @@ type Claims struct { UpdatedAt int64 `json:"updated_at,omitempty"` HD string `json:"hd,omitempty"` Team string `json:"team,omitempty"` + Nonce string `json:"nonce,omitempty"` + NonceSupported bool `json:"nonce_supported,omitempty"` RawClaims map[string]interface{} `json:"raw_claims,omitempty"` } diff --git a/selfservice/strategy/oidc/provider_apple.go b/selfservice/strategy/oidc/provider_apple.go index 3df61dc99eb2..686cad1c10ed 100644 --- a/selfservice/strategy/oidc/provider_apple.go +++ b/selfservice/strategy/oidc/provider_apple.go @@ -12,7 +12,9 @@ import ( "net/url" "time" + "github.com/coreos/go-oidc" "github.com/golang-jwt/jwt/v4" + "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "github.com/pkg/errors" @@ -21,18 +23,20 @@ import ( type ProviderApple struct { *ProviderGenericOIDC + jwksUrl string } func NewProviderApple( config *Configuration, reg dependencies, -) *ProviderApple { +) Provider { config.IssuerURL = "https://appleid.apple.com" return &ProviderApple{ ProviderGenericOIDC: &ProviderGenericOIDC{ config: config, reg: reg, }, + jwksUrl: "https://appleid.apple.com/auth/keys", } } @@ -146,3 +150,27 @@ func decodeQuery(query url.Values, claims *Claims) { } } } + +var _ IDTokenVerifier = new(ProviderApple) + +func (a *ProviderApple) Verify(ctx context.Context, rawIDToken string) (*Claims, error) { + keySet := oidc.NewRemoteKeySet(ctx, a.jwksUrl) + verifier := oidc.NewVerifier("https://appleid.apple.com", keySet, &oidc.Config{ + ClientID: a.config.ClientID, + }) + token, err := verifier.Verify(oidc.ClientContext(ctx, otelhttp.DefaultClient), rawIDToken) + if err != nil { + return nil, err + } + claims := &Claims{} + if err := token.Claims(claims); err != nil { + return nil, err + } + return claims, nil +} + +var _ NonceValidationSkipper = new(ProviderApple) + +func (a *ProviderApple) CanSkipNonce(c *Claims) bool { + return c.NonceSupported +} diff --git a/selfservice/strategy/oidc/provider_apple_test.go b/selfservice/strategy/oidc/provider_apple_test.go index 9aa4cd926ff9..7690fec5d78a 100644 --- a/selfservice/strategy/oidc/provider_apple_test.go +++ b/selfservice/strategy/oidc/provider_apple_test.go @@ -4,11 +4,21 @@ package oidc import ( + "context" + "encoding/json" "fmt" + "net/http" + "net/http/httptest" "net/url" "testing" + "time" + _ "embed" + + "github.com/golang-jwt/jwt/v4" + "github.com/rakutentech/jwk-go/jwk" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestDecodeQuery(t *testing.T) { @@ -38,3 +48,98 @@ func TestDecodeQuery(t *testing.T) { } } + +//go:embed stub/jwk.json +var rawKey []byte + +//go:embed stub/jwks_public.json +var publicJWKS []byte + +// Just a public key set, to be able to test what happens if an ID token was issued by a different private key. +// +//go:embed stub/jwks_public2.json +var publicJWKS2 []byte + +type claims struct { + *jwt.RegisteredClaims + Email string `json:"email"` +} + +func createIdToken(t *testing.T, aud string) string { + key := &jwk.KeySpec{} + require.NoError(t, json.Unmarshal(rawKey, key)) + token := jwt.NewWithClaims(jwt.SigningMethodRS256, &claims{ + RegisteredClaims: &jwt.RegisteredClaims{ + Issuer: "https://appleid.apple.com", + Subject: "apple@ory.sh", + Audience: jwt.ClaimStrings{aud}, + ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), + }, + Email: "apple@ory.sh", + }) + token.Header["kid"] = key.KeyID + s, err := token.SignedString(key.Key) + require.NoError(t, err) + return s +} + +func TestVerify(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(200) + w.Write(publicJWKS) + })) + + tsOtherJWKS := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(200) + w.Write(publicJWKS2) + })) + t.Run("case=successful verification", func(t *testing.T) { + apple := ProviderApple{ + jwksUrl: ts.URL, + ProviderGenericOIDC: &ProviderGenericOIDC{ + config: &Configuration{ + ClientID: "com.example.app", + }, + }, + } + token := createIdToken(t, "com.example.app") + + c, err := apple.Verify(context.Background(), token) + require.NoError(t, err) + assert.Equal(t, "apple@ory.sh", c.Email) + assert.Equal(t, "apple@ory.sh", c.Subject) + assert.Equal(t, "https://appleid.apple.com", c.Issuer) + }) + + t.Run("case=fails due to client_id mismatch", func(t *testing.T) { + apple := ProviderApple{ + jwksUrl: ts.URL, + ProviderGenericOIDC: &ProviderGenericOIDC{ + config: &Configuration{ + ClientID: "com.example.app", + }, + }, + } + token := createIdToken(t, "com.different-example.app") + + _, err := apple.Verify(context.Background(), token) + require.Error(t, err) + assert.Equal(t, `oidc: expected audience "com.example.app" got ["com.different-example.app"]`, err.Error()) + }) + + t.Run("case=fails due to jwks mismatch", func(t *testing.T) { + apple := ProviderApple{ + jwksUrl: tsOtherJWKS.URL, + ProviderGenericOIDC: &ProviderGenericOIDC{ + config: &Configuration{ + ClientID: "com.example.app", + }, + }, + } + token := createIdToken(t, "com.example.app") + + _, err := apple.Verify(context.Background(), token) + require.Error(t, err) + assert.Equal(t, "failed to verify signature: failed to verify id token signature", err.Error()) + }) +} diff --git a/selfservice/strategy/oidc/provider_auth0.go b/selfservice/strategy/oidc/provider_auth0.go index fbb71687e959..3b9f7a3dff5f 100644 --- a/selfservice/strategy/oidc/provider_auth0.go +++ b/selfservice/strategy/oidc/provider_auth0.go @@ -33,7 +33,7 @@ type ProviderAuth0 struct { func NewProviderAuth0( config *Configuration, reg dependencies, -) *ProviderAuth0 { +) Provider { return &ProviderAuth0{ ProviderGenericOIDC: &ProviderGenericOIDC{ config: config, diff --git a/selfservice/strategy/oidc/provider_config.go b/selfservice/strategy/oidc/provider_config.go index 8be144dbb1c8..45fc0734ae91 100644 --- a/selfservice/strategy/oidc/provider_config.go +++ b/selfservice/strategy/oidc/provider_config.go @@ -9,6 +9,7 @@ import ( "strings" "github.com/pkg/errors" + "golang.org/x/exp/maps" "github.com/ory/herodot" @@ -116,61 +117,41 @@ type ConfigurationCollection struct { Providers []Configuration `json:"providers"` } +// !!! WARNING !!! +// +// If you add a provider here, please also add a test to +// provider_private_net_test.go +var supportedProviders = map[string]func(config *Configuration, reg dependencies) Provider{ + "generic": NewProviderGenericOIDC, + "google": NewProviderGoogle, + "github": NewProviderGitHub, + "github-app": NewProviderGitHubApp, + "gitlab": NewProviderGitLab, + "microsoft": NewProviderMicrosoft, + "discord": NewProviderDiscord, + "slack": NewProviderSlack, + "facebook": NewProviderFacebook, + "auth0": NewProviderAuth0, + "vk": NewProviderVK, + "yandex": NewProviderYandex, + "apple": NewProviderApple, + "spotify": NewProviderSpotify, + "netid": NewProviderNetID, + "dingtalk": NewProviderDingTalk, + "linkedin": NewProviderLinkedIn, + "patreon": NewProviderPatreon, + "lark": NewProviderLark, +} + func (c ConfigurationCollection) Provider(id string, reg dependencies) (Provider, error) { for k := range c.Providers { p := c.Providers[k] if p.ID == id { - var providerNames []string - var addProviderName = func(pn string) string { - providerNames = append(providerNames, pn) - return pn + if f, ok := supportedProviders[p.Provider]; ok { + return f(&p, reg), nil } - // !!! WARNING !!! - // - // If you add a provider here, please also add a test to - // provider_private_net_test.go - switch p.Provider { - case addProviderName("generic"): - return NewProviderGenericOIDC(&p, reg), nil - case addProviderName("google"): - return NewProviderGoogle(&p, reg), nil - case addProviderName("github"): - return NewProviderGitHub(&p, reg), nil - case addProviderName("github-app"): - return NewProviderGitHubApp(&p, reg), nil - case addProviderName("gitlab"): - return NewProviderGitLab(&p, reg), nil - case addProviderName("microsoft"): - return NewProviderMicrosoft(&p, reg), nil - case addProviderName("discord"): - return NewProviderDiscord(&p, reg), nil - case addProviderName("slack"): - return NewProviderSlack(&p, reg), nil - case addProviderName("facebook"): - return NewProviderFacebook(&p, reg), nil - case addProviderName("auth0"): - return NewProviderAuth0(&p, reg), nil - case addProviderName("vk"): - return NewProviderVK(&p, reg), nil - case addProviderName("yandex"): - return NewProviderYandex(&p, reg), nil - case addProviderName("apple"): - return NewProviderApple(&p, reg), nil - case addProviderName("spotify"): - return NewProviderSpotify(&p, reg), nil - case addProviderName("netid"): - return NewProviderNetID(&p, reg), nil - case addProviderName("dingtalk"): - return NewProviderDingTalk(&p, reg), nil - case addProviderName("linkedin"): - return NewProviderLinkedIn(&p, reg), nil - case addProviderName("patreon"): - return NewProviderPatreon(&p, reg), nil - case addProviderName("lark"): - return NewProviderLark(&p, reg), nil - } - return nil, errors.Errorf("provider type %s is not supported, supported are: %v", p.Provider, providerNames) + return nil, errors.Errorf("provider type %s is not supported, supported are: %v", p.Provider, maps.Keys(supportedProviders)) } } return nil, errors.WithStack(herodot.ErrNotFound.WithReasonf(`OpenID Connect Provider "%s" is unknown or has not been configured`, id)) diff --git a/selfservice/strategy/oidc/provider_dingtalk.go b/selfservice/strategy/oidc/provider_dingtalk.go index 71ae65c870cc..7b4a835e5734 100644 --- a/selfservice/strategy/oidc/provider_dingtalk.go +++ b/selfservice/strategy/oidc/provider_dingtalk.go @@ -28,7 +28,7 @@ type ProviderDingTalk struct { func NewProviderDingTalk( config *Configuration, reg dependencies, -) *ProviderDingTalk { +) Provider { return &ProviderDingTalk{ config: config, reg: reg, diff --git a/selfservice/strategy/oidc/provider_discord.go b/selfservice/strategy/oidc/provider_discord.go index 9a91021d0995..e48ce351a6dc 100644 --- a/selfservice/strategy/oidc/provider_discord.go +++ b/selfservice/strategy/oidc/provider_discord.go @@ -27,7 +27,7 @@ type ProviderDiscord struct { func NewProviderDiscord( config *Configuration, reg dependencies, -) *ProviderDiscord { +) Provider { return &ProviderDiscord{ config: config, reg: reg, diff --git a/selfservice/strategy/oidc/provider_facebook.go b/selfservice/strategy/oidc/provider_facebook.go index 70e7df99b749..7cf89538f978 100644 --- a/selfservice/strategy/oidc/provider_facebook.go +++ b/selfservice/strategy/oidc/provider_facebook.go @@ -31,7 +31,7 @@ type ProviderFacebook struct { func NewProviderFacebook( config *Configuration, reg dependencies, -) *ProviderFacebook { +) Provider { config.IssuerURL = "https://www.facebook.com" return &ProviderFacebook{ ProviderGenericOIDC: &ProviderGenericOIDC{ diff --git a/selfservice/strategy/oidc/provider_generic_oidc.go b/selfservice/strategy/oidc/provider_generic_oidc.go index c09185575969..59d86f985994 100644 --- a/selfservice/strategy/oidc/provider_generic_oidc.go +++ b/selfservice/strategy/oidc/provider_generic_oidc.go @@ -27,7 +27,7 @@ type ProviderGenericOIDC struct { func NewProviderGenericOIDC( config *Configuration, reg dependencies, -) *ProviderGenericOIDC { +) Provider { return &ProviderGenericOIDC{ config: config, reg: reg, diff --git a/selfservice/strategy/oidc/provider_github.go b/selfservice/strategy/oidc/provider_github.go index d53a055fc247..8b8b97ee5f83 100644 --- a/selfservice/strategy/oidc/provider_github.go +++ b/selfservice/strategy/oidc/provider_github.go @@ -30,7 +30,7 @@ type ProviderGitHub struct { func NewProviderGitHub( config *Configuration, reg dependencies, -) *ProviderGitHub { +) Provider { return &ProviderGitHub{ config: config, reg: reg, diff --git a/selfservice/strategy/oidc/provider_github_app.go b/selfservice/strategy/oidc/provider_github_app.go index 86c19b3069c3..f48de9664547 100644 --- a/selfservice/strategy/oidc/provider_github_app.go +++ b/selfservice/strategy/oidc/provider_github_app.go @@ -27,7 +27,7 @@ type ProviderGitHubApp struct { func NewProviderGitHubApp( config *Configuration, reg dependencies, -) *ProviderGitHubApp { +) Provider { return &ProviderGitHubApp{ config: config, reg: reg, diff --git a/selfservice/strategy/oidc/provider_gitlab.go b/selfservice/strategy/oidc/provider_gitlab.go index a7dbee735a0f..fde2506e0a63 100644 --- a/selfservice/strategy/oidc/provider_gitlab.go +++ b/selfservice/strategy/oidc/provider_gitlab.go @@ -32,7 +32,7 @@ type ProviderGitLab struct { func NewProviderGitLab( config *Configuration, reg dependencies, -) *ProviderGitLab { +) Provider { return &ProviderGitLab{ ProviderGenericOIDC: &ProviderGenericOIDC{ config: config, diff --git a/selfservice/strategy/oidc/provider_google.go b/selfservice/strategy/oidc/provider_google.go index cb98696484ca..dc084ec81b6b 100644 --- a/selfservice/strategy/oidc/provider_google.go +++ b/selfservice/strategy/oidc/provider_google.go @@ -19,7 +19,7 @@ type ProviderGoogle struct { func NewProviderGoogle( config *Configuration, reg dependencies, -) *ProviderGoogle { +) Provider { config.IssuerURL = "https://accounts.google.com" return &ProviderGoogle{ ProviderGenericOIDC: &ProviderGenericOIDC{ diff --git a/selfservice/strategy/oidc/provider_lark.go b/selfservice/strategy/oidc/provider_lark.go index 5541a73335af..b239a207c095 100644 --- a/selfservice/strategy/oidc/provider_lark.go +++ b/selfservice/strategy/oidc/provider_lark.go @@ -32,7 +32,7 @@ var ( func NewProviderLark( config *Configuration, reg dependencies, -) *ProviderLark { +) Provider { return &ProviderLark{ &ProviderGenericOIDC{ config: config, diff --git a/selfservice/strategy/oidc/provider_linkedin.go b/selfservice/strategy/oidc/provider_linkedin.go index 8a85bb9c9ed5..a9dde8ce37e3 100644 --- a/selfservice/strategy/oidc/provider_linkedin.go +++ b/selfservice/strategy/oidc/provider_linkedin.go @@ -71,7 +71,7 @@ type ProviderLinkedIn struct { func NewProviderLinkedIn( config *Configuration, reg dependencies, -) *ProviderLinkedIn { +) Provider { return &ProviderLinkedIn{ config: config, reg: reg, diff --git a/selfservice/strategy/oidc/provider_microsoft.go b/selfservice/strategy/oidc/provider_microsoft.go index e5c4a8ec68ff..af664f7f8aca 100644 --- a/selfservice/strategy/oidc/provider_microsoft.go +++ b/selfservice/strategy/oidc/provider_microsoft.go @@ -30,7 +30,7 @@ type ProviderMicrosoft struct { func NewProviderMicrosoft( config *Configuration, reg dependencies, -) *ProviderMicrosoft { +) Provider { return &ProviderMicrosoft{ ProviderGenericOIDC: &ProviderGenericOIDC{ config: config, diff --git a/selfservice/strategy/oidc/provider_netid.go b/selfservice/strategy/oidc/provider_netid.go index 07e52953882a..a919c177728f 100644 --- a/selfservice/strategy/oidc/provider_netid.go +++ b/selfservice/strategy/oidc/provider_netid.go @@ -35,7 +35,7 @@ type ProviderNetID struct { func NewProviderNetID( config *Configuration, reg dependencies, -) *ProviderNetID { +) Provider { config.IssuerURL = fmt.Sprintf("%s://%s/", defaultBrokerScheme, defaultBrokerHost) if !stringslice.Has(config.Scope, gooidc.ScopeOpenID) { config.Scope = append(config.Scope, gooidc.ScopeOpenID) diff --git a/selfservice/strategy/oidc/provider_patreon.go b/selfservice/strategy/oidc/provider_patreon.go index 4dbb60b42d9c..dbd740ff88bf 100644 --- a/selfservice/strategy/oidc/provider_patreon.go +++ b/selfservice/strategy/oidc/provider_patreon.go @@ -40,7 +40,7 @@ type PatreonIdentityResponse struct { func NewProviderPatreon( config *Configuration, reg dependencies, -) *ProviderPatreon { +) Provider { return &ProviderPatreon{ config: config, reg: reg, diff --git a/selfservice/strategy/oidc/provider_slack.go b/selfservice/strategy/oidc/provider_slack.go index f23d543a40c5..951b7fab1874 100644 --- a/selfservice/strategy/oidc/provider_slack.go +++ b/selfservice/strategy/oidc/provider_slack.go @@ -27,7 +27,7 @@ type ProviderSlack struct { func NewProviderSlack( config *Configuration, reg dependencies, -) *ProviderSlack { +) Provider { return &ProviderSlack{ config: config, reg: reg, diff --git a/selfservice/strategy/oidc/provider_spotify.go b/selfservice/strategy/oidc/provider_spotify.go index a60efb552b83..3c0d95ea043d 100644 --- a/selfservice/strategy/oidc/provider_spotify.go +++ b/selfservice/strategy/oidc/provider_spotify.go @@ -30,7 +30,7 @@ type ProviderSpotify struct { func NewProviderSpotify( config *Configuration, reg dependencies, -) *ProviderSpotify { +) Provider { return &ProviderSpotify{ config: config, reg: reg, diff --git a/selfservice/strategy/oidc/provider_test.go b/selfservice/strategy/oidc/provider_test.go index 1b464bd2eec5..74fdb05031fc 100644 --- a/selfservice/strategy/oidc/provider_test.go +++ b/selfservice/strategy/oidc/provider_test.go @@ -4,6 +4,9 @@ package oidc import ( + "context" + "encoding/json" + "fmt" "testing" "github.com/stretchr/testify/require" @@ -17,3 +20,35 @@ func TestClaimsValidate(t *testing.T) { require.Error(t, (&Claims{Subject: "not-empty"}).Validate()) require.NoError(t, (&Claims{Issuer: "not-empty", Subject: "not-empty"}).Validate()) } + +type TestProvider struct { + *ProviderGenericOIDC +} + +func NewTestProvider(c *Configuration, reg dependencies) Provider { + return &TestProvider{ + ProviderGenericOIDC: NewProviderGenericOIDC(c, reg).(*ProviderGenericOIDC), + } +} + +func RegisterTestProvider(id string) func() { + supportedProviders[id] = func(c *Configuration, reg dependencies) Provider { + return NewTestProvider(c, reg) + } + return func() { + delete(supportedProviders, id) + } +} + +var _ IDTokenVerifier = new(TestProvider) + +func (t *TestProvider) Verify(ctx context.Context, token string) (*Claims, error) { + if token == "error" { + return nil, fmt.Errorf("stub error") + } + c := Claims{} + if err := json.Unmarshal([]byte(token), &c); err != nil { + return nil, err + } + return &c, nil +} diff --git a/selfservice/strategy/oidc/provider_vk.go b/selfservice/strategy/oidc/provider_vk.go index 602a8574f999..6d89170d77a1 100644 --- a/selfservice/strategy/oidc/provider_vk.go +++ b/selfservice/strategy/oidc/provider_vk.go @@ -27,7 +27,7 @@ type ProviderVK struct { func NewProviderVK( config *Configuration, reg dependencies, -) *ProviderVK { +) Provider { return &ProviderVK{ config: config, reg: reg, diff --git a/selfservice/strategy/oidc/provider_yandex.go b/selfservice/strategy/oidc/provider_yandex.go index 12a845185b91..4c93a13a196e 100644 --- a/selfservice/strategy/oidc/provider_yandex.go +++ b/selfservice/strategy/oidc/provider_yandex.go @@ -25,7 +25,7 @@ type ProviderYandex struct { func NewProviderYandex( config *Configuration, reg dependencies, -) *ProviderYandex { +) Provider { return &ProviderYandex{ config: config, reg: reg, diff --git a/selfservice/strategy/oidc/strategy.go b/selfservice/strategy/oidc/strategy.go index 1b4f9ca56034..d772bfd0f198 100644 --- a/selfservice/strategy/oidc/strategy.go +++ b/selfservice/strategy/oidc/strategy.go @@ -432,7 +432,7 @@ func (s *Strategy) handleCallback(w http.ResponseWriter, r *http.Request, ps htt return case *registration.Flow: a.TransientPayload = cntnr.TransientPayload - if ff, err := s.processRegistration(w, r, a, token, claims, provider, cntnr); err != nil { + if ff, err := s.processRegistration(w, r, a, token, claims, provider, cntnr, ""); err != nil { if ff != nil { s.forwardError(w, r, ff, err) return @@ -589,3 +589,39 @@ func (s *Strategy) CompletedAuthenticationMethod(ctx context.Context) session.Au AAL: identity.AuthenticatorAssuranceLevel1, } } + +func (s *Strategy) processIDToken(w http.ResponseWriter, r *http.Request, provider Provider, idToken, idTokenNonce string) (*Claims, error) { + verifier, ok := provider.(IDTokenVerifier) + if !ok { + return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("The provider %s does not support id_token verification", provider.Config().Provider)) + } + claims, err := verifier.Verify(r.Context(), idToken) + if err != nil { + return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Could not verify id_token").WithError(err.Error())) + } + + if err := claims.Validate(); err != nil { + return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("The id_token claims were invalid").WithError(err.Error())) + } + + // First check if the JWT contains the nonce claim. + if claims.Nonce == "" { + // If it doesn't, check if the provider supports nonces. + if nonceSkipper, ok := verifier.(NonceValidationSkipper); !ok || !nonceSkipper.CanSkipNonce(claims) { + // If the provider supports nonces, abort the flow! + return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("No nonce was included in the id_token but is required by the provider")) + } + // If the provider does not support nonces, we don't do validation and return the claim. + // This case only applies to Apple, as some of their devices do not support nonces. + // https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_rest_api/authenticating_users_with_sign_in_with_apple + } else if idTokenNonce == "" { + // A nonce was present in the JWT token, but no nonce was submitted in the flow + return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("No nonce was provided but is required by the provider")) + } else if idTokenNonce != claims.Nonce { + // The nonce from the JWT token does not match the nonce from the flow. + return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("The supplied nonce does not match the nonce from the id_token")) + } + // Nonce checking was successful + + return claims, nil +} diff --git a/selfservice/strategy/oidc/strategy_helper_test.go b/selfservice/strategy/oidc/strategy_helper_test.go index db3904d0221f..c708eb340022 100644 --- a/selfservice/strategy/oidc/strategy_helper_test.go +++ b/selfservice/strategy/oidc/strategy_helper_test.go @@ -324,8 +324,17 @@ func newOIDCProvider( func viperSetProviderConfig(t *testing.T, conf *config.Config, providers ...oidc.Configuration) { ctx := context.Background() - conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+"."+string(identity.CredentialsTypeOIDC)+".config", &oidc.ConfigurationCollection{Providers: providers}) - conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+"."+string(identity.CredentialsTypeOIDC)+".enabled", true) + baseKey := fmt.Sprintf("%s.%s", config.ViperKeySelfServiceStrategyConfig, identity.CredentialsTypeOIDC) + currentConfig := conf.GetProvider(ctx).Get(baseKey + ".config") + currentEnabled := conf.GetProvider(ctx).Get(baseKey + ".enabled") + + conf.MustSet(ctx, baseKey+".config", &oidc.ConfigurationCollection{Providers: providers}) + conf.MustSet(ctx, baseKey+".enabled", true) + + t.Cleanup(func() { + conf.MustSet(ctx, baseKey+".config", currentConfig) + conf.MustSet(ctx, baseKey+".enabled", currentEnabled) + }) } // AssertSystemError asserts an error ui response diff --git a/selfservice/strategy/oidc/strategy_login.go b/selfservice/strategy/oidc/strategy_login.go index 24af92562f5c..14d44702bb75 100644 --- a/selfservice/strategy/oidc/strategy_login.go +++ b/selfservice/strategy/oidc/strategy_login.go @@ -81,6 +81,24 @@ type UpdateLoginFlowWithOidcMethod struct { // // required: false UpstreamParameters json.RawMessage `json:"upstream_parameters"` + + // IDToken is an optional id token provided by an OIDC provider + // + // If submitted, it is verified using the OIDC provider's public key set and the claims are used to populate + // the OIDC credentials of the identity. + // If the OIDC provider does not store additional claims (such as name, etc.) in the IDToken itself, you can use + // the `traits` field to populate the identity's traits. Note, that Apple only includes the users email in the IDToken. + // + // Supported providers are + // - Apple + // required: false + IDToken string `json:"id_token,omitempty"` + + // IDTokenNonce is the nonce, used when generating the IDToken. + // If the provider supports nonce validation, the nonce will be validated against this value and required. + // + // required: false + IDTokenNonce string `json:"id_token_nonce,omitempty"` } func (s *Strategy) processLogin(w http.ResponseWriter, r *http.Request, loginFlow *login.Flow, token *oauth2.Token, claims *Claims, provider Provider, container *authCodeContainer) (*registration.Flow, error) { @@ -123,12 +141,14 @@ func (s *Strategy) processLogin(w http.ResponseWriter, r *http.Request, loginFlo return nil, s.handleError(w, r, loginFlow, provider.Config().ID, nil, err) } + registrationFlow.IDToken = loginFlow.IDToken + registrationFlow.RawIDTokenNonce = loginFlow.RawIDTokenNonce registrationFlow.RequestURL, err = x.TakeOverReturnToParameter(loginFlow.RequestURL, registrationFlow.RequestURL) if err != nil { return nil, s.handleError(w, r, loginFlow, provider.Config().ID, nil, err) } - if _, err := s.processRegistration(w, r, registrationFlow, token, claims, provider, container); err != nil { + if _, err := s.processRegistration(w, r, registrationFlow, token, claims, provider, container, loginFlow.IDToken); err != nil { return registrationFlow, err } @@ -167,6 +187,9 @@ func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, return nil, s.handleError(w, r, f, "", nil, errors.WithStack(herodot.ErrBadRequest.WithDebug(err.Error()).WithReasonf("Unable to parse HTTP form request: %s", err.Error()))) } + f.IDToken = p.IDToken + f.RawIDTokenNonce = p.IDTokenNonce + pid := p.Provider // this can come from both url query and post body if pid == "" { return nil, errors.WithStack(flow.ErrStrategyNotResponsible) @@ -196,6 +219,22 @@ func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, } else if authenticated { return i, nil } + + if p.IDToken != "" { + claims, err := s.processIDToken(w, r, provider, p.IDToken, p.IDTokenNonce) + if err != nil { + return nil, s.handleError(w, r, f, pid, nil, err) + } + _, err = s.processLogin(w, r, f, nil, claims, provider, &authCodeContainer{ + FlowID: f.ID.String(), + Traits: p.Traits, + }) + if err != nil { + return nil, s.handleError(w, r, f, pid, nil, err) + } + return nil, errors.WithStack(flow.ErrCompletedByStrategy) + } + state := generateState(f.ID.String()) if code, hasCode, _ := s.d.SessionTokenExchangePersister().CodeForFlow(r.Context(), f.ID); hasCode { state.setCode(code.InitCode) diff --git a/selfservice/strategy/oidc/strategy_registration.go b/selfservice/strategy/oidc/strategy_registration.go index debc45d770db..15b42ac56c6f 100644 --- a/selfservice/strategy/oidc/strategy_registration.go +++ b/selfservice/strategy/oidc/strategy_registration.go @@ -98,6 +98,24 @@ type UpdateRegistrationFlowWithOidcMethod struct { // // required: false UpstreamParameters json.RawMessage `json:"upstream_parameters"` + + // IDToken is an optional id token provided by an OIDC provider + // + // If submitted, it is verified using the OIDC provider's public key set and the claims are used to populate + // the OIDC credentials of the identity. + // If the OIDC provider does not store additional claims (such as name, etc.) in the IDToken itself, you can use + // the `traits` field to populate the identity's traits. Note, that Apple only includes the users email in the IDToken. + // + // Supported providers are + // - Apple + // required: false + IDToken string `json:"id_token,omitempty"` + + // IDTokenNonce is the nonce, used when generating the IDToken. + // If the provider supports nonce validation, the nonce will be validated against this value and is required. + // + // required: false + IDTokenNonce string `json:"id_token_nonce,omitempty"` } func (s *Strategy) newLinkDecoder(p interface{}, r *http.Request) error { @@ -136,6 +154,8 @@ func (s *Strategy) Register(w http.ResponseWriter, r *http.Request, f *registrat } f.TransientPayload = p.TransientPayload + f.IDToken = p.IDToken + f.RawIDTokenNonce = p.IDTokenNonce pid := p.Provider // this can come from both url query and post body if pid == "" { @@ -167,6 +187,22 @@ func (s *Strategy) Register(w http.ResponseWriter, r *http.Request, f *registrat return errors.WithStack(registration.ErrAlreadyLoggedIn) } + if p.IDToken != "" { + claims, err := s.processIDToken(w, r, provider, p.IDToken, p.IDTokenNonce) + if err != nil { + return s.handleError(w, r, f, pid, nil, err) + } + _, err = s.processRegistration(w, r, f, nil, claims, provider, &authCodeContainer{ + FlowID: f.ID.String(), + Traits: p.Traits, + TransientPayload: f.TransientPayload, + }, p.IDToken) + if err != nil { + return s.handleError(w, r, f, pid, nil, err) + } + return errors.WithStack(flow.ErrCompletedByStrategy) + } + state := generateState(f.ID.String()) if code, hasCode, _ := s.d.SessionTokenExchangePersister().CodeForFlow(r.Context(), f.ID); hasCode { state.setCode(code.InitCode) @@ -226,7 +262,7 @@ func (s *Strategy) registrationToLogin(w http.ResponseWriter, r *http.Request, r return lf, nil } -func (s *Strategy) processRegistration(w http.ResponseWriter, r *http.Request, rf *registration.Flow, token *oauth2.Token, claims *Claims, provider Provider, container *authCodeContainer) (*login.Flow, error) { +func (s *Strategy) processRegistration(w http.ResponseWriter, r *http.Request, rf *registration.Flow, token *oauth2.Token, claims *Claims, provider Provider, container *authCodeContainer, idToken string) (*login.Flow, error) { if _, _, err := s.d.PrivilegedIdentityPool().FindByCredentialsIdentifier(r.Context(), identity.CredentialsTypeOIDC, identity.OIDCUniqueID(provider.Config().ID, claims.Subject)); err == nil { // If the identity already exists, we should perform the login flow instead. @@ -281,21 +317,26 @@ func (s *Strategy) processRegistration(w http.ResponseWriter, r *http.Request, r } } - var it string - if idToken, ok := token.Extra("id_token").(string); ok { - if it, err = s.d.Cipher(r.Context()).Encrypt(r.Context(), []byte(idToken)); err != nil { - return nil, s.handleError(w, r, rf, provider.Config().ID, i.Traits, err) + var it string = idToken + var ( + cat, crt string + ) + if token != nil { + if idToken, ok := token.Extra("id_token").(string); ok { + if it, err = s.d.Cipher(r.Context()).Encrypt(r.Context(), []byte(idToken)); err != nil { + return nil, s.handleError(w, r, rf, provider.Config().ID, i.Traits, err) + } } - } - cat, err := s.d.Cipher(r.Context()).Encrypt(r.Context(), []byte(token.AccessToken)) - if err != nil { - return nil, s.handleError(w, r, rf, provider.Config().ID, i.Traits, err) - } + cat, err = s.d.Cipher(r.Context()).Encrypt(r.Context(), []byte(token.AccessToken)) + if err != nil { + return nil, s.handleError(w, r, rf, provider.Config().ID, i.Traits, err) + } - crt, err := s.d.Cipher(r.Context()).Encrypt(r.Context(), []byte(token.RefreshToken)) - if err != nil { - return nil, s.handleError(w, r, rf, provider.Config().ID, i.Traits, err) + crt, err = s.d.Cipher(r.Context()).Encrypt(r.Context(), []byte(token.RefreshToken)) + if err != nil { + return nil, s.handleError(w, r, rf, provider.Config().ID, i.Traits, err) + } } creds, err := identity.NewCredentialsOIDC(it, cat, crt, provider.Config().ID, claims.Subject) @@ -362,12 +403,16 @@ func (s *Strategy) setTraits(w http.ResponseWriter, r *http.Request, a *registra return errors.WithStack(herodot.ErrInternalServerError.WithReasonf("OpenID Connect Jsonnet mapper did not return an object for key identity.traits. Please check your Jsonnet code!")) } - traits, err := merge(container.Traits, json.RawMessage(jsonTraits.Raw)) - if err != nil { - return s.handleError(w, r, a, provider.Config().ID, nil, err) - } + if container != nil { + traits, err := merge(container.Traits, json.RawMessage(jsonTraits.Raw)) + if err != nil { + return s.handleError(w, r, a, provider.Config().ID, nil, err) + } - i.Traits = traits + i.Traits = traits + } else { + i.Traits = identity.Traits(json.RawMessage(jsonTraits.Raw)) + } s.d.Logger(). WithRequest(r). WithField("oidc_provider", provider.Config().ID). diff --git a/selfservice/strategy/oidc/strategy_test.go b/selfservice/strategy/oidc/strategy_test.go index aaf1f2ba818c..5d0a542ea7bd 100644 --- a/selfservice/strategy/oidc/strategy_test.go +++ b/selfservice/strategy/oidc/strategy_test.go @@ -20,6 +20,7 @@ import ( "github.com/ory/kratos/hydra" "github.com/ory/kratos/selfservice/sessiontokenexchange" "github.com/ory/kratos/session" + "github.com/ory/x/randx" "github.com/ory/x/snapshotx" "github.com/ory/kratos/text" @@ -549,7 +550,225 @@ func TestStrategy(t *testing.T) { tc.then(t) }) } + }) + + t.Run("case=submit id_token during registration or login", func(t *testing.T) { + viperSetProviderConfig( + t, + conf, + newOIDCProvider(t, ts, remotePublic, remoteAdmin, "valid"), + oidc.Configuration{ + Provider: "test-provider", + ID: "test-provider", + ClientID: invalid.ClientID, + ClientSecret: invalid.ClientSecret, + IssuerURL: remotePublic + "/", + Mapper: "file://./stub/oidc.facebook.jsonnet", + }, + ) + t.Cleanup(oidc.RegisterTestProvider("test-provider")) + + cl := http.Client{} + type testCase struct { + name string + idToken string + provider string + v func(string, string, string) url.Values + expect func(t *testing.T, res *http.Response, body []byte) + } + + var prep = func(tc *testCase) (provider string, token string, nonce string) { + provider = tc.provider + if provider == "" { + provider = "test-provider" + } + token = tc.idToken + token = strings.Replace(token, "{{sub}}", testhelpers.RandomEmail(), -1) + nonce = randx.MustString(16, randx.Alpha) + token = strings.Replace(token, "{{nonce}}", nonce, -1) + return + } + + for _, tc := range []testCase{ + { + name: "should fail if provider does not support id_token submission", + idToken: "error", + provider: "valid", + expect: func(t *testing.T, res *http.Response, body []byte) { + require.Equal(t, "The provider generic does not support id_token verification", gjson.GetBytes(body, "error.reason").String(), "%s", body) + }, + }, + { + name: "should fail because id_token is invalid", + idToken: "error", + expect: func(t *testing.T, res *http.Response, body []byte) { + require.Equal(t, "Could not verify id_token", gjson.GetBytes(body, "error.reason").String(), "%s", body) + require.Equal(t, "stub error", gjson.GetBytes(body, "error.message").String(), "%s", body) + }, + }, + { + name: "should fail because claims are invalid", + idToken: "{}", + expect: func(t *testing.T, res *http.Response, body []byte) { + require.Equal(t, "The id_token claims were invalid", gjson.GetBytes(body, "error.reason").String(), "%s", body) + }, + }, + { + name: "should fail if no nonce is included in the id_token", + idToken: `{ + "iss": "https://appleid.apple.com", + "sub": "{{sub}}" + }`, + expect: func(t *testing.T, res *http.Response, body []byte) { + require.Equal(t, "No nonce was included in the id_token but is required by the provider", gjson.GetBytes(body, "error.reason").String(), "%s", body) + }, + }, + { + name: "should fail if no nonce is supplied in request", + idToken: `{ + "iss": "https://appleid.apple.com", + "sub": "{{sub}}", + "nonce": "{{nonce}}" + }`, + v: func(provider, token, _ string) url.Values { + return url.Values{ + "id_token": {token}, + "provider": {provider}, + } + }, + expect: func(t *testing.T, res *http.Response, body []byte) { + require.Equal(t, "No nonce was provided but is required by the provider", gjson.GetBytes(body, "error.reason").String(), "%s", body) + }, + }, + { + name: "should pass if claims are valid", + idToken: `{ + "iss": "https://appleid.apple.com", + "sub": "{{sub}}", + "nonce": "{{nonce}}" + }`, + expect: func(t *testing.T, res *http.Response, body []byte) { + require.NotEmpty(t, gjson.GetBytes(body, "session_token").String(), "%s", body) + }, + }, + { + name: "nonce mismatch", + idToken: `{ + "iss": "https://appleid.apple.com", + "sub": "{{sub}}", + "nonce": "random-nonce" + }`, + expect: func(t *testing.T, res *http.Response, body []byte) { + require.Equal(t, "The supplied nonce does not match the nonce from the id_token", gjson.GetBytes(body, "error.reason").String(), "%s", body) + }, + }, + } { + tc := tc + t.Run(fmt.Sprintf("flow=registration/case=%s", tc.name), func(t *testing.T) { + f := newAPIRegistrationFlow(t, returnTS.URL, time.Minute) + provider, token, nonce := prep(&tc) + action := assertFormValues(t, f.ID, "test-provider") + v := url.Values{ + "id_token": {token}, + "provider": {provider}, + "id_token_nonce": {nonce}, + } + if tc.v != nil { + v = tc.v(provider, token, nonce) + } + res, err := cl.PostForm(action, v) + require.NoError(t, err) + body := ioutilx.MustReadAll(res.Body) + tc.expect(t, res, body) + }) + + t.Run(fmt.Sprintf("flow=login/case=%s", tc.name), func(t *testing.T) { + provider, token, nonce := prep(&tc) + rf := newAPIRegistrationFlow(t, returnTS.URL, time.Minute) + action := assertFormValues(t, rf.ID, "test-provider") + v := url.Values{ + "id_token": {token}, + "provider": {provider}, + "id_token_nonce": {nonce}, + } + if tc.v != nil { + v = tc.v(provider, token, nonce) + } + res, err := cl.PostForm(action, v) + require.NoError(t, err) + + lf := newAPILoginFlow(t, returnTS.URL, time.Minute) + action = assertFormValues(t, lf.ID, "test-provider") + + res, err = cl.PostForm(action, v) + require.NoError(t, err) + body := ioutilx.MustReadAll(res.Body) + tc.expect(t, res, body) + }) + + t.Run(fmt.Sprintf("flow=login_without_registration/case=%s", tc.name), func(t *testing.T) { + provider, token, nonce := prep(&tc) + rf := newAPIRegistrationFlow(t, returnTS.URL, time.Minute) + action := assertFormValues(t, rf.ID, "test-provider") + + v := url.Values{ + "id_token": {token}, + "provider": {provider}, + "id_token_nonce": {nonce}, + } + if tc.v != nil { + v = tc.v(provider, token, nonce) + } + res, err := cl.PostForm(action, v) + require.NoError(t, err) + + lf := newAPIRegistrationFlow(t, returnTS.URL, time.Minute) + action = assertFormValues(t, lf.ID, "test-provider") + + res, err = cl.PostForm(action, v) + require.NoError(t, err) + body := ioutilx.MustReadAll(res.Body) + tc.expect(t, res, body) + }) + + t.Run(fmt.Sprintf("flow=login_with_return_session_token_exchange_code/case=%s", tc.name), func(t *testing.T) { + provider, token, nonce := prep(&tc) + lf := newAPILoginFlow(t, returnTS.URL+"?return_session_token_exchange_code=true&return_to=/app_code", time.Minute) + action := assertFormValues(t, lf.ID, "test-provider") + v := url.Values{ + "id_token": {token}, + "provider": {provider}, + "id_token_nonce": {nonce}, + } + if tc.v != nil { + v = tc.v(provider, token, nonce) + } + res, err := cl.PostForm(action, v) + require.NoError(t, err) + body := ioutilx.MustReadAll(res.Body) + tc.expect(t, res, body) + }) + + t.Run(fmt.Sprintf("flow=registration_with_return_session_token_exchange_code/case=%s", tc.name), func(t *testing.T) { + provider, token, nonce := prep(&tc) + lf := newAPIRegistrationFlow(t, returnTS.URL+"?return_session_token_exchange_code=true&return_to=/app_code", time.Minute) + action := assertFormValues(t, lf.ID, "test-provider") + v := url.Values{ + "id_token": {token}, + "provider": {provider}, + "id_token_nonce": {nonce}, + } + if tc.v != nil { + v = tc.v(provider, token, nonce) + } + res, err := cl.PostForm(action, v) + require.NoError(t, err) + body := ioutilx.MustReadAll(res.Body) + tc.expect(t, res, body) + }) + + } }) t.Run("case=login without registered account with return_to", func(t *testing.T) { diff --git a/selfservice/strategy/oidc/stub/jwk.json b/selfservice/strategy/oidc/stub/jwk.json new file mode 100644 index 000000000000..7922b733f7aa --- /dev/null +++ b/selfservice/strategy/oidc/stub/jwk.json @@ -0,0 +1,14 @@ +{ + "p": "8Bh18gHHaVBWHgHX2s9eAsTHSgFq1kSvAuhvWpipsfbrDMBYZ2nwPCB1g3hb-L6cIMzxTmsv8bxwC0l316I8f77NgjSB4mlZAHjXZp861Z9xAFQ_Kx9ZcRldGmbUQ0NOQaHxMCSh5C1hmr8X54BzTEuMTlOnjVQrKUAPoaxhRpU", + "kty": "RSA", + "q": "4id2MrhpalEruyQUIDeLts0rqqanYhny1PU_K7CibTmAFm88U2npceffxg0o6RLYccybx51VYvzPqp01uGL5-TWAJLHihpXbVt8pgidok21mN54IXScG_EOblrp6sPjzhn39dpiCzAgIZhgOQR-IHepWSYwEuKbD8mVnKkYD44c", + "d": "LsaTOZr2KEUMppL92JtlDatcVSXSDYBTqhG4Sr2Pn-Pbq-VVpHTIRtvHeAz3Kiyei8MYG7jhOLzoA2zQGq7DqNP3BGOAPjPgPqW7nQ33TFIAlS8Q-8iJnmZC3NNG4G0go5YJoNgu7aQeBmOqL_jngCwAxvF2KvmOEOpfZzG9Nt0XMBMnAWa5NskKrtnB7b8oxxjghPyLsFa_N9JfjYPUDh_zZWfgv866k2UEqLaWOUMDRhfFpXeEu_YL4i8xwGmX-mDAxESXEjRZQrK29_SldIhTAopzGoacmic9CJwntGENOt5hihlDzCpMUEKafiFzODCQVYZSl0GaYupopZoH2Q", + "e": "AQAB", + "use": "sig", + "kid": "RTSkc-Jk-iD1lx2TK9WtYDtBtWs0MSyCG0nQSR1mglU", + "qi": "ini3TIy3h4Lm85imQRXVjd5VyzA4_b7CkRhIAbj2Q-Pv2xoHJ6xhDgE6jRa1rher4DNrcAuBuOel5f_2U6EcVe6IoQU5-IvqS7hfo0JCWTjCjBKNTqpNFjUC2kE8kaWKaP_tfDESmW-ZO0iKAbuRCneSyNHgj2RQIcXFbq1bIRQ", + "dp": "nk7ClgtuPJZn8ektNm08g37UGIvOsfEfpD82DPpUCa_RU9sPb0B-0mZklYcqvVyQ_V-kTByIxE-HYSnUBy5FzcU1JAETEwJ7WMBU5qle1bQHgjwKWpiVFOmwZdQfaSpb0xLAQQomZJk3nh0Z2d7sJwY5QPwPojQ5MT24ENXkXfE", + "alg": "RS256", + "dq": "bbifi_QUkNRY1y6l5QuN6V6ZdO3t_5Z_Tfq-bz__Tea70iadqgqUjALnensgAhR2lp-iZLJcnu3xAuHLEm5SwSnHxgXX1VwXUopq5Q6hmgVVtl4hyLAKn5Fdhz9qDzp5TCMMOeG8c6jiCkZZhBb8PydWPdCE6eFe59dyufvGHzk", + "n": "1BqatHWJWPTN4mnkrhns2pSk4LRe7W0cyjs8vp7INp3PtgzQ0-KuUibnE0v0k-6DQcu-3hkP88fUOGlYm2z0x9y2urMoAepBwiWybs1v0xqaQx_eLxtkCiElF3i9zYTqmR6cdAOb_duKpTeuTZm326UdpmDoU3TwcGBcszNkNfcNjeq-3z2bvS3GXvJIR9A-6j17xAXVVifUwjPIcNs21ajJVhNFcM9cM90OG9mivbE645KkqMT-WQxFPEQ-DqjijmXnLed9QabcfXcZdkT96O7x_zxHTgF46FlVyJtswuLRUO-h-48ai3-6NmfnR0tOCoVYhHJxndcQ0L_-uqFXkw" +} diff --git a/selfservice/strategy/oidc/stub/jwks_public.json b/selfservice/strategy/oidc/stub/jwks_public.json new file mode 100644 index 000000000000..48ada384219d --- /dev/null +++ b/selfservice/strategy/oidc/stub/jwks_public.json @@ -0,0 +1,12 @@ +{ + "keys": [ + { + "kty": "RSA", + "e": "AQAB", + "use": "sig", + "kid": "RTSkc-Jk-iD1lx2TK9WtYDtBtWs0MSyCG0nQSR1mglU", + "alg": "RS256", + "n": "1BqatHWJWPTN4mnkrhns2pSk4LRe7W0cyjs8vp7INp3PtgzQ0-KuUibnE0v0k-6DQcu-3hkP88fUOGlYm2z0x9y2urMoAepBwiWybs1v0xqaQx_eLxtkCiElF3i9zYTqmR6cdAOb_duKpTeuTZm326UdpmDoU3TwcGBcszNkNfcNjeq-3z2bvS3GXvJIR9A-6j17xAXVVifUwjPIcNs21ajJVhNFcM9cM90OG9mivbE645KkqMT-WQxFPEQ-DqjijmXnLed9QabcfXcZdkT96O7x_zxHTgF46FlVyJtswuLRUO-h-48ai3-6NmfnR0tOCoVYhHJxndcQ0L_-uqFXkw" + } + ] +} diff --git a/selfservice/strategy/oidc/stub/jwks_public2.json b/selfservice/strategy/oidc/stub/jwks_public2.json new file mode 100644 index 000000000000..6abd16936229 --- /dev/null +++ b/selfservice/strategy/oidc/stub/jwks_public2.json @@ -0,0 +1,12 @@ +{ + "keys": [ + { + "kty": "RSA", + "e": "AQAB", + "use": "sig", + "kid": "swo5qZbZECb_alwFmwoleMN7nFw6Us-TP6f-sKIPDF0", + "alg": "RS256", + "n": "kOB5UX-fhCEesMn7BBRKCwkV33blQrD4xZhRK3rQDySNGwf9Uoeemm6SsO5E3WBnYQHWyH4X4jlwVNmkqBHyijKs3v2DBhIZTXa0dU2qp6dGJXQObSHKN51RzPX6yE3DiuzhKcl0ORlvjZk2nzPDl3l9y_Fl6opjFsnnCdHUovqdTBi9HcdocF7E5QeFvQG0QHs8zDC1myjs73m1F18IlTF6peXgFhgsiPKrXrgugh8vItpzr4dfA8fK3ND-NBLloNaZbtCAGmW6vxJnRae2PVBzSf8GamMBCuCNOJBRaQMRkZnZvkAIMGc9WngaHFhGBnW3IC__B0e-_fCyAVr4KQ" + } + ] +} diff --git a/spec/api.json b/spec/api.json index f1e8897dafee..6c12cdbf26f4 100644 --- a/spec/api.json +++ b/spec/api.json @@ -2468,6 +2468,14 @@ "description": "The CSRF Token", "type": "string" }, + "id_token": { + "description": "IDToken is an optional id token provided by an OIDC provider\n\nIf submitted, it is verified using the OIDC provider's public key set and the claims are used to populate\nthe OIDC credentials of the identity.\nIf the OIDC provider does not store additional claims (such as name, etc.) in the IDToken itself, you can use\nthe `traits` field to populate the identity's traits. Note, that Apple only includes the users email in the IDToken.\n\nSupported providers are\nApple", + "type": "string" + }, + "id_token_nonce": { + "description": "IDTokenNonce is the nonce, used when generating the IDToken.\nIf the provider supports nonce validation, the nonce will be validated against this value and required.", + "type": "string" + }, "method": { "description": "Method to use\n\nThis field must be set to `oidc` when using the oidc method.", "type": "string" @@ -2712,6 +2720,14 @@ "description": "The CSRF Token", "type": "string" }, + "id_token": { + "description": "IDToken is an optional id token provided by an OIDC provider\n\nIf submitted, it is verified using the OIDC provider's public key set and the claims are used to populate\nthe OIDC credentials of the identity.\nIf the OIDC provider does not store additional claims (such as name, etc.) in the IDToken itself, you can use\nthe `traits` field to populate the identity's traits. Note, that Apple only includes the users email in the IDToken.\n\nSupported providers are\nApple", + "type": "string" + }, + "id_token_nonce": { + "description": "IDTokenNonce is the nonce, used when generating the IDToken.\nIf the provider supports nonce validation, the nonce will be validated against this value and is required.", + "type": "string" + }, "method": { "description": "Method to use\n\nThis field must be set to `oidc` when using the oidc method.", "type": "string" diff --git a/spec/swagger.json b/spec/swagger.json index a364c11770c2..3bfd4226af23 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -5393,6 +5393,14 @@ "description": "The CSRF Token", "type": "string" }, + "id_token": { + "description": "IDToken is an optional id token provided by an OIDC provider\n\nIf submitted, it is verified using the OIDC provider's public key set and the claims are used to populate\nthe OIDC credentials of the identity.\nIf the OIDC provider does not store additional claims (such as name, etc.) in the IDToken itself, you can use\nthe `traits` field to populate the identity's traits. Note, that Apple only includes the users email in the IDToken.\n\nSupported providers are\nApple", + "type": "string" + }, + "id_token_nonce": { + "description": "IDTokenNonce is the nonce, used when generating the IDToken.\nIf the provider supports nonce validation, the nonce will be validated against this value and required.", + "type": "string" + }, "method": { "description": "Method to use\n\nThis field must be set to `oidc` when using the oidc method.", "type": "string" @@ -5601,6 +5609,14 @@ "description": "The CSRF Token", "type": "string" }, + "id_token": { + "description": "IDToken is an optional id token provided by an OIDC provider\n\nIf submitted, it is verified using the OIDC provider's public key set and the claims are used to populate\nthe OIDC credentials of the identity.\nIf the OIDC provider does not store additional claims (such as name, etc.) in the IDToken itself, you can use\nthe `traits` field to populate the identity's traits. Note, that Apple only includes the users email in the IDToken.\n\nSupported providers are\nApple", + "type": "string" + }, + "id_token_nonce": { + "description": "IDTokenNonce is the nonce, used when generating the IDToken.\nIf the provider supports nonce validation, the nonce will be validated against this value and is required.", + "type": "string" + }, "method": { "description": "Method to use\n\nThis field must be set to `oidc` when using the oidc method.", "type": "string" From f303c1db9d21266addce3b42363f5a3a96d06682 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Tue, 12 Sep 2023 13:53:22 +0000 Subject: [PATCH 080/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5ce772a852a..e7f2bb19a137 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-09-08)](#2023-09-08) +- [ (2023-09-12)](#2023-09-12) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -310,7 +310,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-09-08) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-09-12) ## Breaking Changes @@ -561,12 +561,23 @@ https://github.com/ory/kratos/pull/3480 - chore: synchronize workspaces +- Support auth_type parameter + ([#3487](https://github.com/ory/kratos/issues/3487)) + ([fc30304](https://github.com/ory/kratos/commit/fc303040b71139f512fd1491ce30f80837b940b9)): + + The Facebook OIDC provider supports an auth_type parameter that when set to + "reauthenticate" will force the user to reauthenticate (similar to + `prompt=login` for other Providers). + - Support multiple origins for WebAuthN ([#3380](https://github.com/ory/kratos/issues/3380)) ([013f335](https://github.com/ory/kratos/commit/013f335881831bbf90ac31b219b57118fc089fe6)): Users can now supply a list of origins for webauthn in the configuration. +- Support native social sign using apple sdk + ([#3476](https://github.com/ory/kratos/issues/3476)) + ([f561013](https://github.com/ory/kratos/commit/f561013dd737dadcc82c4ec049fde12861e91e43)) - Transmit current session ID to Hydra when accepting the login ([#3426](https://github.com/ory/kratos/issues/3426)) ([610c76d](https://github.com/ory/kratos/commit/610c76d9140f2f43217ac55094051a994ea83ecc)): From df74339802d98a292abb32806eca35fb2554960b Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Wed, 13 Sep 2023 13:24:44 +0200 Subject: [PATCH 081/282] feat: emit error details when we find stray cookies in an API flow (#3496) --- selfservice/flow/request.go | 14 ++++++-------- selfservice/flow/request_test.go | 26 ++++++++++++++++++-------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/selfservice/flow/request.go b/selfservice/flow/request.go index 6c7bc9709525..1fe427c5b4fe 100644 --- a/selfservice/flow/request.go +++ b/selfservice/flow/request.go @@ -30,9 +30,8 @@ var ErrOriginHeaderNeedsBrowserFlow = herodot.ErrBadRequest. var ErrCookieHeaderNeedsBrowserFlow = herodot.ErrBadRequest. WithReasonf(`The HTTP Request Header included the "Cookie" key, indicating that this request was made by a Browser. The flow however was initiated as an API request. To prevent potential misuse and mitigate several attack vectors including CSRF, the request has been blocked. Please consult the documentation.`) -func EnsureCSRF(reg interface { - config.Provider -}, +func EnsureCSRF( + reg config.Provider, r *http.Request, flowType Type, disableAPIFlowEnforcement bool, @@ -54,16 +53,15 @@ func EnsureCSRF(reg interface { } // Workaround for Cloudflare setting cookies that we can't control. - var hasCookie bool + var cookies []string for _, c := range r.Cookies() { if !strings.HasPrefix(c.Name, "__cf") { - hasCookie = true - break + cookies = append(cookies, c.Name) } } - if hasCookie { - return errors.WithStack(ErrCookieHeaderNeedsBrowserFlow) + if len(cookies) > 0 { + return errors.WithStack(ErrCookieHeaderNeedsBrowserFlow.WithDetail("found cookies", cookies)) } return nil diff --git a/selfservice/flow/request_test.go b/selfservice/flow/request_test.go index 17a7d9e2d0d3..477baae11810 100644 --- a/selfservice/flow/request_test.go +++ b/selfservice/flow/request_test.go @@ -14,6 +14,7 @@ import ( "github.com/stretchr/testify/assert" + "github.com/ory/herodot" "github.com/ory/kratos/driver/config" "github.com/ory/kratos/internal" "github.com/ory/kratos/selfservice/flow" @@ -33,22 +34,31 @@ func TestVerifyRequest(t *testing.T) { }, flow.TypeAPI, false, x.FakeCSRFTokenGenerator, ""), flow.ErrOriginHeaderNeedsBrowserFlow.Error()) require.EqualError(t, flow.EnsureCSRF(reg, &http.Request{ Header: http.Header{"Cookie": {"cookie=ory"}}, - }, flow.TypeAPI, false, x.FakeCSRFTokenGenerator, ""), flow.ErrCookieHeaderNeedsBrowserFlow.Error()) + }, flow.TypeAPI, false, x.FakeCSRFTokenGenerator, ""), flow.ErrCookieHeaderNeedsBrowserFlow.Error(), "should error because of cookie=ory") + + err := flow.EnsureCSRF(reg, &http.Request{ + Header: http.Header{"Cookie": {"cookie1=cookievalue", "cookie2=cookievalue"}}, + }, flow.TypeAPI, false, x.FakeCSRFTokenGenerator, "") + var he herodot.DetailsCarrier + require.ErrorAs(t, err, &he) + cs, ok := he.Details()["found cookies"].([]string) + require.True(t, ok) + require.ElementsMatch(t, cs, []string{"cookie1", "cookie2"}) // Cloudflare require.NoError(t, flow.EnsureCSRF(reg, &http.Request{ Header: http.Header{"Cookie": {"__cflb=0pg1RtZzPoPDprTf8gX3TJm8XF5hKZ4pZV74UCe7"}}, - }, flow.TypeAPI, false, x.FakeCSRFTokenGenerator, ""), flow.ErrCookieHeaderNeedsBrowserFlow.Error()) + }, flow.TypeAPI, false, x.FakeCSRFTokenGenerator, ""), "should ignore Cloudflare cookies") require.NoError(t, flow.EnsureCSRF(reg, &http.Request{ Header: http.Header{"Cookie": {"__cflb=0pg1RtZzPoPDprTf8gX3TJm8XF5hKZ4pZV74UCe7; __cfruid=0pg1RtZzPoPDprTf8gX3TJm8XF5hKZ4pZV74UCe7"}}, - }, flow.TypeAPI, false, x.FakeCSRFTokenGenerator, ""), flow.ErrCookieHeaderNeedsBrowserFlow.Error()) - require.Error(t, flow.EnsureCSRF(reg, &http.Request{ + }, flow.TypeAPI, false, x.FakeCSRFTokenGenerator, ""), "should ignore Cloudflare cookies") + require.EqualError(t, flow.EnsureCSRF(reg, &http.Request{ Header: http.Header{"Cookie": {"__cflb=0pg1RtZzPoPDprTf8gX3TJm8XF5hKZ4pZV74UCe7; __cfruid=0pg1RtZzPoPDprTf8gX3TJm8XF5hKZ4pZV74UCe7; some_cookie=some_value"}}, - }, flow.TypeAPI, false, x.FakeCSRFTokenGenerator, ""), flow.ErrCookieHeaderNeedsBrowserFlow.Error()) - require.Error(t, flow.EnsureCSRF(reg, &http.Request{ + }, flow.TypeAPI, false, x.FakeCSRFTokenGenerator, ""), flow.ErrCookieHeaderNeedsBrowserFlow.Error(), "should error because of some_cookie") + require.EqualError(t, flow.EnsureCSRF(reg, &http.Request{ Header: http.Header{"Cookie": {"some_cookie=some_value"}}, - }, flow.TypeAPI, false, x.FakeCSRFTokenGenerator, ""), flow.ErrCookieHeaderNeedsBrowserFlow.Error()) - require.NoError(t, flow.EnsureCSRF(reg, &http.Request{}, flow.TypeAPI, false, x.FakeCSRFTokenGenerator, ""), flow.ErrCookieHeaderNeedsBrowserFlow.Error()) + }, flow.TypeAPI, false, x.FakeCSRFTokenGenerator, ""), flow.ErrCookieHeaderNeedsBrowserFlow.Error(), "should error because of some_cookie") + require.NoError(t, flow.EnsureCSRF(reg, &http.Request{}, flow.TypeAPI, false, x.FakeCSRFTokenGenerator, ""), "no cookie, no error") } func TestMethodEnabledAndAllowed(t *testing.T) { From 159c13142a11d4a9cd006da5d0afdda9e0f94ca9 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Wed, 13 Sep 2023 12:38:23 +0000 Subject: [PATCH 082/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e7f2bb19a137..2c7d1045de97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-09-12)](#2023-09-12) +- [ (2023-09-13)](#2023-09-13) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -310,7 +310,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-09-12) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-09-13) ## Breaking Changes @@ -523,6 +523,9 @@ https://github.com/ory/kratos/pull/3480 This feature allows marking emails provided by social sign in providers as verified. +- Emit error details when we find stray cookies in an API flow + ([#3496](https://github.com/ory/kratos/issues/3496)) + ([df74339](https://github.com/ory/kratos/commit/df74339802d98a292abb32806eca35fb2554960b)) - Hot-reload CORS origins ([#3423](https://github.com/ory/kratos/issues/3423)) ([157d934](https://github.com/ory/kratos/commit/157d9345aeb04f371f9d85b70c89e8646e781333)) - Improve messages for easier i18n From f124ab5586781cdbfc0a0cfd11b4355bfc8a115c Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Thu, 14 Sep 2023 10:42:14 +0200 Subject: [PATCH 083/282] fix: ignore more cloudflare cookies (#3499) --- selfservice/flow/request.go | 3 ++- selfservice/flow/request_test.go | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/selfservice/flow/request.go b/selfservice/flow/request.go index 1fe427c5b4fe..6db872f43199 100644 --- a/selfservice/flow/request.go +++ b/selfservice/flow/request.go @@ -53,9 +53,10 @@ func EnsureCSRF( } // Workaround for Cloudflare setting cookies that we can't control. + // https://developers.cloudflare.com/fundamentals/reference/policies-compliances/cloudflare-cookies/ var cookies []string for _, c := range r.Cookies() { - if !strings.HasPrefix(c.Name, "__cf") { + if !(strings.HasPrefix(c.Name, "__cf") || strings.HasPrefix(c.Name, "_cf") || strings.HasPrefix(c.Name, "cf_")) { cookies = append(cookies, c.Name) } } diff --git a/selfservice/flow/request_test.go b/selfservice/flow/request_test.go index 477baae11810..adc47f6149c9 100644 --- a/selfservice/flow/request_test.go +++ b/selfservice/flow/request_test.go @@ -47,7 +47,7 @@ func TestVerifyRequest(t *testing.T) { // Cloudflare require.NoError(t, flow.EnsureCSRF(reg, &http.Request{ - Header: http.Header{"Cookie": {"__cflb=0pg1RtZzPoPDprTf8gX3TJm8XF5hKZ4pZV74UCe7"}}, + Header: http.Header{"Cookie": {"__cflb=0pg1RtZzPoPDprTf8gX3TJm8XF5hKZ4pZV74UCe7", "_cfuvid=blub", "cf_clearance=bla"}}, }, flow.TypeAPI, false, x.FakeCSRFTokenGenerator, ""), "should ignore Cloudflare cookies") require.NoError(t, flow.EnsureCSRF(reg, &http.Request{ Header: http.Header{"Cookie": {"__cflb=0pg1RtZzPoPDprTf8gX3TJm8XF5hKZ4pZV74UCe7; __cfruid=0pg1RtZzPoPDprTf8gX3TJm8XF5hKZ4pZV74UCe7"}}, From 57a3273055c6e8627dd0b736e881dba3fb0fe75d Mon Sep 17 00:00:00 2001 From: Patrik Date: Thu, 14 Sep 2023 10:44:19 +0200 Subject: [PATCH 084/282] fix: do not encode full config in multiple places (#3500) --- driver/config/config.go | 113 ++++++++++++---------------------------- go.mod | 4 +- go.sum | 8 +-- 3 files changed, 37 insertions(+), 88 deletions(-) diff --git a/driver/config/config.go b/driver/config/config.go index c0614d636894..4cdbff51aad2 100644 --- a/driver/config/config.go +++ b/driver/config/config.go @@ -22,11 +22,9 @@ import ( "github.com/go-webauthn/webauthn/webauthn" "github.com/gofrs/uuid" "github.com/inhies/go-bytesize" - kjson "github.com/knadh/koanf/parsers/json" "github.com/pkg/errors" "github.com/rs/cors" "github.com/stretchr/testify/require" - "github.com/tidwall/gjson" "go.opentelemetry.io/otel/trace" "golang.org/x/net/publicsuffix" @@ -38,7 +36,6 @@ import ( "github.com/ory/x/contextx" "github.com/ory/x/httpx" "github.com/ory/x/jsonschemax" - "github.com/ory/x/jsonx" "github.com/ory/x/logrusx" "github.com/ory/x/otelx" "github.com/ory/x/stringsx" @@ -684,23 +681,18 @@ func (p *Config) SelfServiceFlowRegistrationBeforeHooks(ctx context.Context) []S func (p *Config) selfServiceHooks(ctx context.Context, key string) []SelfServiceHook { pp := p.GetProvider(ctx) - - var hooks []SelfServiceHook - if !pp.Exists(key) { + val := pp.Get(key) + if val == nil { return []SelfServiceHook{} } - out, err := pp.Marshal(kjson.Parser()) + config, err := json.Marshal(val) if err != nil { p.l.WithError(err).Fatalf("Unable to decode values from configuration key: %s", key) } - config := gjson.GetBytes(out, key).Raw - if len(config) == 0 { - return []SelfServiceHook{} - } - - if err := jsonx.NewStrictDecoder(bytes.NewBufferString(config)).Decode(&hooks); err != nil { + var hooks []SelfServiceHook + if err := json.Unmarshal(config, &hooks); err != nil { p.l.WithError(err).Fatalf("Unable to encode value \"%s\" from configuration key: %s", config, key) } @@ -727,73 +719,48 @@ func (p *Config) SelfServiceFlowRegistrationAfterHooks(ctx context.Context, stra func (p *Config) SelfServiceStrategy(ctx context.Context, strategy string) *SelfServiceStrategy { pp := p.GetProvider(ctx) + config := json.RawMessage("{}") + basePath := fmt.Sprintf("%s.%s", ViperKeySelfServiceStrategyConfig, strategy) - config := "{}" - out, err := pp.Marshal(kjson.Parser()) + var err error + config, err = json.Marshal(pp.GetF(basePath+".config", config)) if err != nil { p.l.WithError(err).Warn("Unable to marshal self service strategy configuration.") - } else if c := gjson.GetBytes(out, - fmt.Sprintf("%s.%s.config", ViperKeySelfServiceStrategyConfig, strategy)).Raw; len(c) > 0 { - config = c - } - - basePath := fmt.Sprintf("%s.%s", ViperKeySelfServiceStrategyConfig, strategy) - enabledKey := fmt.Sprintf("%s.enabled", basePath) - s := &SelfServiceStrategy{ - Enabled: pp.Bool(enabledKey), - Config: json.RawMessage(config), + config = json.RawMessage("{}") } // The default value can easily be overwritten by setting e.g. `{"selfservice": "null"}` which means that // we need to forcibly set these values here: - if !pp.Exists(enabledKey) { - switch strategy { - case "otp": - case "password": - fallthrough - case "profile": - fallthrough - case "code": - s.Enabled = true - } + defaultEnabled := false + switch strategy { + case "code", "password", "profile": + defaultEnabled = true } - - if len(s.Config) == 0 { - s.Config = json.RawMessage("{}") + return &SelfServiceStrategy{ + Enabled: pp.BoolF(basePath+".enabled", defaultEnabled), + Config: config, } - - return s } func (p *Config) SelfServiceCodeStrategy(ctx context.Context) *SelfServiceStrategyCode { pp := p.GetProvider(ctx) + config := json.RawMessage("{}") + basePath := ViperKeySelfServiceStrategyConfig + ".code" - config := "{}" - out, err := pp.Marshal(kjson.Parser()) + var err error + config, err = json.Marshal(pp.GetF(basePath+".config", config)) if err != nil { p.l.WithError(err).Warn("Unable to marshal self service strategy configuration.") - } else if c := gjson.GetBytes(out, - fmt.Sprintf("%s.%s.config", ViperKeySelfServiceStrategyConfig, "code")).Raw; len(c) > 0 { - config = c + config = json.RawMessage("{}") } - basePath := fmt.Sprintf("%s.%s", ViperKeySelfServiceStrategyConfig, "code") - enabledKey := fmt.Sprintf("%s.enabled", basePath) - passwordlessKey := fmt.Sprintf("%s.passwordless_enabled", basePath) - - s := &SelfServiceStrategyCode{ + return &SelfServiceStrategyCode{ SelfServiceStrategy: &SelfServiceStrategy{ - Enabled: pp.Bool(enabledKey), - Config: json.RawMessage(config), + Enabled: pp.BoolF(basePath+".enabled", true), + Config: config, }, - PasswordlessEnabled: pp.Bool(passwordlessKey), - } - - if !pp.Exists(enabledKey) { - s.PasswordlessEnabled = false - s.Enabled = true + PasswordlessEnabled: pp.BoolF(basePath+".passwordless_enabled", false), } - return s } func (p *Config) SecretsDefault(ctx context.Context) [][]byte { @@ -1036,18 +1003,13 @@ func (p *Config) CourierEmailRequestConfig(ctx context.Context) json.RawMessage return nil } - out, err := p.GetProvider(ctx).Marshal(kjson.Parser()) + config, err := json.Marshal(p.GetProvider(ctx).Get(ViperKeyCourierHTTPRequestConfig)) if err != nil { p.l.WithError(err).Warn("Unable to marshal mailer request configuration.") return nil } - config := gjson.GetBytes(out, ViperKeyCourierHTTPRequestConfig).Raw - if len(config) <= 0 { - return json.RawMessage("{}") - } - - return json.RawMessage(config) + return config } func (p *Config) CourierSMTPClientCertPath(ctx context.Context) string { @@ -1087,18 +1049,13 @@ func (p *Config) CourierTemplatesHelper(ctx context.Context, key string) *Courie return courierTemplate } - out, err := p.GetProvider(ctx).Marshal(kjson.Parser()) + config, err := json.Marshal(p.GetProvider(ctx).Get(key)) if err != nil { p.l.WithError(err).Fatalf("Unable to dencode values from %s.", key) return courierTemplate } - config := gjson.GetBytes(out, key).Raw - if len(config) == 0 { - return courierTemplate - } - - if err := json.NewDecoder(bytes.NewBufferString(config)).Decode(&courierTemplate); err != nil { + if err := json.Unmarshal(config, courierTemplate); err != nil { p.l.WithError(err).Fatalf("Unable to encode values from %s.", key) return courierTemplate } @@ -1158,18 +1115,12 @@ func (p *Config) CourierSMSRequestConfig(ctx context.Context) json.RawMessage { return nil } - out, err := p.GetProvider(ctx).Marshal(kjson.Parser()) + config, err := json.Marshal(p.GetProvider(ctx).Get(ViperKeyCourierSMSRequestConfig)) if err != nil { p.l.WithError(err).Warn("Unable to marshal SMS request configuration.") - return nil - } - - config := gjson.GetBytes(out, ViperKeyCourierSMSRequestConfig).Raw - if len(config) <= 0 { return json.RawMessage("{}") } - - return json.RawMessage(config) + return config } func (p *Config) CourierSMSFrom(ctx context.Context) string { diff --git a/go.mod b/go.mod index 8d674ff157d0..6f489ac3b3ae 100644 --- a/go.mod +++ b/go.mod @@ -80,6 +80,7 @@ require ( github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 github.com/pkg/errors v0.9.1 github.com/pquerna/otp v1.4.0 + github.com/rakutentech/jwk-go v1.1.3 github.com/rs/cors v1.8.2 github.com/samber/lo v1.37.0 github.com/sirupsen/logrus v1.9.0 @@ -140,7 +141,6 @@ require ( github.com/fatih/structs v1.1.0 // indirect github.com/felixge/fgprof v0.9.3 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect - github.com/form3tech-oss/jwt-go v3.2.5+incompatible // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fxamacker/cbor/v2 v2.4.0 // indirect github.com/go-crypt/x v0.2.1 // indirect @@ -172,7 +172,6 @@ require ( github.com/goccy/go-yaml v1.9.6 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/golang/glog v1.1.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/btree v1.0.1 // indirect @@ -262,7 +261,6 @@ require ( github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect - github.com/rakutentech/jwk-go v1.1.3 // indirect github.com/rjeczalik/notify v0.0.0-20181126183243-629144ba06a1 // indirect github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/seatgeek/logrus-gelf-formatter v0.0.0-20210414080842-5b05eb8ff761 // indirect diff --git a/go.sum b/go.sum index 87fe4c8ce7b9..ab00679edf54 100644 --- a/go.sum +++ b/go.sum @@ -200,8 +200,6 @@ github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNu github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/form3tech-oss/jwt-go v3.2.5+incompatible h1:/l4kBbb4/vGSsdtB5nUe8L7B9mImVMaBPw9L/0TBHU8= -github.com/form3tech-oss/jwt-go v3.2.5+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -360,8 +358,6 @@ github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRx github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= -github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/gddo v0.0.0-20190904175337-72a348e765d2 h1:xisWqjiKEff2B0KfFYGpCqc3M3zdTz+OHQHRc09FeYk= @@ -784,6 +780,7 @@ github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nyaruka/phonenumbers v1.1.6 h1:DcueYq7QrOArAprAYNoQfDgp0KetO4LqtnBtQC6Wyes= github.com/nyaruka/phonenumbers v1.1.6/go.mod h1:yShPJHDSH3aTKzCbXyVxNpbl2kA+F+Ne5Pun/MvFRos= github.com/ogier/pflag v0.0.1 h1:RW6JSWSu/RkSatfcLtogGfFgpim5p7ARQ10ECk5O750= @@ -792,8 +789,10 @@ github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= @@ -1578,6 +1577,7 @@ gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 h1:6D+BvnJ/j6e222UW gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473/go.mod h1:N1eN2tsCx0Ydtgjl4cqmbRCsY4/+z4cYDeqwZTk6zog= gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/validator.v2 v2.0.0-20180514200540-135c24b11c19/go.mod h1:o4V0GXN9/CAmCsvJ0oXYZvrZOe7syiDZSN1GWGZTGzc= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= From 7939bd34bb6d597272aa5d8a0954544525a93bec Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Thu, 14 Sep 2023 10:03:47 +0000 Subject: [PATCH 085/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 166 +++++++++++++++++++++++++++++---------------------- 1 file changed, 93 insertions(+), 73 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c7d1045de97..965c7cb20a09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-09-13)](#2023-09-13) +- [ (2023-09-14)](#2023-09-14) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -35,200 +35,203 @@ - [Features](#features-3) - [Tests](#tests-3) - [0.11.0 (2022-12-02)](#0110-2022-12-02) + - [Code Generation](#code-generation-3) + - [Features](#features-4) +- [0.11.0-alpha.0.pre.2 (2022-11-28)](#0110-alpha0pre2-2022-11-28) - [Breaking Changes](#breaking-changes-3) - [Bug Fixes](#bug-fixes-4) - - [Code Generation](#code-generation-3) + - [Code Generation](#code-generation-4) - [Code Refactoring](#code-refactoring-1) - [Documentation](#documentation-4) - - [Features](#features-4) + - [Features](#features-5) - [Reverts](#reverts) - [Tests](#tests-4) - [Unclassified](#unclassified-2) - [0.10.1 (2022-06-01)](#0101-2022-06-01) - [Bug Fixes](#bug-fixes-5) - - [Code Generation](#code-generation-4) + - [Code Generation](#code-generation-5) - [0.10.0 (2022-05-30)](#0100-2022-05-30) - [Breaking Changes](#breaking-changes-4) - [Bug Fixes](#bug-fixes-6) - - [Code Generation](#code-generation-5) + - [Code Generation](#code-generation-6) - [Code Refactoring](#code-refactoring-2) - [Documentation](#documentation-5) - - [Features](#features-5) + - [Features](#features-6) - [Tests](#tests-5) - [Unclassified](#unclassified-3) - [0.9.0-alpha.3 (2022-03-25)](#090-alpha3-2022-03-25) - [Breaking Changes](#breaking-changes-5) - [Bug Fixes](#bug-fixes-7) - - [Code Generation](#code-generation-6) + - [Code Generation](#code-generation-7) - [Documentation](#documentation-6) - [0.9.0-alpha.2 (2022-03-22)](#090-alpha2-2022-03-22) - [Bug Fixes](#bug-fixes-8) - - [Code Generation](#code-generation-7) + - [Code Generation](#code-generation-8) - [0.9.0-alpha.1 (2022-03-21)](#090-alpha1-2022-03-21) - [Breaking Changes](#breaking-changes-6) - [Bug Fixes](#bug-fixes-9) - - [Code Generation](#code-generation-8) + - [Code Generation](#code-generation-9) - [Code Refactoring](#code-refactoring-3) - [Documentation](#documentation-7) - - [Features](#features-6) + - [Features](#features-7) - [Tests](#tests-6) - [Unclassified](#unclassified-4) - [0.8.3-alpha.1.pre.0 (2022-01-21)](#083-alpha1pre0-2022-01-21) - [Breaking Changes](#breaking-changes-7) - [Bug Fixes](#bug-fixes-10) - - [Code Generation](#code-generation-9) + - [Code Generation](#code-generation-10) - [Code Refactoring](#code-refactoring-4) - [Documentation](#documentation-8) - - [Features](#features-7) + - [Features](#features-8) - [Tests](#tests-7) - [0.8.2-alpha.1 (2021-12-17)](#082-alpha1-2021-12-17) - [Bug Fixes](#bug-fixes-11) - - [Code Generation](#code-generation-10) + - [Code Generation](#code-generation-11) - [Documentation](#documentation-9) - [0.8.1-alpha.1 (2021-12-13)](#081-alpha1-2021-12-13) - [Bug Fixes](#bug-fixes-12) - - [Code Generation](#code-generation-11) + - [Code Generation](#code-generation-12) - [Documentation](#documentation-10) - - [Features](#features-8) + - [Features](#features-9) - [Tests](#tests-8) - [0.8.0-alpha.4.pre.0 (2021-11-09)](#080-alpha4pre0-2021-11-09) - [Breaking Changes](#breaking-changes-8) - [Bug Fixes](#bug-fixes-13) - - [Code Generation](#code-generation-12) + - [Code Generation](#code-generation-13) - [Documentation](#documentation-11) - - [Features](#features-9) + - [Features](#features-10) - [Tests](#tests-9) - [0.8.0-alpha.3 (2021-10-28)](#080-alpha3-2021-10-28) - [Bug Fixes](#bug-fixes-14) - - [Code Generation](#code-generation-13) -- [0.8.0-alpha.2 (2021-10-28)](#080-alpha2-2021-10-28) - [Code Generation](#code-generation-14) +- [0.8.0-alpha.2 (2021-10-28)](#080-alpha2-2021-10-28) + - [Code Generation](#code-generation-15) - [0.8.0-alpha.1 (2021-10-27)](#080-alpha1-2021-10-27) - [Breaking Changes](#breaking-changes-9) - [Bug Fixes](#bug-fixes-15) - - [Code Generation](#code-generation-15) + - [Code Generation](#code-generation-16) - [Code Refactoring](#code-refactoring-5) - [Documentation](#documentation-12) - - [Features](#features-10) + - [Features](#features-11) - [Reverts](#reverts-1) - [Tests](#tests-10) - [Unclassified](#unclassified-5) - [0.7.6-alpha.1 (2021-09-12)](#076-alpha1-2021-09-12) - - [Code Generation](#code-generation-16) -- [0.7.5-alpha.1 (2021-09-11)](#075-alpha1-2021-09-11) - [Code Generation](#code-generation-17) +- [0.7.5-alpha.1 (2021-09-11)](#075-alpha1-2021-09-11) + - [Code Generation](#code-generation-18) - [0.7.4-alpha.1 (2021-09-09)](#074-alpha1-2021-09-09) - [Bug Fixes](#bug-fixes-16) - - [Code Generation](#code-generation-18) + - [Code Generation](#code-generation-19) - [Documentation](#documentation-13) - - [Features](#features-11) + - [Features](#features-12) - [Tests](#tests-11) - [0.7.3-alpha.1 (2021-08-28)](#073-alpha1-2021-08-28) - [Bug Fixes](#bug-fixes-17) - - [Code Generation](#code-generation-19) + - [Code Generation](#code-generation-20) - [Documentation](#documentation-14) - - [Features](#features-12) + - [Features](#features-13) - [0.7.1-alpha.1 (2021-07-22)](#071-alpha1-2021-07-22) - [Bug Fixes](#bug-fixes-18) - - [Code Generation](#code-generation-20) + - [Code Generation](#code-generation-21) - [Documentation](#documentation-15) - [Tests](#tests-12) - [0.7.0-alpha.1 (2021-07-13)](#070-alpha1-2021-07-13) - [Breaking Changes](#breaking-changes-10) - [Bug Fixes](#bug-fixes-19) - - [Code Generation](#code-generation-21) + - [Code Generation](#code-generation-22) - [Code Refactoring](#code-refactoring-6) - [Documentation](#documentation-16) - - [Features](#features-13) + - [Features](#features-14) - [Tests](#tests-13) - [Unclassified](#unclassified-6) - [0.6.3-alpha.1 (2021-05-17)](#063-alpha1-2021-05-17) - [Breaking Changes](#breaking-changes-11) - [Bug Fixes](#bug-fixes-20) - - [Code Generation](#code-generation-22) + - [Code Generation](#code-generation-23) - [Code Refactoring](#code-refactoring-7) - [0.6.2-alpha.1 (2021-05-14)](#062-alpha1-2021-05-14) - - [Code Generation](#code-generation-23) + - [Code Generation](#code-generation-24) - [Documentation](#documentation-17) - [0.6.1-alpha.1 (2021-05-11)](#061-alpha1-2021-05-11) - - [Code Generation](#code-generation-24) - - [Features](#features-14) -- [0.6.0-alpha.2 (2021-05-07)](#060-alpha2-2021-05-07) - - [Bug Fixes](#bug-fixes-21) - [Code Generation](#code-generation-25) - [Features](#features-15) +- [0.6.0-alpha.2 (2021-05-07)](#060-alpha2-2021-05-07) + - [Bug Fixes](#bug-fixes-21) + - [Code Generation](#code-generation-26) + - [Features](#features-16) - [0.6.0-alpha.1 (2021-05-05)](#060-alpha1-2021-05-05) - [Breaking Changes](#breaking-changes-12) - [Bug Fixes](#bug-fixes-22) - - [Code Generation](#code-generation-26) + - [Code Generation](#code-generation-27) - [Code Refactoring](#code-refactoring-8) - [Documentation](#documentation-18) - - [Features](#features-16) + - [Features](#features-17) - [Tests](#tests-14) - [Unclassified](#unclassified-7) - [0.5.5-alpha.1 (2020-12-09)](#055-alpha1-2020-12-09) - [Bug Fixes](#bug-fixes-23) - - [Code Generation](#code-generation-27) + - [Code Generation](#code-generation-28) - [Documentation](#documentation-19) - - [Features](#features-17) + - [Features](#features-18) - [Tests](#tests-15) - [Unclassified](#unclassified-8) - [0.5.4-alpha.1 (2020-11-11)](#054-alpha1-2020-11-11) - [Bug Fixes](#bug-fixes-24) - - [Code Generation](#code-generation-28) + - [Code Generation](#code-generation-29) - [Code Refactoring](#code-refactoring-9) - [Documentation](#documentation-20) - - [Features](#features-18) + - [Features](#features-19) - [0.5.3-alpha.1 (2020-10-27)](#053-alpha1-2020-10-27) - [Bug Fixes](#bug-fixes-25) - - [Code Generation](#code-generation-29) + - [Code Generation](#code-generation-30) - [Documentation](#documentation-21) - - [Features](#features-19) + - [Features](#features-20) - [Tests](#tests-16) - [0.5.2-alpha.1 (2020-10-22)](#052-alpha1-2020-10-22) - [Bug Fixes](#bug-fixes-26) - - [Code Generation](#code-generation-30) + - [Code Generation](#code-generation-31) - [Documentation](#documentation-22) - [Tests](#tests-17) - [0.5.1-alpha.1 (2020-10-20)](#051-alpha1-2020-10-20) - [Bug Fixes](#bug-fixes-27) - - [Code Generation](#code-generation-31) + - [Code Generation](#code-generation-32) - [Documentation](#documentation-23) - - [Features](#features-20) + - [Features](#features-21) - [Tests](#tests-18) - [Unclassified](#unclassified-9) - [0.5.0-alpha.1 (2020-10-15)](#050-alpha1-2020-10-15) - [Breaking Changes](#breaking-changes-13) - [Bug Fixes](#bug-fixes-28) - - [Code Generation](#code-generation-32) + - [Code Generation](#code-generation-33) - [Code Refactoring](#code-refactoring-10) - [Documentation](#documentation-24) - - [Features](#features-21) + - [Features](#features-22) - [Tests](#tests-19) - [Unclassified](#unclassified-10) - [0.4.6-alpha.1 (2020-07-13)](#046-alpha1-2020-07-13) - [Bug Fixes](#bug-fixes-29) - - [Code Generation](#code-generation-33) + - [Code Generation](#code-generation-34) - [0.4.5-alpha.1 (2020-07-13)](#045-alpha1-2020-07-13) - [Bug Fixes](#bug-fixes-30) - - [Code Generation](#code-generation-34) + - [Code Generation](#code-generation-35) - [0.4.4-alpha.1 (2020-07-10)](#044-alpha1-2020-07-10) - [Bug Fixes](#bug-fixes-31) - - [Code Generation](#code-generation-35) + - [Code Generation](#code-generation-36) - [Documentation](#documentation-25) - [0.4.3-alpha.1 (2020-07-08)](#043-alpha1-2020-07-08) - [Bug Fixes](#bug-fixes-32) - - [Code Generation](#code-generation-36) + - [Code Generation](#code-generation-37) - [0.4.2-alpha.1 (2020-07-08)](#042-alpha1-2020-07-08) - [Bug Fixes](#bug-fixes-33) - - [Code Generation](#code-generation-37) + - [Code Generation](#code-generation-38) - [0.4.0-alpha.1 (2020-07-08)](#040-alpha1-2020-07-08) - [Breaking Changes](#breaking-changes-14) - [Bug Fixes](#bug-fixes-34) - - [Code Generation](#code-generation-38) + - [Code Generation](#code-generation-39) - [Code Refactoring](#code-refactoring-11) - [Documentation](#documentation-26) - - [Features](#features-22) + - [Features](#features-23) - [Unclassified](#unclassified-11) - [0.3.0-alpha.1 (2020-05-15)](#030-alpha1-2020-05-15) - [Breaking Changes](#breaking-changes-15) @@ -236,7 +239,7 @@ - [Chores](#chores) - [Code Refactoring](#code-refactoring-12) - [Documentation](#documentation-27) - - [Features](#features-23) + - [Features](#features-24) - [Unclassified](#unclassified-12) - [0.2.1-alpha.1 (2020-05-05)](#021-alpha1-2020-05-05) - [Chores](#chores-1) @@ -247,7 +250,7 @@ - [Chores](#chores-2) - [Code Refactoring](#code-refactoring-13) - [Documentation](#documentation-29) - - [Features](#features-24) + - [Features](#features-25) - [Unclassified](#unclassified-13) - [0.1.1-alpha.1 (2020-02-18)](#011-alpha1-2020-02-18) - [Bug Fixes](#bug-fixes-37) @@ -257,10 +260,10 @@ - [Bug Fixes](#bug-fixes-38) - [Code Refactoring](#code-refactoring-15) - [Documentation](#documentation-31) - - [Features](#features-25) + - [Features](#features-26) - [0.1.0-alpha.5 (2020-02-06)](#010-alpha5-2020-02-06) - [Documentation](#documentation-32) - - [Features](#features-26) + - [Features](#features-27) - [0.1.0-alpha.4 (2020-02-06)](#010-alpha4-2020-02-06) - [Continuous Integration](#continuous-integration) - [Documentation](#documentation-33) @@ -269,7 +272,7 @@ - [0.1.0-alpha.2 (2020-02-03)](#010-alpha2-2020-02-03) - [Bug Fixes](#bug-fixes-39) - [Documentation](#documentation-34) - - [Features](#features-27) + - [Features](#features-28) - [Unclassified](#unclassified-14) - [0.1.0-alpha.1 (2020-01-31)](#010-alpha1-2020-01-31) - [Documentation](#documentation-35) @@ -310,7 +313,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-09-13) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-09-14) ## Breaking Changes @@ -373,6 +376,9 @@ https://github.com/ory/kratos/pull/3480 - Code method on registration and 2fa ([#3481](https://github.com/ory/kratos/issues/3481)) ([7aa2e29](https://github.com/ory/kratos/commit/7aa2e293175d0f4b6c13552cc3781f54f8caf3a0)) +- Do not encode full config in multiple places + ([#3500](https://github.com/ory/kratos/issues/3500)) + ([57a3273](https://github.com/ory/kratos/commit/57a3273055c6e8627dd0b736e881dba3fb0fe75d)) - Don't require session for OIDC verification ([#3443](https://github.com/ory/kratos/issues/3443)) ([e08f831](https://github.com/ory/kratos/commit/e08f831c2715e515bf58dc2dbb47fc3576421a5c)) @@ -389,6 +395,9 @@ https://github.com/ory/kratos/pull/3480 Adds correct pagination parameters to the SDK methods for listing identities and sessions. +- Ignore more cloudflare cookies + ([#3499](https://github.com/ory/kratos/issues/3499)) + ([f124ab5](https://github.com/ory/kratos/commit/f124ab5586781cdbfc0a0cfd11b4355bfc8a115c)) - Issue session after verification after registration with OIDC SSO ([#3467](https://github.com/ory/kratos/issues/3467)) ([a28b523](https://github.com/ory/kratos/commit/a28b523238743f3873b51479eea3b86d684092f9)) @@ -1588,7 +1597,7 @@ The `/admin/courier/messages` endpoint now uses `keysetpagination` instead. ([#3000](https://github.com/ory/kratos/issues/3000)) ([6d26e5c](https://github.com/ory/kratos/commit/6d26e5c735a28ecb8b2d8cd142751ef679e19e86)) -# [0.11.0](https://github.com/ory/kratos/compare/v0.10.1...v0.11.0) (2022-12-02) +# [0.11.0](https://github.com/ory/kratos/compare/v0.11.0-alpha.0.pre.2...v0.11.0) (2022-12-02) The 2022 winter release of Ory Kratos is here, and we are extremely excited to share with you some of the highlights included: @@ -1613,6 +1622,25 @@ Please read the changelog carefully to identify changes which might affect you. Always test upgrading with a copy of your production system before applying the upgrade in production. +### Code Generation + +- Pin v0.11.0 release commit + ([59c30b6](https://github.com/ory/kratos/commit/59c30b6860b56990e132416366e0ae6abe7a275f)) + +### Features + +- Forward parsed request cookies to webhook Jsonnet snippet + ([#2917](https://github.com/ory/kratos/issues/2917)) + ([70ed068](https://github.com/ory/kratos/commit/70ed068debe7a711ba36e2eb4fcf60be8cae4681)): + + Request cookies were already available in raw form in the ctx.request_headers + top-level argument to the Jsonnet snippet. Parsing cookies in Jsonnet is + tedious and error-prone, though, so we parse them internally for convenience. + +# [0.11.0-alpha.0.pre.2](https://github.com/ory/kratos/compare/v0.10.1...v0.11.0-alpha.0.pre.2) (2022-11-28) + +autogen: pin v0.11.0-alpha.0.pre.2 release commit + ## Breaking Changes This patch changes the behavior of the recovery flow. It introduces a new @@ -1874,8 +1902,8 @@ SDK Method `getJsonSchema` was renamed to `getIdentitySchema`. ### Code Generation -- Pin v0.11.0 release commit - ([59c30b6](https://github.com/ory/kratos/commit/59c30b6860b56990e132416366e0ae6abe7a275f)) +- Pin v0.11.0-alpha.0.pre.2 release commit + ([624e1f0](https://github.com/ory/kratos/commit/624e1f0d23b1c58bc28b2eaf845d4ef63e64bdba)) ### Code Refactoring @@ -2024,14 +2052,6 @@ SDK Method `getJsonSchema` was renamed to `getIdentitySchema`. ([#2406](https://github.com/ory/kratos/issues/2406)) ([29d6376](https://github.com/ory/kratos/commit/29d6376e22e4de617ec63ca0a5dcb4dbf34c7c37)), closes [#952](https://github.com/ory/kratos/issues/952) -- Forward parsed request cookies to webhook Jsonnet snippet - ([#2917](https://github.com/ory/kratos/issues/2917)) - ([70ed068](https://github.com/ory/kratos/commit/70ed068debe7a711ba36e2eb4fcf60be8cae4681)): - - Request cookies were already available in raw form in the ctx.request_headers - top-level argument to the Jsonnet snippet. Parsing cookies in Jsonnet is - tedious and error-prone, though, so we parse them internally for convenience. - - Handler for update API with credentials ([#2423](https://github.com/ory/kratos/issues/2423)) ([561187d](https://github.com/ory/kratos/commit/561187dafe2fea324d55c4efe3ffa6b65f9bed72)), From 622018459ddb16c182da49dfd91fd1c6ef8c6b73 Mon Sep 17 00:00:00 2001 From: Alano Terblanche <18033717+Benehiko@users.noreply.github.com> Date: Fri, 15 Sep 2023 14:32:27 +0200 Subject: [PATCH 086/282] fix: registration code ui nodes group (#3505) * fix: registration code ui nodes group * style: format --- selfservice/strategy/code/strategy.go | 6 +++--- test/e2e/cypress/support/commands.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/selfservice/strategy/code/strategy.go b/selfservice/strategy/code/strategy.go index 94c8de75e9b6..229c6dfaf8d1 100644 --- a/selfservice/strategy/code/strategy.go +++ b/selfservice/strategy/code/strategy.go @@ -162,13 +162,13 @@ func (s *Strategy) PopulateMethod(r *http.Request, f flow.Flow) error { // set the traits on the default group so that the ui can render them // this prevents having multiple of the same ui fields on the same ui form - traitNodes, err := container.NodesFromJSONSchema(r.Context(), node.CodeGroup, ds.String(), "", nil) + traitNodes, err := container.NodesFromJSONSchema(r.Context(), node.DefaultGroup, ds.String(), "", nil) if err != nil { return err } for _, n := range traitNodes { - nodes.Append(n) + nodes.Upsert(n) } } @@ -240,7 +240,7 @@ func (s *Strategy) PopulateMethod(r *http.Request, f flow.Flow) error { continue } - if n.Group == node.CodeGroup { + if n.Group == node.DefaultGroup { freshNodes = append(freshNodes, n) } } diff --git a/test/e2e/cypress/support/commands.ts b/test/e2e/cypress/support/commands.ts index c2aa9e98bbc6..b7ccff939add 100644 --- a/test/e2e/cypress/support/commands.ts +++ b/test/e2e/cypress/support/commands.ts @@ -426,7 +426,7 @@ Cypress.Commands.add( expect( body.ui.nodes.find( (f: UiNode) => - f.group === "code" && + f.group === "default" && "name" in f.attributes && f.attributes.name === "traits.email", ).attributes.value, From 44aa74fe330e18c1fd5ad57ec4fd6dd6b467e1a9 Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Fri, 15 Sep 2023 15:30:07 +0200 Subject: [PATCH 087/282] chore: upgrade ory/x to v0.0.589 (#3509) --- go.mod | 3 ++- go.sum | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 6f489ac3b3ae..3b86d4e92abd 100644 --- a/go.mod +++ b/go.mod @@ -76,7 +76,7 @@ require ( github.com/ory/jsonschema/v3 v3.0.8 github.com/ory/mail/v3 v3.0.0 github.com/ory/nosurf v1.2.7 - github.com/ory/x v0.0.588 + github.com/ory/x v0.0.589 github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 github.com/pkg/errors v0.9.1 github.com/pquerna/otp v1.4.0 @@ -143,6 +143,7 @@ require ( github.com/felixge/httpsnoop v1.0.3 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fxamacker/cbor/v2 v2.4.0 // indirect + github.com/go-bindata/go-bindata v3.1.2+incompatible // indirect github.com/go-crypt/x v0.2.1 // indirect github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect diff --git a/go.sum b/go.sum index ab00679edf54..a54b199a2b27 100644 --- a/go.sum +++ b/go.sum @@ -209,6 +209,8 @@ github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-bindata/go-bindata v3.1.2+incompatible h1:5vjJMVhowQdPzjE1LdxyFF7YFTXg5IgGVW4gBr5IbvE= +github.com/go-bindata/go-bindata v3.1.2+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo= github.com/go-crypt/crypt v0.2.9 h1:5gWWTId2Qyqs9ROIsegt5pnqo9wUSRLbhpkR6JSftjg= github.com/go-crypt/crypt v0.2.9/go.mod h1:JjzdTYE2mArb6nBoIvvpF7o46/rK/1pfmlArCRMTFUk= github.com/go-crypt/x v0.2.1 h1:OGw78Bswme9lffCOX6tyuC280ouU5391glsvThMtM5U= @@ -827,6 +829,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/x v0.0.588 h1:3qoC1d7qTKnMLwS3Os7KVbDLeSOUHXON8hUFuGUoScQ= github.com/ory/x v0.0.588/go.mod h1:ksLBEd6iW6czGpE6eNA0gCIxO1FFeqIxCZgsgwNrzMM= +github.com/ory/x v0.0.589 h1:ZNQ+nBzTCm3jI2ZZY/1kGWSE4jEtyvDYWu0ScfLgzac= +github.com/ory/x v0.0.589/go.mod h1:ksLBEd6iW6czGpE6eNA0gCIxO1FFeqIxCZgsgwNrzMM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= From dd5a9f38c5102b536b0bfd19d825331bf3fb6018 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Fri, 15 Sep 2023 14:31:49 +0000 Subject: [PATCH 088/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 965c7cb20a09..9706e4252d32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-09-14)](#2023-09-14) +- [ (2023-09-15)](#2023-09-15) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -313,7 +313,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-09-14) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-09-15) ## Breaking Changes @@ -427,6 +427,14 @@ https://github.com/ory/kratos/pull/3480 Significantly improves performance by reducing the amount of queries we need to do when checking for the different AAL levels. +- Registration code ui nodes group + ([#3505](https://github.com/ory/kratos/issues/3505)) + ([6220184](https://github.com/ory/kratos/commit/622018459ddb16c182da49dfd91fd1c6ef8c6b73)): + + - fix: registration code ui nodes group + + - style: format + - Registration with verification ([#3451](https://github.com/ory/kratos/issues/3451)) ([77c3196](https://github.com/ory/kratos/commit/77c3196fd60c5927b84e9a7f6546f80ac2d78ee5)) From 47d5eb146568e1dfa47a596d7136b8b785970192 Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Mon, 18 Sep 2023 08:57:58 +0200 Subject: [PATCH 089/282] chore: allow node 18 (#3492) --- test/e2e/package-lock.json | 169 ++++++++++++++++++++----------------- test/e2e/package.json | 8 +- test/e2e/run.sh | 41 +++------ 3 files changed, 107 insertions(+), 111 deletions(-) diff --git a/test/e2e/package-lock.json b/test/e2e/package-lock.json index 0cd1fcf6a2a5..fa3ca9753eeb 100644 --- a/test/e2e/package-lock.json +++ b/test/e2e/package-lock.json @@ -20,7 +20,7 @@ "json-schema-to-typescript": "^12.0.0", "otplib": "^12.0.1", "typescript": "^4.7.4", - "wait-on": "5.3.0", + "wait-on": "7.0.1", "yamljs": "^0.3.0" } }, @@ -91,9 +91,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": { @@ -187,18 +187,18 @@ } }, "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" } }, "node_modules/@sideway/formula": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", - "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", "dev": true }, "node_modules/@sideway/pinpoint": { @@ -1680,15 +1680,15 @@ "dev": true }, "node_modules/joi": { - "version": "17.6.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.6.0.tgz", - "integrity": "sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw==", + "version": "17.10.1", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.10.1.tgz", + "integrity": "sha512-vIiDxQKmRidUVp8KngT8MZSOcmRVm2zV7jbMjNYWuHcJWI0bUck3nRTGQjhpPlQenIQIBC5Vp9AhcnHbWQqafw==", "dev": true, "dependencies": { "@hapi/hoek": "^9.0.0", "@hapi/topo": "^5.0.0", "@sideway/address": "^4.1.3", - "@sideway/formula": "^3.0.0", + "@sideway/formula": "^3.0.1", "@sideway/pinpoint": "^2.0.0" } }, @@ -2015,10 +2015,13 @@ } }, "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/mkdirp": { "version": "1.0.4", @@ -2342,9 +2345,9 @@ } }, "node_modules/rxjs": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.4.tgz", - "integrity": "sha512-h5M3Hk78r6wAheJF0a5YahB1yRQKCsZ4MsGdZ5O9ETbVtjPcScGfrMmoOq7EBsCRzd4BDkvDJ7ogP8Sz5tTFiQ==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, "dependencies": { "tslib": "^2.1.0" @@ -2687,42 +2690,48 @@ } }, "node_modules/wait-on": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-5.3.0.tgz", - "integrity": "sha512-DwrHrnTK+/0QFaB9a8Ol5Lna3k7WvUR4jzSKmz0YaPBpuN2sACyiPVKVfj6ejnjcajAcvn3wlbTyMIn9AZouOg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.0.1.tgz", + "integrity": "sha512-9AnJE9qTjRQOlTZIldAaf/da2eW0eSRSgcqq85mXQja/DW3MriHxkpODDSUEg+Gri/rKEcXUZHe+cevvYItaog==", "dev": true, "dependencies": { - "axios": "^0.21.1", - "joi": "^17.3.0", + "axios": "^0.27.2", + "joi": "^17.7.0", "lodash": "^4.17.21", - "minimist": "^1.2.5", - "rxjs": "^6.6.3" + "minimist": "^1.2.7", + "rxjs": "^7.8.0" }, "bin": { "wait-on": "bin/wait-on" }, "engines": { - "node": ">=8.9.0" + "node": ">=12.0.0" } }, - "node_modules/wait-on/node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "node_modules/wait-on/node_modules/axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", "dev": true, "dependencies": { - "tslib": "^1.9.0" + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } + }, + "node_modules/wait-on/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" }, "engines": { - "npm": ">=2.0.0" + "node": ">= 6" } }, - "node_modules/wait-on/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -2874,9 +2883,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": { @@ -2962,18 +2971,18 @@ } }, "@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" } }, "@sideway/formula": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", - "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", "dev": true }, "@sideway/pinpoint": { @@ -4104,15 +4113,15 @@ "dev": true }, "joi": { - "version": "17.6.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.6.0.tgz", - "integrity": "sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw==", + "version": "17.10.1", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.10.1.tgz", + "integrity": "sha512-vIiDxQKmRidUVp8KngT8MZSOcmRVm2zV7jbMjNYWuHcJWI0bUck3nRTGQjhpPlQenIQIBC5Vp9AhcnHbWQqafw==", "dev": true, "requires": { "@hapi/hoek": "^9.0.0", "@hapi/topo": "^5.0.0", "@sideway/address": "^4.1.3", - "@sideway/formula": "^3.0.0", + "@sideway/formula": "^3.0.1", "@sideway/pinpoint": "^2.0.0" } }, @@ -4373,9 +4382,9 @@ } }, "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true }, "mkdirp": { @@ -4616,9 +4625,9 @@ } }, "rxjs": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.4.tgz", - "integrity": "sha512-h5M3Hk78r6wAheJF0a5YahB1yRQKCsZ4MsGdZ5O9ETbVtjPcScGfrMmoOq7EBsCRzd4BDkvDJ7ogP8Sz5tTFiQ==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, "requires": { "tslib": "^2.1.0" @@ -4869,32 +4878,38 @@ } }, "wait-on": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-5.3.0.tgz", - "integrity": "sha512-DwrHrnTK+/0QFaB9a8Ol5Lna3k7WvUR4jzSKmz0YaPBpuN2sACyiPVKVfj6ejnjcajAcvn3wlbTyMIn9AZouOg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.0.1.tgz", + "integrity": "sha512-9AnJE9qTjRQOlTZIldAaf/da2eW0eSRSgcqq85mXQja/DW3MriHxkpODDSUEg+Gri/rKEcXUZHe+cevvYItaog==", "dev": true, "requires": { - "axios": "^0.21.1", - "joi": "^17.3.0", + "axios": "^0.27.2", + "joi": "^17.7.0", "lodash": "^4.17.21", - "minimist": "^1.2.5", - "rxjs": "^6.6.3" + "minimist": "^1.2.7", + "rxjs": "^7.8.0" }, "dependencies": { - "rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", "dev": true, "requires": { - "tslib": "^1.9.0" + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" } }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } } } }, diff --git a/test/e2e/package.json b/test/e2e/package.json index c3204c330060..7fb4aa522bc3 100644 --- a/test/e2e/package.json +++ b/test/e2e/package.json @@ -3,12 +3,12 @@ "version": "0.0.1", "scripts": { "openapi-generator-cli": "openapi-generator-cli", + "playwright": "playwright test", + "playwright:ui": "playwright test --ui", "test": "cypress run --browser chrome", "test:watch": "cypress open --browser chrome", "text-run": "exit 0", - "wait-on": "wait-on", - "playwright": "playwright test", - "playwright:ui": "playwright test --ui" + "wait-on": "wait-on" }, "devDependencies": { "@ory/kratos-client": "0.0.0-next.8d3b018594f7", @@ -23,7 +23,7 @@ "json-schema-to-typescript": "^12.0.0", "otplib": "^12.0.1", "typescript": "^4.7.4", - "wait-on": "5.3.0", + "wait-on": "7.0.1", "yamljs": "^0.3.0" } } diff --git a/test/e2e/run.sh b/test/e2e/run.sh index 553dcda30a79..6dba7949c779 100755 --- a/test/e2e/run.sh +++ b/test/e2e/run.sh @@ -2,24 +2,6 @@ echo "Running Ory Kratos E2E Tests..." echo "" - -NODE_VERSION=$(node -v) - -if [[ $NODE_VERSION =~ v([0-9]{1,2}).* ]]; then - MAJOR_NODE_VERSION=${BASH_REMATCH[1]} - if [[ $MAJOR_NODE_VERSION -gt 16 ]]; then - echo "It seems you are running this script using a node version newer than 16 ($NODE_VERSION)." - echo "Currently, this script will not work if not run using Node 16 (or lower) due to changes in the way Node 18 does network requests." - echo "Please use Node 16 instead." - echo "" - echo " Using nvm (https://github.com/nvm-sh/nvm):" - echo " $ nvm install 16" - exit - fi -else - echo "could not detect node version from string $NODE_VERSION. Continuing..." -fi - set -euxo pipefail cd "$(dirname "${BASH_SOURCE[0]}")/../.." @@ -138,14 +120,13 @@ prepare() { nc -zv localhost 4446 && exit 1 nc -zv localhost 4455 && exit 1 nc -zv localhost 19006 && exit 1 - nc -zv localhost 4456 && exit 1 + nc -zv localhost 4456 && exit 1 nc -zv localhost 4458 && exit 1 nc -zv localhost 4744 && exit 1 nc -zv localhost 4745 && exit 1 ( cd "$rn_ui_dir" - npm i expo-cli KRATOS_URL=http://localhost:4433 CI=1 npm run web \ >"${base}/test/e2e/rn-profile-app.e2e.log" 2>&1 & ) @@ -285,16 +266,16 @@ run() { (modd -f test/e2e/modd.conf >"${base}/test/e2e/kratos.e2e.log" 2>&1 &) - npm run wait-on -- -l -t 300000 http-get://localhost:4434/health/ready \ - http-get://localhost:4444/.well-known/openid-configuration \ - http-get://localhost:4455/health/ready \ - http-get://localhost:4445/health/ready \ - http-get://localhost:4446/ \ - http-get://localhost:4456/health/alive \ - http-get://localhost:19006/ \ - http-get://localhost:4437/mail \ - http-get://localhost:4458/ \ - http-get://localhost:4459/health + npm run wait-on -- -l -t 300000 http-get://127.0.0.1:4434/health/ready \ + http-get://127.0.0.1:4444/.well-known/openid-configuration \ + http-get://127.0.0.1:4455/health/ready \ + http-get://127.0.0.1:4445/health/ready \ + http-get://127.0.0.1:4446/ \ + http-get://127.0.0.1:4456/health/alive \ + http-get://127.0.0.1:19006/ \ + http-get://127.0.0.1:4437/mail \ + http-get://127.0.0.1:4458/ \ + http-get://127.0.0.1:4459/health echo "::endgroup::" if [[ $dev == "yes" ]]; then From 57b7bb846c8072f786ea6b80cd688fdee75805da Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Mon, 18 Sep 2023 10:52:36 +0300 Subject: [PATCH 090/282] feat: add ability to convert session to JWT when calling whoami (#3472) This patch adds a query parameter `tokenize_as` to `/session/whoami` which encodes the session to a JWT. It is possible to customize the JWT claims by using a JsonNet template, and furthermore change the expiry of the token. The tokenize feature supports multiple templates, which makes it easy to use the resulting JWT in a variety of use cases. Closes #2487 --- driver/config/config.go | 23 ++- driver/registry.go | 1 + driver/registry_default.go | 36 ++++- embedx/config.schema.json | 38 +++++ go.mod | 10 ++ go.sum | 34 ++++ internal/client-go/api_frontend.go | 28 ++++ internal/client-go/model_session.go | 37 +++++ internal/httpclient/api_frontend.go | 28 ++++ internal/httpclient/model_session.go | 37 +++++ persistence/sql/persister.go | 14 +- ...tTokenizer-case=es256-without-jsonnet.json | 8 + ...tTokenizer-case=es512-without-jsonnet.json | 8 + ...TestTokenizer-case=rs512-with-jsonnet.json | 12 ++ session/handler.go | 34 +++- session/handler_test.go | 27 ++++ session/session.go | 5 + session/stub/jwk.es256.json | 14 ++ session/stub/jwk.es512.json | 14 ++ session/stub/jwk.rs512.json | 18 +++ session/stub/rs512-template.jsonnet | 12 ++ session/tokenizer.go | 152 ++++++++++++++++++ session/tokenizer_test.go | 118 ++++++++++++++ spec/api.json | 14 +- spec/swagger.json | 12 +- x/events/events.go | 19 +++ x/fetcher.go | 10 ++ 27 files changed, 754 insertions(+), 9 deletions(-) create mode 100644 session/.snapshots/TestTokenizer-case=es256-without-jsonnet.json create mode 100644 session/.snapshots/TestTokenizer-case=es512-without-jsonnet.json create mode 100644 session/.snapshots/TestTokenizer-case=rs512-with-jsonnet.json create mode 100644 session/stub/jwk.es256.json create mode 100644 session/stub/jwk.es512.json create mode 100644 session/stub/jwk.rs512.json create mode 100644 session/stub/rs512-template.jsonnet create mode 100644 session/tokenizer.go create mode 100644 session/tokenizer_test.go create mode 100644 x/fetcher.go diff --git a/driver/config/config.go b/driver/config/config.go index 4cdbff51aad2..6d5aa68d8900 100644 --- a/driver/config/config.go +++ b/driver/config/config.go @@ -106,6 +106,7 @@ const ( ViperKeySessionName = "session.cookie.name" ViperKeySessionPath = "session.cookie.path" ViperKeySessionPersistentCookie = "session.cookie.persistent" + ViperKeySessionTokenizerTemplates = "session.whoami.tokenizer.templates" ViperKeySessionWhoAmIAAL = "session.whoami.required_aal" ViperKeySessionWhoAmICaching = "feature_flags.cacheable_sessions" ViperKeySessionRefreshMinTimeLeft = "session.earliest_possible_extend" @@ -1051,7 +1052,7 @@ func (p *Config) CourierTemplatesHelper(ctx context.Context, key string) *Courie config, err := json.Marshal(p.GetProvider(ctx).Get(key)) if err != nil { - p.l.WithError(err).Fatalf("Unable to dencode values from %s.", key) + p.l.WithError(err).Fatalf("Unable to decode values from %s.", key) return courierTemplate } @@ -1467,3 +1468,23 @@ func (p *Config) getTLSCertificates(ctx context.Context, daemon, certBase64, key func (p *Config) GetProvider(ctx context.Context) *configx.Provider { return p.c.Config(ctx, p.p) } + +type SessionTokenizeFormat struct { + TTL time.Duration `koanf:"ttl" json:"ttl"` + ClaimsMapperURL string `koanf:"claims_mapper_url" json:"claims_mapper_url"` + JWKSURL string `koanf:"jwks_url" json:"jwks_url"` +} + +func (p *Config) TokenizeTemplate(ctx context.Context, key string) (_ *SessionTokenizeFormat, err error) { + var result SessionTokenizeFormat + path := ViperKeySessionTokenizerTemplates + "." + key + if !p.GetProvider(ctx).Exists(path) { + return nil, errors.WithStack(herodot.ErrBadRequest.WithReasonf("Unable to find tokenizer template \"%s\".", key)) + } + + if err := p.GetProvider(ctx).Unmarshal(path, &result); err != nil { + return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Unable to decode tokenizer template \"%s\": %s", key, err)) + } + + return &result, nil +} diff --git a/driver/registry.go b/driver/registry.go index 38c87baf5c9b..e0e0d2562393 100644 --- a/driver/registry.go +++ b/driver/registry.go @@ -113,6 +113,7 @@ type Registry interface { session.HandlerProvider session.ManagementProvider session.PersistenceProvider + session.TokenizerProvider settings.HandlerProvider settings.ErrorHandlerProvider diff --git a/driver/registry_default.go b/driver/registry_default.go index 514409f5bd1e..b4733fc6dccf 100644 --- a/driver/registry_default.go +++ b/driver/registry_default.go @@ -12,6 +12,10 @@ import ( "testing" "time" + "github.com/dgraph-io/ristretto" + + "github.com/ory/x/jwksx" + "github.com/ory/x/contextx" "github.com/ory/x/jsonnetsecure" @@ -114,8 +118,9 @@ type RegistryDefault struct { schemaHandler *schema.Handler - sessionHandler *session.Handler - sessionManager session.Manager + sessionHandler *session.Handler + sessionManager session.Manager + sessionTokenizer *session.Tokenizer passwordHasher hash.Hasher passwordValidator password2.Validator @@ -163,6 +168,7 @@ type RegistryDefault struct { csrfTokenGenerator x.CSRFToken jsonnetVMProvider jsonnetsecure.VMProvider + jwkFetcher *jwksx.FetcherNext } func (m *RegistryDefault) JsonnetVM(ctx context.Context) (jsonnetsecure.VM, error) { @@ -839,3 +845,29 @@ func (m *RegistryDefault) Contextualizer() contextx.Contextualizer { } return m.ctxer } + +func (m *RegistryDefault) Fetcher() *jwksx.FetcherNext { + if m.jwkFetcher == nil { + maxItems := int64(10000000) + cache, _ := ristretto.NewCache(&ristretto.Config{ + NumCounters: maxItems * 10, + MaxCost: maxItems, + BufferItems: 64, + Metrics: true, + IgnoreInternalCost: true, + Cost: func(value interface{}) int64 { + return 1 + }, + }) + + m.jwkFetcher = jwksx.NewFetcherNext(cache) + } + return m.jwkFetcher +} + +func (m *RegistryDefault) SessionTokenizer() *session.Tokenizer { + if m.sessionTokenizer == nil { + m.sessionTokenizer = session.NewTokenizer(m) + } + return m.sessionTokenizer +} diff --git a/embedx/config.schema.json b/embedx/config.schema.json index 662cd3403800..e7f5ba3ddf95 100644 --- a/embedx/config.schema.json +++ b/embedx/config.schema.json @@ -2597,6 +2597,44 @@ "properties": { "required_aal": { "$ref": "#/definitions/featureRequiredAal" + }, + "tokenizer": { + "title": "Tokenizer configuration", + "description": "Configure the tokenizer, responsible for converting a session into a token format such as JWT.", + "type": "object", + "properties": { + "templates": { + "title": "Tokenizer templates", + "description": "A list of different templates that govern how a session is converted to a token format.", + "type": "object", + "patternProperties": { + "[a-zA-Z0-9-_.]+": { + "type": "object", + "required": [ + "jwks_url" + ], + "properties": { + "ttl": { + "type": "string", + "pattern": "^([0-9]+(ns|us|ms|s|m|h))+$", + "default": "1m", + "title": "Token time to live" + }, + "claims_mapper_url": { + "type": "string", + "format": "uri", + "title": "JsonNet mapper URL" + }, + "jwks_url": { + "type": "string", + "format": "uri", + "title": "JSON Web Key Set URL" + } + } + } + } + } + } } }, "additionalProperties": false diff --git a/go.mod b/go.mod index 3b86d4e92abd..a35d9afc7289 100644 --- a/go.mod +++ b/go.mod @@ -42,6 +42,7 @@ require ( github.com/gobuffalo/pop/v6 v6.1.2-0.20230318123913-c85387acc9a0 github.com/gofrs/uuid v4.3.1+incompatible github.com/golang-jwt/jwt/v4 v4.5.0 + github.com/golang-jwt/jwt/v5 v5.0.0 github.com/golang/gddo v0.0.0-20190904175337-72a348e765d2 github.com/golang/mock v1.6.0 github.com/google/go-github/v27 v27.0.1 @@ -60,6 +61,7 @@ require ( github.com/julienschmidt/httprouter v1.3.0 github.com/knadh/koanf/parsers/json v0.1.0 github.com/laher/mergefs v0.1.2-0.20230223191438-d16611b2f4e7 + github.com/lestrrat-go/jwx v1.2.26 github.com/luna-duclos/instrumentedsql v1.1.3 github.com/mailhog/MailHog v1.0.1 github.com/mattn/goveralls v0.0.7 @@ -130,6 +132,7 @@ require ( github.com/containerd/continuity v0.3.0 // indirect github.com/cortesi/moddwatch v0.0.0-20210222043437-a6aaad86a36e // indirect github.com/cortesi/termlog v0.0.0-20210222042314-a1eec763abec // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/docker/cli v20.10.21+incompatible // indirect github.com/docker/distribution v2.8.2+incompatible // indirect github.com/docker/docker v20.10.24+incompatible // indirect @@ -145,6 +148,7 @@ require ( github.com/fxamacker/cbor/v2 v2.4.0 // indirect github.com/go-bindata/go-bindata v3.1.2+incompatible // indirect github.com/go-crypt/x v0.2.1 // indirect + github.com/go-jose/go-jose/v3 v3.0.0 // indirect github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/analysis v0.21.4 // indirect @@ -170,6 +174,7 @@ require ( github.com/gobuffalo/tags/v3 v3.1.4 // indirect github.com/gobuffalo/validate/v3 v3.3.3 // indirect github.com/gobwas/glob v0.2.3 // indirect + github.com/goccy/go-json v0.10.2 // indirect github.com/goccy/go-yaml v1.9.6 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect @@ -224,6 +229,11 @@ require ( github.com/kr/pretty v0.3.0 // indirect github.com/kr/text v0.2.0 // indirect github.com/leodido/go-urn v1.2.0 // indirect + github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect + github.com/lestrrat-go/blackmagic v1.0.1 // indirect + github.com/lestrrat-go/httpcc v1.0.1 // indirect + github.com/lestrrat-go/iter v1.0.2 // indirect + github.com/lestrrat-go/option v1.0.1 // indirect github.com/lib/pq v1.10.7 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mailhog/MailHog-Server v1.0.1 // indirect diff --git a/go.sum b/go.sum index a54b199a2b27..b8f3117cbc72 100644 --- a/go.sum +++ b/go.sum @@ -158,6 +158,9 @@ 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/davidrjonas/semver-cli v0.0.0-20190116233701-ee19a9a0dda6 h1:VzPvKOw28XJ77PYwOq5gAqvFB4gk6gst0HxxiW8kfZQ= github.com/davidrjonas/semver-cli v0.0.0-20190116233701-ee19a9a0dda6/go.mod h1:+6FzxsSbK4oEuvdN06Jco8zKB2mQqIB6UduZdd0Zesk= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= @@ -220,6 +223,8 @@ github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm 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-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo= +github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= @@ -347,6 +352,8 @@ github.com/gobuffalo/validate/v3 v3.3.3 h1:o7wkIGSvZBYBd6ChQoLxkz2y1pfmhbI4jNJYh github.com/gobuffalo/validate/v3 v3.3.3/go.mod h1:YC7FsbJ/9hW/VjQdmXPvFqvRis4vrRYFxr69WiNZw6g= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-yaml v1.9.6 h1:KhAu1zf9JXnm3vbG49aDE0E5uEBUsM4uwD31/58ZWyI= github.com/goccy/go-yaml v1.9.6/go.mod h1:JubOolP3gh0HpiBc4BLRD4YmjEjHAmIIB2aaXKkTfoE= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -362,6 +369,8 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= +github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/gddo v0.0.0-20190904175337-72a348e765d2 h1:xisWqjiKEff2B0KfFYGpCqc3M3zdTz+OHQHRc09FeYk= 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= @@ -678,6 +687,19 @@ github.com/laher/mergefs v0.1.2-0.20230223191438-d16611b2f4e7 h1:PDeBswTUsSIT4QS github.com/laher/mergefs v0.1.2-0.20230223191438-d16611b2f4e7/go.mod h1:FSY1hYy94on4Tz60waRMGdO1awwS23BacqJlqf9lJ9Q= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A= +github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y= +github.com/lestrrat-go/blackmagic v1.0.1 h1:lS5Zts+5HIC/8og6cGHb0uCcNCa3OUt1ygh3Qz2Fe80= +github.com/lestrrat-go/blackmagic v1.0.1/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU= +github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE= +github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= +github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI= +github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4= +github.com/lestrrat-go/jwx v1.2.26 h1:4iFo8FPRZGDYe1t19mQP0zTRqA7n8HnJ5lkIiDvJcB0= +github.com/lestrrat-go/jwx v1.2.26/go.mod h1:MaiCdGbn3/cckbOFSCluJlJMmp9dmZm5hDuIkx8ftpQ= +github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= +github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU= +github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= 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= @@ -1113,6 +1135,7 @@ golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaE golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -1130,6 +1153,7 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220517005047-85d78b3ac167/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1170,6 +1194,7 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1223,6 +1248,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1343,6 +1370,8 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20191110171634-ad39bd3f0407/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -1353,6 +1382,8 @@ golang.org/x/term v0.0.0-20210317153231-de623e64d2a6/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1365,6 +1396,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1436,6 +1469,7 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools/cmd/cover v0.1.0-deprecated h1:Rwy+mWYz6loAF+LnG1jHG/JWMHRMMC2/1XX3Ejkx9lA= diff --git a/internal/client-go/api_frontend.go b/internal/client-go/api_frontend.go index e3dc0fcf14f1..657a2c6c7721 100644 --- a/internal/client-go/api_frontend.go +++ b/internal/client-go/api_frontend.go @@ -665,6 +665,16 @@ type FrontendApi interface { console.log(session) ``` + When using a token template, the token is included in the `tokenized` field of the session. + + ```js + pseudo-code example + ... + const session = await client.toSession("the-session-token", { tokenize_as: "example-jwt-template" }) + + console.log(session.tokenized) // The JWT + ``` + Depending on your configuration this endpoint might return a 403 status code if the session has a lower Authenticator Assurance Level (AAL) than is possible for the identity. This can happen if the identity has password + webauthn credentials (which would result in AAL2) but the session has only AAL1. If this error occurs, ask the user @@ -4477,6 +4487,7 @@ type FrontendApiApiToSessionRequest struct { ApiService FrontendApi xSessionToken *string cookie *string + tokenizeAs *string } func (r FrontendApiApiToSessionRequest) XSessionToken(xSessionToken string) FrontendApiApiToSessionRequest { @@ -4487,6 +4498,10 @@ func (r FrontendApiApiToSessionRequest) Cookie(cookie string) FrontendApiApiToSe r.cookie = &cookie return r } +func (r FrontendApiApiToSessionRequest) TokenizeAs(tokenizeAs string) FrontendApiApiToSessionRequest { + r.tokenizeAs = &tokenizeAs + return r +} func (r FrontendApiApiToSessionRequest) Execute() (*Session, *http.Response, error) { return r.ApiService.ToSessionExecute(r) @@ -4521,6 +4536,16 @@ const session = await client.toSession("the-session-token") console.log(session) ``` +When using a token template, the token is included in the `tokenized` field of the session. + +```js +pseudo-code example +... +const session = await client.toSession("the-session-token", { tokenize_as: "example-jwt-template" }) + +console.log(session.tokenized) // The JWT +``` + Depending on your configuration this endpoint might return a 403 status code if the session has a lower Authenticator Assurance Level (AAL) than is possible for the identity. This can happen if the identity has password + webauthn credentials (which would result in AAL2) but the session has only AAL1. If this error occurs, ask the user @@ -4579,6 +4604,9 @@ func (a *FrontendApiService) ToSessionExecute(r FrontendApiApiToSessionRequest) localVarQueryParams := url.Values{} localVarFormParams := url.Values{} + if r.tokenizeAs != nil { + localVarQueryParams.Add("tokenize_as", parameterToString(*r.tokenizeAs, "")) + } // to determine the Content-Type header localVarHTTPContentTypes := []string{} diff --git a/internal/client-go/model_session.go b/internal/client-go/model_session.go index 0ded40302a1c..aa10a1dac55c 100644 --- a/internal/client-go/model_session.go +++ b/internal/client-go/model_session.go @@ -34,6 +34,8 @@ type Session struct { Identity *Identity `json:"identity,omitempty"` // The Session Issuance Timestamp When this session was issued at. Usually equal or close to `authenticated_at`. IssuedAt *time.Time `json:"issued_at,omitempty"` + // Tokenized is the tokenized (e.g. JWT) version of the session. It is only set when the `tokenize` query parameter was set to a valid tokenize template during calls to `/session/whoami`. + Tokenized *string `json:"tokenized,omitempty"` } // NewSession instantiates a new Session object @@ -334,6 +336,38 @@ func (o *Session) SetIssuedAt(v time.Time) { o.IssuedAt = &v } +// GetTokenized returns the Tokenized field value if set, zero value otherwise. +func (o *Session) GetTokenized() string { + if o == nil || o.Tokenized == nil { + var ret string + return ret + } + return *o.Tokenized +} + +// GetTokenizedOk returns a tuple with the Tokenized field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *Session) GetTokenizedOk() (*string, bool) { + if o == nil || o.Tokenized == nil { + return nil, false + } + return o.Tokenized, true +} + +// HasTokenized returns a boolean if a field has been set. +func (o *Session) HasTokenized() bool { + if o != nil && o.Tokenized != nil { + return true + } + + return false +} + +// SetTokenized gets a reference to the given string and assigns it to the Tokenized field. +func (o *Session) SetTokenized(v string) { + o.Tokenized = &v +} + func (o Session) MarshalJSON() ([]byte, error) { toSerialize := map[string]interface{}{} if o.Active != nil { @@ -363,6 +397,9 @@ func (o Session) MarshalJSON() ([]byte, error) { if o.IssuedAt != nil { toSerialize["issued_at"] = o.IssuedAt } + if o.Tokenized != nil { + toSerialize["tokenized"] = o.Tokenized + } return json.Marshal(toSerialize) } diff --git a/internal/httpclient/api_frontend.go b/internal/httpclient/api_frontend.go index e3dc0fcf14f1..657a2c6c7721 100644 --- a/internal/httpclient/api_frontend.go +++ b/internal/httpclient/api_frontend.go @@ -665,6 +665,16 @@ type FrontendApi interface { console.log(session) ``` + When using a token template, the token is included in the `tokenized` field of the session. + + ```js + pseudo-code example + ... + const session = await client.toSession("the-session-token", { tokenize_as: "example-jwt-template" }) + + console.log(session.tokenized) // The JWT + ``` + Depending on your configuration this endpoint might return a 403 status code if the session has a lower Authenticator Assurance Level (AAL) than is possible for the identity. This can happen if the identity has password + webauthn credentials (which would result in AAL2) but the session has only AAL1. If this error occurs, ask the user @@ -4477,6 +4487,7 @@ type FrontendApiApiToSessionRequest struct { ApiService FrontendApi xSessionToken *string cookie *string + tokenizeAs *string } func (r FrontendApiApiToSessionRequest) XSessionToken(xSessionToken string) FrontendApiApiToSessionRequest { @@ -4487,6 +4498,10 @@ func (r FrontendApiApiToSessionRequest) Cookie(cookie string) FrontendApiApiToSe r.cookie = &cookie return r } +func (r FrontendApiApiToSessionRequest) TokenizeAs(tokenizeAs string) FrontendApiApiToSessionRequest { + r.tokenizeAs = &tokenizeAs + return r +} func (r FrontendApiApiToSessionRequest) Execute() (*Session, *http.Response, error) { return r.ApiService.ToSessionExecute(r) @@ -4521,6 +4536,16 @@ const session = await client.toSession("the-session-token") console.log(session) ``` +When using a token template, the token is included in the `tokenized` field of the session. + +```js +pseudo-code example +... +const session = await client.toSession("the-session-token", { tokenize_as: "example-jwt-template" }) + +console.log(session.tokenized) // The JWT +``` + Depending on your configuration this endpoint might return a 403 status code if the session has a lower Authenticator Assurance Level (AAL) than is possible for the identity. This can happen if the identity has password + webauthn credentials (which would result in AAL2) but the session has only AAL1. If this error occurs, ask the user @@ -4579,6 +4604,9 @@ func (a *FrontendApiService) ToSessionExecute(r FrontendApiApiToSessionRequest) localVarQueryParams := url.Values{} localVarFormParams := url.Values{} + if r.tokenizeAs != nil { + localVarQueryParams.Add("tokenize_as", parameterToString(*r.tokenizeAs, "")) + } // to determine the Content-Type header localVarHTTPContentTypes := []string{} diff --git a/internal/httpclient/model_session.go b/internal/httpclient/model_session.go index 0ded40302a1c..aa10a1dac55c 100644 --- a/internal/httpclient/model_session.go +++ b/internal/httpclient/model_session.go @@ -34,6 +34,8 @@ type Session struct { Identity *Identity `json:"identity,omitempty"` // The Session Issuance Timestamp When this session was issued at. Usually equal or close to `authenticated_at`. IssuedAt *time.Time `json:"issued_at,omitempty"` + // Tokenized is the tokenized (e.g. JWT) version of the session. It is only set when the `tokenize` query parameter was set to a valid tokenize template during calls to `/session/whoami`. + Tokenized *string `json:"tokenized,omitempty"` } // NewSession instantiates a new Session object @@ -334,6 +336,38 @@ func (o *Session) SetIssuedAt(v time.Time) { o.IssuedAt = &v } +// GetTokenized returns the Tokenized field value if set, zero value otherwise. +func (o *Session) GetTokenized() string { + if o == nil || o.Tokenized == nil { + var ret string + return ret + } + return *o.Tokenized +} + +// GetTokenizedOk returns a tuple with the Tokenized field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *Session) GetTokenizedOk() (*string, bool) { + if o == nil || o.Tokenized == nil { + return nil, false + } + return o.Tokenized, true +} + +// HasTokenized returns a boolean if a field has been set. +func (o *Session) HasTokenized() bool { + if o != nil && o.Tokenized != nil { + return true + } + + return false +} + +// SetTokenized gets a reference to the given string and assigns it to the Tokenized field. +func (o *Session) SetTokenized(v string) { + o.Tokenized = &v +} + func (o Session) MarshalJSON() ([]byte, error) { toSerialize := map[string]interface{}{} if o.Active != nil { @@ -363,6 +397,9 @@ func (o Session) MarshalJSON() ([]byte, error) { if o.IssuedAt != nil { toSerialize["issued_at"] = o.IssuedAt } + if o.Tokenized != nil { + toSerialize["tokenized"] = o.Tokenized + } return json.Marshal(toSerialize) } diff --git a/persistence/sql/persister.go b/persistence/sql/persister.go index c7c98188dc78..f14abd7a557d 100644 --- a/persistence/sql/persister.go +++ b/persistence/sql/persister.go @@ -55,12 +55,22 @@ type ( ) func NewPersister(ctx context.Context, r persisterDependencies, c *pop.Connection, extraMigrations ...fs.FS) (*Persister, error) { - m, err := popx.NewMigrationBox(mergefs.Merge(append([]fs.FS{migrations, networkx.Migrations}, extraMigrations...)...), popx.NewMigrator(c, r.Logger(), r.Tracer(ctx), 0)) + m, err := popx.NewMigrationBox( + mergefs.Merge( + append( + []fs.FS{ + migrations, networkx.Migrations, + }, + extraMigrations..., + )..., + ), + popx.NewMigrator(c, r.Logger(), r.Tracer(ctx), 0), + ) if err != nil { return nil, err } - m.DumpMigrations = false + m.DumpMigrations = false return &Persister{ c: c, mb: m, diff --git a/session/.snapshots/TestTokenizer-case=es256-without-jsonnet.json b/session/.snapshots/TestTokenizer-case=es256-without-jsonnet.json new file mode 100644 index 000000000000..19ce08b76775 --- /dev/null +++ b/session/.snapshots/TestTokenizer-case=es256-without-jsonnet.json @@ -0,0 +1,8 @@ +{ + "exp": 1675209660, + "iat": 1675209600, + "iss": "http://localhost/", + "nbf": 1675209600, + "sid": "432caf86-c1d8-401c-978a-8da89133f78b", + "sub": "7458af86-c1d8-401c-978a-8da89133f78b" +} diff --git a/session/.snapshots/TestTokenizer-case=es512-without-jsonnet.json b/session/.snapshots/TestTokenizer-case=es512-without-jsonnet.json new file mode 100644 index 000000000000..19ce08b76775 --- /dev/null +++ b/session/.snapshots/TestTokenizer-case=es512-without-jsonnet.json @@ -0,0 +1,8 @@ +{ + "exp": 1675209660, + "iat": 1675209600, + "iss": "http://localhost/", + "nbf": 1675209600, + "sid": "432caf86-c1d8-401c-978a-8da89133f78b", + "sub": "7458af86-c1d8-401c-978a-8da89133f78b" +} diff --git a/session/.snapshots/TestTokenizer-case=rs512-with-jsonnet.json b/session/.snapshots/TestTokenizer-case=rs512-with-jsonnet.json new file mode 100644 index 000000000000..84816eca114d --- /dev/null +++ b/session/.snapshots/TestTokenizer-case=rs512-with-jsonnet.json @@ -0,0 +1,12 @@ +{ + "aal": "aal1", + "exp": 1675209660, + "foo": "bar", + "iat": 1675209600, + "iss": "http://localhost/", + "nbf": 1675209600, + "schema_id": "default", + "second_claim": 1675209660, + "sid": "432caf86-c1d8-401c-978a-8da89133f78b", + "sub": "7458af86-c1d8-401c-978a-8da89133f78b" +} diff --git a/session/handler.go b/session/handler.go index fb0ae50d8c81..0fcfd9ad2103 100644 --- a/session/handler.go +++ b/session/handler.go @@ -34,10 +34,12 @@ type ( ManagementProvider PersistenceProvider x.WriterProvider + x.TracingProvider x.LoggingProvider x.CSRFProvider config.Provider sessiontokenexchange.PersistenceProvider + TokenizerProvider } HandlerProvider interface { SessionHandler() *Handler @@ -124,6 +126,13 @@ type toSession struct { // // in: header Cookie string `json:"Cookie"` + + // Returns the session additionally as a token (such as a JWT) + // + // The value of this parameter has to be a valid, configured Ory Session token template. For more information head over to [the documentation](http://ory.sh/docs/identities/session-to-jwt-cors). + // + // in: query + TokenizeAs string `json:"tokenize_as"` } // swagger:route GET /sessions/whoami frontend toSession @@ -156,6 +165,16 @@ type toSession struct { // // console.log(session) // ``` // +// When using a token template, the token is included in the `tokenized` field of the session. +// +// ```js +// // pseudo-code example +// // ... +// const session = await client.toSession("the-session-token", { tokenize_as: "example-jwt-template" }) +// +// console.log(session.tokenized) // The JWT +// ``` +// // Depending on your configuration this endpoint might return a 403 status code if the session has a lower Authenticator // Assurance Level (AAL) than is possible for the identity. This can happen if the identity has password + webauthn // credentials (which would result in AAL2) but the session has only AAL1. If this error occurs, ask the user @@ -191,6 +210,9 @@ type toSession struct { // 403: errorGeneric // default: errorGeneric func (h *Handler) whoami(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + ctx, span := h.r.Tracer(r.Context()).Tracer().Start(r.Context(), "sessions.Handler.whoami") + defer span.End() + s, err := h.r.SessionManager().FetchFromRequest(r.Context(), r) c := h.r.Config() if err != nil { @@ -221,11 +243,19 @@ func (h *Handler) whoami(w http.ResponseWriter, r *http.Request, _ httprouter.Pa // s.Devices = nil s.Identity = s.Identity.CopyWithoutCredentials() + tokenizeTemplate := r.URL.Query().Get("tokenize_as") + if tokenizeTemplate != "" { + if err := h.r.SessionTokenizer().TokenizeSession(ctx, tokenizeTemplate, s); err != nil { + h.r.Writer().WriteError(w, r, err) + return + } + } + // Set userId as the X-Kratos-Authenticated-Identity-Id header. w.Header().Set("X-Kratos-Authenticated-Identity-Id", s.Identity.ID.String()) - // Set Cache header only when configured - if c.SessionWhoAmICaching(r.Context()) { + // Set Cache header only when configured, and when no tokenization is requested. + if c.SessionWhoAmICaching(r.Context()) && len(tokenizeTemplate) == 0 { w.Header().Set("Ory-Session-Cache-For", fmt.Sprintf("%d", int64(time.Until(s.ExpiresAt).Seconds()))) } diff --git a/session/handler_test.go b/session/handler_test.go index 352301a682ab..b565381a986c 100644 --- a/session/handler_test.go +++ b/session/handler_test.go @@ -5,6 +5,7 @@ package session_test import ( "context" + "encoding/base64" "encoding/json" "fmt" "io" @@ -211,6 +212,32 @@ func TestSessionWhoAmI(t *testing.T) { }) }) + t.Run("tokenize", func(t *testing.T) { + setTokenizeConfig(conf, "es256", "jwk.es256.json", "") + conf.MustSet(ctx, config.ViperKeySessionWhoAmICaching, true) + + h3, _ := testhelpers.MockSessionCreateHandlerWithIdentityAndAMR(t, reg, createAAL1Identity(t, reg), []identity.CredentialsType{identity.CredentialsTypePassword}) + r.GET("/set/tokenize", h3) + + client := testhelpers.NewClientWithCookies(t) + testhelpers.MockHydrateCookieClient(t, client, ts.URL+"/set/"+"tokenize") + + res, err := client.Get(ts.URL + RouteWhoami + "?tokenize_as=es256") + require.NoError(t, err) + body := x.MustReadAll(res.Body) + assert.EqualValues(t, http.StatusOK, res.StatusCode, string(body)) + + token := gjson.GetBytes(body, "tokenized").String() + require.NotEmpty(t, token) + segments := strings.Split(token, ".") + require.Len(t, segments, 3, token) + decoded, err := base64.RawURLEncoding.DecodeString(segments[1]) + require.NoError(t, err) + + assert.NotEmpty(t, gjson.GetBytes(decoded, "sub").Str, decoded) + assert.Empty(t, res.Header.Get("Ory-Session-Cache-For")) + }) + /* t.Run("case=respects AAL config", func(t *testing.T) { conf.MustSet(ctx, config.ViperKeySessionLifespan, "1m") diff --git a/session/session.go b/session/session.go index 41b811b146b9..ceb792f66b2e 100644 --- a/session/session.go +++ b/session/session.go @@ -140,6 +140,11 @@ type Session struct { // UpdatedAt is a helper struct field for gobuffalo.pop. UpdatedAt time.Time `json:"-" faker:"-" db:"updated_at"` + // Tokenized is the tokenized (e.g. JWT) version of the session. + // + // It is only set when the `tokenize` query parameter was set to a valid tokenize template during calls to `/session/whoami`. + Tokenized string `json:"tokenized,omitempty" faker:"-" db:"-"` + // The Session Token // // The token of this session. diff --git a/session/stub/jwk.es256.json b/session/stub/jwk.es256.json new file mode 100644 index 000000000000..860ff1038bac --- /dev/null +++ b/session/stub/jwk.es256.json @@ -0,0 +1,14 @@ +{ + "keys": [ + { + "use": "sig", + "kty": "EC", + "kid": "247f1420-e581-4023-88e0-07ee662f80da", + "crv": "P-256", + "alg": "ES256", + "x": "1odGSu9bvVq_9QqqNny8TvvUElscLYoTExxhnomYOgQ", + "y": "pa4d4Ql1lO86PBnQ8efYzSzW9nUrsfLlomn3RIpH2Ic", + "d": "kPoEy2OcUeHobxp9jK00YKTs0CBoRTMWZJoPOe9K5hQ" + } + ] +} diff --git a/session/stub/jwk.es512.json b/session/stub/jwk.es512.json new file mode 100644 index 000000000000..d8ab0abcd746 --- /dev/null +++ b/session/stub/jwk.es512.json @@ -0,0 +1,14 @@ +{ + "keys": [ + { + "use": "sig", + "kty": "EC", + "kid": "bc7f7afc-6742-427c-bb9e-164fe0f8b6a7", + "crv": "P-521", + "alg": "ES512", + "x": "ASj36HQOpsWiaGyzK1F0GkxXRt37R01M-OCWFk8rFqH8UnFBk0qnCmVYWv3pwVPPsN0CfFiaXTrV1gUSapkkDgWY", + "y": "ALf5bqXExUq6FzQNQg01hDhR2lOKzkrC02Bc6Alld8Zji3-echbimNZltoOi4MhXbSJeWHpU8wzb3v9XAAW4eovn", + "d": "ALP0Sf7cmcELc9CQ2bWd6Qs-YxMu0N9EYZhDmR6qbYdGnvv-lcGy_ySoEJD0vPMKagA8PHDvFhC7ORwP-sBIJ4O_" + } + ] +} diff --git a/session/stub/jwk.rs512.json b/session/stub/jwk.rs512.json new file mode 100644 index 000000000000..1d70bb1595e9 --- /dev/null +++ b/session/stub/jwk.rs512.json @@ -0,0 +1,18 @@ +{ + "keys": [ + { + "use": "sig", + "kty": "RSA", + "kid": "95311ff8-ff91-486b-9ad9-21df8bdc95d7", + "alg": "RS512", + "n": "6_ygtx-8qvTeN7ts_qFJCuOIEyxOnUpggbx04cG3vqjtyfzZMfi0wlidgMH3zhglij2MwC5lPLbze5n4lGQk26s8bl0uhdWlFHO_44hN3l2NVbPcocVZDWwqOdct2qRx1sEdRAt-P1a-2gxYN4HaemER9lgZSgbikJhmL3EEKhcr0QklUZyMcUnbaHAopzdiMKpnykR28-SXEizBi7JTI0hRDgCVmjuCRsciI5GAFy-nQ5n3Ofm0x8wGflKN1RAeWvolpakb7YJgQAXKQhOY3huoHlr-sh3ZO9vQjBgVQ1AM3k-z4OiQjJwvgogfLa1lSLmh9_Ax3LJQ5iax-aN9yQ", + "e": "AQAB", + "d": "DjZhy4WazEUBGSQtlUxLZN99M4Jonap8E3QxKeOL2Gy-HXsf7ZWH9Wh22-lSrlPf9upsDqr8p-Jw2ZHVWcKKQbyXYCI2ihLq5UdvWBm-btT9jRrO_-Mt0NQh2uftuAxNWty4kX-Ls-7agbFaosUsTlCIT2jQ5RdzD7hN9y98S7iJ6oUiBKdc7cRkNj2lGqowwM_IR4IoU2rY2pC7OtHZg_BKU8UnSYcPopn9tnobpr4E_AA1x49iUOkEny3wSXEfP2gEqb2Frqsf342b0pOtiq4WuiAopG2vBfMCKGddDBG_fFsxp858i03G9S4IuMDYk1uSeXd0zc_nb0GxFjXpXQ", + "p": "-_rHgqAtRJpeUbdTWhWQxlUFp-g0Yt1WCnKhCYXzgwM1kG-m9mzHW9mEJxTc0olygeo2A0vJ7htZJpd9NtJkD6g5yDZ7GIm5Emr9fNk4glz8nkVV9udU2gv6hVe83XU86cI4B4XWXhjdNvjQd7ohO7kBwB3uBmekVRm6ZaUCD-c", + "q": "78CGezUjroDlUA5CiF75_apyBgrEI41eNiOPwN9X7Jy-3zpvecY9ZfIuyf5O1yNkC_zjanGEKom6L3iqcAV_1-wzGMOMvtIwhmkTPT9g0f1Z1utRQVljyXFBml7__xb9cCfq62YnH7irsM5nbe9Txziq2zvBjWCkkjJwTBPWDs8", + "dp": "lXjhuJ8Du1pG8Ppqu1lnk_8DZ-LakHrzeyccV-XZ2bGhqJhS1oMYj2esePJrO4jFIEOq3rGqi1A1xiq-4DJVoOQNwrJuutOXsVE-JT1FxC8cu1Yt9FSthNruNQMiycut4oyPaAcAbrkZIG7gWuVSqXbJjwkyFSKN3N1yMLF9U6k", + "dq": "MLapnHcbnOVLsoxzMEo7-TKcoGWnnKGots9a8hFvSABBOBIjfFavOvuOTjSByGzEczsa6hHOjOYXEnYuCzzS0QiJCUsSWeNTQLww0I0EGyajDmwZwnFrOQ7uCXOsCCSfsh4qOVI0ONnI6M_HbCrolt4IuSrXFObCCYJ-FrchEzk", + "qi": "fBkpKoiyeXnwBYezKcxkeu6E2F2tWiRgRikM-s50kRu2fGgmAZ-nIIHU5glPXCPbn4IolURxeLm8ZZyCCo2tNPWiAQV2C7UF04Kh8QANULoUdpObjplLEWQuCDgz5m9EkR4Sx6FGGA1TvUpYCjks8YxvdSIa56o3l72I49aL1t8" + } + ] +} diff --git a/session/stub/rs512-template.jsonnet b/session/stub/rs512-template.jsonnet new file mode 100644 index 000000000000..fa67d936b54a --- /dev/null +++ b/session/stub/rs512-template.jsonnet @@ -0,0 +1,12 @@ +local claims = std.extVar('claims'); +local session = std.extVar('session'); + +{ + claims: { + foo: "bar", + sub: "can not be overwritten", + schema_id: session.identity.schema_id, + aal: session.authenticator_assurance_level, + second_claim: claims.exp, + } +} diff --git a/session/tokenizer.go b/session/tokenizer.go new file mode 100644 index 000000000000..f4317f067ac1 --- /dev/null +++ b/session/tokenizer.go @@ -0,0 +1,152 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package session + +import ( + "context" + "encoding/json" + "time" + + "go.opentelemetry.io/otel/trace" + + "github.com/ory/kratos/x/events" + + "github.com/gofrs/uuid" + "github.com/golang-jwt/jwt/v5" + "github.com/pkg/errors" + "github.com/tidwall/gjson" + + "github.com/ory/herodot" + "github.com/ory/kratos/driver/config" + "github.com/ory/kratos/x" + "github.com/ory/x/fetcher" + "github.com/ory/x/jsonnetsecure" + "github.com/ory/x/jwksx" + "github.com/ory/x/otelx" +) + +type ( + tokenizerDependencies interface { + jsonnetsecure.VMProvider + x.TracingProvider + x.HTTPClientProvider + config.Provider + x.JWKFetchProvider + } + Tokenizer struct { + r tokenizerDependencies + nowFunc func() time.Time + } + TokenizerProvider interface { + SessionTokenizer() *Tokenizer + } +) + +func NewTokenizer(r tokenizerDependencies) *Tokenizer { + return &Tokenizer{r: r, nowFunc: time.Now} +} + +func (s *Tokenizer) SetNowFunc(t func() time.Time) { + s.nowFunc = t +} + +func (s *Tokenizer) TokenizeSession(ctx context.Context, template string, session *Session) (err error) { + ctx, span := s.r.Tracer(ctx).Tracer().Start(ctx, "sessions.ManagerHTTP.TokenizeSession") + defer otelx.End(span, &err) + + tpl, err := s.r.Config().TokenizeTemplate(ctx, template) + if err != nil { + return err + } + + httpClient := s.r.HTTPClient(ctx) + key, err := s.r.Fetcher().ResolveKey( + ctx, + tpl.JWKSURL, + jwksx.WithCacheEnabled(), + jwksx.WithCacheTTL(time.Hour), + jwksx.WithHTTPClient(httpClient)) + if err != nil { + if errors.Is(err, jwksx.ErrUnableToFindKeyID) { + return errors.WithStack(herodot.ErrBadRequest.WithReasonf("Could not find key a suitable key for tokenization in the JWKS url.")) + } + return err + } + + alg := jwt.GetSigningMethod(key.Algorithm()) + if alg == nil { + return errors.WithStack(herodot.ErrBadRequest.WithReasonf("The JSON Web Key must include a valid \"alg\" parameter but \"%s\" was given.", key.Algorithm())) + } + + vm, err := s.r.JsonnetVM(ctx) + if err != nil { + return err + } + + fetch := fetcher.NewFetcher(fetcher.WithClient(httpClient)) + + now := s.nowFunc() + token := jwt.New(alg) + token.Header["kid"] = key.KeyID() + claims := jwt.MapClaims{ + "jti": uuid.Must(uuid.NewV4()).String(), + "iss": s.r.Config().SelfPublicURL(ctx).String(), + "exp": now.Add(tpl.TTL).Unix(), + "sub": session.IdentityID.String(), + "sid": session.ID.String(), + "nbf": now.Unix(), + "iat": now.Unix(), + } + + if mapper := tpl.ClaimsMapperURL; len(mapper) > 0 { + jn, err := fetch.FetchContext(ctx, mapper) + if err != nil { + return err + } + + sessionRaw, err := json.Marshal(session) + if err != nil { + return errors.WithStack(herodot.ErrInternalServerError.WithWrap(err).WithReasonf("Unable to encode session to JSON.")) + } + + claimsRaw, err := json.Marshal(&claims) + if err != nil { + return errors.WithStack(herodot.ErrInternalServerError.WithWrap(err).WithReasonf("Unable to encode claims to JSON.")) + } + + vm.ExtCode("session", string(sessionRaw)) + vm.ExtCode("claims", string(claimsRaw)) + + evaluated, err := vm.EvaluateAnonymousSnippet(tpl.ClaimsMapperURL, jn.String()) + if err != nil { + return errors.WithStack(herodot.ErrBadRequest.WithWrap(err).WithDebug(err.Error()).WithReasonf("Unable to execute tokenizer JsonNet.")) + } + + evaluatedClaims := gjson.Get(evaluated, "claims") + if !evaluatedClaims.IsObject() { + return errors.WithStack(herodot.ErrBadRequest.WithWrap(err).WithReasonf("Expected tokenizer JsonNet to return a claims object but it did not.")) + } + + if err := json.Unmarshal([]byte(evaluatedClaims.Raw), &claims); err != nil { + return errors.WithStack(herodot.ErrBadRequest.WithWrap(err).WithReasonf("Unable to encode tokenized claims.")) + } + + claims["sub"] = session.IdentityID.String() + } + + var privateKey interface{} + if err := key.Raw(&privateKey); err != nil { + return errors.WithStack(herodot.ErrBadRequest.WithWrap(err).WithReasonf("Unable to decode the given private key.")) + } + + token.Claims = claims + result, err := token.SignedString(privateKey) + if err != nil { + return errors.WithStack(herodot.ErrBadRequest.WithWrap(err).WithReasonf("Unable to sign JSON Web Token.")) + } + + trace.SpanFromContext(ctx).AddEvent(events.NewSessionJWTIssued(ctx, session.ID, session.IdentityID, tpl.TTL)) + session.Tokenized = result + return nil +} diff --git a/session/tokenizer_test.go b/session/tokenizer_test.go new file mode 100644 index 000000000000..bb69b222b83e --- /dev/null +++ b/session/tokenizer_test.go @@ -0,0 +1,118 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package session_test + +import ( + "context" + _ "embed" + "net/http/httptest" + "testing" + "time" + + "github.com/gofrs/uuid" + "github.com/golang-jwt/jwt/v5" + "github.com/lestrrat-go/jwx/jwk" + "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/session" + "github.com/ory/x/snapshotx" +) + +//go:embed stub/jwk.es256.json +var es256Key []byte + +//go:embed stub/jwk.es512.json +var es512Key []byte + +func validateTokenized(t *testing.T, raw string, key []byte) *jwt.Token { + token, err := jwt.Parse( + raw, + func(token *jwt.Token) (target interface{}, _ error) { + set, err := jwk.Parse(key) + if err != nil { + return nil, err + } + key, _ := set.Get(0) + if pk, err := key.PublicKey(); err != nil { + return nil, err + } else if err := pk.Raw(&target); err != nil { + return nil, err + } + return target, nil + }, + // We use a fixed time function for snapshot testing, and thus can not validate claims. + jwt.WithoutClaimsValidation(), + ) + require.NoError(t, err) + return token +} + +func setTokenizeConfig(conf *config.Config, templateID string, keyFile string, mapper string) { + conf.MustSet(context.Background(), config.ViperKeySessionTokenizerTemplates+"."+templateID, &config.SessionTokenizeFormat{ + TTL: time.Minute, + JWKSURL: "file://stub/" + keyFile, + ClaimsMapperURL: mapper, + }) +} + +func TestTokenizer(t *testing.T) { + ctx := context.Background() + now := time.Now() + + conf, reg := internal.NewFastRegistryWithMocks(t) + conf.MustSet(ctx, config.ViperKeyPublicBaseURL, "http://localhost/") + tkn := session.NewTokenizer(reg) + nowDate := time.Date(2023, 02, 01, 00, 00, 00, 0, time.UTC) + tkn.SetNowFunc(func() time.Time { + return nowDate + }) + + r := httptest.NewRequest("GET", "/sessions/whoami", nil) + i := identity.NewIdentity("default") + i.ID = uuid.FromStringOrNil("7458af86-c1d8-401c-978a-8da89133f78b") + + s, err := session.NewActiveSession(r, i, conf, now, identity.CredentialsTypePassword, identity.AuthenticatorAssuranceLevel1) + require.NoError(t, err) + s.ID = uuid.FromStringOrNil("432caf86-c1d8-401c-978a-8da89133f78b") + + t.Run("case=es256-without-jsonnet", func(t *testing.T) { + tid := "es256-no-template" + setTokenizeConfig(conf, tid, "jwk.es256.json", "") + + require.NoError(t, tkn.TokenizeSession(ctx, tid, s)) + token := validateTokenized(t, s.Tokenized, es256Key) + + resultClaims := token.Claims.(jwt.MapClaims) + assert.Equal(t, i.ID.String(), resultClaims["sub"]) + assert.Equal(t, s.ID.String(), resultClaims["sid"]) + assert.NotEmpty(t, resultClaims["jti"]) + assert.EqualValues(t, resultClaims["exp"], nowDate.Add(time.Minute).Unix()) + + snapshotx.SnapshotT(t, token.Claims, snapshotx.ExceptPaths("jti")) + }) + + t.Run("case=es512-without-jsonnet", func(t *testing.T) { + tid := "es512-no-template" + setTokenizeConfig(conf, tid, "jwk.es512.json", "") + + require.NoError(t, tkn.TokenizeSession(ctx, tid, s)) + token := validateTokenized(t, s.Tokenized, es512Key) + + snapshotx.SnapshotT(t, token.Claims, snapshotx.ExceptPaths("jti")) + }) + + t.Run("case=rs512-with-jsonnet", func(t *testing.T) { + tid := "rs512-template" + setTokenizeConfig(conf, tid, "jwk.es512.json", "file://stub/rs512-template.jsonnet") + + require.NoError(t, tkn.TokenizeSession(ctx, tid, s)) + token := validateTokenized(t, s.Tokenized, es512Key) + + snapshotx.SnapshotT(t, token.Claims, snapshotx.ExceptPaths("jti")) + }) +} diff --git a/spec/api.json b/spec/api.json index 6c12cdbf26f4..06cd193d9edc 100644 --- a/spec/api.json +++ b/spec/api.json @@ -1736,6 +1736,10 @@ "description": "The Session Issuance Timestamp\n\nWhen this session was issued at. Usually equal or close to `authenticated_at`.", "format": "date-time", "type": "string" + }, + "tokenized": { + "description": "Tokenized is the tokenized (e.g. JWT) version of the session.\n\nIt is only set when the `tokenize` query parameter was set to a valid tokenize template during calls to `/session/whoami`.", + "type": "string" } }, "required": [ @@ -6846,7 +6850,7 @@ }, "/sessions/whoami": { "get": { - "description": "Uses the HTTP Headers in the GET request to determine (e.g. by using checking the cookies) who is authenticated.\nReturns a session object in the body or 401 if the credentials are invalid or no credentials were sent.\nWhen the request it successful it adds the user ID to the 'X-Kratos-Authenticated-Identity-Id' header\nin the response.\n\nIf you call this endpoint from a server-side application, you must forward the HTTP Cookie Header to this endpoint:\n\n```js\npseudo-code example\nrouter.get('/protected-endpoint', async function (req, res) {\nconst session = await client.toSession(undefined, req.header('cookie'))\n\nconsole.log(session)\n})\n```\n\nWhen calling this endpoint from a non-browser application (e.g. mobile app) you must include the session token:\n\n```js\npseudo-code example\n...\nconst session = await client.toSession(\"the-session-token\")\n\nconsole.log(session)\n```\n\nDepending on your configuration this endpoint might return a 403 status code if the session has a lower Authenticator\nAssurance Level (AAL) than is possible for the identity. This can happen if the identity has password + webauthn\ncredentials (which would result in AAL2) but the session has only AAL1. If this error occurs, ask the user\nto sign in with the second factor or change the configuration.\n\nThis endpoint is useful for:\n\nAJAX calls. Remember to send credentials and set up CORS correctly!\nReverse proxies and API Gateways\nServer-side calls - use the `X-Session-Token` header!\n\nThis endpoint authenticates users by checking:\n\nif the `Cookie` HTTP header was set containing an Ory Kratos Session Cookie;\nif the `Authorization: bearer \u003cory-session-token\u003e` HTTP header was set with a valid Ory Kratos Session Token;\nif the `X-Session-Token` HTTP header was set with a valid Ory Kratos Session Token.\n\nIf none of these headers are set or the cookie or token are invalid, the endpoint returns a HTTP 401 status code.\n\nAs explained above, this request may fail due to several reasons. The `error.id` can be one of:\n\n`session_inactive`: No active session was found in the request (e.g. no Ory Session Cookie / Ory Session Token).\n`session_aal2_required`: An active session was found but it does not fulfil the Authenticator Assurance Level, implying that the session must (e.g.) authenticate the second factor.", + "description": "Uses the HTTP Headers in the GET request to determine (e.g. by using checking the cookies) who is authenticated.\nReturns a session object in the body or 401 if the credentials are invalid or no credentials were sent.\nWhen the request it successful it adds the user ID to the 'X-Kratos-Authenticated-Identity-Id' header\nin the response.\n\nIf you call this endpoint from a server-side application, you must forward the HTTP Cookie Header to this endpoint:\n\n```js\npseudo-code example\nrouter.get('/protected-endpoint', async function (req, res) {\nconst session = await client.toSession(undefined, req.header('cookie'))\n\nconsole.log(session)\n})\n```\n\nWhen calling this endpoint from a non-browser application (e.g. mobile app) you must include the session token:\n\n```js\npseudo-code example\n...\nconst session = await client.toSession(\"the-session-token\")\n\nconsole.log(session)\n```\n\nWhen using a token template, the token is included in the `tokenized` field of the session.\n\n```js\npseudo-code example\n...\nconst session = await client.toSession(\"the-session-token\", { tokenize_as: \"example-jwt-template\" })\n\nconsole.log(session.tokenized) // The JWT\n```\n\nDepending on your configuration this endpoint might return a 403 status code if the session has a lower Authenticator\nAssurance Level (AAL) than is possible for the identity. This can happen if the identity has password + webauthn\ncredentials (which would result in AAL2) but the session has only AAL1. If this error occurs, ask the user\nto sign in with the second factor or change the configuration.\n\nThis endpoint is useful for:\n\nAJAX calls. Remember to send credentials and set up CORS correctly!\nReverse proxies and API Gateways\nServer-side calls - use the `X-Session-Token` header!\n\nThis endpoint authenticates users by checking:\n\nif the `Cookie` HTTP header was set containing an Ory Kratos Session Cookie;\nif the `Authorization: bearer \u003cory-session-token\u003e` HTTP header was set with a valid Ory Kratos Session Token;\nif the `X-Session-Token` HTTP header was set with a valid Ory Kratos Session Token.\n\nIf none of these headers are set or the cookie or token are invalid, the endpoint returns a HTTP 401 status code.\n\nAs explained above, this request may fail due to several reasons. The `error.id` can be one of:\n\n`session_inactive`: No active session was found in the request (e.g. no Ory Session Cookie / Ory Session Token).\n`session_aal2_required`: An active session was found but it does not fulfil the Authenticator Assurance Level, implying that the session must (e.g.) authenticate the second factor.", "operationId": "toSession", "parameters": [ { @@ -6866,6 +6870,14 @@ "schema": { "type": "string" } + }, + { + "description": "Returns the session additionally as a token (such as a JWT)\n\nThe value of this parameter has to be a valid, configured Ory Session token template. For more information head over to [the documentation](http://ory.sh/docs/identities/session-to-jwt-cors).", + "in": "query", + "name": "tokenize_as", + "schema": { + "type": "string" + } } ], "responses": { diff --git a/spec/swagger.json b/spec/swagger.json index 3bfd4226af23..7d4321cf0b78 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -3010,7 +3010,7 @@ }, "/sessions/whoami": { "get": { - "description": "Uses the HTTP Headers in the GET request to determine (e.g. by using checking the cookies) who is authenticated.\nReturns a session object in the body or 401 if the credentials are invalid or no credentials were sent.\nWhen the request it successful it adds the user ID to the 'X-Kratos-Authenticated-Identity-Id' header\nin the response.\n\nIf you call this endpoint from a server-side application, you must forward the HTTP Cookie Header to this endpoint:\n\n```js\npseudo-code example\nrouter.get('/protected-endpoint', async function (req, res) {\nconst session = await client.toSession(undefined, req.header('cookie'))\n\nconsole.log(session)\n})\n```\n\nWhen calling this endpoint from a non-browser application (e.g. mobile app) you must include the session token:\n\n```js\npseudo-code example\n...\nconst session = await client.toSession(\"the-session-token\")\n\nconsole.log(session)\n```\n\nDepending on your configuration this endpoint might return a 403 status code if the session has a lower Authenticator\nAssurance Level (AAL) than is possible for the identity. This can happen if the identity has password + webauthn\ncredentials (which would result in AAL2) but the session has only AAL1. If this error occurs, ask the user\nto sign in with the second factor or change the configuration.\n\nThis endpoint is useful for:\n\nAJAX calls. Remember to send credentials and set up CORS correctly!\nReverse proxies and API Gateways\nServer-side calls - use the `X-Session-Token` header!\n\nThis endpoint authenticates users by checking:\n\nif the `Cookie` HTTP header was set containing an Ory Kratos Session Cookie;\nif the `Authorization: bearer \u003cory-session-token\u003e` HTTP header was set with a valid Ory Kratos Session Token;\nif the `X-Session-Token` HTTP header was set with a valid Ory Kratos Session Token.\n\nIf none of these headers are set or the cookie or token are invalid, the endpoint returns a HTTP 401 status code.\n\nAs explained above, this request may fail due to several reasons. The `error.id` can be one of:\n\n`session_inactive`: No active session was found in the request (e.g. no Ory Session Cookie / Ory Session Token).\n`session_aal2_required`: An active session was found but it does not fulfil the Authenticator Assurance Level, implying that the session must (e.g.) authenticate the second factor.", + "description": "Uses the HTTP Headers in the GET request to determine (e.g. by using checking the cookies) who is authenticated.\nReturns a session object in the body or 401 if the credentials are invalid or no credentials were sent.\nWhen the request it successful it adds the user ID to the 'X-Kratos-Authenticated-Identity-Id' header\nin the response.\n\nIf you call this endpoint from a server-side application, you must forward the HTTP Cookie Header to this endpoint:\n\n```js\npseudo-code example\nrouter.get('/protected-endpoint', async function (req, res) {\nconst session = await client.toSession(undefined, req.header('cookie'))\n\nconsole.log(session)\n})\n```\n\nWhen calling this endpoint from a non-browser application (e.g. mobile app) you must include the session token:\n\n```js\npseudo-code example\n...\nconst session = await client.toSession(\"the-session-token\")\n\nconsole.log(session)\n```\n\nWhen using a token template, the token is included in the `tokenized` field of the session.\n\n```js\npseudo-code example\n...\nconst session = await client.toSession(\"the-session-token\", { tokenize_as: \"example-jwt-template\" })\n\nconsole.log(session.tokenized) // The JWT\n```\n\nDepending on your configuration this endpoint might return a 403 status code if the session has a lower Authenticator\nAssurance Level (AAL) than is possible for the identity. This can happen if the identity has password + webauthn\ncredentials (which would result in AAL2) but the session has only AAL1. If this error occurs, ask the user\nto sign in with the second factor or change the configuration.\n\nThis endpoint is useful for:\n\nAJAX calls. Remember to send credentials and set up CORS correctly!\nReverse proxies and API Gateways\nServer-side calls - use the `X-Session-Token` header!\n\nThis endpoint authenticates users by checking:\n\nif the `Cookie` HTTP header was set containing an Ory Kratos Session Cookie;\nif the `Authorization: bearer \u003cory-session-token\u003e` HTTP header was set with a valid Ory Kratos Session Token;\nif the `X-Session-Token` HTTP header was set with a valid Ory Kratos Session Token.\n\nIf none of these headers are set or the cookie or token are invalid, the endpoint returns a HTTP 401 status code.\n\nAs explained above, this request may fail due to several reasons. The `error.id` can be one of:\n\n`session_inactive`: No active session was found in the request (e.g. no Ory Session Cookie / Ory Session Token).\n`session_aal2_required`: An active session was found but it does not fulfil the Authenticator Assurance Level, implying that the session must (e.g.) authenticate the second factor.", "produces": [ "application/json" ], @@ -3035,6 +3035,12 @@ "description": "Set the Cookie Header. This is especially useful when calling this endpoint from a server-side application. In that\nscenario you must include the HTTP Cookie Header which originally was included in the request to your server.\nAn example of a session in the HTTP Cookie Header is: `ory_kratos_session=a19iOVAbdzdgl70Rq1QZmrKmcjDtdsviCTZx7m9a9yHIUS8Wa9T7hvqyGTsLHi6Qifn2WUfpAKx9DWp0SJGleIn9vh2YF4A16id93kXFTgIgmwIOvbVAScyrx7yVl6bPZnCx27ec4WQDtaTewC1CpgudeDV2jQQnSaCP6ny3xa8qLH-QUgYqdQuoA_LF1phxgRCUfIrCLQOkolX5nv3ze_f==`.\n\nIt is ok if more than one cookie are included here as all other cookies will be ignored.", "name": "Cookie", "in": "header" + }, + { + "type": "string", + "description": "Returns the session additionally as a token (such as a JWT)\n\nThe value of this parameter has to be a valid, configured Ory Session token template. For more information head over to [the documentation](http://ory.sh/docs/identities/session-to-jwt-cors).", + "name": "tokenize_as", + "in": "query" } ], "responses": { @@ -4730,6 +4736,10 @@ "description": "The Session Issuance Timestamp\n\nWhen this session was issued at. Usually equal or close to `authenticated_at`.", "type": "string", "format": "date-time" + }, + "tokenized": { + "description": "Tokenized is the tokenized (e.g. JWT) version of the session.\n\nIt is only set when the `tokenize` query parameter was set to a valid tokenize template during calls to `/session/whoami`.", + "type": "string" } } }, diff --git a/x/events/events.go b/x/events/events.go index b8f26bab2ffc..83da68e98558 100644 --- a/x/events/events.go +++ b/x/events/events.go @@ -5,6 +5,7 @@ package events import ( "context" + "time" "github.com/gofrs/uuid" otelattr "go.opentelemetry.io/otel/attribute" @@ -17,6 +18,7 @@ const ( SessionIssued semconv.Event = "SessionIssued" SessionChanged semconv.Event = "SessionChanged" SessionRevoked semconv.Event = "SessionRevoked" + SessionTokenizedAsJWT semconv.Event = "SessionTokenizedAsJWT" RegistrationFailed semconv.Event = "RegistrationFailed" RegistrationSucceeded semconv.Event = "RegistrationSucceeded" LoginFailed semconv.Event = "LoginFailed" @@ -39,12 +41,17 @@ const ( attributeKeySelfServiceSSOProviderUsed semconv.AttributeKey = "SelfServiceSSOProviderUsed" attributeKeyLoginRequestedAAL semconv.AttributeKey = "LoginRequestedAAL" attributeKeyLoginRequestedPrivilegedSession semconv.AttributeKey = "LoginRequestedPrivilegedSession" + attributeKeyTokenizedSessionTTL semconv.AttributeKey = "TokenizedSessionTTL" ) func attrSessionID(val uuid.UUID) otelattr.KeyValue { return otelattr.String(attributeKeySessionID.String(), val.String()) } +func attrTokenizedSessionTTL(ttl time.Duration) otelattr.KeyValue { + return otelattr.String(attributeKeyTokenizedSessionTTL.String(), ttl.String()) +} + func attrSessionAAL(val string) otelattr.KeyValue { return otelattr.String(attributeKeySessionAAL.String(), val) } @@ -232,3 +239,15 @@ func NewSessionRevoked(ctx context.Context, sessionID, identityID uuid.UUID) (st )..., ) } + +func NewSessionJWTIssued(ctx context.Context, sessionID, identityID uuid.UUID, ttl time.Duration) (string, trace.EventOption) { + return SessionTokenizedAsJWT.String(), + trace.WithAttributes( + append( + semconv.AttributesFromContext(ctx), + semconv.AttrIdentityID(identityID), + attrSessionID(sessionID), + attrTokenizedSessionTTL(ttl), + )..., + ) +} diff --git a/x/fetcher.go b/x/fetcher.go new file mode 100644 index 000000000000..77f3dbf31099 --- /dev/null +++ b/x/fetcher.go @@ -0,0 +1,10 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package x + +import "github.com/ory/x/jwksx" + +type JWKFetchProvider interface { + Fetcher() *jwksx.FetcherNext +} From ed996c0d25e68e8a2c7de861c546f0b0e42e9e6e Mon Sep 17 00:00:00 2001 From: Jakub Pogorzelski <8654187+jpogorzelski@users.noreply.github.com> Date: Mon, 18 Sep 2023 10:24:23 +0200 Subject: [PATCH 091/282] fix: incorrect sdk generator path (#3488) --- Makefile | 4 +- internal/client-go/.openapi-generator/FILES | 1 + internal/client-go/api_v0alpha2.go | 205 ------- .../model_admin_create_identity_body.go | 363 ----------- ...create_identity_import_credentials_oidc.go | 117 ---- ...identity_import_credentials_oidc_config.go | 154 ----- ...entity_import_credentials_oidc_provider.go | 141 ----- ...te_identity_import_credentials_password.go | 117 ---- ...tity_import_credentials_password_config.go | 155 ----- ..._create_self_service_recovery_code_body.go | 148 ----- ..._create_self_service_recovery_link_body.go | 148 ----- ...model_admin_identity_import_credentials.go | 153 ----- .../model_admin_update_identity_body.go | 282 --------- .../model_continue_with_flow_view.go | 150 ----- .../model_continue_with_set_token.go | 138 ----- ...el_continue_with_verification_ui_all_of.go | 114 ---- ...ntinue_with_verification_ui_all_of_flow.go | 114 ---- .../model_courier_message_dispatch.go | 301 ---------- .../client-go/model_flow_redirect_required.go | 403 ------------- .../model_identity_credentials_otp.go | 162 ----- .../client-go/model_identity_patch_error.go | 150 ----- internal/client-go/model_json_error.go | 110 ---- internal/client-go/model_login_request.go | 410 ------------- .../model_open_id_connect_context.go | 266 --------- .../model_patch_identities_response.go | 115 ---- internal/client-go/model_revoked_sessions.go | 118 ---- ..._browser_location_change_required_error.go | 407 ------------- .../client-go/model_self_service_error.go | 222 ------- .../model_self_service_login_flow.go | 564 ------------------ .../model_self_service_login_flow_state.go | 85 --- .../model_self_service_logout_url.go | 141 ----- .../model_self_service_recovery_code.go | 179 ------ .../model_self_service_recovery_flow.go | 364 ----------- .../model_self_service_recovery_flow_state.go | 85 --- .../model_self_service_recovery_link.go | 149 ----- .../model_self_service_registration_flow.go | 417 ------------- ...el_self_service_registration_flow_state.go | 85 --- .../model_self_service_settings_flow.go | 393 ------------ .../model_self_service_settings_flow_state.go | 84 --- .../model_self_service_verification_flow.go | 385 ------------ ...el_self_service_verification_flow_state.go | 85 --- .../model_settings_profile_form_config.go | 206 ------- ...flow_with_web_authn_registration_method.go | 155 ----- ...del_submit_self_service_login_flow_body.go | 239 -------- ...gin_flow_with_lookup_secret_method_body.go | 178 ------ ...ervice_login_flow_with_oidc_method_body.go | 215 ------- ...ce_login_flow_with_password_method_body.go | 245 -------- ...ervice_login_flow_with_totp_method_body.go | 178 ------ ...e_login_flow_with_web_authn_method_body.go | 215 ------- ...ervice_logout_flow_without_browser_body.go | 111 ---- ..._submit_self_service_recovery_flow_body.go | 149 ----- ...ice_recovery_flow_with_code_method_body.go | 222 ------- ...ice_recovery_flow_with_link_method_body.go | 178 ------ ...mit_self_service_registration_flow_body.go | 179 ------ ...registration_flow_with_oidc_method_body.go | 215 ------- ...stration_flow_with_password_method_body.go | 208 ------- ...tration_flow_with_web_authn_method_body.go | 252 -------- ..._submit_self_service_settings_flow_body.go | 269 --------- ...e_settings_flow_with_lookup_method_body.go | 296 --------- ...ice_settings_flow_with_oidc_method_body.go | 259 -------- ...settings_flow_with_password_method_body.go | 178 ------ ..._settings_flow_with_profile_method_body.go | 178 ------ ...ice_settings_flow_with_totp_method_body.go | 222 ------- ...ettings_flow_with_web_authn_method_body.go | 259 -------- ...mit_self_service_verification_flow_body.go | 119 ---- ...verification_flow_with_link_method_body.go | 178 ------ ...sful_self_service_login_without_browser.go | 147 ----- ...lf_service_registration_without_browser.go | 183 ------ ...verification_flow_with_code_method_body.go | 263 -------- 69 files changed, 3 insertions(+), 13877 deletions(-) delete mode 100644 internal/client-go/api_v0alpha2.go delete mode 100644 internal/client-go/model_admin_create_identity_body.go delete mode 100644 internal/client-go/model_admin_create_identity_import_credentials_oidc.go delete mode 100644 internal/client-go/model_admin_create_identity_import_credentials_oidc_config.go delete mode 100644 internal/client-go/model_admin_create_identity_import_credentials_oidc_provider.go delete mode 100644 internal/client-go/model_admin_create_identity_import_credentials_password.go delete mode 100644 internal/client-go/model_admin_create_identity_import_credentials_password_config.go delete mode 100644 internal/client-go/model_admin_create_self_service_recovery_code_body.go delete mode 100644 internal/client-go/model_admin_create_self_service_recovery_link_body.go delete mode 100644 internal/client-go/model_admin_identity_import_credentials.go delete mode 100644 internal/client-go/model_admin_update_identity_body.go delete mode 100644 internal/client-go/model_continue_with_flow_view.go delete mode 100644 internal/client-go/model_continue_with_set_token.go delete mode 100644 internal/client-go/model_continue_with_verification_ui_all_of.go delete mode 100644 internal/client-go/model_continue_with_verification_ui_all_of_flow.go delete mode 100644 internal/client-go/model_courier_message_dispatch.go delete mode 100644 internal/client-go/model_flow_redirect_required.go delete mode 100644 internal/client-go/model_identity_credentials_otp.go delete mode 100644 internal/client-go/model_identity_patch_error.go delete mode 100644 internal/client-go/model_json_error.go delete mode 100644 internal/client-go/model_login_request.go delete mode 100644 internal/client-go/model_open_id_connect_context.go delete mode 100644 internal/client-go/model_patch_identities_response.go delete mode 100644 internal/client-go/model_revoked_sessions.go delete mode 100644 internal/client-go/model_self_service_browser_location_change_required_error.go delete mode 100644 internal/client-go/model_self_service_error.go delete mode 100644 internal/client-go/model_self_service_login_flow.go delete mode 100644 internal/client-go/model_self_service_login_flow_state.go delete mode 100644 internal/client-go/model_self_service_logout_url.go delete mode 100644 internal/client-go/model_self_service_recovery_code.go delete mode 100644 internal/client-go/model_self_service_recovery_flow.go delete mode 100644 internal/client-go/model_self_service_recovery_flow_state.go delete mode 100644 internal/client-go/model_self_service_recovery_link.go delete mode 100644 internal/client-go/model_self_service_registration_flow.go delete mode 100644 internal/client-go/model_self_service_registration_flow_state.go delete mode 100644 internal/client-go/model_self_service_settings_flow.go delete mode 100644 internal/client-go/model_self_service_settings_flow_state.go delete mode 100644 internal/client-go/model_self_service_verification_flow.go delete mode 100644 internal/client-go/model_self_service_verification_flow_state.go delete mode 100644 internal/client-go/model_settings_profile_form_config.go delete mode 100644 internal/client-go/model_submit_self_service_flow_with_web_authn_registration_method.go delete mode 100644 internal/client-go/model_submit_self_service_login_flow_body.go delete mode 100644 internal/client-go/model_submit_self_service_login_flow_with_lookup_secret_method_body.go delete mode 100644 internal/client-go/model_submit_self_service_login_flow_with_oidc_method_body.go delete mode 100644 internal/client-go/model_submit_self_service_login_flow_with_password_method_body.go delete mode 100644 internal/client-go/model_submit_self_service_login_flow_with_totp_method_body.go delete mode 100644 internal/client-go/model_submit_self_service_login_flow_with_web_authn_method_body.go delete mode 100644 internal/client-go/model_submit_self_service_logout_flow_without_browser_body.go delete mode 100644 internal/client-go/model_submit_self_service_recovery_flow_body.go delete mode 100644 internal/client-go/model_submit_self_service_recovery_flow_with_code_method_body.go delete mode 100644 internal/client-go/model_submit_self_service_recovery_flow_with_link_method_body.go delete mode 100644 internal/client-go/model_submit_self_service_registration_flow_body.go delete mode 100644 internal/client-go/model_submit_self_service_registration_flow_with_oidc_method_body.go delete mode 100644 internal/client-go/model_submit_self_service_registration_flow_with_password_method_body.go delete mode 100644 internal/client-go/model_submit_self_service_registration_flow_with_web_authn_method_body.go delete mode 100644 internal/client-go/model_submit_self_service_settings_flow_body.go delete mode 100644 internal/client-go/model_submit_self_service_settings_flow_with_lookup_method_body.go delete mode 100644 internal/client-go/model_submit_self_service_settings_flow_with_oidc_method_body.go delete mode 100644 internal/client-go/model_submit_self_service_settings_flow_with_password_method_body.go delete mode 100644 internal/client-go/model_submit_self_service_settings_flow_with_profile_method_body.go delete mode 100644 internal/client-go/model_submit_self_service_settings_flow_with_totp_method_body.go delete mode 100644 internal/client-go/model_submit_self_service_settings_flow_with_web_authn_method_body.go delete mode 100644 internal/client-go/model_submit_self_service_verification_flow_body.go delete mode 100644 internal/client-go/model_submit_self_service_verification_flow_with_link_method_body.go delete mode 100644 internal/client-go/model_successful_self_service_login_without_browser.go delete mode 100644 internal/client-go/model_successful_self_service_registration_without_browser.go delete mode 100644 internal/client-go/model_update_verification_flow_with_code_method_body.go diff --git a/Makefile b/Makefile index 854832f11cb6..e0242dab683d 100644 --- a/Makefile +++ b/Makefile @@ -129,8 +129,8 @@ sdk: .bin/swagger .bin/ory node_modules (cd internal/httpclient; rm -rf go.mod go.sum test api docs) - rm -rf internal/httpclient-central - mkdir -p internal/httpclient-central/ + rm -rf internal/client-go + mkdir -p internal/client-go/ npm run openapi-generator-cli -- generate -i "spec/api.json" \ -g go \ -o "internal/client-go" \ diff --git a/internal/client-go/.openapi-generator/FILES b/internal/client-go/.openapi-generator/FILES index c36bd85082c4..908e0021b70e 100644 --- a/internal/client-go/.openapi-generator/FILES +++ b/internal/client-go/.openapi-generator/FILES @@ -1,4 +1,5 @@ .gitignore +.openapi-generator-ignore .travis.yml README.md api/openapi.yaml diff --git a/internal/client-go/api_v0alpha2.go b/internal/client-go/api_v0alpha2.go deleted file mode 100644 index b858e85e2763..000000000000 --- a/internal/client-go/api_v0alpha2.go +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Ory Identities API - * - * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. - * - * API version: - * Contact: office@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "bytes" - "context" - "io" - "net/http" - "net/url" - "reflect" - "strings" -) - -// Linger please -var ( - _ context.Context -) - -type V0alpha2Api interface { - - /* - * AdminGetSession This endpoint returns the session object with expandables specified. - * This endpoint is useful for: - - Getting a session object with all specified expandables that exist in an administrative context. - * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - * @param id ID is the session's ID. - * @return V0alpha2ApiApiAdminGetSessionRequest - */ - AdminGetSession(ctx context.Context, id string) V0alpha2ApiApiAdminGetSessionRequest - - /* - * AdminGetSessionExecute executes the request - * @return Session - */ - AdminGetSessionExecute(r V0alpha2ApiApiAdminGetSessionRequest) (*Session, *http.Response, error) -} - -// V0alpha2ApiService V0alpha2Api service -type V0alpha2ApiService service - -type V0alpha2ApiApiAdminGetSessionRequest struct { - ctx context.Context - ApiService V0alpha2Api - id string - expand *[]string -} - -func (r V0alpha2ApiApiAdminGetSessionRequest) Expand(expand []string) V0alpha2ApiApiAdminGetSessionRequest { - r.expand = &expand - return r -} - -func (r V0alpha2ApiApiAdminGetSessionRequest) Execute() (*Session, *http.Response, error) { - return r.ApiService.AdminGetSessionExecute(r) -} - -/* - - AdminGetSession This endpoint returns the session object with expandables specified. - - This endpoint is useful for: - -Getting a session object with all specified expandables that exist in an administrative context. - - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - - @param id ID is the session's ID. - - @return V0alpha2ApiApiAdminGetSessionRequest -*/ -func (a *V0alpha2ApiService) AdminGetSession(ctx context.Context, id string) V0alpha2ApiApiAdminGetSessionRequest { - return V0alpha2ApiApiAdminGetSessionRequest{ - ApiService: a, - ctx: ctx, - id: id, - } -} - -/* - * Execute executes the request - * @return Session - */ -func (a *V0alpha2ApiService) AdminGetSessionExecute(r V0alpha2ApiApiAdminGetSessionRequest) (*Session, *http.Response, error) { - var ( - localVarHTTPMethod = http.MethodGet - localVarPostBody interface{} - localVarFormFileName string - localVarFileName string - localVarFileBytes []byte - localVarReturnValue *Session - ) - - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "V0alpha2ApiService.AdminGetSession") - if err != nil { - return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} - } - - localVarPath := localBasePath + "/admin/sessions/{id}" - localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", url.PathEscape(parameterToString(r.id, "")), -1) - - localVarHeaderParams := make(map[string]string) - localVarQueryParams := url.Values{} - localVarFormParams := url.Values{} - - if r.expand != nil { - t := *r.expand - if reflect.TypeOf(t).Kind() == reflect.Slice { - s := reflect.ValueOf(t) - for i := 0; i < s.Len(); i++ { - localVarQueryParams.Add("expand", parameterToString(s.Index(i), "multi")) - } - } else { - localVarQueryParams.Add("expand", parameterToString(t, "multi")) - } - } - // to determine the Content-Type header - localVarHTTPContentTypes := []string{} - - // set Content-Type header - localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) - if localVarHTTPContentType != "" { - localVarHeaderParams["Content-Type"] = localVarHTTPContentType - } - - // to determine the Accept header - localVarHTTPHeaderAccepts := []string{"application/json"} - - // set Accept header - localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) - if localVarHTTPHeaderAccept != "" { - localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept - } - if r.ctx != nil { - // API Key Authentication - if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { - if apiKey, ok := auth["oryAccessToken"]; ok { - var key string - if apiKey.Prefix != "" { - key = apiKey.Prefix + " " + apiKey.Key - } else { - key = apiKey.Key - } - localVarHeaderParams["Authorization"] = key - } - } - } - req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFormFileName, localVarFileName, localVarFileBytes) - if err != nil { - return localVarReturnValue, nil, err - } - - localVarHTTPResponse, err := a.client.callAPI(req) - if err != nil || localVarHTTPResponse == nil { - return localVarReturnValue, localVarHTTPResponse, err - } - - localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) - localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) - if err != nil { - return localVarReturnValue, localVarHTTPResponse, err - } - - if localVarHTTPResponse.StatusCode >= 300 { - newErr := &GenericOpenAPIError{ - body: localVarBody, - error: localVarHTTPResponse.Status, - } - if localVarHTTPResponse.StatusCode == 400 { - var v ErrorGeneric - err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) - if err != nil { - newErr.error = err.Error() - return localVarReturnValue, localVarHTTPResponse, newErr - } - newErr.model = v - return localVarReturnValue, localVarHTTPResponse, newErr - } - var v ErrorGeneric - err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) - if err != nil { - newErr.error = err.Error() - return localVarReturnValue, localVarHTTPResponse, newErr - } - newErr.model = v - return localVarReturnValue, localVarHTTPResponse, newErr - } - - err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) - if err != nil { - newErr := &GenericOpenAPIError{ - body: localVarBody, - error: err.Error(), - } - return localVarReturnValue, localVarHTTPResponse, newErr - } - - return localVarReturnValue, localVarHTTPResponse, nil -} diff --git a/internal/client-go/model_admin_create_identity_body.go b/internal/client-go/model_admin_create_identity_body.go deleted file mode 100644 index 5ad69ad52c57..000000000000 --- a/internal/client-go/model_admin_create_identity_body.go +++ /dev/null @@ -1,363 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// AdminCreateIdentityBody struct for AdminCreateIdentityBody -type AdminCreateIdentityBody struct { - Credentials *AdminIdentityImportCredentials `json:"credentials,omitempty"` - // Store metadata about the user which is only accessible through admin APIs such as `GET /admin/identities/`. - MetadataAdmin interface{} `json:"metadata_admin,omitempty"` - // Store metadata about the identity which the identity itself can see when calling for example the session endpoint. Do not store sensitive information (e.g. credit score) about the identity in this field. - MetadataPublic interface{} `json:"metadata_public,omitempty"` - // RecoveryAddresses contains all the addresses that can be used to recover an identity. Use this structure to import recovery addresses for an identity. Please keep in mind that the address needs to be represented in the Identity Schema or this field will be overwritten on the next identity update. - RecoveryAddresses []RecoveryIdentityAddress `json:"recovery_addresses,omitempty"` - // SchemaID is the ID of the JSON Schema to be used for validating the identity's traits. - SchemaId string `json:"schema_id"` - State *IdentityState `json:"state,omitempty"` - // Traits represent an identity's traits. The identity is able to create, modify, and delete traits in a self-service manner. The input will always be validated against the JSON Schema defined in `schema_url`. - Traits map[string]interface{} `json:"traits"` - // VerifiableAddresses contains all the addresses that can be verified by the user. Use this structure to import verified addresses for an identity. Please keep in mind that the address needs to be represented in the Identity Schema or this field will be overwritten on the next identity update. - VerifiableAddresses []VerifiableIdentityAddress `json:"verifiable_addresses,omitempty"` -} - -// NewAdminCreateIdentityBody instantiates a new AdminCreateIdentityBody 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 NewAdminCreateIdentityBody(schemaId string, traits map[string]interface{}) *AdminCreateIdentityBody { - this := AdminCreateIdentityBody{} - this.SchemaId = schemaId - this.Traits = traits - return &this -} - -// NewAdminCreateIdentityBodyWithDefaults instantiates a new AdminCreateIdentityBody 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 NewAdminCreateIdentityBodyWithDefaults() *AdminCreateIdentityBody { - this := AdminCreateIdentityBody{} - return &this -} - -// GetCredentials returns the Credentials field value if set, zero value otherwise. -func (o *AdminCreateIdentityBody) GetCredentials() AdminIdentityImportCredentials { - if o == nil || o.Credentials == nil { - var ret AdminIdentityImportCredentials - return ret - } - return *o.Credentials -} - -// GetCredentialsOk returns a tuple with the Credentials field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *AdminCreateIdentityBody) GetCredentialsOk() (*AdminIdentityImportCredentials, bool) { - if o == nil || o.Credentials == nil { - return nil, false - } - return o.Credentials, true -} - -// HasCredentials returns a boolean if a field has been set. -func (o *AdminCreateIdentityBody) HasCredentials() bool { - if o != nil && o.Credentials != nil { - return true - } - - return false -} - -// SetCredentials gets a reference to the given AdminIdentityImportCredentials and assigns it to the Credentials field. -func (o *AdminCreateIdentityBody) SetCredentials(v AdminIdentityImportCredentials) { - o.Credentials = &v -} - -// GetMetadataAdmin returns the MetadataAdmin field value if set, zero value otherwise (both if not set or set to explicit null). -func (o *AdminCreateIdentityBody) GetMetadataAdmin() interface{} { - if o == nil { - var ret interface{} - return ret - } - return o.MetadataAdmin -} - -// GetMetadataAdminOk returns a tuple with the MetadataAdmin 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 *AdminCreateIdentityBody) GetMetadataAdminOk() (*interface{}, bool) { - if o == nil || o.MetadataAdmin == nil { - return nil, false - } - return &o.MetadataAdmin, true -} - -// HasMetadataAdmin returns a boolean if a field has been set. -func (o *AdminCreateIdentityBody) HasMetadataAdmin() bool { - if o != nil && o.MetadataAdmin != nil { - return true - } - - return false -} - -// SetMetadataAdmin gets a reference to the given interface{} and assigns it to the MetadataAdmin field. -func (o *AdminCreateIdentityBody) SetMetadataAdmin(v interface{}) { - o.MetadataAdmin = v -} - -// GetMetadataPublic returns the MetadataPublic field value if set, zero value otherwise (both if not set or set to explicit null). -func (o *AdminCreateIdentityBody) GetMetadataPublic() interface{} { - if o == nil { - var ret interface{} - return ret - } - return o.MetadataPublic -} - -// GetMetadataPublicOk returns a tuple with the MetadataPublic 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 *AdminCreateIdentityBody) GetMetadataPublicOk() (*interface{}, bool) { - if o == nil || o.MetadataPublic == nil { - return nil, false - } - return &o.MetadataPublic, true -} - -// HasMetadataPublic returns a boolean if a field has been set. -func (o *AdminCreateIdentityBody) HasMetadataPublic() bool { - if o != nil && o.MetadataPublic != nil { - return true - } - - return false -} - -// SetMetadataPublic gets a reference to the given interface{} and assigns it to the MetadataPublic field. -func (o *AdminCreateIdentityBody) SetMetadataPublic(v interface{}) { - o.MetadataPublic = v -} - -// GetRecoveryAddresses returns the RecoveryAddresses field value if set, zero value otherwise. -func (o *AdminCreateIdentityBody) GetRecoveryAddresses() []RecoveryIdentityAddress { - if o == nil || o.RecoveryAddresses == nil { - var ret []RecoveryIdentityAddress - return ret - } - return o.RecoveryAddresses -} - -// GetRecoveryAddressesOk returns a tuple with the RecoveryAddresses field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *AdminCreateIdentityBody) GetRecoveryAddressesOk() ([]RecoveryIdentityAddress, bool) { - if o == nil || o.RecoveryAddresses == nil { - return nil, false - } - return o.RecoveryAddresses, true -} - -// HasRecoveryAddresses returns a boolean if a field has been set. -func (o *AdminCreateIdentityBody) HasRecoveryAddresses() bool { - if o != nil && o.RecoveryAddresses != nil { - return true - } - - return false -} - -// SetRecoveryAddresses gets a reference to the given []RecoveryIdentityAddress and assigns it to the RecoveryAddresses field. -func (o *AdminCreateIdentityBody) SetRecoveryAddresses(v []RecoveryIdentityAddress) { - o.RecoveryAddresses = v -} - -// GetSchemaId returns the SchemaId field value -func (o *AdminCreateIdentityBody) GetSchemaId() string { - if o == nil { - var ret string - return ret - } - - return o.SchemaId -} - -// GetSchemaIdOk returns a tuple with the SchemaId field value -// and a boolean to check if the value has been set. -func (o *AdminCreateIdentityBody) GetSchemaIdOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.SchemaId, true -} - -// SetSchemaId sets field value -func (o *AdminCreateIdentityBody) SetSchemaId(v string) { - o.SchemaId = v -} - -// GetState returns the State field value if set, zero value otherwise. -func (o *AdminCreateIdentityBody) GetState() IdentityState { - if o == nil || o.State == nil { - var ret IdentityState - return ret - } - return *o.State -} - -// GetStateOk returns a tuple with the State field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *AdminCreateIdentityBody) GetStateOk() (*IdentityState, bool) { - if o == nil || o.State == nil { - return nil, false - } - return o.State, true -} - -// HasState returns a boolean if a field has been set. -func (o *AdminCreateIdentityBody) HasState() bool { - if o != nil && o.State != nil { - return true - } - - return false -} - -// SetState gets a reference to the given IdentityState and assigns it to the State field. -func (o *AdminCreateIdentityBody) SetState(v IdentityState) { - o.State = &v -} - -// GetTraits returns the Traits field value -func (o *AdminCreateIdentityBody) GetTraits() map[string]interface{} { - if o == nil { - var ret map[string]interface{} - return ret - } - - return o.Traits -} - -// GetTraitsOk returns a tuple with the Traits field value -// and a boolean to check if the value has been set. -func (o *AdminCreateIdentityBody) GetTraitsOk() (map[string]interface{}, bool) { - if o == nil { - return nil, false - } - return o.Traits, true -} - -// SetTraits sets field value -func (o *AdminCreateIdentityBody) SetTraits(v map[string]interface{}) { - o.Traits = v -} - -// GetVerifiableAddresses returns the VerifiableAddresses field value if set, zero value otherwise. -func (o *AdminCreateIdentityBody) GetVerifiableAddresses() []VerifiableIdentityAddress { - if o == nil || o.VerifiableAddresses == nil { - var ret []VerifiableIdentityAddress - return ret - } - return o.VerifiableAddresses -} - -// GetVerifiableAddressesOk returns a tuple with the VerifiableAddresses field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *AdminCreateIdentityBody) GetVerifiableAddressesOk() ([]VerifiableIdentityAddress, bool) { - if o == nil || o.VerifiableAddresses == nil { - return nil, false - } - return o.VerifiableAddresses, true -} - -// HasVerifiableAddresses returns a boolean if a field has been set. -func (o *AdminCreateIdentityBody) HasVerifiableAddresses() bool { - if o != nil && o.VerifiableAddresses != nil { - return true - } - - return false -} - -// SetVerifiableAddresses gets a reference to the given []VerifiableIdentityAddress and assigns it to the VerifiableAddresses field. -func (o *AdminCreateIdentityBody) SetVerifiableAddresses(v []VerifiableIdentityAddress) { - o.VerifiableAddresses = v -} - -func (o AdminCreateIdentityBody) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.Credentials != nil { - toSerialize["credentials"] = o.Credentials - } - if o.MetadataAdmin != nil { - toSerialize["metadata_admin"] = o.MetadataAdmin - } - if o.MetadataPublic != nil { - toSerialize["metadata_public"] = o.MetadataPublic - } - if o.RecoveryAddresses != nil { - toSerialize["recovery_addresses"] = o.RecoveryAddresses - } - if true { - toSerialize["schema_id"] = o.SchemaId - } - if o.State != nil { - toSerialize["state"] = o.State - } - if true { - toSerialize["traits"] = o.Traits - } - if o.VerifiableAddresses != nil { - toSerialize["verifiable_addresses"] = o.VerifiableAddresses - } - return json.Marshal(toSerialize) -} - -type NullableAdminCreateIdentityBody struct { - value *AdminCreateIdentityBody - isSet bool -} - -func (v NullableAdminCreateIdentityBody) Get() *AdminCreateIdentityBody { - return v.value -} - -func (v *NullableAdminCreateIdentityBody) Set(val *AdminCreateIdentityBody) { - v.value = val - v.isSet = true -} - -func (v NullableAdminCreateIdentityBody) IsSet() bool { - return v.isSet -} - -func (v *NullableAdminCreateIdentityBody) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableAdminCreateIdentityBody(val *AdminCreateIdentityBody) *NullableAdminCreateIdentityBody { - return &NullableAdminCreateIdentityBody{value: val, isSet: true} -} - -func (v NullableAdminCreateIdentityBody) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableAdminCreateIdentityBody) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_admin_create_identity_import_credentials_oidc.go b/internal/client-go/model_admin_create_identity_import_credentials_oidc.go deleted file mode 100644 index b0646a299823..000000000000 --- a/internal/client-go/model_admin_create_identity_import_credentials_oidc.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// AdminCreateIdentityImportCredentialsOidc struct for AdminCreateIdentityImportCredentialsOidc -type AdminCreateIdentityImportCredentialsOidc struct { - Config *AdminCreateIdentityImportCredentialsOidcConfig `json:"config,omitempty"` -} - -// NewAdminCreateIdentityImportCredentialsOidc instantiates a new AdminCreateIdentityImportCredentialsOidc 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 NewAdminCreateIdentityImportCredentialsOidc() *AdminCreateIdentityImportCredentialsOidc { - this := AdminCreateIdentityImportCredentialsOidc{} - return &this -} - -// NewAdminCreateIdentityImportCredentialsOidcWithDefaults instantiates a new AdminCreateIdentityImportCredentialsOidc 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 NewAdminCreateIdentityImportCredentialsOidcWithDefaults() *AdminCreateIdentityImportCredentialsOidc { - this := AdminCreateIdentityImportCredentialsOidc{} - return &this -} - -// GetConfig returns the Config field value if set, zero value otherwise. -func (o *AdminCreateIdentityImportCredentialsOidc) GetConfig() AdminCreateIdentityImportCredentialsOidcConfig { - if o == nil || o.Config == nil { - var ret AdminCreateIdentityImportCredentialsOidcConfig - return ret - } - return *o.Config -} - -// GetConfigOk returns a tuple with the Config field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *AdminCreateIdentityImportCredentialsOidc) GetConfigOk() (*AdminCreateIdentityImportCredentialsOidcConfig, bool) { - if o == nil || o.Config == nil { - return nil, false - } - return o.Config, true -} - -// HasConfig returns a boolean if a field has been set. -func (o *AdminCreateIdentityImportCredentialsOidc) HasConfig() bool { - if o != nil && o.Config != nil { - return true - } - - return false -} - -// SetConfig gets a reference to the given AdminCreateIdentityImportCredentialsOidcConfig and assigns it to the Config field. -func (o *AdminCreateIdentityImportCredentialsOidc) SetConfig(v AdminCreateIdentityImportCredentialsOidcConfig) { - o.Config = &v -} - -func (o AdminCreateIdentityImportCredentialsOidc) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.Config != nil { - toSerialize["config"] = o.Config - } - return json.Marshal(toSerialize) -} - -type NullableAdminCreateIdentityImportCredentialsOidc struct { - value *AdminCreateIdentityImportCredentialsOidc - isSet bool -} - -func (v NullableAdminCreateIdentityImportCredentialsOidc) Get() *AdminCreateIdentityImportCredentialsOidc { - return v.value -} - -func (v *NullableAdminCreateIdentityImportCredentialsOidc) Set(val *AdminCreateIdentityImportCredentialsOidc) { - v.value = val - v.isSet = true -} - -func (v NullableAdminCreateIdentityImportCredentialsOidc) IsSet() bool { - return v.isSet -} - -func (v *NullableAdminCreateIdentityImportCredentialsOidc) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableAdminCreateIdentityImportCredentialsOidc(val *AdminCreateIdentityImportCredentialsOidc) *NullableAdminCreateIdentityImportCredentialsOidc { - return &NullableAdminCreateIdentityImportCredentialsOidc{value: val, isSet: true} -} - -func (v NullableAdminCreateIdentityImportCredentialsOidc) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableAdminCreateIdentityImportCredentialsOidc) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_admin_create_identity_import_credentials_oidc_config.go b/internal/client-go/model_admin_create_identity_import_credentials_oidc_config.go deleted file mode 100644 index 16ae2ad59897..000000000000 --- a/internal/client-go/model_admin_create_identity_import_credentials_oidc_config.go +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// AdminCreateIdentityImportCredentialsOidcConfig struct for AdminCreateIdentityImportCredentialsOidcConfig -type AdminCreateIdentityImportCredentialsOidcConfig struct { - Config *AdminCreateIdentityImportCredentialsPasswordConfig `json:"config,omitempty"` - // A list of OpenID Connect Providers - Providers []AdminCreateIdentityImportCredentialsOidcProvider `json:"providers,omitempty"` -} - -// NewAdminCreateIdentityImportCredentialsOidcConfig instantiates a new AdminCreateIdentityImportCredentialsOidcConfig 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 NewAdminCreateIdentityImportCredentialsOidcConfig() *AdminCreateIdentityImportCredentialsOidcConfig { - this := AdminCreateIdentityImportCredentialsOidcConfig{} - return &this -} - -// NewAdminCreateIdentityImportCredentialsOidcConfigWithDefaults instantiates a new AdminCreateIdentityImportCredentialsOidcConfig 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 NewAdminCreateIdentityImportCredentialsOidcConfigWithDefaults() *AdminCreateIdentityImportCredentialsOidcConfig { - this := AdminCreateIdentityImportCredentialsOidcConfig{} - return &this -} - -// GetConfig returns the Config field value if set, zero value otherwise. -func (o *AdminCreateIdentityImportCredentialsOidcConfig) GetConfig() AdminCreateIdentityImportCredentialsPasswordConfig { - if o == nil || o.Config == nil { - var ret AdminCreateIdentityImportCredentialsPasswordConfig - return ret - } - return *o.Config -} - -// GetConfigOk returns a tuple with the Config field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *AdminCreateIdentityImportCredentialsOidcConfig) GetConfigOk() (*AdminCreateIdentityImportCredentialsPasswordConfig, bool) { - if o == nil || o.Config == nil { - return nil, false - } - return o.Config, true -} - -// HasConfig returns a boolean if a field has been set. -func (o *AdminCreateIdentityImportCredentialsOidcConfig) HasConfig() bool { - if o != nil && o.Config != nil { - return true - } - - return false -} - -// SetConfig gets a reference to the given AdminCreateIdentityImportCredentialsPasswordConfig and assigns it to the Config field. -func (o *AdminCreateIdentityImportCredentialsOidcConfig) SetConfig(v AdminCreateIdentityImportCredentialsPasswordConfig) { - o.Config = &v -} - -// GetProviders returns the Providers field value if set, zero value otherwise. -func (o *AdminCreateIdentityImportCredentialsOidcConfig) GetProviders() []AdminCreateIdentityImportCredentialsOidcProvider { - if o == nil || o.Providers == nil { - var ret []AdminCreateIdentityImportCredentialsOidcProvider - return ret - } - return o.Providers -} - -// GetProvidersOk returns a tuple with the Providers field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *AdminCreateIdentityImportCredentialsOidcConfig) GetProvidersOk() ([]AdminCreateIdentityImportCredentialsOidcProvider, bool) { - if o == nil || o.Providers == nil { - return nil, false - } - return o.Providers, true -} - -// HasProviders returns a boolean if a field has been set. -func (o *AdminCreateIdentityImportCredentialsOidcConfig) HasProviders() bool { - if o != nil && o.Providers != nil { - return true - } - - return false -} - -// SetProviders gets a reference to the given []AdminCreateIdentityImportCredentialsOidcProvider and assigns it to the Providers field. -func (o *AdminCreateIdentityImportCredentialsOidcConfig) SetProviders(v []AdminCreateIdentityImportCredentialsOidcProvider) { - o.Providers = v -} - -func (o AdminCreateIdentityImportCredentialsOidcConfig) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.Config != nil { - toSerialize["config"] = o.Config - } - if o.Providers != nil { - toSerialize["providers"] = o.Providers - } - return json.Marshal(toSerialize) -} - -type NullableAdminCreateIdentityImportCredentialsOidcConfig struct { - value *AdminCreateIdentityImportCredentialsOidcConfig - isSet bool -} - -func (v NullableAdminCreateIdentityImportCredentialsOidcConfig) Get() *AdminCreateIdentityImportCredentialsOidcConfig { - return v.value -} - -func (v *NullableAdminCreateIdentityImportCredentialsOidcConfig) Set(val *AdminCreateIdentityImportCredentialsOidcConfig) { - v.value = val - v.isSet = true -} - -func (v NullableAdminCreateIdentityImportCredentialsOidcConfig) IsSet() bool { - return v.isSet -} - -func (v *NullableAdminCreateIdentityImportCredentialsOidcConfig) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableAdminCreateIdentityImportCredentialsOidcConfig(val *AdminCreateIdentityImportCredentialsOidcConfig) *NullableAdminCreateIdentityImportCredentialsOidcConfig { - return &NullableAdminCreateIdentityImportCredentialsOidcConfig{value: val, isSet: true} -} - -func (v NullableAdminCreateIdentityImportCredentialsOidcConfig) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableAdminCreateIdentityImportCredentialsOidcConfig) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_admin_create_identity_import_credentials_oidc_provider.go b/internal/client-go/model_admin_create_identity_import_credentials_oidc_provider.go deleted file mode 100644 index 6aebaa44ea4f..000000000000 --- a/internal/client-go/model_admin_create_identity_import_credentials_oidc_provider.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// AdminCreateIdentityImportCredentialsOidcProvider struct for AdminCreateIdentityImportCredentialsOidcProvider -type AdminCreateIdentityImportCredentialsOidcProvider struct { - // The OpenID Connect provider to link the subject to. Usually something like `google` or `github`. - Provider string `json:"provider"` - // The subject (`sub`) of the OpenID Connect connection. Usually the `sub` field of the ID Token. - Subject string `json:"subject"` -} - -// NewAdminCreateIdentityImportCredentialsOidcProvider instantiates a new AdminCreateIdentityImportCredentialsOidcProvider 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 NewAdminCreateIdentityImportCredentialsOidcProvider(provider string, subject string) *AdminCreateIdentityImportCredentialsOidcProvider { - this := AdminCreateIdentityImportCredentialsOidcProvider{} - this.Provider = provider - this.Subject = subject - return &this -} - -// NewAdminCreateIdentityImportCredentialsOidcProviderWithDefaults instantiates a new AdminCreateIdentityImportCredentialsOidcProvider 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 NewAdminCreateIdentityImportCredentialsOidcProviderWithDefaults() *AdminCreateIdentityImportCredentialsOidcProvider { - this := AdminCreateIdentityImportCredentialsOidcProvider{} - return &this -} - -// GetProvider returns the Provider field value -func (o *AdminCreateIdentityImportCredentialsOidcProvider) GetProvider() string { - if o == nil { - var ret string - return ret - } - - return o.Provider -} - -// GetProviderOk returns a tuple with the Provider field value -// and a boolean to check if the value has been set. -func (o *AdminCreateIdentityImportCredentialsOidcProvider) GetProviderOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Provider, true -} - -// SetProvider sets field value -func (o *AdminCreateIdentityImportCredentialsOidcProvider) SetProvider(v string) { - o.Provider = v -} - -// GetSubject returns the Subject field value -func (o *AdminCreateIdentityImportCredentialsOidcProvider) GetSubject() string { - if o == nil { - var ret string - return ret - } - - return o.Subject -} - -// GetSubjectOk returns a tuple with the Subject field value -// and a boolean to check if the value has been set. -func (o *AdminCreateIdentityImportCredentialsOidcProvider) GetSubjectOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Subject, true -} - -// SetSubject sets field value -func (o *AdminCreateIdentityImportCredentialsOidcProvider) SetSubject(v string) { - o.Subject = v -} - -func (o AdminCreateIdentityImportCredentialsOidcProvider) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if true { - toSerialize["provider"] = o.Provider - } - if true { - toSerialize["subject"] = o.Subject - } - return json.Marshal(toSerialize) -} - -type NullableAdminCreateIdentityImportCredentialsOidcProvider struct { - value *AdminCreateIdentityImportCredentialsOidcProvider - isSet bool -} - -func (v NullableAdminCreateIdentityImportCredentialsOidcProvider) Get() *AdminCreateIdentityImportCredentialsOidcProvider { - return v.value -} - -func (v *NullableAdminCreateIdentityImportCredentialsOidcProvider) Set(val *AdminCreateIdentityImportCredentialsOidcProvider) { - v.value = val - v.isSet = true -} - -func (v NullableAdminCreateIdentityImportCredentialsOidcProvider) IsSet() bool { - return v.isSet -} - -func (v *NullableAdminCreateIdentityImportCredentialsOidcProvider) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableAdminCreateIdentityImportCredentialsOidcProvider(val *AdminCreateIdentityImportCredentialsOidcProvider) *NullableAdminCreateIdentityImportCredentialsOidcProvider { - return &NullableAdminCreateIdentityImportCredentialsOidcProvider{value: val, isSet: true} -} - -func (v NullableAdminCreateIdentityImportCredentialsOidcProvider) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableAdminCreateIdentityImportCredentialsOidcProvider) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_admin_create_identity_import_credentials_password.go b/internal/client-go/model_admin_create_identity_import_credentials_password.go deleted file mode 100644 index 95d6654df20f..000000000000 --- a/internal/client-go/model_admin_create_identity_import_credentials_password.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// AdminCreateIdentityImportCredentialsPassword struct for AdminCreateIdentityImportCredentialsPassword -type AdminCreateIdentityImportCredentialsPassword struct { - Config *AdminCreateIdentityImportCredentialsPasswordConfig `json:"config,omitempty"` -} - -// NewAdminCreateIdentityImportCredentialsPassword instantiates a new AdminCreateIdentityImportCredentialsPassword 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 NewAdminCreateIdentityImportCredentialsPassword() *AdminCreateIdentityImportCredentialsPassword { - this := AdminCreateIdentityImportCredentialsPassword{} - return &this -} - -// NewAdminCreateIdentityImportCredentialsPasswordWithDefaults instantiates a new AdminCreateIdentityImportCredentialsPassword 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 NewAdminCreateIdentityImportCredentialsPasswordWithDefaults() *AdminCreateIdentityImportCredentialsPassword { - this := AdminCreateIdentityImportCredentialsPassword{} - return &this -} - -// GetConfig returns the Config field value if set, zero value otherwise. -func (o *AdminCreateIdentityImportCredentialsPassword) GetConfig() AdminCreateIdentityImportCredentialsPasswordConfig { - if o == nil || o.Config == nil { - var ret AdminCreateIdentityImportCredentialsPasswordConfig - return ret - } - return *o.Config -} - -// GetConfigOk returns a tuple with the Config field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *AdminCreateIdentityImportCredentialsPassword) GetConfigOk() (*AdminCreateIdentityImportCredentialsPasswordConfig, bool) { - if o == nil || o.Config == nil { - return nil, false - } - return o.Config, true -} - -// HasConfig returns a boolean if a field has been set. -func (o *AdminCreateIdentityImportCredentialsPassword) HasConfig() bool { - if o != nil && o.Config != nil { - return true - } - - return false -} - -// SetConfig gets a reference to the given AdminCreateIdentityImportCredentialsPasswordConfig and assigns it to the Config field. -func (o *AdminCreateIdentityImportCredentialsPassword) SetConfig(v AdminCreateIdentityImportCredentialsPasswordConfig) { - o.Config = &v -} - -func (o AdminCreateIdentityImportCredentialsPassword) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.Config != nil { - toSerialize["config"] = o.Config - } - return json.Marshal(toSerialize) -} - -type NullableAdminCreateIdentityImportCredentialsPassword struct { - value *AdminCreateIdentityImportCredentialsPassword - isSet bool -} - -func (v NullableAdminCreateIdentityImportCredentialsPassword) Get() *AdminCreateIdentityImportCredentialsPassword { - return v.value -} - -func (v *NullableAdminCreateIdentityImportCredentialsPassword) Set(val *AdminCreateIdentityImportCredentialsPassword) { - v.value = val - v.isSet = true -} - -func (v NullableAdminCreateIdentityImportCredentialsPassword) IsSet() bool { - return v.isSet -} - -func (v *NullableAdminCreateIdentityImportCredentialsPassword) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableAdminCreateIdentityImportCredentialsPassword(val *AdminCreateIdentityImportCredentialsPassword) *NullableAdminCreateIdentityImportCredentialsPassword { - return &NullableAdminCreateIdentityImportCredentialsPassword{value: val, isSet: true} -} - -func (v NullableAdminCreateIdentityImportCredentialsPassword) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableAdminCreateIdentityImportCredentialsPassword) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_admin_create_identity_import_credentials_password_config.go b/internal/client-go/model_admin_create_identity_import_credentials_password_config.go deleted file mode 100644 index c3ea31847547..000000000000 --- a/internal/client-go/model_admin_create_identity_import_credentials_password_config.go +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// AdminCreateIdentityImportCredentialsPasswordConfig struct for AdminCreateIdentityImportCredentialsPasswordConfig -type AdminCreateIdentityImportCredentialsPasswordConfig struct { - // The hashed password in [PHC format]( https://www.ory.sh/docs/kratos/concepts/credentials/username-email-password#hashed-password-format) - HashedPassword *string `json:"hashed_password,omitempty"` - // The password in plain text if no hash is available. - Password *string `json:"password,omitempty"` -} - -// NewAdminCreateIdentityImportCredentialsPasswordConfig instantiates a new AdminCreateIdentityImportCredentialsPasswordConfig 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 NewAdminCreateIdentityImportCredentialsPasswordConfig() *AdminCreateIdentityImportCredentialsPasswordConfig { - this := AdminCreateIdentityImportCredentialsPasswordConfig{} - return &this -} - -// NewAdminCreateIdentityImportCredentialsPasswordConfigWithDefaults instantiates a new AdminCreateIdentityImportCredentialsPasswordConfig 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 NewAdminCreateIdentityImportCredentialsPasswordConfigWithDefaults() *AdminCreateIdentityImportCredentialsPasswordConfig { - this := AdminCreateIdentityImportCredentialsPasswordConfig{} - return &this -} - -// GetHashedPassword returns the HashedPassword field value if set, zero value otherwise. -func (o *AdminCreateIdentityImportCredentialsPasswordConfig) GetHashedPassword() string { - if o == nil || o.HashedPassword == nil { - var ret string - return ret - } - return *o.HashedPassword -} - -// GetHashedPasswordOk returns a tuple with the HashedPassword field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *AdminCreateIdentityImportCredentialsPasswordConfig) GetHashedPasswordOk() (*string, bool) { - if o == nil || o.HashedPassword == nil { - return nil, false - } - return o.HashedPassword, true -} - -// HasHashedPassword returns a boolean if a field has been set. -func (o *AdminCreateIdentityImportCredentialsPasswordConfig) HasHashedPassword() bool { - if o != nil && o.HashedPassword != nil { - return true - } - - return false -} - -// SetHashedPassword gets a reference to the given string and assigns it to the HashedPassword field. -func (o *AdminCreateIdentityImportCredentialsPasswordConfig) SetHashedPassword(v string) { - o.HashedPassword = &v -} - -// GetPassword returns the Password field value if set, zero value otherwise. -func (o *AdminCreateIdentityImportCredentialsPasswordConfig) GetPassword() string { - if o == nil || o.Password == nil { - var ret string - return ret - } - return *o.Password -} - -// GetPasswordOk returns a tuple with the Password field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *AdminCreateIdentityImportCredentialsPasswordConfig) GetPasswordOk() (*string, bool) { - if o == nil || o.Password == nil { - return nil, false - } - return o.Password, true -} - -// HasPassword returns a boolean if a field has been set. -func (o *AdminCreateIdentityImportCredentialsPasswordConfig) HasPassword() bool { - if o != nil && o.Password != nil { - return true - } - - return false -} - -// SetPassword gets a reference to the given string and assigns it to the Password field. -func (o *AdminCreateIdentityImportCredentialsPasswordConfig) SetPassword(v string) { - o.Password = &v -} - -func (o AdminCreateIdentityImportCredentialsPasswordConfig) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.HashedPassword != nil { - toSerialize["hashed_password"] = o.HashedPassword - } - if o.Password != nil { - toSerialize["password"] = o.Password - } - return json.Marshal(toSerialize) -} - -type NullableAdminCreateIdentityImportCredentialsPasswordConfig struct { - value *AdminCreateIdentityImportCredentialsPasswordConfig - isSet bool -} - -func (v NullableAdminCreateIdentityImportCredentialsPasswordConfig) Get() *AdminCreateIdentityImportCredentialsPasswordConfig { - return v.value -} - -func (v *NullableAdminCreateIdentityImportCredentialsPasswordConfig) Set(val *AdminCreateIdentityImportCredentialsPasswordConfig) { - v.value = val - v.isSet = true -} - -func (v NullableAdminCreateIdentityImportCredentialsPasswordConfig) IsSet() bool { - return v.isSet -} - -func (v *NullableAdminCreateIdentityImportCredentialsPasswordConfig) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableAdminCreateIdentityImportCredentialsPasswordConfig(val *AdminCreateIdentityImportCredentialsPasswordConfig) *NullableAdminCreateIdentityImportCredentialsPasswordConfig { - return &NullableAdminCreateIdentityImportCredentialsPasswordConfig{value: val, isSet: true} -} - -func (v NullableAdminCreateIdentityImportCredentialsPasswordConfig) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableAdminCreateIdentityImportCredentialsPasswordConfig) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_admin_create_self_service_recovery_code_body.go b/internal/client-go/model_admin_create_self_service_recovery_code_body.go deleted file mode 100644 index 256d870c672f..000000000000 --- a/internal/client-go/model_admin_create_self_service_recovery_code_body.go +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// AdminCreateSelfServiceRecoveryCodeBody struct for AdminCreateSelfServiceRecoveryCodeBody -type AdminCreateSelfServiceRecoveryCodeBody struct { - // Code Expires In The recovery code will expire after that amount of time has passed. Defaults to the configuration value of `selfservice.methods.code.config.lifespan`. - ExpiresIn *string `json:"expires_in,omitempty"` - // Identity to Recover The identity's ID you wish to recover. - IdentityId string `json:"identity_id"` -} - -// NewAdminCreateSelfServiceRecoveryCodeBody instantiates a new AdminCreateSelfServiceRecoveryCodeBody 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 NewAdminCreateSelfServiceRecoveryCodeBody(identityId string) *AdminCreateSelfServiceRecoveryCodeBody { - this := AdminCreateSelfServiceRecoveryCodeBody{} - this.IdentityId = identityId - return &this -} - -// NewAdminCreateSelfServiceRecoveryCodeBodyWithDefaults instantiates a new AdminCreateSelfServiceRecoveryCodeBody 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 NewAdminCreateSelfServiceRecoveryCodeBodyWithDefaults() *AdminCreateSelfServiceRecoveryCodeBody { - this := AdminCreateSelfServiceRecoveryCodeBody{} - return &this -} - -// GetExpiresIn returns the ExpiresIn field value if set, zero value otherwise. -func (o *AdminCreateSelfServiceRecoveryCodeBody) GetExpiresIn() string { - if o == nil || o.ExpiresIn == nil { - var ret string - return ret - } - return *o.ExpiresIn -} - -// GetExpiresInOk returns a tuple with the ExpiresIn field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *AdminCreateSelfServiceRecoveryCodeBody) GetExpiresInOk() (*string, bool) { - if o == nil || o.ExpiresIn == nil { - return nil, false - } - return o.ExpiresIn, true -} - -// HasExpiresIn returns a boolean if a field has been set. -func (o *AdminCreateSelfServiceRecoveryCodeBody) HasExpiresIn() bool { - if o != nil && o.ExpiresIn != nil { - return true - } - - return false -} - -// SetExpiresIn gets a reference to the given string and assigns it to the ExpiresIn field. -func (o *AdminCreateSelfServiceRecoveryCodeBody) SetExpiresIn(v string) { - o.ExpiresIn = &v -} - -// GetIdentityId returns the IdentityId field value -func (o *AdminCreateSelfServiceRecoveryCodeBody) GetIdentityId() string { - if o == nil { - var ret string - return ret - } - - return o.IdentityId -} - -// GetIdentityIdOk returns a tuple with the IdentityId field value -// and a boolean to check if the value has been set. -func (o *AdminCreateSelfServiceRecoveryCodeBody) GetIdentityIdOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.IdentityId, true -} - -// SetIdentityId sets field value -func (o *AdminCreateSelfServiceRecoveryCodeBody) SetIdentityId(v string) { - o.IdentityId = v -} - -func (o AdminCreateSelfServiceRecoveryCodeBody) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.ExpiresIn != nil { - toSerialize["expires_in"] = o.ExpiresIn - } - if true { - toSerialize["identity_id"] = o.IdentityId - } - return json.Marshal(toSerialize) -} - -type NullableAdminCreateSelfServiceRecoveryCodeBody struct { - value *AdminCreateSelfServiceRecoveryCodeBody - isSet bool -} - -func (v NullableAdminCreateSelfServiceRecoveryCodeBody) Get() *AdminCreateSelfServiceRecoveryCodeBody { - return v.value -} - -func (v *NullableAdminCreateSelfServiceRecoveryCodeBody) Set(val *AdminCreateSelfServiceRecoveryCodeBody) { - v.value = val - v.isSet = true -} - -func (v NullableAdminCreateSelfServiceRecoveryCodeBody) IsSet() bool { - return v.isSet -} - -func (v *NullableAdminCreateSelfServiceRecoveryCodeBody) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableAdminCreateSelfServiceRecoveryCodeBody(val *AdminCreateSelfServiceRecoveryCodeBody) *NullableAdminCreateSelfServiceRecoveryCodeBody { - return &NullableAdminCreateSelfServiceRecoveryCodeBody{value: val, isSet: true} -} - -func (v NullableAdminCreateSelfServiceRecoveryCodeBody) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableAdminCreateSelfServiceRecoveryCodeBody) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_admin_create_self_service_recovery_link_body.go b/internal/client-go/model_admin_create_self_service_recovery_link_body.go deleted file mode 100644 index 1638891db51a..000000000000 --- a/internal/client-go/model_admin_create_self_service_recovery_link_body.go +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// AdminCreateSelfServiceRecoveryLinkBody struct for AdminCreateSelfServiceRecoveryLinkBody -type AdminCreateSelfServiceRecoveryLinkBody struct { - // Link Expires In The recovery link will expire after that amount of time has passed. Defaults to the configuration value of `selfservice.methods.code.config.lifespan`. - ExpiresIn *string `json:"expires_in,omitempty"` - // Identity to Recover The identity's ID you wish to recover. - IdentityId string `json:"identity_id"` -} - -// NewAdminCreateSelfServiceRecoveryLinkBody instantiates a new AdminCreateSelfServiceRecoveryLinkBody 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 NewAdminCreateSelfServiceRecoveryLinkBody(identityId string) *AdminCreateSelfServiceRecoveryLinkBody { - this := AdminCreateSelfServiceRecoveryLinkBody{} - this.IdentityId = identityId - return &this -} - -// NewAdminCreateSelfServiceRecoveryLinkBodyWithDefaults instantiates a new AdminCreateSelfServiceRecoveryLinkBody 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 NewAdminCreateSelfServiceRecoveryLinkBodyWithDefaults() *AdminCreateSelfServiceRecoveryLinkBody { - this := AdminCreateSelfServiceRecoveryLinkBody{} - return &this -} - -// GetExpiresIn returns the ExpiresIn field value if set, zero value otherwise. -func (o *AdminCreateSelfServiceRecoveryLinkBody) GetExpiresIn() string { - if o == nil || o.ExpiresIn == nil { - var ret string - return ret - } - return *o.ExpiresIn -} - -// GetExpiresInOk returns a tuple with the ExpiresIn field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *AdminCreateSelfServiceRecoveryLinkBody) GetExpiresInOk() (*string, bool) { - if o == nil || o.ExpiresIn == nil { - return nil, false - } - return o.ExpiresIn, true -} - -// HasExpiresIn returns a boolean if a field has been set. -func (o *AdminCreateSelfServiceRecoveryLinkBody) HasExpiresIn() bool { - if o != nil && o.ExpiresIn != nil { - return true - } - - return false -} - -// SetExpiresIn gets a reference to the given string and assigns it to the ExpiresIn field. -func (o *AdminCreateSelfServiceRecoveryLinkBody) SetExpiresIn(v string) { - o.ExpiresIn = &v -} - -// GetIdentityId returns the IdentityId field value -func (o *AdminCreateSelfServiceRecoveryLinkBody) GetIdentityId() string { - if o == nil { - var ret string - return ret - } - - return o.IdentityId -} - -// GetIdentityIdOk returns a tuple with the IdentityId field value -// and a boolean to check if the value has been set. -func (o *AdminCreateSelfServiceRecoveryLinkBody) GetIdentityIdOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.IdentityId, true -} - -// SetIdentityId sets field value -func (o *AdminCreateSelfServiceRecoveryLinkBody) SetIdentityId(v string) { - o.IdentityId = v -} - -func (o AdminCreateSelfServiceRecoveryLinkBody) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.ExpiresIn != nil { - toSerialize["expires_in"] = o.ExpiresIn - } - if true { - toSerialize["identity_id"] = o.IdentityId - } - return json.Marshal(toSerialize) -} - -type NullableAdminCreateSelfServiceRecoveryLinkBody struct { - value *AdminCreateSelfServiceRecoveryLinkBody - isSet bool -} - -func (v NullableAdminCreateSelfServiceRecoveryLinkBody) Get() *AdminCreateSelfServiceRecoveryLinkBody { - return v.value -} - -func (v *NullableAdminCreateSelfServiceRecoveryLinkBody) Set(val *AdminCreateSelfServiceRecoveryLinkBody) { - v.value = val - v.isSet = true -} - -func (v NullableAdminCreateSelfServiceRecoveryLinkBody) IsSet() bool { - return v.isSet -} - -func (v *NullableAdminCreateSelfServiceRecoveryLinkBody) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableAdminCreateSelfServiceRecoveryLinkBody(val *AdminCreateSelfServiceRecoveryLinkBody) *NullableAdminCreateSelfServiceRecoveryLinkBody { - return &NullableAdminCreateSelfServiceRecoveryLinkBody{value: val, isSet: true} -} - -func (v NullableAdminCreateSelfServiceRecoveryLinkBody) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableAdminCreateSelfServiceRecoveryLinkBody) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_admin_identity_import_credentials.go b/internal/client-go/model_admin_identity_import_credentials.go deleted file mode 100644 index 30599e955181..000000000000 --- a/internal/client-go/model_admin_identity_import_credentials.go +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// AdminIdentityImportCredentials struct for AdminIdentityImportCredentials -type AdminIdentityImportCredentials struct { - Oidc *AdminCreateIdentityImportCredentialsOidc `json:"oidc,omitempty"` - Password *AdminCreateIdentityImportCredentialsPassword `json:"password,omitempty"` -} - -// NewAdminIdentityImportCredentials instantiates a new AdminIdentityImportCredentials 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 NewAdminIdentityImportCredentials() *AdminIdentityImportCredentials { - this := AdminIdentityImportCredentials{} - return &this -} - -// NewAdminIdentityImportCredentialsWithDefaults instantiates a new AdminIdentityImportCredentials 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 NewAdminIdentityImportCredentialsWithDefaults() *AdminIdentityImportCredentials { - this := AdminIdentityImportCredentials{} - return &this -} - -// GetOidc returns the Oidc field value if set, zero value otherwise. -func (o *AdminIdentityImportCredentials) GetOidc() AdminCreateIdentityImportCredentialsOidc { - if o == nil || o.Oidc == nil { - var ret AdminCreateIdentityImportCredentialsOidc - return ret - } - return *o.Oidc -} - -// GetOidcOk returns a tuple with the Oidc field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *AdminIdentityImportCredentials) GetOidcOk() (*AdminCreateIdentityImportCredentialsOidc, bool) { - if o == nil || o.Oidc == nil { - return nil, false - } - return o.Oidc, true -} - -// HasOidc returns a boolean if a field has been set. -func (o *AdminIdentityImportCredentials) HasOidc() bool { - if o != nil && o.Oidc != nil { - return true - } - - return false -} - -// SetOidc gets a reference to the given AdminCreateIdentityImportCredentialsOidc and assigns it to the Oidc field. -func (o *AdminIdentityImportCredentials) SetOidc(v AdminCreateIdentityImportCredentialsOidc) { - o.Oidc = &v -} - -// GetPassword returns the Password field value if set, zero value otherwise. -func (o *AdminIdentityImportCredentials) GetPassword() AdminCreateIdentityImportCredentialsPassword { - if o == nil || o.Password == nil { - var ret AdminCreateIdentityImportCredentialsPassword - return ret - } - return *o.Password -} - -// GetPasswordOk returns a tuple with the Password field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *AdminIdentityImportCredentials) GetPasswordOk() (*AdminCreateIdentityImportCredentialsPassword, bool) { - if o == nil || o.Password == nil { - return nil, false - } - return o.Password, true -} - -// HasPassword returns a boolean if a field has been set. -func (o *AdminIdentityImportCredentials) HasPassword() bool { - if o != nil && o.Password != nil { - return true - } - - return false -} - -// SetPassword gets a reference to the given AdminCreateIdentityImportCredentialsPassword and assigns it to the Password field. -func (o *AdminIdentityImportCredentials) SetPassword(v AdminCreateIdentityImportCredentialsPassword) { - o.Password = &v -} - -func (o AdminIdentityImportCredentials) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.Oidc != nil { - toSerialize["oidc"] = o.Oidc - } - if o.Password != nil { - toSerialize["password"] = o.Password - } - return json.Marshal(toSerialize) -} - -type NullableAdminIdentityImportCredentials struct { - value *AdminIdentityImportCredentials - isSet bool -} - -func (v NullableAdminIdentityImportCredentials) Get() *AdminIdentityImportCredentials { - return v.value -} - -func (v *NullableAdminIdentityImportCredentials) Set(val *AdminIdentityImportCredentials) { - v.value = val - v.isSet = true -} - -func (v NullableAdminIdentityImportCredentials) IsSet() bool { - return v.isSet -} - -func (v *NullableAdminIdentityImportCredentials) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableAdminIdentityImportCredentials(val *AdminIdentityImportCredentials) *NullableAdminIdentityImportCredentials { - return &NullableAdminIdentityImportCredentials{value: val, isSet: true} -} - -func (v NullableAdminIdentityImportCredentials) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableAdminIdentityImportCredentials) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_admin_update_identity_body.go b/internal/client-go/model_admin_update_identity_body.go deleted file mode 100644 index e0e0a2ac1e32..000000000000 --- a/internal/client-go/model_admin_update_identity_body.go +++ /dev/null @@ -1,282 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// AdminUpdateIdentityBody struct for AdminUpdateIdentityBody -type AdminUpdateIdentityBody struct { - Credentials *AdminIdentityImportCredentials `json:"credentials,omitempty"` - // Store metadata about the user which is only accessible through admin APIs such as `GET /admin/identities/`. - MetadataAdmin interface{} `json:"metadata_admin,omitempty"` - // Store metadata about the identity which the identity itself can see when calling for example the session endpoint. Do not store sensitive information (e.g. credit score) about the identity in this field. - MetadataPublic interface{} `json:"metadata_public,omitempty"` - // SchemaID is the ID of the JSON Schema to be used for validating the identity's traits. If set will update the Identity's SchemaID. - SchemaId string `json:"schema_id"` - State IdentityState `json:"state"` - // Traits represent an identity's traits. The identity is able to create, modify, and delete traits in a self-service manner. The input will always be validated against the JSON Schema defined in `schema_id`. - Traits map[string]interface{} `json:"traits"` -} - -// NewAdminUpdateIdentityBody instantiates a new AdminUpdateIdentityBody 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 NewAdminUpdateIdentityBody(schemaId string, state IdentityState, traits map[string]interface{}) *AdminUpdateIdentityBody { - this := AdminUpdateIdentityBody{} - this.SchemaId = schemaId - this.State = state - this.Traits = traits - return &this -} - -// NewAdminUpdateIdentityBodyWithDefaults instantiates a new AdminUpdateIdentityBody 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 NewAdminUpdateIdentityBodyWithDefaults() *AdminUpdateIdentityBody { - this := AdminUpdateIdentityBody{} - return &this -} - -// GetCredentials returns the Credentials field value if set, zero value otherwise. -func (o *AdminUpdateIdentityBody) GetCredentials() AdminIdentityImportCredentials { - if o == nil || o.Credentials == nil { - var ret AdminIdentityImportCredentials - return ret - } - return *o.Credentials -} - -// GetCredentialsOk returns a tuple with the Credentials field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *AdminUpdateIdentityBody) GetCredentialsOk() (*AdminIdentityImportCredentials, bool) { - if o == nil || o.Credentials == nil { - return nil, false - } - return o.Credentials, true -} - -// HasCredentials returns a boolean if a field has been set. -func (o *AdminUpdateIdentityBody) HasCredentials() bool { - if o != nil && o.Credentials != nil { - return true - } - - return false -} - -// SetCredentials gets a reference to the given AdminIdentityImportCredentials and assigns it to the Credentials field. -func (o *AdminUpdateIdentityBody) SetCredentials(v AdminIdentityImportCredentials) { - o.Credentials = &v -} - -// GetMetadataAdmin returns the MetadataAdmin field value if set, zero value otherwise (both if not set or set to explicit null). -func (o *AdminUpdateIdentityBody) GetMetadataAdmin() interface{} { - if o == nil { - var ret interface{} - return ret - } - return o.MetadataAdmin -} - -// GetMetadataAdminOk returns a tuple with the MetadataAdmin 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 *AdminUpdateIdentityBody) GetMetadataAdminOk() (*interface{}, bool) { - if o == nil || o.MetadataAdmin == nil { - return nil, false - } - return &o.MetadataAdmin, true -} - -// HasMetadataAdmin returns a boolean if a field has been set. -func (o *AdminUpdateIdentityBody) HasMetadataAdmin() bool { - if o != nil && o.MetadataAdmin != nil { - return true - } - - return false -} - -// SetMetadataAdmin gets a reference to the given interface{} and assigns it to the MetadataAdmin field. -func (o *AdminUpdateIdentityBody) SetMetadataAdmin(v interface{}) { - o.MetadataAdmin = v -} - -// GetMetadataPublic returns the MetadataPublic field value if set, zero value otherwise (both if not set or set to explicit null). -func (o *AdminUpdateIdentityBody) GetMetadataPublic() interface{} { - if o == nil { - var ret interface{} - return ret - } - return o.MetadataPublic -} - -// GetMetadataPublicOk returns a tuple with the MetadataPublic 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 *AdminUpdateIdentityBody) GetMetadataPublicOk() (*interface{}, bool) { - if o == nil || o.MetadataPublic == nil { - return nil, false - } - return &o.MetadataPublic, true -} - -// HasMetadataPublic returns a boolean if a field has been set. -func (o *AdminUpdateIdentityBody) HasMetadataPublic() bool { - if o != nil && o.MetadataPublic != nil { - return true - } - - return false -} - -// SetMetadataPublic gets a reference to the given interface{} and assigns it to the MetadataPublic field. -func (o *AdminUpdateIdentityBody) SetMetadataPublic(v interface{}) { - o.MetadataPublic = v -} - -// GetSchemaId returns the SchemaId field value -func (o *AdminUpdateIdentityBody) GetSchemaId() string { - if o == nil { - var ret string - return ret - } - - return o.SchemaId -} - -// GetSchemaIdOk returns a tuple with the SchemaId field value -// and a boolean to check if the value has been set. -func (o *AdminUpdateIdentityBody) GetSchemaIdOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.SchemaId, true -} - -// SetSchemaId sets field value -func (o *AdminUpdateIdentityBody) SetSchemaId(v string) { - o.SchemaId = v -} - -// GetState returns the State field value -func (o *AdminUpdateIdentityBody) GetState() IdentityState { - if o == nil { - var ret IdentityState - return ret - } - - return o.State -} - -// GetStateOk returns a tuple with the State field value -// and a boolean to check if the value has been set. -func (o *AdminUpdateIdentityBody) GetStateOk() (*IdentityState, bool) { - if o == nil { - return nil, false - } - return &o.State, true -} - -// SetState sets field value -func (o *AdminUpdateIdentityBody) SetState(v IdentityState) { - o.State = v -} - -// GetTraits returns the Traits field value -func (o *AdminUpdateIdentityBody) GetTraits() map[string]interface{} { - if o == nil { - var ret map[string]interface{} - return ret - } - - return o.Traits -} - -// GetTraitsOk returns a tuple with the Traits field value -// and a boolean to check if the value has been set. -func (o *AdminUpdateIdentityBody) GetTraitsOk() (map[string]interface{}, bool) { - if o == nil { - return nil, false - } - return o.Traits, true -} - -// SetTraits sets field value -func (o *AdminUpdateIdentityBody) SetTraits(v map[string]interface{}) { - o.Traits = v -} - -func (o AdminUpdateIdentityBody) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.Credentials != nil { - toSerialize["credentials"] = o.Credentials - } - if o.MetadataAdmin != nil { - toSerialize["metadata_admin"] = o.MetadataAdmin - } - if o.MetadataPublic != nil { - toSerialize["metadata_public"] = o.MetadataPublic - } - if true { - toSerialize["schema_id"] = o.SchemaId - } - if true { - toSerialize["state"] = o.State - } - if true { - toSerialize["traits"] = o.Traits - } - return json.Marshal(toSerialize) -} - -type NullableAdminUpdateIdentityBody struct { - value *AdminUpdateIdentityBody - isSet bool -} - -func (v NullableAdminUpdateIdentityBody) Get() *AdminUpdateIdentityBody { - return v.value -} - -func (v *NullableAdminUpdateIdentityBody) Set(val *AdminUpdateIdentityBody) { - v.value = val - v.isSet = true -} - -func (v NullableAdminUpdateIdentityBody) IsSet() bool { - return v.isSet -} - -func (v *NullableAdminUpdateIdentityBody) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableAdminUpdateIdentityBody(val *AdminUpdateIdentityBody) *NullableAdminUpdateIdentityBody { - return &NullableAdminUpdateIdentityBody{value: val, isSet: true} -} - -func (v NullableAdminUpdateIdentityBody) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableAdminUpdateIdentityBody) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_continue_with_flow_view.go b/internal/client-go/model_continue_with_flow_view.go deleted file mode 100644 index 66d7e57fda0e..000000000000 --- a/internal/client-go/model_continue_with_flow_view.go +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Ory Identities API - * - * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. - * - * API version: - * Contact: office@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// ContinueWithFlowView struct for ContinueWithFlowView -type ContinueWithFlowView struct { - Class *string `json:"class,omitempty"` - Id *string `json:"id,omitempty"` -} - -// NewContinueWithFlowView instantiates a new ContinueWithFlowView 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 NewContinueWithFlowView() *ContinueWithFlowView { - this := ContinueWithFlowView{} - return &this -} - -// NewContinueWithFlowViewWithDefaults instantiates a new ContinueWithFlowView 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 NewContinueWithFlowViewWithDefaults() *ContinueWithFlowView { - this := ContinueWithFlowView{} - return &this -} - -// GetClass returns the Class field value if set, zero value otherwise. -func (o *ContinueWithFlowView) GetClass() string { - if o == nil || o.Class == nil { - var ret string - return ret - } - return *o.Class -} - -// GetClassOk returns a tuple with the Class field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *ContinueWithFlowView) GetClassOk() (*string, bool) { - if o == nil || o.Class == nil { - return nil, false - } - return o.Class, true -} - -// HasClass returns a boolean if a field has been set. -func (o *ContinueWithFlowView) HasClass() bool { - if o != nil && o.Class != nil { - return true - } - - return false -} - -// SetClass gets a reference to the given string and assigns it to the Class field. -func (o *ContinueWithFlowView) SetClass(v string) { - o.Class = &v -} - -// GetId returns the Id field value if set, zero value otherwise. -func (o *ContinueWithFlowView) GetId() string { - if o == nil || o.Id == nil { - var ret string - return ret - } - return *o.Id -} - -// GetIdOk returns a tuple with the Id field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *ContinueWithFlowView) GetIdOk() (*string, bool) { - if o == nil || o.Id == nil { - return nil, false - } - return o.Id, true -} - -// HasId returns a boolean if a field has been set. -func (o *ContinueWithFlowView) HasId() bool { - if o != nil && o.Id != nil { - return true - } - - return false -} - -// SetId gets a reference to the given string and assigns it to the Id field. -func (o *ContinueWithFlowView) SetId(v string) { - o.Id = &v -} - -func (o ContinueWithFlowView) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.Class != nil { - toSerialize["class"] = o.Class - } - if o.Id != nil { - toSerialize["id"] = o.Id - } - return json.Marshal(toSerialize) -} - -type NullableContinueWithFlowView struct { - value *ContinueWithFlowView - isSet bool -} - -func (v NullableContinueWithFlowView) Get() *ContinueWithFlowView { - return v.value -} - -func (v *NullableContinueWithFlowView) Set(val *ContinueWithFlowView) { - v.value = val - v.isSet = true -} - -func (v NullableContinueWithFlowView) IsSet() bool { - return v.isSet -} - -func (v *NullableContinueWithFlowView) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableContinueWithFlowView(val *ContinueWithFlowView) *NullableContinueWithFlowView { - return &NullableContinueWithFlowView{value: val, isSet: true} -} - -func (v NullableContinueWithFlowView) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableContinueWithFlowView) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_continue_with_set_token.go b/internal/client-go/model_continue_with_set_token.go deleted file mode 100644 index b7dc65ea984f..000000000000 --- a/internal/client-go/model_continue_with_set_token.go +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Ory Identities API - * - * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. - * - * API version: - * Contact: office@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// ContinueWithSetToken Indicates that a session was issued, and the application should use this token for authenticated requests -type ContinueWithSetToken struct { - // Action will always be `set_token` set_token ContinueWithActionSetToken verification_ui ContinueWithActionVerificationUI - Action string `json:"action"` - // Token is the token of the session - Token string `json:"token"` -} - -// NewContinueWithSetToken instantiates a new ContinueWithSetToken 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 NewContinueWithSetToken(action string, token string) *ContinueWithSetToken { - this := ContinueWithSetToken{} - this.Action = action - this.Token = token - return &this -} - -// NewContinueWithSetTokenWithDefaults instantiates a new ContinueWithSetToken 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 NewContinueWithSetTokenWithDefaults() *ContinueWithSetToken { - this := ContinueWithSetToken{} - return &this -} - -// GetAction returns the Action field value -func (o *ContinueWithSetToken) GetAction() string { - if o == nil { - var ret string - return ret - } - - return o.Action -} - -// GetActionOk returns a tuple with the Action field value -// and a boolean to check if the value has been set. -func (o *ContinueWithSetToken) GetActionOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Action, true -} - -// SetAction sets field value -func (o *ContinueWithSetToken) SetAction(v string) { - o.Action = v -} - -// GetToken returns the Token field value -func (o *ContinueWithSetToken) GetToken() string { - if o == nil { - var ret string - return ret - } - - return o.Token -} - -// GetTokenOk returns a tuple with the Token field value -// and a boolean to check if the value has been set. -func (o *ContinueWithSetToken) GetTokenOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Token, true -} - -// SetToken sets field value -func (o *ContinueWithSetToken) SetToken(v string) { - o.Token = v -} - -func (o ContinueWithSetToken) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if true { - toSerialize["action"] = o.Action - } - if true { - toSerialize["token"] = o.Token - } - return json.Marshal(toSerialize) -} - -type NullableContinueWithSetToken struct { - value *ContinueWithSetToken - isSet bool -} - -func (v NullableContinueWithSetToken) Get() *ContinueWithSetToken { - return v.value -} - -func (v *NullableContinueWithSetToken) Set(val *ContinueWithSetToken) { - v.value = val - v.isSet = true -} - -func (v NullableContinueWithSetToken) IsSet() bool { - return v.isSet -} - -func (v *NullableContinueWithSetToken) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableContinueWithSetToken(val *ContinueWithSetToken) *NullableContinueWithSetToken { - return &NullableContinueWithSetToken{value: val, isSet: true} -} - -func (v NullableContinueWithSetToken) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableContinueWithSetToken) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_continue_with_verification_ui_all_of.go b/internal/client-go/model_continue_with_verification_ui_all_of.go deleted file mode 100644 index ac19e398f12a..000000000000 --- a/internal/client-go/model_continue_with_verification_ui_all_of.go +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Ory Identities API - * - * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. - * - * API version: - * Contact: office@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// ContinueWithVerificationUiAllOf struct for ContinueWithVerificationUiAllOf -type ContinueWithVerificationUiAllOf struct { - Flow *ContinueWithVerificationUiAllOfFlow `json:"flow,omitempty"` -} - -// NewContinueWithVerificationUiAllOf instantiates a new ContinueWithVerificationUiAllOf 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 NewContinueWithVerificationUiAllOf() *ContinueWithVerificationUiAllOf { - this := ContinueWithVerificationUiAllOf{} - return &this -} - -// NewContinueWithVerificationUiAllOfWithDefaults instantiates a new ContinueWithVerificationUiAllOf 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 NewContinueWithVerificationUiAllOfWithDefaults() *ContinueWithVerificationUiAllOf { - this := ContinueWithVerificationUiAllOf{} - return &this -} - -// GetFlow returns the Flow field value if set, zero value otherwise. -func (o *ContinueWithVerificationUiAllOf) GetFlow() ContinueWithVerificationUiAllOfFlow { - if o == nil || o.Flow == nil { - var ret ContinueWithVerificationUiAllOfFlow - return ret - } - return *o.Flow -} - -// GetFlowOk returns a tuple with the Flow field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *ContinueWithVerificationUiAllOf) GetFlowOk() (*ContinueWithVerificationUiAllOfFlow, bool) { - if o == nil || o.Flow == nil { - return nil, false - } - return o.Flow, true -} - -// HasFlow returns a boolean if a field has been set. -func (o *ContinueWithVerificationUiAllOf) HasFlow() bool { - if o != nil && o.Flow != nil { - return true - } - - return false -} - -// SetFlow gets a reference to the given ContinueWithVerificationUiAllOfFlow and assigns it to the Flow field. -func (o *ContinueWithVerificationUiAllOf) SetFlow(v ContinueWithVerificationUiAllOfFlow) { - o.Flow = &v -} - -func (o ContinueWithVerificationUiAllOf) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.Flow != nil { - toSerialize["flow"] = o.Flow - } - return json.Marshal(toSerialize) -} - -type NullableContinueWithVerificationUiAllOf struct { - value *ContinueWithVerificationUiAllOf - isSet bool -} - -func (v NullableContinueWithVerificationUiAllOf) Get() *ContinueWithVerificationUiAllOf { - return v.value -} - -func (v *NullableContinueWithVerificationUiAllOf) Set(val *ContinueWithVerificationUiAllOf) { - v.value = val - v.isSet = true -} - -func (v NullableContinueWithVerificationUiAllOf) IsSet() bool { - return v.isSet -} - -func (v *NullableContinueWithVerificationUiAllOf) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableContinueWithVerificationUiAllOf(val *ContinueWithVerificationUiAllOf) *NullableContinueWithVerificationUiAllOf { - return &NullableContinueWithVerificationUiAllOf{value: val, isSet: true} -} - -func (v NullableContinueWithVerificationUiAllOf) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableContinueWithVerificationUiAllOf) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_continue_with_verification_ui_all_of_flow.go b/internal/client-go/model_continue_with_verification_ui_all_of_flow.go deleted file mode 100644 index 0ac337cc7935..000000000000 --- a/internal/client-go/model_continue_with_verification_ui_all_of_flow.go +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Ory Identities API - * - * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. - * - * API version: - * Contact: office@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// ContinueWithVerificationUiAllOfFlow struct for ContinueWithVerificationUiAllOfFlow -type ContinueWithVerificationUiAllOfFlow struct { - Id *string `json:"id,omitempty"` -} - -// NewContinueWithVerificationUiAllOfFlow instantiates a new ContinueWithVerificationUiAllOfFlow 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 NewContinueWithVerificationUiAllOfFlow() *ContinueWithVerificationUiAllOfFlow { - this := ContinueWithVerificationUiAllOfFlow{} - return &this -} - -// NewContinueWithVerificationUiAllOfFlowWithDefaults instantiates a new ContinueWithVerificationUiAllOfFlow 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 NewContinueWithVerificationUiAllOfFlowWithDefaults() *ContinueWithVerificationUiAllOfFlow { - this := ContinueWithVerificationUiAllOfFlow{} - return &this -} - -// GetId returns the Id field value if set, zero value otherwise. -func (o *ContinueWithVerificationUiAllOfFlow) GetId() string { - if o == nil || o.Id == nil { - var ret string - return ret - } - return *o.Id -} - -// GetIdOk returns a tuple with the Id field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *ContinueWithVerificationUiAllOfFlow) GetIdOk() (*string, bool) { - if o == nil || o.Id == nil { - return nil, false - } - return o.Id, true -} - -// HasId returns a boolean if a field has been set. -func (o *ContinueWithVerificationUiAllOfFlow) HasId() bool { - if o != nil && o.Id != nil { - return true - } - - return false -} - -// SetId gets a reference to the given string and assigns it to the Id field. -func (o *ContinueWithVerificationUiAllOfFlow) SetId(v string) { - o.Id = &v -} - -func (o ContinueWithVerificationUiAllOfFlow) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.Id != nil { - toSerialize["id"] = o.Id - } - return json.Marshal(toSerialize) -} - -type NullableContinueWithVerificationUiAllOfFlow struct { - value *ContinueWithVerificationUiAllOfFlow - isSet bool -} - -func (v NullableContinueWithVerificationUiAllOfFlow) Get() *ContinueWithVerificationUiAllOfFlow { - return v.value -} - -func (v *NullableContinueWithVerificationUiAllOfFlow) Set(val *ContinueWithVerificationUiAllOfFlow) { - v.value = val - v.isSet = true -} - -func (v NullableContinueWithVerificationUiAllOfFlow) IsSet() bool { - return v.isSet -} - -func (v *NullableContinueWithVerificationUiAllOfFlow) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableContinueWithVerificationUiAllOfFlow(val *ContinueWithVerificationUiAllOfFlow) *NullableContinueWithVerificationUiAllOfFlow { - return &NullableContinueWithVerificationUiAllOfFlow{value: val, isSet: true} -} - -func (v NullableContinueWithVerificationUiAllOfFlow) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableContinueWithVerificationUiAllOfFlow) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_courier_message_dispatch.go b/internal/client-go/model_courier_message_dispatch.go deleted file mode 100644 index fd2ba43945e3..000000000000 --- a/internal/client-go/model_courier_message_dispatch.go +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Ory Identities API - * - * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. - * - * API version: - * Contact: office@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" - "time" -) - -// CourierMessageDispatch CourierMessageDispatch represents an attempt of sending a courier message It contains the status of the attempt (failed or successful) and the error if any occured -type CourierMessageDispatch struct { - // CreatedAt is a helper struct field for gobuffalo.pop. - CreatedAt *time.Time `json:"created_at,omitempty"` - // An optional error - Error *string `json:"error,omitempty"` - // The ID of this message dispatch - Id *string `json:"id,omitempty"` - // The ID of th message being dispatched - MessageId *string `json:"message_id,omitempty"` - // The status of this dispatch Either \"failed\" or \"success\" failed CourierMessageDispatchStatusFailed success CourierMessageDispatchStatusSuccess - Status *string `json:"status,omitempty"` - // UpdatedAt is a helper struct field for gobuffalo.pop. - UpdatedAt *time.Time `json:"updated_at,omitempty"` -} - -// NewCourierMessageDispatch instantiates a new CourierMessageDispatch 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 NewCourierMessageDispatch() *CourierMessageDispatch { - this := CourierMessageDispatch{} - return &this -} - -// NewCourierMessageDispatchWithDefaults instantiates a new CourierMessageDispatch 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 NewCourierMessageDispatchWithDefaults() *CourierMessageDispatch { - this := CourierMessageDispatch{} - return &this -} - -// GetCreatedAt returns the CreatedAt field value if set, zero value otherwise. -func (o *CourierMessageDispatch) 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 *CourierMessageDispatch) 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 *CourierMessageDispatch) 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 *CourierMessageDispatch) SetCreatedAt(v time.Time) { - o.CreatedAt = &v -} - -// GetError returns the Error field value if set, zero value otherwise. -func (o *CourierMessageDispatch) GetError() string { - if o == nil || o.Error == nil { - var ret string - return ret - } - return *o.Error -} - -// GetErrorOk returns a tuple with the Error field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *CourierMessageDispatch) GetErrorOk() (*string, bool) { - if o == nil || o.Error == nil { - return nil, false - } - return o.Error, true -} - -// HasError returns a boolean if a field has been set. -func (o *CourierMessageDispatch) HasError() bool { - if o != nil && o.Error != nil { - return true - } - - return false -} - -// SetError gets a reference to the given string and assigns it to the Error field. -func (o *CourierMessageDispatch) SetError(v string) { - o.Error = &v -} - -// GetId returns the Id field value if set, zero value otherwise. -func (o *CourierMessageDispatch) GetId() string { - if o == nil || o.Id == nil { - var ret string - return ret - } - return *o.Id -} - -// GetIdOk returns a tuple with the Id field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *CourierMessageDispatch) GetIdOk() (*string, bool) { - if o == nil || o.Id == nil { - return nil, false - } - return o.Id, true -} - -// HasId returns a boolean if a field has been set. -func (o *CourierMessageDispatch) HasId() bool { - if o != nil && o.Id != nil { - return true - } - - return false -} - -// SetId gets a reference to the given string and assigns it to the Id field. -func (o *CourierMessageDispatch) SetId(v string) { - o.Id = &v -} - -// GetMessageId returns the MessageId field value if set, zero value otherwise. -func (o *CourierMessageDispatch) GetMessageId() string { - if o == nil || o.MessageId == nil { - var ret string - return ret - } - return *o.MessageId -} - -// GetMessageIdOk returns a tuple with the MessageId field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *CourierMessageDispatch) GetMessageIdOk() (*string, bool) { - if o == nil || o.MessageId == nil { - return nil, false - } - return o.MessageId, true -} - -// HasMessageId returns a boolean if a field has been set. -func (o *CourierMessageDispatch) HasMessageId() bool { - if o != nil && o.MessageId != nil { - return true - } - - return false -} - -// SetMessageId gets a reference to the given string and assigns it to the MessageId field. -func (o *CourierMessageDispatch) SetMessageId(v string) { - o.MessageId = &v -} - -// GetStatus returns the Status field value if set, zero value otherwise. -func (o *CourierMessageDispatch) GetStatus() string { - if o == nil || o.Status == nil { - var ret string - return ret - } - return *o.Status -} - -// GetStatusOk returns a tuple with the Status field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *CourierMessageDispatch) GetStatusOk() (*string, bool) { - if o == nil || o.Status == nil { - return nil, false - } - return o.Status, true -} - -// HasStatus returns a boolean if a field has been set. -func (o *CourierMessageDispatch) HasStatus() bool { - if o != nil && o.Status != nil { - return true - } - - return false -} - -// SetStatus gets a reference to the given string and assigns it to the Status field. -func (o *CourierMessageDispatch) SetStatus(v string) { - o.Status = &v -} - -// GetUpdatedAt returns the UpdatedAt field value if set, zero value otherwise. -func (o *CourierMessageDispatch) 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 *CourierMessageDispatch) 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 *CourierMessageDispatch) 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 *CourierMessageDispatch) SetUpdatedAt(v time.Time) { - o.UpdatedAt = &v -} - -func (o CourierMessageDispatch) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.CreatedAt != nil { - toSerialize["created_at"] = o.CreatedAt - } - if o.Error != nil { - toSerialize["error"] = o.Error - } - if o.Id != nil { - toSerialize["id"] = o.Id - } - if o.MessageId != nil { - toSerialize["message_id"] = o.MessageId - } - if o.Status != nil { - toSerialize["status"] = o.Status - } - if o.UpdatedAt != nil { - toSerialize["updated_at"] = o.UpdatedAt - } - return json.Marshal(toSerialize) -} - -type NullableCourierMessageDispatch struct { - value *CourierMessageDispatch - isSet bool -} - -func (v NullableCourierMessageDispatch) Get() *CourierMessageDispatch { - return v.value -} - -func (v *NullableCourierMessageDispatch) Set(val *CourierMessageDispatch) { - v.value = val - v.isSet = true -} - -func (v NullableCourierMessageDispatch) IsSet() bool { - return v.isSet -} - -func (v *NullableCourierMessageDispatch) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableCourierMessageDispatch(val *CourierMessageDispatch) *NullableCourierMessageDispatch { - return &NullableCourierMessageDispatch{value: val, isSet: true} -} - -func (v NullableCourierMessageDispatch) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableCourierMessageDispatch) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_flow_redirect_required.go b/internal/client-go/model_flow_redirect_required.go deleted file mode 100644 index 793147f6d032..000000000000 --- a/internal/client-go/model_flow_redirect_required.go +++ /dev/null @@ -1,403 +0,0 @@ -/* - * Ory Identities API - * - * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. - * - * API version: - * Contact: office@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// FlowRedirectRequired struct for FlowRedirectRequired -type FlowRedirectRequired struct { - // The status code - Code *int64 `json:"code,omitempty"` - // Debug information This field is often not exposed to protect against leaking sensitive information. - Debug *string `json:"debug,omitempty"` - // Further error details - Details map[string]interface{} `json:"details,omitempty"` - // The error ID Useful when trying to identify various errors in application logic. - Id *string `json:"id,omitempty"` - // Error message The error's message. - Message string `json:"message"` - // A human-readable reason for the error - Reason *string `json:"reason,omitempty"` - // The request ID The request ID is often exposed internally in order to trace errors across service architectures. This is often a UUID. - Request *string `json:"request,omitempty"` - SessionToken *string `json:"session_token,omitempty"` - // The status description - Status *string `json:"status,omitempty"` -} - -// NewFlowRedirectRequired instantiates a new FlowRedirectRequired 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 NewFlowRedirectRequired(message string) *FlowRedirectRequired { - this := FlowRedirectRequired{} - this.Message = message - return &this -} - -// NewFlowRedirectRequiredWithDefaults instantiates a new FlowRedirectRequired 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 NewFlowRedirectRequiredWithDefaults() *FlowRedirectRequired { - this := FlowRedirectRequired{} - return &this -} - -// GetCode returns the Code field value if set, zero value otherwise. -func (o *FlowRedirectRequired) GetCode() int64 { - if o == nil || o.Code == nil { - var ret int64 - return ret - } - return *o.Code -} - -// GetCodeOk returns a tuple with the Code field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *FlowRedirectRequired) GetCodeOk() (*int64, bool) { - if o == nil || o.Code == nil { - return nil, false - } - return o.Code, true -} - -// HasCode returns a boolean if a field has been set. -func (o *FlowRedirectRequired) HasCode() bool { - if o != nil && o.Code != nil { - return true - } - - return false -} - -// SetCode gets a reference to the given int64 and assigns it to the Code field. -func (o *FlowRedirectRequired) SetCode(v int64) { - o.Code = &v -} - -// GetDebug returns the Debug field value if set, zero value otherwise. -func (o *FlowRedirectRequired) GetDebug() string { - if o == nil || o.Debug == nil { - var ret string - return ret - } - return *o.Debug -} - -// GetDebugOk returns a tuple with the Debug field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *FlowRedirectRequired) GetDebugOk() (*string, bool) { - if o == nil || o.Debug == nil { - return nil, false - } - return o.Debug, true -} - -// HasDebug returns a boolean if a field has been set. -func (o *FlowRedirectRequired) HasDebug() bool { - if o != nil && o.Debug != nil { - return true - } - - return false -} - -// SetDebug gets a reference to the given string and assigns it to the Debug field. -func (o *FlowRedirectRequired) SetDebug(v string) { - o.Debug = &v -} - -// GetDetails returns the Details field value if set, zero value otherwise. -func (o *FlowRedirectRequired) GetDetails() map[string]interface{} { - if o == nil || o.Details == nil { - var ret map[string]interface{} - return ret - } - return o.Details -} - -// GetDetailsOk returns a tuple with the Details field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *FlowRedirectRequired) GetDetailsOk() (map[string]interface{}, bool) { - if o == nil || o.Details == nil { - return nil, false - } - return o.Details, true -} - -// HasDetails returns a boolean if a field has been set. -func (o *FlowRedirectRequired) HasDetails() bool { - if o != nil && o.Details != nil { - return true - } - - return false -} - -// SetDetails gets a reference to the given map[string]interface{} and assigns it to the Details field. -func (o *FlowRedirectRequired) SetDetails(v map[string]interface{}) { - o.Details = v -} - -// GetId returns the Id field value if set, zero value otherwise. -func (o *FlowRedirectRequired) GetId() string { - if o == nil || o.Id == nil { - var ret string - return ret - } - return *o.Id -} - -// GetIdOk returns a tuple with the Id field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *FlowRedirectRequired) GetIdOk() (*string, bool) { - if o == nil || o.Id == nil { - return nil, false - } - return o.Id, true -} - -// HasId returns a boolean if a field has been set. -func (o *FlowRedirectRequired) HasId() bool { - if o != nil && o.Id != nil { - return true - } - - return false -} - -// SetId gets a reference to the given string and assigns it to the Id field. -func (o *FlowRedirectRequired) SetId(v string) { - o.Id = &v -} - -// GetMessage returns the Message field value -func (o *FlowRedirectRequired) GetMessage() string { - if o == nil { - var ret string - return ret - } - - return o.Message -} - -// GetMessageOk returns a tuple with the Message field value -// and a boolean to check if the value has been set. -func (o *FlowRedirectRequired) GetMessageOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Message, true -} - -// SetMessage sets field value -func (o *FlowRedirectRequired) SetMessage(v string) { - o.Message = v -} - -// GetReason returns the Reason field value if set, zero value otherwise. -func (o *FlowRedirectRequired) GetReason() string { - if o == nil || o.Reason == nil { - var ret string - return ret - } - return *o.Reason -} - -// GetReasonOk returns a tuple with the Reason field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *FlowRedirectRequired) GetReasonOk() (*string, bool) { - if o == nil || o.Reason == nil { - return nil, false - } - return o.Reason, true -} - -// HasReason returns a boolean if a field has been set. -func (o *FlowRedirectRequired) HasReason() bool { - if o != nil && o.Reason != nil { - return true - } - - return false -} - -// SetReason gets a reference to the given string and assigns it to the Reason field. -func (o *FlowRedirectRequired) SetReason(v string) { - o.Reason = &v -} - -// GetRequest returns the Request field value if set, zero value otherwise. -func (o *FlowRedirectRequired) GetRequest() string { - if o == nil || o.Request == nil { - var ret string - return ret - } - return *o.Request -} - -// GetRequestOk returns a tuple with the Request field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *FlowRedirectRequired) GetRequestOk() (*string, bool) { - if o == nil || o.Request == nil { - return nil, false - } - return o.Request, true -} - -// HasRequest returns a boolean if a field has been set. -func (o *FlowRedirectRequired) HasRequest() bool { - if o != nil && o.Request != nil { - return true - } - - return false -} - -// SetRequest gets a reference to the given string and assigns it to the Request field. -func (o *FlowRedirectRequired) SetRequest(v string) { - o.Request = &v -} - -// GetSessionToken returns the SessionToken field value if set, zero value otherwise. -func (o *FlowRedirectRequired) GetSessionToken() string { - if o == nil || o.SessionToken == nil { - var ret string - return ret - } - return *o.SessionToken -} - -// GetSessionTokenOk returns a tuple with the SessionToken field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *FlowRedirectRequired) GetSessionTokenOk() (*string, bool) { - if o == nil || o.SessionToken == nil { - return nil, false - } - return o.SessionToken, true -} - -// HasSessionToken returns a boolean if a field has been set. -func (o *FlowRedirectRequired) HasSessionToken() bool { - if o != nil && o.SessionToken != nil { - return true - } - - return false -} - -// SetSessionToken gets a reference to the given string and assigns it to the SessionToken field. -func (o *FlowRedirectRequired) SetSessionToken(v string) { - o.SessionToken = &v -} - -// GetStatus returns the Status field value if set, zero value otherwise. -func (o *FlowRedirectRequired) GetStatus() string { - if o == nil || o.Status == nil { - var ret string - return ret - } - return *o.Status -} - -// GetStatusOk returns a tuple with the Status field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *FlowRedirectRequired) GetStatusOk() (*string, bool) { - if o == nil || o.Status == nil { - return nil, false - } - return o.Status, true -} - -// HasStatus returns a boolean if a field has been set. -func (o *FlowRedirectRequired) HasStatus() bool { - if o != nil && o.Status != nil { - return true - } - - return false -} - -// SetStatus gets a reference to the given string and assigns it to the Status field. -func (o *FlowRedirectRequired) SetStatus(v string) { - o.Status = &v -} - -func (o FlowRedirectRequired) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.Code != nil { - toSerialize["code"] = o.Code - } - if o.Debug != nil { - toSerialize["debug"] = o.Debug - } - if o.Details != nil { - toSerialize["details"] = o.Details - } - if o.Id != nil { - toSerialize["id"] = o.Id - } - if true { - toSerialize["message"] = o.Message - } - if o.Reason != nil { - toSerialize["reason"] = o.Reason - } - if o.Request != nil { - toSerialize["request"] = o.Request - } - if o.SessionToken != nil { - toSerialize["session_token"] = o.SessionToken - } - if o.Status != nil { - toSerialize["status"] = o.Status - } - return json.Marshal(toSerialize) -} - -type NullableFlowRedirectRequired struct { - value *FlowRedirectRequired - isSet bool -} - -func (v NullableFlowRedirectRequired) Get() *FlowRedirectRequired { - return v.value -} - -func (v *NullableFlowRedirectRequired) Set(val *FlowRedirectRequired) { - v.value = val - v.isSet = true -} - -func (v NullableFlowRedirectRequired) IsSet() bool { - return v.isSet -} - -func (v *NullableFlowRedirectRequired) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableFlowRedirectRequired(val *FlowRedirectRequired) *NullableFlowRedirectRequired { - return &NullableFlowRedirectRequired{value: val, isSet: true} -} - -func (v NullableFlowRedirectRequired) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableFlowRedirectRequired) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_identity_credentials_otp.go b/internal/client-go/model_identity_credentials_otp.go deleted file mode 100644 index b60601987e67..000000000000 --- a/internal/client-go/model_identity_credentials_otp.go +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Ory Identities API - * - * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. - * - * API version: - * Contact: office@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" - "time" -) - -// IdentityCredentialsOTP CredentialsOTP represents an OTP code -type IdentityCredentialsOTP struct { - AddressType *string `json:"address_type,omitempty"` - UsedAt NullableTime `json:"used_at,omitempty"` -} - -// NewIdentityCredentialsOTP instantiates a new IdentityCredentialsOTP 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 NewIdentityCredentialsOTP() *IdentityCredentialsOTP { - this := IdentityCredentialsOTP{} - return &this -} - -// NewIdentityCredentialsOTPWithDefaults instantiates a new IdentityCredentialsOTP 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 NewIdentityCredentialsOTPWithDefaults() *IdentityCredentialsOTP { - this := IdentityCredentialsOTP{} - return &this -} - -// GetAddressType returns the AddressType field value if set, zero value otherwise. -func (o *IdentityCredentialsOTP) GetAddressType() string { - if o == nil || o.AddressType == nil { - var ret string - return ret - } - return *o.AddressType -} - -// GetAddressTypeOk returns a tuple with the AddressType field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *IdentityCredentialsOTP) GetAddressTypeOk() (*string, bool) { - if o == nil || o.AddressType == nil { - return nil, false - } - return o.AddressType, true -} - -// HasAddressType returns a boolean if a field has been set. -func (o *IdentityCredentialsOTP) HasAddressType() bool { - if o != nil && o.AddressType != nil { - return true - } - - return false -} - -// SetAddressType gets a reference to the given string and assigns it to the AddressType field. -func (o *IdentityCredentialsOTP) SetAddressType(v string) { - o.AddressType = &v -} - -// GetUsedAt returns the UsedAt field value if set, zero value otherwise (both if not set or set to explicit null). -func (o *IdentityCredentialsOTP) GetUsedAt() time.Time { - if o == nil || o.UsedAt.Get() == nil { - var ret time.Time - return ret - } - return *o.UsedAt.Get() -} - -// GetUsedAtOk returns a tuple with the UsedAt 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 *IdentityCredentialsOTP) GetUsedAtOk() (*time.Time, bool) { - if o == nil { - return nil, false - } - return o.UsedAt.Get(), o.UsedAt.IsSet() -} - -// HasUsedAt returns a boolean if a field has been set. -func (o *IdentityCredentialsOTP) HasUsedAt() bool { - if o != nil && o.UsedAt.IsSet() { - return true - } - - return false -} - -// SetUsedAt gets a reference to the given NullableTime and assigns it to the UsedAt field. -func (o *IdentityCredentialsOTP) SetUsedAt(v time.Time) { - o.UsedAt.Set(&v) -} - -// SetUsedAtNil sets the value for UsedAt to be an explicit nil -func (o *IdentityCredentialsOTP) SetUsedAtNil() { - o.UsedAt.Set(nil) -} - -// UnsetUsedAt ensures that no value is present for UsedAt, not even an explicit nil -func (o *IdentityCredentialsOTP) UnsetUsedAt() { - o.UsedAt.Unset() -} - -func (o IdentityCredentialsOTP) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.AddressType != nil { - toSerialize["address_type"] = o.AddressType - } - if o.UsedAt.IsSet() { - toSerialize["used_at"] = o.UsedAt.Get() - } - return json.Marshal(toSerialize) -} - -type NullableIdentityCredentialsOTP struct { - value *IdentityCredentialsOTP - isSet bool -} - -func (v NullableIdentityCredentialsOTP) Get() *IdentityCredentialsOTP { - return v.value -} - -func (v *NullableIdentityCredentialsOTP) Set(val *IdentityCredentialsOTP) { - v.value = val - v.isSet = true -} - -func (v NullableIdentityCredentialsOTP) IsSet() bool { - return v.isSet -} - -func (v *NullableIdentityCredentialsOTP) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableIdentityCredentialsOTP(val *IdentityCredentialsOTP) *NullableIdentityCredentialsOTP { - return &NullableIdentityCredentialsOTP{value: val, isSet: true} -} - -func (v NullableIdentityCredentialsOTP) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableIdentityCredentialsOTP) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_identity_patch_error.go b/internal/client-go/model_identity_patch_error.go deleted file mode 100644 index 32d6ffddf2f8..000000000000 --- a/internal/client-go/model_identity_patch_error.go +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Ory Identities API - * - * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. - * - * API version: - * Contact: office@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// IdentityPatchError Error for a single identity patch -type IdentityPatchError struct { - Error *GenericError `json:"error,omitempty"` - Patch *IdentityPatchResponse `json:"patch,omitempty"` -} - -// NewIdentityPatchError instantiates a new IdentityPatchError 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 NewIdentityPatchError() *IdentityPatchError { - this := IdentityPatchError{} - return &this -} - -// NewIdentityPatchErrorWithDefaults instantiates a new IdentityPatchError 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 NewIdentityPatchErrorWithDefaults() *IdentityPatchError { - this := IdentityPatchError{} - return &this -} - -// GetError returns the Error field value if set, zero value otherwise. -func (o *IdentityPatchError) GetError() GenericError { - if o == nil || o.Error == nil { - var ret GenericError - return ret - } - return *o.Error -} - -// GetErrorOk returns a tuple with the Error field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *IdentityPatchError) GetErrorOk() (*GenericError, bool) { - if o == nil || o.Error == nil { - return nil, false - } - return o.Error, true -} - -// HasError returns a boolean if a field has been set. -func (o *IdentityPatchError) HasError() bool { - if o != nil && o.Error != nil { - return true - } - - return false -} - -// SetError gets a reference to the given GenericError and assigns it to the Error field. -func (o *IdentityPatchError) SetError(v GenericError) { - o.Error = &v -} - -// GetPatch returns the Patch field value if set, zero value otherwise. -func (o *IdentityPatchError) GetPatch() IdentityPatchResponse { - if o == nil || o.Patch == nil { - var ret IdentityPatchResponse - return ret - } - return *o.Patch -} - -// GetPatchOk returns a tuple with the Patch field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *IdentityPatchError) GetPatchOk() (*IdentityPatchResponse, bool) { - if o == nil || o.Patch == nil { - return nil, false - } - return o.Patch, true -} - -// HasPatch returns a boolean if a field has been set. -func (o *IdentityPatchError) HasPatch() bool { - if o != nil && o.Patch != nil { - return true - } - - return false -} - -// SetPatch gets a reference to the given IdentityPatchResponse and assigns it to the Patch field. -func (o *IdentityPatchError) SetPatch(v IdentityPatchResponse) { - o.Patch = &v -} - -func (o IdentityPatchError) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.Error != nil { - toSerialize["error"] = o.Error - } - if o.Patch != nil { - toSerialize["patch"] = o.Patch - } - return json.Marshal(toSerialize) -} - -type NullableIdentityPatchError struct { - value *IdentityPatchError - isSet bool -} - -func (v NullableIdentityPatchError) Get() *IdentityPatchError { - return v.value -} - -func (v *NullableIdentityPatchError) Set(val *IdentityPatchError) { - v.value = val - v.isSet = true -} - -func (v NullableIdentityPatchError) IsSet() bool { - return v.isSet -} - -func (v *NullableIdentityPatchError) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableIdentityPatchError(val *IdentityPatchError) *NullableIdentityPatchError { - return &NullableIdentityPatchError{value: val, isSet: true} -} - -func (v NullableIdentityPatchError) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableIdentityPatchError) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_json_error.go b/internal/client-go/model_json_error.go deleted file mode 100644 index 8115a0ea8a5f..000000000000 --- a/internal/client-go/model_json_error.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// JsonError The standard Ory JSON API error format. -type JsonError struct { - Error GenericError `json:"error"` -} - -// NewJsonError instantiates a new JsonError 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 NewJsonError(error_ GenericError) *JsonError { - this := JsonError{} - this.Error = error_ - return &this -} - -// NewJsonErrorWithDefaults instantiates a new JsonError 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 NewJsonErrorWithDefaults() *JsonError { - this := JsonError{} - return &this -} - -// GetError returns the Error field value -func (o *JsonError) GetError() GenericError { - if o == nil { - var ret GenericError - return ret - } - - return o.Error -} - -// GetErrorOk returns a tuple with the Error field value -// and a boolean to check if the value has been set. -func (o *JsonError) GetErrorOk() (*GenericError, bool) { - if o == nil { - return nil, false - } - return &o.Error, true -} - -// SetError sets field value -func (o *JsonError) SetError(v GenericError) { - o.Error = v -} - -func (o JsonError) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if true { - toSerialize["error"] = o.Error - } - return json.Marshal(toSerialize) -} - -type NullableJsonError struct { - value *JsonError - isSet bool -} - -func (v NullableJsonError) Get() *JsonError { - return v.value -} - -func (v *NullableJsonError) Set(val *JsonError) { - v.value = val - v.isSet = true -} - -func (v NullableJsonError) IsSet() bool { - return v.isSet -} - -func (v *NullableJsonError) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableJsonError(val *JsonError) *NullableJsonError { - return &NullableJsonError{value: val, isSet: true} -} - -func (v NullableJsonError) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableJsonError) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_login_request.go b/internal/client-go/model_login_request.go deleted file mode 100644 index 8328919b5bf7..000000000000 --- a/internal/client-go/model_login_request.go +++ /dev/null @@ -1,410 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * 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/client-go/model_open_id_connect_context.go b/internal/client-go/model_open_id_connect_context.go deleted file mode 100644 index 4a20884fbd59..000000000000 --- a/internal/client-go/model_open_id_connect_context.go +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * 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]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]interface{} { - if o == nil || o.IdTokenHintClaims == nil { - var ret 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]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]interface{} and assigns it to the IdTokenHintClaims field. -func (o *OpenIDConnectContext) SetIdTokenHintClaims(v 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/client-go/model_patch_identities_response.go b/internal/client-go/model_patch_identities_response.go deleted file mode 100644 index 89baada600eb..000000000000 --- a/internal/client-go/model_patch_identities_response.go +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Ory Identities API - * - * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. - * - * API version: - * Contact: office@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// PatchIdentitiesResponse Patch identities response -type PatchIdentitiesResponse struct { - // The patch responses for the individual identities. - Identities []IdentityPatchResponse `json:"identities,omitempty"` -} - -// NewPatchIdentitiesResponse instantiates a new PatchIdentitiesResponse 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 NewPatchIdentitiesResponse() *PatchIdentitiesResponse { - this := PatchIdentitiesResponse{} - return &this -} - -// NewPatchIdentitiesResponseWithDefaults instantiates a new PatchIdentitiesResponse 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 NewPatchIdentitiesResponseWithDefaults() *PatchIdentitiesResponse { - this := PatchIdentitiesResponse{} - return &this -} - -// GetIdentities returns the Identities field value if set, zero value otherwise. -func (o *PatchIdentitiesResponse) GetIdentities() []IdentityPatchResponse { - if o == nil || o.Identities == nil { - var ret []IdentityPatchResponse - return ret - } - return o.Identities -} - -// GetIdentitiesOk returns a tuple with the Identities field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *PatchIdentitiesResponse) GetIdentitiesOk() ([]IdentityPatchResponse, bool) { - if o == nil || o.Identities == nil { - return nil, false - } - return o.Identities, true -} - -// HasIdentities returns a boolean if a field has been set. -func (o *PatchIdentitiesResponse) HasIdentities() bool { - if o != nil && o.Identities != nil { - return true - } - - return false -} - -// SetIdentities gets a reference to the given []IdentityPatchResponse and assigns it to the Identities field. -func (o *PatchIdentitiesResponse) SetIdentities(v []IdentityPatchResponse) { - o.Identities = v -} - -func (o PatchIdentitiesResponse) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.Identities != nil { - toSerialize["identities"] = o.Identities - } - return json.Marshal(toSerialize) -} - -type NullablePatchIdentitiesResponse struct { - value *PatchIdentitiesResponse - isSet bool -} - -func (v NullablePatchIdentitiesResponse) Get() *PatchIdentitiesResponse { - return v.value -} - -func (v *NullablePatchIdentitiesResponse) Set(val *PatchIdentitiesResponse) { - v.value = val - v.isSet = true -} - -func (v NullablePatchIdentitiesResponse) IsSet() bool { - return v.isSet -} - -func (v *NullablePatchIdentitiesResponse) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullablePatchIdentitiesResponse(val *PatchIdentitiesResponse) *NullablePatchIdentitiesResponse { - return &NullablePatchIdentitiesResponse{value: val, isSet: true} -} - -func (v NullablePatchIdentitiesResponse) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullablePatchIdentitiesResponse) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_revoked_sessions.go b/internal/client-go/model_revoked_sessions.go deleted file mode 100644 index 3423aa863466..000000000000 --- a/internal/client-go/model_revoked_sessions.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// RevokedSessions struct for RevokedSessions -type RevokedSessions struct { - // The number of sessions that were revoked. - Count *int64 `json:"count,omitempty"` -} - -// NewRevokedSessions instantiates a new RevokedSessions 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 NewRevokedSessions() *RevokedSessions { - this := RevokedSessions{} - return &this -} - -// NewRevokedSessionsWithDefaults instantiates a new RevokedSessions 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 NewRevokedSessionsWithDefaults() *RevokedSessions { - this := RevokedSessions{} - return &this -} - -// GetCount returns the Count field value if set, zero value otherwise. -func (o *RevokedSessions) GetCount() int64 { - if o == nil || o.Count == nil { - var ret int64 - return ret - } - return *o.Count -} - -// GetCountOk returns a tuple with the Count field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *RevokedSessions) GetCountOk() (*int64, bool) { - if o == nil || o.Count == nil { - return nil, false - } - return o.Count, true -} - -// HasCount returns a boolean if a field has been set. -func (o *RevokedSessions) HasCount() bool { - if o != nil && o.Count != nil { - return true - } - - return false -} - -// SetCount gets a reference to the given int64 and assigns it to the Count field. -func (o *RevokedSessions) SetCount(v int64) { - o.Count = &v -} - -func (o RevokedSessions) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.Count != nil { - toSerialize["count"] = o.Count - } - return json.Marshal(toSerialize) -} - -type NullableRevokedSessions struct { - value *RevokedSessions - isSet bool -} - -func (v NullableRevokedSessions) Get() *RevokedSessions { - return v.value -} - -func (v *NullableRevokedSessions) Set(val *RevokedSessions) { - v.value = val - v.isSet = true -} - -func (v NullableRevokedSessions) IsSet() bool { - return v.isSet -} - -func (v *NullableRevokedSessions) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableRevokedSessions(val *RevokedSessions) *NullableRevokedSessions { - return &NullableRevokedSessions{value: val, isSet: true} -} - -func (v NullableRevokedSessions) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableRevokedSessions) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_self_service_browser_location_change_required_error.go b/internal/client-go/model_self_service_browser_location_change_required_error.go deleted file mode 100644 index 6b6aa4c12537..000000000000 --- a/internal/client-go/model_self_service_browser_location_change_required_error.go +++ /dev/null @@ -1,407 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// SelfServiceBrowserLocationChangeRequiredError struct for SelfServiceBrowserLocationChangeRequiredError -type SelfServiceBrowserLocationChangeRequiredError struct { - // The status code - Code *int64 `json:"code,omitempty"` - // Debug information This field is often not exposed to protect against leaking sensitive information. - Debug *string `json:"debug,omitempty"` - // Further error details - Details map[string]interface{} `json:"details,omitempty"` - // The error ID Useful when trying to identify various errors in application logic. - Id *string `json:"id,omitempty"` - // Error message The error's message. - Message string `json:"message"` - // A human-readable reason for the error - Reason *string `json:"reason,omitempty"` - // Since when the flow has expired - RedirectBrowserTo *string `json:"redirect_browser_to,omitempty"` - // The request ID The request ID is often exposed internally in order to trace errors across service architectures. This is often a UUID. - Request *string `json:"request,omitempty"` - // The status description - Status *string `json:"status,omitempty"` -} - -// NewSelfServiceBrowserLocationChangeRequiredError instantiates a new SelfServiceBrowserLocationChangeRequiredError 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 NewSelfServiceBrowserLocationChangeRequiredError(message string) *SelfServiceBrowserLocationChangeRequiredError { - this := SelfServiceBrowserLocationChangeRequiredError{} - this.Message = message - return &this -} - -// NewSelfServiceBrowserLocationChangeRequiredErrorWithDefaults instantiates a new SelfServiceBrowserLocationChangeRequiredError 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 NewSelfServiceBrowserLocationChangeRequiredErrorWithDefaults() *SelfServiceBrowserLocationChangeRequiredError { - this := SelfServiceBrowserLocationChangeRequiredError{} - return &this -} - -// GetCode returns the Code field value if set, zero value otherwise. -func (o *SelfServiceBrowserLocationChangeRequiredError) GetCode() int64 { - if o == nil || o.Code == nil { - var ret int64 - return ret - } - return *o.Code -} - -// GetCodeOk returns a tuple with the Code field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SelfServiceBrowserLocationChangeRequiredError) GetCodeOk() (*int64, bool) { - if o == nil || o.Code == nil { - return nil, false - } - return o.Code, true -} - -// HasCode returns a boolean if a field has been set. -func (o *SelfServiceBrowserLocationChangeRequiredError) HasCode() bool { - if o != nil && o.Code != nil { - return true - } - - return false -} - -// SetCode gets a reference to the given int64 and assigns it to the Code field. -func (o *SelfServiceBrowserLocationChangeRequiredError) SetCode(v int64) { - o.Code = &v -} - -// GetDebug returns the Debug field value if set, zero value otherwise. -func (o *SelfServiceBrowserLocationChangeRequiredError) GetDebug() string { - if o == nil || o.Debug == nil { - var ret string - return ret - } - return *o.Debug -} - -// GetDebugOk returns a tuple with the Debug field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SelfServiceBrowserLocationChangeRequiredError) GetDebugOk() (*string, bool) { - if o == nil || o.Debug == nil { - return nil, false - } - return o.Debug, true -} - -// HasDebug returns a boolean if a field has been set. -func (o *SelfServiceBrowserLocationChangeRequiredError) HasDebug() bool { - if o != nil && o.Debug != nil { - return true - } - - return false -} - -// SetDebug gets a reference to the given string and assigns it to the Debug field. -func (o *SelfServiceBrowserLocationChangeRequiredError) SetDebug(v string) { - o.Debug = &v -} - -// GetDetails returns the Details field value if set, zero value otherwise. -func (o *SelfServiceBrowserLocationChangeRequiredError) GetDetails() map[string]interface{} { - if o == nil || o.Details == nil { - var ret map[string]interface{} - return ret - } - return o.Details -} - -// GetDetailsOk returns a tuple with the Details field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SelfServiceBrowserLocationChangeRequiredError) GetDetailsOk() (map[string]interface{}, bool) { - if o == nil || o.Details == nil { - return nil, false - } - return o.Details, true -} - -// HasDetails returns a boolean if a field has been set. -func (o *SelfServiceBrowserLocationChangeRequiredError) HasDetails() bool { - if o != nil && o.Details != nil { - return true - } - - return false -} - -// SetDetails gets a reference to the given map[string]interface{} and assigns it to the Details field. -func (o *SelfServiceBrowserLocationChangeRequiredError) SetDetails(v map[string]interface{}) { - o.Details = v -} - -// GetId returns the Id field value if set, zero value otherwise. -func (o *SelfServiceBrowserLocationChangeRequiredError) GetId() string { - if o == nil || o.Id == nil { - var ret string - return ret - } - return *o.Id -} - -// GetIdOk returns a tuple with the Id field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SelfServiceBrowserLocationChangeRequiredError) GetIdOk() (*string, bool) { - if o == nil || o.Id == nil { - return nil, false - } - return o.Id, true -} - -// HasId returns a boolean if a field has been set. -func (o *SelfServiceBrowserLocationChangeRequiredError) HasId() bool { - if o != nil && o.Id != nil { - return true - } - - return false -} - -// SetId gets a reference to the given string and assigns it to the Id field. -func (o *SelfServiceBrowserLocationChangeRequiredError) SetId(v string) { - o.Id = &v -} - -// GetMessage returns the Message field value -func (o *SelfServiceBrowserLocationChangeRequiredError) GetMessage() string { - if o == nil { - var ret string - return ret - } - - return o.Message -} - -// GetMessageOk returns a tuple with the Message field value -// and a boolean to check if the value has been set. -func (o *SelfServiceBrowserLocationChangeRequiredError) GetMessageOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Message, true -} - -// SetMessage sets field value -func (o *SelfServiceBrowserLocationChangeRequiredError) SetMessage(v string) { - o.Message = v -} - -// GetReason returns the Reason field value if set, zero value otherwise. -func (o *SelfServiceBrowserLocationChangeRequiredError) GetReason() string { - if o == nil || o.Reason == nil { - var ret string - return ret - } - return *o.Reason -} - -// GetReasonOk returns a tuple with the Reason field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SelfServiceBrowserLocationChangeRequiredError) GetReasonOk() (*string, bool) { - if o == nil || o.Reason == nil { - return nil, false - } - return o.Reason, true -} - -// HasReason returns a boolean if a field has been set. -func (o *SelfServiceBrowserLocationChangeRequiredError) HasReason() bool { - if o != nil && o.Reason != nil { - return true - } - - return false -} - -// SetReason gets a reference to the given string and assigns it to the Reason field. -func (o *SelfServiceBrowserLocationChangeRequiredError) SetReason(v string) { - o.Reason = &v -} - -// GetRedirectBrowserTo returns the RedirectBrowserTo field value if set, zero value otherwise. -func (o *SelfServiceBrowserLocationChangeRequiredError) GetRedirectBrowserTo() string { - if o == nil || o.RedirectBrowserTo == nil { - var ret string - return ret - } - return *o.RedirectBrowserTo -} - -// GetRedirectBrowserToOk returns a tuple with the RedirectBrowserTo field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SelfServiceBrowserLocationChangeRequiredError) GetRedirectBrowserToOk() (*string, bool) { - if o == nil || o.RedirectBrowserTo == nil { - return nil, false - } - return o.RedirectBrowserTo, true -} - -// HasRedirectBrowserTo returns a boolean if a field has been set. -func (o *SelfServiceBrowserLocationChangeRequiredError) HasRedirectBrowserTo() bool { - if o != nil && o.RedirectBrowserTo != nil { - return true - } - - return false -} - -// SetRedirectBrowserTo gets a reference to the given string and assigns it to the RedirectBrowserTo field. -func (o *SelfServiceBrowserLocationChangeRequiredError) SetRedirectBrowserTo(v string) { - o.RedirectBrowserTo = &v -} - -// GetRequest returns the Request field value if set, zero value otherwise. -func (o *SelfServiceBrowserLocationChangeRequiredError) GetRequest() string { - if o == nil || o.Request == nil { - var ret string - return ret - } - return *o.Request -} - -// GetRequestOk returns a tuple with the Request field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SelfServiceBrowserLocationChangeRequiredError) GetRequestOk() (*string, bool) { - if o == nil || o.Request == nil { - return nil, false - } - return o.Request, true -} - -// HasRequest returns a boolean if a field has been set. -func (o *SelfServiceBrowserLocationChangeRequiredError) HasRequest() bool { - if o != nil && o.Request != nil { - return true - } - - return false -} - -// SetRequest gets a reference to the given string and assigns it to the Request field. -func (o *SelfServiceBrowserLocationChangeRequiredError) SetRequest(v string) { - o.Request = &v -} - -// GetStatus returns the Status field value if set, zero value otherwise. -func (o *SelfServiceBrowserLocationChangeRequiredError) GetStatus() string { - if o == nil || o.Status == nil { - var ret string - return ret - } - return *o.Status -} - -// GetStatusOk returns a tuple with the Status field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SelfServiceBrowserLocationChangeRequiredError) GetStatusOk() (*string, bool) { - if o == nil || o.Status == nil { - return nil, false - } - return o.Status, true -} - -// HasStatus returns a boolean if a field has been set. -func (o *SelfServiceBrowserLocationChangeRequiredError) HasStatus() bool { - if o != nil && o.Status != nil { - return true - } - - return false -} - -// SetStatus gets a reference to the given string and assigns it to the Status field. -func (o *SelfServiceBrowserLocationChangeRequiredError) SetStatus(v string) { - o.Status = &v -} - -func (o SelfServiceBrowserLocationChangeRequiredError) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.Code != nil { - toSerialize["code"] = o.Code - } - if o.Debug != nil { - toSerialize["debug"] = o.Debug - } - if o.Details != nil { - toSerialize["details"] = o.Details - } - if o.Id != nil { - toSerialize["id"] = o.Id - } - if true { - toSerialize["message"] = o.Message - } - if o.Reason != nil { - toSerialize["reason"] = o.Reason - } - if o.RedirectBrowserTo != nil { - toSerialize["redirect_browser_to"] = o.RedirectBrowserTo - } - if o.Request != nil { - toSerialize["request"] = o.Request - } - if o.Status != nil { - toSerialize["status"] = o.Status - } - return json.Marshal(toSerialize) -} - -type NullableSelfServiceBrowserLocationChangeRequiredError struct { - value *SelfServiceBrowserLocationChangeRequiredError - isSet bool -} - -func (v NullableSelfServiceBrowserLocationChangeRequiredError) Get() *SelfServiceBrowserLocationChangeRequiredError { - return v.value -} - -func (v *NullableSelfServiceBrowserLocationChangeRequiredError) Set(val *SelfServiceBrowserLocationChangeRequiredError) { - v.value = val - v.isSet = true -} - -func (v NullableSelfServiceBrowserLocationChangeRequiredError) IsSet() bool { - return v.isSet -} - -func (v *NullableSelfServiceBrowserLocationChangeRequiredError) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSelfServiceBrowserLocationChangeRequiredError(val *SelfServiceBrowserLocationChangeRequiredError) *NullableSelfServiceBrowserLocationChangeRequiredError { - return &NullableSelfServiceBrowserLocationChangeRequiredError{value: val, isSet: true} -} - -func (v NullableSelfServiceBrowserLocationChangeRequiredError) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSelfServiceBrowserLocationChangeRequiredError) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_self_service_error.go b/internal/client-go/model_self_service_error.go deleted file mode 100644 index c8cd87d9b763..000000000000 --- a/internal/client-go/model_self_service_error.go +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" - "time" -) - -// SelfServiceError struct for SelfServiceError -type SelfServiceError struct { - // CreatedAt is a helper struct field for gobuffalo.pop. - CreatedAt *time.Time `json:"created_at,omitempty"` - Error map[string]interface{} `json:"error,omitempty"` - // ID of the error container. - Id string `json:"id"` - // UpdatedAt is a helper struct field for gobuffalo.pop. - UpdatedAt *time.Time `json:"updated_at,omitempty"` -} - -// NewSelfServiceError instantiates a new SelfServiceError 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 NewSelfServiceError(id string) *SelfServiceError { - this := SelfServiceError{} - this.Id = id - return &this -} - -// NewSelfServiceErrorWithDefaults instantiates a new SelfServiceError 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 NewSelfServiceErrorWithDefaults() *SelfServiceError { - this := SelfServiceError{} - return &this -} - -// GetCreatedAt returns the CreatedAt field value if set, zero value otherwise. -func (o *SelfServiceError) 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 *SelfServiceError) 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 *SelfServiceError) 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 *SelfServiceError) SetCreatedAt(v time.Time) { - o.CreatedAt = &v -} - -// GetError returns the Error field value if set, zero value otherwise. -func (o *SelfServiceError) GetError() map[string]interface{} { - if o == nil || o.Error == nil { - var ret map[string]interface{} - return ret - } - return o.Error -} - -// GetErrorOk returns a tuple with the Error field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SelfServiceError) GetErrorOk() (map[string]interface{}, bool) { - if o == nil || o.Error == nil { - return nil, false - } - return o.Error, true -} - -// HasError returns a boolean if a field has been set. -func (o *SelfServiceError) HasError() bool { - if o != nil && o.Error != nil { - return true - } - - return false -} - -// SetError gets a reference to the given map[string]interface{} and assigns it to the Error field. -func (o *SelfServiceError) SetError(v map[string]interface{}) { - o.Error = v -} - -// GetId returns the Id field value -func (o *SelfServiceError) GetId() string { - if o == nil { - var ret string - return ret - } - - return o.Id -} - -// GetIdOk returns a tuple with the Id field value -// and a boolean to check if the value has been set. -func (o *SelfServiceError) GetIdOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Id, true -} - -// SetId sets field value -func (o *SelfServiceError) SetId(v string) { - o.Id = v -} - -// GetUpdatedAt returns the UpdatedAt field value if set, zero value otherwise. -func (o *SelfServiceError) 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 *SelfServiceError) 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 *SelfServiceError) 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 *SelfServiceError) SetUpdatedAt(v time.Time) { - o.UpdatedAt = &v -} - -func (o SelfServiceError) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.CreatedAt != nil { - toSerialize["created_at"] = o.CreatedAt - } - if o.Error != nil { - toSerialize["error"] = o.Error - } - if true { - toSerialize["id"] = o.Id - } - if o.UpdatedAt != nil { - toSerialize["updated_at"] = o.UpdatedAt - } - return json.Marshal(toSerialize) -} - -type NullableSelfServiceError struct { - value *SelfServiceError - isSet bool -} - -func (v NullableSelfServiceError) Get() *SelfServiceError { - return v.value -} - -func (v *NullableSelfServiceError) Set(val *SelfServiceError) { - v.value = val - v.isSet = true -} - -func (v NullableSelfServiceError) IsSet() bool { - return v.isSet -} - -func (v *NullableSelfServiceError) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSelfServiceError(val *SelfServiceError) *NullableSelfServiceError { - return &NullableSelfServiceError{value: val, isSet: true} -} - -func (v NullableSelfServiceError) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSelfServiceError) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_self_service_login_flow.go b/internal/client-go/model_self_service_login_flow.go deleted file mode 100644 index d75a0fa93073..000000000000 --- a/internal/client-go/model_self_service_login_flow.go +++ /dev/null @@ -1,564 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" - "time" -) - -// SelfServiceLoginFlow This object represents a login flow. A login flow is initiated at the \"Initiate Login API / Browser Flow\" endpoint by a client. Once a login flow is completed successfully, a session cookie or session token will be issued. -type SelfServiceLoginFlow struct { - Active *IdentityCredentialsType `json:"active,omitempty"` - // CreatedAt is a helper struct field for gobuffalo.pop. - CreatedAt *time.Time `json:"created_at,omitempty"` - // ExpiresAt is the time (UTC) when the flow expires. If the user still wishes to log in, a new flow has to be initiated. - ExpiresAt time.Time `json:"expires_at"` - // 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"` - 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. - RequestUrl string `json:"request_url"` - RequestedAal *AuthenticatorAssuranceLevel `json:"requested_aal,omitempty"` - // ReturnTo contains the requested return_to URL. - ReturnTo *string `json:"return_to,omitempty"` - // The flow type can either be `api` or `browser`. - Type string `json:"type"` - Ui UiContainer `json:"ui"` - // UpdatedAt is a helper struct field for gobuffalo.pop. - UpdatedAt *time.Time `json:"updated_at,omitempty"` -} - -// NewSelfServiceLoginFlow instantiates a new SelfServiceLoginFlow 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 NewSelfServiceLoginFlow(expiresAt time.Time, id string, issuedAt time.Time, requestUrl string, type_ string, ui UiContainer) *SelfServiceLoginFlow { - this := SelfServiceLoginFlow{} - this.ExpiresAt = expiresAt - this.Id = id - this.IssuedAt = issuedAt - this.RequestUrl = requestUrl - this.Type = type_ - this.Ui = ui - return &this -} - -// NewSelfServiceLoginFlowWithDefaults instantiates a new SelfServiceLoginFlow 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 NewSelfServiceLoginFlowWithDefaults() *SelfServiceLoginFlow { - this := SelfServiceLoginFlow{} - return &this -} - -// GetActive returns the Active field value if set, zero value otherwise. -func (o *SelfServiceLoginFlow) GetActive() IdentityCredentialsType { - if o == nil || o.Active == nil { - var ret IdentityCredentialsType - return ret - } - return *o.Active -} - -// GetActiveOk returns a tuple with the Active field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SelfServiceLoginFlow) GetActiveOk() (*IdentityCredentialsType, bool) { - if o == nil || o.Active == nil { - return nil, false - } - return o.Active, true -} - -// HasActive returns a boolean if a field has been set. -func (o *SelfServiceLoginFlow) HasActive() bool { - if o != nil && o.Active != nil { - return true - } - - return false -} - -// SetActive gets a reference to the given IdentityCredentialsType and assigns it to the Active field. -func (o *SelfServiceLoginFlow) SetActive(v IdentityCredentialsType) { - o.Active = &v -} - -// GetCreatedAt returns the CreatedAt field value if set, zero value otherwise. -func (o *SelfServiceLoginFlow) 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 *SelfServiceLoginFlow) 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 *SelfServiceLoginFlow) 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 *SelfServiceLoginFlow) SetCreatedAt(v time.Time) { - o.CreatedAt = &v -} - -// GetExpiresAt returns the ExpiresAt field value -func (o *SelfServiceLoginFlow) GetExpiresAt() time.Time { - if o == nil { - var ret time.Time - return ret - } - - return o.ExpiresAt -} - -// GetExpiresAtOk returns a tuple with the ExpiresAt field value -// and a boolean to check if the value has been set. -func (o *SelfServiceLoginFlow) GetExpiresAtOk() (*time.Time, bool) { - if o == nil { - return nil, false - } - return &o.ExpiresAt, true -} - -// SetExpiresAt sets field value -func (o *SelfServiceLoginFlow) SetExpiresAt(v time.Time) { - o.ExpiresAt = v -} - -// GetId returns the Id field value -func (o *SelfServiceLoginFlow) GetId() string { - if o == nil { - var ret string - return ret - } - - return o.Id -} - -// GetIdOk returns a tuple with the Id field value -// and a boolean to check if the value has been set. -func (o *SelfServiceLoginFlow) GetIdOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Id, true -} - -// SetId sets field value -func (o *SelfServiceLoginFlow) SetId(v string) { - o.Id = v -} - -// GetIssuedAt returns the IssuedAt field value -func (o *SelfServiceLoginFlow) GetIssuedAt() time.Time { - if o == nil { - var ret time.Time - return ret - } - - return o.IssuedAt -} - -// GetIssuedAtOk returns a tuple with the IssuedAt field value -// and a boolean to check if the value has been set. -func (o *SelfServiceLoginFlow) GetIssuedAtOk() (*time.Time, bool) { - if o == nil { - return nil, false - } - return &o.IssuedAt, true -} - -// SetIssuedAt sets field value -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 { - var ret bool - return ret - } - return *o.Refresh -} - -// GetRefreshOk returns a tuple with the Refresh field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SelfServiceLoginFlow) GetRefreshOk() (*bool, bool) { - if o == nil || o.Refresh == nil { - return nil, false - } - return o.Refresh, true -} - -// HasRefresh returns a boolean if a field has been set. -func (o *SelfServiceLoginFlow) HasRefresh() bool { - if o != nil && o.Refresh != nil { - return true - } - - return false -} - -// SetRefresh gets a reference to the given bool and assigns it to the Refresh field. -func (o *SelfServiceLoginFlow) SetRefresh(v bool) { - o.Refresh = &v -} - -// GetRequestUrl returns the RequestUrl field value -func (o *SelfServiceLoginFlow) GetRequestUrl() string { - if o == nil { - var ret string - return ret - } - - return o.RequestUrl -} - -// GetRequestUrlOk returns a tuple with the RequestUrl field value -// and a boolean to check if the value has been set. -func (o *SelfServiceLoginFlow) GetRequestUrlOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.RequestUrl, true -} - -// SetRequestUrl sets field value -func (o *SelfServiceLoginFlow) SetRequestUrl(v string) { - o.RequestUrl = v -} - -// GetRequestedAal returns the RequestedAal field value if set, zero value otherwise. -func (o *SelfServiceLoginFlow) GetRequestedAal() AuthenticatorAssuranceLevel { - if o == nil || o.RequestedAal == nil { - var ret AuthenticatorAssuranceLevel - return ret - } - return *o.RequestedAal -} - -// GetRequestedAalOk returns a tuple with the RequestedAal field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SelfServiceLoginFlow) GetRequestedAalOk() (*AuthenticatorAssuranceLevel, bool) { - if o == nil || o.RequestedAal == nil { - return nil, false - } - return o.RequestedAal, true -} - -// HasRequestedAal returns a boolean if a field has been set. -func (o *SelfServiceLoginFlow) HasRequestedAal() bool { - if o != nil && o.RequestedAal != nil { - return true - } - - return false -} - -// SetRequestedAal gets a reference to the given AuthenticatorAssuranceLevel and assigns it to the RequestedAal field. -func (o *SelfServiceLoginFlow) SetRequestedAal(v AuthenticatorAssuranceLevel) { - o.RequestedAal = &v -} - -// GetReturnTo returns the ReturnTo field value if set, zero value otherwise. -func (o *SelfServiceLoginFlow) GetReturnTo() string { - if o == nil || o.ReturnTo == nil { - var ret string - return ret - } - return *o.ReturnTo -} - -// GetReturnToOk returns a tuple with the ReturnTo field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SelfServiceLoginFlow) GetReturnToOk() (*string, bool) { - if o == nil || o.ReturnTo == nil { - return nil, false - } - return o.ReturnTo, true -} - -// HasReturnTo returns a boolean if a field has been set. -func (o *SelfServiceLoginFlow) HasReturnTo() bool { - if o != nil && o.ReturnTo != nil { - return true - } - - return false -} - -// SetReturnTo gets a reference to the given string and assigns it to the ReturnTo field. -func (o *SelfServiceLoginFlow) SetReturnTo(v string) { - o.ReturnTo = &v -} - -// GetType returns the Type field value -func (o *SelfServiceLoginFlow) GetType() string { - if o == nil { - var ret string - return ret - } - - return o.Type -} - -// GetTypeOk returns a tuple with the Type field value -// and a boolean to check if the value has been set. -func (o *SelfServiceLoginFlow) GetTypeOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Type, true -} - -// SetType sets field value -func (o *SelfServiceLoginFlow) SetType(v string) { - o.Type = v -} - -// GetUi returns the Ui field value -func (o *SelfServiceLoginFlow) GetUi() UiContainer { - if o == nil { - var ret UiContainer - return ret - } - - return o.Ui -} - -// GetUiOk returns a tuple with the Ui field value -// and a boolean to check if the value has been set. -func (o *SelfServiceLoginFlow) GetUiOk() (*UiContainer, bool) { - if o == nil { - return nil, false - } - return &o.Ui, true -} - -// SetUi sets field value -func (o *SelfServiceLoginFlow) SetUi(v UiContainer) { - o.Ui = v -} - -// GetUpdatedAt returns the UpdatedAt field value if set, zero value otherwise. -func (o *SelfServiceLoginFlow) 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 *SelfServiceLoginFlow) 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 *SelfServiceLoginFlow) 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 *SelfServiceLoginFlow) SetUpdatedAt(v time.Time) { - o.UpdatedAt = &v -} - -func (o SelfServiceLoginFlow) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.Active != nil { - toSerialize["active"] = o.Active - } - if o.CreatedAt != nil { - toSerialize["created_at"] = o.CreatedAt - } - if true { - toSerialize["expires_at"] = o.ExpiresAt - } - if true { - toSerialize["id"] = o.Id - } - 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 - } - if true { - toSerialize["request_url"] = o.RequestUrl - } - if o.RequestedAal != nil { - toSerialize["requested_aal"] = o.RequestedAal - } - if o.ReturnTo != nil { - toSerialize["return_to"] = o.ReturnTo - } - if true { - toSerialize["type"] = o.Type - } - if true { - toSerialize["ui"] = o.Ui - } - if o.UpdatedAt != nil { - toSerialize["updated_at"] = o.UpdatedAt - } - return json.Marshal(toSerialize) -} - -type NullableSelfServiceLoginFlow struct { - value *SelfServiceLoginFlow - isSet bool -} - -func (v NullableSelfServiceLoginFlow) Get() *SelfServiceLoginFlow { - return v.value -} - -func (v *NullableSelfServiceLoginFlow) Set(val *SelfServiceLoginFlow) { - v.value = val - v.isSet = true -} - -func (v NullableSelfServiceLoginFlow) IsSet() bool { - return v.isSet -} - -func (v *NullableSelfServiceLoginFlow) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSelfServiceLoginFlow(val *SelfServiceLoginFlow) *NullableSelfServiceLoginFlow { - return &NullableSelfServiceLoginFlow{value: val, isSet: true} -} - -func (v NullableSelfServiceLoginFlow) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSelfServiceLoginFlow) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_self_service_login_flow_state.go b/internal/client-go/model_self_service_login_flow_state.go deleted file mode 100644 index 093d300fe207..000000000000 --- a/internal/client-go/model_self_service_login_flow_state.go +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Ory Identities API - * - * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. - * - * API version: - * Contact: office@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" - "fmt" -) - -// SelfServiceLoginFlowState The state represents the state of the login flow. choose_method: ask the user to choose a method (e.g. login account via email) sent_email: the email has been sent to the user passed_challenge: the request was successful and the login challenge was passed. -type SelfServiceLoginFlowState string - -// List of SelfServiceLoginFlowState -const ( - SELFSERVICELOGINFLOWSTATE_CHOOSE_METHOD SelfServiceLoginFlowState = "choose_method" - SELFSERVICELOGINFLOWSTATE_SENT_EMAIL SelfServiceLoginFlowState = "sent_email" - SELFSERVICELOGINFLOWSTATE_PASSED_CHALLENGE SelfServiceLoginFlowState = "passed_challenge" -) - -func (v *SelfServiceLoginFlowState) UnmarshalJSON(src []byte) error { - var value string - err := json.Unmarshal(src, &value) - if err != nil { - return err - } - enumTypeValue := SelfServiceLoginFlowState(value) - for _, existing := range []SelfServiceLoginFlowState{"choose_method", "sent_email", "passed_challenge"} { - if existing == enumTypeValue { - *v = enumTypeValue - return nil - } - } - - return fmt.Errorf("%+v is not a valid SelfServiceLoginFlowState", value) -} - -// Ptr returns reference to SelfServiceLoginFlowState value -func (v SelfServiceLoginFlowState) Ptr() *SelfServiceLoginFlowState { - return &v -} - -type NullableSelfServiceLoginFlowState struct { - value *SelfServiceLoginFlowState - isSet bool -} - -func (v NullableSelfServiceLoginFlowState) Get() *SelfServiceLoginFlowState { - return v.value -} - -func (v *NullableSelfServiceLoginFlowState) Set(val *SelfServiceLoginFlowState) { - v.value = val - v.isSet = true -} - -func (v NullableSelfServiceLoginFlowState) IsSet() bool { - return v.isSet -} - -func (v *NullableSelfServiceLoginFlowState) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSelfServiceLoginFlowState(val *SelfServiceLoginFlowState) *NullableSelfServiceLoginFlowState { - return &NullableSelfServiceLoginFlowState{value: val, isSet: true} -} - -func (v NullableSelfServiceLoginFlowState) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSelfServiceLoginFlowState) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_self_service_logout_url.go b/internal/client-go/model_self_service_logout_url.go deleted file mode 100644 index 38f1b10311b2..000000000000 --- a/internal/client-go/model_self_service_logout_url.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// SelfServiceLogoutUrl struct for SelfServiceLogoutUrl -type SelfServiceLogoutUrl struct { - // LogoutToken can be used to perform logout using AJAX. - LogoutToken string `json:"logout_token"` - // LogoutURL can be opened in a browser to sign the user out. format: uri - LogoutUrl string `json:"logout_url"` -} - -// NewSelfServiceLogoutUrl instantiates a new SelfServiceLogoutUrl 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 NewSelfServiceLogoutUrl(logoutToken string, logoutUrl string) *SelfServiceLogoutUrl { - this := SelfServiceLogoutUrl{} - this.LogoutToken = logoutToken - this.LogoutUrl = logoutUrl - return &this -} - -// NewSelfServiceLogoutUrlWithDefaults instantiates a new SelfServiceLogoutUrl 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 NewSelfServiceLogoutUrlWithDefaults() *SelfServiceLogoutUrl { - this := SelfServiceLogoutUrl{} - return &this -} - -// GetLogoutToken returns the LogoutToken field value -func (o *SelfServiceLogoutUrl) GetLogoutToken() string { - if o == nil { - var ret string - return ret - } - - return o.LogoutToken -} - -// GetLogoutTokenOk returns a tuple with the LogoutToken field value -// and a boolean to check if the value has been set. -func (o *SelfServiceLogoutUrl) GetLogoutTokenOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.LogoutToken, true -} - -// SetLogoutToken sets field value -func (o *SelfServiceLogoutUrl) SetLogoutToken(v string) { - o.LogoutToken = v -} - -// GetLogoutUrl returns the LogoutUrl field value -func (o *SelfServiceLogoutUrl) GetLogoutUrl() string { - if o == nil { - var ret string - return ret - } - - return o.LogoutUrl -} - -// GetLogoutUrlOk returns a tuple with the LogoutUrl field value -// and a boolean to check if the value has been set. -func (o *SelfServiceLogoutUrl) GetLogoutUrlOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.LogoutUrl, true -} - -// SetLogoutUrl sets field value -func (o *SelfServiceLogoutUrl) SetLogoutUrl(v string) { - o.LogoutUrl = v -} - -func (o SelfServiceLogoutUrl) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if true { - toSerialize["logout_token"] = o.LogoutToken - } - if true { - toSerialize["logout_url"] = o.LogoutUrl - } - return json.Marshal(toSerialize) -} - -type NullableSelfServiceLogoutUrl struct { - value *SelfServiceLogoutUrl - isSet bool -} - -func (v NullableSelfServiceLogoutUrl) Get() *SelfServiceLogoutUrl { - return v.value -} - -func (v *NullableSelfServiceLogoutUrl) Set(val *SelfServiceLogoutUrl) { - v.value = val - v.isSet = true -} - -func (v NullableSelfServiceLogoutUrl) IsSet() bool { - return v.isSet -} - -func (v *NullableSelfServiceLogoutUrl) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSelfServiceLogoutUrl(val *SelfServiceLogoutUrl) *NullableSelfServiceLogoutUrl { - return &NullableSelfServiceLogoutUrl{value: val, isSet: true} -} - -func (v NullableSelfServiceLogoutUrl) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSelfServiceLogoutUrl) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_self_service_recovery_code.go b/internal/client-go/model_self_service_recovery_code.go deleted file mode 100644 index 53fcbe215962..000000000000 --- a/internal/client-go/model_self_service_recovery_code.go +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" - "time" -) - -// SelfServiceRecoveryCode struct for SelfServiceRecoveryCode -type SelfServiceRecoveryCode struct { - // Expires At is the timestamp of when the recovery flow expires The timestamp when the recovery link expires. - ExpiresAt *time.Time `json:"expires_at,omitempty"` - // RecoveryCode is the code that can be used to recover the account - RecoveryCode string `json:"recovery_code"` - // RecoveryLink with flow This link opens the recovery UI with an empty `code` field. - RecoveryLink string `json:"recovery_link"` -} - -// NewSelfServiceRecoveryCode instantiates a new SelfServiceRecoveryCode 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 NewSelfServiceRecoveryCode(recoveryCode string, recoveryLink string) *SelfServiceRecoveryCode { - this := SelfServiceRecoveryCode{} - this.RecoveryCode = recoveryCode - this.RecoveryLink = recoveryLink - return &this -} - -// NewSelfServiceRecoveryCodeWithDefaults instantiates a new SelfServiceRecoveryCode 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 NewSelfServiceRecoveryCodeWithDefaults() *SelfServiceRecoveryCode { - this := SelfServiceRecoveryCode{} - return &this -} - -// GetExpiresAt returns the ExpiresAt field value if set, zero value otherwise. -func (o *SelfServiceRecoveryCode) GetExpiresAt() time.Time { - if o == nil || o.ExpiresAt == nil { - var ret time.Time - return ret - } - return *o.ExpiresAt -} - -// GetExpiresAtOk returns a tuple with the ExpiresAt field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SelfServiceRecoveryCode) GetExpiresAtOk() (*time.Time, bool) { - if o == nil || o.ExpiresAt == nil { - return nil, false - } - return o.ExpiresAt, true -} - -// HasExpiresAt returns a boolean if a field has been set. -func (o *SelfServiceRecoveryCode) HasExpiresAt() bool { - if o != nil && o.ExpiresAt != nil { - return true - } - - return false -} - -// SetExpiresAt gets a reference to the given time.Time and assigns it to the ExpiresAt field. -func (o *SelfServiceRecoveryCode) SetExpiresAt(v time.Time) { - o.ExpiresAt = &v -} - -// GetRecoveryCode returns the RecoveryCode field value -func (o *SelfServiceRecoveryCode) GetRecoveryCode() string { - if o == nil { - var ret string - return ret - } - - return o.RecoveryCode -} - -// GetRecoveryCodeOk returns a tuple with the RecoveryCode field value -// and a boolean to check if the value has been set. -func (o *SelfServiceRecoveryCode) GetRecoveryCodeOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.RecoveryCode, true -} - -// SetRecoveryCode sets field value -func (o *SelfServiceRecoveryCode) SetRecoveryCode(v string) { - o.RecoveryCode = v -} - -// GetRecoveryLink returns the RecoveryLink field value -func (o *SelfServiceRecoveryCode) GetRecoveryLink() string { - if o == nil { - var ret string - return ret - } - - return o.RecoveryLink -} - -// GetRecoveryLinkOk returns a tuple with the RecoveryLink field value -// and a boolean to check if the value has been set. -func (o *SelfServiceRecoveryCode) GetRecoveryLinkOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.RecoveryLink, true -} - -// SetRecoveryLink sets field value -func (o *SelfServiceRecoveryCode) SetRecoveryLink(v string) { - o.RecoveryLink = v -} - -func (o SelfServiceRecoveryCode) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.ExpiresAt != nil { - toSerialize["expires_at"] = o.ExpiresAt - } - if true { - toSerialize["recovery_code"] = o.RecoveryCode - } - if true { - toSerialize["recovery_link"] = o.RecoveryLink - } - return json.Marshal(toSerialize) -} - -type NullableSelfServiceRecoveryCode struct { - value *SelfServiceRecoveryCode - isSet bool -} - -func (v NullableSelfServiceRecoveryCode) Get() *SelfServiceRecoveryCode { - return v.value -} - -func (v *NullableSelfServiceRecoveryCode) Set(val *SelfServiceRecoveryCode) { - v.value = val - v.isSet = true -} - -func (v NullableSelfServiceRecoveryCode) IsSet() bool { - return v.isSet -} - -func (v *NullableSelfServiceRecoveryCode) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSelfServiceRecoveryCode(val *SelfServiceRecoveryCode) *NullableSelfServiceRecoveryCode { - return &NullableSelfServiceRecoveryCode{value: val, isSet: true} -} - -func (v NullableSelfServiceRecoveryCode) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSelfServiceRecoveryCode) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_self_service_recovery_flow.go b/internal/client-go/model_self_service_recovery_flow.go deleted file mode 100644 index d9e94fd63df0..000000000000 --- a/internal/client-go/model_self_service_recovery_flow.go +++ /dev/null @@ -1,364 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" - "time" -) - -// SelfServiceRecoveryFlow This request is used when an identity wants to recover their account. We recommend reading the [Account Recovery Documentation](../self-service/flows/password-reset-account-recovery) -type SelfServiceRecoveryFlow struct { - // Active, if set, contains the recovery method that is being used. It is initially not set. - Active *string `json:"active,omitempty"` - // ExpiresAt is the time (UTC) when the request expires. If the user still wishes to update the setting, a new request has to be initiated. - ExpiresAt time.Time `json:"expires_at"` - // ID represents the request's unique ID. When performing the recovery flow, this represents the id in the recovery ui's query parameter: http://?request= - Id string `json:"id"` - // IssuedAt is the time (UTC) when the request occurred. - IssuedAt time.Time `json:"issued_at"` - // 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. - ReturnTo *string `json:"return_to,omitempty"` - State SelfServiceRecoveryFlowState `json:"state"` - // The flow type can either be `api` or `browser`. - Type string `json:"type"` - Ui UiContainer `json:"ui"` -} - -// NewSelfServiceRecoveryFlow instantiates a new SelfServiceRecoveryFlow 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 NewSelfServiceRecoveryFlow(expiresAt time.Time, id string, issuedAt time.Time, requestUrl string, state SelfServiceRecoveryFlowState, type_ string, ui UiContainer) *SelfServiceRecoveryFlow { - this := SelfServiceRecoveryFlow{} - this.ExpiresAt = expiresAt - this.Id = id - this.IssuedAt = issuedAt - this.RequestUrl = requestUrl - this.State = state - this.Type = type_ - this.Ui = ui - return &this -} - -// NewSelfServiceRecoveryFlowWithDefaults instantiates a new SelfServiceRecoveryFlow 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 NewSelfServiceRecoveryFlowWithDefaults() *SelfServiceRecoveryFlow { - this := SelfServiceRecoveryFlow{} - return &this -} - -// GetActive returns the Active field value if set, zero value otherwise. -func (o *SelfServiceRecoveryFlow) GetActive() string { - if o == nil || o.Active == nil { - var ret string - return ret - } - return *o.Active -} - -// GetActiveOk returns a tuple with the Active field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SelfServiceRecoveryFlow) GetActiveOk() (*string, bool) { - if o == nil || o.Active == nil { - return nil, false - } - return o.Active, true -} - -// HasActive returns a boolean if a field has been set. -func (o *SelfServiceRecoveryFlow) HasActive() bool { - if o != nil && o.Active != nil { - return true - } - - return false -} - -// SetActive gets a reference to the given string and assigns it to the Active field. -func (o *SelfServiceRecoveryFlow) SetActive(v string) { - o.Active = &v -} - -// GetExpiresAt returns the ExpiresAt field value -func (o *SelfServiceRecoveryFlow) GetExpiresAt() time.Time { - if o == nil { - var ret time.Time - return ret - } - - return o.ExpiresAt -} - -// GetExpiresAtOk returns a tuple with the ExpiresAt field value -// and a boolean to check if the value has been set. -func (o *SelfServiceRecoveryFlow) GetExpiresAtOk() (*time.Time, bool) { - if o == nil { - return nil, false - } - return &o.ExpiresAt, true -} - -// SetExpiresAt sets field value -func (o *SelfServiceRecoveryFlow) SetExpiresAt(v time.Time) { - o.ExpiresAt = v -} - -// GetId returns the Id field value -func (o *SelfServiceRecoveryFlow) GetId() string { - if o == nil { - var ret string - return ret - } - - return o.Id -} - -// GetIdOk returns a tuple with the Id field value -// and a boolean to check if the value has been set. -func (o *SelfServiceRecoveryFlow) GetIdOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Id, true -} - -// SetId sets field value -func (o *SelfServiceRecoveryFlow) SetId(v string) { - o.Id = v -} - -// GetIssuedAt returns the IssuedAt field value -func (o *SelfServiceRecoveryFlow) GetIssuedAt() time.Time { - if o == nil { - var ret time.Time - return ret - } - - return o.IssuedAt -} - -// GetIssuedAtOk returns a tuple with the IssuedAt field value -// and a boolean to check if the value has been set. -func (o *SelfServiceRecoveryFlow) GetIssuedAtOk() (*time.Time, bool) { - if o == nil { - return nil, false - } - return &o.IssuedAt, true -} - -// SetIssuedAt sets field value -func (o *SelfServiceRecoveryFlow) SetIssuedAt(v time.Time) { - o.IssuedAt = v -} - -// GetRequestUrl returns the RequestUrl field value -func (o *SelfServiceRecoveryFlow) GetRequestUrl() string { - if o == nil { - var ret string - return ret - } - - return o.RequestUrl -} - -// GetRequestUrlOk returns a tuple with the RequestUrl field value -// and a boolean to check if the value has been set. -func (o *SelfServiceRecoveryFlow) GetRequestUrlOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.RequestUrl, true -} - -// SetRequestUrl sets field value -func (o *SelfServiceRecoveryFlow) SetRequestUrl(v string) { - o.RequestUrl = v -} - -// GetReturnTo returns the ReturnTo field value if set, zero value otherwise. -func (o *SelfServiceRecoveryFlow) GetReturnTo() string { - if o == nil || o.ReturnTo == nil { - var ret string - return ret - } - return *o.ReturnTo -} - -// GetReturnToOk returns a tuple with the ReturnTo field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SelfServiceRecoveryFlow) GetReturnToOk() (*string, bool) { - if o == nil || o.ReturnTo == nil { - return nil, false - } - return o.ReturnTo, true -} - -// HasReturnTo returns a boolean if a field has been set. -func (o *SelfServiceRecoveryFlow) HasReturnTo() bool { - if o != nil && o.ReturnTo != nil { - return true - } - - return false -} - -// SetReturnTo gets a reference to the given string and assigns it to the ReturnTo field. -func (o *SelfServiceRecoveryFlow) SetReturnTo(v string) { - o.ReturnTo = &v -} - -// GetState returns the State field value -func (o *SelfServiceRecoveryFlow) GetState() SelfServiceRecoveryFlowState { - if o == nil { - var ret SelfServiceRecoveryFlowState - return ret - } - - return o.State -} - -// GetStateOk returns a tuple with the State field value -// and a boolean to check if the value has been set. -func (o *SelfServiceRecoveryFlow) GetStateOk() (*SelfServiceRecoveryFlowState, bool) { - if o == nil { - return nil, false - } - return &o.State, true -} - -// SetState sets field value -func (o *SelfServiceRecoveryFlow) SetState(v SelfServiceRecoveryFlowState) { - o.State = v -} - -// GetType returns the Type field value -func (o *SelfServiceRecoveryFlow) GetType() string { - if o == nil { - var ret string - return ret - } - - return o.Type -} - -// GetTypeOk returns a tuple with the Type field value -// and a boolean to check if the value has been set. -func (o *SelfServiceRecoveryFlow) GetTypeOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Type, true -} - -// SetType sets field value -func (o *SelfServiceRecoveryFlow) SetType(v string) { - o.Type = v -} - -// GetUi returns the Ui field value -func (o *SelfServiceRecoveryFlow) GetUi() UiContainer { - if o == nil { - var ret UiContainer - return ret - } - - return o.Ui -} - -// GetUiOk returns a tuple with the Ui field value -// and a boolean to check if the value has been set. -func (o *SelfServiceRecoveryFlow) GetUiOk() (*UiContainer, bool) { - if o == nil { - return nil, false - } - return &o.Ui, true -} - -// SetUi sets field value -func (o *SelfServiceRecoveryFlow) SetUi(v UiContainer) { - o.Ui = v -} - -func (o SelfServiceRecoveryFlow) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.Active != nil { - toSerialize["active"] = o.Active - } - if true { - toSerialize["expires_at"] = o.ExpiresAt - } - if true { - toSerialize["id"] = o.Id - } - if true { - toSerialize["issued_at"] = o.IssuedAt - } - if true { - toSerialize["request_url"] = o.RequestUrl - } - if o.ReturnTo != nil { - toSerialize["return_to"] = o.ReturnTo - } - if true { - toSerialize["state"] = o.State - } - if true { - toSerialize["type"] = o.Type - } - if true { - toSerialize["ui"] = o.Ui - } - return json.Marshal(toSerialize) -} - -type NullableSelfServiceRecoveryFlow struct { - value *SelfServiceRecoveryFlow - isSet bool -} - -func (v NullableSelfServiceRecoveryFlow) Get() *SelfServiceRecoveryFlow { - return v.value -} - -func (v *NullableSelfServiceRecoveryFlow) Set(val *SelfServiceRecoveryFlow) { - v.value = val - v.isSet = true -} - -func (v NullableSelfServiceRecoveryFlow) IsSet() bool { - return v.isSet -} - -func (v *NullableSelfServiceRecoveryFlow) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSelfServiceRecoveryFlow(val *SelfServiceRecoveryFlow) *NullableSelfServiceRecoveryFlow { - return &NullableSelfServiceRecoveryFlow{value: val, isSet: true} -} - -func (v NullableSelfServiceRecoveryFlow) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSelfServiceRecoveryFlow) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_self_service_recovery_flow_state.go b/internal/client-go/model_self_service_recovery_flow_state.go deleted file mode 100644 index ae492a51d26b..000000000000 --- a/internal/client-go/model_self_service_recovery_flow_state.go +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Ory Identities API - * - * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. - * - * API version: - * Contact: office@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" - "fmt" -) - -// SelfServiceRecoveryFlowState The state represents the state of the recovery flow. choose_method: ask the user to choose a method (e.g. recover account via email) sent_email: the email has been sent to the user passed_challenge: the request was successful and the recovery challenge was passed. -type SelfServiceRecoveryFlowState string - -// List of SelfServiceRecoveryFlowState -const ( - SELFSERVICERECOVERYFLOWSTATE_CHOOSE_METHOD SelfServiceRecoveryFlowState = "choose_method" - SELFSERVICERECOVERYFLOWSTATE_SENT_EMAIL SelfServiceRecoveryFlowState = "sent_email" - SELFSERVICERECOVERYFLOWSTATE_PASSED_CHALLENGE SelfServiceRecoveryFlowState = "passed_challenge" -) - -func (v *SelfServiceRecoveryFlowState) UnmarshalJSON(src []byte) error { - var value string - err := json.Unmarshal(src, &value) - if err != nil { - return err - } - enumTypeValue := SelfServiceRecoveryFlowState(value) - for _, existing := range []SelfServiceRecoveryFlowState{"choose_method", "sent_email", "passed_challenge"} { - if existing == enumTypeValue { - *v = enumTypeValue - return nil - } - } - - return fmt.Errorf("%+v is not a valid SelfServiceRecoveryFlowState", value) -} - -// Ptr returns reference to SelfServiceRecoveryFlowState value -func (v SelfServiceRecoveryFlowState) Ptr() *SelfServiceRecoveryFlowState { - return &v -} - -type NullableSelfServiceRecoveryFlowState struct { - value *SelfServiceRecoveryFlowState - isSet bool -} - -func (v NullableSelfServiceRecoveryFlowState) Get() *SelfServiceRecoveryFlowState { - return v.value -} - -func (v *NullableSelfServiceRecoveryFlowState) Set(val *SelfServiceRecoveryFlowState) { - v.value = val - v.isSet = true -} - -func (v NullableSelfServiceRecoveryFlowState) IsSet() bool { - return v.isSet -} - -func (v *NullableSelfServiceRecoveryFlowState) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSelfServiceRecoveryFlowState(val *SelfServiceRecoveryFlowState) *NullableSelfServiceRecoveryFlowState { - return &NullableSelfServiceRecoveryFlowState{value: val, isSet: true} -} - -func (v NullableSelfServiceRecoveryFlowState) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSelfServiceRecoveryFlowState) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_self_service_recovery_link.go b/internal/client-go/model_self_service_recovery_link.go deleted file mode 100644 index 18236e1909af..000000000000 --- a/internal/client-go/model_self_service_recovery_link.go +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" - "time" -) - -// SelfServiceRecoveryLink struct for SelfServiceRecoveryLink -type SelfServiceRecoveryLink struct { - // Recovery Link Expires At The timestamp when the recovery link expires. - ExpiresAt *time.Time `json:"expires_at,omitempty"` - // Recovery Link This link can be used to recover the account. - RecoveryLink string `json:"recovery_link"` -} - -// NewSelfServiceRecoveryLink instantiates a new SelfServiceRecoveryLink 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 NewSelfServiceRecoveryLink(recoveryLink string) *SelfServiceRecoveryLink { - this := SelfServiceRecoveryLink{} - this.RecoveryLink = recoveryLink - return &this -} - -// NewSelfServiceRecoveryLinkWithDefaults instantiates a new SelfServiceRecoveryLink 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 NewSelfServiceRecoveryLinkWithDefaults() *SelfServiceRecoveryLink { - this := SelfServiceRecoveryLink{} - return &this -} - -// GetExpiresAt returns the ExpiresAt field value if set, zero value otherwise. -func (o *SelfServiceRecoveryLink) GetExpiresAt() time.Time { - if o == nil || o.ExpiresAt == nil { - var ret time.Time - return ret - } - return *o.ExpiresAt -} - -// GetExpiresAtOk returns a tuple with the ExpiresAt field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SelfServiceRecoveryLink) GetExpiresAtOk() (*time.Time, bool) { - if o == nil || o.ExpiresAt == nil { - return nil, false - } - return o.ExpiresAt, true -} - -// HasExpiresAt returns a boolean if a field has been set. -func (o *SelfServiceRecoveryLink) HasExpiresAt() bool { - if o != nil && o.ExpiresAt != nil { - return true - } - - return false -} - -// SetExpiresAt gets a reference to the given time.Time and assigns it to the ExpiresAt field. -func (o *SelfServiceRecoveryLink) SetExpiresAt(v time.Time) { - o.ExpiresAt = &v -} - -// GetRecoveryLink returns the RecoveryLink field value -func (o *SelfServiceRecoveryLink) GetRecoveryLink() string { - if o == nil { - var ret string - return ret - } - - return o.RecoveryLink -} - -// GetRecoveryLinkOk returns a tuple with the RecoveryLink field value -// and a boolean to check if the value has been set. -func (o *SelfServiceRecoveryLink) GetRecoveryLinkOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.RecoveryLink, true -} - -// SetRecoveryLink sets field value -func (o *SelfServiceRecoveryLink) SetRecoveryLink(v string) { - o.RecoveryLink = v -} - -func (o SelfServiceRecoveryLink) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.ExpiresAt != nil { - toSerialize["expires_at"] = o.ExpiresAt - } - if true { - toSerialize["recovery_link"] = o.RecoveryLink - } - return json.Marshal(toSerialize) -} - -type NullableSelfServiceRecoveryLink struct { - value *SelfServiceRecoveryLink - isSet bool -} - -func (v NullableSelfServiceRecoveryLink) Get() *SelfServiceRecoveryLink { - return v.value -} - -func (v *NullableSelfServiceRecoveryLink) Set(val *SelfServiceRecoveryLink) { - v.value = val - v.isSet = true -} - -func (v NullableSelfServiceRecoveryLink) IsSet() bool { - return v.isSet -} - -func (v *NullableSelfServiceRecoveryLink) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSelfServiceRecoveryLink(val *SelfServiceRecoveryLink) *NullableSelfServiceRecoveryLink { - return &NullableSelfServiceRecoveryLink{value: val, isSet: true} -} - -func (v NullableSelfServiceRecoveryLink) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSelfServiceRecoveryLink) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_self_service_registration_flow.go b/internal/client-go/model_self_service_registration_flow.go deleted file mode 100644 index 26dcfc08880e..000000000000 --- a/internal/client-go/model_self_service_registration_flow.go +++ /dev/null @@ -1,417 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" - "time" -) - -// SelfServiceRegistrationFlow struct for SelfServiceRegistrationFlow -type SelfServiceRegistrationFlow struct { - Active *IdentityCredentialsType `json:"active,omitempty"` - // ExpiresAt is the time (UTC) when the flow expires. If the user still wishes to log in, a new flow has to be initiated. - ExpiresAt time.Time `json:"expires_at"` - // 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"` - 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. - ReturnTo *string `json:"return_to,omitempty"` - // The flow type can either be `api` or `browser`. - Type string `json:"type"` - Ui UiContainer `json:"ui"` -} - -// NewSelfServiceRegistrationFlow instantiates a new SelfServiceRegistrationFlow 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 NewSelfServiceRegistrationFlow(expiresAt time.Time, id string, issuedAt time.Time, requestUrl string, type_ string, ui UiContainer) *SelfServiceRegistrationFlow { - this := SelfServiceRegistrationFlow{} - this.ExpiresAt = expiresAt - this.Id = id - this.IssuedAt = issuedAt - this.RequestUrl = requestUrl - this.Type = type_ - this.Ui = ui - return &this -} - -// NewSelfServiceRegistrationFlowWithDefaults instantiates a new SelfServiceRegistrationFlow 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 NewSelfServiceRegistrationFlowWithDefaults() *SelfServiceRegistrationFlow { - this := SelfServiceRegistrationFlow{} - return &this -} - -// GetActive returns the Active field value if set, zero value otherwise. -func (o *SelfServiceRegistrationFlow) GetActive() IdentityCredentialsType { - if o == nil || o.Active == nil { - var ret IdentityCredentialsType - return ret - } - return *o.Active -} - -// GetActiveOk returns a tuple with the Active field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SelfServiceRegistrationFlow) GetActiveOk() (*IdentityCredentialsType, bool) { - if o == nil || o.Active == nil { - return nil, false - } - return o.Active, true -} - -// HasActive returns a boolean if a field has been set. -func (o *SelfServiceRegistrationFlow) HasActive() bool { - if o != nil && o.Active != nil { - return true - } - - return false -} - -// SetActive gets a reference to the given IdentityCredentialsType and assigns it to the Active field. -func (o *SelfServiceRegistrationFlow) SetActive(v IdentityCredentialsType) { - o.Active = &v -} - -// GetExpiresAt returns the ExpiresAt field value -func (o *SelfServiceRegistrationFlow) GetExpiresAt() time.Time { - if o == nil { - var ret time.Time - return ret - } - - return o.ExpiresAt -} - -// GetExpiresAtOk returns a tuple with the ExpiresAt field value -// and a boolean to check if the value has been set. -func (o *SelfServiceRegistrationFlow) GetExpiresAtOk() (*time.Time, bool) { - if o == nil { - return nil, false - } - return &o.ExpiresAt, true -} - -// SetExpiresAt sets field value -func (o *SelfServiceRegistrationFlow) SetExpiresAt(v time.Time) { - o.ExpiresAt = v -} - -// GetId returns the Id field value -func (o *SelfServiceRegistrationFlow) GetId() string { - if o == nil { - var ret string - return ret - } - - return o.Id -} - -// GetIdOk returns a tuple with the Id field value -// and a boolean to check if the value has been set. -func (o *SelfServiceRegistrationFlow) GetIdOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Id, true -} - -// SetId sets field value -func (o *SelfServiceRegistrationFlow) SetId(v string) { - o.Id = v -} - -// GetIssuedAt returns the IssuedAt field value -func (o *SelfServiceRegistrationFlow) GetIssuedAt() time.Time { - if o == nil { - var ret time.Time - return ret - } - - return o.IssuedAt -} - -// GetIssuedAtOk returns a tuple with the IssuedAt field value -// and a boolean to check if the value has been set. -func (o *SelfServiceRegistrationFlow) GetIssuedAtOk() (*time.Time, bool) { - if o == nil { - return nil, false - } - return &o.IssuedAt, true -} - -// SetIssuedAt sets field value -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 { - var ret string - return ret - } - - return o.RequestUrl -} - -// GetRequestUrlOk returns a tuple with the RequestUrl field value -// and a boolean to check if the value has been set. -func (o *SelfServiceRegistrationFlow) GetRequestUrlOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.RequestUrl, true -} - -// SetRequestUrl sets field value -func (o *SelfServiceRegistrationFlow) SetRequestUrl(v string) { - o.RequestUrl = v -} - -// GetReturnTo returns the ReturnTo field value if set, zero value otherwise. -func (o *SelfServiceRegistrationFlow) GetReturnTo() string { - if o == nil || o.ReturnTo == nil { - var ret string - return ret - } - return *o.ReturnTo -} - -// GetReturnToOk returns a tuple with the ReturnTo field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SelfServiceRegistrationFlow) GetReturnToOk() (*string, bool) { - if o == nil || o.ReturnTo == nil { - return nil, false - } - return o.ReturnTo, true -} - -// HasReturnTo returns a boolean if a field has been set. -func (o *SelfServiceRegistrationFlow) HasReturnTo() bool { - if o != nil && o.ReturnTo != nil { - return true - } - - return false -} - -// SetReturnTo gets a reference to the given string and assigns it to the ReturnTo field. -func (o *SelfServiceRegistrationFlow) SetReturnTo(v string) { - o.ReturnTo = &v -} - -// GetType returns the Type field value -func (o *SelfServiceRegistrationFlow) GetType() string { - if o == nil { - var ret string - return ret - } - - return o.Type -} - -// GetTypeOk returns a tuple with the Type field value -// and a boolean to check if the value has been set. -func (o *SelfServiceRegistrationFlow) GetTypeOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Type, true -} - -// SetType sets field value -func (o *SelfServiceRegistrationFlow) SetType(v string) { - o.Type = v -} - -// GetUi returns the Ui field value -func (o *SelfServiceRegistrationFlow) GetUi() UiContainer { - if o == nil { - var ret UiContainer - return ret - } - - return o.Ui -} - -// GetUiOk returns a tuple with the Ui field value -// and a boolean to check if the value has been set. -func (o *SelfServiceRegistrationFlow) GetUiOk() (*UiContainer, bool) { - if o == nil { - return nil, false - } - return &o.Ui, true -} - -// SetUi sets field value -func (o *SelfServiceRegistrationFlow) SetUi(v UiContainer) { - o.Ui = v -} - -func (o SelfServiceRegistrationFlow) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.Active != nil { - toSerialize["active"] = o.Active - } - if true { - toSerialize["expires_at"] = o.ExpiresAt - } - if true { - toSerialize["id"] = o.Id - } - 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 - } - if o.ReturnTo != nil { - toSerialize["return_to"] = o.ReturnTo - } - if true { - toSerialize["type"] = o.Type - } - if true { - toSerialize["ui"] = o.Ui - } - return json.Marshal(toSerialize) -} - -type NullableSelfServiceRegistrationFlow struct { - value *SelfServiceRegistrationFlow - isSet bool -} - -func (v NullableSelfServiceRegistrationFlow) Get() *SelfServiceRegistrationFlow { - return v.value -} - -func (v *NullableSelfServiceRegistrationFlow) Set(val *SelfServiceRegistrationFlow) { - v.value = val - v.isSet = true -} - -func (v NullableSelfServiceRegistrationFlow) IsSet() bool { - return v.isSet -} - -func (v *NullableSelfServiceRegistrationFlow) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSelfServiceRegistrationFlow(val *SelfServiceRegistrationFlow) *NullableSelfServiceRegistrationFlow { - return &NullableSelfServiceRegistrationFlow{value: val, isSet: true} -} - -func (v NullableSelfServiceRegistrationFlow) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSelfServiceRegistrationFlow) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_self_service_registration_flow_state.go b/internal/client-go/model_self_service_registration_flow_state.go deleted file mode 100644 index a84387784ef1..000000000000 --- a/internal/client-go/model_self_service_registration_flow_state.go +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Ory Identities API - * - * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. - * - * API version: - * Contact: office@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" - "fmt" -) - -// SelfServiceRegistrationFlowState choose_method: ask the user to choose a method (e.g. registration with email) sent_email: the email has been sent to the user passed_challenge: the request was successful and the registration challenge was passed. -type SelfServiceRegistrationFlowState string - -// List of SelfServiceRegistrationFlowState -const ( - SELFSERVICEREGISTRATIONFLOWSTATE_CHOOSE_METHOD SelfServiceRegistrationFlowState = "choose_method" - SELFSERVICEREGISTRATIONFLOWSTATE_SENT_EMAIL SelfServiceRegistrationFlowState = "sent_email" - SELFSERVICEREGISTRATIONFLOWSTATE_PASSED_CHALLENGE SelfServiceRegistrationFlowState = "passed_challenge" -) - -func (v *SelfServiceRegistrationFlowState) UnmarshalJSON(src []byte) error { - var value string - err := json.Unmarshal(src, &value) - if err != nil { - return err - } - enumTypeValue := SelfServiceRegistrationFlowState(value) - for _, existing := range []SelfServiceRegistrationFlowState{"choose_method", "sent_email", "passed_challenge"} { - if existing == enumTypeValue { - *v = enumTypeValue - return nil - } - } - - return fmt.Errorf("%+v is not a valid SelfServiceRegistrationFlowState", value) -} - -// Ptr returns reference to SelfServiceRegistrationFlowState value -func (v SelfServiceRegistrationFlowState) Ptr() *SelfServiceRegistrationFlowState { - return &v -} - -type NullableSelfServiceRegistrationFlowState struct { - value *SelfServiceRegistrationFlowState - isSet bool -} - -func (v NullableSelfServiceRegistrationFlowState) Get() *SelfServiceRegistrationFlowState { - return v.value -} - -func (v *NullableSelfServiceRegistrationFlowState) Set(val *SelfServiceRegistrationFlowState) { - v.value = val - v.isSet = true -} - -func (v NullableSelfServiceRegistrationFlowState) IsSet() bool { - return v.isSet -} - -func (v *NullableSelfServiceRegistrationFlowState) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSelfServiceRegistrationFlowState(val *SelfServiceRegistrationFlowState) *NullableSelfServiceRegistrationFlowState { - return &NullableSelfServiceRegistrationFlowState{value: val, isSet: true} -} - -func (v NullableSelfServiceRegistrationFlowState) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSelfServiceRegistrationFlowState) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_self_service_settings_flow.go b/internal/client-go/model_self_service_settings_flow.go deleted file mode 100644 index 0dcaf7d6b7a7..000000000000 --- a/internal/client-go/model_self_service_settings_flow.go +++ /dev/null @@ -1,393 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" - "time" -) - -// SelfServiceSettingsFlow This flow is used when an identity wants to update settings (e.g. profile data, passwords, ...) in a selfservice manner. We recommend reading the [User Settings Documentation](../self-service/flows/user-settings) -type SelfServiceSettingsFlow struct { - // Active, if set, contains the registration method that is being used. It is initially not set. - Active *string `json:"active,omitempty"` - // ExpiresAt is the time (UTC) when the flow expires. If the user still wishes to update the setting, a new flow has to be initiated. - ExpiresAt time.Time `json:"expires_at"` - // ID represents the flow's unique ID. When performing the settings flow, this represents the id in the settings ui's query parameter: http://?flow= - Id string `json:"id"` - Identity Identity `json:"identity"` - // IssuedAt is the time (UTC) when the flow occurred. - IssuedAt time.Time `json:"issued_at"` - // 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. - ReturnTo *string `json:"return_to,omitempty"` - State SelfServiceSettingsFlowState `json:"state"` - // The flow type can either be `api` or `browser`. - Type string `json:"type"` - Ui UiContainer `json:"ui"` -} - -// NewSelfServiceSettingsFlow instantiates a new SelfServiceSettingsFlow 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 NewSelfServiceSettingsFlow(expiresAt time.Time, id string, identity Identity, issuedAt time.Time, requestUrl string, state SelfServiceSettingsFlowState, type_ string, ui UiContainer) *SelfServiceSettingsFlow { - this := SelfServiceSettingsFlow{} - this.ExpiresAt = expiresAt - this.Id = id - this.Identity = identity - this.IssuedAt = issuedAt - this.RequestUrl = requestUrl - this.State = state - this.Type = type_ - this.Ui = ui - return &this -} - -// NewSelfServiceSettingsFlowWithDefaults instantiates a new SelfServiceSettingsFlow 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 NewSelfServiceSettingsFlowWithDefaults() *SelfServiceSettingsFlow { - this := SelfServiceSettingsFlow{} - return &this -} - -// GetActive returns the Active field value if set, zero value otherwise. -func (o *SelfServiceSettingsFlow) GetActive() string { - if o == nil || o.Active == nil { - var ret string - return ret - } - return *o.Active -} - -// GetActiveOk returns a tuple with the Active field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SelfServiceSettingsFlow) GetActiveOk() (*string, bool) { - if o == nil || o.Active == nil { - return nil, false - } - return o.Active, true -} - -// HasActive returns a boolean if a field has been set. -func (o *SelfServiceSettingsFlow) HasActive() bool { - if o != nil && o.Active != nil { - return true - } - - return false -} - -// SetActive gets a reference to the given string and assigns it to the Active field. -func (o *SelfServiceSettingsFlow) SetActive(v string) { - o.Active = &v -} - -// GetExpiresAt returns the ExpiresAt field value -func (o *SelfServiceSettingsFlow) GetExpiresAt() time.Time { - if o == nil { - var ret time.Time - return ret - } - - return o.ExpiresAt -} - -// GetExpiresAtOk returns a tuple with the ExpiresAt field value -// and a boolean to check if the value has been set. -func (o *SelfServiceSettingsFlow) GetExpiresAtOk() (*time.Time, bool) { - if o == nil { - return nil, false - } - return &o.ExpiresAt, true -} - -// SetExpiresAt sets field value -func (o *SelfServiceSettingsFlow) SetExpiresAt(v time.Time) { - o.ExpiresAt = v -} - -// GetId returns the Id field value -func (o *SelfServiceSettingsFlow) GetId() string { - if o == nil { - var ret string - return ret - } - - return o.Id -} - -// GetIdOk returns a tuple with the Id field value -// and a boolean to check if the value has been set. -func (o *SelfServiceSettingsFlow) GetIdOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Id, true -} - -// SetId sets field value -func (o *SelfServiceSettingsFlow) SetId(v string) { - o.Id = v -} - -// GetIdentity returns the Identity field value -func (o *SelfServiceSettingsFlow) GetIdentity() Identity { - if o == nil { - var ret Identity - return ret - } - - return o.Identity -} - -// GetIdentityOk returns a tuple with the Identity field value -// and a boolean to check if the value has been set. -func (o *SelfServiceSettingsFlow) GetIdentityOk() (*Identity, bool) { - if o == nil { - return nil, false - } - return &o.Identity, true -} - -// SetIdentity sets field value -func (o *SelfServiceSettingsFlow) SetIdentity(v Identity) { - o.Identity = v -} - -// GetIssuedAt returns the IssuedAt field value -func (o *SelfServiceSettingsFlow) GetIssuedAt() time.Time { - if o == nil { - var ret time.Time - return ret - } - - return o.IssuedAt -} - -// GetIssuedAtOk returns a tuple with the IssuedAt field value -// and a boolean to check if the value has been set. -func (o *SelfServiceSettingsFlow) GetIssuedAtOk() (*time.Time, bool) { - if o == nil { - return nil, false - } - return &o.IssuedAt, true -} - -// SetIssuedAt sets field value -func (o *SelfServiceSettingsFlow) SetIssuedAt(v time.Time) { - o.IssuedAt = v -} - -// GetRequestUrl returns the RequestUrl field value -func (o *SelfServiceSettingsFlow) GetRequestUrl() string { - if o == nil { - var ret string - return ret - } - - return o.RequestUrl -} - -// GetRequestUrlOk returns a tuple with the RequestUrl field value -// and a boolean to check if the value has been set. -func (o *SelfServiceSettingsFlow) GetRequestUrlOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.RequestUrl, true -} - -// SetRequestUrl sets field value -func (o *SelfServiceSettingsFlow) SetRequestUrl(v string) { - o.RequestUrl = v -} - -// GetReturnTo returns the ReturnTo field value if set, zero value otherwise. -func (o *SelfServiceSettingsFlow) GetReturnTo() string { - if o == nil || o.ReturnTo == nil { - var ret string - return ret - } - return *o.ReturnTo -} - -// GetReturnToOk returns a tuple with the ReturnTo field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SelfServiceSettingsFlow) GetReturnToOk() (*string, bool) { - if o == nil || o.ReturnTo == nil { - return nil, false - } - return o.ReturnTo, true -} - -// HasReturnTo returns a boolean if a field has been set. -func (o *SelfServiceSettingsFlow) HasReturnTo() bool { - if o != nil && o.ReturnTo != nil { - return true - } - - return false -} - -// SetReturnTo gets a reference to the given string and assigns it to the ReturnTo field. -func (o *SelfServiceSettingsFlow) SetReturnTo(v string) { - o.ReturnTo = &v -} - -// GetState returns the State field value -func (o *SelfServiceSettingsFlow) GetState() SelfServiceSettingsFlowState { - if o == nil { - var ret SelfServiceSettingsFlowState - return ret - } - - return o.State -} - -// GetStateOk returns a tuple with the State field value -// and a boolean to check if the value has been set. -func (o *SelfServiceSettingsFlow) GetStateOk() (*SelfServiceSettingsFlowState, bool) { - if o == nil { - return nil, false - } - return &o.State, true -} - -// SetState sets field value -func (o *SelfServiceSettingsFlow) SetState(v SelfServiceSettingsFlowState) { - o.State = v -} - -// GetType returns the Type field value -func (o *SelfServiceSettingsFlow) GetType() string { - if o == nil { - var ret string - return ret - } - - return o.Type -} - -// GetTypeOk returns a tuple with the Type field value -// and a boolean to check if the value has been set. -func (o *SelfServiceSettingsFlow) GetTypeOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Type, true -} - -// SetType sets field value -func (o *SelfServiceSettingsFlow) SetType(v string) { - o.Type = v -} - -// GetUi returns the Ui field value -func (o *SelfServiceSettingsFlow) GetUi() UiContainer { - if o == nil { - var ret UiContainer - return ret - } - - return o.Ui -} - -// GetUiOk returns a tuple with the Ui field value -// and a boolean to check if the value has been set. -func (o *SelfServiceSettingsFlow) GetUiOk() (*UiContainer, bool) { - if o == nil { - return nil, false - } - return &o.Ui, true -} - -// SetUi sets field value -func (o *SelfServiceSettingsFlow) SetUi(v UiContainer) { - o.Ui = v -} - -func (o SelfServiceSettingsFlow) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.Active != nil { - toSerialize["active"] = o.Active - } - if true { - toSerialize["expires_at"] = o.ExpiresAt - } - if true { - toSerialize["id"] = o.Id - } - if true { - toSerialize["identity"] = o.Identity - } - if true { - toSerialize["issued_at"] = o.IssuedAt - } - if true { - toSerialize["request_url"] = o.RequestUrl - } - if o.ReturnTo != nil { - toSerialize["return_to"] = o.ReturnTo - } - if true { - toSerialize["state"] = o.State - } - if true { - toSerialize["type"] = o.Type - } - if true { - toSerialize["ui"] = o.Ui - } - return json.Marshal(toSerialize) -} - -type NullableSelfServiceSettingsFlow struct { - value *SelfServiceSettingsFlow - isSet bool -} - -func (v NullableSelfServiceSettingsFlow) Get() *SelfServiceSettingsFlow { - return v.value -} - -func (v *NullableSelfServiceSettingsFlow) Set(val *SelfServiceSettingsFlow) { - v.value = val - v.isSet = true -} - -func (v NullableSelfServiceSettingsFlow) IsSet() bool { - return v.isSet -} - -func (v *NullableSelfServiceSettingsFlow) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSelfServiceSettingsFlow(val *SelfServiceSettingsFlow) *NullableSelfServiceSettingsFlow { - return &NullableSelfServiceSettingsFlow{value: val, isSet: true} -} - -func (v NullableSelfServiceSettingsFlow) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSelfServiceSettingsFlow) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_self_service_settings_flow_state.go b/internal/client-go/model_self_service_settings_flow_state.go deleted file mode 100644 index 9163efb643e5..000000000000 --- a/internal/client-go/model_self_service_settings_flow_state.go +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Ory Identities API - * - * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. - * - * API version: - * Contact: office@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" - "fmt" -) - -// SelfServiceSettingsFlowState show_form: No user data has been collected, or it is invalid, and thus the form should be shown. success: Indicates that the settings flow has been updated successfully with the provided data. Done will stay true when repeatedly checking. If set to true, done will revert back to false only when a flow with invalid (e.g. \"please use a valid phone number\") data was sent. -type SelfServiceSettingsFlowState string - -// List of SelfServiceSettingsFlowState -const ( - SELFSERVICESETTINGSFLOWSTATE_SHOW_FORM SelfServiceSettingsFlowState = "show_form" - SELFSERVICESETTINGSFLOWSTATE_SUCCESS SelfServiceSettingsFlowState = "success" -) - -func (v *SelfServiceSettingsFlowState) UnmarshalJSON(src []byte) error { - var value string - err := json.Unmarshal(src, &value) - if err != nil { - return err - } - enumTypeValue := SelfServiceSettingsFlowState(value) - for _, existing := range []SelfServiceSettingsFlowState{"show_form", "success"} { - if existing == enumTypeValue { - *v = enumTypeValue - return nil - } - } - - return fmt.Errorf("%+v is not a valid SelfServiceSettingsFlowState", value) -} - -// Ptr returns reference to SelfServiceSettingsFlowState value -func (v SelfServiceSettingsFlowState) Ptr() *SelfServiceSettingsFlowState { - return &v -} - -type NullableSelfServiceSettingsFlowState struct { - value *SelfServiceSettingsFlowState - isSet bool -} - -func (v NullableSelfServiceSettingsFlowState) Get() *SelfServiceSettingsFlowState { - return v.value -} - -func (v *NullableSelfServiceSettingsFlowState) Set(val *SelfServiceSettingsFlowState) { - v.value = val - v.isSet = true -} - -func (v NullableSelfServiceSettingsFlowState) IsSet() bool { - return v.isSet -} - -func (v *NullableSelfServiceSettingsFlowState) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSelfServiceSettingsFlowState(val *SelfServiceSettingsFlowState) *NullableSelfServiceSettingsFlowState { - return &NullableSelfServiceSettingsFlowState{value: val, isSet: true} -} - -func (v NullableSelfServiceSettingsFlowState) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSelfServiceSettingsFlowState) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_self_service_verification_flow.go b/internal/client-go/model_self_service_verification_flow.go deleted file mode 100644 index 7ddccb2176cc..000000000000 --- a/internal/client-go/model_self_service_verification_flow.go +++ /dev/null @@ -1,385 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" - "time" -) - -// SelfServiceVerificationFlow Used to verify an out-of-band communication channel such as an email address or a phone number. For more information head over to: https://www.ory.sh/docs/kratos/self-service/flows/verify-email-account-activation -type SelfServiceVerificationFlow struct { - // Active, if set, contains the registration method that is being used. It is initially not set. - Active *string `json:"active,omitempty"` - // ExpiresAt is the time (UTC) when the request expires. If the user still wishes to verify the address, a new request has to be initiated. - ExpiresAt *time.Time `json:"expires_at,omitempty"` - // ID represents the request's unique ID. When performing the verification flow, this represents the id in the verify ui's query parameter: http://?request= type: string format: uuid - Id string `json:"id"` - // IssuedAt is the time (UTC) when the request occurred. - IssuedAt *time.Time `json:"issued_at,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,omitempty"` - // ReturnTo contains the requested return_to URL. - ReturnTo *string `json:"return_to,omitempty"` - State SelfServiceVerificationFlowState `json:"state"` - // The flow type can either be `api` or `browser`. - Type string `json:"type"` - Ui UiContainer `json:"ui"` -} - -// NewSelfServiceVerificationFlow instantiates a new SelfServiceVerificationFlow 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 NewSelfServiceVerificationFlow(id string, state SelfServiceVerificationFlowState, type_ string, ui UiContainer) *SelfServiceVerificationFlow { - this := SelfServiceVerificationFlow{} - this.Id = id - this.State = state - this.Type = type_ - this.Ui = ui - return &this -} - -// NewSelfServiceVerificationFlowWithDefaults instantiates a new SelfServiceVerificationFlow 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 NewSelfServiceVerificationFlowWithDefaults() *SelfServiceVerificationFlow { - this := SelfServiceVerificationFlow{} - return &this -} - -// GetActive returns the Active field value if set, zero value otherwise. -func (o *SelfServiceVerificationFlow) GetActive() string { - if o == nil || o.Active == nil { - var ret string - return ret - } - return *o.Active -} - -// GetActiveOk returns a tuple with the Active field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SelfServiceVerificationFlow) GetActiveOk() (*string, bool) { - if o == nil || o.Active == nil { - return nil, false - } - return o.Active, true -} - -// HasActive returns a boolean if a field has been set. -func (o *SelfServiceVerificationFlow) HasActive() bool { - if o != nil && o.Active != nil { - return true - } - - return false -} - -// SetActive gets a reference to the given string and assigns it to the Active field. -func (o *SelfServiceVerificationFlow) SetActive(v string) { - o.Active = &v -} - -// GetExpiresAt returns the ExpiresAt field value if set, zero value otherwise. -func (o *SelfServiceVerificationFlow) GetExpiresAt() time.Time { - if o == nil || o.ExpiresAt == nil { - var ret time.Time - return ret - } - return *o.ExpiresAt -} - -// GetExpiresAtOk returns a tuple with the ExpiresAt field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SelfServiceVerificationFlow) GetExpiresAtOk() (*time.Time, bool) { - if o == nil || o.ExpiresAt == nil { - return nil, false - } - return o.ExpiresAt, true -} - -// HasExpiresAt returns a boolean if a field has been set. -func (o *SelfServiceVerificationFlow) HasExpiresAt() bool { - if o != nil && o.ExpiresAt != nil { - return true - } - - return false -} - -// SetExpiresAt gets a reference to the given time.Time and assigns it to the ExpiresAt field. -func (o *SelfServiceVerificationFlow) SetExpiresAt(v time.Time) { - o.ExpiresAt = &v -} - -// GetId returns the Id field value -func (o *SelfServiceVerificationFlow) GetId() string { - if o == nil { - var ret string - return ret - } - - return o.Id -} - -// GetIdOk returns a tuple with the Id field value -// and a boolean to check if the value has been set. -func (o *SelfServiceVerificationFlow) GetIdOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Id, true -} - -// SetId sets field value -func (o *SelfServiceVerificationFlow) SetId(v string) { - o.Id = v -} - -// GetIssuedAt returns the IssuedAt field value if set, zero value otherwise. -func (o *SelfServiceVerificationFlow) GetIssuedAt() time.Time { - if o == nil || o.IssuedAt == nil { - var ret time.Time - return ret - } - return *o.IssuedAt -} - -// GetIssuedAtOk returns a tuple with the IssuedAt field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SelfServiceVerificationFlow) GetIssuedAtOk() (*time.Time, bool) { - if o == nil || o.IssuedAt == nil { - return nil, false - } - return o.IssuedAt, true -} - -// HasIssuedAt returns a boolean if a field has been set. -func (o *SelfServiceVerificationFlow) HasIssuedAt() bool { - if o != nil && o.IssuedAt != nil { - return true - } - - return false -} - -// SetIssuedAt gets a reference to the given time.Time and assigns it to the IssuedAt field. -func (o *SelfServiceVerificationFlow) SetIssuedAt(v time.Time) { - o.IssuedAt = &v -} - -// GetRequestUrl returns the RequestUrl field value if set, zero value otherwise. -func (o *SelfServiceVerificationFlow) 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 *SelfServiceVerificationFlow) 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 *SelfServiceVerificationFlow) 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 *SelfServiceVerificationFlow) SetRequestUrl(v string) { - o.RequestUrl = &v -} - -// GetReturnTo returns the ReturnTo field value if set, zero value otherwise. -func (o *SelfServiceVerificationFlow) GetReturnTo() string { - if o == nil || o.ReturnTo == nil { - var ret string - return ret - } - return *o.ReturnTo -} - -// GetReturnToOk returns a tuple with the ReturnTo field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SelfServiceVerificationFlow) GetReturnToOk() (*string, bool) { - if o == nil || o.ReturnTo == nil { - return nil, false - } - return o.ReturnTo, true -} - -// HasReturnTo returns a boolean if a field has been set. -func (o *SelfServiceVerificationFlow) HasReturnTo() bool { - if o != nil && o.ReturnTo != nil { - return true - } - - return false -} - -// SetReturnTo gets a reference to the given string and assigns it to the ReturnTo field. -func (o *SelfServiceVerificationFlow) SetReturnTo(v string) { - o.ReturnTo = &v -} - -// GetState returns the State field value -func (o *SelfServiceVerificationFlow) GetState() SelfServiceVerificationFlowState { - if o == nil { - var ret SelfServiceVerificationFlowState - return ret - } - - return o.State -} - -// GetStateOk returns a tuple with the State field value -// and a boolean to check if the value has been set. -func (o *SelfServiceVerificationFlow) GetStateOk() (*SelfServiceVerificationFlowState, bool) { - if o == nil { - return nil, false - } - return &o.State, true -} - -// SetState sets field value -func (o *SelfServiceVerificationFlow) SetState(v SelfServiceVerificationFlowState) { - o.State = v -} - -// GetType returns the Type field value -func (o *SelfServiceVerificationFlow) GetType() string { - if o == nil { - var ret string - return ret - } - - return o.Type -} - -// GetTypeOk returns a tuple with the Type field value -// and a boolean to check if the value has been set. -func (o *SelfServiceVerificationFlow) GetTypeOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Type, true -} - -// SetType sets field value -func (o *SelfServiceVerificationFlow) SetType(v string) { - o.Type = v -} - -// GetUi returns the Ui field value -func (o *SelfServiceVerificationFlow) GetUi() UiContainer { - if o == nil { - var ret UiContainer - return ret - } - - return o.Ui -} - -// GetUiOk returns a tuple with the Ui field value -// and a boolean to check if the value has been set. -func (o *SelfServiceVerificationFlow) GetUiOk() (*UiContainer, bool) { - if o == nil { - return nil, false - } - return &o.Ui, true -} - -// SetUi sets field value -func (o *SelfServiceVerificationFlow) SetUi(v UiContainer) { - o.Ui = v -} - -func (o SelfServiceVerificationFlow) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.Active != nil { - toSerialize["active"] = o.Active - } - if o.ExpiresAt != nil { - toSerialize["expires_at"] = o.ExpiresAt - } - if true { - toSerialize["id"] = o.Id - } - if o.IssuedAt != nil { - toSerialize["issued_at"] = o.IssuedAt - } - if o.RequestUrl != nil { - toSerialize["request_url"] = o.RequestUrl - } - if o.ReturnTo != nil { - toSerialize["return_to"] = o.ReturnTo - } - if true { - toSerialize["state"] = o.State - } - if true { - toSerialize["type"] = o.Type - } - if true { - toSerialize["ui"] = o.Ui - } - return json.Marshal(toSerialize) -} - -type NullableSelfServiceVerificationFlow struct { - value *SelfServiceVerificationFlow - isSet bool -} - -func (v NullableSelfServiceVerificationFlow) Get() *SelfServiceVerificationFlow { - return v.value -} - -func (v *NullableSelfServiceVerificationFlow) Set(val *SelfServiceVerificationFlow) { - v.value = val - v.isSet = true -} - -func (v NullableSelfServiceVerificationFlow) IsSet() bool { - return v.isSet -} - -func (v *NullableSelfServiceVerificationFlow) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSelfServiceVerificationFlow(val *SelfServiceVerificationFlow) *NullableSelfServiceVerificationFlow { - return &NullableSelfServiceVerificationFlow{value: val, isSet: true} -} - -func (v NullableSelfServiceVerificationFlow) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSelfServiceVerificationFlow) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_self_service_verification_flow_state.go b/internal/client-go/model_self_service_verification_flow_state.go deleted file mode 100644 index a3b9691ab038..000000000000 --- a/internal/client-go/model_self_service_verification_flow_state.go +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Ory Identities API - * - * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. - * - * API version: - * Contact: office@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" - "fmt" -) - -// SelfServiceVerificationFlowState The state represents the state of the verification flow. choose_method: ask the user to choose a method (e.g. recover account via email) sent_email: the email has been sent to the user passed_challenge: the request was successful and the recovery challenge was passed. -type SelfServiceVerificationFlowState string - -// List of SelfServiceVerificationFlowState -const ( - SELFSERVICEVERIFICATIONFLOWSTATE_CHOOSE_METHOD SelfServiceVerificationFlowState = "choose_method" - SELFSERVICEVERIFICATIONFLOWSTATE_SENT_EMAIL SelfServiceVerificationFlowState = "sent_email" - SELFSERVICEVERIFICATIONFLOWSTATE_PASSED_CHALLENGE SelfServiceVerificationFlowState = "passed_challenge" -) - -func (v *SelfServiceVerificationFlowState) UnmarshalJSON(src []byte) error { - var value string - err := json.Unmarshal(src, &value) - if err != nil { - return err - } - enumTypeValue := SelfServiceVerificationFlowState(value) - for _, existing := range []SelfServiceVerificationFlowState{"choose_method", "sent_email", "passed_challenge"} { - if existing == enumTypeValue { - *v = enumTypeValue - return nil - } - } - - return fmt.Errorf("%+v is not a valid SelfServiceVerificationFlowState", value) -} - -// Ptr returns reference to SelfServiceVerificationFlowState value -func (v SelfServiceVerificationFlowState) Ptr() *SelfServiceVerificationFlowState { - return &v -} - -type NullableSelfServiceVerificationFlowState struct { - value *SelfServiceVerificationFlowState - isSet bool -} - -func (v NullableSelfServiceVerificationFlowState) Get() *SelfServiceVerificationFlowState { - return v.value -} - -func (v *NullableSelfServiceVerificationFlowState) Set(val *SelfServiceVerificationFlowState) { - v.value = val - v.isSet = true -} - -func (v NullableSelfServiceVerificationFlowState) IsSet() bool { - return v.isSet -} - -func (v *NullableSelfServiceVerificationFlowState) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSelfServiceVerificationFlowState(val *SelfServiceVerificationFlowState) *NullableSelfServiceVerificationFlowState { - return &NullableSelfServiceVerificationFlowState{value: val, isSet: true} -} - -func (v NullableSelfServiceVerificationFlowState) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSelfServiceVerificationFlowState) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_settings_profile_form_config.go b/internal/client-go/model_settings_profile_form_config.go deleted file mode 100644 index 0e41fafb4a38..000000000000 --- a/internal/client-go/model_settings_profile_form_config.go +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// SettingsProfileFormConfig struct for SettingsProfileFormConfig -type SettingsProfileFormConfig struct { - // Action should be used as the form action URL `
`. - Action string `json:"action"` - Messages []UiText `json:"messages,omitempty"` - // Method is the form method (e.g. POST) - Method string `json:"method"` - Nodes []UiNode `json:"nodes"` -} - -// NewSettingsProfileFormConfig instantiates a new SettingsProfileFormConfig 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 NewSettingsProfileFormConfig(action string, method string, nodes []UiNode) *SettingsProfileFormConfig { - this := SettingsProfileFormConfig{} - this.Action = action - this.Method = method - this.Nodes = nodes - return &this -} - -// NewSettingsProfileFormConfigWithDefaults instantiates a new SettingsProfileFormConfig 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 NewSettingsProfileFormConfigWithDefaults() *SettingsProfileFormConfig { - this := SettingsProfileFormConfig{} - return &this -} - -// GetAction returns the Action field value -func (o *SettingsProfileFormConfig) GetAction() string { - if o == nil { - var ret string - return ret - } - - return o.Action -} - -// GetActionOk returns a tuple with the Action field value -// and a boolean to check if the value has been set. -func (o *SettingsProfileFormConfig) GetActionOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Action, true -} - -// SetAction sets field value -func (o *SettingsProfileFormConfig) SetAction(v string) { - o.Action = v -} - -// GetMessages returns the Messages field value if set, zero value otherwise. -func (o *SettingsProfileFormConfig) GetMessages() []UiText { - if o == nil || o.Messages == nil { - var ret []UiText - return ret - } - return o.Messages -} - -// GetMessagesOk returns a tuple with the Messages field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SettingsProfileFormConfig) GetMessagesOk() ([]UiText, bool) { - if o == nil || o.Messages == nil { - return nil, false - } - return o.Messages, true -} - -// HasMessages returns a boolean if a field has been set. -func (o *SettingsProfileFormConfig) HasMessages() bool { - if o != nil && o.Messages != nil { - return true - } - - return false -} - -// SetMessages gets a reference to the given []UiText and assigns it to the Messages field. -func (o *SettingsProfileFormConfig) SetMessages(v []UiText) { - o.Messages = v -} - -// GetMethod returns the Method field value -func (o *SettingsProfileFormConfig) GetMethod() string { - if o == nil { - var ret string - return ret - } - - return o.Method -} - -// GetMethodOk returns a tuple with the Method field value -// and a boolean to check if the value has been set. -func (o *SettingsProfileFormConfig) GetMethodOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Method, true -} - -// SetMethod sets field value -func (o *SettingsProfileFormConfig) SetMethod(v string) { - o.Method = v -} - -// GetNodes returns the Nodes field value -func (o *SettingsProfileFormConfig) GetNodes() []UiNode { - if o == nil { - var ret []UiNode - return ret - } - - return o.Nodes -} - -// GetNodesOk returns a tuple with the Nodes field value -// and a boolean to check if the value has been set. -func (o *SettingsProfileFormConfig) GetNodesOk() ([]UiNode, bool) { - if o == nil { - return nil, false - } - return o.Nodes, true -} - -// SetNodes sets field value -func (o *SettingsProfileFormConfig) SetNodes(v []UiNode) { - o.Nodes = v -} - -func (o SettingsProfileFormConfig) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if true { - toSerialize["action"] = o.Action - } - if o.Messages != nil { - toSerialize["messages"] = o.Messages - } - if true { - toSerialize["method"] = o.Method - } - if true { - toSerialize["nodes"] = o.Nodes - } - return json.Marshal(toSerialize) -} - -type NullableSettingsProfileFormConfig struct { - value *SettingsProfileFormConfig - isSet bool -} - -func (v NullableSettingsProfileFormConfig) Get() *SettingsProfileFormConfig { - return v.value -} - -func (v *NullableSettingsProfileFormConfig) Set(val *SettingsProfileFormConfig) { - v.value = val - v.isSet = true -} - -func (v NullableSettingsProfileFormConfig) IsSet() bool { - return v.isSet -} - -func (v *NullableSettingsProfileFormConfig) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSettingsProfileFormConfig(val *SettingsProfileFormConfig) *NullableSettingsProfileFormConfig { - return &NullableSettingsProfileFormConfig{value: val, isSet: true} -} - -func (v NullableSettingsProfileFormConfig) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSettingsProfileFormConfig) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_submit_self_service_flow_with_web_authn_registration_method.go b/internal/client-go/model_submit_self_service_flow_with_web_authn_registration_method.go deleted file mode 100644 index bed40667c32c..000000000000 --- a/internal/client-go/model_submit_self_service_flow_with_web_authn_registration_method.go +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// SubmitSelfServiceFlowWithWebAuthnRegistrationMethod struct for SubmitSelfServiceFlowWithWebAuthnRegistrationMethod -type SubmitSelfServiceFlowWithWebAuthnRegistrationMethod struct { - // Register a WebAuthn Security Key It is expected that the JSON returned by the WebAuthn registration process is included here. - WebauthnRegister *string `json:"webauthn_register,omitempty"` - // Name of the WebAuthn Security Key to be Added A human-readable name for the security key which will be added. - WebauthnRegisterDisplayname *string `json:"webauthn_register_displayname,omitempty"` -} - -// NewSubmitSelfServiceFlowWithWebAuthnRegistrationMethod instantiates a new SubmitSelfServiceFlowWithWebAuthnRegistrationMethod 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 NewSubmitSelfServiceFlowWithWebAuthnRegistrationMethod() *SubmitSelfServiceFlowWithWebAuthnRegistrationMethod { - this := SubmitSelfServiceFlowWithWebAuthnRegistrationMethod{} - return &this -} - -// NewSubmitSelfServiceFlowWithWebAuthnRegistrationMethodWithDefaults instantiates a new SubmitSelfServiceFlowWithWebAuthnRegistrationMethod 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 NewSubmitSelfServiceFlowWithWebAuthnRegistrationMethodWithDefaults() *SubmitSelfServiceFlowWithWebAuthnRegistrationMethod { - this := SubmitSelfServiceFlowWithWebAuthnRegistrationMethod{} - return &this -} - -// GetWebauthnRegister returns the WebauthnRegister field value if set, zero value otherwise. -func (o *SubmitSelfServiceFlowWithWebAuthnRegistrationMethod) GetWebauthnRegister() string { - if o == nil || o.WebauthnRegister == nil { - var ret string - return ret - } - return *o.WebauthnRegister -} - -// GetWebauthnRegisterOk returns a tuple with the WebauthnRegister field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceFlowWithWebAuthnRegistrationMethod) GetWebauthnRegisterOk() (*string, bool) { - if o == nil || o.WebauthnRegister == nil { - return nil, false - } - return o.WebauthnRegister, true -} - -// HasWebauthnRegister returns a boolean if a field has been set. -func (o *SubmitSelfServiceFlowWithWebAuthnRegistrationMethod) HasWebauthnRegister() bool { - if o != nil && o.WebauthnRegister != nil { - return true - } - - return false -} - -// SetWebauthnRegister gets a reference to the given string and assigns it to the WebauthnRegister field. -func (o *SubmitSelfServiceFlowWithWebAuthnRegistrationMethod) SetWebauthnRegister(v string) { - o.WebauthnRegister = &v -} - -// GetWebauthnRegisterDisplayname returns the WebauthnRegisterDisplayname field value if set, zero value otherwise. -func (o *SubmitSelfServiceFlowWithWebAuthnRegistrationMethod) GetWebauthnRegisterDisplayname() string { - if o == nil || o.WebauthnRegisterDisplayname == nil { - var ret string - return ret - } - return *o.WebauthnRegisterDisplayname -} - -// GetWebauthnRegisterDisplaynameOk returns a tuple with the WebauthnRegisterDisplayname field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceFlowWithWebAuthnRegistrationMethod) GetWebauthnRegisterDisplaynameOk() (*string, bool) { - if o == nil || o.WebauthnRegisterDisplayname == nil { - return nil, false - } - return o.WebauthnRegisterDisplayname, true -} - -// HasWebauthnRegisterDisplayname returns a boolean if a field has been set. -func (o *SubmitSelfServiceFlowWithWebAuthnRegistrationMethod) HasWebauthnRegisterDisplayname() bool { - if o != nil && o.WebauthnRegisterDisplayname != nil { - return true - } - - return false -} - -// SetWebauthnRegisterDisplayname gets a reference to the given string and assigns it to the WebauthnRegisterDisplayname field. -func (o *SubmitSelfServiceFlowWithWebAuthnRegistrationMethod) SetWebauthnRegisterDisplayname(v string) { - o.WebauthnRegisterDisplayname = &v -} - -func (o SubmitSelfServiceFlowWithWebAuthnRegistrationMethod) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.WebauthnRegister != nil { - toSerialize["webauthn_register"] = o.WebauthnRegister - } - if o.WebauthnRegisterDisplayname != nil { - toSerialize["webauthn_register_displayname"] = o.WebauthnRegisterDisplayname - } - return json.Marshal(toSerialize) -} - -type NullableSubmitSelfServiceFlowWithWebAuthnRegistrationMethod struct { - value *SubmitSelfServiceFlowWithWebAuthnRegistrationMethod - isSet bool -} - -func (v NullableSubmitSelfServiceFlowWithWebAuthnRegistrationMethod) Get() *SubmitSelfServiceFlowWithWebAuthnRegistrationMethod { - return v.value -} - -func (v *NullableSubmitSelfServiceFlowWithWebAuthnRegistrationMethod) Set(val *SubmitSelfServiceFlowWithWebAuthnRegistrationMethod) { - v.value = val - v.isSet = true -} - -func (v NullableSubmitSelfServiceFlowWithWebAuthnRegistrationMethod) IsSet() bool { - return v.isSet -} - -func (v *NullableSubmitSelfServiceFlowWithWebAuthnRegistrationMethod) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSubmitSelfServiceFlowWithWebAuthnRegistrationMethod(val *SubmitSelfServiceFlowWithWebAuthnRegistrationMethod) *NullableSubmitSelfServiceFlowWithWebAuthnRegistrationMethod { - return &NullableSubmitSelfServiceFlowWithWebAuthnRegistrationMethod{value: val, isSet: true} -} - -func (v NullableSubmitSelfServiceFlowWithWebAuthnRegistrationMethod) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSubmitSelfServiceFlowWithWebAuthnRegistrationMethod) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_submit_self_service_login_flow_body.go b/internal/client-go/model_submit_self_service_login_flow_body.go deleted file mode 100644 index e92f9466df0a..000000000000 --- a/internal/client-go/model_submit_self_service_login_flow_body.go +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" - "fmt" -) - -// SubmitSelfServiceLoginFlowBody - struct for SubmitSelfServiceLoginFlowBody -type SubmitSelfServiceLoginFlowBody struct { - SubmitSelfServiceLoginFlowWithLookupSecretMethodBody *SubmitSelfServiceLoginFlowWithLookupSecretMethodBody - SubmitSelfServiceLoginFlowWithOidcMethodBody *SubmitSelfServiceLoginFlowWithOidcMethodBody - SubmitSelfServiceLoginFlowWithPasswordMethodBody *SubmitSelfServiceLoginFlowWithPasswordMethodBody - SubmitSelfServiceLoginFlowWithTotpMethodBody *SubmitSelfServiceLoginFlowWithTotpMethodBody - SubmitSelfServiceLoginFlowWithWebAuthnMethodBody *SubmitSelfServiceLoginFlowWithWebAuthnMethodBody -} - -// SubmitSelfServiceLoginFlowWithLookupSecretMethodBodyAsSubmitSelfServiceLoginFlowBody is a convenience function that returns SubmitSelfServiceLoginFlowWithLookupSecretMethodBody wrapped in SubmitSelfServiceLoginFlowBody -func SubmitSelfServiceLoginFlowWithLookupSecretMethodBodyAsSubmitSelfServiceLoginFlowBody(v *SubmitSelfServiceLoginFlowWithLookupSecretMethodBody) SubmitSelfServiceLoginFlowBody { - return SubmitSelfServiceLoginFlowBody{ - SubmitSelfServiceLoginFlowWithLookupSecretMethodBody: v, - } -} - -// SubmitSelfServiceLoginFlowWithOidcMethodBodyAsSubmitSelfServiceLoginFlowBody is a convenience function that returns SubmitSelfServiceLoginFlowWithOidcMethodBody wrapped in SubmitSelfServiceLoginFlowBody -func SubmitSelfServiceLoginFlowWithOidcMethodBodyAsSubmitSelfServiceLoginFlowBody(v *SubmitSelfServiceLoginFlowWithOidcMethodBody) SubmitSelfServiceLoginFlowBody { - return SubmitSelfServiceLoginFlowBody{ - SubmitSelfServiceLoginFlowWithOidcMethodBody: v, - } -} - -// SubmitSelfServiceLoginFlowWithPasswordMethodBodyAsSubmitSelfServiceLoginFlowBody is a convenience function that returns SubmitSelfServiceLoginFlowWithPasswordMethodBody wrapped in SubmitSelfServiceLoginFlowBody -func SubmitSelfServiceLoginFlowWithPasswordMethodBodyAsSubmitSelfServiceLoginFlowBody(v *SubmitSelfServiceLoginFlowWithPasswordMethodBody) SubmitSelfServiceLoginFlowBody { - return SubmitSelfServiceLoginFlowBody{ - SubmitSelfServiceLoginFlowWithPasswordMethodBody: v, - } -} - -// SubmitSelfServiceLoginFlowWithTotpMethodBodyAsSubmitSelfServiceLoginFlowBody is a convenience function that returns SubmitSelfServiceLoginFlowWithTotpMethodBody wrapped in SubmitSelfServiceLoginFlowBody -func SubmitSelfServiceLoginFlowWithTotpMethodBodyAsSubmitSelfServiceLoginFlowBody(v *SubmitSelfServiceLoginFlowWithTotpMethodBody) SubmitSelfServiceLoginFlowBody { - return SubmitSelfServiceLoginFlowBody{ - SubmitSelfServiceLoginFlowWithTotpMethodBody: v, - } -} - -// SubmitSelfServiceLoginFlowWithWebAuthnMethodBodyAsSubmitSelfServiceLoginFlowBody is a convenience function that returns SubmitSelfServiceLoginFlowWithWebAuthnMethodBody wrapped in SubmitSelfServiceLoginFlowBody -func SubmitSelfServiceLoginFlowWithWebAuthnMethodBodyAsSubmitSelfServiceLoginFlowBody(v *SubmitSelfServiceLoginFlowWithWebAuthnMethodBody) SubmitSelfServiceLoginFlowBody { - return SubmitSelfServiceLoginFlowBody{ - SubmitSelfServiceLoginFlowWithWebAuthnMethodBody: v, - } -} - -// Unmarshal JSON data into one of the pointers in the struct -func (dst *SubmitSelfServiceLoginFlowBody) UnmarshalJSON(data []byte) error { - var err error - match := 0 - // try to unmarshal data into SubmitSelfServiceLoginFlowWithLookupSecretMethodBody - err = newStrictDecoder(data).Decode(&dst.SubmitSelfServiceLoginFlowWithLookupSecretMethodBody) - if err == nil { - jsonSubmitSelfServiceLoginFlowWithLookupSecretMethodBody, _ := json.Marshal(dst.SubmitSelfServiceLoginFlowWithLookupSecretMethodBody) - if string(jsonSubmitSelfServiceLoginFlowWithLookupSecretMethodBody) == "{}" { // empty struct - dst.SubmitSelfServiceLoginFlowWithLookupSecretMethodBody = nil - } else { - match++ - } - } else { - dst.SubmitSelfServiceLoginFlowWithLookupSecretMethodBody = nil - } - - // try to unmarshal data into SubmitSelfServiceLoginFlowWithOidcMethodBody - err = newStrictDecoder(data).Decode(&dst.SubmitSelfServiceLoginFlowWithOidcMethodBody) - if err == nil { - jsonSubmitSelfServiceLoginFlowWithOidcMethodBody, _ := json.Marshal(dst.SubmitSelfServiceLoginFlowWithOidcMethodBody) - if string(jsonSubmitSelfServiceLoginFlowWithOidcMethodBody) == "{}" { // empty struct - dst.SubmitSelfServiceLoginFlowWithOidcMethodBody = nil - } else { - match++ - } - } else { - dst.SubmitSelfServiceLoginFlowWithOidcMethodBody = nil - } - - // try to unmarshal data into SubmitSelfServiceLoginFlowWithPasswordMethodBody - err = newStrictDecoder(data).Decode(&dst.SubmitSelfServiceLoginFlowWithPasswordMethodBody) - if err == nil { - jsonSubmitSelfServiceLoginFlowWithPasswordMethodBody, _ := json.Marshal(dst.SubmitSelfServiceLoginFlowWithPasswordMethodBody) - if string(jsonSubmitSelfServiceLoginFlowWithPasswordMethodBody) == "{}" { // empty struct - dst.SubmitSelfServiceLoginFlowWithPasswordMethodBody = nil - } else { - match++ - } - } else { - dst.SubmitSelfServiceLoginFlowWithPasswordMethodBody = nil - } - - // try to unmarshal data into SubmitSelfServiceLoginFlowWithTotpMethodBody - err = newStrictDecoder(data).Decode(&dst.SubmitSelfServiceLoginFlowWithTotpMethodBody) - if err == nil { - jsonSubmitSelfServiceLoginFlowWithTotpMethodBody, _ := json.Marshal(dst.SubmitSelfServiceLoginFlowWithTotpMethodBody) - if string(jsonSubmitSelfServiceLoginFlowWithTotpMethodBody) == "{}" { // empty struct - dst.SubmitSelfServiceLoginFlowWithTotpMethodBody = nil - } else { - match++ - } - } else { - dst.SubmitSelfServiceLoginFlowWithTotpMethodBody = nil - } - - // try to unmarshal data into SubmitSelfServiceLoginFlowWithWebAuthnMethodBody - err = newStrictDecoder(data).Decode(&dst.SubmitSelfServiceLoginFlowWithWebAuthnMethodBody) - if err == nil { - jsonSubmitSelfServiceLoginFlowWithWebAuthnMethodBody, _ := json.Marshal(dst.SubmitSelfServiceLoginFlowWithWebAuthnMethodBody) - if string(jsonSubmitSelfServiceLoginFlowWithWebAuthnMethodBody) == "{}" { // empty struct - dst.SubmitSelfServiceLoginFlowWithWebAuthnMethodBody = nil - } else { - match++ - } - } else { - dst.SubmitSelfServiceLoginFlowWithWebAuthnMethodBody = nil - } - - if match > 1 { // more than 1 match - // reset to nil - dst.SubmitSelfServiceLoginFlowWithLookupSecretMethodBody = nil - dst.SubmitSelfServiceLoginFlowWithOidcMethodBody = nil - dst.SubmitSelfServiceLoginFlowWithPasswordMethodBody = nil - dst.SubmitSelfServiceLoginFlowWithTotpMethodBody = nil - dst.SubmitSelfServiceLoginFlowWithWebAuthnMethodBody = nil - - return fmt.Errorf("Data matches more than one schema in oneOf(SubmitSelfServiceLoginFlowBody)") - } else if match == 1 { - return nil // exactly one match - } else { // no match - return fmt.Errorf("Data failed to match schemas in oneOf(SubmitSelfServiceLoginFlowBody)") - } -} - -// Marshal data from the first non-nil pointers in the struct to JSON -func (src SubmitSelfServiceLoginFlowBody) MarshalJSON() ([]byte, error) { - if src.SubmitSelfServiceLoginFlowWithLookupSecretMethodBody != nil { - return json.Marshal(&src.SubmitSelfServiceLoginFlowWithLookupSecretMethodBody) - } - - if src.SubmitSelfServiceLoginFlowWithOidcMethodBody != nil { - return json.Marshal(&src.SubmitSelfServiceLoginFlowWithOidcMethodBody) - } - - if src.SubmitSelfServiceLoginFlowWithPasswordMethodBody != nil { - return json.Marshal(&src.SubmitSelfServiceLoginFlowWithPasswordMethodBody) - } - - if src.SubmitSelfServiceLoginFlowWithTotpMethodBody != nil { - return json.Marshal(&src.SubmitSelfServiceLoginFlowWithTotpMethodBody) - } - - if src.SubmitSelfServiceLoginFlowWithWebAuthnMethodBody != nil { - return json.Marshal(&src.SubmitSelfServiceLoginFlowWithWebAuthnMethodBody) - } - - return nil, nil // no data in oneOf schemas -} - -// Get the actual instance -func (obj *SubmitSelfServiceLoginFlowBody) GetActualInstance() interface{} { - if obj == nil { - return nil - } - if obj.SubmitSelfServiceLoginFlowWithLookupSecretMethodBody != nil { - return obj.SubmitSelfServiceLoginFlowWithLookupSecretMethodBody - } - - if obj.SubmitSelfServiceLoginFlowWithOidcMethodBody != nil { - return obj.SubmitSelfServiceLoginFlowWithOidcMethodBody - } - - if obj.SubmitSelfServiceLoginFlowWithPasswordMethodBody != nil { - return obj.SubmitSelfServiceLoginFlowWithPasswordMethodBody - } - - if obj.SubmitSelfServiceLoginFlowWithTotpMethodBody != nil { - return obj.SubmitSelfServiceLoginFlowWithTotpMethodBody - } - - if obj.SubmitSelfServiceLoginFlowWithWebAuthnMethodBody != nil { - return obj.SubmitSelfServiceLoginFlowWithWebAuthnMethodBody - } - - // all schemas are nil - return nil -} - -type NullableSubmitSelfServiceLoginFlowBody struct { - value *SubmitSelfServiceLoginFlowBody - isSet bool -} - -func (v NullableSubmitSelfServiceLoginFlowBody) Get() *SubmitSelfServiceLoginFlowBody { - return v.value -} - -func (v *NullableSubmitSelfServiceLoginFlowBody) Set(val *SubmitSelfServiceLoginFlowBody) { - v.value = val - v.isSet = true -} - -func (v NullableSubmitSelfServiceLoginFlowBody) IsSet() bool { - return v.isSet -} - -func (v *NullableSubmitSelfServiceLoginFlowBody) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSubmitSelfServiceLoginFlowBody(val *SubmitSelfServiceLoginFlowBody) *NullableSubmitSelfServiceLoginFlowBody { - return &NullableSubmitSelfServiceLoginFlowBody{value: val, isSet: true} -} - -func (v NullableSubmitSelfServiceLoginFlowBody) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSubmitSelfServiceLoginFlowBody) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_submit_self_service_login_flow_with_lookup_secret_method_body.go b/internal/client-go/model_submit_self_service_login_flow_with_lookup_secret_method_body.go deleted file mode 100644 index fc520dcda8e9..000000000000 --- a/internal/client-go/model_submit_self_service_login_flow_with_lookup_secret_method_body.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// SubmitSelfServiceLoginFlowWithLookupSecretMethodBody struct for SubmitSelfServiceLoginFlowWithLookupSecretMethodBody -type SubmitSelfServiceLoginFlowWithLookupSecretMethodBody struct { - // Sending the anti-csrf token is only required for browser login flows. - CsrfToken *string `json:"csrf_token,omitempty"` - // The lookup secret. - LookupSecret string `json:"lookup_secret"` - // Method should be set to \"lookup_secret\" when logging in using the lookup_secret strategy. - Method string `json:"method"` -} - -// NewSubmitSelfServiceLoginFlowWithLookupSecretMethodBody instantiates a new SubmitSelfServiceLoginFlowWithLookupSecretMethodBody 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 NewSubmitSelfServiceLoginFlowWithLookupSecretMethodBody(lookupSecret string, method string) *SubmitSelfServiceLoginFlowWithLookupSecretMethodBody { - this := SubmitSelfServiceLoginFlowWithLookupSecretMethodBody{} - this.LookupSecret = lookupSecret - this.Method = method - return &this -} - -// NewSubmitSelfServiceLoginFlowWithLookupSecretMethodBodyWithDefaults instantiates a new SubmitSelfServiceLoginFlowWithLookupSecretMethodBody 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 NewSubmitSelfServiceLoginFlowWithLookupSecretMethodBodyWithDefaults() *SubmitSelfServiceLoginFlowWithLookupSecretMethodBody { - this := SubmitSelfServiceLoginFlowWithLookupSecretMethodBody{} - return &this -} - -// GetCsrfToken returns the CsrfToken field value if set, zero value otherwise. -func (o *SubmitSelfServiceLoginFlowWithLookupSecretMethodBody) GetCsrfToken() string { - if o == nil || o.CsrfToken == nil { - var ret string - return ret - } - return *o.CsrfToken -} - -// GetCsrfTokenOk returns a tuple with the CsrfToken field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceLoginFlowWithLookupSecretMethodBody) GetCsrfTokenOk() (*string, bool) { - if o == nil || o.CsrfToken == nil { - return nil, false - } - return o.CsrfToken, true -} - -// HasCsrfToken returns a boolean if a field has been set. -func (o *SubmitSelfServiceLoginFlowWithLookupSecretMethodBody) HasCsrfToken() bool { - if o != nil && o.CsrfToken != nil { - return true - } - - return false -} - -// SetCsrfToken gets a reference to the given string and assigns it to the CsrfToken field. -func (o *SubmitSelfServiceLoginFlowWithLookupSecretMethodBody) SetCsrfToken(v string) { - o.CsrfToken = &v -} - -// GetLookupSecret returns the LookupSecret field value -func (o *SubmitSelfServiceLoginFlowWithLookupSecretMethodBody) GetLookupSecret() string { - if o == nil { - var ret string - return ret - } - - return o.LookupSecret -} - -// GetLookupSecretOk returns a tuple with the LookupSecret field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceLoginFlowWithLookupSecretMethodBody) GetLookupSecretOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.LookupSecret, true -} - -// SetLookupSecret sets field value -func (o *SubmitSelfServiceLoginFlowWithLookupSecretMethodBody) SetLookupSecret(v string) { - o.LookupSecret = v -} - -// GetMethod returns the Method field value -func (o *SubmitSelfServiceLoginFlowWithLookupSecretMethodBody) GetMethod() string { - if o == nil { - var ret string - return ret - } - - return o.Method -} - -// GetMethodOk returns a tuple with the Method field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceLoginFlowWithLookupSecretMethodBody) GetMethodOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Method, true -} - -// SetMethod sets field value -func (o *SubmitSelfServiceLoginFlowWithLookupSecretMethodBody) SetMethod(v string) { - o.Method = v -} - -func (o SubmitSelfServiceLoginFlowWithLookupSecretMethodBody) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.CsrfToken != nil { - toSerialize["csrf_token"] = o.CsrfToken - } - if true { - toSerialize["lookup_secret"] = o.LookupSecret - } - if true { - toSerialize["method"] = o.Method - } - return json.Marshal(toSerialize) -} - -type NullableSubmitSelfServiceLoginFlowWithLookupSecretMethodBody struct { - value *SubmitSelfServiceLoginFlowWithLookupSecretMethodBody - isSet bool -} - -func (v NullableSubmitSelfServiceLoginFlowWithLookupSecretMethodBody) Get() *SubmitSelfServiceLoginFlowWithLookupSecretMethodBody { - return v.value -} - -func (v *NullableSubmitSelfServiceLoginFlowWithLookupSecretMethodBody) Set(val *SubmitSelfServiceLoginFlowWithLookupSecretMethodBody) { - v.value = val - v.isSet = true -} - -func (v NullableSubmitSelfServiceLoginFlowWithLookupSecretMethodBody) IsSet() bool { - return v.isSet -} - -func (v *NullableSubmitSelfServiceLoginFlowWithLookupSecretMethodBody) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSubmitSelfServiceLoginFlowWithLookupSecretMethodBody(val *SubmitSelfServiceLoginFlowWithLookupSecretMethodBody) *NullableSubmitSelfServiceLoginFlowWithLookupSecretMethodBody { - return &NullableSubmitSelfServiceLoginFlowWithLookupSecretMethodBody{value: val, isSet: true} -} - -func (v NullableSubmitSelfServiceLoginFlowWithLookupSecretMethodBody) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSubmitSelfServiceLoginFlowWithLookupSecretMethodBody) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_submit_self_service_login_flow_with_oidc_method_body.go b/internal/client-go/model_submit_self_service_login_flow_with_oidc_method_body.go deleted file mode 100644 index 68fdd1ce409f..000000000000 --- a/internal/client-go/model_submit_self_service_login_flow_with_oidc_method_body.go +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// SubmitSelfServiceLoginFlowWithOidcMethodBody SubmitSelfServiceLoginFlowWithOidcMethodBody is used to decode the login form payload when using the oidc method. -type SubmitSelfServiceLoginFlowWithOidcMethodBody struct { - // The CSRF Token - CsrfToken *string `json:"csrf_token,omitempty"` - // Method to use This field must be set to `oidc` when using the oidc method. - Method string `json:"method"` - // The provider to register with - Provider string `json:"provider"` - // The identity traits. This is a placeholder for the registration flow. - Traits map[string]interface{} `json:"traits,omitempty"` -} - -// NewSubmitSelfServiceLoginFlowWithOidcMethodBody instantiates a new SubmitSelfServiceLoginFlowWithOidcMethodBody 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 NewSubmitSelfServiceLoginFlowWithOidcMethodBody(method string, provider string) *SubmitSelfServiceLoginFlowWithOidcMethodBody { - this := SubmitSelfServiceLoginFlowWithOidcMethodBody{} - this.Method = method - this.Provider = provider - return &this -} - -// NewSubmitSelfServiceLoginFlowWithOidcMethodBodyWithDefaults instantiates a new SubmitSelfServiceLoginFlowWithOidcMethodBody 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 NewSubmitSelfServiceLoginFlowWithOidcMethodBodyWithDefaults() *SubmitSelfServiceLoginFlowWithOidcMethodBody { - this := SubmitSelfServiceLoginFlowWithOidcMethodBody{} - return &this -} - -// GetCsrfToken returns the CsrfToken field value if set, zero value otherwise. -func (o *SubmitSelfServiceLoginFlowWithOidcMethodBody) GetCsrfToken() string { - if o == nil || o.CsrfToken == nil { - var ret string - return ret - } - return *o.CsrfToken -} - -// GetCsrfTokenOk returns a tuple with the CsrfToken field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceLoginFlowWithOidcMethodBody) GetCsrfTokenOk() (*string, bool) { - if o == nil || o.CsrfToken == nil { - return nil, false - } - return o.CsrfToken, true -} - -// HasCsrfToken returns a boolean if a field has been set. -func (o *SubmitSelfServiceLoginFlowWithOidcMethodBody) HasCsrfToken() bool { - if o != nil && o.CsrfToken != nil { - return true - } - - return false -} - -// SetCsrfToken gets a reference to the given string and assigns it to the CsrfToken field. -func (o *SubmitSelfServiceLoginFlowWithOidcMethodBody) SetCsrfToken(v string) { - o.CsrfToken = &v -} - -// GetMethod returns the Method field value -func (o *SubmitSelfServiceLoginFlowWithOidcMethodBody) GetMethod() string { - if o == nil { - var ret string - return ret - } - - return o.Method -} - -// GetMethodOk returns a tuple with the Method field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceLoginFlowWithOidcMethodBody) GetMethodOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Method, true -} - -// SetMethod sets field value -func (o *SubmitSelfServiceLoginFlowWithOidcMethodBody) SetMethod(v string) { - o.Method = v -} - -// GetProvider returns the Provider field value -func (o *SubmitSelfServiceLoginFlowWithOidcMethodBody) GetProvider() string { - if o == nil { - var ret string - return ret - } - - return o.Provider -} - -// GetProviderOk returns a tuple with the Provider field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceLoginFlowWithOidcMethodBody) GetProviderOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Provider, true -} - -// SetProvider sets field value -func (o *SubmitSelfServiceLoginFlowWithOidcMethodBody) SetProvider(v string) { - o.Provider = v -} - -// GetTraits returns the Traits field value if set, zero value otherwise. -func (o *SubmitSelfServiceLoginFlowWithOidcMethodBody) GetTraits() map[string]interface{} { - if o == nil || o.Traits == nil { - var ret map[string]interface{} - return ret - } - return o.Traits -} - -// GetTraitsOk returns a tuple with the Traits field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceLoginFlowWithOidcMethodBody) GetTraitsOk() (map[string]interface{}, bool) { - if o == nil || o.Traits == nil { - return nil, false - } - return o.Traits, true -} - -// HasTraits returns a boolean if a field has been set. -func (o *SubmitSelfServiceLoginFlowWithOidcMethodBody) HasTraits() bool { - if o != nil && o.Traits != nil { - return true - } - - return false -} - -// SetTraits gets a reference to the given map[string]interface{} and assigns it to the Traits field. -func (o *SubmitSelfServiceLoginFlowWithOidcMethodBody) SetTraits(v map[string]interface{}) { - o.Traits = v -} - -func (o SubmitSelfServiceLoginFlowWithOidcMethodBody) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.CsrfToken != nil { - toSerialize["csrf_token"] = o.CsrfToken - } - if true { - toSerialize["method"] = o.Method - } - if true { - toSerialize["provider"] = o.Provider - } - if o.Traits != nil { - toSerialize["traits"] = o.Traits - } - return json.Marshal(toSerialize) -} - -type NullableSubmitSelfServiceLoginFlowWithOidcMethodBody struct { - value *SubmitSelfServiceLoginFlowWithOidcMethodBody - isSet bool -} - -func (v NullableSubmitSelfServiceLoginFlowWithOidcMethodBody) Get() *SubmitSelfServiceLoginFlowWithOidcMethodBody { - return v.value -} - -func (v *NullableSubmitSelfServiceLoginFlowWithOidcMethodBody) Set(val *SubmitSelfServiceLoginFlowWithOidcMethodBody) { - v.value = val - v.isSet = true -} - -func (v NullableSubmitSelfServiceLoginFlowWithOidcMethodBody) IsSet() bool { - return v.isSet -} - -func (v *NullableSubmitSelfServiceLoginFlowWithOidcMethodBody) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSubmitSelfServiceLoginFlowWithOidcMethodBody(val *SubmitSelfServiceLoginFlowWithOidcMethodBody) *NullableSubmitSelfServiceLoginFlowWithOidcMethodBody { - return &NullableSubmitSelfServiceLoginFlowWithOidcMethodBody{value: val, isSet: true} -} - -func (v NullableSubmitSelfServiceLoginFlowWithOidcMethodBody) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSubmitSelfServiceLoginFlowWithOidcMethodBody) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_submit_self_service_login_flow_with_password_method_body.go b/internal/client-go/model_submit_self_service_login_flow_with_password_method_body.go deleted file mode 100644 index 3fb118934478..000000000000 --- a/internal/client-go/model_submit_self_service_login_flow_with_password_method_body.go +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// SubmitSelfServiceLoginFlowWithPasswordMethodBody struct for SubmitSelfServiceLoginFlowWithPasswordMethodBody -type SubmitSelfServiceLoginFlowWithPasswordMethodBody struct { - // Sending the anti-csrf token is only required for browser login flows. - CsrfToken *string `json:"csrf_token,omitempty"` - // Identifier is the email or username of the user trying to log in. - Identifier string `json:"identifier"` - // Method should be set to \"password\" when logging in using the identifier and password strategy. - Method string `json:"method"` - // The user's password. - Password string `json:"password"` - // Identifier is the email or username of the user trying to log in. This field is deprecated! - PasswordIdentifier *string `json:"password_identifier,omitempty"` -} - -// NewSubmitSelfServiceLoginFlowWithPasswordMethodBody instantiates a new SubmitSelfServiceLoginFlowWithPasswordMethodBody 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 NewSubmitSelfServiceLoginFlowWithPasswordMethodBody(identifier string, method string, password string) *SubmitSelfServiceLoginFlowWithPasswordMethodBody { - this := SubmitSelfServiceLoginFlowWithPasswordMethodBody{} - this.Identifier = identifier - this.Method = method - this.Password = password - return &this -} - -// NewSubmitSelfServiceLoginFlowWithPasswordMethodBodyWithDefaults instantiates a new SubmitSelfServiceLoginFlowWithPasswordMethodBody 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 NewSubmitSelfServiceLoginFlowWithPasswordMethodBodyWithDefaults() *SubmitSelfServiceLoginFlowWithPasswordMethodBody { - this := SubmitSelfServiceLoginFlowWithPasswordMethodBody{} - return &this -} - -// GetCsrfToken returns the CsrfToken field value if set, zero value otherwise. -func (o *SubmitSelfServiceLoginFlowWithPasswordMethodBody) GetCsrfToken() string { - if o == nil || o.CsrfToken == nil { - var ret string - return ret - } - return *o.CsrfToken -} - -// GetCsrfTokenOk returns a tuple with the CsrfToken field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceLoginFlowWithPasswordMethodBody) GetCsrfTokenOk() (*string, bool) { - if o == nil || o.CsrfToken == nil { - return nil, false - } - return o.CsrfToken, true -} - -// HasCsrfToken returns a boolean if a field has been set. -func (o *SubmitSelfServiceLoginFlowWithPasswordMethodBody) HasCsrfToken() bool { - if o != nil && o.CsrfToken != nil { - return true - } - - return false -} - -// SetCsrfToken gets a reference to the given string and assigns it to the CsrfToken field. -func (o *SubmitSelfServiceLoginFlowWithPasswordMethodBody) SetCsrfToken(v string) { - o.CsrfToken = &v -} - -// GetIdentifier returns the Identifier field value -func (o *SubmitSelfServiceLoginFlowWithPasswordMethodBody) GetIdentifier() string { - if o == nil { - var ret string - return ret - } - - return o.Identifier -} - -// GetIdentifierOk returns a tuple with the Identifier field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceLoginFlowWithPasswordMethodBody) GetIdentifierOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Identifier, true -} - -// SetIdentifier sets field value -func (o *SubmitSelfServiceLoginFlowWithPasswordMethodBody) SetIdentifier(v string) { - o.Identifier = v -} - -// GetMethod returns the Method field value -func (o *SubmitSelfServiceLoginFlowWithPasswordMethodBody) GetMethod() string { - if o == nil { - var ret string - return ret - } - - return o.Method -} - -// GetMethodOk returns a tuple with the Method field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceLoginFlowWithPasswordMethodBody) GetMethodOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Method, true -} - -// SetMethod sets field value -func (o *SubmitSelfServiceLoginFlowWithPasswordMethodBody) SetMethod(v string) { - o.Method = v -} - -// GetPassword returns the Password field value -func (o *SubmitSelfServiceLoginFlowWithPasswordMethodBody) GetPassword() string { - if o == nil { - var ret string - return ret - } - - return o.Password -} - -// GetPasswordOk returns a tuple with the Password field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceLoginFlowWithPasswordMethodBody) GetPasswordOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Password, true -} - -// SetPassword sets field value -func (o *SubmitSelfServiceLoginFlowWithPasswordMethodBody) SetPassword(v string) { - o.Password = v -} - -// GetPasswordIdentifier returns the PasswordIdentifier field value if set, zero value otherwise. -func (o *SubmitSelfServiceLoginFlowWithPasswordMethodBody) GetPasswordIdentifier() string { - if o == nil || o.PasswordIdentifier == nil { - var ret string - return ret - } - return *o.PasswordIdentifier -} - -// GetPasswordIdentifierOk returns a tuple with the PasswordIdentifier field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceLoginFlowWithPasswordMethodBody) GetPasswordIdentifierOk() (*string, bool) { - if o == nil || o.PasswordIdentifier == nil { - return nil, false - } - return o.PasswordIdentifier, true -} - -// HasPasswordIdentifier returns a boolean if a field has been set. -func (o *SubmitSelfServiceLoginFlowWithPasswordMethodBody) HasPasswordIdentifier() bool { - if o != nil && o.PasswordIdentifier != nil { - return true - } - - return false -} - -// SetPasswordIdentifier gets a reference to the given string and assigns it to the PasswordIdentifier field. -func (o *SubmitSelfServiceLoginFlowWithPasswordMethodBody) SetPasswordIdentifier(v string) { - o.PasswordIdentifier = &v -} - -func (o SubmitSelfServiceLoginFlowWithPasswordMethodBody) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.CsrfToken != nil { - toSerialize["csrf_token"] = o.CsrfToken - } - if true { - toSerialize["identifier"] = o.Identifier - } - if true { - toSerialize["method"] = o.Method - } - if true { - toSerialize["password"] = o.Password - } - if o.PasswordIdentifier != nil { - toSerialize["password_identifier"] = o.PasswordIdentifier - } - return json.Marshal(toSerialize) -} - -type NullableSubmitSelfServiceLoginFlowWithPasswordMethodBody struct { - value *SubmitSelfServiceLoginFlowWithPasswordMethodBody - isSet bool -} - -func (v NullableSubmitSelfServiceLoginFlowWithPasswordMethodBody) Get() *SubmitSelfServiceLoginFlowWithPasswordMethodBody { - return v.value -} - -func (v *NullableSubmitSelfServiceLoginFlowWithPasswordMethodBody) Set(val *SubmitSelfServiceLoginFlowWithPasswordMethodBody) { - v.value = val - v.isSet = true -} - -func (v NullableSubmitSelfServiceLoginFlowWithPasswordMethodBody) IsSet() bool { - return v.isSet -} - -func (v *NullableSubmitSelfServiceLoginFlowWithPasswordMethodBody) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSubmitSelfServiceLoginFlowWithPasswordMethodBody(val *SubmitSelfServiceLoginFlowWithPasswordMethodBody) *NullableSubmitSelfServiceLoginFlowWithPasswordMethodBody { - return &NullableSubmitSelfServiceLoginFlowWithPasswordMethodBody{value: val, isSet: true} -} - -func (v NullableSubmitSelfServiceLoginFlowWithPasswordMethodBody) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSubmitSelfServiceLoginFlowWithPasswordMethodBody) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_submit_self_service_login_flow_with_totp_method_body.go b/internal/client-go/model_submit_self_service_login_flow_with_totp_method_body.go deleted file mode 100644 index e7cf2dfc3e4d..000000000000 --- a/internal/client-go/model_submit_self_service_login_flow_with_totp_method_body.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// SubmitSelfServiceLoginFlowWithTotpMethodBody struct for SubmitSelfServiceLoginFlowWithTotpMethodBody -type SubmitSelfServiceLoginFlowWithTotpMethodBody struct { - // Sending the anti-csrf token is only required for browser login flows. - CsrfToken *string `json:"csrf_token,omitempty"` - // Method should be set to \"totp\" when logging in using the TOTP strategy. - Method string `json:"method"` - // The TOTP code. - TotpCode string `json:"totp_code"` -} - -// NewSubmitSelfServiceLoginFlowWithTotpMethodBody instantiates a new SubmitSelfServiceLoginFlowWithTotpMethodBody 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 NewSubmitSelfServiceLoginFlowWithTotpMethodBody(method string, totpCode string) *SubmitSelfServiceLoginFlowWithTotpMethodBody { - this := SubmitSelfServiceLoginFlowWithTotpMethodBody{} - this.Method = method - this.TotpCode = totpCode - return &this -} - -// NewSubmitSelfServiceLoginFlowWithTotpMethodBodyWithDefaults instantiates a new SubmitSelfServiceLoginFlowWithTotpMethodBody 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 NewSubmitSelfServiceLoginFlowWithTotpMethodBodyWithDefaults() *SubmitSelfServiceLoginFlowWithTotpMethodBody { - this := SubmitSelfServiceLoginFlowWithTotpMethodBody{} - return &this -} - -// GetCsrfToken returns the CsrfToken field value if set, zero value otherwise. -func (o *SubmitSelfServiceLoginFlowWithTotpMethodBody) GetCsrfToken() string { - if o == nil || o.CsrfToken == nil { - var ret string - return ret - } - return *o.CsrfToken -} - -// GetCsrfTokenOk returns a tuple with the CsrfToken field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceLoginFlowWithTotpMethodBody) GetCsrfTokenOk() (*string, bool) { - if o == nil || o.CsrfToken == nil { - return nil, false - } - return o.CsrfToken, true -} - -// HasCsrfToken returns a boolean if a field has been set. -func (o *SubmitSelfServiceLoginFlowWithTotpMethodBody) HasCsrfToken() bool { - if o != nil && o.CsrfToken != nil { - return true - } - - return false -} - -// SetCsrfToken gets a reference to the given string and assigns it to the CsrfToken field. -func (o *SubmitSelfServiceLoginFlowWithTotpMethodBody) SetCsrfToken(v string) { - o.CsrfToken = &v -} - -// GetMethod returns the Method field value -func (o *SubmitSelfServiceLoginFlowWithTotpMethodBody) GetMethod() string { - if o == nil { - var ret string - return ret - } - - return o.Method -} - -// GetMethodOk returns a tuple with the Method field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceLoginFlowWithTotpMethodBody) GetMethodOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Method, true -} - -// SetMethod sets field value -func (o *SubmitSelfServiceLoginFlowWithTotpMethodBody) SetMethod(v string) { - o.Method = v -} - -// GetTotpCode returns the TotpCode field value -func (o *SubmitSelfServiceLoginFlowWithTotpMethodBody) GetTotpCode() string { - if o == nil { - var ret string - return ret - } - - return o.TotpCode -} - -// GetTotpCodeOk returns a tuple with the TotpCode field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceLoginFlowWithTotpMethodBody) GetTotpCodeOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.TotpCode, true -} - -// SetTotpCode sets field value -func (o *SubmitSelfServiceLoginFlowWithTotpMethodBody) SetTotpCode(v string) { - o.TotpCode = v -} - -func (o SubmitSelfServiceLoginFlowWithTotpMethodBody) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.CsrfToken != nil { - toSerialize["csrf_token"] = o.CsrfToken - } - if true { - toSerialize["method"] = o.Method - } - if true { - toSerialize["totp_code"] = o.TotpCode - } - return json.Marshal(toSerialize) -} - -type NullableSubmitSelfServiceLoginFlowWithTotpMethodBody struct { - value *SubmitSelfServiceLoginFlowWithTotpMethodBody - isSet bool -} - -func (v NullableSubmitSelfServiceLoginFlowWithTotpMethodBody) Get() *SubmitSelfServiceLoginFlowWithTotpMethodBody { - return v.value -} - -func (v *NullableSubmitSelfServiceLoginFlowWithTotpMethodBody) Set(val *SubmitSelfServiceLoginFlowWithTotpMethodBody) { - v.value = val - v.isSet = true -} - -func (v NullableSubmitSelfServiceLoginFlowWithTotpMethodBody) IsSet() bool { - return v.isSet -} - -func (v *NullableSubmitSelfServiceLoginFlowWithTotpMethodBody) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSubmitSelfServiceLoginFlowWithTotpMethodBody(val *SubmitSelfServiceLoginFlowWithTotpMethodBody) *NullableSubmitSelfServiceLoginFlowWithTotpMethodBody { - return &NullableSubmitSelfServiceLoginFlowWithTotpMethodBody{value: val, isSet: true} -} - -func (v NullableSubmitSelfServiceLoginFlowWithTotpMethodBody) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSubmitSelfServiceLoginFlowWithTotpMethodBody) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_submit_self_service_login_flow_with_web_authn_method_body.go b/internal/client-go/model_submit_self_service_login_flow_with_web_authn_method_body.go deleted file mode 100644 index ed8d59109e2b..000000000000 --- a/internal/client-go/model_submit_self_service_login_flow_with_web_authn_method_body.go +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// SubmitSelfServiceLoginFlowWithWebAuthnMethodBody struct for SubmitSelfServiceLoginFlowWithWebAuthnMethodBody -type SubmitSelfServiceLoginFlowWithWebAuthnMethodBody struct { - // Sending the anti-csrf token is only required for browser login flows. - CsrfToken *string `json:"csrf_token,omitempty"` - // Identifier is the email or username of the user trying to log in. - Identifier string `json:"identifier"` - // Method should be set to \"webAuthn\" when logging in using the WebAuthn strategy. - Method string `json:"method"` - // Login a WebAuthn Security Key This must contain the ID of the WebAuthN connection. - WebauthnLogin *string `json:"webauthn_login,omitempty"` -} - -// NewSubmitSelfServiceLoginFlowWithWebAuthnMethodBody instantiates a new SubmitSelfServiceLoginFlowWithWebAuthnMethodBody 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 NewSubmitSelfServiceLoginFlowWithWebAuthnMethodBody(identifier string, method string) *SubmitSelfServiceLoginFlowWithWebAuthnMethodBody { - this := SubmitSelfServiceLoginFlowWithWebAuthnMethodBody{} - this.Identifier = identifier - this.Method = method - return &this -} - -// NewSubmitSelfServiceLoginFlowWithWebAuthnMethodBodyWithDefaults instantiates a new SubmitSelfServiceLoginFlowWithWebAuthnMethodBody 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 NewSubmitSelfServiceLoginFlowWithWebAuthnMethodBodyWithDefaults() *SubmitSelfServiceLoginFlowWithWebAuthnMethodBody { - this := SubmitSelfServiceLoginFlowWithWebAuthnMethodBody{} - return &this -} - -// GetCsrfToken returns the CsrfToken field value if set, zero value otherwise. -func (o *SubmitSelfServiceLoginFlowWithWebAuthnMethodBody) GetCsrfToken() string { - if o == nil || o.CsrfToken == nil { - var ret string - return ret - } - return *o.CsrfToken -} - -// GetCsrfTokenOk returns a tuple with the CsrfToken field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceLoginFlowWithWebAuthnMethodBody) GetCsrfTokenOk() (*string, bool) { - if o == nil || o.CsrfToken == nil { - return nil, false - } - return o.CsrfToken, true -} - -// HasCsrfToken returns a boolean if a field has been set. -func (o *SubmitSelfServiceLoginFlowWithWebAuthnMethodBody) HasCsrfToken() bool { - if o != nil && o.CsrfToken != nil { - return true - } - - return false -} - -// SetCsrfToken gets a reference to the given string and assigns it to the CsrfToken field. -func (o *SubmitSelfServiceLoginFlowWithWebAuthnMethodBody) SetCsrfToken(v string) { - o.CsrfToken = &v -} - -// GetIdentifier returns the Identifier field value -func (o *SubmitSelfServiceLoginFlowWithWebAuthnMethodBody) GetIdentifier() string { - if o == nil { - var ret string - return ret - } - - return o.Identifier -} - -// GetIdentifierOk returns a tuple with the Identifier field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceLoginFlowWithWebAuthnMethodBody) GetIdentifierOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Identifier, true -} - -// SetIdentifier sets field value -func (o *SubmitSelfServiceLoginFlowWithWebAuthnMethodBody) SetIdentifier(v string) { - o.Identifier = v -} - -// GetMethod returns the Method field value -func (o *SubmitSelfServiceLoginFlowWithWebAuthnMethodBody) GetMethod() string { - if o == nil { - var ret string - return ret - } - - return o.Method -} - -// GetMethodOk returns a tuple with the Method field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceLoginFlowWithWebAuthnMethodBody) GetMethodOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Method, true -} - -// SetMethod sets field value -func (o *SubmitSelfServiceLoginFlowWithWebAuthnMethodBody) SetMethod(v string) { - o.Method = v -} - -// GetWebauthnLogin returns the WebauthnLogin field value if set, zero value otherwise. -func (o *SubmitSelfServiceLoginFlowWithWebAuthnMethodBody) GetWebauthnLogin() string { - if o == nil || o.WebauthnLogin == nil { - var ret string - return ret - } - return *o.WebauthnLogin -} - -// GetWebauthnLoginOk returns a tuple with the WebauthnLogin field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceLoginFlowWithWebAuthnMethodBody) GetWebauthnLoginOk() (*string, bool) { - if o == nil || o.WebauthnLogin == nil { - return nil, false - } - return o.WebauthnLogin, true -} - -// HasWebauthnLogin returns a boolean if a field has been set. -func (o *SubmitSelfServiceLoginFlowWithWebAuthnMethodBody) HasWebauthnLogin() bool { - if o != nil && o.WebauthnLogin != nil { - return true - } - - return false -} - -// SetWebauthnLogin gets a reference to the given string and assigns it to the WebauthnLogin field. -func (o *SubmitSelfServiceLoginFlowWithWebAuthnMethodBody) SetWebauthnLogin(v string) { - o.WebauthnLogin = &v -} - -func (o SubmitSelfServiceLoginFlowWithWebAuthnMethodBody) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.CsrfToken != nil { - toSerialize["csrf_token"] = o.CsrfToken - } - if true { - toSerialize["identifier"] = o.Identifier - } - if true { - toSerialize["method"] = o.Method - } - if o.WebauthnLogin != nil { - toSerialize["webauthn_login"] = o.WebauthnLogin - } - return json.Marshal(toSerialize) -} - -type NullableSubmitSelfServiceLoginFlowWithWebAuthnMethodBody struct { - value *SubmitSelfServiceLoginFlowWithWebAuthnMethodBody - isSet bool -} - -func (v NullableSubmitSelfServiceLoginFlowWithWebAuthnMethodBody) Get() *SubmitSelfServiceLoginFlowWithWebAuthnMethodBody { - return v.value -} - -func (v *NullableSubmitSelfServiceLoginFlowWithWebAuthnMethodBody) Set(val *SubmitSelfServiceLoginFlowWithWebAuthnMethodBody) { - v.value = val - v.isSet = true -} - -func (v NullableSubmitSelfServiceLoginFlowWithWebAuthnMethodBody) IsSet() bool { - return v.isSet -} - -func (v *NullableSubmitSelfServiceLoginFlowWithWebAuthnMethodBody) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSubmitSelfServiceLoginFlowWithWebAuthnMethodBody(val *SubmitSelfServiceLoginFlowWithWebAuthnMethodBody) *NullableSubmitSelfServiceLoginFlowWithWebAuthnMethodBody { - return &NullableSubmitSelfServiceLoginFlowWithWebAuthnMethodBody{value: val, isSet: true} -} - -func (v NullableSubmitSelfServiceLoginFlowWithWebAuthnMethodBody) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSubmitSelfServiceLoginFlowWithWebAuthnMethodBody) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_submit_self_service_logout_flow_without_browser_body.go b/internal/client-go/model_submit_self_service_logout_flow_without_browser_body.go deleted file mode 100644 index 0febd1518522..000000000000 --- a/internal/client-go/model_submit_self_service_logout_flow_without_browser_body.go +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// SubmitSelfServiceLogoutFlowWithoutBrowserBody nolint:deadcode,unused -type SubmitSelfServiceLogoutFlowWithoutBrowserBody struct { - // The Session Token Invalidate this session token. - SessionToken string `json:"session_token"` -} - -// NewSubmitSelfServiceLogoutFlowWithoutBrowserBody instantiates a new SubmitSelfServiceLogoutFlowWithoutBrowserBody 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 NewSubmitSelfServiceLogoutFlowWithoutBrowserBody(sessionToken string) *SubmitSelfServiceLogoutFlowWithoutBrowserBody { - this := SubmitSelfServiceLogoutFlowWithoutBrowserBody{} - this.SessionToken = sessionToken - return &this -} - -// NewSubmitSelfServiceLogoutFlowWithoutBrowserBodyWithDefaults instantiates a new SubmitSelfServiceLogoutFlowWithoutBrowserBody 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 NewSubmitSelfServiceLogoutFlowWithoutBrowserBodyWithDefaults() *SubmitSelfServiceLogoutFlowWithoutBrowserBody { - this := SubmitSelfServiceLogoutFlowWithoutBrowserBody{} - return &this -} - -// GetSessionToken returns the SessionToken field value -func (o *SubmitSelfServiceLogoutFlowWithoutBrowserBody) GetSessionToken() string { - if o == nil { - var ret string - return ret - } - - return o.SessionToken -} - -// GetSessionTokenOk returns a tuple with the SessionToken field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceLogoutFlowWithoutBrowserBody) GetSessionTokenOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.SessionToken, true -} - -// SetSessionToken sets field value -func (o *SubmitSelfServiceLogoutFlowWithoutBrowserBody) SetSessionToken(v string) { - o.SessionToken = v -} - -func (o SubmitSelfServiceLogoutFlowWithoutBrowserBody) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if true { - toSerialize["session_token"] = o.SessionToken - } - return json.Marshal(toSerialize) -} - -type NullableSubmitSelfServiceLogoutFlowWithoutBrowserBody struct { - value *SubmitSelfServiceLogoutFlowWithoutBrowserBody - isSet bool -} - -func (v NullableSubmitSelfServiceLogoutFlowWithoutBrowserBody) Get() *SubmitSelfServiceLogoutFlowWithoutBrowserBody { - return v.value -} - -func (v *NullableSubmitSelfServiceLogoutFlowWithoutBrowserBody) Set(val *SubmitSelfServiceLogoutFlowWithoutBrowserBody) { - v.value = val - v.isSet = true -} - -func (v NullableSubmitSelfServiceLogoutFlowWithoutBrowserBody) IsSet() bool { - return v.isSet -} - -func (v *NullableSubmitSelfServiceLogoutFlowWithoutBrowserBody) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSubmitSelfServiceLogoutFlowWithoutBrowserBody(val *SubmitSelfServiceLogoutFlowWithoutBrowserBody) *NullableSubmitSelfServiceLogoutFlowWithoutBrowserBody { - return &NullableSubmitSelfServiceLogoutFlowWithoutBrowserBody{value: val, isSet: true} -} - -func (v NullableSubmitSelfServiceLogoutFlowWithoutBrowserBody) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSubmitSelfServiceLogoutFlowWithoutBrowserBody) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_submit_self_service_recovery_flow_body.go b/internal/client-go/model_submit_self_service_recovery_flow_body.go deleted file mode 100644 index 2bf7645ad831..000000000000 --- a/internal/client-go/model_submit_self_service_recovery_flow_body.go +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" - "fmt" -) - -// SubmitSelfServiceRecoveryFlowBody - struct for SubmitSelfServiceRecoveryFlowBody -type SubmitSelfServiceRecoveryFlowBody struct { - SubmitSelfServiceRecoveryFlowWithCodeMethodBody *SubmitSelfServiceRecoveryFlowWithCodeMethodBody - SubmitSelfServiceRecoveryFlowWithLinkMethodBody *SubmitSelfServiceRecoveryFlowWithLinkMethodBody -} - -// SubmitSelfServiceRecoveryFlowWithCodeMethodBodyAsSubmitSelfServiceRecoveryFlowBody is a convenience function that returns SubmitSelfServiceRecoveryFlowWithCodeMethodBody wrapped in SubmitSelfServiceRecoveryFlowBody -func SubmitSelfServiceRecoveryFlowWithCodeMethodBodyAsSubmitSelfServiceRecoveryFlowBody(v *SubmitSelfServiceRecoveryFlowWithCodeMethodBody) SubmitSelfServiceRecoveryFlowBody { - return SubmitSelfServiceRecoveryFlowBody{ - SubmitSelfServiceRecoveryFlowWithCodeMethodBody: v, - } -} - -// SubmitSelfServiceRecoveryFlowWithLinkMethodBodyAsSubmitSelfServiceRecoveryFlowBody is a convenience function that returns SubmitSelfServiceRecoveryFlowWithLinkMethodBody wrapped in SubmitSelfServiceRecoveryFlowBody -func SubmitSelfServiceRecoveryFlowWithLinkMethodBodyAsSubmitSelfServiceRecoveryFlowBody(v *SubmitSelfServiceRecoveryFlowWithLinkMethodBody) SubmitSelfServiceRecoveryFlowBody { - return SubmitSelfServiceRecoveryFlowBody{ - SubmitSelfServiceRecoveryFlowWithLinkMethodBody: v, - } -} - -// Unmarshal JSON data into one of the pointers in the struct -func (dst *SubmitSelfServiceRecoveryFlowBody) UnmarshalJSON(data []byte) error { - var err error - match := 0 - // try to unmarshal data into SubmitSelfServiceRecoveryFlowWithCodeMethodBody - err = newStrictDecoder(data).Decode(&dst.SubmitSelfServiceRecoveryFlowWithCodeMethodBody) - if err == nil { - jsonSubmitSelfServiceRecoveryFlowWithCodeMethodBody, _ := json.Marshal(dst.SubmitSelfServiceRecoveryFlowWithCodeMethodBody) - if string(jsonSubmitSelfServiceRecoveryFlowWithCodeMethodBody) == "{}" { // empty struct - dst.SubmitSelfServiceRecoveryFlowWithCodeMethodBody = nil - } else { - match++ - } - } else { - dst.SubmitSelfServiceRecoveryFlowWithCodeMethodBody = nil - } - - // try to unmarshal data into SubmitSelfServiceRecoveryFlowWithLinkMethodBody - err = newStrictDecoder(data).Decode(&dst.SubmitSelfServiceRecoveryFlowWithLinkMethodBody) - if err == nil { - jsonSubmitSelfServiceRecoveryFlowWithLinkMethodBody, _ := json.Marshal(dst.SubmitSelfServiceRecoveryFlowWithLinkMethodBody) - if string(jsonSubmitSelfServiceRecoveryFlowWithLinkMethodBody) == "{}" { // empty struct - dst.SubmitSelfServiceRecoveryFlowWithLinkMethodBody = nil - } else { - match++ - } - } else { - dst.SubmitSelfServiceRecoveryFlowWithLinkMethodBody = nil - } - - if match > 1 { // more than 1 match - // reset to nil - dst.SubmitSelfServiceRecoveryFlowWithCodeMethodBody = nil - dst.SubmitSelfServiceRecoveryFlowWithLinkMethodBody = nil - - return fmt.Errorf("Data matches more than one schema in oneOf(SubmitSelfServiceRecoveryFlowBody)") - } else if match == 1 { - return nil // exactly one match - } else { // no match - return fmt.Errorf("Data failed to match schemas in oneOf(SubmitSelfServiceRecoveryFlowBody)") - } -} - -// Marshal data from the first non-nil pointers in the struct to JSON -func (src SubmitSelfServiceRecoveryFlowBody) MarshalJSON() ([]byte, error) { - if src.SubmitSelfServiceRecoveryFlowWithCodeMethodBody != nil { - return json.Marshal(&src.SubmitSelfServiceRecoveryFlowWithCodeMethodBody) - } - - if src.SubmitSelfServiceRecoveryFlowWithLinkMethodBody != nil { - return json.Marshal(&src.SubmitSelfServiceRecoveryFlowWithLinkMethodBody) - } - - return nil, nil // no data in oneOf schemas -} - -// Get the actual instance -func (obj *SubmitSelfServiceRecoveryFlowBody) GetActualInstance() interface{} { - if obj == nil { - return nil - } - if obj.SubmitSelfServiceRecoveryFlowWithCodeMethodBody != nil { - return obj.SubmitSelfServiceRecoveryFlowWithCodeMethodBody - } - - if obj.SubmitSelfServiceRecoveryFlowWithLinkMethodBody != nil { - return obj.SubmitSelfServiceRecoveryFlowWithLinkMethodBody - } - - // all schemas are nil - return nil -} - -type NullableSubmitSelfServiceRecoveryFlowBody struct { - value *SubmitSelfServiceRecoveryFlowBody - isSet bool -} - -func (v NullableSubmitSelfServiceRecoveryFlowBody) Get() *SubmitSelfServiceRecoveryFlowBody { - return v.value -} - -func (v *NullableSubmitSelfServiceRecoveryFlowBody) Set(val *SubmitSelfServiceRecoveryFlowBody) { - v.value = val - v.isSet = true -} - -func (v NullableSubmitSelfServiceRecoveryFlowBody) IsSet() bool { - return v.isSet -} - -func (v *NullableSubmitSelfServiceRecoveryFlowBody) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSubmitSelfServiceRecoveryFlowBody(val *SubmitSelfServiceRecoveryFlowBody) *NullableSubmitSelfServiceRecoveryFlowBody { - return &NullableSubmitSelfServiceRecoveryFlowBody{value: val, isSet: true} -} - -func (v NullableSubmitSelfServiceRecoveryFlowBody) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSubmitSelfServiceRecoveryFlowBody) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_submit_self_service_recovery_flow_with_code_method_body.go b/internal/client-go/model_submit_self_service_recovery_flow_with_code_method_body.go deleted file mode 100644 index 8074e4fa6570..000000000000 --- a/internal/client-go/model_submit_self_service_recovery_flow_with_code_method_body.go +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// SubmitSelfServiceRecoveryFlowWithCodeMethodBody struct for SubmitSelfServiceRecoveryFlowWithCodeMethodBody -type SubmitSelfServiceRecoveryFlowWithCodeMethodBody struct { - // Code from recovery email Sent to the user once a recovery has been initiated and is used to prove that the user is in possession of the email - Code *string `json:"code,omitempty"` - // Sending the anti-csrf token is only required for browser login flows. - CsrfToken *string `json:"csrf_token,omitempty"` - // Email to Recover Needs to be set when initiating the flow. If the email is a registered recovery email, a recovery link will be sent. If the email is not known, a email with details on what happened will be sent instead. format: email - Email *string `json:"email,omitempty"` - // Method supports `link` and `code` only right now. - Method string `json:"method"` -} - -// NewSubmitSelfServiceRecoveryFlowWithCodeMethodBody instantiates a new SubmitSelfServiceRecoveryFlowWithCodeMethodBody 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 NewSubmitSelfServiceRecoveryFlowWithCodeMethodBody(method string) *SubmitSelfServiceRecoveryFlowWithCodeMethodBody { - this := SubmitSelfServiceRecoveryFlowWithCodeMethodBody{} - this.Method = method - return &this -} - -// NewSubmitSelfServiceRecoveryFlowWithCodeMethodBodyWithDefaults instantiates a new SubmitSelfServiceRecoveryFlowWithCodeMethodBody 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 NewSubmitSelfServiceRecoveryFlowWithCodeMethodBodyWithDefaults() *SubmitSelfServiceRecoveryFlowWithCodeMethodBody { - this := SubmitSelfServiceRecoveryFlowWithCodeMethodBody{} - return &this -} - -// GetCode returns the Code field value if set, zero value otherwise. -func (o *SubmitSelfServiceRecoveryFlowWithCodeMethodBody) GetCode() string { - if o == nil || o.Code == nil { - var ret string - return ret - } - return *o.Code -} - -// GetCodeOk returns a tuple with the Code field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceRecoveryFlowWithCodeMethodBody) GetCodeOk() (*string, bool) { - if o == nil || o.Code == nil { - return nil, false - } - return o.Code, true -} - -// HasCode returns a boolean if a field has been set. -func (o *SubmitSelfServiceRecoveryFlowWithCodeMethodBody) HasCode() bool { - if o != nil && o.Code != nil { - return true - } - - return false -} - -// SetCode gets a reference to the given string and assigns it to the Code field. -func (o *SubmitSelfServiceRecoveryFlowWithCodeMethodBody) SetCode(v string) { - o.Code = &v -} - -// GetCsrfToken returns the CsrfToken field value if set, zero value otherwise. -func (o *SubmitSelfServiceRecoveryFlowWithCodeMethodBody) GetCsrfToken() string { - if o == nil || o.CsrfToken == nil { - var ret string - return ret - } - return *o.CsrfToken -} - -// GetCsrfTokenOk returns a tuple with the CsrfToken field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceRecoveryFlowWithCodeMethodBody) GetCsrfTokenOk() (*string, bool) { - if o == nil || o.CsrfToken == nil { - return nil, false - } - return o.CsrfToken, true -} - -// HasCsrfToken returns a boolean if a field has been set. -func (o *SubmitSelfServiceRecoveryFlowWithCodeMethodBody) HasCsrfToken() bool { - if o != nil && o.CsrfToken != nil { - return true - } - - return false -} - -// SetCsrfToken gets a reference to the given string and assigns it to the CsrfToken field. -func (o *SubmitSelfServiceRecoveryFlowWithCodeMethodBody) SetCsrfToken(v string) { - o.CsrfToken = &v -} - -// GetEmail returns the Email field value if set, zero value otherwise. -func (o *SubmitSelfServiceRecoveryFlowWithCodeMethodBody) GetEmail() string { - if o == nil || o.Email == nil { - var ret string - return ret - } - return *o.Email -} - -// GetEmailOk returns a tuple with the Email field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceRecoveryFlowWithCodeMethodBody) GetEmailOk() (*string, bool) { - if o == nil || o.Email == nil { - return nil, false - } - return o.Email, true -} - -// HasEmail returns a boolean if a field has been set. -func (o *SubmitSelfServiceRecoveryFlowWithCodeMethodBody) HasEmail() bool { - if o != nil && o.Email != nil { - return true - } - - return false -} - -// SetEmail gets a reference to the given string and assigns it to the Email field. -func (o *SubmitSelfServiceRecoveryFlowWithCodeMethodBody) SetEmail(v string) { - o.Email = &v -} - -// GetMethod returns the Method field value -func (o *SubmitSelfServiceRecoveryFlowWithCodeMethodBody) GetMethod() string { - if o == nil { - var ret string - return ret - } - - return o.Method -} - -// GetMethodOk returns a tuple with the Method field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceRecoveryFlowWithCodeMethodBody) GetMethodOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Method, true -} - -// SetMethod sets field value -func (o *SubmitSelfServiceRecoveryFlowWithCodeMethodBody) SetMethod(v string) { - o.Method = v -} - -func (o SubmitSelfServiceRecoveryFlowWithCodeMethodBody) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.Code != nil { - toSerialize["code"] = o.Code - } - if o.CsrfToken != nil { - toSerialize["csrf_token"] = o.CsrfToken - } - if o.Email != nil { - toSerialize["email"] = o.Email - } - if true { - toSerialize["method"] = o.Method - } - return json.Marshal(toSerialize) -} - -type NullableSubmitSelfServiceRecoveryFlowWithCodeMethodBody struct { - value *SubmitSelfServiceRecoveryFlowWithCodeMethodBody - isSet bool -} - -func (v NullableSubmitSelfServiceRecoveryFlowWithCodeMethodBody) Get() *SubmitSelfServiceRecoveryFlowWithCodeMethodBody { - return v.value -} - -func (v *NullableSubmitSelfServiceRecoveryFlowWithCodeMethodBody) Set(val *SubmitSelfServiceRecoveryFlowWithCodeMethodBody) { - v.value = val - v.isSet = true -} - -func (v NullableSubmitSelfServiceRecoveryFlowWithCodeMethodBody) IsSet() bool { - return v.isSet -} - -func (v *NullableSubmitSelfServiceRecoveryFlowWithCodeMethodBody) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSubmitSelfServiceRecoveryFlowWithCodeMethodBody(val *SubmitSelfServiceRecoveryFlowWithCodeMethodBody) *NullableSubmitSelfServiceRecoveryFlowWithCodeMethodBody { - return &NullableSubmitSelfServiceRecoveryFlowWithCodeMethodBody{value: val, isSet: true} -} - -func (v NullableSubmitSelfServiceRecoveryFlowWithCodeMethodBody) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSubmitSelfServiceRecoveryFlowWithCodeMethodBody) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_submit_self_service_recovery_flow_with_link_method_body.go b/internal/client-go/model_submit_self_service_recovery_flow_with_link_method_body.go deleted file mode 100644 index a2a3519174b4..000000000000 --- a/internal/client-go/model_submit_self_service_recovery_flow_with_link_method_body.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// SubmitSelfServiceRecoveryFlowWithLinkMethodBody struct for SubmitSelfServiceRecoveryFlowWithLinkMethodBody -type SubmitSelfServiceRecoveryFlowWithLinkMethodBody struct { - // Sending the anti-csrf token is only required for browser login flows. - CsrfToken *string `json:"csrf_token,omitempty"` - // Email to Recover Needs to be set when initiating the flow. If the email is a registered recovery email, a recovery link will be sent. If the email is not known, a email with details on what happened will be sent instead. format: email - Email string `json:"email"` - // Method supports `link` only right now. - Method string `json:"method"` -} - -// NewSubmitSelfServiceRecoveryFlowWithLinkMethodBody instantiates a new SubmitSelfServiceRecoveryFlowWithLinkMethodBody 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 NewSubmitSelfServiceRecoveryFlowWithLinkMethodBody(email string, method string) *SubmitSelfServiceRecoveryFlowWithLinkMethodBody { - this := SubmitSelfServiceRecoveryFlowWithLinkMethodBody{} - this.Email = email - this.Method = method - return &this -} - -// NewSubmitSelfServiceRecoveryFlowWithLinkMethodBodyWithDefaults instantiates a new SubmitSelfServiceRecoveryFlowWithLinkMethodBody 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 NewSubmitSelfServiceRecoveryFlowWithLinkMethodBodyWithDefaults() *SubmitSelfServiceRecoveryFlowWithLinkMethodBody { - this := SubmitSelfServiceRecoveryFlowWithLinkMethodBody{} - return &this -} - -// GetCsrfToken returns the CsrfToken field value if set, zero value otherwise. -func (o *SubmitSelfServiceRecoveryFlowWithLinkMethodBody) GetCsrfToken() string { - if o == nil || o.CsrfToken == nil { - var ret string - return ret - } - return *o.CsrfToken -} - -// GetCsrfTokenOk returns a tuple with the CsrfToken field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceRecoveryFlowWithLinkMethodBody) GetCsrfTokenOk() (*string, bool) { - if o == nil || o.CsrfToken == nil { - return nil, false - } - return o.CsrfToken, true -} - -// HasCsrfToken returns a boolean if a field has been set. -func (o *SubmitSelfServiceRecoveryFlowWithLinkMethodBody) HasCsrfToken() bool { - if o != nil && o.CsrfToken != nil { - return true - } - - return false -} - -// SetCsrfToken gets a reference to the given string and assigns it to the CsrfToken field. -func (o *SubmitSelfServiceRecoveryFlowWithLinkMethodBody) SetCsrfToken(v string) { - o.CsrfToken = &v -} - -// GetEmail returns the Email field value -func (o *SubmitSelfServiceRecoveryFlowWithLinkMethodBody) GetEmail() string { - if o == nil { - var ret string - return ret - } - - return o.Email -} - -// GetEmailOk returns a tuple with the Email field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceRecoveryFlowWithLinkMethodBody) GetEmailOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Email, true -} - -// SetEmail sets field value -func (o *SubmitSelfServiceRecoveryFlowWithLinkMethodBody) SetEmail(v string) { - o.Email = v -} - -// GetMethod returns the Method field value -func (o *SubmitSelfServiceRecoveryFlowWithLinkMethodBody) GetMethod() string { - if o == nil { - var ret string - return ret - } - - return o.Method -} - -// GetMethodOk returns a tuple with the Method field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceRecoveryFlowWithLinkMethodBody) GetMethodOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Method, true -} - -// SetMethod sets field value -func (o *SubmitSelfServiceRecoveryFlowWithLinkMethodBody) SetMethod(v string) { - o.Method = v -} - -func (o SubmitSelfServiceRecoveryFlowWithLinkMethodBody) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.CsrfToken != nil { - toSerialize["csrf_token"] = o.CsrfToken - } - if true { - toSerialize["email"] = o.Email - } - if true { - toSerialize["method"] = o.Method - } - return json.Marshal(toSerialize) -} - -type NullableSubmitSelfServiceRecoveryFlowWithLinkMethodBody struct { - value *SubmitSelfServiceRecoveryFlowWithLinkMethodBody - isSet bool -} - -func (v NullableSubmitSelfServiceRecoveryFlowWithLinkMethodBody) Get() *SubmitSelfServiceRecoveryFlowWithLinkMethodBody { - return v.value -} - -func (v *NullableSubmitSelfServiceRecoveryFlowWithLinkMethodBody) Set(val *SubmitSelfServiceRecoveryFlowWithLinkMethodBody) { - v.value = val - v.isSet = true -} - -func (v NullableSubmitSelfServiceRecoveryFlowWithLinkMethodBody) IsSet() bool { - return v.isSet -} - -func (v *NullableSubmitSelfServiceRecoveryFlowWithLinkMethodBody) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSubmitSelfServiceRecoveryFlowWithLinkMethodBody(val *SubmitSelfServiceRecoveryFlowWithLinkMethodBody) *NullableSubmitSelfServiceRecoveryFlowWithLinkMethodBody { - return &NullableSubmitSelfServiceRecoveryFlowWithLinkMethodBody{value: val, isSet: true} -} - -func (v NullableSubmitSelfServiceRecoveryFlowWithLinkMethodBody) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSubmitSelfServiceRecoveryFlowWithLinkMethodBody) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_submit_self_service_registration_flow_body.go b/internal/client-go/model_submit_self_service_registration_flow_body.go deleted file mode 100644 index ada41b0ddec2..000000000000 --- a/internal/client-go/model_submit_self_service_registration_flow_body.go +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" - "fmt" -) - -// SubmitSelfServiceRegistrationFlowBody - struct for SubmitSelfServiceRegistrationFlowBody -type SubmitSelfServiceRegistrationFlowBody struct { - SubmitSelfServiceRegistrationFlowWithOidcMethodBody *SubmitSelfServiceRegistrationFlowWithOidcMethodBody - SubmitSelfServiceRegistrationFlowWithPasswordMethodBody *SubmitSelfServiceRegistrationFlowWithPasswordMethodBody - SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody *SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody -} - -// SubmitSelfServiceRegistrationFlowWithOidcMethodBodyAsSubmitSelfServiceRegistrationFlowBody is a convenience function that returns SubmitSelfServiceRegistrationFlowWithOidcMethodBody wrapped in SubmitSelfServiceRegistrationFlowBody -func SubmitSelfServiceRegistrationFlowWithOidcMethodBodyAsSubmitSelfServiceRegistrationFlowBody(v *SubmitSelfServiceRegistrationFlowWithOidcMethodBody) SubmitSelfServiceRegistrationFlowBody { - return SubmitSelfServiceRegistrationFlowBody{ - SubmitSelfServiceRegistrationFlowWithOidcMethodBody: v, - } -} - -// SubmitSelfServiceRegistrationFlowWithPasswordMethodBodyAsSubmitSelfServiceRegistrationFlowBody is a convenience function that returns SubmitSelfServiceRegistrationFlowWithPasswordMethodBody wrapped in SubmitSelfServiceRegistrationFlowBody -func SubmitSelfServiceRegistrationFlowWithPasswordMethodBodyAsSubmitSelfServiceRegistrationFlowBody(v *SubmitSelfServiceRegistrationFlowWithPasswordMethodBody) SubmitSelfServiceRegistrationFlowBody { - return SubmitSelfServiceRegistrationFlowBody{ - SubmitSelfServiceRegistrationFlowWithPasswordMethodBody: v, - } -} - -// SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBodyAsSubmitSelfServiceRegistrationFlowBody is a convenience function that returns SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody wrapped in SubmitSelfServiceRegistrationFlowBody -func SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBodyAsSubmitSelfServiceRegistrationFlowBody(v *SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) SubmitSelfServiceRegistrationFlowBody { - return SubmitSelfServiceRegistrationFlowBody{ - SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody: v, - } -} - -// Unmarshal JSON data into one of the pointers in the struct -func (dst *SubmitSelfServiceRegistrationFlowBody) UnmarshalJSON(data []byte) error { - var err error - match := 0 - // try to unmarshal data into SubmitSelfServiceRegistrationFlowWithOidcMethodBody - err = newStrictDecoder(data).Decode(&dst.SubmitSelfServiceRegistrationFlowWithOidcMethodBody) - if err == nil { - jsonSubmitSelfServiceRegistrationFlowWithOidcMethodBody, _ := json.Marshal(dst.SubmitSelfServiceRegistrationFlowWithOidcMethodBody) - if string(jsonSubmitSelfServiceRegistrationFlowWithOidcMethodBody) == "{}" { // empty struct - dst.SubmitSelfServiceRegistrationFlowWithOidcMethodBody = nil - } else { - match++ - } - } else { - dst.SubmitSelfServiceRegistrationFlowWithOidcMethodBody = nil - } - - // try to unmarshal data into SubmitSelfServiceRegistrationFlowWithPasswordMethodBody - err = newStrictDecoder(data).Decode(&dst.SubmitSelfServiceRegistrationFlowWithPasswordMethodBody) - if err == nil { - jsonSubmitSelfServiceRegistrationFlowWithPasswordMethodBody, _ := json.Marshal(dst.SubmitSelfServiceRegistrationFlowWithPasswordMethodBody) - if string(jsonSubmitSelfServiceRegistrationFlowWithPasswordMethodBody) == "{}" { // empty struct - dst.SubmitSelfServiceRegistrationFlowWithPasswordMethodBody = nil - } else { - match++ - } - } else { - dst.SubmitSelfServiceRegistrationFlowWithPasswordMethodBody = nil - } - - // try to unmarshal data into SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody - err = newStrictDecoder(data).Decode(&dst.SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) - if err == nil { - jsonSubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody, _ := json.Marshal(dst.SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) - if string(jsonSubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) == "{}" { // empty struct - dst.SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody = nil - } else { - match++ - } - } else { - dst.SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody = nil - } - - if match > 1 { // more than 1 match - // reset to nil - dst.SubmitSelfServiceRegistrationFlowWithOidcMethodBody = nil - dst.SubmitSelfServiceRegistrationFlowWithPasswordMethodBody = nil - dst.SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody = nil - - return fmt.Errorf("Data matches more than one schema in oneOf(SubmitSelfServiceRegistrationFlowBody)") - } else if match == 1 { - return nil // exactly one match - } else { // no match - return fmt.Errorf("Data failed to match schemas in oneOf(SubmitSelfServiceRegistrationFlowBody)") - } -} - -// Marshal data from the first non-nil pointers in the struct to JSON -func (src SubmitSelfServiceRegistrationFlowBody) MarshalJSON() ([]byte, error) { - if src.SubmitSelfServiceRegistrationFlowWithOidcMethodBody != nil { - return json.Marshal(&src.SubmitSelfServiceRegistrationFlowWithOidcMethodBody) - } - - if src.SubmitSelfServiceRegistrationFlowWithPasswordMethodBody != nil { - return json.Marshal(&src.SubmitSelfServiceRegistrationFlowWithPasswordMethodBody) - } - - if src.SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody != nil { - return json.Marshal(&src.SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) - } - - return nil, nil // no data in oneOf schemas -} - -// Get the actual instance -func (obj *SubmitSelfServiceRegistrationFlowBody) GetActualInstance() interface{} { - if obj == nil { - return nil - } - if obj.SubmitSelfServiceRegistrationFlowWithOidcMethodBody != nil { - return obj.SubmitSelfServiceRegistrationFlowWithOidcMethodBody - } - - if obj.SubmitSelfServiceRegistrationFlowWithPasswordMethodBody != nil { - return obj.SubmitSelfServiceRegistrationFlowWithPasswordMethodBody - } - - if obj.SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody != nil { - return obj.SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody - } - - // all schemas are nil - return nil -} - -type NullableSubmitSelfServiceRegistrationFlowBody struct { - value *SubmitSelfServiceRegistrationFlowBody - isSet bool -} - -func (v NullableSubmitSelfServiceRegistrationFlowBody) Get() *SubmitSelfServiceRegistrationFlowBody { - return v.value -} - -func (v *NullableSubmitSelfServiceRegistrationFlowBody) Set(val *SubmitSelfServiceRegistrationFlowBody) { - v.value = val - v.isSet = true -} - -func (v NullableSubmitSelfServiceRegistrationFlowBody) IsSet() bool { - return v.isSet -} - -func (v *NullableSubmitSelfServiceRegistrationFlowBody) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSubmitSelfServiceRegistrationFlowBody(val *SubmitSelfServiceRegistrationFlowBody) *NullableSubmitSelfServiceRegistrationFlowBody { - return &NullableSubmitSelfServiceRegistrationFlowBody{value: val, isSet: true} -} - -func (v NullableSubmitSelfServiceRegistrationFlowBody) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSubmitSelfServiceRegistrationFlowBody) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_submit_self_service_registration_flow_with_oidc_method_body.go b/internal/client-go/model_submit_self_service_registration_flow_with_oidc_method_body.go deleted file mode 100644 index 6a6943029e1f..000000000000 --- a/internal/client-go/model_submit_self_service_registration_flow_with_oidc_method_body.go +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// SubmitSelfServiceRegistrationFlowWithOidcMethodBody SubmitSelfServiceRegistrationFlowWithOidcMethodBody is used to decode the registration form payload when using the oidc method. -type SubmitSelfServiceRegistrationFlowWithOidcMethodBody struct { - // The CSRF Token - CsrfToken *string `json:"csrf_token,omitempty"` - // Method to use This field must be set to `oidc` when using the oidc method. - Method string `json:"method"` - // The provider to register with - Provider string `json:"provider"` - // The identity traits - Traits map[string]interface{} `json:"traits,omitempty"` -} - -// NewSubmitSelfServiceRegistrationFlowWithOidcMethodBody instantiates a new SubmitSelfServiceRegistrationFlowWithOidcMethodBody 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 NewSubmitSelfServiceRegistrationFlowWithOidcMethodBody(method string, provider string) *SubmitSelfServiceRegistrationFlowWithOidcMethodBody { - this := SubmitSelfServiceRegistrationFlowWithOidcMethodBody{} - this.Method = method - this.Provider = provider - return &this -} - -// NewSubmitSelfServiceRegistrationFlowWithOidcMethodBodyWithDefaults instantiates a new SubmitSelfServiceRegistrationFlowWithOidcMethodBody 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 NewSubmitSelfServiceRegistrationFlowWithOidcMethodBodyWithDefaults() *SubmitSelfServiceRegistrationFlowWithOidcMethodBody { - this := SubmitSelfServiceRegistrationFlowWithOidcMethodBody{} - return &this -} - -// GetCsrfToken returns the CsrfToken field value if set, zero value otherwise. -func (o *SubmitSelfServiceRegistrationFlowWithOidcMethodBody) GetCsrfToken() string { - if o == nil || o.CsrfToken == nil { - var ret string - return ret - } - return *o.CsrfToken -} - -// GetCsrfTokenOk returns a tuple with the CsrfToken field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceRegistrationFlowWithOidcMethodBody) GetCsrfTokenOk() (*string, bool) { - if o == nil || o.CsrfToken == nil { - return nil, false - } - return o.CsrfToken, true -} - -// HasCsrfToken returns a boolean if a field has been set. -func (o *SubmitSelfServiceRegistrationFlowWithOidcMethodBody) HasCsrfToken() bool { - if o != nil && o.CsrfToken != nil { - return true - } - - return false -} - -// SetCsrfToken gets a reference to the given string and assigns it to the CsrfToken field. -func (o *SubmitSelfServiceRegistrationFlowWithOidcMethodBody) SetCsrfToken(v string) { - o.CsrfToken = &v -} - -// GetMethod returns the Method field value -func (o *SubmitSelfServiceRegistrationFlowWithOidcMethodBody) GetMethod() string { - if o == nil { - var ret string - return ret - } - - return o.Method -} - -// GetMethodOk returns a tuple with the Method field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceRegistrationFlowWithOidcMethodBody) GetMethodOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Method, true -} - -// SetMethod sets field value -func (o *SubmitSelfServiceRegistrationFlowWithOidcMethodBody) SetMethod(v string) { - o.Method = v -} - -// GetProvider returns the Provider field value -func (o *SubmitSelfServiceRegistrationFlowWithOidcMethodBody) GetProvider() string { - if o == nil { - var ret string - return ret - } - - return o.Provider -} - -// GetProviderOk returns a tuple with the Provider field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceRegistrationFlowWithOidcMethodBody) GetProviderOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Provider, true -} - -// SetProvider sets field value -func (o *SubmitSelfServiceRegistrationFlowWithOidcMethodBody) SetProvider(v string) { - o.Provider = v -} - -// GetTraits returns the Traits field value if set, zero value otherwise. -func (o *SubmitSelfServiceRegistrationFlowWithOidcMethodBody) GetTraits() map[string]interface{} { - if o == nil || o.Traits == nil { - var ret map[string]interface{} - return ret - } - return o.Traits -} - -// GetTraitsOk returns a tuple with the Traits field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceRegistrationFlowWithOidcMethodBody) GetTraitsOk() (map[string]interface{}, bool) { - if o == nil || o.Traits == nil { - return nil, false - } - return o.Traits, true -} - -// HasTraits returns a boolean if a field has been set. -func (o *SubmitSelfServiceRegistrationFlowWithOidcMethodBody) HasTraits() bool { - if o != nil && o.Traits != nil { - return true - } - - return false -} - -// SetTraits gets a reference to the given map[string]interface{} and assigns it to the Traits field. -func (o *SubmitSelfServiceRegistrationFlowWithOidcMethodBody) SetTraits(v map[string]interface{}) { - o.Traits = v -} - -func (o SubmitSelfServiceRegistrationFlowWithOidcMethodBody) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.CsrfToken != nil { - toSerialize["csrf_token"] = o.CsrfToken - } - if true { - toSerialize["method"] = o.Method - } - if true { - toSerialize["provider"] = o.Provider - } - if o.Traits != nil { - toSerialize["traits"] = o.Traits - } - return json.Marshal(toSerialize) -} - -type NullableSubmitSelfServiceRegistrationFlowWithOidcMethodBody struct { - value *SubmitSelfServiceRegistrationFlowWithOidcMethodBody - isSet bool -} - -func (v NullableSubmitSelfServiceRegistrationFlowWithOidcMethodBody) Get() *SubmitSelfServiceRegistrationFlowWithOidcMethodBody { - return v.value -} - -func (v *NullableSubmitSelfServiceRegistrationFlowWithOidcMethodBody) Set(val *SubmitSelfServiceRegistrationFlowWithOidcMethodBody) { - v.value = val - v.isSet = true -} - -func (v NullableSubmitSelfServiceRegistrationFlowWithOidcMethodBody) IsSet() bool { - return v.isSet -} - -func (v *NullableSubmitSelfServiceRegistrationFlowWithOidcMethodBody) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSubmitSelfServiceRegistrationFlowWithOidcMethodBody(val *SubmitSelfServiceRegistrationFlowWithOidcMethodBody) *NullableSubmitSelfServiceRegistrationFlowWithOidcMethodBody { - return &NullableSubmitSelfServiceRegistrationFlowWithOidcMethodBody{value: val, isSet: true} -} - -func (v NullableSubmitSelfServiceRegistrationFlowWithOidcMethodBody) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSubmitSelfServiceRegistrationFlowWithOidcMethodBody) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_submit_self_service_registration_flow_with_password_method_body.go b/internal/client-go/model_submit_self_service_registration_flow_with_password_method_body.go deleted file mode 100644 index 8514d9ce71d7..000000000000 --- a/internal/client-go/model_submit_self_service_registration_flow_with_password_method_body.go +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// SubmitSelfServiceRegistrationFlowWithPasswordMethodBody SubmitSelfServiceRegistrationFlowWithPasswordMethodBody is used to decode the registration form payload when using the password method. -type SubmitSelfServiceRegistrationFlowWithPasswordMethodBody struct { - // The CSRF Token - CsrfToken *string `json:"csrf_token,omitempty"` - // Method to use This field must be set to `password` when using the password method. - Method string `json:"method"` - // Password to sign the user up with - Password string `json:"password"` - // The identity's traits - Traits map[string]interface{} `json:"traits"` -} - -// NewSubmitSelfServiceRegistrationFlowWithPasswordMethodBody instantiates a new SubmitSelfServiceRegistrationFlowWithPasswordMethodBody 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 NewSubmitSelfServiceRegistrationFlowWithPasswordMethodBody(method string, password string, traits map[string]interface{}) *SubmitSelfServiceRegistrationFlowWithPasswordMethodBody { - this := SubmitSelfServiceRegistrationFlowWithPasswordMethodBody{} - this.Method = method - this.Password = password - this.Traits = traits - return &this -} - -// NewSubmitSelfServiceRegistrationFlowWithPasswordMethodBodyWithDefaults instantiates a new SubmitSelfServiceRegistrationFlowWithPasswordMethodBody 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 NewSubmitSelfServiceRegistrationFlowWithPasswordMethodBodyWithDefaults() *SubmitSelfServiceRegistrationFlowWithPasswordMethodBody { - this := SubmitSelfServiceRegistrationFlowWithPasswordMethodBody{} - return &this -} - -// GetCsrfToken returns the CsrfToken field value if set, zero value otherwise. -func (o *SubmitSelfServiceRegistrationFlowWithPasswordMethodBody) GetCsrfToken() string { - if o == nil || o.CsrfToken == nil { - var ret string - return ret - } - return *o.CsrfToken -} - -// GetCsrfTokenOk returns a tuple with the CsrfToken field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceRegistrationFlowWithPasswordMethodBody) GetCsrfTokenOk() (*string, bool) { - if o == nil || o.CsrfToken == nil { - return nil, false - } - return o.CsrfToken, true -} - -// HasCsrfToken returns a boolean if a field has been set. -func (o *SubmitSelfServiceRegistrationFlowWithPasswordMethodBody) HasCsrfToken() bool { - if o != nil && o.CsrfToken != nil { - return true - } - - return false -} - -// SetCsrfToken gets a reference to the given string and assigns it to the CsrfToken field. -func (o *SubmitSelfServiceRegistrationFlowWithPasswordMethodBody) SetCsrfToken(v string) { - o.CsrfToken = &v -} - -// GetMethod returns the Method field value -func (o *SubmitSelfServiceRegistrationFlowWithPasswordMethodBody) GetMethod() string { - if o == nil { - var ret string - return ret - } - - return o.Method -} - -// GetMethodOk returns a tuple with the Method field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceRegistrationFlowWithPasswordMethodBody) GetMethodOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Method, true -} - -// SetMethod sets field value -func (o *SubmitSelfServiceRegistrationFlowWithPasswordMethodBody) SetMethod(v string) { - o.Method = v -} - -// GetPassword returns the Password field value -func (o *SubmitSelfServiceRegistrationFlowWithPasswordMethodBody) GetPassword() string { - if o == nil { - var ret string - return ret - } - - return o.Password -} - -// GetPasswordOk returns a tuple with the Password field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceRegistrationFlowWithPasswordMethodBody) GetPasswordOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Password, true -} - -// SetPassword sets field value -func (o *SubmitSelfServiceRegistrationFlowWithPasswordMethodBody) SetPassword(v string) { - o.Password = v -} - -// GetTraits returns the Traits field value -func (o *SubmitSelfServiceRegistrationFlowWithPasswordMethodBody) GetTraits() map[string]interface{} { - if o == nil { - var ret map[string]interface{} - return ret - } - - return o.Traits -} - -// GetTraitsOk returns a tuple with the Traits field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceRegistrationFlowWithPasswordMethodBody) GetTraitsOk() (map[string]interface{}, bool) { - if o == nil { - return nil, false - } - return o.Traits, true -} - -// SetTraits sets field value -func (o *SubmitSelfServiceRegistrationFlowWithPasswordMethodBody) SetTraits(v map[string]interface{}) { - o.Traits = v -} - -func (o SubmitSelfServiceRegistrationFlowWithPasswordMethodBody) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.CsrfToken != nil { - toSerialize["csrf_token"] = o.CsrfToken - } - if true { - toSerialize["method"] = o.Method - } - if true { - toSerialize["password"] = o.Password - } - if true { - toSerialize["traits"] = o.Traits - } - return json.Marshal(toSerialize) -} - -type NullableSubmitSelfServiceRegistrationFlowWithPasswordMethodBody struct { - value *SubmitSelfServiceRegistrationFlowWithPasswordMethodBody - isSet bool -} - -func (v NullableSubmitSelfServiceRegistrationFlowWithPasswordMethodBody) Get() *SubmitSelfServiceRegistrationFlowWithPasswordMethodBody { - return v.value -} - -func (v *NullableSubmitSelfServiceRegistrationFlowWithPasswordMethodBody) Set(val *SubmitSelfServiceRegistrationFlowWithPasswordMethodBody) { - v.value = val - v.isSet = true -} - -func (v NullableSubmitSelfServiceRegistrationFlowWithPasswordMethodBody) IsSet() bool { - return v.isSet -} - -func (v *NullableSubmitSelfServiceRegistrationFlowWithPasswordMethodBody) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSubmitSelfServiceRegistrationFlowWithPasswordMethodBody(val *SubmitSelfServiceRegistrationFlowWithPasswordMethodBody) *NullableSubmitSelfServiceRegistrationFlowWithPasswordMethodBody { - return &NullableSubmitSelfServiceRegistrationFlowWithPasswordMethodBody{value: val, isSet: true} -} - -func (v NullableSubmitSelfServiceRegistrationFlowWithPasswordMethodBody) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSubmitSelfServiceRegistrationFlowWithPasswordMethodBody) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_submit_self_service_registration_flow_with_web_authn_method_body.go b/internal/client-go/model_submit_self_service_registration_flow_with_web_authn_method_body.go deleted file mode 100644 index 73156fff348b..000000000000 --- a/internal/client-go/model_submit_self_service_registration_flow_with_web_authn_method_body.go +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody struct for SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody -type SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody struct { - // CSRFToken is the anti-CSRF token - CsrfToken *string `json:"csrf_token,omitempty"` - // Method Should be set to \"webauthn\" when trying to add, update, or remove a webAuthn pairing. - Method string `json:"method"` - // The identity's traits - Traits map[string]interface{} `json:"traits"` - // Register a WebAuthn Security Key It is expected that the JSON returned by the WebAuthn registration process is included here. - WebauthnRegister *string `json:"webauthn_register,omitempty"` - // Name of the WebAuthn Security Key to be Added A human-readable name for the security key which will be added. - WebauthnRegisterDisplayname *string `json:"webauthn_register_displayname,omitempty"` -} - -// NewSubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody instantiates a new SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody 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 NewSubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody(method string, traits map[string]interface{}) *SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody { - this := SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody{} - this.Method = method - this.Traits = traits - return &this -} - -// NewSubmitSelfServiceRegistrationFlowWithWebAuthnMethodBodyWithDefaults instantiates a new SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody 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 NewSubmitSelfServiceRegistrationFlowWithWebAuthnMethodBodyWithDefaults() *SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody { - this := SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody{} - return &this -} - -// GetCsrfToken returns the CsrfToken field value if set, zero value otherwise. -func (o *SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) GetCsrfToken() string { - if o == nil || o.CsrfToken == nil { - var ret string - return ret - } - return *o.CsrfToken -} - -// GetCsrfTokenOk returns a tuple with the CsrfToken field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) GetCsrfTokenOk() (*string, bool) { - if o == nil || o.CsrfToken == nil { - return nil, false - } - return o.CsrfToken, true -} - -// HasCsrfToken returns a boolean if a field has been set. -func (o *SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) HasCsrfToken() bool { - if o != nil && o.CsrfToken != nil { - return true - } - - return false -} - -// SetCsrfToken gets a reference to the given string and assigns it to the CsrfToken field. -func (o *SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) SetCsrfToken(v string) { - o.CsrfToken = &v -} - -// GetMethod returns the Method field value -func (o *SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) GetMethod() string { - if o == nil { - var ret string - return ret - } - - return o.Method -} - -// GetMethodOk returns a tuple with the Method field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) GetMethodOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Method, true -} - -// SetMethod sets field value -func (o *SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) SetMethod(v string) { - o.Method = v -} - -// GetTraits returns the Traits field value -func (o *SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) GetTraits() map[string]interface{} { - if o == nil { - var ret map[string]interface{} - return ret - } - - return o.Traits -} - -// GetTraitsOk returns a tuple with the Traits field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) GetTraitsOk() (map[string]interface{}, bool) { - if o == nil { - return nil, false - } - return o.Traits, true -} - -// SetTraits sets field value -func (o *SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) SetTraits(v map[string]interface{}) { - o.Traits = v -} - -// GetWebauthnRegister returns the WebauthnRegister field value if set, zero value otherwise. -func (o *SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) GetWebauthnRegister() string { - if o == nil || o.WebauthnRegister == nil { - var ret string - return ret - } - return *o.WebauthnRegister -} - -// GetWebauthnRegisterOk returns a tuple with the WebauthnRegister field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) GetWebauthnRegisterOk() (*string, bool) { - if o == nil || o.WebauthnRegister == nil { - return nil, false - } - return o.WebauthnRegister, true -} - -// HasWebauthnRegister returns a boolean if a field has been set. -func (o *SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) HasWebauthnRegister() bool { - if o != nil && o.WebauthnRegister != nil { - return true - } - - return false -} - -// SetWebauthnRegister gets a reference to the given string and assigns it to the WebauthnRegister field. -func (o *SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) SetWebauthnRegister(v string) { - o.WebauthnRegister = &v -} - -// GetWebauthnRegisterDisplayname returns the WebauthnRegisterDisplayname field value if set, zero value otherwise. -func (o *SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) GetWebauthnRegisterDisplayname() string { - if o == nil || o.WebauthnRegisterDisplayname == nil { - var ret string - return ret - } - return *o.WebauthnRegisterDisplayname -} - -// GetWebauthnRegisterDisplaynameOk returns a tuple with the WebauthnRegisterDisplayname field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) GetWebauthnRegisterDisplaynameOk() (*string, bool) { - if o == nil || o.WebauthnRegisterDisplayname == nil { - return nil, false - } - return o.WebauthnRegisterDisplayname, true -} - -// HasWebauthnRegisterDisplayname returns a boolean if a field has been set. -func (o *SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) HasWebauthnRegisterDisplayname() bool { - if o != nil && o.WebauthnRegisterDisplayname != nil { - return true - } - - return false -} - -// SetWebauthnRegisterDisplayname gets a reference to the given string and assigns it to the WebauthnRegisterDisplayname field. -func (o *SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) SetWebauthnRegisterDisplayname(v string) { - o.WebauthnRegisterDisplayname = &v -} - -func (o SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.CsrfToken != nil { - toSerialize["csrf_token"] = o.CsrfToken - } - if true { - toSerialize["method"] = o.Method - } - if true { - toSerialize["traits"] = o.Traits - } - if o.WebauthnRegister != nil { - toSerialize["webauthn_register"] = o.WebauthnRegister - } - if o.WebauthnRegisterDisplayname != nil { - toSerialize["webauthn_register_displayname"] = o.WebauthnRegisterDisplayname - } - return json.Marshal(toSerialize) -} - -type NullableSubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody struct { - value *SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody - isSet bool -} - -func (v NullableSubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) Get() *SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody { - return v.value -} - -func (v *NullableSubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) Set(val *SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) { - v.value = val - v.isSet = true -} - -func (v NullableSubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) IsSet() bool { - return v.isSet -} - -func (v *NullableSubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody(val *SubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) *NullableSubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody { - return &NullableSubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody{value: val, isSet: true} -} - -func (v NullableSubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSubmitSelfServiceRegistrationFlowWithWebAuthnMethodBody) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_submit_self_service_settings_flow_body.go b/internal/client-go/model_submit_self_service_settings_flow_body.go deleted file mode 100644 index 73f1e7868aab..000000000000 --- a/internal/client-go/model_submit_self_service_settings_flow_body.go +++ /dev/null @@ -1,269 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" - "fmt" -) - -// SubmitSelfServiceSettingsFlowBody - struct for SubmitSelfServiceSettingsFlowBody -type SubmitSelfServiceSettingsFlowBody struct { - SubmitSelfServiceSettingsFlowWithLookupMethodBody *SubmitSelfServiceSettingsFlowWithLookupMethodBody - SubmitSelfServiceSettingsFlowWithOidcMethodBody *SubmitSelfServiceSettingsFlowWithOidcMethodBody - SubmitSelfServiceSettingsFlowWithPasswordMethodBody *SubmitSelfServiceSettingsFlowWithPasswordMethodBody - SubmitSelfServiceSettingsFlowWithProfileMethodBody *SubmitSelfServiceSettingsFlowWithProfileMethodBody - SubmitSelfServiceSettingsFlowWithTotpMethodBody *SubmitSelfServiceSettingsFlowWithTotpMethodBody - SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody *SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody -} - -// SubmitSelfServiceSettingsFlowWithLookupMethodBodyAsSubmitSelfServiceSettingsFlowBody is a convenience function that returns SubmitSelfServiceSettingsFlowWithLookupMethodBody wrapped in SubmitSelfServiceSettingsFlowBody -func SubmitSelfServiceSettingsFlowWithLookupMethodBodyAsSubmitSelfServiceSettingsFlowBody(v *SubmitSelfServiceSettingsFlowWithLookupMethodBody) SubmitSelfServiceSettingsFlowBody { - return SubmitSelfServiceSettingsFlowBody{ - SubmitSelfServiceSettingsFlowWithLookupMethodBody: v, - } -} - -// SubmitSelfServiceSettingsFlowWithOidcMethodBodyAsSubmitSelfServiceSettingsFlowBody is a convenience function that returns SubmitSelfServiceSettingsFlowWithOidcMethodBody wrapped in SubmitSelfServiceSettingsFlowBody -func SubmitSelfServiceSettingsFlowWithOidcMethodBodyAsSubmitSelfServiceSettingsFlowBody(v *SubmitSelfServiceSettingsFlowWithOidcMethodBody) SubmitSelfServiceSettingsFlowBody { - return SubmitSelfServiceSettingsFlowBody{ - SubmitSelfServiceSettingsFlowWithOidcMethodBody: v, - } -} - -// SubmitSelfServiceSettingsFlowWithPasswordMethodBodyAsSubmitSelfServiceSettingsFlowBody is a convenience function that returns SubmitSelfServiceSettingsFlowWithPasswordMethodBody wrapped in SubmitSelfServiceSettingsFlowBody -func SubmitSelfServiceSettingsFlowWithPasswordMethodBodyAsSubmitSelfServiceSettingsFlowBody(v *SubmitSelfServiceSettingsFlowWithPasswordMethodBody) SubmitSelfServiceSettingsFlowBody { - return SubmitSelfServiceSettingsFlowBody{ - SubmitSelfServiceSettingsFlowWithPasswordMethodBody: v, - } -} - -// SubmitSelfServiceSettingsFlowWithProfileMethodBodyAsSubmitSelfServiceSettingsFlowBody is a convenience function that returns SubmitSelfServiceSettingsFlowWithProfileMethodBody wrapped in SubmitSelfServiceSettingsFlowBody -func SubmitSelfServiceSettingsFlowWithProfileMethodBodyAsSubmitSelfServiceSettingsFlowBody(v *SubmitSelfServiceSettingsFlowWithProfileMethodBody) SubmitSelfServiceSettingsFlowBody { - return SubmitSelfServiceSettingsFlowBody{ - SubmitSelfServiceSettingsFlowWithProfileMethodBody: v, - } -} - -// SubmitSelfServiceSettingsFlowWithTotpMethodBodyAsSubmitSelfServiceSettingsFlowBody is a convenience function that returns SubmitSelfServiceSettingsFlowWithTotpMethodBody wrapped in SubmitSelfServiceSettingsFlowBody -func SubmitSelfServiceSettingsFlowWithTotpMethodBodyAsSubmitSelfServiceSettingsFlowBody(v *SubmitSelfServiceSettingsFlowWithTotpMethodBody) SubmitSelfServiceSettingsFlowBody { - return SubmitSelfServiceSettingsFlowBody{ - SubmitSelfServiceSettingsFlowWithTotpMethodBody: v, - } -} - -// SubmitSelfServiceSettingsFlowWithWebAuthnMethodBodyAsSubmitSelfServiceSettingsFlowBody is a convenience function that returns SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody wrapped in SubmitSelfServiceSettingsFlowBody -func SubmitSelfServiceSettingsFlowWithWebAuthnMethodBodyAsSubmitSelfServiceSettingsFlowBody(v *SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) SubmitSelfServiceSettingsFlowBody { - return SubmitSelfServiceSettingsFlowBody{ - SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody: v, - } -} - -// Unmarshal JSON data into one of the pointers in the struct -func (dst *SubmitSelfServiceSettingsFlowBody) UnmarshalJSON(data []byte) error { - var err error - match := 0 - // try to unmarshal data into SubmitSelfServiceSettingsFlowWithLookupMethodBody - err = newStrictDecoder(data).Decode(&dst.SubmitSelfServiceSettingsFlowWithLookupMethodBody) - if err == nil { - jsonSubmitSelfServiceSettingsFlowWithLookupMethodBody, _ := json.Marshal(dst.SubmitSelfServiceSettingsFlowWithLookupMethodBody) - if string(jsonSubmitSelfServiceSettingsFlowWithLookupMethodBody) == "{}" { // empty struct - dst.SubmitSelfServiceSettingsFlowWithLookupMethodBody = nil - } else { - match++ - } - } else { - dst.SubmitSelfServiceSettingsFlowWithLookupMethodBody = nil - } - - // try to unmarshal data into SubmitSelfServiceSettingsFlowWithOidcMethodBody - err = newStrictDecoder(data).Decode(&dst.SubmitSelfServiceSettingsFlowWithOidcMethodBody) - if err == nil { - jsonSubmitSelfServiceSettingsFlowWithOidcMethodBody, _ := json.Marshal(dst.SubmitSelfServiceSettingsFlowWithOidcMethodBody) - if string(jsonSubmitSelfServiceSettingsFlowWithOidcMethodBody) == "{}" { // empty struct - dst.SubmitSelfServiceSettingsFlowWithOidcMethodBody = nil - } else { - match++ - } - } else { - dst.SubmitSelfServiceSettingsFlowWithOidcMethodBody = nil - } - - // try to unmarshal data into SubmitSelfServiceSettingsFlowWithPasswordMethodBody - err = newStrictDecoder(data).Decode(&dst.SubmitSelfServiceSettingsFlowWithPasswordMethodBody) - if err == nil { - jsonSubmitSelfServiceSettingsFlowWithPasswordMethodBody, _ := json.Marshal(dst.SubmitSelfServiceSettingsFlowWithPasswordMethodBody) - if string(jsonSubmitSelfServiceSettingsFlowWithPasswordMethodBody) == "{}" { // empty struct - dst.SubmitSelfServiceSettingsFlowWithPasswordMethodBody = nil - } else { - match++ - } - } else { - dst.SubmitSelfServiceSettingsFlowWithPasswordMethodBody = nil - } - - // try to unmarshal data into SubmitSelfServiceSettingsFlowWithProfileMethodBody - err = newStrictDecoder(data).Decode(&dst.SubmitSelfServiceSettingsFlowWithProfileMethodBody) - if err == nil { - jsonSubmitSelfServiceSettingsFlowWithProfileMethodBody, _ := json.Marshal(dst.SubmitSelfServiceSettingsFlowWithProfileMethodBody) - if string(jsonSubmitSelfServiceSettingsFlowWithProfileMethodBody) == "{}" { // empty struct - dst.SubmitSelfServiceSettingsFlowWithProfileMethodBody = nil - } else { - match++ - } - } else { - dst.SubmitSelfServiceSettingsFlowWithProfileMethodBody = nil - } - - // try to unmarshal data into SubmitSelfServiceSettingsFlowWithTotpMethodBody - err = newStrictDecoder(data).Decode(&dst.SubmitSelfServiceSettingsFlowWithTotpMethodBody) - if err == nil { - jsonSubmitSelfServiceSettingsFlowWithTotpMethodBody, _ := json.Marshal(dst.SubmitSelfServiceSettingsFlowWithTotpMethodBody) - if string(jsonSubmitSelfServiceSettingsFlowWithTotpMethodBody) == "{}" { // empty struct - dst.SubmitSelfServiceSettingsFlowWithTotpMethodBody = nil - } else { - match++ - } - } else { - dst.SubmitSelfServiceSettingsFlowWithTotpMethodBody = nil - } - - // try to unmarshal data into SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody - err = newStrictDecoder(data).Decode(&dst.SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) - if err == nil { - jsonSubmitSelfServiceSettingsFlowWithWebAuthnMethodBody, _ := json.Marshal(dst.SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) - if string(jsonSubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) == "{}" { // empty struct - dst.SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody = nil - } else { - match++ - } - } else { - dst.SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody = nil - } - - if match > 1 { // more than 1 match - // reset to nil - dst.SubmitSelfServiceSettingsFlowWithLookupMethodBody = nil - dst.SubmitSelfServiceSettingsFlowWithOidcMethodBody = nil - dst.SubmitSelfServiceSettingsFlowWithPasswordMethodBody = nil - dst.SubmitSelfServiceSettingsFlowWithProfileMethodBody = nil - dst.SubmitSelfServiceSettingsFlowWithTotpMethodBody = nil - dst.SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody = nil - - return fmt.Errorf("Data matches more than one schema in oneOf(SubmitSelfServiceSettingsFlowBody)") - } else if match == 1 { - return nil // exactly one match - } else { // no match - return fmt.Errorf("Data failed to match schemas in oneOf(SubmitSelfServiceSettingsFlowBody)") - } -} - -// Marshal data from the first non-nil pointers in the struct to JSON -func (src SubmitSelfServiceSettingsFlowBody) MarshalJSON() ([]byte, error) { - if src.SubmitSelfServiceSettingsFlowWithLookupMethodBody != nil { - return json.Marshal(&src.SubmitSelfServiceSettingsFlowWithLookupMethodBody) - } - - if src.SubmitSelfServiceSettingsFlowWithOidcMethodBody != nil { - return json.Marshal(&src.SubmitSelfServiceSettingsFlowWithOidcMethodBody) - } - - if src.SubmitSelfServiceSettingsFlowWithPasswordMethodBody != nil { - return json.Marshal(&src.SubmitSelfServiceSettingsFlowWithPasswordMethodBody) - } - - if src.SubmitSelfServiceSettingsFlowWithProfileMethodBody != nil { - return json.Marshal(&src.SubmitSelfServiceSettingsFlowWithProfileMethodBody) - } - - if src.SubmitSelfServiceSettingsFlowWithTotpMethodBody != nil { - return json.Marshal(&src.SubmitSelfServiceSettingsFlowWithTotpMethodBody) - } - - if src.SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody != nil { - return json.Marshal(&src.SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) - } - - return nil, nil // no data in oneOf schemas -} - -// Get the actual instance -func (obj *SubmitSelfServiceSettingsFlowBody) GetActualInstance() interface{} { - if obj == nil { - return nil - } - if obj.SubmitSelfServiceSettingsFlowWithLookupMethodBody != nil { - return obj.SubmitSelfServiceSettingsFlowWithLookupMethodBody - } - - if obj.SubmitSelfServiceSettingsFlowWithOidcMethodBody != nil { - return obj.SubmitSelfServiceSettingsFlowWithOidcMethodBody - } - - if obj.SubmitSelfServiceSettingsFlowWithPasswordMethodBody != nil { - return obj.SubmitSelfServiceSettingsFlowWithPasswordMethodBody - } - - if obj.SubmitSelfServiceSettingsFlowWithProfileMethodBody != nil { - return obj.SubmitSelfServiceSettingsFlowWithProfileMethodBody - } - - if obj.SubmitSelfServiceSettingsFlowWithTotpMethodBody != nil { - return obj.SubmitSelfServiceSettingsFlowWithTotpMethodBody - } - - if obj.SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody != nil { - return obj.SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody - } - - // all schemas are nil - return nil -} - -type NullableSubmitSelfServiceSettingsFlowBody struct { - value *SubmitSelfServiceSettingsFlowBody - isSet bool -} - -func (v NullableSubmitSelfServiceSettingsFlowBody) Get() *SubmitSelfServiceSettingsFlowBody { - return v.value -} - -func (v *NullableSubmitSelfServiceSettingsFlowBody) Set(val *SubmitSelfServiceSettingsFlowBody) { - v.value = val - v.isSet = true -} - -func (v NullableSubmitSelfServiceSettingsFlowBody) IsSet() bool { - return v.isSet -} - -func (v *NullableSubmitSelfServiceSettingsFlowBody) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSubmitSelfServiceSettingsFlowBody(val *SubmitSelfServiceSettingsFlowBody) *NullableSubmitSelfServiceSettingsFlowBody { - return &NullableSubmitSelfServiceSettingsFlowBody{value: val, isSet: true} -} - -func (v NullableSubmitSelfServiceSettingsFlowBody) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSubmitSelfServiceSettingsFlowBody) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_submit_self_service_settings_flow_with_lookup_method_body.go b/internal/client-go/model_submit_self_service_settings_flow_with_lookup_method_body.go deleted file mode 100644 index d225d0744515..000000000000 --- a/internal/client-go/model_submit_self_service_settings_flow_with_lookup_method_body.go +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// SubmitSelfServiceSettingsFlowWithLookupMethodBody struct for SubmitSelfServiceSettingsFlowWithLookupMethodBody -type SubmitSelfServiceSettingsFlowWithLookupMethodBody struct { - // CSRFToken is the anti-CSRF token - CsrfToken *string `json:"csrf_token,omitempty"` - // If set to true will save the regenerated lookup secrets - LookupSecretConfirm *bool `json:"lookup_secret_confirm,omitempty"` - // Disables this method if true. - LookupSecretDisable *bool `json:"lookup_secret_disable,omitempty"` - // If set to true will regenerate the lookup secrets - LookupSecretRegenerate *bool `json:"lookup_secret_regenerate,omitempty"` - // If set to true will reveal the lookup secrets - LookupSecretReveal *bool `json:"lookup_secret_reveal,omitempty"` - // Method Should be set to \"lookup\" when trying to add, update, or remove a lookup pairing. - Method string `json:"method"` -} - -// NewSubmitSelfServiceSettingsFlowWithLookupMethodBody instantiates a new SubmitSelfServiceSettingsFlowWithLookupMethodBody 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 NewSubmitSelfServiceSettingsFlowWithLookupMethodBody(method string) *SubmitSelfServiceSettingsFlowWithLookupMethodBody { - this := SubmitSelfServiceSettingsFlowWithLookupMethodBody{} - this.Method = method - return &this -} - -// NewSubmitSelfServiceSettingsFlowWithLookupMethodBodyWithDefaults instantiates a new SubmitSelfServiceSettingsFlowWithLookupMethodBody 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 NewSubmitSelfServiceSettingsFlowWithLookupMethodBodyWithDefaults() *SubmitSelfServiceSettingsFlowWithLookupMethodBody { - this := SubmitSelfServiceSettingsFlowWithLookupMethodBody{} - return &this -} - -// GetCsrfToken returns the CsrfToken field value if set, zero value otherwise. -func (o *SubmitSelfServiceSettingsFlowWithLookupMethodBody) GetCsrfToken() string { - if o == nil || o.CsrfToken == nil { - var ret string - return ret - } - return *o.CsrfToken -} - -// GetCsrfTokenOk returns a tuple with the CsrfToken field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceSettingsFlowWithLookupMethodBody) GetCsrfTokenOk() (*string, bool) { - if o == nil || o.CsrfToken == nil { - return nil, false - } - return o.CsrfToken, true -} - -// HasCsrfToken returns a boolean if a field has been set. -func (o *SubmitSelfServiceSettingsFlowWithLookupMethodBody) HasCsrfToken() bool { - if o != nil && o.CsrfToken != nil { - return true - } - - return false -} - -// SetCsrfToken gets a reference to the given string and assigns it to the CsrfToken field. -func (o *SubmitSelfServiceSettingsFlowWithLookupMethodBody) SetCsrfToken(v string) { - o.CsrfToken = &v -} - -// GetLookupSecretConfirm returns the LookupSecretConfirm field value if set, zero value otherwise. -func (o *SubmitSelfServiceSettingsFlowWithLookupMethodBody) GetLookupSecretConfirm() bool { - if o == nil || o.LookupSecretConfirm == nil { - var ret bool - return ret - } - return *o.LookupSecretConfirm -} - -// GetLookupSecretConfirmOk returns a tuple with the LookupSecretConfirm field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceSettingsFlowWithLookupMethodBody) GetLookupSecretConfirmOk() (*bool, bool) { - if o == nil || o.LookupSecretConfirm == nil { - return nil, false - } - return o.LookupSecretConfirm, true -} - -// HasLookupSecretConfirm returns a boolean if a field has been set. -func (o *SubmitSelfServiceSettingsFlowWithLookupMethodBody) HasLookupSecretConfirm() bool { - if o != nil && o.LookupSecretConfirm != nil { - return true - } - - return false -} - -// SetLookupSecretConfirm gets a reference to the given bool and assigns it to the LookupSecretConfirm field. -func (o *SubmitSelfServiceSettingsFlowWithLookupMethodBody) SetLookupSecretConfirm(v bool) { - o.LookupSecretConfirm = &v -} - -// GetLookupSecretDisable returns the LookupSecretDisable field value if set, zero value otherwise. -func (o *SubmitSelfServiceSettingsFlowWithLookupMethodBody) GetLookupSecretDisable() bool { - if o == nil || o.LookupSecretDisable == nil { - var ret bool - return ret - } - return *o.LookupSecretDisable -} - -// GetLookupSecretDisableOk returns a tuple with the LookupSecretDisable field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceSettingsFlowWithLookupMethodBody) GetLookupSecretDisableOk() (*bool, bool) { - if o == nil || o.LookupSecretDisable == nil { - return nil, false - } - return o.LookupSecretDisable, true -} - -// HasLookupSecretDisable returns a boolean if a field has been set. -func (o *SubmitSelfServiceSettingsFlowWithLookupMethodBody) HasLookupSecretDisable() bool { - if o != nil && o.LookupSecretDisable != nil { - return true - } - - return false -} - -// SetLookupSecretDisable gets a reference to the given bool and assigns it to the LookupSecretDisable field. -func (o *SubmitSelfServiceSettingsFlowWithLookupMethodBody) SetLookupSecretDisable(v bool) { - o.LookupSecretDisable = &v -} - -// GetLookupSecretRegenerate returns the LookupSecretRegenerate field value if set, zero value otherwise. -func (o *SubmitSelfServiceSettingsFlowWithLookupMethodBody) GetLookupSecretRegenerate() bool { - if o == nil || o.LookupSecretRegenerate == nil { - var ret bool - return ret - } - return *o.LookupSecretRegenerate -} - -// GetLookupSecretRegenerateOk returns a tuple with the LookupSecretRegenerate field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceSettingsFlowWithLookupMethodBody) GetLookupSecretRegenerateOk() (*bool, bool) { - if o == nil || o.LookupSecretRegenerate == nil { - return nil, false - } - return o.LookupSecretRegenerate, true -} - -// HasLookupSecretRegenerate returns a boolean if a field has been set. -func (o *SubmitSelfServiceSettingsFlowWithLookupMethodBody) HasLookupSecretRegenerate() bool { - if o != nil && o.LookupSecretRegenerate != nil { - return true - } - - return false -} - -// SetLookupSecretRegenerate gets a reference to the given bool and assigns it to the LookupSecretRegenerate field. -func (o *SubmitSelfServiceSettingsFlowWithLookupMethodBody) SetLookupSecretRegenerate(v bool) { - o.LookupSecretRegenerate = &v -} - -// GetLookupSecretReveal returns the LookupSecretReveal field value if set, zero value otherwise. -func (o *SubmitSelfServiceSettingsFlowWithLookupMethodBody) GetLookupSecretReveal() bool { - if o == nil || o.LookupSecretReveal == nil { - var ret bool - return ret - } - return *o.LookupSecretReveal -} - -// GetLookupSecretRevealOk returns a tuple with the LookupSecretReveal field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceSettingsFlowWithLookupMethodBody) GetLookupSecretRevealOk() (*bool, bool) { - if o == nil || o.LookupSecretReveal == nil { - return nil, false - } - return o.LookupSecretReveal, true -} - -// HasLookupSecretReveal returns a boolean if a field has been set. -func (o *SubmitSelfServiceSettingsFlowWithLookupMethodBody) HasLookupSecretReveal() bool { - if o != nil && o.LookupSecretReveal != nil { - return true - } - - return false -} - -// SetLookupSecretReveal gets a reference to the given bool and assigns it to the LookupSecretReveal field. -func (o *SubmitSelfServiceSettingsFlowWithLookupMethodBody) SetLookupSecretReveal(v bool) { - o.LookupSecretReveal = &v -} - -// GetMethod returns the Method field value -func (o *SubmitSelfServiceSettingsFlowWithLookupMethodBody) GetMethod() string { - if o == nil { - var ret string - return ret - } - - return o.Method -} - -// GetMethodOk returns a tuple with the Method field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceSettingsFlowWithLookupMethodBody) GetMethodOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Method, true -} - -// SetMethod sets field value -func (o *SubmitSelfServiceSettingsFlowWithLookupMethodBody) SetMethod(v string) { - o.Method = v -} - -func (o SubmitSelfServiceSettingsFlowWithLookupMethodBody) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.CsrfToken != nil { - toSerialize["csrf_token"] = o.CsrfToken - } - if o.LookupSecretConfirm != nil { - toSerialize["lookup_secret_confirm"] = o.LookupSecretConfirm - } - if o.LookupSecretDisable != nil { - toSerialize["lookup_secret_disable"] = o.LookupSecretDisable - } - if o.LookupSecretRegenerate != nil { - toSerialize["lookup_secret_regenerate"] = o.LookupSecretRegenerate - } - if o.LookupSecretReveal != nil { - toSerialize["lookup_secret_reveal"] = o.LookupSecretReveal - } - if true { - toSerialize["method"] = o.Method - } - return json.Marshal(toSerialize) -} - -type NullableSubmitSelfServiceSettingsFlowWithLookupMethodBody struct { - value *SubmitSelfServiceSettingsFlowWithLookupMethodBody - isSet bool -} - -func (v NullableSubmitSelfServiceSettingsFlowWithLookupMethodBody) Get() *SubmitSelfServiceSettingsFlowWithLookupMethodBody { - return v.value -} - -func (v *NullableSubmitSelfServiceSettingsFlowWithLookupMethodBody) Set(val *SubmitSelfServiceSettingsFlowWithLookupMethodBody) { - v.value = val - v.isSet = true -} - -func (v NullableSubmitSelfServiceSettingsFlowWithLookupMethodBody) IsSet() bool { - return v.isSet -} - -func (v *NullableSubmitSelfServiceSettingsFlowWithLookupMethodBody) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSubmitSelfServiceSettingsFlowWithLookupMethodBody(val *SubmitSelfServiceSettingsFlowWithLookupMethodBody) *NullableSubmitSelfServiceSettingsFlowWithLookupMethodBody { - return &NullableSubmitSelfServiceSettingsFlowWithLookupMethodBody{value: val, isSet: true} -} - -func (v NullableSubmitSelfServiceSettingsFlowWithLookupMethodBody) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSubmitSelfServiceSettingsFlowWithLookupMethodBody) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_submit_self_service_settings_flow_with_oidc_method_body.go b/internal/client-go/model_submit_self_service_settings_flow_with_oidc_method_body.go deleted file mode 100644 index ed4279e67e48..000000000000 --- a/internal/client-go/model_submit_self_service_settings_flow_with_oidc_method_body.go +++ /dev/null @@ -1,259 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// SubmitSelfServiceSettingsFlowWithOidcMethodBody nolint:deadcode,unused -type SubmitSelfServiceSettingsFlowWithOidcMethodBody struct { - // Flow ID is the flow's ID. in: query - Flow *string `json:"flow,omitempty"` - // Link this provider Either this or `unlink` must be set. type: string in: body - Link *string `json:"link,omitempty"` - // Method Should be set to profile when trying to update a profile. - Method string `json:"method"` - // The identity's traits in: body - Traits map[string]interface{} `json:"traits,omitempty"` - // Unlink this provider Either this or `link` must be set. type: string in: body - Unlink *string `json:"unlink,omitempty"` -} - -// NewSubmitSelfServiceSettingsFlowWithOidcMethodBody instantiates a new SubmitSelfServiceSettingsFlowWithOidcMethodBody 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 NewSubmitSelfServiceSettingsFlowWithOidcMethodBody(method string) *SubmitSelfServiceSettingsFlowWithOidcMethodBody { - this := SubmitSelfServiceSettingsFlowWithOidcMethodBody{} - this.Method = method - return &this -} - -// NewSubmitSelfServiceSettingsFlowWithOidcMethodBodyWithDefaults instantiates a new SubmitSelfServiceSettingsFlowWithOidcMethodBody 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 NewSubmitSelfServiceSettingsFlowWithOidcMethodBodyWithDefaults() *SubmitSelfServiceSettingsFlowWithOidcMethodBody { - this := SubmitSelfServiceSettingsFlowWithOidcMethodBody{} - return &this -} - -// GetFlow returns the Flow field value if set, zero value otherwise. -func (o *SubmitSelfServiceSettingsFlowWithOidcMethodBody) GetFlow() string { - if o == nil || o.Flow == nil { - var ret string - return ret - } - return *o.Flow -} - -// GetFlowOk returns a tuple with the Flow field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceSettingsFlowWithOidcMethodBody) GetFlowOk() (*string, bool) { - if o == nil || o.Flow == nil { - return nil, false - } - return o.Flow, true -} - -// HasFlow returns a boolean if a field has been set. -func (o *SubmitSelfServiceSettingsFlowWithOidcMethodBody) HasFlow() bool { - if o != nil && o.Flow != nil { - return true - } - - return false -} - -// SetFlow gets a reference to the given string and assigns it to the Flow field. -func (o *SubmitSelfServiceSettingsFlowWithOidcMethodBody) SetFlow(v string) { - o.Flow = &v -} - -// GetLink returns the Link field value if set, zero value otherwise. -func (o *SubmitSelfServiceSettingsFlowWithOidcMethodBody) GetLink() string { - if o == nil || o.Link == nil { - var ret string - return ret - } - return *o.Link -} - -// GetLinkOk returns a tuple with the Link field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceSettingsFlowWithOidcMethodBody) GetLinkOk() (*string, bool) { - if o == nil || o.Link == nil { - return nil, false - } - return o.Link, true -} - -// HasLink returns a boolean if a field has been set. -func (o *SubmitSelfServiceSettingsFlowWithOidcMethodBody) HasLink() bool { - if o != nil && o.Link != nil { - return true - } - - return false -} - -// SetLink gets a reference to the given string and assigns it to the Link field. -func (o *SubmitSelfServiceSettingsFlowWithOidcMethodBody) SetLink(v string) { - o.Link = &v -} - -// GetMethod returns the Method field value -func (o *SubmitSelfServiceSettingsFlowWithOidcMethodBody) GetMethod() string { - if o == nil { - var ret string - return ret - } - - return o.Method -} - -// GetMethodOk returns a tuple with the Method field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceSettingsFlowWithOidcMethodBody) GetMethodOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Method, true -} - -// SetMethod sets field value -func (o *SubmitSelfServiceSettingsFlowWithOidcMethodBody) SetMethod(v string) { - o.Method = v -} - -// GetTraits returns the Traits field value if set, zero value otherwise. -func (o *SubmitSelfServiceSettingsFlowWithOidcMethodBody) GetTraits() map[string]interface{} { - if o == nil || o.Traits == nil { - var ret map[string]interface{} - return ret - } - return o.Traits -} - -// GetTraitsOk returns a tuple with the Traits field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceSettingsFlowWithOidcMethodBody) GetTraitsOk() (map[string]interface{}, bool) { - if o == nil || o.Traits == nil { - return nil, false - } - return o.Traits, true -} - -// HasTraits returns a boolean if a field has been set. -func (o *SubmitSelfServiceSettingsFlowWithOidcMethodBody) HasTraits() bool { - if o != nil && o.Traits != nil { - return true - } - - return false -} - -// SetTraits gets a reference to the given map[string]interface{} and assigns it to the Traits field. -func (o *SubmitSelfServiceSettingsFlowWithOidcMethodBody) SetTraits(v map[string]interface{}) { - o.Traits = v -} - -// GetUnlink returns the Unlink field value if set, zero value otherwise. -func (o *SubmitSelfServiceSettingsFlowWithOidcMethodBody) GetUnlink() string { - if o == nil || o.Unlink == nil { - var ret string - return ret - } - return *o.Unlink -} - -// GetUnlinkOk returns a tuple with the Unlink field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceSettingsFlowWithOidcMethodBody) GetUnlinkOk() (*string, bool) { - if o == nil || o.Unlink == nil { - return nil, false - } - return o.Unlink, true -} - -// HasUnlink returns a boolean if a field has been set. -func (o *SubmitSelfServiceSettingsFlowWithOidcMethodBody) HasUnlink() bool { - if o != nil && o.Unlink != nil { - return true - } - - return false -} - -// SetUnlink gets a reference to the given string and assigns it to the Unlink field. -func (o *SubmitSelfServiceSettingsFlowWithOidcMethodBody) SetUnlink(v string) { - o.Unlink = &v -} - -func (o SubmitSelfServiceSettingsFlowWithOidcMethodBody) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.Flow != nil { - toSerialize["flow"] = o.Flow - } - if o.Link != nil { - toSerialize["link"] = o.Link - } - if true { - toSerialize["method"] = o.Method - } - if o.Traits != nil { - toSerialize["traits"] = o.Traits - } - if o.Unlink != nil { - toSerialize["unlink"] = o.Unlink - } - return json.Marshal(toSerialize) -} - -type NullableSubmitSelfServiceSettingsFlowWithOidcMethodBody struct { - value *SubmitSelfServiceSettingsFlowWithOidcMethodBody - isSet bool -} - -func (v NullableSubmitSelfServiceSettingsFlowWithOidcMethodBody) Get() *SubmitSelfServiceSettingsFlowWithOidcMethodBody { - return v.value -} - -func (v *NullableSubmitSelfServiceSettingsFlowWithOidcMethodBody) Set(val *SubmitSelfServiceSettingsFlowWithOidcMethodBody) { - v.value = val - v.isSet = true -} - -func (v NullableSubmitSelfServiceSettingsFlowWithOidcMethodBody) IsSet() bool { - return v.isSet -} - -func (v *NullableSubmitSelfServiceSettingsFlowWithOidcMethodBody) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSubmitSelfServiceSettingsFlowWithOidcMethodBody(val *SubmitSelfServiceSettingsFlowWithOidcMethodBody) *NullableSubmitSelfServiceSettingsFlowWithOidcMethodBody { - return &NullableSubmitSelfServiceSettingsFlowWithOidcMethodBody{value: val, isSet: true} -} - -func (v NullableSubmitSelfServiceSettingsFlowWithOidcMethodBody) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSubmitSelfServiceSettingsFlowWithOidcMethodBody) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_submit_self_service_settings_flow_with_password_method_body.go b/internal/client-go/model_submit_self_service_settings_flow_with_password_method_body.go deleted file mode 100644 index d244f5155361..000000000000 --- a/internal/client-go/model_submit_self_service_settings_flow_with_password_method_body.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// SubmitSelfServiceSettingsFlowWithPasswordMethodBody struct for SubmitSelfServiceSettingsFlowWithPasswordMethodBody -type SubmitSelfServiceSettingsFlowWithPasswordMethodBody struct { - // CSRFToken is the anti-CSRF token - CsrfToken *string `json:"csrf_token,omitempty"` - // Method Should be set to password when trying to update a password. - Method string `json:"method"` - // Password is the updated password - Password string `json:"password"` -} - -// NewSubmitSelfServiceSettingsFlowWithPasswordMethodBody instantiates a new SubmitSelfServiceSettingsFlowWithPasswordMethodBody 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 NewSubmitSelfServiceSettingsFlowWithPasswordMethodBody(method string, password string) *SubmitSelfServiceSettingsFlowWithPasswordMethodBody { - this := SubmitSelfServiceSettingsFlowWithPasswordMethodBody{} - this.Method = method - this.Password = password - return &this -} - -// NewSubmitSelfServiceSettingsFlowWithPasswordMethodBodyWithDefaults instantiates a new SubmitSelfServiceSettingsFlowWithPasswordMethodBody 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 NewSubmitSelfServiceSettingsFlowWithPasswordMethodBodyWithDefaults() *SubmitSelfServiceSettingsFlowWithPasswordMethodBody { - this := SubmitSelfServiceSettingsFlowWithPasswordMethodBody{} - return &this -} - -// GetCsrfToken returns the CsrfToken field value if set, zero value otherwise. -func (o *SubmitSelfServiceSettingsFlowWithPasswordMethodBody) GetCsrfToken() string { - if o == nil || o.CsrfToken == nil { - var ret string - return ret - } - return *o.CsrfToken -} - -// GetCsrfTokenOk returns a tuple with the CsrfToken field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceSettingsFlowWithPasswordMethodBody) GetCsrfTokenOk() (*string, bool) { - if o == nil || o.CsrfToken == nil { - return nil, false - } - return o.CsrfToken, true -} - -// HasCsrfToken returns a boolean if a field has been set. -func (o *SubmitSelfServiceSettingsFlowWithPasswordMethodBody) HasCsrfToken() bool { - if o != nil && o.CsrfToken != nil { - return true - } - - return false -} - -// SetCsrfToken gets a reference to the given string and assigns it to the CsrfToken field. -func (o *SubmitSelfServiceSettingsFlowWithPasswordMethodBody) SetCsrfToken(v string) { - o.CsrfToken = &v -} - -// GetMethod returns the Method field value -func (o *SubmitSelfServiceSettingsFlowWithPasswordMethodBody) GetMethod() string { - if o == nil { - var ret string - return ret - } - - return o.Method -} - -// GetMethodOk returns a tuple with the Method field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceSettingsFlowWithPasswordMethodBody) GetMethodOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Method, true -} - -// SetMethod sets field value -func (o *SubmitSelfServiceSettingsFlowWithPasswordMethodBody) SetMethod(v string) { - o.Method = v -} - -// GetPassword returns the Password field value -func (o *SubmitSelfServiceSettingsFlowWithPasswordMethodBody) GetPassword() string { - if o == nil { - var ret string - return ret - } - - return o.Password -} - -// GetPasswordOk returns a tuple with the Password field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceSettingsFlowWithPasswordMethodBody) GetPasswordOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Password, true -} - -// SetPassword sets field value -func (o *SubmitSelfServiceSettingsFlowWithPasswordMethodBody) SetPassword(v string) { - o.Password = v -} - -func (o SubmitSelfServiceSettingsFlowWithPasswordMethodBody) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.CsrfToken != nil { - toSerialize["csrf_token"] = o.CsrfToken - } - if true { - toSerialize["method"] = o.Method - } - if true { - toSerialize["password"] = o.Password - } - return json.Marshal(toSerialize) -} - -type NullableSubmitSelfServiceSettingsFlowWithPasswordMethodBody struct { - value *SubmitSelfServiceSettingsFlowWithPasswordMethodBody - isSet bool -} - -func (v NullableSubmitSelfServiceSettingsFlowWithPasswordMethodBody) Get() *SubmitSelfServiceSettingsFlowWithPasswordMethodBody { - return v.value -} - -func (v *NullableSubmitSelfServiceSettingsFlowWithPasswordMethodBody) Set(val *SubmitSelfServiceSettingsFlowWithPasswordMethodBody) { - v.value = val - v.isSet = true -} - -func (v NullableSubmitSelfServiceSettingsFlowWithPasswordMethodBody) IsSet() bool { - return v.isSet -} - -func (v *NullableSubmitSelfServiceSettingsFlowWithPasswordMethodBody) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSubmitSelfServiceSettingsFlowWithPasswordMethodBody(val *SubmitSelfServiceSettingsFlowWithPasswordMethodBody) *NullableSubmitSelfServiceSettingsFlowWithPasswordMethodBody { - return &NullableSubmitSelfServiceSettingsFlowWithPasswordMethodBody{value: val, isSet: true} -} - -func (v NullableSubmitSelfServiceSettingsFlowWithPasswordMethodBody) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSubmitSelfServiceSettingsFlowWithPasswordMethodBody) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_submit_self_service_settings_flow_with_profile_method_body.go b/internal/client-go/model_submit_self_service_settings_flow_with_profile_method_body.go deleted file mode 100644 index 277cf241f386..000000000000 --- a/internal/client-go/model_submit_self_service_settings_flow_with_profile_method_body.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// SubmitSelfServiceSettingsFlowWithProfileMethodBody nolint:deadcode,unused -type SubmitSelfServiceSettingsFlowWithProfileMethodBody struct { - // The Anti-CSRF Token This token is only required when performing browser flows. - CsrfToken *string `json:"csrf_token,omitempty"` - // Method Should be set to profile when trying to update a profile. - Method string `json:"method"` - // Traits contains all of the identity's traits. - Traits map[string]interface{} `json:"traits"` -} - -// NewSubmitSelfServiceSettingsFlowWithProfileMethodBody instantiates a new SubmitSelfServiceSettingsFlowWithProfileMethodBody 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 NewSubmitSelfServiceSettingsFlowWithProfileMethodBody(method string, traits map[string]interface{}) *SubmitSelfServiceSettingsFlowWithProfileMethodBody { - this := SubmitSelfServiceSettingsFlowWithProfileMethodBody{} - this.Method = method - this.Traits = traits - return &this -} - -// NewSubmitSelfServiceSettingsFlowWithProfileMethodBodyWithDefaults instantiates a new SubmitSelfServiceSettingsFlowWithProfileMethodBody 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 NewSubmitSelfServiceSettingsFlowWithProfileMethodBodyWithDefaults() *SubmitSelfServiceSettingsFlowWithProfileMethodBody { - this := SubmitSelfServiceSettingsFlowWithProfileMethodBody{} - return &this -} - -// GetCsrfToken returns the CsrfToken field value if set, zero value otherwise. -func (o *SubmitSelfServiceSettingsFlowWithProfileMethodBody) GetCsrfToken() string { - if o == nil || o.CsrfToken == nil { - var ret string - return ret - } - return *o.CsrfToken -} - -// GetCsrfTokenOk returns a tuple with the CsrfToken field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceSettingsFlowWithProfileMethodBody) GetCsrfTokenOk() (*string, bool) { - if o == nil || o.CsrfToken == nil { - return nil, false - } - return o.CsrfToken, true -} - -// HasCsrfToken returns a boolean if a field has been set. -func (o *SubmitSelfServiceSettingsFlowWithProfileMethodBody) HasCsrfToken() bool { - if o != nil && o.CsrfToken != nil { - return true - } - - return false -} - -// SetCsrfToken gets a reference to the given string and assigns it to the CsrfToken field. -func (o *SubmitSelfServiceSettingsFlowWithProfileMethodBody) SetCsrfToken(v string) { - o.CsrfToken = &v -} - -// GetMethod returns the Method field value -func (o *SubmitSelfServiceSettingsFlowWithProfileMethodBody) GetMethod() string { - if o == nil { - var ret string - return ret - } - - return o.Method -} - -// GetMethodOk returns a tuple with the Method field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceSettingsFlowWithProfileMethodBody) GetMethodOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Method, true -} - -// SetMethod sets field value -func (o *SubmitSelfServiceSettingsFlowWithProfileMethodBody) SetMethod(v string) { - o.Method = v -} - -// GetTraits returns the Traits field value -func (o *SubmitSelfServiceSettingsFlowWithProfileMethodBody) GetTraits() map[string]interface{} { - if o == nil { - var ret map[string]interface{} - return ret - } - - return o.Traits -} - -// GetTraitsOk returns a tuple with the Traits field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceSettingsFlowWithProfileMethodBody) GetTraitsOk() (map[string]interface{}, bool) { - if o == nil { - return nil, false - } - return o.Traits, true -} - -// SetTraits sets field value -func (o *SubmitSelfServiceSettingsFlowWithProfileMethodBody) SetTraits(v map[string]interface{}) { - o.Traits = v -} - -func (o SubmitSelfServiceSettingsFlowWithProfileMethodBody) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.CsrfToken != nil { - toSerialize["csrf_token"] = o.CsrfToken - } - if true { - toSerialize["method"] = o.Method - } - if true { - toSerialize["traits"] = o.Traits - } - return json.Marshal(toSerialize) -} - -type NullableSubmitSelfServiceSettingsFlowWithProfileMethodBody struct { - value *SubmitSelfServiceSettingsFlowWithProfileMethodBody - isSet bool -} - -func (v NullableSubmitSelfServiceSettingsFlowWithProfileMethodBody) Get() *SubmitSelfServiceSettingsFlowWithProfileMethodBody { - return v.value -} - -func (v *NullableSubmitSelfServiceSettingsFlowWithProfileMethodBody) Set(val *SubmitSelfServiceSettingsFlowWithProfileMethodBody) { - v.value = val - v.isSet = true -} - -func (v NullableSubmitSelfServiceSettingsFlowWithProfileMethodBody) IsSet() bool { - return v.isSet -} - -func (v *NullableSubmitSelfServiceSettingsFlowWithProfileMethodBody) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSubmitSelfServiceSettingsFlowWithProfileMethodBody(val *SubmitSelfServiceSettingsFlowWithProfileMethodBody) *NullableSubmitSelfServiceSettingsFlowWithProfileMethodBody { - return &NullableSubmitSelfServiceSettingsFlowWithProfileMethodBody{value: val, isSet: true} -} - -func (v NullableSubmitSelfServiceSettingsFlowWithProfileMethodBody) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSubmitSelfServiceSettingsFlowWithProfileMethodBody) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_submit_self_service_settings_flow_with_totp_method_body.go b/internal/client-go/model_submit_self_service_settings_flow_with_totp_method_body.go deleted file mode 100644 index cf63442ab0c0..000000000000 --- a/internal/client-go/model_submit_self_service_settings_flow_with_totp_method_body.go +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// SubmitSelfServiceSettingsFlowWithTotpMethodBody struct for SubmitSelfServiceSettingsFlowWithTotpMethodBody -type SubmitSelfServiceSettingsFlowWithTotpMethodBody struct { - // CSRFToken is the anti-CSRF token - CsrfToken *string `json:"csrf_token,omitempty"` - // Method Should be set to \"totp\" when trying to add, update, or remove a totp pairing. - Method string `json:"method"` - // ValidationTOTP must contain a valid TOTP based on the - TotpCode *string `json:"totp_code,omitempty"` - // UnlinkTOTP if true will remove the TOTP pairing, effectively removing the credential. This can be used to set up a new TOTP device. - TotpUnlink *bool `json:"totp_unlink,omitempty"` -} - -// NewSubmitSelfServiceSettingsFlowWithTotpMethodBody instantiates a new SubmitSelfServiceSettingsFlowWithTotpMethodBody 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 NewSubmitSelfServiceSettingsFlowWithTotpMethodBody(method string) *SubmitSelfServiceSettingsFlowWithTotpMethodBody { - this := SubmitSelfServiceSettingsFlowWithTotpMethodBody{} - this.Method = method - return &this -} - -// NewSubmitSelfServiceSettingsFlowWithTotpMethodBodyWithDefaults instantiates a new SubmitSelfServiceSettingsFlowWithTotpMethodBody 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 NewSubmitSelfServiceSettingsFlowWithTotpMethodBodyWithDefaults() *SubmitSelfServiceSettingsFlowWithTotpMethodBody { - this := SubmitSelfServiceSettingsFlowWithTotpMethodBody{} - return &this -} - -// GetCsrfToken returns the CsrfToken field value if set, zero value otherwise. -func (o *SubmitSelfServiceSettingsFlowWithTotpMethodBody) GetCsrfToken() string { - if o == nil || o.CsrfToken == nil { - var ret string - return ret - } - return *o.CsrfToken -} - -// GetCsrfTokenOk returns a tuple with the CsrfToken field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceSettingsFlowWithTotpMethodBody) GetCsrfTokenOk() (*string, bool) { - if o == nil || o.CsrfToken == nil { - return nil, false - } - return o.CsrfToken, true -} - -// HasCsrfToken returns a boolean if a field has been set. -func (o *SubmitSelfServiceSettingsFlowWithTotpMethodBody) HasCsrfToken() bool { - if o != nil && o.CsrfToken != nil { - return true - } - - return false -} - -// SetCsrfToken gets a reference to the given string and assigns it to the CsrfToken field. -func (o *SubmitSelfServiceSettingsFlowWithTotpMethodBody) SetCsrfToken(v string) { - o.CsrfToken = &v -} - -// GetMethod returns the Method field value -func (o *SubmitSelfServiceSettingsFlowWithTotpMethodBody) GetMethod() string { - if o == nil { - var ret string - return ret - } - - return o.Method -} - -// GetMethodOk returns a tuple with the Method field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceSettingsFlowWithTotpMethodBody) GetMethodOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Method, true -} - -// SetMethod sets field value -func (o *SubmitSelfServiceSettingsFlowWithTotpMethodBody) SetMethod(v string) { - o.Method = v -} - -// GetTotpCode returns the TotpCode field value if set, zero value otherwise. -func (o *SubmitSelfServiceSettingsFlowWithTotpMethodBody) GetTotpCode() string { - if o == nil || o.TotpCode == nil { - var ret string - return ret - } - return *o.TotpCode -} - -// GetTotpCodeOk returns a tuple with the TotpCode field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceSettingsFlowWithTotpMethodBody) GetTotpCodeOk() (*string, bool) { - if o == nil || o.TotpCode == nil { - return nil, false - } - return o.TotpCode, true -} - -// HasTotpCode returns a boolean if a field has been set. -func (o *SubmitSelfServiceSettingsFlowWithTotpMethodBody) HasTotpCode() bool { - if o != nil && o.TotpCode != nil { - return true - } - - return false -} - -// SetTotpCode gets a reference to the given string and assigns it to the TotpCode field. -func (o *SubmitSelfServiceSettingsFlowWithTotpMethodBody) SetTotpCode(v string) { - o.TotpCode = &v -} - -// GetTotpUnlink returns the TotpUnlink field value if set, zero value otherwise. -func (o *SubmitSelfServiceSettingsFlowWithTotpMethodBody) GetTotpUnlink() bool { - if o == nil || o.TotpUnlink == nil { - var ret bool - return ret - } - return *o.TotpUnlink -} - -// GetTotpUnlinkOk returns a tuple with the TotpUnlink field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceSettingsFlowWithTotpMethodBody) GetTotpUnlinkOk() (*bool, bool) { - if o == nil || o.TotpUnlink == nil { - return nil, false - } - return o.TotpUnlink, true -} - -// HasTotpUnlink returns a boolean if a field has been set. -func (o *SubmitSelfServiceSettingsFlowWithTotpMethodBody) HasTotpUnlink() bool { - if o != nil && o.TotpUnlink != nil { - return true - } - - return false -} - -// SetTotpUnlink gets a reference to the given bool and assigns it to the TotpUnlink field. -func (o *SubmitSelfServiceSettingsFlowWithTotpMethodBody) SetTotpUnlink(v bool) { - o.TotpUnlink = &v -} - -func (o SubmitSelfServiceSettingsFlowWithTotpMethodBody) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.CsrfToken != nil { - toSerialize["csrf_token"] = o.CsrfToken - } - if true { - toSerialize["method"] = o.Method - } - if o.TotpCode != nil { - toSerialize["totp_code"] = o.TotpCode - } - if o.TotpUnlink != nil { - toSerialize["totp_unlink"] = o.TotpUnlink - } - return json.Marshal(toSerialize) -} - -type NullableSubmitSelfServiceSettingsFlowWithTotpMethodBody struct { - value *SubmitSelfServiceSettingsFlowWithTotpMethodBody - isSet bool -} - -func (v NullableSubmitSelfServiceSettingsFlowWithTotpMethodBody) Get() *SubmitSelfServiceSettingsFlowWithTotpMethodBody { - return v.value -} - -func (v *NullableSubmitSelfServiceSettingsFlowWithTotpMethodBody) Set(val *SubmitSelfServiceSettingsFlowWithTotpMethodBody) { - v.value = val - v.isSet = true -} - -func (v NullableSubmitSelfServiceSettingsFlowWithTotpMethodBody) IsSet() bool { - return v.isSet -} - -func (v *NullableSubmitSelfServiceSettingsFlowWithTotpMethodBody) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSubmitSelfServiceSettingsFlowWithTotpMethodBody(val *SubmitSelfServiceSettingsFlowWithTotpMethodBody) *NullableSubmitSelfServiceSettingsFlowWithTotpMethodBody { - return &NullableSubmitSelfServiceSettingsFlowWithTotpMethodBody{value: val, isSet: true} -} - -func (v NullableSubmitSelfServiceSettingsFlowWithTotpMethodBody) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSubmitSelfServiceSettingsFlowWithTotpMethodBody) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_submit_self_service_settings_flow_with_web_authn_method_body.go b/internal/client-go/model_submit_self_service_settings_flow_with_web_authn_method_body.go deleted file mode 100644 index 3e70ac1f19c8..000000000000 --- a/internal/client-go/model_submit_self_service_settings_flow_with_web_authn_method_body.go +++ /dev/null @@ -1,259 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody struct for SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody -type SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody struct { - // CSRFToken is the anti-CSRF token - CsrfToken *string `json:"csrf_token,omitempty"` - // Method Should be set to \"webauthn\" when trying to add, update, or remove a webAuthn pairing. - Method string `json:"method"` - // Register a WebAuthn Security Key It is expected that the JSON returned by the WebAuthn registration process is included here. - WebauthnRegister *string `json:"webauthn_register,omitempty"` - // Name of the WebAuthn Security Key to be Added A human-readable name for the security key which will be added. - WebauthnRegisterDisplayname *string `json:"webauthn_register_displayname,omitempty"` - // Remove a WebAuthn Security Key This must contain the ID of the WebAuthN connection. - WebauthnRemove *string `json:"webauthn_remove,omitempty"` -} - -// NewSubmitSelfServiceSettingsFlowWithWebAuthnMethodBody instantiates a new SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody 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 NewSubmitSelfServiceSettingsFlowWithWebAuthnMethodBody(method string) *SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody { - this := SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody{} - this.Method = method - return &this -} - -// NewSubmitSelfServiceSettingsFlowWithWebAuthnMethodBodyWithDefaults instantiates a new SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody 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 NewSubmitSelfServiceSettingsFlowWithWebAuthnMethodBodyWithDefaults() *SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody { - this := SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody{} - return &this -} - -// GetCsrfToken returns the CsrfToken field value if set, zero value otherwise. -func (o *SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) GetCsrfToken() string { - if o == nil || o.CsrfToken == nil { - var ret string - return ret - } - return *o.CsrfToken -} - -// GetCsrfTokenOk returns a tuple with the CsrfToken field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) GetCsrfTokenOk() (*string, bool) { - if o == nil || o.CsrfToken == nil { - return nil, false - } - return o.CsrfToken, true -} - -// HasCsrfToken returns a boolean if a field has been set. -func (o *SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) HasCsrfToken() bool { - if o != nil && o.CsrfToken != nil { - return true - } - - return false -} - -// SetCsrfToken gets a reference to the given string and assigns it to the CsrfToken field. -func (o *SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) SetCsrfToken(v string) { - o.CsrfToken = &v -} - -// GetMethod returns the Method field value -func (o *SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) GetMethod() string { - if o == nil { - var ret string - return ret - } - - return o.Method -} - -// GetMethodOk returns a tuple with the Method field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) GetMethodOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Method, true -} - -// SetMethod sets field value -func (o *SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) SetMethod(v string) { - o.Method = v -} - -// GetWebauthnRegister returns the WebauthnRegister field value if set, zero value otherwise. -func (o *SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) GetWebauthnRegister() string { - if o == nil || o.WebauthnRegister == nil { - var ret string - return ret - } - return *o.WebauthnRegister -} - -// GetWebauthnRegisterOk returns a tuple with the WebauthnRegister field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) GetWebauthnRegisterOk() (*string, bool) { - if o == nil || o.WebauthnRegister == nil { - return nil, false - } - return o.WebauthnRegister, true -} - -// HasWebauthnRegister returns a boolean if a field has been set. -func (o *SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) HasWebauthnRegister() bool { - if o != nil && o.WebauthnRegister != nil { - return true - } - - return false -} - -// SetWebauthnRegister gets a reference to the given string and assigns it to the WebauthnRegister field. -func (o *SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) SetWebauthnRegister(v string) { - o.WebauthnRegister = &v -} - -// GetWebauthnRegisterDisplayname returns the WebauthnRegisterDisplayname field value if set, zero value otherwise. -func (o *SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) GetWebauthnRegisterDisplayname() string { - if o == nil || o.WebauthnRegisterDisplayname == nil { - var ret string - return ret - } - return *o.WebauthnRegisterDisplayname -} - -// GetWebauthnRegisterDisplaynameOk returns a tuple with the WebauthnRegisterDisplayname field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) GetWebauthnRegisterDisplaynameOk() (*string, bool) { - if o == nil || o.WebauthnRegisterDisplayname == nil { - return nil, false - } - return o.WebauthnRegisterDisplayname, true -} - -// HasWebauthnRegisterDisplayname returns a boolean if a field has been set. -func (o *SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) HasWebauthnRegisterDisplayname() bool { - if o != nil && o.WebauthnRegisterDisplayname != nil { - return true - } - - return false -} - -// SetWebauthnRegisterDisplayname gets a reference to the given string and assigns it to the WebauthnRegisterDisplayname field. -func (o *SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) SetWebauthnRegisterDisplayname(v string) { - o.WebauthnRegisterDisplayname = &v -} - -// GetWebauthnRemove returns the WebauthnRemove field value if set, zero value otherwise. -func (o *SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) GetWebauthnRemove() string { - if o == nil || o.WebauthnRemove == nil { - var ret string - return ret - } - return *o.WebauthnRemove -} - -// GetWebauthnRemoveOk returns a tuple with the WebauthnRemove field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) GetWebauthnRemoveOk() (*string, bool) { - if o == nil || o.WebauthnRemove == nil { - return nil, false - } - return o.WebauthnRemove, true -} - -// HasWebauthnRemove returns a boolean if a field has been set. -func (o *SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) HasWebauthnRemove() bool { - if o != nil && o.WebauthnRemove != nil { - return true - } - - return false -} - -// SetWebauthnRemove gets a reference to the given string and assigns it to the WebauthnRemove field. -func (o *SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) SetWebauthnRemove(v string) { - o.WebauthnRemove = &v -} - -func (o SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.CsrfToken != nil { - toSerialize["csrf_token"] = o.CsrfToken - } - if true { - toSerialize["method"] = o.Method - } - if o.WebauthnRegister != nil { - toSerialize["webauthn_register"] = o.WebauthnRegister - } - if o.WebauthnRegisterDisplayname != nil { - toSerialize["webauthn_register_displayname"] = o.WebauthnRegisterDisplayname - } - if o.WebauthnRemove != nil { - toSerialize["webauthn_remove"] = o.WebauthnRemove - } - return json.Marshal(toSerialize) -} - -type NullableSubmitSelfServiceSettingsFlowWithWebAuthnMethodBody struct { - value *SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody - isSet bool -} - -func (v NullableSubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) Get() *SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody { - return v.value -} - -func (v *NullableSubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) Set(val *SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) { - v.value = val - v.isSet = true -} - -func (v NullableSubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) IsSet() bool { - return v.isSet -} - -func (v *NullableSubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSubmitSelfServiceSettingsFlowWithWebAuthnMethodBody(val *SubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) *NullableSubmitSelfServiceSettingsFlowWithWebAuthnMethodBody { - return &NullableSubmitSelfServiceSettingsFlowWithWebAuthnMethodBody{value: val, isSet: true} -} - -func (v NullableSubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSubmitSelfServiceSettingsFlowWithWebAuthnMethodBody) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_submit_self_service_verification_flow_body.go b/internal/client-go/model_submit_self_service_verification_flow_body.go deleted file mode 100644 index 05052a31e5b4..000000000000 --- a/internal/client-go/model_submit_self_service_verification_flow_body.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" - "fmt" -) - -// SubmitSelfServiceVerificationFlowBody - nolint:deadcode,unused -type SubmitSelfServiceVerificationFlowBody struct { - SubmitSelfServiceVerificationFlowWithLinkMethodBody *SubmitSelfServiceVerificationFlowWithLinkMethodBody -} - -// SubmitSelfServiceVerificationFlowWithLinkMethodBodyAsSubmitSelfServiceVerificationFlowBody is a convenience function that returns SubmitSelfServiceVerificationFlowWithLinkMethodBody wrapped in SubmitSelfServiceVerificationFlowBody -func SubmitSelfServiceVerificationFlowWithLinkMethodBodyAsSubmitSelfServiceVerificationFlowBody(v *SubmitSelfServiceVerificationFlowWithLinkMethodBody) SubmitSelfServiceVerificationFlowBody { - return SubmitSelfServiceVerificationFlowBody{ - SubmitSelfServiceVerificationFlowWithLinkMethodBody: v, - } -} - -// Unmarshal JSON data into one of the pointers in the struct -func (dst *SubmitSelfServiceVerificationFlowBody) UnmarshalJSON(data []byte) error { - var err error - match := 0 - // try to unmarshal data into SubmitSelfServiceVerificationFlowWithLinkMethodBody - err = newStrictDecoder(data).Decode(&dst.SubmitSelfServiceVerificationFlowWithLinkMethodBody) - if err == nil { - jsonSubmitSelfServiceVerificationFlowWithLinkMethodBody, _ := json.Marshal(dst.SubmitSelfServiceVerificationFlowWithLinkMethodBody) - if string(jsonSubmitSelfServiceVerificationFlowWithLinkMethodBody) == "{}" { // empty struct - dst.SubmitSelfServiceVerificationFlowWithLinkMethodBody = nil - } else { - match++ - } - } else { - dst.SubmitSelfServiceVerificationFlowWithLinkMethodBody = nil - } - - if match > 1 { // more than 1 match - // reset to nil - dst.SubmitSelfServiceVerificationFlowWithLinkMethodBody = nil - - return fmt.Errorf("Data matches more than one schema in oneOf(SubmitSelfServiceVerificationFlowBody)") - } else if match == 1 { - return nil // exactly one match - } else { // no match - return fmt.Errorf("Data failed to match schemas in oneOf(SubmitSelfServiceVerificationFlowBody)") - } -} - -// Marshal data from the first non-nil pointers in the struct to JSON -func (src SubmitSelfServiceVerificationFlowBody) MarshalJSON() ([]byte, error) { - if src.SubmitSelfServiceVerificationFlowWithLinkMethodBody != nil { - return json.Marshal(&src.SubmitSelfServiceVerificationFlowWithLinkMethodBody) - } - - return nil, nil // no data in oneOf schemas -} - -// Get the actual instance -func (obj *SubmitSelfServiceVerificationFlowBody) GetActualInstance() interface{} { - if obj == nil { - return nil - } - if obj.SubmitSelfServiceVerificationFlowWithLinkMethodBody != nil { - return obj.SubmitSelfServiceVerificationFlowWithLinkMethodBody - } - - // all schemas are nil - return nil -} - -type NullableSubmitSelfServiceVerificationFlowBody struct { - value *SubmitSelfServiceVerificationFlowBody - isSet bool -} - -func (v NullableSubmitSelfServiceVerificationFlowBody) Get() *SubmitSelfServiceVerificationFlowBody { - return v.value -} - -func (v *NullableSubmitSelfServiceVerificationFlowBody) Set(val *SubmitSelfServiceVerificationFlowBody) { - v.value = val - v.isSet = true -} - -func (v NullableSubmitSelfServiceVerificationFlowBody) IsSet() bool { - return v.isSet -} - -func (v *NullableSubmitSelfServiceVerificationFlowBody) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSubmitSelfServiceVerificationFlowBody(val *SubmitSelfServiceVerificationFlowBody) *NullableSubmitSelfServiceVerificationFlowBody { - return &NullableSubmitSelfServiceVerificationFlowBody{value: val, isSet: true} -} - -func (v NullableSubmitSelfServiceVerificationFlowBody) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSubmitSelfServiceVerificationFlowBody) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_submit_self_service_verification_flow_with_link_method_body.go b/internal/client-go/model_submit_self_service_verification_flow_with_link_method_body.go deleted file mode 100644 index 21d7e624fec2..000000000000 --- a/internal/client-go/model_submit_self_service_verification_flow_with_link_method_body.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// SubmitSelfServiceVerificationFlowWithLinkMethodBody struct for SubmitSelfServiceVerificationFlowWithLinkMethodBody -type SubmitSelfServiceVerificationFlowWithLinkMethodBody struct { - // Sending the anti-csrf token is only required for browser login flows. - CsrfToken *string `json:"csrf_token,omitempty"` - // Email to Verify Needs to be set when initiating the flow. If the email is a registered verification email, a verification link will be sent. If the email is not known, a email with details on what happened will be sent instead. format: email - Email string `json:"email"` - // Method supports `link` only right now. - Method string `json:"method"` -} - -// NewSubmitSelfServiceVerificationFlowWithLinkMethodBody instantiates a new SubmitSelfServiceVerificationFlowWithLinkMethodBody 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 NewSubmitSelfServiceVerificationFlowWithLinkMethodBody(email string, method string) *SubmitSelfServiceVerificationFlowWithLinkMethodBody { - this := SubmitSelfServiceVerificationFlowWithLinkMethodBody{} - this.Email = email - this.Method = method - return &this -} - -// NewSubmitSelfServiceVerificationFlowWithLinkMethodBodyWithDefaults instantiates a new SubmitSelfServiceVerificationFlowWithLinkMethodBody 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 NewSubmitSelfServiceVerificationFlowWithLinkMethodBodyWithDefaults() *SubmitSelfServiceVerificationFlowWithLinkMethodBody { - this := SubmitSelfServiceVerificationFlowWithLinkMethodBody{} - return &this -} - -// GetCsrfToken returns the CsrfToken field value if set, zero value otherwise. -func (o *SubmitSelfServiceVerificationFlowWithLinkMethodBody) GetCsrfToken() string { - if o == nil || o.CsrfToken == nil { - var ret string - return ret - } - return *o.CsrfToken -} - -// GetCsrfTokenOk returns a tuple with the CsrfToken field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceVerificationFlowWithLinkMethodBody) GetCsrfTokenOk() (*string, bool) { - if o == nil || o.CsrfToken == nil { - return nil, false - } - return o.CsrfToken, true -} - -// HasCsrfToken returns a boolean if a field has been set. -func (o *SubmitSelfServiceVerificationFlowWithLinkMethodBody) HasCsrfToken() bool { - if o != nil && o.CsrfToken != nil { - return true - } - - return false -} - -// SetCsrfToken gets a reference to the given string and assigns it to the CsrfToken field. -func (o *SubmitSelfServiceVerificationFlowWithLinkMethodBody) SetCsrfToken(v string) { - o.CsrfToken = &v -} - -// GetEmail returns the Email field value -func (o *SubmitSelfServiceVerificationFlowWithLinkMethodBody) GetEmail() string { - if o == nil { - var ret string - return ret - } - - return o.Email -} - -// GetEmailOk returns a tuple with the Email field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceVerificationFlowWithLinkMethodBody) GetEmailOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Email, true -} - -// SetEmail sets field value -func (o *SubmitSelfServiceVerificationFlowWithLinkMethodBody) SetEmail(v string) { - o.Email = v -} - -// GetMethod returns the Method field value -func (o *SubmitSelfServiceVerificationFlowWithLinkMethodBody) GetMethod() string { - if o == nil { - var ret string - return ret - } - - return o.Method -} - -// GetMethodOk returns a tuple with the Method field value -// and a boolean to check if the value has been set. -func (o *SubmitSelfServiceVerificationFlowWithLinkMethodBody) GetMethodOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Method, true -} - -// SetMethod sets field value -func (o *SubmitSelfServiceVerificationFlowWithLinkMethodBody) SetMethod(v string) { - o.Method = v -} - -func (o SubmitSelfServiceVerificationFlowWithLinkMethodBody) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.CsrfToken != nil { - toSerialize["csrf_token"] = o.CsrfToken - } - if true { - toSerialize["email"] = o.Email - } - if true { - toSerialize["method"] = o.Method - } - return json.Marshal(toSerialize) -} - -type NullableSubmitSelfServiceVerificationFlowWithLinkMethodBody struct { - value *SubmitSelfServiceVerificationFlowWithLinkMethodBody - isSet bool -} - -func (v NullableSubmitSelfServiceVerificationFlowWithLinkMethodBody) Get() *SubmitSelfServiceVerificationFlowWithLinkMethodBody { - return v.value -} - -func (v *NullableSubmitSelfServiceVerificationFlowWithLinkMethodBody) Set(val *SubmitSelfServiceVerificationFlowWithLinkMethodBody) { - v.value = val - v.isSet = true -} - -func (v NullableSubmitSelfServiceVerificationFlowWithLinkMethodBody) IsSet() bool { - return v.isSet -} - -func (v *NullableSubmitSelfServiceVerificationFlowWithLinkMethodBody) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSubmitSelfServiceVerificationFlowWithLinkMethodBody(val *SubmitSelfServiceVerificationFlowWithLinkMethodBody) *NullableSubmitSelfServiceVerificationFlowWithLinkMethodBody { - return &NullableSubmitSelfServiceVerificationFlowWithLinkMethodBody{value: val, isSet: true} -} - -func (v NullableSubmitSelfServiceVerificationFlowWithLinkMethodBody) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSubmitSelfServiceVerificationFlowWithLinkMethodBody) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_successful_self_service_login_without_browser.go b/internal/client-go/model_successful_self_service_login_without_browser.go deleted file mode 100644 index 8d2428c052df..000000000000 --- a/internal/client-go/model_successful_self_service_login_without_browser.go +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// SuccessfulSelfServiceLoginWithoutBrowser The Response for Login Flows via API -type SuccessfulSelfServiceLoginWithoutBrowser struct { - Session Session `json:"session"` - // The Session Token A session token is equivalent to a session cookie, but it can be sent in the HTTP Authorization Header: Authorization: bearer ${session-token} The session token is only issued for API flows, not for Browser flows! - SessionToken *string `json:"session_token,omitempty"` -} - -// NewSuccessfulSelfServiceLoginWithoutBrowser instantiates a new SuccessfulSelfServiceLoginWithoutBrowser 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 NewSuccessfulSelfServiceLoginWithoutBrowser(session Session) *SuccessfulSelfServiceLoginWithoutBrowser { - this := SuccessfulSelfServiceLoginWithoutBrowser{} - this.Session = session - return &this -} - -// NewSuccessfulSelfServiceLoginWithoutBrowserWithDefaults instantiates a new SuccessfulSelfServiceLoginWithoutBrowser 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 NewSuccessfulSelfServiceLoginWithoutBrowserWithDefaults() *SuccessfulSelfServiceLoginWithoutBrowser { - this := SuccessfulSelfServiceLoginWithoutBrowser{} - return &this -} - -// GetSession returns the Session field value -func (o *SuccessfulSelfServiceLoginWithoutBrowser) GetSession() Session { - if o == nil { - var ret Session - return ret - } - - return o.Session -} - -// GetSessionOk returns a tuple with the Session field value -// and a boolean to check if the value has been set. -func (o *SuccessfulSelfServiceLoginWithoutBrowser) GetSessionOk() (*Session, bool) { - if o == nil { - return nil, false - } - return &o.Session, true -} - -// SetSession sets field value -func (o *SuccessfulSelfServiceLoginWithoutBrowser) SetSession(v Session) { - o.Session = v -} - -// GetSessionToken returns the SessionToken field value if set, zero value otherwise. -func (o *SuccessfulSelfServiceLoginWithoutBrowser) GetSessionToken() string { - if o == nil || o.SessionToken == nil { - var ret string - return ret - } - return *o.SessionToken -} - -// GetSessionTokenOk returns a tuple with the SessionToken field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SuccessfulSelfServiceLoginWithoutBrowser) GetSessionTokenOk() (*string, bool) { - if o == nil || o.SessionToken == nil { - return nil, false - } - return o.SessionToken, true -} - -// HasSessionToken returns a boolean if a field has been set. -func (o *SuccessfulSelfServiceLoginWithoutBrowser) HasSessionToken() bool { - if o != nil && o.SessionToken != nil { - return true - } - - return false -} - -// SetSessionToken gets a reference to the given string and assigns it to the SessionToken field. -func (o *SuccessfulSelfServiceLoginWithoutBrowser) SetSessionToken(v string) { - o.SessionToken = &v -} - -func (o SuccessfulSelfServiceLoginWithoutBrowser) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if true { - toSerialize["session"] = o.Session - } - if o.SessionToken != nil { - toSerialize["session_token"] = o.SessionToken - } - return json.Marshal(toSerialize) -} - -type NullableSuccessfulSelfServiceLoginWithoutBrowser struct { - value *SuccessfulSelfServiceLoginWithoutBrowser - isSet bool -} - -func (v NullableSuccessfulSelfServiceLoginWithoutBrowser) Get() *SuccessfulSelfServiceLoginWithoutBrowser { - return v.value -} - -func (v *NullableSuccessfulSelfServiceLoginWithoutBrowser) Set(val *SuccessfulSelfServiceLoginWithoutBrowser) { - v.value = val - v.isSet = true -} - -func (v NullableSuccessfulSelfServiceLoginWithoutBrowser) IsSet() bool { - return v.isSet -} - -func (v *NullableSuccessfulSelfServiceLoginWithoutBrowser) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSuccessfulSelfServiceLoginWithoutBrowser(val *SuccessfulSelfServiceLoginWithoutBrowser) *NullableSuccessfulSelfServiceLoginWithoutBrowser { - return &NullableSuccessfulSelfServiceLoginWithoutBrowser{value: val, isSet: true} -} - -func (v NullableSuccessfulSelfServiceLoginWithoutBrowser) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSuccessfulSelfServiceLoginWithoutBrowser) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_successful_self_service_registration_without_browser.go b/internal/client-go/model_successful_self_service_registration_without_browser.go deleted file mode 100644 index 28a2197172ec..000000000000 --- a/internal/client-go/model_successful_self_service_registration_without_browser.go +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -/* - * 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: - * Contact: hi@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// SuccessfulSelfServiceRegistrationWithoutBrowser The Response for Registration Flows via API -type SuccessfulSelfServiceRegistrationWithoutBrowser struct { - Identity Identity `json:"identity"` - Session *Session `json:"session,omitempty"` - // The Session Token This field is only set when the session hook is configured as a post-registration hook. A session token is equivalent to a session cookie, but it can be sent in the HTTP Authorization Header: Authorization: bearer ${session-token} The session token is only issued for API flows, not for Browser flows! - SessionToken *string `json:"session_token,omitempty"` -} - -// NewSuccessfulSelfServiceRegistrationWithoutBrowser instantiates a new SuccessfulSelfServiceRegistrationWithoutBrowser 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 NewSuccessfulSelfServiceRegistrationWithoutBrowser(identity Identity) *SuccessfulSelfServiceRegistrationWithoutBrowser { - this := SuccessfulSelfServiceRegistrationWithoutBrowser{} - this.Identity = identity - return &this -} - -// NewSuccessfulSelfServiceRegistrationWithoutBrowserWithDefaults instantiates a new SuccessfulSelfServiceRegistrationWithoutBrowser 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 NewSuccessfulSelfServiceRegistrationWithoutBrowserWithDefaults() *SuccessfulSelfServiceRegistrationWithoutBrowser { - this := SuccessfulSelfServiceRegistrationWithoutBrowser{} - return &this -} - -// GetIdentity returns the Identity field value -func (o *SuccessfulSelfServiceRegistrationWithoutBrowser) GetIdentity() Identity { - if o == nil { - var ret Identity - return ret - } - - return o.Identity -} - -// GetIdentityOk returns a tuple with the Identity field value -// and a boolean to check if the value has been set. -func (o *SuccessfulSelfServiceRegistrationWithoutBrowser) GetIdentityOk() (*Identity, bool) { - if o == nil { - return nil, false - } - return &o.Identity, true -} - -// SetIdentity sets field value -func (o *SuccessfulSelfServiceRegistrationWithoutBrowser) SetIdentity(v Identity) { - o.Identity = v -} - -// GetSession returns the Session field value if set, zero value otherwise. -func (o *SuccessfulSelfServiceRegistrationWithoutBrowser) GetSession() Session { - if o == nil || o.Session == nil { - var ret Session - return ret - } - return *o.Session -} - -// GetSessionOk returns a tuple with the Session field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SuccessfulSelfServiceRegistrationWithoutBrowser) GetSessionOk() (*Session, bool) { - if o == nil || o.Session == nil { - return nil, false - } - return o.Session, true -} - -// HasSession returns a boolean if a field has been set. -func (o *SuccessfulSelfServiceRegistrationWithoutBrowser) HasSession() bool { - if o != nil && o.Session != nil { - return true - } - - return false -} - -// SetSession gets a reference to the given Session and assigns it to the Session field. -func (o *SuccessfulSelfServiceRegistrationWithoutBrowser) SetSession(v Session) { - o.Session = &v -} - -// GetSessionToken returns the SessionToken field value if set, zero value otherwise. -func (o *SuccessfulSelfServiceRegistrationWithoutBrowser) GetSessionToken() string { - if o == nil || o.SessionToken == nil { - var ret string - return ret - } - return *o.SessionToken -} - -// GetSessionTokenOk returns a tuple with the SessionToken field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *SuccessfulSelfServiceRegistrationWithoutBrowser) GetSessionTokenOk() (*string, bool) { - if o == nil || o.SessionToken == nil { - return nil, false - } - return o.SessionToken, true -} - -// HasSessionToken returns a boolean if a field has been set. -func (o *SuccessfulSelfServiceRegistrationWithoutBrowser) HasSessionToken() bool { - if o != nil && o.SessionToken != nil { - return true - } - - return false -} - -// SetSessionToken gets a reference to the given string and assigns it to the SessionToken field. -func (o *SuccessfulSelfServiceRegistrationWithoutBrowser) SetSessionToken(v string) { - o.SessionToken = &v -} - -func (o SuccessfulSelfServiceRegistrationWithoutBrowser) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if true { - toSerialize["identity"] = o.Identity - } - if o.Session != nil { - toSerialize["session"] = o.Session - } - if o.SessionToken != nil { - toSerialize["session_token"] = o.SessionToken - } - return json.Marshal(toSerialize) -} - -type NullableSuccessfulSelfServiceRegistrationWithoutBrowser struct { - value *SuccessfulSelfServiceRegistrationWithoutBrowser - isSet bool -} - -func (v NullableSuccessfulSelfServiceRegistrationWithoutBrowser) Get() *SuccessfulSelfServiceRegistrationWithoutBrowser { - return v.value -} - -func (v *NullableSuccessfulSelfServiceRegistrationWithoutBrowser) Set(val *SuccessfulSelfServiceRegistrationWithoutBrowser) { - v.value = val - v.isSet = true -} - -func (v NullableSuccessfulSelfServiceRegistrationWithoutBrowser) IsSet() bool { - return v.isSet -} - -func (v *NullableSuccessfulSelfServiceRegistrationWithoutBrowser) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableSuccessfulSelfServiceRegistrationWithoutBrowser(val *SuccessfulSelfServiceRegistrationWithoutBrowser) *NullableSuccessfulSelfServiceRegistrationWithoutBrowser { - return &NullableSuccessfulSelfServiceRegistrationWithoutBrowser{value: val, isSet: true} -} - -func (v NullableSuccessfulSelfServiceRegistrationWithoutBrowser) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableSuccessfulSelfServiceRegistrationWithoutBrowser) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_update_verification_flow_with_code_method_body.go b/internal/client-go/model_update_verification_flow_with_code_method_body.go deleted file mode 100644 index d5ec31b6bfee..000000000000 --- a/internal/client-go/model_update_verification_flow_with_code_method_body.go +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Ory Identities API - * - * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. - * - * API version: - * Contact: office@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// UpdateVerificationFlowWithCodeMethodBody struct for UpdateVerificationFlowWithCodeMethodBody -type UpdateVerificationFlowWithCodeMethodBody struct { - // The verification code - Code *string `json:"code,omitempty"` - // Sending the anti-csrf token is only required for browser login flows. - CsrfToken *string `json:"csrf_token,omitempty"` - // Email to Verify Needs to be set when initiating the flow. If the email is a registered verification email, a verification link will be sent. If the email is not known, a email with details on what happened will be sent instead. format: email - Email *string `json:"email,omitempty"` - // The id of the flow - Flow *string `json:"flow,omitempty"` - // Method is the recovery method - Method *string `json:"method,omitempty"` -} - -// NewUpdateVerificationFlowWithCodeMethodBody instantiates a new UpdateVerificationFlowWithCodeMethodBody 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 NewUpdateVerificationFlowWithCodeMethodBody() *UpdateVerificationFlowWithCodeMethodBody { - this := UpdateVerificationFlowWithCodeMethodBody{} - return &this -} - -// NewUpdateVerificationFlowWithCodeMethodBodyWithDefaults instantiates a new UpdateVerificationFlowWithCodeMethodBody 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 NewUpdateVerificationFlowWithCodeMethodBodyWithDefaults() *UpdateVerificationFlowWithCodeMethodBody { - this := UpdateVerificationFlowWithCodeMethodBody{} - return &this -} - -// GetCode returns the Code field value if set, zero value otherwise. -func (o *UpdateVerificationFlowWithCodeMethodBody) GetCode() string { - if o == nil || o.Code == nil { - var ret string - return ret - } - return *o.Code -} - -// GetCodeOk returns a tuple with the Code field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *UpdateVerificationFlowWithCodeMethodBody) GetCodeOk() (*string, bool) { - if o == nil || o.Code == nil { - return nil, false - } - return o.Code, true -} - -// HasCode returns a boolean if a field has been set. -func (o *UpdateVerificationFlowWithCodeMethodBody) HasCode() bool { - if o != nil && o.Code != nil { - return true - } - - return false -} - -// SetCode gets a reference to the given string and assigns it to the Code field. -func (o *UpdateVerificationFlowWithCodeMethodBody) SetCode(v string) { - o.Code = &v -} - -// GetCsrfToken returns the CsrfToken field value if set, zero value otherwise. -func (o *UpdateVerificationFlowWithCodeMethodBody) GetCsrfToken() string { - if o == nil || o.CsrfToken == nil { - var ret string - return ret - } - return *o.CsrfToken -} - -// GetCsrfTokenOk returns a tuple with the CsrfToken field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *UpdateVerificationFlowWithCodeMethodBody) GetCsrfTokenOk() (*string, bool) { - if o == nil || o.CsrfToken == nil { - return nil, false - } - return o.CsrfToken, true -} - -// HasCsrfToken returns a boolean if a field has been set. -func (o *UpdateVerificationFlowWithCodeMethodBody) HasCsrfToken() bool { - if o != nil && o.CsrfToken != nil { - return true - } - - return false -} - -// SetCsrfToken gets a reference to the given string and assigns it to the CsrfToken field. -func (o *UpdateVerificationFlowWithCodeMethodBody) SetCsrfToken(v string) { - o.CsrfToken = &v -} - -// GetEmail returns the Email field value if set, zero value otherwise. -func (o *UpdateVerificationFlowWithCodeMethodBody) GetEmail() string { - if o == nil || o.Email == nil { - var ret string - return ret - } - return *o.Email -} - -// GetEmailOk returns a tuple with the Email field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *UpdateVerificationFlowWithCodeMethodBody) GetEmailOk() (*string, bool) { - if o == nil || o.Email == nil { - return nil, false - } - return o.Email, true -} - -// HasEmail returns a boolean if a field has been set. -func (o *UpdateVerificationFlowWithCodeMethodBody) HasEmail() bool { - if o != nil && o.Email != nil { - return true - } - - return false -} - -// SetEmail gets a reference to the given string and assigns it to the Email field. -func (o *UpdateVerificationFlowWithCodeMethodBody) SetEmail(v string) { - o.Email = &v -} - -// GetFlow returns the Flow field value if set, zero value otherwise. -func (o *UpdateVerificationFlowWithCodeMethodBody) GetFlow() string { - if o == nil || o.Flow == nil { - var ret string - return ret - } - return *o.Flow -} - -// GetFlowOk returns a tuple with the Flow field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *UpdateVerificationFlowWithCodeMethodBody) GetFlowOk() (*string, bool) { - if o == nil || o.Flow == nil { - return nil, false - } - return o.Flow, true -} - -// HasFlow returns a boolean if a field has been set. -func (o *UpdateVerificationFlowWithCodeMethodBody) HasFlow() bool { - if o != nil && o.Flow != nil { - return true - } - - return false -} - -// SetFlow gets a reference to the given string and assigns it to the Flow field. -func (o *UpdateVerificationFlowWithCodeMethodBody) SetFlow(v string) { - o.Flow = &v -} - -// GetMethod returns the Method field value if set, zero value otherwise. -func (o *UpdateVerificationFlowWithCodeMethodBody) GetMethod() string { - if o == nil || o.Method == nil { - var ret string - return ret - } - return *o.Method -} - -// GetMethodOk returns a tuple with the Method field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *UpdateVerificationFlowWithCodeMethodBody) GetMethodOk() (*string, bool) { - if o == nil || o.Method == nil { - return nil, false - } - return o.Method, true -} - -// HasMethod returns a boolean if a field has been set. -func (o *UpdateVerificationFlowWithCodeMethodBody) HasMethod() bool { - if o != nil && o.Method != nil { - return true - } - - return false -} - -// SetMethod gets a reference to the given string and assigns it to the Method field. -func (o *UpdateVerificationFlowWithCodeMethodBody) SetMethod(v string) { - o.Method = &v -} - -func (o UpdateVerificationFlowWithCodeMethodBody) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.Code != nil { - toSerialize["code"] = o.Code - } - if o.CsrfToken != nil { - toSerialize["csrf_token"] = o.CsrfToken - } - if o.Email != nil { - toSerialize["email"] = o.Email - } - if o.Flow != nil { - toSerialize["flow"] = o.Flow - } - if o.Method != nil { - toSerialize["method"] = o.Method - } - return json.Marshal(toSerialize) -} - -type NullableUpdateVerificationFlowWithCodeMethodBody struct { - value *UpdateVerificationFlowWithCodeMethodBody - isSet bool -} - -func (v NullableUpdateVerificationFlowWithCodeMethodBody) Get() *UpdateVerificationFlowWithCodeMethodBody { - return v.value -} - -func (v *NullableUpdateVerificationFlowWithCodeMethodBody) Set(val *UpdateVerificationFlowWithCodeMethodBody) { - v.value = val - v.isSet = true -} - -func (v NullableUpdateVerificationFlowWithCodeMethodBody) IsSet() bool { - return v.isSet -} - -func (v *NullableUpdateVerificationFlowWithCodeMethodBody) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableUpdateVerificationFlowWithCodeMethodBody(val *UpdateVerificationFlowWithCodeMethodBody) *NullableUpdateVerificationFlowWithCodeMethodBody { - return &NullableUpdateVerificationFlowWithCodeMethodBody{value: val, isSet: true} -} - -func (v NullableUpdateVerificationFlowWithCodeMethodBody) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableUpdateVerificationFlowWithCodeMethodBody) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} From f12f622a3afb2a4fa6df156c966b86ec8a6188c9 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Mon, 18 Sep 2023 08:30:03 +0000 Subject: [PATCH 092/282] autogen(openapi): regenerate swagger spec and internal client [skip ci] --- internal/client-go/model_pagination.go | 160 ------------------------- 1 file changed, 160 deletions(-) delete mode 100644 internal/client-go/model_pagination.go diff --git a/internal/client-go/model_pagination.go b/internal/client-go/model_pagination.go deleted file mode 100644 index f5154c7eea47..000000000000 --- a/internal/client-go/model_pagination.go +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Ory Identities API - * - * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. - * - * API version: - * Contact: office@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" -) - -// Pagination struct for Pagination -type Pagination struct { - // Pagination Page This value is currently an integer, but it is not sequential. The value is not the page number, but a reference. The next page can be any number and some numbers might return an empty list. For example, page 2 might not follow after page 1. And even if page 3 and 5 exist, but page 4 might not exist. - Page *int64 `json:"page,omitempty"` - // Items per Page This is the number of items per page. - PerPage *int64 `json:"per_page,omitempty"` -} - -// NewPagination instantiates a new Pagination 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 NewPagination() *Pagination { - this := Pagination{} - var page int64 = 1 - this.Page = &page - var perPage int64 = 250 - this.PerPage = &perPage - return &this -} - -// NewPaginationWithDefaults instantiates a new Pagination 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 NewPaginationWithDefaults() *Pagination { - this := Pagination{} - var page int64 = 1 - this.Page = &page - var perPage int64 = 250 - this.PerPage = &perPage - return &this -} - -// GetPage returns the Page field value if set, zero value otherwise. -func (o *Pagination) GetPage() int64 { - if o == nil || o.Page == nil { - var ret int64 - return ret - } - return *o.Page -} - -// GetPageOk returns a tuple with the Page field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *Pagination) GetPageOk() (*int64, bool) { - if o == nil || o.Page == nil { - return nil, false - } - return o.Page, true -} - -// HasPage returns a boolean if a field has been set. -func (o *Pagination) HasPage() bool { - if o != nil && o.Page != nil { - return true - } - - return false -} - -// SetPage gets a reference to the given int64 and assigns it to the Page field. -func (o *Pagination) SetPage(v int64) { - o.Page = &v -} - -// GetPerPage returns the PerPage field value if set, zero value otherwise. -func (o *Pagination) GetPerPage() int64 { - if o == nil || o.PerPage == nil { - var ret int64 - return ret - } - return *o.PerPage -} - -// GetPerPageOk returns a tuple with the PerPage field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *Pagination) GetPerPageOk() (*int64, bool) { - if o == nil || o.PerPage == nil { - return nil, false - } - return o.PerPage, true -} - -// HasPerPage returns a boolean if a field has been set. -func (o *Pagination) HasPerPage() bool { - if o != nil && o.PerPage != nil { - return true - } - - return false -} - -// SetPerPage gets a reference to the given int64 and assigns it to the PerPage field. -func (o *Pagination) SetPerPage(v int64) { - o.PerPage = &v -} - -func (o Pagination) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if o.Page != nil { - toSerialize["page"] = o.Page - } - if o.PerPage != nil { - toSerialize["per_page"] = o.PerPage - } - return json.Marshal(toSerialize) -} - -type NullablePagination struct { - value *Pagination - isSet bool -} - -func (v NullablePagination) Get() *Pagination { - return v.value -} - -func (v *NullablePagination) Set(val *Pagination) { - v.value = val - v.isSet = true -} - -func (v NullablePagination) IsSet() bool { - return v.isSet -} - -func (v *NullablePagination) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullablePagination(val *Pagination) *NullablePagination { - return &NullablePagination{value: val, isSet: true} -} - -func (v NullablePagination) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullablePagination) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} From a9786c599d09f61e2e07df5066ce94feb2d99bac Mon Sep 17 00:00:00 2001 From: Patrik Date: Mon, 18 Sep 2023 10:56:31 +0200 Subject: [PATCH 093/282] feat: improve performance by computing password hashes while validating (#3508) --- selfservice/strategy/password/registration.go | 30 +++++++++++++++-- selfservice/strategy/password/settings.go | 33 +++++++++++++------ 2 files changed, 51 insertions(+), 12 deletions(-) diff --git a/selfservice/strategy/password/registration.go b/selfservice/strategy/password/registration.go index b49ff630e458..7dc7a627ffab 100644 --- a/selfservice/strategy/password/registration.go +++ b/selfservice/strategy/password/registration.go @@ -101,13 +101,28 @@ func (s *Strategy) Register(w http.ResponseWriter, r *http.Request, f *registrat p.Traits = json.RawMessage("{}") } - hpw, err := s.d.Hasher(r.Context()).Generate(r.Context(), []byte(p.Password)) + hpw := make(chan []byte) + errC := make(chan error) + go func() { + defer close(hpw) + defer close(errC) + + h, err := s.d.Hasher(r.Context()).Generate(r.Context(), []byte(p.Password)) + if err != nil { + errC <- err + return + } + hpw <- h + }() + if err != nil { return s.handleRegistrationError(w, r, f, &p, err) } i.Traits = identity.Traits(p.Traits) - if err := i.SetCredentialsWithConfig(s.ID(), identity.Credentials{Type: s.ID(), Identifiers: []string{}}, &identity.CredentialsPassword{HashedPassword: string(hpw)}); err != nil { + // We have to set the credential here, so the identity validator can populate the identifiers. + // The password hash is computed in parallel and set later. + if err := i.SetCredentialsWithConfig(s.ID(), identity.Credentials{Type: s.ID(), Identifiers: []string{}}, json.RawMessage("{}")); err != nil { return s.handleRegistrationError(w, r, f, &p, err) } @@ -115,6 +130,17 @@ func (s *Strategy) Register(w http.ResponseWriter, r *http.Request, f *registrat return s.handleRegistrationError(w, r, f, &p, err) } + select { + case err := <-errC: + return s.handleRegistrationError(w, r, f, &p, err) + case h := <-hpw: + co, err := json.Marshal(&identity.CredentialsPassword{HashedPassword: string(h)}) + if err != nil { + return s.handleRegistrationError(w, r, f, &p, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Unable to encode password options to JSON: %s", err))) + } + i.UpsertCredentialsConfig(s.ID(), co, 0) + } + return nil } diff --git a/selfservice/strategy/password/settings.go b/selfservice/strategy/password/settings.go index 4ba0b115e53a..f5447ab44eb2 100644 --- a/selfservice/strategy/password/settings.go +++ b/selfservice/strategy/password/settings.go @@ -125,25 +125,38 @@ func (s *Strategy) continueSettingsFlow( return schema.NewRequiredError("#/password", "password") } - hpw, err := s.d.Hasher(r.Context()).Generate(r.Context(), []byte(p.Password)) - if err != nil { - return err - } - - co, err := json.Marshal(&identity.CredentialsPassword{HashedPassword: string(hpw)}) - if err != nil { - return errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Unable to encode password options to JSON: %s", err)) - } + hpw, errC := make(chan []byte), make(chan error) + go func() { + defer close(hpw) + defer close(errC) + h, err := s.d.Hasher(r.Context()).Generate(r.Context(), []byte(p.Password)) + if err != nil { + errC <- err + return + } + hpw <- h + }() i, err := s.d.PrivilegedIdentityPool().GetIdentityConfidential(r.Context(), ctxUpdate.Session.Identity.ID) if err != nil { return err } - i.UpsertCredentialsConfig(s.ID(), co, 0) + i.UpsertCredentialsConfig(s.ID(), []byte("{}"), 0) if err := s.validateCredentials(r.Context(), i, p.Password); err != nil { return err } + + select { + case err := <-errC: + return err + case h := <-hpw: + co, err := json.Marshal(&identity.CredentialsPassword{HashedPassword: string(h)}) + if err != nil { + return errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Unable to encode password options to JSON: %s", err)) + } + i.UpsertCredentialsConfig(s.ID(), co, 0) + } ctxUpdate.UpdateIdentity(i) return nil From 89928c8107373ee6892b5fd831e1edd76cd11ea4 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Mon, 18 Sep 2023 10:06:48 +0000 Subject: [PATCH 094/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9706e4252d32..b109b8f07a7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-09-15)](#2023-09-15) +- [ (2023-09-18)](#2023-09-18) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -313,7 +313,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-09-15) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-09-18) ## Breaking Changes @@ -398,6 +398,9 @@ https://github.com/ory/kratos/pull/3480 - Ignore more cloudflare cookies ([#3499](https://github.com/ory/kratos/issues/3499)) ([f124ab5](https://github.com/ory/kratos/commit/f124ab5586781cdbfc0a0cfd11b4355bfc8a115c)) +- Incorrect sdk generator path + ([#3488](https://github.com/ory/kratos/issues/3488)) + ([ed996c0](https://github.com/ory/kratos/commit/ed996c0d25e68e8a2c7de861c546f0b0e42e9e6e)) - Issue session after verification after registration with OIDC SSO ([#3467](https://github.com/ory/kratos/issues/3467)) ([a28b523](https://github.com/ory/kratos/commit/a28b523238743f3873b51479eea3b86d684092f9)) @@ -470,6 +473,18 @@ https://github.com/ory/kratos/pull/3480 ### Features +- Add ability to convert session to JWT when calling whoami + ([#3472](https://github.com/ory/kratos/issues/3472)) + ([57b7bb8](https://github.com/ory/kratos/commit/57b7bb846c8072f786ea6b80cd688fdee75805da)), + closes [#2487](https://github.com/ory/kratos/issues/2487): + + This patch adds a query parameter `tokenize_as` to `/session/whoami` which + encodes the session to a JWT. It is possible to customize the JWT claims by + using a JsonNet template, and furthermore change the expiry of the token. + + The tokenize feature supports multiple templates, which makes it easy to use + the resulting JWT in a variety of use cases. + - Add GetID member functions to RecoveryAddress and Credentials ([#3474](https://github.com/ory/kratos/issues/3474)) ([085d500](https://github.com/ory/kratos/commit/085d5002df27d455057d33bd2d93dfbca0de4872)) @@ -548,6 +563,9 @@ https://github.com/ory/kratos/pull/3480 - Improve messages for easier i18n ([#3457](https://github.com/ory/kratos/issues/3457)) ([37f1657](https://github.com/ory/kratos/commit/37f16577d92ba88869bf15fb1ea54e819b062724)) +- Improve performance by computing password hashes while validating + ([#3508](https://github.com/ory/kratos/issues/3508)) + ([a9786c5](https://github.com/ory/kratos/commit/a9786c599d09f61e2e07df5066ce94feb2d99bac)) - Passwordless browser login and registration via code to email ([#3378](https://github.com/ory/kratos/issues/3378)) ([eaaf375](https://github.com/ory/kratos/commit/eaaf37519917612671238412a633847386d7c613)), From 055ed9226d9d12f5142542be2e18438ff708c2e2 Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Tue, 19 Sep 2023 07:53:36 +0200 Subject: [PATCH 095/282] feat: add ID Token sign in with Google Android/iOS SDK (#3515) --- selfservice/strategy/oidc/provider_apple.go | 13 +-- .../strategy/oidc/provider_apple_test.go | 109 ++++++------------ selfservice/strategy/oidc/provider_google.go | 28 +++++ .../strategy/oidc/provider_google_test.go | 72 +++++++++++- .../strategy/oidc/strategy_helper_test.go | 33 ++++++ 5 files changed, 175 insertions(+), 80 deletions(-) diff --git a/selfservice/strategy/oidc/provider_apple.go b/selfservice/strategy/oidc/provider_apple.go index 686cad1c10ed..74affe5afb3d 100644 --- a/selfservice/strategy/oidc/provider_apple.go +++ b/selfservice/strategy/oidc/provider_apple.go @@ -14,7 +14,6 @@ import ( "github.com/coreos/go-oidc" "github.com/golang-jwt/jwt/v4" - "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "github.com/pkg/errors" @@ -23,7 +22,7 @@ import ( type ProviderApple struct { *ProviderGenericOIDC - jwksUrl string + JWKSUrl string } func NewProviderApple( @@ -36,7 +35,7 @@ func NewProviderApple( config: config, reg: reg, }, - jwksUrl: "https://appleid.apple.com/auth/keys", + JWKSUrl: "https://appleid.apple.com/auth/keys", } } @@ -118,7 +117,7 @@ func (a *ProviderApple) Claims(ctx context.Context, exchange *oauth2.Token, quer if err != nil { return claims, err } - decodeQuery(query, claims) + a.DecodeQuery(query, claims) return claims, nil } @@ -127,7 +126,7 @@ func (a *ProviderApple) Claims(ctx context.Context, exchange *oauth2.Token, quer // The info is sent as an extra query parameter to the redirect URL. // See https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_js/configuring_your_webpage_for_sign_in_with_apple#3331292 // Note that there's no way to make sure the info hasn't been tampered with. -func decodeQuery(query url.Values, claims *Claims) { +func (a *ProviderApple) DecodeQuery(query url.Values, claims *Claims) { var user struct { Name *struct { FirstName *string `json:"firstName"` @@ -154,11 +153,11 @@ func decodeQuery(query url.Values, claims *Claims) { var _ IDTokenVerifier = new(ProviderApple) func (a *ProviderApple) Verify(ctx context.Context, rawIDToken string) (*Claims, error) { - keySet := oidc.NewRemoteKeySet(ctx, a.jwksUrl) + keySet := oidc.NewRemoteKeySet(ctx, a.JWKSUrl) verifier := oidc.NewVerifier("https://appleid.apple.com", keySet, &oidc.Config{ ClientID: a.config.ClientID, }) - token, err := verifier.Verify(oidc.ClientContext(ctx, otelhttp.DefaultClient), rawIDToken) + token, err := verifier.Verify(oidc.ClientContext(ctx, a.reg.HTTPClient(ctx).HTTPClient), rawIDToken) if err != nil { return nil, err } diff --git a/selfservice/strategy/oidc/provider_apple_test.go b/selfservice/strategy/oidc/provider_apple_test.go index 7690fec5d78a..a1d754fdb48d 100644 --- a/selfservice/strategy/oidc/provider_apple_test.go +++ b/selfservice/strategy/oidc/provider_apple_test.go @@ -1,11 +1,10 @@ // Copyright © 2023 Ory Corp // SPDX-License-Identifier: Apache-2.0 -package oidc +package oidc_test import ( "context" - "encoding/json" "fmt" "net/http" "net/http/httptest" @@ -16,9 +15,11 @@ import ( _ "embed" "github.com/golang-jwt/jwt/v4" - "github.com/rakutentech/jwk-go/jwk" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/ory/kratos/internal" + "github.com/ory/kratos/selfservice/strategy/oidc" ) func TestDecodeQuery(t *testing.T) { @@ -27,18 +28,19 @@ func TestDecodeQuery(t *testing.T) { } for k, tc := range []struct { - claims *Claims + claims *oidc.Claims familyName string givenName string lastName string }{ - {claims: &Claims{}, familyName: "first", givenName: "first", lastName: "last"}, - {claims: &Claims{FamilyName: "fam"}, familyName: "fam", givenName: "first", lastName: "last"}, - {claims: &Claims{FamilyName: "fam", GivenName: "giv"}, familyName: "fam", givenName: "giv", lastName: "last"}, - {claims: &Claims{FamilyName: "fam", GivenName: "giv", LastName: "las"}, familyName: "fam", givenName: "giv", lastName: "las"}, + {claims: &oidc.Claims{}, familyName: "first", givenName: "first", lastName: "last"}, + {claims: &oidc.Claims{FamilyName: "fam"}, familyName: "fam", givenName: "first", lastName: "last"}, + {claims: &oidc.Claims{FamilyName: "fam", GivenName: "giv"}, familyName: "fam", givenName: "giv", lastName: "last"}, + {claims: &oidc.Claims{FamilyName: "fam", GivenName: "giv", LastName: "las"}, familyName: "fam", givenName: "giv", lastName: "las"}, } { t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { - decodeQuery(query, tc.claims) + a := oidc.NewProviderApple(&oidc.Configuration{}, nil).(*oidc.ProviderApple) + a.DecodeQuery(query, tc.claims) assert.Equal(t, tc.familyName, tc.claims.FamilyName) assert.Equal(t, tc.givenName, tc.claims.GivenName) assert.Equal(t, tc.lastName, tc.claims.LastName) @@ -49,41 +51,7 @@ func TestDecodeQuery(t *testing.T) { } -//go:embed stub/jwk.json -var rawKey []byte - -//go:embed stub/jwks_public.json -var publicJWKS []byte - -// Just a public key set, to be able to test what happens if an ID token was issued by a different private key. -// -//go:embed stub/jwks_public2.json -var publicJWKS2 []byte - -type claims struct { - *jwt.RegisteredClaims - Email string `json:"email"` -} - -func createIdToken(t *testing.T, aud string) string { - key := &jwk.KeySpec{} - require.NoError(t, json.Unmarshal(rawKey, key)) - token := jwt.NewWithClaims(jwt.SigningMethodRS256, &claims{ - RegisteredClaims: &jwt.RegisteredClaims{ - Issuer: "https://appleid.apple.com", - Subject: "apple@ory.sh", - Audience: jwt.ClaimStrings{aud}, - ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), - }, - Email: "apple@ory.sh", - }) - token.Header["kid"] = key.KeyID - s, err := token.SignedString(key.Key) - require.NoError(t, err) - return s -} - -func TestVerify(t *testing.T) { +func TestAppleVerify(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(200) w.Write(publicJWKS) @@ -93,16 +61,21 @@ func TestVerify(t *testing.T) { w.WriteHeader(200) w.Write(publicJWKS2) })) - t.Run("case=successful verification", func(t *testing.T) { - apple := ProviderApple{ - jwksUrl: ts.URL, - ProviderGenericOIDC: &ProviderGenericOIDC{ - config: &Configuration{ - ClientID: "com.example.app", - }, - }, + makeClaims := func(aud string) jwt.RegisteredClaims { + return jwt.RegisteredClaims{ + Issuer: "https://appleid.apple.com", + Subject: "apple@ory.sh", + Audience: jwt.ClaimStrings{aud}, + ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), } - token := createIdToken(t, "com.example.app") + } + t.Run("case=successful verification", func(t *testing.T) { + _, reg := internal.NewFastRegistryWithMocks(t) + apple := oidc.NewProviderApple(&oidc.Configuration{ + ClientID: "com.example.app", + }, reg).(*oidc.ProviderApple) + apple.JWKSUrl = ts.URL + token := createIdToken(t, makeClaims("com.example.app")) c, err := apple.Verify(context.Background(), token) require.NoError(t, err) @@ -112,15 +85,12 @@ func TestVerify(t *testing.T) { }) t.Run("case=fails due to client_id mismatch", func(t *testing.T) { - apple := ProviderApple{ - jwksUrl: ts.URL, - ProviderGenericOIDC: &ProviderGenericOIDC{ - config: &Configuration{ - ClientID: "com.example.app", - }, - }, - } - token := createIdToken(t, "com.different-example.app") + _, reg := internal.NewFastRegistryWithMocks(t) + apple := oidc.NewProviderApple(&oidc.Configuration{ + ClientID: "com.example.app", + }, reg).(*oidc.ProviderApple) + apple.JWKSUrl = ts.URL + token := createIdToken(t, makeClaims("com.different-example.app")) _, err := apple.Verify(context.Background(), token) require.Error(t, err) @@ -128,15 +98,12 @@ func TestVerify(t *testing.T) { }) t.Run("case=fails due to jwks mismatch", func(t *testing.T) { - apple := ProviderApple{ - jwksUrl: tsOtherJWKS.URL, - ProviderGenericOIDC: &ProviderGenericOIDC{ - config: &Configuration{ - ClientID: "com.example.app", - }, - }, - } - token := createIdToken(t, "com.example.app") + _, reg := internal.NewFastRegistryWithMocks(t) + apple := oidc.NewProviderApple(&oidc.Configuration{ + ClientID: "com.example.app", + }, reg).(*oidc.ProviderApple) + apple.JWKSUrl = tsOtherJWKS.URL + token := createIdToken(t, makeClaims("com.example.app")) _, err := apple.Verify(context.Background(), token) require.Error(t, err) diff --git a/selfservice/strategy/oidc/provider_google.go b/selfservice/strategy/oidc/provider_google.go index dc084ec81b6b..54adda2b96c3 100644 --- a/selfservice/strategy/oidc/provider_google.go +++ b/selfservice/strategy/oidc/provider_google.go @@ -6,6 +6,7 @@ package oidc import ( "context" + "github.com/coreos/go-oidc" gooidc "github.com/coreos/go-oidc" "golang.org/x/oauth2" @@ -14,6 +15,7 @@ import ( type ProviderGoogle struct { *ProviderGenericOIDC + JWKSUrl string } func NewProviderGoogle( @@ -26,6 +28,7 @@ func NewProviderGoogle( config: config, reg: reg, }, + JWKSUrl: "https://www.googleapis.com/oauth2/v3/certs", } } @@ -66,3 +69,28 @@ func (g *ProviderGoogle) AuthCodeURLOptions(r ider) []oauth2.AuthCodeOption { return options } + +var _ IDTokenVerifier = new(ProviderGoogle) + +func (p *ProviderGoogle) Verify(ctx context.Context, rawIDToken string) (*Claims, error) { + keySet := oidc.NewRemoteKeySet(ctx, p.JWKSUrl) + verifier := oidc.NewVerifier("https://accounts.google.com", keySet, &oidc.Config{ + ClientID: p.config.ClientID, + }) + token, err := verifier.Verify(oidc.ClientContext(ctx, p.reg.HTTPClient(ctx).HTTPClient), rawIDToken) + if err != nil { + return nil, err + } + claims := &Claims{} + if err := token.Claims(claims); err != nil { + return nil, err + } + return claims, nil +} + +var _ NonceValidationSkipper = new(ProviderGoogle) + +func (a *ProviderGoogle) CanSkipNonce(c *Claims) bool { + // Not all SDKs support nonce validation, so we skip it if no nonce is present in the claims of the ID Token. + return c.Nonce == "" +} diff --git a/selfservice/strategy/oidc/provider_google_test.go b/selfservice/strategy/oidc/provider_google_test.go index f7cd21d77819..2d849948d391 100644 --- a/selfservice/strategy/oidc/provider_google_test.go +++ b/selfservice/strategy/oidc/provider_google_test.go @@ -5,9 +5,14 @@ package oidc_test import ( "context" + "net/http" + "net/http/httptest" "testing" + "time" + "github.com/golang-jwt/jwt/v4" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "golang.org/x/oauth2" "github.com/ory/kratos/internal" @@ -17,7 +22,7 @@ import ( ) func TestProviderGoogle_Scope(t *testing.T) { - _, reg := internal.NewFastRegistryWithMocks(t) + _, reg := internal.NewVeryFastRegistryWithoutDB(t) p := oidc.NewProviderGoogle(&oidc.Configuration{ Provider: "google", @@ -34,7 +39,7 @@ func TestProviderGoogle_Scope(t *testing.T) { } func TestProviderGoogle_AccessType(t *testing.T) { - _, reg := internal.NewFastRegistryWithMocks(t) + _, reg := internal.NewVeryFastRegistryWithoutDB(t) p := oidc.NewProviderGoogle(&oidc.Configuration{ Provider: "google", @@ -53,3 +58,66 @@ func TestProviderGoogle_AccessType(t *testing.T) { options := p.AuthCodeURLOptions(r) assert.Contains(t, options, oauth2.AccessTypeOffline) } + +func TestVerify(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(200) + w.Write(publicJWKS) + })) + + tsOtherJWKS := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(200) + w.Write(publicJWKS2) + })) + + makeClaims := func(aud string) jwt.RegisteredClaims { + return jwt.RegisteredClaims{ + Issuer: "https://accounts.google.com", + Subject: "apple@ory.sh", + Audience: jwt.ClaimStrings{aud}, + ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), + } + } + createProvider := func(jwksUrl string) *oidc.ProviderGoogle { + _, reg := internal.NewVeryFastRegistryWithoutDB(t) + p := oidc.NewProviderGoogle(&oidc.Configuration{ + Provider: "google", + ID: "valid", + ClientID: "com.example.app", + ClientSecret: "secret", + Mapper: "file://./stub/hydra.schema.json", + RequestedClaims: nil, + Scope: []string{"email", "profile", "offline_access"}, + }, reg).(*oidc.ProviderGoogle) + p.JWKSUrl = jwksUrl + return p + } + t.Run("case=successful verification", func(t *testing.T) { + p := createProvider(ts.URL) + token := createIdToken(t, makeClaims("com.example.app")) + + c, err := p.Verify(context.Background(), token) + require.NoError(t, err) + assert.Equal(t, "apple@ory.sh", c.Email) + assert.Equal(t, "apple@ory.sh", c.Subject) + assert.Equal(t, "https://accounts.google.com", c.Issuer) + }) + + t.Run("case=fails due to client_id mismatch", func(t *testing.T) { + p := createProvider(ts.URL) + token := createIdToken(t, makeClaims("com.different-example.app")) + + _, err := p.Verify(context.Background(), token) + require.Error(t, err) + assert.Equal(t, `oidc: expected audience "com.example.app" got ["com.different-example.app"]`, err.Error()) + }) + + t.Run("case=fails due to jwks mismatch", func(t *testing.T) { + p := createProvider(tsOtherJWKS.URL) + token := createIdToken(t, makeClaims("com.example.app")) + + _, err := p.Verify(context.Background(), token) + require.Error(t, err) + assert.Equal(t, "failed to verify signature: failed to verify id token signature", err.Error()) + }) +} diff --git a/selfservice/strategy/oidc/strategy_helper_test.go b/selfservice/strategy/oidc/strategy_helper_test.go index c708eb340022..0c92de45d0c7 100644 --- a/selfservice/strategy/oidc/strategy_helper_test.go +++ b/selfservice/strategy/oidc/strategy_helper_test.go @@ -17,13 +17,17 @@ import ( "testing" "time" + "github.com/golang-jwt/jwt/v4" "github.com/julienschmidt/httprouter" "github.com/phayes/freeport" "github.com/pkg/errors" + "github.com/rakutentech/jwk-go/jwk" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tidwall/gjson" + _ "embed" + "github.com/ory/dockertest/v3" "github.com/ory/dockertest/v3/docker" "github.com/ory/kratos/driver" @@ -344,3 +348,32 @@ func AssertSystemError(t *testing.T, errTS *httptest.Server, res *http.Response, assert.Equal(t, int64(code), gjson.GetBytes(body, "code").Int(), "%s", body) assert.Contains(t, gjson.GetBytes(body, "reason").String(), reason, "%s", body) } + +//go:embed stub/jwk.json +var rawKey []byte + +//go:embed stub/jwks_public.json +var publicJWKS []byte + +// Just a public key set, to be able to test what happens if an ID token was issued by a different private key. +// +//go:embed stub/jwks_public2.json +var publicJWKS2 []byte + +type claims struct { + *jwt.RegisteredClaims + Email string `json:"email"` +} + +func createIdToken(t *testing.T, cl jwt.RegisteredClaims) string { + key := &jwk.KeySpec{} + require.NoError(t, json.Unmarshal(rawKey, key)) + token := jwt.NewWithClaims(jwt.SigningMethodRS256, &claims{ + RegisteredClaims: &cl, + Email: "apple@ory.sh", + }) + token.Header["kid"] = key.KeyID + s, err := token.SignedString(key.Key) + require.NoError(t, err) + return s +} From e6af6db37ff5de33a656ce7804c813451395459d Mon Sep 17 00:00:00 2001 From: dreksx <110417569+dreksx@users.noreply.github.com> Date: Tue, 19 Sep 2023 08:55:59 +0300 Subject: [PATCH 096/282] feat: hook to revoke sessions after password changed (#3514) Currently, the Kratos system does not automatically log out or invalidate other active sessions when a user changes their password. This poses a significant security risk as it allows potentially unauthorized individuals to maintain access to the account even after the password has been updated. This PR provides the option to add the `revoke_active_sessions` hook to the actions sections of the selfservice settings. Closes #3513 --- embedx/config.schema.json | 3 + selfservice/flow/settings/hook.go | 10 +-- selfservice/hook/error.go | 2 +- selfservice/hook/session_destroyer.go | 12 ++++ selfservice/hook/session_destroyer_test.go | 12 ++++ selfservice/hook/verification.go | 2 +- selfservice/hook/verification_test.go | 2 +- selfservice/hook/web_hook.go | 2 +- selfservice/hook/web_hook_integration_test.go | 9 +-- .../strategy/password/settings_test.go | 68 +++++++++++++++++++ test/e2e/cypress/support/config.d.ts | 2 +- .../selfServiceAfterSettingsMethod.full.yaml | 1 + 12 files changed, 111 insertions(+), 14 deletions(-) diff --git a/embedx/config.schema.json b/embedx/config.schema.json index e7f5ba3ddf95..7ab6390538f2 100644 --- a/embedx/config.schema.json +++ b/embedx/config.schema.json @@ -733,6 +733,9 @@ "anyOf": [ { "$ref": "#/definitions/selfServiceWebHook" + }, + { + "$ref": "#/definitions/selfServiceSessionRevokerHook" } ] }, diff --git a/selfservice/flow/settings/hook.go b/selfservice/flow/settings/hook.go index c5e35610c7a2..b688fd0fc431 100644 --- a/selfservice/flow/settings/hook.go +++ b/selfservice/flow/settings/hook.go @@ -44,9 +44,9 @@ type ( PostHookPrePersistExecutorFunc func(w http.ResponseWriter, r *http.Request, a *Flow, s *identity.Identity) error PostHookPostPersistExecutor interface { - ExecuteSettingsPostPersistHook(w http.ResponseWriter, r *http.Request, a *Flow, s *identity.Identity) error + ExecuteSettingsPostPersistHook(w http.ResponseWriter, r *http.Request, a *Flow, id *identity.Identity, s *session.Session) error } - PostHookPostPersistExecutorFunc func(w http.ResponseWriter, r *http.Request, a *Flow, s *identity.Identity) error + PostHookPostPersistExecutorFunc func(w http.ResponseWriter, r *http.Request, a *Flow, id *identity.Identity, s *session.Session) error HooksProvider interface { PreSettingsHooks(ctx context.Context) []PreHookExecutor @@ -84,8 +84,8 @@ func (f PostHookPrePersistExecutorFunc) ExecuteSettingsPrePersistHook(w http.Res return f(w, r, a, s) } -func (f PostHookPostPersistExecutorFunc) ExecuteSettingsPostPersistHook(w http.ResponseWriter, r *http.Request, a *Flow, s *identity.Identity) error { - return f(w, r, a, s) +func (f PostHookPostPersistExecutorFunc) ExecuteSettingsPostPersistHook(w http.ResponseWriter, r *http.Request, a *Flow, id *identity.Identity, s *session.Session) error { + return f(w, r, a, id, s) } func PostHookPostPersistExecutorNames(e []PostHookPostPersistExecutor) []string { @@ -252,7 +252,7 @@ func (e *HookExecutor) PostSettingsHook(w http.ResponseWriter, r *http.Request, } for k, executor := range e.d.PostSettingsPostPersistHooks(r.Context(), settingsType) { - if err := executor.ExecuteSettingsPostPersistHook(w, r, ctxUpdate.Flow, i); err != nil { + if err := executor.ExecuteSettingsPostPersistHook(w, r, ctxUpdate.Flow, i, ctxUpdate.Session); err != nil { if errors.Is(err, ErrHookAbortFlow) { e.d.Logger(). WithRequest(r). diff --git a/selfservice/hook/error.go b/selfservice/hook/error.go index 9c9e1a97c03a..bb396578e5f8 100644 --- a/selfservice/hook/error.go +++ b/selfservice/hook/error.go @@ -60,7 +60,7 @@ func (e Error) ExecuteSettingsPrePersistHook(w http.ResponseWriter, r *http.Requ return e.err("ExecuteSettingsPrePersistHook", settings.ErrHookAbortFlow) } -func (e Error) ExecuteSettingsPostPersistHook(w http.ResponseWriter, r *http.Request, a *settings.Flow, s *identity.Identity) error { +func (e Error) ExecuteSettingsPostPersistHook(w http.ResponseWriter, r *http.Request, a *settings.Flow, id *identity.Identity, s *session.Session) error { return e.err("ExecuteSettingsPostPersistHook", settings.ErrHookAbortFlow) } diff --git a/selfservice/hook/session_destroyer.go b/selfservice/hook/session_destroyer.go index 6a797dc78dee..16f7aa11b435 100644 --- a/selfservice/hook/session_destroyer.go +++ b/selfservice/hook/session_destroyer.go @@ -7,8 +7,10 @@ import ( "context" "net/http" + "github.com/ory/kratos/identity" "github.com/ory/kratos/selfservice/flow/login" "github.com/ory/kratos/selfservice/flow/recovery" + "github.com/ory/kratos/selfservice/flow/settings" "github.com/ory/kratos/session" "github.com/ory/kratos/ui/node" "github.com/ory/x/otelx" @@ -16,6 +18,7 @@ import ( var _ login.PostHookExecutor = new(SessionDestroyer) var _ recovery.PostHookExecutor = new(SessionDestroyer) +var _ settings.PostHookPostPersistExecutor = new(SessionDestroyer) type ( sessionDestroyerDependencies interface { @@ -48,3 +51,12 @@ func (e *SessionDestroyer) ExecutePostRecoveryHook(_ http.ResponseWriter, r *htt return nil }) } + +func (e *SessionDestroyer) ExecuteSettingsPostPersistHook(_ http.ResponseWriter, r *http.Request, _ *settings.Flow, i *identity.Identity, s *session.Session) error { + return otelx.WithSpan(r.Context(), "selfservice.hook.SessionDestroyer.ExecuteSettingsPostPersistHook", func(ctx context.Context) error { + if _, err := e.r.SessionPersister().RevokeSessionsIdentityExcept(ctx, i.ID, s.ID); err != nil { + return err + } + return nil + }) +} diff --git a/selfservice/hook/session_destroyer_test.go b/selfservice/hook/session_destroyer_test.go index 6f52e93762f5..653f77111209 100644 --- a/selfservice/hook/session_destroyer_test.go +++ b/selfservice/hook/session_destroyer_test.go @@ -66,6 +66,18 @@ func TestSessionDestroyer(t *testing.T) { ) }, }, + { + name: "ExecuteSettingsPostPersistHook", + hook: func(i *identity.Identity) error { + return h.ExecuteSettingsPostPersistHook( + httptest.NewRecorder(), + new(http.Request), + nil, + i, + &session.Session{Identity: i}, + ) + }, + }, } { t.Run(tc.name, func(t *testing.T) { var i identity.Identity diff --git a/selfservice/hook/verification.go b/selfservice/hook/verification.go index e72f833faabf..e041164f372d 100644 --- a/selfservice/hook/verification.go +++ b/selfservice/hook/verification.go @@ -55,7 +55,7 @@ func (e *Verifier) ExecutePostRegistrationPostPersistHook(w http.ResponseWriter, }) } -func (e *Verifier) ExecuteSettingsPostPersistHook(w http.ResponseWriter, r *http.Request, f *settings.Flow, i *identity.Identity) error { +func (e *Verifier) ExecuteSettingsPostPersistHook(w http.ResponseWriter, r *http.Request, f *settings.Flow, i *identity.Identity, _ *session.Session) error { return otelx.WithSpan(r.Context(), "selfservice.hook.Verifier.ExecuteSettingsPostPersistHook", func(ctx context.Context) error { return e.do(w, r.WithContext(ctx), i, f, nil) }) diff --git a/selfservice/hook/verification_test.go b/selfservice/hook/verification_test.go index 3d4195b6e0ba..652df7bec61c 100644 --- a/selfservice/hook/verification_test.go +++ b/selfservice/hook/verification_test.go @@ -35,7 +35,7 @@ func TestVerifier(t *testing.T) { for k, hf := range map[string]func(*hook.Verifier, *identity.Identity, flow.Flow) error{ "settings": func(h *hook.Verifier, i *identity.Identity, f flow.Flow) error { return h.ExecuteSettingsPostPersistHook( - httptest.NewRecorder(), u, f.(*settings.Flow), i) + httptest.NewRecorder(), u, f.(*settings.Flow), i, &session.Session{ID: x.NewUUID(), Identity: i}) }, "register": func(h *hook.Verifier, i *identity.Identity, f flow.Flow) error { return h.ExecutePostRegistrationPostPersistHook( diff --git a/selfservice/hook/web_hook.go b/selfservice/hook/web_hook.go index 6a5a8f358e47..a21b3e2e444a 100644 --- a/selfservice/hook/web_hook.go +++ b/selfservice/hook/web_hook.go @@ -250,7 +250,7 @@ func (e *WebHook) ExecuteSettingsPreHook(_ http.ResponseWriter, req *http.Reques }) } -func (e *WebHook) ExecuteSettingsPostPersistHook(_ http.ResponseWriter, req *http.Request, flow *settings.Flow, id *identity.Identity) error { +func (e *WebHook) ExecuteSettingsPostPersistHook(_ http.ResponseWriter, req *http.Request, flow *settings.Flow, id *identity.Identity, _ *session.Session) error { if gjson.GetBytes(e.conf, "can_interrupt").Bool() || gjson.GetBytes(e.conf, "response.parse").Bool() { return nil } diff --git a/selfservice/hook/web_hook_integration_test.go b/selfservice/hook/web_hook_integration_test.go index 88632463d597..c6a030b2d394 100644 --- a/selfservice/hook/web_hook_integration_test.go +++ b/selfservice/hook/web_hook_integration_test.go @@ -248,7 +248,7 @@ func TestWebHooks(t *testing.T) { uc: "Post Settings Hook", createFlow: func() flow.Flow { return &settings.Flow{ID: x.NewUUID()} }, callWebHook: func(wh *hook.WebHook, req *http.Request, f flow.Flow, s *session.Session) error { - return wh.ExecuteSettingsPostPersistHook(nil, req, f.(*settings.Flow), s.Identity) + return wh.ExecuteSettingsPostPersistHook(nil, req, f.(*settings.Flow), s.Identity, s) }, expectedBody: func(req *http.Request, f flow.Flow, s *session.Session) string { return bodyWithFlowAndIdentity(req, f, s) @@ -568,7 +568,7 @@ func TestWebHooks(t *testing.T) { uc: "Post Settings Hook - no block", createFlow: func() flow.Flow { return &settings.Flow{ID: x.NewUUID()} }, callWebHook: func(wh *hook.WebHook, req *http.Request, f flow.Flow, s *session.Session) error { - return wh.ExecuteSettingsPostPersistHook(nil, req, f.(*settings.Flow), s.Identity) + return wh.ExecuteSettingsPostPersistHook(nil, req, f.(*settings.Flow), s.Identity, s) }, webHookResponse: func() (int, []byte) { return http.StatusOK, []byte{} @@ -590,7 +590,7 @@ func TestWebHooks(t *testing.T) { uc: "Post Settings Hook Post Persist - block has no effect", createFlow: func() flow.Flow { return &settings.Flow{ID: x.NewUUID()} }, callWebHook: func(wh *hook.WebHook, req *http.Request, f flow.Flow, s *session.Session) error { - return wh.ExecuteSettingsPostPersistHook(nil, req, f.(*settings.Flow), s.Identity) + return wh.ExecuteSettingsPostPersistHook(nil, req, f.(*settings.Flow), s.Identity, s) }, webHookResponse: func() (int, []byte) { return http.StatusBadRequest, webHookResponse @@ -789,8 +789,9 @@ func TestWebHooks(t *testing.T) { wh := hook.NewWebHook(&whDeps, conf) uuid := x.NewUUID() in := &identity.Identity{ID: uuid} + s := &session.Session{ID: x.NewUUID(), Identity: in} - postPersistErr := wh.ExecuteSettingsPostPersistHook(nil, req, f, in) + postPersistErr := wh.ExecuteSettingsPostPersistHook(nil, req, f, in, s) assert.NoError(t, postPersistErr) assert.Equal(t, in, &identity.Identity{ID: uuid}) diff --git a/selfservice/strategy/password/settings_test.go b/selfservice/strategy/password/settings_test.go index 502f7e5c98a1..3c5a3c9f9615 100644 --- a/selfservice/strategy/password/settings_test.go +++ b/selfservice/strategy/password/settings_test.go @@ -413,6 +413,74 @@ func TestSettings(t *testing.T) { }) }) + t.Run("description=should update the password and revoke other user sessions", func(t *testing.T) { + conf.MustSet(ctx, config.HookStrategyKey(config.ViperKeySelfServiceSettingsAfter, "password"), []config.SelfServiceHook{{Name: "revoke_active_sessions"}}) + t.Cleanup(func() { + conf.MustSet(ctx, config.ViperKeySelfServiceSettingsAfter, nil) + }) + + var check = func(t *testing.T, actual string, id *identity.Identity) { + assert.Equal(t, "success", gjson.Get(actual, "state").String(), "%s", actual) + assert.Empty(t, gjson.Get(actual, "ui.nodes.#(name==password).attributes.value").String(), "%s", actual) + + actualIdentity, err := reg.PrivilegedIdentityPool().GetIdentityConfidential(context.Background(), id.ID) + require.NoError(t, err) + cfg := string(actualIdentity.Credentials[identity.CredentialsTypePassword].Config) + assert.Contains(t, cfg, "hashed_password", "%+v", actualIdentity.Credentials) + require.Len(t, actualIdentity.Credentials[identity.CredentialsTypePassword].Identifiers, 1) + assert.Contains(t, actualIdentity.Credentials[identity.CredentialsTypePassword].Identifiers[0], "-4") + } + + var initClients = func(isAPI, isSPA bool, id *identity.Identity) (client1, client2 *http.Client) { + if isAPI { + client1 = testhelpers.NewHTTPClientWithIdentitySessionToken(t, reg, id) + client2 = testhelpers.NewHTTPClientWithIdentitySessionToken(t, reg, id) + return client1, client2 + } + client1 = testhelpers.NewHTTPClientWithIdentitySessionCookie(t, reg, id) + client2 = testhelpers.NewHTTPClientWithIdentitySessionCookie(t, reg, id) + + return client1, client2 + } + + var run = func(t *testing.T, isAPI, isSPA bool, id *identity.Identity) { + var payload = func(v url.Values) { + v.Set("method", "password") + v.Set("password", randx.MustString(16, randx.AlphaNum)) + } + + user1, user2 := initClients(isAPI, isSPA, id) + + actual := expectSuccess(t, isAPI, isSPA, user1, payload) + check(t, actual, id) + + // second client should be logged out + res, err := user2.Do(httpx.MustNewRequest("POST", publicTS.URL+settings.RouteSubmitFlow, strings.NewReader(url.Values{"foo": {"bar"}}.Encode()), "application/json")) + require.NoError(t, err) + res.Body.Close() + assert.EqualValues(t, http.StatusUnauthorized, res.StatusCode, "%+v", res.Request) + + // again change password via first client + actual = expectSuccess(t, isAPI, isSPA, user1, payload) + check(t, actual, id) + } + + t.Run("type=api", func(t *testing.T) { + id := newIdentityWithoutCredentials(x.NewUUID().String() + "@ory.sh") + run(t, true, false, id) + }) + + t.Run("type=spa", func(t *testing.T) { + id := newIdentityWithoutCredentials(x.NewUUID().String() + "@ory.sh") + run(t, false, true, id) + }) + + t.Run("type=browser", func(t *testing.T) { + id := newIdentityWithoutCredentials(x.NewUUID().String() + "@ory.sh") + run(t, false, false, id) + }) + }) + t.Run("case=should fail if no identifier was set in the schema", func(t *testing.T) { testhelpers.SetDefaultIdentitySchema(conf, "file://stub/missing-identifier.schema.json") diff --git a/test/e2e/cypress/support/config.d.ts b/test/e2e/cypress/support/config.d.ts index 1bac43efd7b3..790ef1e41ba9 100644 --- a/test/e2e/cypress/support/config.d.ts +++ b/test/e2e/cypress/support/config.d.ts @@ -679,7 +679,7 @@ export interface SelfServiceAfterSettings { } export interface SelfServiceAfterSettingsMethod { default_browser_return_url?: RedirectBrowsersToSetURLPerDefault - hooks?: SelfServiceWebHook[] + hooks?: (SelfServiceWebHook | SelfServiceSessionRevokerHook)[] } export interface SelfServiceWebHook { hook: "web_hook" diff --git a/test/schema/fixtures/config.schema.test.success/selfServiceAfterSettingsMethod.full.yaml b/test/schema/fixtures/config.schema.test.success/selfServiceAfterSettingsMethod.full.yaml index 9938abcf7de6..5e3a24ea95ed 100644 --- a/test/schema/fixtures/config.schema.test.success/selfServiceAfterSettingsMethod.full.yaml +++ b/test/schema/fixtures/config.schema.test.success/selfServiceAfterSettingsMethod.full.yaml @@ -1,3 +1,4 @@ default_browser_return_url: "#/definitions/defaultReturnTo" hooks: - "#/definitions/selfServiceWebHook" + - "#/definitions/selfServiceSessionRevokerHook" From fc057a8bed44d446d11882139b774c8460bb1e5c Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Tue, 19 Sep 2023 07:05:46 +0000 Subject: [PATCH 097/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b109b8f07a7d..d558e370c95c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-09-18)](#2023-09-18) +- [ (2023-09-19)](#2023-09-19) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -313,7 +313,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-09-18) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-09-19) ## Breaking Changes @@ -488,6 +488,9 @@ https://github.com/ory/kratos/pull/3480 - Add GetID member functions to RecoveryAddress and Credentials ([#3474](https://github.com/ory/kratos/issues/3474)) ([085d500](https://github.com/ory/kratos/commit/085d5002df27d455057d33bd2d93dfbca0de4872)) +- Add ID Token sign in with Google Android/iOS SDK + ([#3515](https://github.com/ory/kratos/issues/3515)) + ([055ed92](https://github.com/ory/kratos/commit/055ed9226d9d12f5142542be2e18438ff708c2e2)) - Add OpenTelemetry span for password hash comparison ([#3383](https://github.com/ory/kratos/issues/3383)) ([e3fcf0c](https://github.com/ory/kratos/commit/e3fcf0c31db9742ed61bcf783e37ee119ed19d42)) @@ -558,6 +561,19 @@ https://github.com/ory/kratos/pull/3480 - Emit error details when we find stray cookies in an API flow ([#3496](https://github.com/ory/kratos/issues/3496)) ([df74339](https://github.com/ory/kratos/commit/df74339802d98a292abb32806eca35fb2554960b)) +- Hook to revoke sessions after password changed + ([#3514](https://github.com/ory/kratos/issues/3514)) + ([e6af6db](https://github.com/ory/kratos/commit/e6af6db37ff5de33a656ce7804c813451395459d)), + closes [#3513](https://github.com/ory/kratos/issues/3513): + + Currently, the Kratos system does not automatically log out or invalidate + other active sessions when a user changes their password. This poses a + significant security risk as it allows potentially unauthorized individuals to + maintain access to the account even after the password has been updated. + + This PR provides the option to add the `revoke_active_sessions` hook to the + actions sections of the selfservice settings. + - Hot-reload CORS origins ([#3423](https://github.com/ory/kratos/issues/3423)) ([157d934](https://github.com/ory/kratos/commit/157d9345aeb04f371f9d85b70c89e8646e781333)) - Improve messages for easier i18n From 30ba71e9aa8ed97a414da7aec59a6f423a2a2d58 Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Tue, 19 Sep 2023 17:01:23 +0200 Subject: [PATCH 098/282] chore: update docker base images (#3521) --- .docker/Dockerfile-build | 10 +++++----- .docker/Dockerfile-debug | 2 +- .docker/Dockerfile-distroless-static | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.docker/Dockerfile-build b/.docker/Dockerfile-build index c75aed17db64..e50fc2104570 100644 --- a/.docker/Dockerfile-build +++ b/.docker/Dockerfile-build @@ -1,9 +1,9 @@ # syntax = docker/dockerfile:1-experimental # Workaround for https://github.com/GoogleContainerTools/distroless/issues/1342 -FROM golang:1.19-bullseye AS builder +FROM golang:1.21 AS builder RUN apt-get update && apt-get upgrade -y &&\ - mkdir -p /var/lib/sqlite + mkdir -p /var/lib/sqlite WORKDIR /go/src/github.com/ory/kratos @@ -25,11 +25,11 @@ ARG COMMIT ARG BUILD_DATE RUN --mount=type=cache,target=/root/.cache/go-build go build -tags sqlite \ - -ldflags="-X 'github.com/ory/kratos/driver/config.Version=${VERSION}' -X 'github.com/ory/kratos/driver/config.Date=${BUILD_DATE}' -X 'github.com/ory/kratos/driver/config.Commit=${COMMIT}'" \ - -o /usr/bin/kratos + -ldflags="-X 'github.com/ory/kratos/driver/config.Version=${VERSION}' -X 'github.com/ory/kratos/driver/config.Date=${BUILD_DATE}' -X 'github.com/ory/kratos/driver/config.Commit=${COMMIT}'" \ + -o /usr/bin/kratos ######################### -FROM gcr.io/distroless/base-nossl-debian11:nonroot AS runner +FROM gcr.io/distroless/base-nossl-debian12:nonroot AS runner COPY --from=builder --chown=nonroot:nonroot /var/lib/sqlite /var/lib/sqlite COPY --from=builder --chown=nonroot:nonroot /usr/bin/kratos /usr/bin/kratos diff --git a/.docker/Dockerfile-debug b/.docker/Dockerfile-debug index a5365a546da3..9ed036daebe7 100644 --- a/.docker/Dockerfile-debug +++ b/.docker/Dockerfile-debug @@ -1,4 +1,4 @@ -FROM golang:1.19-buster +FROM golang:1.21 ENV CGO_ENABLED 1 RUN apt-get update && apt-get install -y --no-install-recommends inotify-tools psmisc diff --git a/.docker/Dockerfile-distroless-static b/.docker/Dockerfile-distroless-static index 48cd03a868cc..569723315b89 100644 --- a/.docker/Dockerfile-distroless-static +++ b/.docker/Dockerfile-distroless-static @@ -1,4 +1,4 @@ -FROM gcr.io/distroless/static-debian11:nonroot +FROM gcr.io/distroless/static-debian12:nonroot COPY kratos /usr/bin/kratos EXPOSE 4433 4434 From 4c34c2417db0cb1f79b42db5f33544c90b38ad87 Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Wed, 20 Sep 2023 08:36:50 +0200 Subject: [PATCH 099/282] fix: wrong continue_with enum declaration (#3522) --- ...del_continue_with_set_ory_session_token.go | 2 +- .../model_continue_with_verification_ui.go | 2 +- ...del_continue_with_set_ory_session_token.go | 2 +- .../model_continue_with_verification_ui.go | 2 +- selfservice/flow/continue_with.go | 33 +++++++++++-------- selfservice/hook/session_issuer_test.go | 4 +-- spec/api.json | 12 +++---- spec/swagger.json | 12 +++---- 8 files changed, 36 insertions(+), 33 deletions(-) diff --git a/internal/client-go/model_continue_with_set_ory_session_token.go b/internal/client-go/model_continue_with_set_ory_session_token.go index 641718339f88..e091665d0d00 100644 --- a/internal/client-go/model_continue_with_set_ory_session_token.go +++ b/internal/client-go/model_continue_with_set_ory_session_token.go @@ -17,7 +17,7 @@ import ( // ContinueWithSetOrySessionToken Indicates that a session was issued, and the application should use this token for authenticated requests type ContinueWithSetOrySessionToken struct { - // Action will always be `set_ory_session_token` set_ory_session_token ContinueWithActionSetOrySessionToken show_verification_ui ContinueWithActionShowVerificationUI + // Action will always be `set_ory_session_token` set_ory_session_token ContinueWithActionSetOrySessionTokenString Action string `json:"action"` // Token is the token of the session OrySessionToken string `json:"ory_session_token"` diff --git a/internal/client-go/model_continue_with_verification_ui.go b/internal/client-go/model_continue_with_verification_ui.go index 987c32d18f2e..38ca91116469 100644 --- a/internal/client-go/model_continue_with_verification_ui.go +++ b/internal/client-go/model_continue_with_verification_ui.go @@ -17,7 +17,7 @@ import ( // ContinueWithVerificationUi Indicates, that the UI flow could be continued by showing a verification ui type ContinueWithVerificationUi struct { - // Action will always be `show_verification_ui` set_ory_session_token ContinueWithActionSetOrySessionToken show_verification_ui ContinueWithActionShowVerificationUI + // Action will always be `show_verification_ui` show_verification_ui ContinueWithActionShowVerificationUIString Action string `json:"action"` Flow ContinueWithVerificationUiFlow `json:"flow"` } diff --git a/internal/httpclient/model_continue_with_set_ory_session_token.go b/internal/httpclient/model_continue_with_set_ory_session_token.go index 641718339f88..e091665d0d00 100644 --- a/internal/httpclient/model_continue_with_set_ory_session_token.go +++ b/internal/httpclient/model_continue_with_set_ory_session_token.go @@ -17,7 +17,7 @@ import ( // ContinueWithSetOrySessionToken Indicates that a session was issued, and the application should use this token for authenticated requests type ContinueWithSetOrySessionToken struct { - // Action will always be `set_ory_session_token` set_ory_session_token ContinueWithActionSetOrySessionToken show_verification_ui ContinueWithActionShowVerificationUI + // Action will always be `set_ory_session_token` set_ory_session_token ContinueWithActionSetOrySessionTokenString Action string `json:"action"` // Token is the token of the session OrySessionToken string `json:"ory_session_token"` diff --git a/internal/httpclient/model_continue_with_verification_ui.go b/internal/httpclient/model_continue_with_verification_ui.go index 987c32d18f2e..38ca91116469 100644 --- a/internal/httpclient/model_continue_with_verification_ui.go +++ b/internal/httpclient/model_continue_with_verification_ui.go @@ -17,7 +17,7 @@ import ( // ContinueWithVerificationUi Indicates, that the UI flow could be continued by showing a verification ui type ContinueWithVerificationUi struct { - // Action will always be `show_verification_ui` set_ory_session_token ContinueWithActionSetOrySessionToken show_verification_ui ContinueWithActionShowVerificationUI + // Action will always be `show_verification_ui` show_verification_ui ContinueWithActionShowVerificationUIString Action string `json:"action"` Flow ContinueWithVerificationUiFlow `json:"flow"` } diff --git a/selfservice/flow/continue_with.go b/selfservice/flow/continue_with.go index 0b22b8b8ecb3..5d6eb6ff1619 100644 --- a/selfservice/flow/continue_with.go +++ b/selfservice/flow/continue_with.go @@ -14,24 +14,23 @@ import ( // swagger:model continueWith type ContinueWith any -// swagger:enum ContinueWithAction -type ContinueWithAction string +// swagger:enum ContinueWithActionSetOrySessionToken +type ContinueWithActionSetOrySessionToken string // #nosec G101 -- only a key constant const ( - ContinueWithActionSetOrySessionToken ContinueWithAction = "set_ory_session_token" - ContinueWithActionShowVerificationUI ContinueWithAction = "show_verification_ui" + ContinueWithActionSetOrySessionTokenString ContinueWithActionSetOrySessionToken = "set_ory_session_token" ) -var _ ContinueWith = new(ContinueWithSetToken) +var _ ContinueWith = new(ContinueWithSetOrySessionToken) // Indicates that a session was issued, and the application should use this token for authenticated requests // swagger:model continueWithSetOrySessionToken -type ContinueWithSetToken struct { +type ContinueWithSetOrySessionToken struct { // Action will always be `set_ory_session_token` // // required: true - Action ContinueWithAction `json:"action"` + Action ContinueWithActionSetOrySessionToken `json:"action"` // Token is the token of the session // @@ -39,17 +38,25 @@ type ContinueWithSetToken struct { OrySessionToken string `json:"ory_session_token"` } -func (ContinueWithSetToken) AppendTo(url.Values) url.Values { +func (ContinueWithSetOrySessionToken) AppendTo(url.Values) url.Values { return nil } -func NewContinueWithSetToken(t string) *ContinueWithSetToken { - return &ContinueWithSetToken{ - Action: ContinueWithActionSetOrySessionToken, +func NewContinueWithSetToken(t string) *ContinueWithSetOrySessionToken { + return &ContinueWithSetOrySessionToken{ + Action: ContinueWithActionSetOrySessionTokenString, OrySessionToken: t, } } +// swagger:enum ContinueWithActionShowVerificationUI +type ContinueWithActionShowVerificationUI string + +// #nosec G101 -- only a key constant +const ( + ContinueWithActionShowVerificationUIString ContinueWithActionShowVerificationUI = "show_verification_ui" +) + var _ ContinueWith = new(ContinueWithVerificationUI) // Indicates, that the UI flow could be continued by showing a verification ui @@ -59,7 +66,7 @@ type ContinueWithVerificationUI struct { // Action will always be `show_verification_ui` // // required: true - Action ContinueWithAction `json:"action"` + Action ContinueWithActionShowVerificationUI `json:"action"` // Flow contains the ID of the verification flow // // required: true @@ -86,7 +93,7 @@ type ContinueWithVerificationUIFlow struct { func NewContinueWithVerificationUI(f Flow, address, url string) *ContinueWithVerificationUI { return &ContinueWithVerificationUI{ - Action: ContinueWithActionShowVerificationUI, + Action: ContinueWithActionShowVerificationUIString, Flow: ContinueWithVerificationUIFlow{ ID: f.GetID(), VerifiableAddress: address, diff --git a/selfservice/hook/session_issuer_test.go b/selfservice/hook/session_issuer_test.go index db62ab2d643d..c58faec0fb2f 100644 --- a/selfservice/hook/session_issuer_test.go +++ b/selfservice/hook/session_issuer_test.go @@ -76,8 +76,8 @@ func TestSessionIssuer(t *testing.T) { require.Len(t, f.ContinueWithItems, 1) st := f.ContinueWithItems[0] - require.IsType(t, &flow.ContinueWithSetToken{}, st) - assert.NotEmpty(t, st.(*flow.ContinueWithSetToken).OrySessionToken) + require.IsType(t, &flow.ContinueWithSetOrySessionToken{}, st) + assert.NotEmpty(t, st.(*flow.ContinueWithSetOrySessionToken).OrySessionToken) got, err := reg.SessionPersister().GetSession(context.Background(), s.ID, session.ExpandNothing) require.NoError(t, err) diff --git a/spec/api.json b/spec/api.json index 06cd193d9edc..d163cd2d65f6 100644 --- a/spec/api.json +++ b/spec/api.json @@ -478,13 +478,12 @@ "description": "Indicates that a session was issued, and the application should use this token for authenticated requests", "properties": { "action": { - "description": "Action will always be `set_ory_session_token`\nset_ory_session_token ContinueWithActionSetOrySessionToken\nshow_verification_ui ContinueWithActionShowVerificationUI", + "description": "Action will always be `set_ory_session_token`\nset_ory_session_token ContinueWithActionSetOrySessionTokenString", "enum": [ - "set_ory_session_token", - "show_verification_ui" + "set_ory_session_token" ], "type": "string", - "x-go-enum-desc": "set_ory_session_token ContinueWithActionSetOrySessionToken\nshow_verification_ui ContinueWithActionShowVerificationUI" + "x-go-enum-desc": "set_ory_session_token ContinueWithActionSetOrySessionTokenString" }, "ory_session_token": { "description": "Token is the token of the session", @@ -501,13 +500,12 @@ "description": "Indicates, that the UI flow could be continued by showing a verification ui", "properties": { "action": { - "description": "Action will always be `show_verification_ui`\nset_ory_session_token ContinueWithActionSetOrySessionToken\nshow_verification_ui ContinueWithActionShowVerificationUI", + "description": "Action will always be `show_verification_ui`\nshow_verification_ui ContinueWithActionShowVerificationUIString", "enum": [ - "set_ory_session_token", "show_verification_ui" ], "type": "string", - "x-go-enum-desc": "set_ory_session_token ContinueWithActionSetOrySessionToken\nshow_verification_ui ContinueWithActionShowVerificationUI" + "x-go-enum-desc": "show_verification_ui ContinueWithActionShowVerificationUIString" }, "flow": { "$ref": "#/components/schemas/continueWithVerificationUiFlow" diff --git a/spec/swagger.json b/spec/swagger.json index 7d4321cf0b78..df1b67be4013 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -3519,13 +3519,12 @@ ], "properties": { "action": { - "description": "Action will always be `set_ory_session_token`\nset_ory_session_token ContinueWithActionSetOrySessionToken\nshow_verification_ui ContinueWithActionShowVerificationUI", + "description": "Action will always be `set_ory_session_token`\nset_ory_session_token ContinueWithActionSetOrySessionTokenString", "type": "string", "enum": [ - "set_ory_session_token", - "show_verification_ui" + "set_ory_session_token" ], - "x-go-enum-desc": "set_ory_session_token ContinueWithActionSetOrySessionToken\nshow_verification_ui ContinueWithActionShowVerificationUI" + "x-go-enum-desc": "set_ory_session_token ContinueWithActionSetOrySessionTokenString" }, "ory_session_token": { "description": "Token is the token of the session", @@ -3542,13 +3541,12 @@ ], "properties": { "action": { - "description": "Action will always be `show_verification_ui`\nset_ory_session_token ContinueWithActionSetOrySessionToken\nshow_verification_ui ContinueWithActionShowVerificationUI", + "description": "Action will always be `show_verification_ui`\nshow_verification_ui ContinueWithActionShowVerificationUIString", "type": "string", "enum": [ - "set_ory_session_token", "show_verification_ui" ], - "x-go-enum-desc": "set_ory_session_token ContinueWithActionSetOrySessionToken\nshow_verification_ui ContinueWithActionShowVerificationUI" + "x-go-enum-desc": "show_verification_ui ContinueWithActionShowVerificationUIString" }, "flow": { "$ref": "#/definitions/continueWithVerificationUiFlow" From 32d8306e82224cf6beda239e87b62e2a8f25bfb4 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Wed, 20 Sep 2023 07:42:34 +0000 Subject: [PATCH 100/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d558e370c95c..59111de58ac4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-09-19)](#2023-09-19) +- [ (2023-09-20)](#2023-09-20) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -313,7 +313,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-09-19) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-09-20) ## Breaking Changes @@ -458,6 +458,9 @@ https://github.com/ory/kratos/pull/3480 - Use registry client for schema loading ([#3471](https://github.com/ory/kratos/issues/3471)) ([3a57726](https://github.com/ory/kratos/commit/3a577269980213e4415fd5fa713882990e2e7640)) +- Wrong continue_with enum declaration + ([#3522](https://github.com/ory/kratos/issues/3522)) + ([4c34c24](https://github.com/ory/kratos/commit/4c34c2417db0cb1f79b42db5f33544c90b38ad87)) ### Documentation From 75031e67bc82a820a6aba134115e8d5f93303638 Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Wed, 20 Sep 2023 18:01:13 +0200 Subject: [PATCH 101/282] feat: add event (#3524) --- session/manager_http.go | 6 ++++++ x/events/events.go | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/session/manager_http.go b/session/manager_http.go index 252a0dc285d7..e1c31f94f03f 100644 --- a/session/manager_http.go +++ b/session/manager_http.go @@ -9,6 +9,10 @@ import ( "net/url" "time" + "go.opentelemetry.io/otel/trace" + + "github.com/ory/kratos/x/events" + "github.com/ory/kratos/selfservice/flow" "github.com/ory/kratos/selfservice/sessiontokenexchange" "github.com/ory/kratos/ui/node" @@ -240,6 +244,8 @@ func (s *ManagerHTTP) FetchFromRequest(ctx context.Context, r *http.Request) (_ return nil, err } + trace.SpanFromContext(ctx).AddEvent(events.NewSessionChecked(ctx, se.ID, se.IdentityID)) + if !se.IsActive() { return nil, errors.WithStack(NewErrNoActiveSessionFound()) } diff --git a/x/events/events.go b/x/events/events.go index 83da68e98558..35992663319f 100644 --- a/x/events/events.go +++ b/x/events/events.go @@ -18,6 +18,7 @@ const ( SessionIssued semconv.Event = "SessionIssued" SessionChanged semconv.Event = "SessionChanged" SessionRevoked semconv.Event = "SessionRevoked" + SessionChecked semconv.Event = "SessionChecked" SessionTokenizedAsJWT semconv.Event = "SessionTokenizedAsJWT" RegistrationFailed semconv.Event = "RegistrationFailed" RegistrationSucceeded semconv.Event = "RegistrationSucceeded" @@ -240,6 +241,17 @@ func NewSessionRevoked(ctx context.Context, sessionID, identityID uuid.UUID) (st ) } +func NewSessionChecked(ctx context.Context, sessionID, identityID uuid.UUID) (string, trace.EventOption) { + return SessionChecked.String(), + trace.WithAttributes( + append( + semconv.AttributesFromContext(ctx), + semconv.AttrIdentityID(identityID), + attrSessionID(sessionID), + )..., + ) +} + func NewSessionJWTIssued(ctx context.Context, sessionID, identityID uuid.UUID, ttl time.Duration) (string, trace.EventOption) { return SessionTokenizedAsJWT.String(), trace.WithAttributes( From a37f6bddc48443b2fc464699fa5c2922f64d81f6 Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Wed, 20 Sep 2023 18:41:17 +0200 Subject: [PATCH 102/282] feat: fine-grained hooks for all available flow methods (#3519) Adds fine-grained hook configurations to the post-settings flow for methods totp, webauthn, lookup_secret and the post-login flow for totp, lookup_secret, and code. --- embedx/config.schema.json | 41 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/embedx/config.schema.json b/embedx/config.schema.json index 7ab6390538f2..5ad71652f665 100644 --- a/embedx/config.schema.json +++ b/embedx/config.schema.json @@ -721,6 +721,27 @@ "additionalItems": false }, "selfServiceAfterSettingsMethod": { + "type": "object", + "additionalProperties": false, + "properties": { + "default_browser_return_url": { + "$ref": "#/definitions/defaultReturnTo" + }, + "hooks": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/selfServiceWebHook" + } + ] + }, + "uniqueItems": true, + "additionalItems": false + } + } + }, + "selfServiceAfterSettingsAuthMethod": { "type": "object", "additionalProperties": false, "properties": { @@ -843,7 +864,19 @@ "$ref": "#/definitions/defaultReturnTo" }, "password": { - "$ref": "#/definitions/selfServiceAfterSettingsMethod" + "$ref": "#/definitions/selfServiceAfterSettingsAuthMethod" + }, + "totp": { + "$ref": "#/definitions/selfServiceAfterSettingsAuthMethod" + }, + "oidc": { + "$ref": "#/definitions/selfServiceAfterSettingsAuthMethod" + }, + "webauthn": { + "$ref": "#/definitions/selfServiceAfterSettingsAuthMethod" + }, + "lookup_secret": { + "$ref": "#/definitions/selfServiceAfterSettingsAuthMethod" }, "profile": { "$ref": "#/definitions/selfServiceAfterSettingsMethod" @@ -881,6 +914,12 @@ "code": { "$ref": "#/definitions/selfServiceAfterDefaultLoginMethod" }, + "totp": { + "$ref": "#/definitions/selfServiceAfterDefaultLoginMethod" + }, + "lookup_secret": { + "$ref": "#/definitions/selfServiceAfterDefaultLoginMethod" + }, "hooks": { "type": "array", "items": { From 83bfb2d2a9c69bf3a3442500b9484c1a69f8c794 Mon Sep 17 00:00:00 2001 From: Patrik Date: Thu, 21 Sep 2023 08:34:46 +0200 Subject: [PATCH 103/282] fix: error handling on identity import (#3520) When importing identities without any traits, or with malformed traits, 500s are returned. This improves the error handling and messaging. --- go.mod | 1 - go.sum | 4 --- ...e_able_to_import_users-without_traits.json | 7 +++++ identity/handler.go | 2 +- identity/handler_test.go | 26 ++++++++++++++++--- identity/validator.go | 10 ++++++- schema/validator.go | 7 ++++- 7 files changed, 45 insertions(+), 12 deletions(-) create mode 100644 identity/.snapshots/TestHandler-case=should_be_able_to_import_users-without_traits.json diff --git a/go.mod b/go.mod index a35d9afc7289..dd4618fbb2b1 100644 --- a/go.mod +++ b/go.mod @@ -146,7 +146,6 @@ require ( github.com/felixge/httpsnoop v1.0.3 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fxamacker/cbor/v2 v2.4.0 // indirect - github.com/go-bindata/go-bindata v3.1.2+incompatible // indirect github.com/go-crypt/x v0.2.1 // indirect github.com/go-jose/go-jose/v3 v3.0.0 // indirect github.com/go-logr/logr v1.2.3 // indirect diff --git a/go.sum b/go.sum index b8f3117cbc72..fb96c9cdac9f 100644 --- a/go.sum +++ b/go.sum @@ -212,8 +212,6 @@ github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-bindata/go-bindata v3.1.2+incompatible h1:5vjJMVhowQdPzjE1LdxyFF7YFTXg5IgGVW4gBr5IbvE= -github.com/go-bindata/go-bindata v3.1.2+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo= github.com/go-crypt/crypt v0.2.9 h1:5gWWTId2Qyqs9ROIsegt5pnqo9wUSRLbhpkR6JSftjg= github.com/go-crypt/crypt v0.2.9/go.mod h1:JjzdTYE2mArb6nBoIvvpF7o46/rK/1pfmlArCRMTFUk= github.com/go-crypt/x v0.2.1 h1:OGw78Bswme9lffCOX6tyuC280ouU5391glsvThMtM5U= @@ -849,8 +847,6 @@ github.com/ory/nosurf v1.2.7 h1:YrHrbSensQyU6r6HT/V5+HPdVEgrOTMJiLoJABSBOp4= github.com/ory/nosurf v1.2.7/go.mod h1:d4L3ZBa7Amv55bqxCBtCs63wSlyaiCkWVl4vKf3OUxA= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2 h1:zm6sDvHy/U9XrGpixwHiuAwpp0Ock6khSVHkrv6lQQU= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/ory/x v0.0.588 h1:3qoC1d7qTKnMLwS3Os7KVbDLeSOUHXON8hUFuGUoScQ= -github.com/ory/x v0.0.588/go.mod h1:ksLBEd6iW6czGpE6eNA0gCIxO1FFeqIxCZgsgwNrzMM= github.com/ory/x v0.0.589 h1:ZNQ+nBzTCm3jI2ZZY/1kGWSE4jEtyvDYWu0ScfLgzac= github.com/ory/x v0.0.589/go.mod h1:ksLBEd6iW6czGpE6eNA0gCIxO1FFeqIxCZgsgwNrzMM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= diff --git a/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-without_traits.json b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-without_traits.json new file mode 100644 index 000000000000..32e6b205f4a3 --- /dev/null +++ b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-without_traits.json @@ -0,0 +1,7 @@ +{ + "schema_id": "default", + "state": "active", + "traits": {}, + "metadata_public": null, + "metadata_admin": null +} diff --git a/identity/handler.go b/identity/handler.go index 795824fcf046..a878a0b0c31f 100644 --- a/identity/handler.go +++ b/identity/handler.go @@ -409,7 +409,7 @@ type AdminCreateIdentityImportCredentialsOidcProvider struct { func (h *Handler) create(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { var cr CreateIdentityBody if err := jsonx.NewStrictDecoder(r.Body).Decode(&cr); err != nil { - h.r.Writer().WriteErrorCode(w, r, http.StatusBadRequest, errors.WithStack(err)) + h.r.Writer().WriteError(w, r, errors.WithStack(herodot.ErrBadRequest.WithError(err.Error()))) return } diff --git a/identity/handler_test.go b/identity/handler_test.go index 399b6f0cb1ff..934ca62946b0 100644 --- a/identity/handler_test.go +++ b/identity/handler_test.go @@ -89,9 +89,15 @@ func TestHandler(t *testing.T) { send := func(t *testing.T, base *httptest.Server, method, href string, expectCode int, send interface{}) gjson.Result { t.Helper() var b bytes.Buffer - if send != nil { - require.NoError(t, json.NewEncoder(&b).Encode(send)) + switch raw := send.(type) { + case json.RawMessage: + b = *bytes.NewBuffer(raw) + default: + if send != nil { + require.NoError(t, json.NewEncoder(&b).Encode(send)) + } } + req, err := http.NewRequest(method, base.URL+href, &b) require.NoError(t, err) req.Header.Set("Content-Type", "application/json") @@ -190,7 +196,19 @@ func TestHandler(t *testing.T) { actual, err := reg.PrivilegedIdentityPool().GetIdentityConfidential(ctx, uuid.FromStringOrNil(res.Get("id").String())) require.NoError(t, err) - snapshotx.SnapshotTExceptMatchingKeys(t, identity.WithCredentialsAndAdminMetadataInJSON(*actual), ignoreDefault) + snapshotx.SnapshotT(t, identity.WithCredentialsAndAdminMetadataInJSON(*actual), snapshotx.ExceptNestedKeys(ignoreDefault...)) + }) + + t.Run("without traits", func(t *testing.T) { + res := send(t, adminTS, "POST", "/identities", http.StatusCreated, json.RawMessage("{}")) + actual, err := reg.PrivilegedIdentityPool().GetIdentityConfidential(ctx, uuid.FromStringOrNil(res.Get("id").String())) + require.NoError(t, err) + + snapshotx.SnapshotT(t, identity.WithCredentialsAndAdminMetadataInJSON(*actual), snapshotx.ExceptNestedKeys(ignoreDefault...)) + }) + + t.Run("with malformed traits", func(t *testing.T) { + send(t, adminTS, "POST", "/identities", http.StatusBadRequest, json.RawMessage(`{"traits": not valid JSON}`)) }) t.Run("with cleartext password and oidc credentials", func(t *testing.T) { @@ -276,7 +294,7 @@ func TestHandler(t *testing.T) { actual, err := reg.PrivilegedIdentityPool().GetIdentityConfidential(ctx, uuid.FromStringOrNil(res.Get("id").String())) require.NoError(t, err) - snapshotx.SnapshotTExceptMatchingKeys(t, identity.WithCredentialsAndAdminMetadataInJSON(*actual), append(ignoreDefault, "hashed_password")) + snapshotx.SnapshotT(t, identity.WithCredentialsAndAdminMetadataInJSON(*actual), snapshotx.ExceptNestedKeys(ignoreDefault...), snapshotx.ExceptNestedKeys("hashed_password")) require.NoError(t, hash.Compare(ctx, []byte(tt.pass), []byte(gjson.GetBytes(actual.Credentials[identity.CredentialsTypePassword].Config, "hashed_password").String()))) }) diff --git a/identity/validator.go b/identity/validator.go index bd7b851d58c9..878162e0bd7b 100644 --- a/identity/validator.go +++ b/identity/validator.go @@ -6,6 +6,10 @@ package identity import ( "context" + "github.com/pkg/errors" + + "github.com/ory/herodot" + "github.com/tidwall/sjson" "github.com/ory/kratos/driver/config" @@ -47,9 +51,13 @@ func (v *Validator) ValidateWithRunner(ctx context.Context, i *Identity, runners return err } + if len(i.Traits) == 0 { + i.Traits = []byte(`{}`) + } + traits, err := sjson.SetRawBytes([]byte(`{}`), "traits", i.Traits) if err != nil { - return err + return errors.WithStack(herodot.ErrBadRequest.WithError(err.Error())) } return v.v.Validate(ctx, s.URL.String(), traits, schema.WithExtensionRunner(runner)) diff --git a/schema/validator.go b/schema/validator.go index 19a51672c943..73a1e77e732a 100644 --- a/schema/validator.go +++ b/schema/validator.go @@ -68,7 +68,12 @@ func (v *Validator) Validate( return errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Unable to parse validate JSON object against JSON schema.").WithDebugf("%s", err)) } - if err := schema.Validate(bytes.NewBuffer(document)); err != nil { + // we decode explicitly here, so we can handle the error, and it is not lost in the schema validation + dec, err := jsonschema.DecodeJSON(bytes.NewBuffer(document)) + if err != nil { + return errors.WithStack(herodot.ErrBadRequest.WithReasonf("Unable to parse validate JSON object against JSON schema.").WithDebugf("%s", err)) + } + if err := schema.ValidateInterface(dec); err != nil { return errors.WithStack(err) } From 0ec037ab298ed28fb0ac84db6a4d2b14b81e57df Mon Sep 17 00:00:00 2001 From: Henning Perl Date: Thu, 21 Sep 2023 10:14:52 +0200 Subject: [PATCH 104/282] feat: support for B2B SSO (#3489) --- .gitignore | 1 + .grype.yaml | 1 + cmd/identities/get_test.go | 2 + driver/registry.go | 29 +++++++-- driver/registry_default.go | 63 ++++++++++++++----- embedx/config.schema.json | 43 +++++++++++++ ...eartext_password_and_oidc_credentials.json | 3 +- ...users-with_hashed_passwords-hash=SSHA.json | 3 +- ...rs-with_hashed_passwords-hash=SSHA256.json | 3 +- ...rs-with_hashed_passwords-hash=SSHA512.json | 3 +- ...rs-with_hashed_passwords-hash=argon2i.json | 3 +- ...s-with_hashed_passwords-hash=argon2id.json | 3 +- ...rs-with_hashed_passwords-hash=bcrypt2.json | 3 +- ..._users-with_hashed_passwords-hash=md5.json | 3 +- ...ers-with_hashed_passwords-hash=pkbdf2.json | 3 +- ...ers-with_hashed_passwords-hash=scrypt.json | 3 +- ..._import_users-without_any_credentials.json | 3 +- ...less_and_multiple_fido_mfa_type-admin.json | 3 +- ...ess_and_multiple_fido_mfa_type-public.json | 3 +- ...move_webauthn_passwordless_type-admin.json | 3 +- ...ove_webauthn_passwordless_type-public.json | 3 +- ...tities-case=success-assert=identity_0.json | 1 + ...tities-case=success-assert=identity_1.json | 1 + ...tities-case=success-assert=identity_2.json | 1 + ...tities-case=success-assert=identity_3.json | 1 + ...ord_and_webauthn_credentials_included.json | 3 +- ...ty_with_password_credentials_included.json | 3 +- ...identity_without_credentials_included.json | 3 +- ...tUpgradeCredentials-empty_credentials.json | 3 +- ...radeCredentials-type=webauthn-from=v0.json | 3 +- ...radeCredentials-type=webauthn-from=v1.json | 3 +- identity/credentials_oidc.go | 14 ++++- identity/credentials_oidc_test.go | 6 +- identity/identity.go | 10 ++- internal/client-go/api_frontend.go | 16 +++++ internal/client-go/model_identity.go | 49 ++++++++++++++- ...odel_identity_credentials_oidc_provider.go | 36 +++++++++++ internal/client-go/model_login_flow.go | 47 ++++++++++++++ internal/client-go/model_registration_flow.go | 47 ++++++++++++++ .../model_session_authentication_method.go | 40 +++++++++++- internal/httpclient/api_frontend.go | 16 +++++ internal/httpclient/model_identity.go | 49 ++++++++++++++- ...odel_identity_credentials_oidc_provider.go | 36 +++++++++++ internal/httpclient/model_login_flow.go | 47 ++++++++++++++ .../httpclient/model_registration_flow.go | 47 ++++++++++++++ .../model_session_authentication_method.go | 40 +++++++++++- ..._buildInsertQueryArgs-case=Identities.json | 5 +- .../0149ce5f-76a8-4efe-b2e3-431b8c6cceb6.json | 3 +- .../0149ce5f-76a8-4efe-b2e3-431b8c6cceb7.json | 3 +- .../196d8c1e-4f04-40f0-94b3-5ec43996b28a.json | 3 +- .../28ff0031-190b-4253-bd15-14308dec013e.json | 3 +- .../2ae6a5a7-2983-49e7-a4d8-7740b37c88cb.json | 3 +- .../308929d3-41a2-43fe-a33c-75308539d841.json | 3 +- .../359963ec-b09b-4ea0-aece-fb4dd95f304a.json | 3 +- .../5ff66179-c240-4703-b0d8-494592cefff5.json | 3 +- .../a251ebc2-880c-4f76-a8f3-38e6940eab0e.json | 3 +- .../d7b9addb-ac15-4bc2-9fa5-562e0bf48755.json | 3 +- .../ed253b2c-48ed-4c58-9b6f-1dc963c30a66.json | 3 +- .../00b1517f-2467-4aaf-b0a5-82b4a27dcaf5.json | 1 + .../0bc96cc9-dda4-4700-9e42-35731f2af91e.json | 1 + .../1fb23c75-b809-42cc-8984-6ca2d0a1192f.json | 1 + .../202c1981-1e25-47f0-8764-75ad506c2bec.json | 1 + .../349c945a-60f8-436a-a301-7a42c92604f9.json | 1 + .../38caf592-b042-4551-b92f-8d5223c2a4e2.json | 1 + .../3a9ea34f-0f12-469b-9417-3ae5795a7baa.json | 1 + .../43c99182-bb67-47e1-b564-bb23bd8d4393.json | 1 + .../47edd3a8-0998-4779-9469-f4b8ee4430df.json | 1 + .../56d94e8b-8a5d-4b7f-8a6e-3259d2b2903e.json | 1 + .../6d387820-f2f4-4f9f-9980-a90d89e7811f.json | 1 + .../916ded11-aa64-4a27-b06e-96e221a509d7.json | 1 + .../99974ce6-388c-4669-a95a-7757ee724020.json | 1 + .../b1fac7fb-d016-4a06-a7fe-e4eab2a0429f.json | 1 + .../cccccccc-dda4-4700-9e42-35731f2af911.json | 1 + .../cccccccc-dda4-4700-9e42-35731f2af91e.json | 1 + .../d6aa1f23-88c9-4b9b-a850-392f48c7f9e8.json | 1 + .../05a7f09d-4ef3-41fb-958a-6ad74584b36a.json | 1 + .../22d58184-b97d-44a5-bbaf-0aa8b4000d81.json | 1 + .../2bf132e0-5d40-4df9-9a11-9106e5333735.json | 1 + .../696e7022-c466-44f6-89c6-8cf93c06a62a.json | 1 + .../69c80296-36cd-4afc-921a-15369cac5bf0.json | 1 + .../87fa3f43-5155-42b4-a1ad-174c2595fdaf.json | 1 + .../8ef215a9-e8d5-43b3-9aa3-cb4333562e36.json | 1 + .../8f32efdc-f6fc-4c27-a3c2-579d109eff60.json | 1 + .../9edcf051-1cd0-44cc-bd2f-6ac21f0c24dd.json | 1 + .../e2150cdc-23ac-4940-a240-6c79c27ab029.json | 1 + .../ef18b06e-4700-4021-9949-ef783cd86be1.json | 1 + .../ef18b06e-4700-4021-9949-ef783cd86be8.json | 1 + .../f1b5ed18-113a-4a98-aae7-d4eba007199c.json | 1 + .../068f6bb6-d15f-436d-94f7-b3fd0489c9ef.json | 3 +- .../7458af86-c1d8-401c-978a-8da89133f78b.json | 3 +- .../7458af86-c1d8-401c-978a-8da89133f98b.json | 3 +- .../8571e374-38f2-4f46-8ad3-b9d914e174d3.json | 3 +- .../dcde5aaa-f789-4d3d-ae1f-76da8d57e67c.json | 3 +- .../f38cdebe-e567-42c9-a562-1bd4dee40998.json | 3 +- .../194c5b05-0487-4a11-bcbc-f301c9ff9678.json | 3 +- .../19ede218-928c-4e02-ab49-b76e12b34f31.json | 3 +- .../19ede218-928c-4e02-ab49-b76e12b34f32.json | 3 +- .../21c5f714-3089-49d2-b387-f244d4dd9e00.json | 3 +- .../74fd6c53-7651-453e-90b8-2c5adbf911bb.json | 3 +- .../77fe4fb3-2d4e-4532-b568-c44b0aece0aa.json | 3 +- .../8248bb5d-8ef7-45e3-8e07-9e2003dd5352.json | 3 +- .../90b4f970-b9ae-42bc-a0a7-73ec750e0aa1.json | 3 +- .../a79bfcf1-68ae-49de-8b23-4f96921b8341.json | 3 +- .../aeba85bd-1a8c-44bf-8fc3-3be83c01a3dc.json | 3 +- .../cdfd1eed-34a4-491d-ad0a-7579d3a0a7ba.json | 3 +- ...7085000000000_add_organization_id.down.sql | 3 + ...000000000_add_organization_id.mysql.up.sql | 3 + ...907085000000000_add_organization_id.up.sql | 3 + selfservice/flow/login/flow.go | 5 +- selfservice/flow/login/handler.go | 21 ++++++- selfservice/flow/login/strategy.go | 4 +- selfservice/flow/registration/flow.go | 5 +- selfservice/flow/registration/handler.go | 19 +++++- selfservice/flow/registration/hook.go | 5 +- selfservice/flow/registration/strategy.go | 4 +- ...te_identity_fields-case=body_is_empty.json | 3 +- ...e=identity_has_updated_admin_metadata.json | 3 +- ...=identity_has_updated_public_metadata.json | 3 +- ...entity_has_updated_recovery_addresses.json | 3 +- ...ields-case=identity_has_updated_state.json | 3 +- ...elds-case=identity_has_updated_traits.json | 3 +- ...entity_has_updated_verified_addresses.json | 3 +- ...ds-case=identity_is_present_but_empty.json | 3 +- selfservice/strategy/code/strategy.go | 4 +- selfservice/strategy/link/strategy.go | 4 +- selfservice/strategy/lookup/strategy.go | 8 +-- selfservice/strategy/oidc/provider_apple.go | 2 +- selfservice/strategy/oidc/provider_auth0.go | 2 +- selfservice/strategy/oidc/provider_config.go | 19 ++++-- .../strategy/oidc/provider_dingtalk.go | 4 +- selfservice/strategy/oidc/provider_discord.go | 4 +- .../strategy/oidc/provider_facebook.go | 2 +- .../strategy/oidc/provider_generic_oidc.go | 4 +- selfservice/strategy/oidc/provider_github.go | 4 +- .../strategy/oidc/provider_github_app.go | 4 +- selfservice/strategy/oidc/provider_gitlab.go | 2 +- selfservice/strategy/oidc/provider_google.go | 2 +- selfservice/strategy/oidc/provider_lark.go | 2 +- .../strategy/oidc/provider_linkedin.go | 4 +- .../strategy/oidc/provider_microsoft.go | 2 +- selfservice/strategy/oidc/provider_netid.go | 2 +- selfservice/strategy/oidc/provider_patreon.go | 4 +- selfservice/strategy/oidc/provider_slack.go | 4 +- selfservice/strategy/oidc/provider_spotify.go | 4 +- selfservice/strategy/oidc/provider_test.go | 4 +- selfservice/strategy/oidc/provider_vk.go | 4 +- selfservice/strategy/oidc/provider_yandex.go | 4 +- selfservice/strategy/oidc/strategy.go | 29 +++++---- selfservice/strategy/oidc/strategy_login.go | 11 ++-- .../strategy/oidc/strategy_registration.go | 19 ++++-- .../strategy/oidc/strategy_settings.go | 4 +- selfservice/strategy/password/strategy.go | 4 +- selfservice/strategy/profile/strategy.go | 4 +- selfservice/strategy/totp/strategy.go | 8 +-- ...ebauthn_login_is_invalid-type=browser.json | 1 + ...if_webauthn_login_is_invalid-type=spa.json | 1 + selfservice/strategy/webauthn/strategy.go | 8 +-- session/session.go | 13 +++- spec/api.json | 29 +++++++++ spec/swagger.json | 38 +++++++++++ 160 files changed, 1003 insertions(+), 186 deletions(-) create mode 100644 persistence/sql/migrations/sql/20230907085000000000_add_organization_id.down.sql create mode 100644 persistence/sql/migrations/sql/20230907085000000000_add_organization_id.mysql.up.sql create mode 100644 persistence/sql/migrations/sql/20230907085000000000_add_organization_id.up.sql diff --git a/.gitignore b/.gitignore index 6525a0dcfb9b..d91c2fb7d111 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ cover.out .idea/ tmp/ +ddl/ .DS_Store /kratos packrd/ diff --git a/.grype.yaml b/.grype.yaml index 4621efcfbc3c..d9727bf1ecf9 100644 --- a/.grype.yaml +++ b/.grype.yaml @@ -3,3 +3,4 @@ ignore: - vulnerability: CVE-2015-5237 - vulnerability: CVE-2022-30065 - vulnerability: CVE-2023-2650 + - vulnerability: CVE-2023-4813 \ No newline at end of file diff --git a/cmd/identities/get_test.go b/cmd/identities/get_test.go index b8f09e7f039f..eafe31520828 100644 --- a/cmd/identities/get_test.go +++ b/cmd/identities/get_test.go @@ -79,6 +79,7 @@ func TestGetCmd(t *testing.T) { InitialAccessToken: transform(accessToken + "0"), InitialRefreshToken: transform(refreshToken + "0"), InitialIDToken: transform(idToken + "0"), + Organization: "foo-org-id", }, { Subject: "baz", @@ -86,6 +87,7 @@ func TestGetCmd(t *testing.T) { InitialAccessToken: transform(accessToken + "1"), InitialRefreshToken: transform(refreshToken + "1"), InitialIDToken: transform(idToken + "1"), + Organization: "bar-org-id", }, }}), } diff --git a/driver/registry.go b/driver/registry.go index e0e0d2562393..3040951d9726 100644 --- a/driver/registry.go +++ b/driver/registry.go @@ -180,11 +180,13 @@ func NewRegistryFromDSN(ctx context.Context, c *config.Config, l *logrusx.Logger } type options struct { - skipNetworkInit bool - config *config.Config - replaceTracer func(*otelx.Tracer) *otelx.Tracer - inspect func(Registry) error - extraMigrations []fs.FS + skipNetworkInit bool + config *config.Config + replaceTracer func(*otelx.Tracer) *otelx.Tracer + inspect func(Registry) error + extraMigrations []fs.FS + replacementStrategies []NewStrategy + extraHooks map[string]func(config.SelfServiceHook) any } type RegistryOption func(*options) @@ -205,6 +207,23 @@ func ReplaceTracer(f func(*otelx.Tracer) *otelx.Tracer) RegistryOption { } } +type NewStrategy func(deps any) any + +// WithReplaceStrategies adds a strategy to the registry. This is useful if you want to +// add a custom strategy to the registry. Default strategies with the same +// name/ID will be overwritten. +func WithReplaceStrategies(s ...NewStrategy) RegistryOption { + return func(o *options) { + o.replacementStrategies = append(o.replacementStrategies, s...) + } +} + +func WithExtraHooks(hooks map[string]func(config.SelfServiceHook) any) RegistryOption { + return func(o *options) { + o.extraHooks = hooks + } +} + func Inspect(f func(reg Registry) error) RegistryOption { return func(o *options) { o.inspect = f diff --git a/driver/registry_default.go b/driver/registry_default.go index b4733fc6dccf..68c460e5297c 100644 --- a/driver/registry_default.go +++ b/driver/registry_default.go @@ -78,7 +78,7 @@ import ( "github.com/ory/kratos/driver/config" "github.com/ory/kratos/identity" "github.com/ory/kratos/selfservice/errorx" - password2 "github.com/ory/kratos/selfservice/strategy/password" + "github.com/ory/kratos/selfservice/strategy/password" "github.com/ory/kratos/session" ) @@ -123,7 +123,7 @@ type RegistryDefault struct { sessionTokenizer *session.Tokenizer passwordHasher hash.Hasher - passwordValidator password2.Validator + passwordValidator password.Validator crypter cipher.Cipher @@ -157,7 +157,8 @@ type RegistryDefault struct { selfserviceLogoutHandler *logout.Handler - selfserviceStrategies []interface{} + selfserviceStrategies []any + replacementSelfserviceStrategies []NewStrategy hydra hydra.Hydra @@ -317,17 +318,25 @@ func (m *RegistryDefault) CourierConfig() config.CourierConfigs { return m.Config() } -func (m *RegistryDefault) selfServiceStrategies() []interface{} { +func (m *RegistryDefault) selfServiceStrategies() []any { if len(m.selfserviceStrategies) == 0 { - m.selfserviceStrategies = []interface{}{ - password2.NewStrategy(m), - oidc.NewStrategy(m), - profile.NewStrategy(m), - code.NewStrategy(m), - link.NewStrategy(m), - totp.NewStrategy(m), - webauthn.NewStrategy(m), - lookup.NewStrategy(m), + if m.replacementSelfserviceStrategies != nil { + // Construct self-service strategies from the replacements + for _, newStrategy := range m.replacementSelfserviceStrategies { + m.selfserviceStrategies = append(m.selfserviceStrategies, newStrategy(m)) + } + } else { + // Construct the default list of strategies + m.selfserviceStrategies = []any{ + password.NewStrategy(m), + oidc.NewStrategy(m), + profile.NewStrategy(m), + code.NewStrategy(m), + link.NewStrategy(m), + totp.NewStrategy(m), + webauthn.NewStrategy(m), + lookup.NewStrategy(m), + } } } @@ -352,9 +361,15 @@ func (m *RegistryDefault) strategyLoginEnabled(ctx context.Context, id string) b } } -func (m *RegistryDefault) RegistrationStrategies(ctx context.Context) (registrationStrategies registration.Strategies) { +func (m *RegistryDefault) RegistrationStrategies(ctx context.Context, filters ...registration.StrategyFilter) (registrationStrategies registration.Strategies) { +nextStrategy: for _, strategy := range m.selfServiceStrategies() { if s, ok := strategy.(registration.Strategy); ok { + for _, filter := range filters { + if !filter(s) { + continue nextStrategy + } + } if m.strategyRegistrationEnabled(ctx, s.ID().String()) { registrationStrategies = append(registrationStrategies, s) } @@ -374,9 +389,15 @@ func (m *RegistryDefault) AllRegistrationStrategies() registration.Strategies { return registrationStrategies } -func (m *RegistryDefault) LoginStrategies(ctx context.Context) (loginStrategies login.Strategies) { +func (m *RegistryDefault) LoginStrategies(ctx context.Context, filters ...login.StrategyFilter) (loginStrategies login.Strategies) { +nextStrategy: for _, strategy := range m.selfServiceStrategies() { if s, ok := strategy.(login.Strategy); ok { + for _, filter := range filters { + if !filter(s) { + continue nextStrategy + } + } if m.strategyLoginEnabled(ctx, s.ID().String()) { loginStrategies = append(loginStrategies, s) } @@ -495,10 +516,10 @@ func (m *RegistryDefault) Hasher(ctx context.Context) hash.Hasher { return m.passwordHasher } -func (m *RegistryDefault) PasswordValidator() password2.Validator { +func (m *RegistryDefault) PasswordValidator() password.Validator { if m.passwordValidator == nil { var err error - m.passwordValidator, err = password2.NewDefaultPasswordValidatorStrategy(m) + m.passwordValidator, err = password.NewDefaultPasswordValidatorStrategy(m) if err != nil { m.Logger().WithError(err).Fatal("could not initialize DefaultPasswordValidator") } @@ -622,6 +643,14 @@ func (m *RegistryDefault) Init(ctx context.Context, ctxer contextx.Contextualize m.trc = o.replaceTracer(m.trc) } + if o.replacementStrategies != nil { + m.replacementSelfserviceStrategies = o.replacementStrategies + } + + if o.extraHooks != nil { + m.WithHooks(o.extraHooks) + } + bc := backoff.NewExponentialBackOff() bc.MaxElapsedTime = time.Minute * 5 bc.Reset() diff --git a/embedx/config.schema.json b/embedx/config.schema.json index 5ad71652f665..02f568ee71fe 100644 --- a/embedx/config.schema.json +++ b/embedx/config.schema.json @@ -96,6 +96,23 @@ "hook" ] }, + "b2bSSOHook": { + "type": "object", + "properties": { + "hook": { + "const": "b2b_sso" + }, + "config": { + "type": "object", + "additionalProperties": true + } + }, + "additionalProperties": false, + "required": [ + "hook", + "config" + ] + }, "webHookAuthBasicAuthProperties": { "properties": { "type": { @@ -578,6 +595,14 @@ }, "requested_claims": { "$ref": "#/definitions/OIDCClaims" + }, + "organization_id": { + "title": "Organization ID", + "description": "The ID of the organization that this provider belongs to. Only effective in the Ory Network.", + "type": "string", + "examples": [ + "12345678-1234-1234-1234-123456789012" + ] } }, "additionalProperties": false, @@ -699,6 +724,9 @@ "anyOf": [ { "$ref": "#/definitions/selfServiceWebHook" + }, + { + "$ref": "#/definitions/b2bSSOHook" } ] }, @@ -811,6 +839,9 @@ }, { "$ref": "#/definitions/selfServiceRequireVerifiedAddressHook" + }, + { + "$ref": "#/definitions/b2bSSOHook" } ] }, @@ -838,6 +869,9 @@ }, { "$ref": "#/definitions/selfServiceShowVerificationUIHook" + }, + { + "$ref": "#/definitions/b2bSSOHook" } ] }, @@ -932,6 +966,9 @@ }, { "$ref": "#/definitions/selfServiceRequireVerifiedAddressHook" + }, + { + "$ref": "#/definitions/b2bSSOHook" } ] }, @@ -2828,6 +2865,12 @@ } }, "additionalProperties": false + }, + "organizations": { + "title": "Organizations", + "description": "Secifies which organizations are available. Only effective in the Ory Network.", + "type": "array", + "default": [] } }, "allOf": [ diff --git a/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_cleartext_password_and_oidc_credentials.json b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_cleartext_password_and_oidc_credentials.json index 9c2afdacbd18..e7074eaf4bd3 100644 --- a/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_cleartext_password_and_oidc_credentials.json +++ b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_cleartext_password_and_oidc_credentials.json @@ -38,5 +38,6 @@ "email": "import-2@ory.sh" }, "metadata_public": null, - "metadata_admin": null + "metadata_admin": null, + "organization_id": null } diff --git a/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=SSHA.json b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=SSHA.json index 0b41bd82167b..ed0c80c0e4f7 100644 --- a/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=SSHA.json +++ b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=SSHA.json @@ -16,5 +16,6 @@ "email": "import-hash-6@ory.sh" }, "metadata_public": null, - "metadata_admin": null + "metadata_admin": null, + "organization_id": null } diff --git a/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=SSHA256.json b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=SSHA256.json index 03976a0b06ea..ec7baa351d83 100644 --- a/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=SSHA256.json +++ b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=SSHA256.json @@ -16,5 +16,6 @@ "email": "import-hash-7@ory.sh" }, "metadata_public": null, - "metadata_admin": null + "metadata_admin": null, + "organization_id": null } diff --git a/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=SSHA512.json b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=SSHA512.json index 202c333f4bee..b07b12075ad7 100644 --- a/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=SSHA512.json +++ b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=SSHA512.json @@ -16,5 +16,6 @@ "email": "import-hash-8@ory.sh" }, "metadata_public": null, - "metadata_admin": null + "metadata_admin": null, + "organization_id": null } diff --git a/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=argon2i.json b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=argon2i.json index 6be9d80c32b5..95cf2a91558b 100644 --- a/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=argon2i.json +++ b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=argon2i.json @@ -16,5 +16,6 @@ "email": "import-hash-2@ory.sh" }, "metadata_public": null, - "metadata_admin": null + "metadata_admin": null, + "organization_id": null } diff --git a/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=argon2id.json b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=argon2id.json index 4383ba993b6c..d73f67f20863 100644 --- a/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=argon2id.json +++ b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=argon2id.json @@ -16,5 +16,6 @@ "email": "import-hash-3@ory.sh" }, "metadata_public": null, - "metadata_admin": null + "metadata_admin": null, + "organization_id": null } diff --git a/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=bcrypt2.json b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=bcrypt2.json index 5ed1aaf1ac95..062ac584f786 100644 --- a/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=bcrypt2.json +++ b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=bcrypt2.json @@ -16,5 +16,6 @@ "email": "import-hash-1@ory.sh" }, "metadata_public": null, - "metadata_admin": null + "metadata_admin": null, + "organization_id": null } diff --git a/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=md5.json b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=md5.json index e19627c2a999..d7fb134c7f38 100644 --- a/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=md5.json +++ b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=md5.json @@ -16,5 +16,6 @@ "email": "import-hash-5@ory.sh" }, "metadata_public": null, - "metadata_admin": null + "metadata_admin": null, + "organization_id": null } diff --git a/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=pkbdf2.json b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=pkbdf2.json index e3f1b0050810..51cdaa603524 100644 --- a/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=pkbdf2.json +++ b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=pkbdf2.json @@ -16,5 +16,6 @@ "email": "import-hash-0@ory.sh" }, "metadata_public": null, - "metadata_admin": null + "metadata_admin": null, + "organization_id": null } diff --git a/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=scrypt.json b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=scrypt.json index 029159b996c9..f8fc83b20016 100644 --- a/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=scrypt.json +++ b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=scrypt.json @@ -16,5 +16,6 @@ "email": "import-hash-4@ory.sh" }, "metadata_public": null, - "metadata_admin": null + "metadata_admin": null, + "organization_id": null } diff --git a/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-without_any_credentials.json b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-without_any_credentials.json index a6faeb36232a..fe341f881564 100644 --- a/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-without_any_credentials.json +++ b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-without_any_credentials.json @@ -15,5 +15,6 @@ "email": "import-1@ory.sh" }, "metadata_public": null, - "metadata_admin": null + "metadata_admin": null, + "organization_id": null } diff --git a/identity/.snapshots/TestHandler-case=should_delete_credential_of_a_specific_user_and_no_longer_be_able_to_retrieve_it-type=remove_webauthn_passwordless_and_multiple_fido_mfa_type-admin.json b/identity/.snapshots/TestHandler-case=should_delete_credential_of_a_specific_user_and_no_longer_be_able_to_retrieve_it-type=remove_webauthn_passwordless_and_multiple_fido_mfa_type-admin.json index 2f07be5e9858..f99899936b3e 100644 --- a/identity/.snapshots/TestHandler-case=should_delete_credential_of_a_specific_user_and_no_longer_be_able_to_retrieve_it-type=remove_webauthn_passwordless_and_multiple_fido_mfa_type-admin.json +++ b/identity/.snapshots/TestHandler-case=should_delete_credential_of_a_specific_user_and_no_longer_be_able_to_retrieve_it-type=remove_webauthn_passwordless_and_multiple_fido_mfa_type-admin.json @@ -39,5 +39,6 @@ "state": "active", "traits": {}, "metadata_public": null, - "metadata_admin": null + "metadata_admin": null, + "organization_id": null } diff --git a/identity/.snapshots/TestHandler-case=should_delete_credential_of_a_specific_user_and_no_longer_be_able_to_retrieve_it-type=remove_webauthn_passwordless_and_multiple_fido_mfa_type-public.json b/identity/.snapshots/TestHandler-case=should_delete_credential_of_a_specific_user_and_no_longer_be_able_to_retrieve_it-type=remove_webauthn_passwordless_and_multiple_fido_mfa_type-public.json index 2f07be5e9858..f99899936b3e 100644 --- a/identity/.snapshots/TestHandler-case=should_delete_credential_of_a_specific_user_and_no_longer_be_able_to_retrieve_it-type=remove_webauthn_passwordless_and_multiple_fido_mfa_type-public.json +++ b/identity/.snapshots/TestHandler-case=should_delete_credential_of_a_specific_user_and_no_longer_be_able_to_retrieve_it-type=remove_webauthn_passwordless_and_multiple_fido_mfa_type-public.json @@ -39,5 +39,6 @@ "state": "active", "traits": {}, "metadata_public": null, - "metadata_admin": null + "metadata_admin": null, + "organization_id": null } diff --git a/identity/.snapshots/TestHandler-case=should_delete_credential_of_a_specific_user_and_no_longer_be_able_to_retrieve_it-type=remove_webauthn_passwordless_type-admin.json b/identity/.snapshots/TestHandler-case=should_delete_credential_of_a_specific_user_and_no_longer_be_able_to_retrieve_it-type=remove_webauthn_passwordless_type-admin.json index e67fb02d62a5..96640c4e5ca9 100644 --- a/identity/.snapshots/TestHandler-case=should_delete_credential_of_a_specific_user_and_no_longer_be_able_to_retrieve_it-type=remove_webauthn_passwordless_type-admin.json +++ b/identity/.snapshots/TestHandler-case=should_delete_credential_of_a_specific_user_and_no_longer_be_able_to_retrieve_it-type=remove_webauthn_passwordless_type-admin.json @@ -27,5 +27,6 @@ "state": "active", "traits": {}, "metadata_public": null, - "metadata_admin": null + "metadata_admin": null, + "organization_id": null } diff --git a/identity/.snapshots/TestHandler-case=should_delete_credential_of_a_specific_user_and_no_longer_be_able_to_retrieve_it-type=remove_webauthn_passwordless_type-public.json b/identity/.snapshots/TestHandler-case=should_delete_credential_of_a_specific_user_and_no_longer_be_able_to_retrieve_it-type=remove_webauthn_passwordless_type-public.json index e67fb02d62a5..96640c4e5ca9 100644 --- a/identity/.snapshots/TestHandler-case=should_delete_credential_of_a_specific_user_and_no_longer_be_able_to_retrieve_it-type=remove_webauthn_passwordless_type-public.json +++ b/identity/.snapshots/TestHandler-case=should_delete_credential_of_a_specific_user_and_no_longer_be_able_to_retrieve_it-type=remove_webauthn_passwordless_type-public.json @@ -27,5 +27,6 @@ "state": "active", "traits": {}, "metadata_public": null, - "metadata_admin": null + "metadata_admin": null, + "organization_id": null } diff --git a/identity/.snapshots/TestHandler-suite=PATCH_identities-case=success-assert=identity_0.json b/identity/.snapshots/TestHandler-suite=PATCH_identities-case=success-assert=identity_0.json index 5ade813c32c7..467c98ce96a2 100644 --- a/identity/.snapshots/TestHandler-suite=PATCH_identities-case=success-assert=identity_0.json +++ b/identity/.snapshots/TestHandler-suite=PATCH_identities-case=success-assert=identity_0.json @@ -11,6 +11,7 @@ "metadata_public": { "public-0": "public" }, + "organization_id": null, "schema_id": "multiple_emails", "state": "active", "traits": { diff --git a/identity/.snapshots/TestHandler-suite=PATCH_identities-case=success-assert=identity_1.json b/identity/.snapshots/TestHandler-suite=PATCH_identities-case=success-assert=identity_1.json index 9b4723abacf8..9e033a976c95 100644 --- a/identity/.snapshots/TestHandler-suite=PATCH_identities-case=success-assert=identity_1.json +++ b/identity/.snapshots/TestHandler-suite=PATCH_identities-case=success-assert=identity_1.json @@ -11,6 +11,7 @@ "metadata_public": { "public-1": "public" }, + "organization_id": null, "schema_id": "multiple_emails", "state": "active", "traits": { diff --git a/identity/.snapshots/TestHandler-suite=PATCH_identities-case=success-assert=identity_2.json b/identity/.snapshots/TestHandler-suite=PATCH_identities-case=success-assert=identity_2.json index 9ff93b942dce..dbb945ee485b 100644 --- a/identity/.snapshots/TestHandler-suite=PATCH_identities-case=success-assert=identity_2.json +++ b/identity/.snapshots/TestHandler-suite=PATCH_identities-case=success-assert=identity_2.json @@ -11,6 +11,7 @@ "metadata_public": { "public-2": "public" }, + "organization_id": null, "schema_id": "multiple_emails", "state": "active", "traits": { diff --git a/identity/.snapshots/TestHandler-suite=PATCH_identities-case=success-assert=identity_3.json b/identity/.snapshots/TestHandler-suite=PATCH_identities-case=success-assert=identity_3.json index 49d8da5cc71a..4800666e9aa8 100644 --- a/identity/.snapshots/TestHandler-suite=PATCH_identities-case=success-assert=identity_3.json +++ b/identity/.snapshots/TestHandler-suite=PATCH_identities-case=success-assert=identity_3.json @@ -11,6 +11,7 @@ "metadata_public": { "public-3": "public" }, + "organization_id": null, "schema_id": "multiple_emails", "state": "active", "traits": { diff --git a/identity/.snapshots/TestHandler-suite=create_and_update-case=should_get_identity_with_credentials-case=should_get_identity_with_password_and_webauthn_credentials_included.json b/identity/.snapshots/TestHandler-suite=create_and_update-case=should_get_identity_with_credentials-case=should_get_identity_with_password_and_webauthn_credentials_included.json index ae4336a69ff3..c44f358f0573 100644 --- a/identity/.snapshots/TestHandler-suite=create_and_update-case=should_get_identity_with_credentials-case=should_get_identity_with_password_and_webauthn_credentials_included.json +++ b/identity/.snapshots/TestHandler-suite=create_and_update-case=should_get_identity_with_credentials-case=should_get_identity_with_password_and_webauthn_credentials_included.json @@ -36,5 +36,6 @@ "state": "active", "traits": {}, "metadata_public": null, - "metadata_admin": null + "metadata_admin": null, + "organization_id": null } diff --git a/identity/.snapshots/TestHandler-suite=create_and_update-case=should_get_identity_with_credentials-case=should_get_identity_with_password_credentials_included.json b/identity/.snapshots/TestHandler-suite=create_and_update-case=should_get_identity_with_credentials-case=should_get_identity_with_password_credentials_included.json index 0004001d98f5..b833a571eaad 100644 --- a/identity/.snapshots/TestHandler-suite=create_and_update-case=should_get_identity_with_credentials-case=should_get_identity_with_password_credentials_included.json +++ b/identity/.snapshots/TestHandler-suite=create_and_update-case=should_get_identity_with_credentials-case=should_get_identity_with_password_credentials_included.json @@ -32,5 +32,6 @@ "state": "active", "traits": {}, "metadata_public": null, - "metadata_admin": null + "metadata_admin": null, + "organization_id": null } diff --git a/identity/.snapshots/TestHandler-suite=create_and_update-case=should_get_identity_with_credentials-case=should_get_identity_without_credentials_included.json b/identity/.snapshots/TestHandler-suite=create_and_update-case=should_get_identity_with_credentials-case=should_get_identity_without_credentials_included.json index 967eec6d8f92..a7840bdb3df9 100644 --- a/identity/.snapshots/TestHandler-suite=create_and_update-case=should_get_identity_with_credentials-case=should_get_identity_without_credentials_included.json +++ b/identity/.snapshots/TestHandler-suite=create_and_update-case=should_get_identity_with_credentials-case=should_get_identity_without_credentials_included.json @@ -29,5 +29,6 @@ "state": "active", "traits": {}, "metadata_public": null, - "metadata_admin": null + "metadata_admin": null, + "organization_id": null } diff --git a/identity/.snapshots/TestUpgradeCredentials-empty_credentials.json b/identity/.snapshots/TestUpgradeCredentials-empty_credentials.json index 8226d7ef009d..81b0c2a4dcab 100644 --- a/identity/.snapshots/TestUpgradeCredentials-empty_credentials.json +++ b/identity/.snapshots/TestUpgradeCredentials-empty_credentials.json @@ -6,5 +6,6 @@ "traits": null, "metadata_public": null, "created_at": "0001-01-01T00:00:00Z", - "updated_at": "0001-01-01T00:00:00Z" + "updated_at": "0001-01-01T00:00:00Z", + "organization_id": null } diff --git a/identity/.snapshots/TestUpgradeCredentials-type=webauthn-from=v0.json b/identity/.snapshots/TestUpgradeCredentials-type=webauthn-from=v0.json index 83c81edb6e0c..0236be234d48 100644 --- a/identity/.snapshots/TestUpgradeCredentials-type=webauthn-from=v0.json +++ b/identity/.snapshots/TestUpgradeCredentials-type=webauthn-from=v0.json @@ -48,5 +48,6 @@ "traits": null, "metadata_public": null, "created_at": "0001-01-01T00:00:00Z", - "updated_at": "0001-01-01T00:00:00Z" + "updated_at": "0001-01-01T00:00:00Z", + "organization_id": null } diff --git a/identity/.snapshots/TestUpgradeCredentials-type=webauthn-from=v1.json b/identity/.snapshots/TestUpgradeCredentials-type=webauthn-from=v1.json index 57614f591497..60038539418a 100644 --- a/identity/.snapshots/TestUpgradeCredentials-type=webauthn-from=v1.json +++ b/identity/.snapshots/TestUpgradeCredentials-type=webauthn-from=v1.json @@ -33,5 +33,6 @@ "traits": null, "metadata_public": null, "created_at": "0001-01-01T00:00:00Z", - "updated_at": "0001-01-01T00:00:00Z" + "updated_at": "0001-01-01T00:00:00Z", + "organization_id": null } diff --git a/identity/credentials_oidc.go b/identity/credentials_oidc.go index 1ad0ada209c1..09b5d0aecad0 100644 --- a/identity/credentials_oidc.go +++ b/identity/credentials_oidc.go @@ -29,10 +29,11 @@ type CredentialsOIDCProvider struct { InitialIDToken string `json:"initial_id_token"` InitialAccessToken string `json:"initial_access_token"` InitialRefreshToken string `json:"initial_refresh_token"` + Organization string `json:"organization,omitempty"` } // NewCredentialsOIDC creates a new OIDC credential. -func NewCredentialsOIDC(idToken, accessToken, refreshToken, provider, subject string) (*Credentials, error) { +func NewCredentialsOIDC(idToken, accessToken, refreshToken, provider, subject, organization string) (*Credentials, error) { if provider == "" { return nil, errors.New("received empty provider in oidc credentials") } @@ -50,6 +51,7 @@ func NewCredentialsOIDC(idToken, accessToken, refreshToken, provider, subject st InitialIDToken: idToken, InitialAccessToken: accessToken, InitialRefreshToken: refreshToken, + Organization: organization, }}, }); err != nil { return nil, errors.WithStack(x.PseudoPanic. @@ -66,3 +68,13 @@ func NewCredentialsOIDC(idToken, accessToken, refreshToken, provider, subject st func OIDCUniqueID(provider, subject string) string { return fmt.Sprintf("%s:%s", provider, subject) } + +func (c *CredentialsOIDC) Organization() string { + for _, p := range c.Providers { + if p.Organization != "" { + return p.Organization + } + } + + return "" +} diff --git a/identity/credentials_oidc_test.go b/identity/credentials_oidc_test.go index b916220f1b9b..dda20f73deb7 100644 --- a/identity/credentials_oidc_test.go +++ b/identity/credentials_oidc_test.go @@ -10,10 +10,10 @@ import ( ) func TestNewCredentialsOIDC(t *testing.T) { - _, err := NewCredentialsOIDC("", "", "", "", "not-empty") + _, err := NewCredentialsOIDC("", "", "", "", "not-empty", "") require.Error(t, err) - _, err = NewCredentialsOIDC("", "", "", "not-empty", "") + _, err = NewCredentialsOIDC("", "", "", "not-empty", "", "") require.Error(t, err) - _, err = NewCredentialsOIDC("", "", "", "not-empty", "not-empty") + _, err = NewCredentialsOIDC("", "", "", "not-empty", "not-empty", "") require.NoError(t, err) } diff --git a/identity/identity.go b/identity/identity.go index 070ec30a666d..064c21121fc1 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -127,8 +127,9 @@ type Identity struct { CreatedAt time.Time `json:"created_at" db:"created_at"` // UpdatedAt is a helper struct field for gobuffalo.pop. - UpdatedAt time.Time `json:"updated_at" db:"updated_at"` - NID uuid.UUID `json:"-" faker:"-" db:"nid"` + UpdatedAt time.Time `json:"updated_at" db:"updated_at"` + NID uuid.UUID `json:"-" faker:"-" db:"nid"` + OrganizationID uuid.NullUUID `json:"organization_id,omitempty" faker:"-" db:"organization_id"` } // Traits represent an identity's traits. The identity is able to create, modify, and delete traits @@ -459,6 +460,11 @@ func (i *Identity) WithDeclassifiedCredentials(ctx context.Context, c cipher.Pro return false } + toPublish.Config, err = sjson.SetBytes(toPublish.Config, fmt.Sprintf("providers.%d.organization", i), v.Get("organization").String()) + if err != nil { + return false + } + i++ return true }) diff --git a/internal/client-go/api_frontend.go b/internal/client-go/api_frontend.go index 657a2c6c7721..0260af5a71b6 100644 --- a/internal/client-go/api_frontend.go +++ b/internal/client-go/api_frontend.go @@ -941,6 +941,7 @@ type FrontendApiApiCreateBrowserLoginFlowRequest struct { returnTo *string cookie *string loginChallenge *string + organization *string } func (r FrontendApiApiCreateBrowserLoginFlowRequest) Refresh(refresh bool) FrontendApiApiCreateBrowserLoginFlowRequest { @@ -963,6 +964,10 @@ func (r FrontendApiApiCreateBrowserLoginFlowRequest) LoginChallenge(loginChallen r.loginChallenge = &loginChallenge return r } +func (r FrontendApiApiCreateBrowserLoginFlowRequest) Organization(organization string) FrontendApiApiCreateBrowserLoginFlowRequest { + r.organization = &organization + return r +} func (r FrontendApiApiCreateBrowserLoginFlowRequest) Execute() (*LoginFlow, *http.Response, error) { return r.ApiService.CreateBrowserLoginFlowExecute(r) @@ -1041,6 +1046,9 @@ func (a *FrontendApiService) CreateBrowserLoginFlowExecute(r FrontendApiApiCreat if r.loginChallenge != nil { localVarQueryParams.Add("login_challenge", parameterToString(*r.loginChallenge, "")) } + if r.organization != nil { + localVarQueryParams.Add("organization", parameterToString(*r.organization, "")) + } // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -1414,6 +1422,7 @@ type FrontendApiApiCreateBrowserRegistrationFlowRequest struct { returnTo *string loginChallenge *string afterVerificationReturnTo *string + organization *string } func (r FrontendApiApiCreateBrowserRegistrationFlowRequest) ReturnTo(returnTo string) FrontendApiApiCreateBrowserRegistrationFlowRequest { @@ -1428,6 +1437,10 @@ func (r FrontendApiApiCreateBrowserRegistrationFlowRequest) AfterVerificationRet r.afterVerificationReturnTo = &afterVerificationReturnTo return r } +func (r FrontendApiApiCreateBrowserRegistrationFlowRequest) Organization(organization string) FrontendApiApiCreateBrowserRegistrationFlowRequest { + r.organization = &organization + return r +} func (r FrontendApiApiCreateBrowserRegistrationFlowRequest) Execute() (*RegistrationFlow, *http.Response, error) { return r.ApiService.CreateBrowserRegistrationFlowExecute(r) @@ -1499,6 +1512,9 @@ func (a *FrontendApiService) CreateBrowserRegistrationFlowExecute(r FrontendApiA if r.afterVerificationReturnTo != nil { localVarQueryParams.Add("after_verification_return_to", parameterToString(*r.afterVerificationReturnTo, "")) } + if r.organization != nil { + localVarQueryParams.Add("organization", parameterToString(*r.organization, "")) + } // to determine the Content-Type header localVarHTTPContentTypes := []string{} diff --git a/internal/client-go/model_identity.go b/internal/client-go/model_identity.go index ea9a18b6972b..282821f468ed 100644 --- a/internal/client-go/model_identity.go +++ b/internal/client-go/model_identity.go @@ -27,7 +27,8 @@ type Identity struct { // NullJSONRawMessage represents a json.RawMessage that works well with JSON, SQL, and Swagger and is NULLable- MetadataAdmin interface{} `json:"metadata_admin,omitempty"` // NullJSONRawMessage represents a json.RawMessage that works well with JSON, SQL, and Swagger and is NULLable- - MetadataPublic interface{} `json:"metadata_public,omitempty"` + MetadataPublic interface{} `json:"metadata_public,omitempty"` + OrganizationId NullableString `json:"organization_id,omitempty"` // RecoveryAddresses contains all the addresses that can be used to recover an identity. RecoveryAddresses []RecoveryIdentityAddress `json:"recovery_addresses,omitempty"` // SchemaID is the ID of the JSON Schema to be used for validating the identity's traits. @@ -219,6 +220,49 @@ func (o *Identity) SetMetadataPublic(v interface{}) { o.MetadataPublic = v } +// GetOrganizationId returns the OrganizationId field value if set, zero value otherwise (both if not set or set to explicit null). +func (o *Identity) GetOrganizationId() string { + if o == nil || o.OrganizationId.Get() == nil { + var ret string + return ret + } + return *o.OrganizationId.Get() +} + +// GetOrganizationIdOk returns a tuple with the OrganizationId 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 *Identity) GetOrganizationIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return o.OrganizationId.Get(), o.OrganizationId.IsSet() +} + +// HasOrganizationId returns a boolean if a field has been set. +func (o *Identity) HasOrganizationId() bool { + if o != nil && o.OrganizationId.IsSet() { + return true + } + + return false +} + +// SetOrganizationId gets a reference to the given NullableString and assigns it to the OrganizationId field. +func (o *Identity) SetOrganizationId(v string) { + o.OrganizationId.Set(&v) +} + +// SetOrganizationIdNil sets the value for OrganizationId to be an explicit nil +func (o *Identity) SetOrganizationIdNil() { + o.OrganizationId.Set(nil) +} + +// UnsetOrganizationId ensures that no value is present for OrganizationId, not even an explicit nil +func (o *Identity) UnsetOrganizationId() { + o.OrganizationId.Unset() +} + // GetRecoveryAddresses returns the RecoveryAddresses field value if set, zero value otherwise. func (o *Identity) GetRecoveryAddresses() []RecoveryIdentityAddress { if o == nil || o.RecoveryAddresses == nil { @@ -470,6 +514,9 @@ func (o Identity) MarshalJSON() ([]byte, error) { if o.MetadataPublic != nil { toSerialize["metadata_public"] = o.MetadataPublic } + if o.OrganizationId.IsSet() { + toSerialize["organization_id"] = o.OrganizationId.Get() + } if o.RecoveryAddresses != nil { toSerialize["recovery_addresses"] = o.RecoveryAddresses } diff --git a/internal/client-go/model_identity_credentials_oidc_provider.go b/internal/client-go/model_identity_credentials_oidc_provider.go index b1ce3cead760..f905f2f60413 100644 --- a/internal/client-go/model_identity_credentials_oidc_provider.go +++ b/internal/client-go/model_identity_credentials_oidc_provider.go @@ -20,6 +20,7 @@ type IdentityCredentialsOidcProvider struct { InitialAccessToken *string `json:"initial_access_token,omitempty"` InitialIdToken *string `json:"initial_id_token,omitempty"` InitialRefreshToken *string `json:"initial_refresh_token,omitempty"` + Organization *string `json:"organization,omitempty"` Provider *string `json:"provider,omitempty"` Subject *string `json:"subject,omitempty"` } @@ -137,6 +138,38 @@ func (o *IdentityCredentialsOidcProvider) SetInitialRefreshToken(v string) { o.InitialRefreshToken = &v } +// GetOrganization returns the Organization field value if set, zero value otherwise. +func (o *IdentityCredentialsOidcProvider) GetOrganization() string { + if o == nil || o.Organization == nil { + var ret string + return ret + } + return *o.Organization +} + +// GetOrganizationOk returns a tuple with the Organization field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *IdentityCredentialsOidcProvider) GetOrganizationOk() (*string, bool) { + if o == nil || o.Organization == nil { + return nil, false + } + return o.Organization, true +} + +// HasOrganization returns a boolean if a field has been set. +func (o *IdentityCredentialsOidcProvider) HasOrganization() bool { + if o != nil && o.Organization != nil { + return true + } + + return false +} + +// SetOrganization gets a reference to the given string and assigns it to the Organization field. +func (o *IdentityCredentialsOidcProvider) SetOrganization(v string) { + o.Organization = &v +} + // GetProvider returns the Provider field value if set, zero value otherwise. func (o *IdentityCredentialsOidcProvider) GetProvider() string { if o == nil || o.Provider == nil { @@ -212,6 +245,9 @@ func (o IdentityCredentialsOidcProvider) MarshalJSON() ([]byte, error) { if o.InitialRefreshToken != nil { toSerialize["initial_refresh_token"] = o.InitialRefreshToken } + if o.Organization != nil { + toSerialize["organization"] = o.Organization + } if o.Provider != nil { toSerialize["provider"] = o.Provider } diff --git a/internal/client-go/model_login_flow.go b/internal/client-go/model_login_flow.go index dc7c67ea2649..161377f6b680 100644 --- a/internal/client-go/model_login_flow.go +++ b/internal/client-go/model_login_flow.go @@ -30,6 +30,7 @@ type LoginFlow struct { // 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 *string `json:"oauth2_login_challenge,omitempty"` Oauth2LoginRequest *OAuth2LoginRequest `json:"oauth2_login_request,omitempty"` + OrganizationId NullableString `json:"organization_id,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. @@ -272,6 +273,49 @@ func (o *LoginFlow) SetOauth2LoginRequest(v OAuth2LoginRequest) { o.Oauth2LoginRequest = &v } +// GetOrganizationId returns the OrganizationId field value if set, zero value otherwise (both if not set or set to explicit null). +func (o *LoginFlow) GetOrganizationId() string { + if o == nil || o.OrganizationId.Get() == nil { + var ret string + return ret + } + return *o.OrganizationId.Get() +} + +// GetOrganizationIdOk returns a tuple with the OrganizationId 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 *LoginFlow) GetOrganizationIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return o.OrganizationId.Get(), o.OrganizationId.IsSet() +} + +// HasOrganizationId returns a boolean if a field has been set. +func (o *LoginFlow) HasOrganizationId() bool { + if o != nil && o.OrganizationId.IsSet() { + return true + } + + return false +} + +// SetOrganizationId gets a reference to the given NullableString and assigns it to the OrganizationId field. +func (o *LoginFlow) SetOrganizationId(v string) { + o.OrganizationId.Set(&v) +} + +// SetOrganizationIdNil sets the value for OrganizationId to be an explicit nil +func (o *LoginFlow) SetOrganizationIdNil() { + o.OrganizationId.Set(nil) +} + +// UnsetOrganizationId ensures that no value is present for OrganizationId, not even an explicit nil +func (o *LoginFlow) UnsetOrganizationId() { + o.OrganizationId.Unset() +} + // GetRefresh returns the Refresh field value if set, zero value otherwise. func (o *LoginFlow) GetRefresh() bool { if o == nil || o.Refresh == nil { @@ -553,6 +597,9 @@ func (o LoginFlow) MarshalJSON() ([]byte, error) { if o.Oauth2LoginRequest != nil { toSerialize["oauth2_login_request"] = o.Oauth2LoginRequest } + if o.OrganizationId.IsSet() { + toSerialize["organization_id"] = o.OrganizationId.Get() + } if o.Refresh != nil { toSerialize["refresh"] = o.Refresh } diff --git a/internal/client-go/model_registration_flow.go b/internal/client-go/model_registration_flow.go index 9b08288d6a16..85d0365ddcb1 100644 --- a/internal/client-go/model_registration_flow.go +++ b/internal/client-go/model_registration_flow.go @@ -28,6 +28,7 @@ type RegistrationFlow struct { // 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 *string `json:"oauth2_login_challenge,omitempty"` Oauth2LoginRequest *OAuth2LoginRequest `json:"oauth2_login_request,omitempty"` + OrganizationId NullableString `json:"organization_id,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. @@ -235,6 +236,49 @@ func (o *RegistrationFlow) SetOauth2LoginRequest(v OAuth2LoginRequest) { o.Oauth2LoginRequest = &v } +// GetOrganizationId returns the OrganizationId field value if set, zero value otherwise (both if not set or set to explicit null). +func (o *RegistrationFlow) GetOrganizationId() string { + if o == nil || o.OrganizationId.Get() == nil { + var ret string + return ret + } + return *o.OrganizationId.Get() +} + +// GetOrganizationIdOk returns a tuple with the OrganizationId 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 *RegistrationFlow) GetOrganizationIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return o.OrganizationId.Get(), o.OrganizationId.IsSet() +} + +// HasOrganizationId returns a boolean if a field has been set. +func (o *RegistrationFlow) HasOrganizationId() bool { + if o != nil && o.OrganizationId.IsSet() { + return true + } + + return false +} + +// SetOrganizationId gets a reference to the given NullableString and assigns it to the OrganizationId field. +func (o *RegistrationFlow) SetOrganizationId(v string) { + o.OrganizationId.Set(&v) +} + +// SetOrganizationIdNil sets the value for OrganizationId to be an explicit nil +func (o *RegistrationFlow) SetOrganizationIdNil() { + o.OrganizationId.Set(nil) +} + +// UnsetOrganizationId ensures that no value is present for OrganizationId, not even an explicit nil +func (o *RegistrationFlow) UnsetOrganizationId() { + o.OrganizationId.Unset() +} + // GetRequestUrl returns the RequestUrl field value func (o *RegistrationFlow) GetRequestUrl() string { if o == nil { @@ -449,6 +493,9 @@ func (o RegistrationFlow) MarshalJSON() ([]byte, error) { if o.Oauth2LoginRequest != nil { toSerialize["oauth2_login_request"] = o.Oauth2LoginRequest } + if o.OrganizationId.IsSet() { + toSerialize["organization_id"] = o.OrganizationId.Get() + } if true { toSerialize["request_url"] = o.RequestUrl } diff --git a/internal/client-go/model_session_authentication_method.go b/internal/client-go/model_session_authentication_method.go index 032dfb0cc7f6..c887f7df61c6 100644 --- a/internal/client-go/model_session_authentication_method.go +++ b/internal/client-go/model_session_authentication_method.go @@ -20,8 +20,9 @@ import ( type SessionAuthenticationMethod struct { Aal *AuthenticatorAssuranceLevel `json:"aal,omitempty"` // When the authentication challenge was completed. - CompletedAt *time.Time `json:"completed_at,omitempty"` - Method *string `json:"method,omitempty"` + CompletedAt *time.Time `json:"completed_at,omitempty"` + Method *string `json:"method,omitempty"` + Organization *string `json:"organization,omitempty"` // OIDC or SAML provider id used for authentication Provider *string `json:"provider,omitempty"` } @@ -139,6 +140,38 @@ func (o *SessionAuthenticationMethod) SetMethod(v string) { o.Method = &v } +// GetOrganization returns the Organization field value if set, zero value otherwise. +func (o *SessionAuthenticationMethod) GetOrganization() string { + if o == nil || o.Organization == nil { + var ret string + return ret + } + return *o.Organization +} + +// GetOrganizationOk returns a tuple with the Organization field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *SessionAuthenticationMethod) GetOrganizationOk() (*string, bool) { + if o == nil || o.Organization == nil { + return nil, false + } + return o.Organization, true +} + +// HasOrganization returns a boolean if a field has been set. +func (o *SessionAuthenticationMethod) HasOrganization() bool { + if o != nil && o.Organization != nil { + return true + } + + return false +} + +// SetOrganization gets a reference to the given string and assigns it to the Organization field. +func (o *SessionAuthenticationMethod) SetOrganization(v string) { + o.Organization = &v +} + // GetProvider returns the Provider field value if set, zero value otherwise. func (o *SessionAuthenticationMethod) GetProvider() string { if o == nil || o.Provider == nil { @@ -182,6 +215,9 @@ func (o SessionAuthenticationMethod) MarshalJSON() ([]byte, error) { if o.Method != nil { toSerialize["method"] = o.Method } + if o.Organization != nil { + toSerialize["organization"] = o.Organization + } if o.Provider != nil { toSerialize["provider"] = o.Provider } diff --git a/internal/httpclient/api_frontend.go b/internal/httpclient/api_frontend.go index 657a2c6c7721..0260af5a71b6 100644 --- a/internal/httpclient/api_frontend.go +++ b/internal/httpclient/api_frontend.go @@ -941,6 +941,7 @@ type FrontendApiApiCreateBrowserLoginFlowRequest struct { returnTo *string cookie *string loginChallenge *string + organization *string } func (r FrontendApiApiCreateBrowserLoginFlowRequest) Refresh(refresh bool) FrontendApiApiCreateBrowserLoginFlowRequest { @@ -963,6 +964,10 @@ func (r FrontendApiApiCreateBrowserLoginFlowRequest) LoginChallenge(loginChallen r.loginChallenge = &loginChallenge return r } +func (r FrontendApiApiCreateBrowserLoginFlowRequest) Organization(organization string) FrontendApiApiCreateBrowserLoginFlowRequest { + r.organization = &organization + return r +} func (r FrontendApiApiCreateBrowserLoginFlowRequest) Execute() (*LoginFlow, *http.Response, error) { return r.ApiService.CreateBrowserLoginFlowExecute(r) @@ -1041,6 +1046,9 @@ func (a *FrontendApiService) CreateBrowserLoginFlowExecute(r FrontendApiApiCreat if r.loginChallenge != nil { localVarQueryParams.Add("login_challenge", parameterToString(*r.loginChallenge, "")) } + if r.organization != nil { + localVarQueryParams.Add("organization", parameterToString(*r.organization, "")) + } // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -1414,6 +1422,7 @@ type FrontendApiApiCreateBrowserRegistrationFlowRequest struct { returnTo *string loginChallenge *string afterVerificationReturnTo *string + organization *string } func (r FrontendApiApiCreateBrowserRegistrationFlowRequest) ReturnTo(returnTo string) FrontendApiApiCreateBrowserRegistrationFlowRequest { @@ -1428,6 +1437,10 @@ func (r FrontendApiApiCreateBrowserRegistrationFlowRequest) AfterVerificationRet r.afterVerificationReturnTo = &afterVerificationReturnTo return r } +func (r FrontendApiApiCreateBrowserRegistrationFlowRequest) Organization(organization string) FrontendApiApiCreateBrowserRegistrationFlowRequest { + r.organization = &organization + return r +} func (r FrontendApiApiCreateBrowserRegistrationFlowRequest) Execute() (*RegistrationFlow, *http.Response, error) { return r.ApiService.CreateBrowserRegistrationFlowExecute(r) @@ -1499,6 +1512,9 @@ func (a *FrontendApiService) CreateBrowserRegistrationFlowExecute(r FrontendApiA if r.afterVerificationReturnTo != nil { localVarQueryParams.Add("after_verification_return_to", parameterToString(*r.afterVerificationReturnTo, "")) } + if r.organization != nil { + localVarQueryParams.Add("organization", parameterToString(*r.organization, "")) + } // to determine the Content-Type header localVarHTTPContentTypes := []string{} diff --git a/internal/httpclient/model_identity.go b/internal/httpclient/model_identity.go index ea9a18b6972b..282821f468ed 100644 --- a/internal/httpclient/model_identity.go +++ b/internal/httpclient/model_identity.go @@ -27,7 +27,8 @@ type Identity struct { // NullJSONRawMessage represents a json.RawMessage that works well with JSON, SQL, and Swagger and is NULLable- MetadataAdmin interface{} `json:"metadata_admin,omitempty"` // NullJSONRawMessage represents a json.RawMessage that works well with JSON, SQL, and Swagger and is NULLable- - MetadataPublic interface{} `json:"metadata_public,omitempty"` + MetadataPublic interface{} `json:"metadata_public,omitempty"` + OrganizationId NullableString `json:"organization_id,omitempty"` // RecoveryAddresses contains all the addresses that can be used to recover an identity. RecoveryAddresses []RecoveryIdentityAddress `json:"recovery_addresses,omitempty"` // SchemaID is the ID of the JSON Schema to be used for validating the identity's traits. @@ -219,6 +220,49 @@ func (o *Identity) SetMetadataPublic(v interface{}) { o.MetadataPublic = v } +// GetOrganizationId returns the OrganizationId field value if set, zero value otherwise (both if not set or set to explicit null). +func (o *Identity) GetOrganizationId() string { + if o == nil || o.OrganizationId.Get() == nil { + var ret string + return ret + } + return *o.OrganizationId.Get() +} + +// GetOrganizationIdOk returns a tuple with the OrganizationId 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 *Identity) GetOrganizationIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return o.OrganizationId.Get(), o.OrganizationId.IsSet() +} + +// HasOrganizationId returns a boolean if a field has been set. +func (o *Identity) HasOrganizationId() bool { + if o != nil && o.OrganizationId.IsSet() { + return true + } + + return false +} + +// SetOrganizationId gets a reference to the given NullableString and assigns it to the OrganizationId field. +func (o *Identity) SetOrganizationId(v string) { + o.OrganizationId.Set(&v) +} + +// SetOrganizationIdNil sets the value for OrganizationId to be an explicit nil +func (o *Identity) SetOrganizationIdNil() { + o.OrganizationId.Set(nil) +} + +// UnsetOrganizationId ensures that no value is present for OrganizationId, not even an explicit nil +func (o *Identity) UnsetOrganizationId() { + o.OrganizationId.Unset() +} + // GetRecoveryAddresses returns the RecoveryAddresses field value if set, zero value otherwise. func (o *Identity) GetRecoveryAddresses() []RecoveryIdentityAddress { if o == nil || o.RecoveryAddresses == nil { @@ -470,6 +514,9 @@ func (o Identity) MarshalJSON() ([]byte, error) { if o.MetadataPublic != nil { toSerialize["metadata_public"] = o.MetadataPublic } + if o.OrganizationId.IsSet() { + toSerialize["organization_id"] = o.OrganizationId.Get() + } if o.RecoveryAddresses != nil { toSerialize["recovery_addresses"] = o.RecoveryAddresses } diff --git a/internal/httpclient/model_identity_credentials_oidc_provider.go b/internal/httpclient/model_identity_credentials_oidc_provider.go index b1ce3cead760..f905f2f60413 100644 --- a/internal/httpclient/model_identity_credentials_oidc_provider.go +++ b/internal/httpclient/model_identity_credentials_oidc_provider.go @@ -20,6 +20,7 @@ type IdentityCredentialsOidcProvider struct { InitialAccessToken *string `json:"initial_access_token,omitempty"` InitialIdToken *string `json:"initial_id_token,omitempty"` InitialRefreshToken *string `json:"initial_refresh_token,omitempty"` + Organization *string `json:"organization,omitempty"` Provider *string `json:"provider,omitempty"` Subject *string `json:"subject,omitempty"` } @@ -137,6 +138,38 @@ func (o *IdentityCredentialsOidcProvider) SetInitialRefreshToken(v string) { o.InitialRefreshToken = &v } +// GetOrganization returns the Organization field value if set, zero value otherwise. +func (o *IdentityCredentialsOidcProvider) GetOrganization() string { + if o == nil || o.Organization == nil { + var ret string + return ret + } + return *o.Organization +} + +// GetOrganizationOk returns a tuple with the Organization field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *IdentityCredentialsOidcProvider) GetOrganizationOk() (*string, bool) { + if o == nil || o.Organization == nil { + return nil, false + } + return o.Organization, true +} + +// HasOrganization returns a boolean if a field has been set. +func (o *IdentityCredentialsOidcProvider) HasOrganization() bool { + if o != nil && o.Organization != nil { + return true + } + + return false +} + +// SetOrganization gets a reference to the given string and assigns it to the Organization field. +func (o *IdentityCredentialsOidcProvider) SetOrganization(v string) { + o.Organization = &v +} + // GetProvider returns the Provider field value if set, zero value otherwise. func (o *IdentityCredentialsOidcProvider) GetProvider() string { if o == nil || o.Provider == nil { @@ -212,6 +245,9 @@ func (o IdentityCredentialsOidcProvider) MarshalJSON() ([]byte, error) { if o.InitialRefreshToken != nil { toSerialize["initial_refresh_token"] = o.InitialRefreshToken } + if o.Organization != nil { + toSerialize["organization"] = o.Organization + } if o.Provider != nil { toSerialize["provider"] = o.Provider } diff --git a/internal/httpclient/model_login_flow.go b/internal/httpclient/model_login_flow.go index dc7c67ea2649..161377f6b680 100644 --- a/internal/httpclient/model_login_flow.go +++ b/internal/httpclient/model_login_flow.go @@ -30,6 +30,7 @@ type LoginFlow struct { // 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 *string `json:"oauth2_login_challenge,omitempty"` Oauth2LoginRequest *OAuth2LoginRequest `json:"oauth2_login_request,omitempty"` + OrganizationId NullableString `json:"organization_id,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. @@ -272,6 +273,49 @@ func (o *LoginFlow) SetOauth2LoginRequest(v OAuth2LoginRequest) { o.Oauth2LoginRequest = &v } +// GetOrganizationId returns the OrganizationId field value if set, zero value otherwise (both if not set or set to explicit null). +func (o *LoginFlow) GetOrganizationId() string { + if o == nil || o.OrganizationId.Get() == nil { + var ret string + return ret + } + return *o.OrganizationId.Get() +} + +// GetOrganizationIdOk returns a tuple with the OrganizationId 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 *LoginFlow) GetOrganizationIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return o.OrganizationId.Get(), o.OrganizationId.IsSet() +} + +// HasOrganizationId returns a boolean if a field has been set. +func (o *LoginFlow) HasOrganizationId() bool { + if o != nil && o.OrganizationId.IsSet() { + return true + } + + return false +} + +// SetOrganizationId gets a reference to the given NullableString and assigns it to the OrganizationId field. +func (o *LoginFlow) SetOrganizationId(v string) { + o.OrganizationId.Set(&v) +} + +// SetOrganizationIdNil sets the value for OrganizationId to be an explicit nil +func (o *LoginFlow) SetOrganizationIdNil() { + o.OrganizationId.Set(nil) +} + +// UnsetOrganizationId ensures that no value is present for OrganizationId, not even an explicit nil +func (o *LoginFlow) UnsetOrganizationId() { + o.OrganizationId.Unset() +} + // GetRefresh returns the Refresh field value if set, zero value otherwise. func (o *LoginFlow) GetRefresh() bool { if o == nil || o.Refresh == nil { @@ -553,6 +597,9 @@ func (o LoginFlow) MarshalJSON() ([]byte, error) { if o.Oauth2LoginRequest != nil { toSerialize["oauth2_login_request"] = o.Oauth2LoginRequest } + if o.OrganizationId.IsSet() { + toSerialize["organization_id"] = o.OrganizationId.Get() + } if o.Refresh != nil { toSerialize["refresh"] = o.Refresh } diff --git a/internal/httpclient/model_registration_flow.go b/internal/httpclient/model_registration_flow.go index 9b08288d6a16..85d0365ddcb1 100644 --- a/internal/httpclient/model_registration_flow.go +++ b/internal/httpclient/model_registration_flow.go @@ -28,6 +28,7 @@ type RegistrationFlow struct { // 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 *string `json:"oauth2_login_challenge,omitempty"` Oauth2LoginRequest *OAuth2LoginRequest `json:"oauth2_login_request,omitempty"` + OrganizationId NullableString `json:"organization_id,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. @@ -235,6 +236,49 @@ func (o *RegistrationFlow) SetOauth2LoginRequest(v OAuth2LoginRequest) { o.Oauth2LoginRequest = &v } +// GetOrganizationId returns the OrganizationId field value if set, zero value otherwise (both if not set or set to explicit null). +func (o *RegistrationFlow) GetOrganizationId() string { + if o == nil || o.OrganizationId.Get() == nil { + var ret string + return ret + } + return *o.OrganizationId.Get() +} + +// GetOrganizationIdOk returns a tuple with the OrganizationId 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 *RegistrationFlow) GetOrganizationIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return o.OrganizationId.Get(), o.OrganizationId.IsSet() +} + +// HasOrganizationId returns a boolean if a field has been set. +func (o *RegistrationFlow) HasOrganizationId() bool { + if o != nil && o.OrganizationId.IsSet() { + return true + } + + return false +} + +// SetOrganizationId gets a reference to the given NullableString and assigns it to the OrganizationId field. +func (o *RegistrationFlow) SetOrganizationId(v string) { + o.OrganizationId.Set(&v) +} + +// SetOrganizationIdNil sets the value for OrganizationId to be an explicit nil +func (o *RegistrationFlow) SetOrganizationIdNil() { + o.OrganizationId.Set(nil) +} + +// UnsetOrganizationId ensures that no value is present for OrganizationId, not even an explicit nil +func (o *RegistrationFlow) UnsetOrganizationId() { + o.OrganizationId.Unset() +} + // GetRequestUrl returns the RequestUrl field value func (o *RegistrationFlow) GetRequestUrl() string { if o == nil { @@ -449,6 +493,9 @@ func (o RegistrationFlow) MarshalJSON() ([]byte, error) { if o.Oauth2LoginRequest != nil { toSerialize["oauth2_login_request"] = o.Oauth2LoginRequest } + if o.OrganizationId.IsSet() { + toSerialize["organization_id"] = o.OrganizationId.Get() + } if true { toSerialize["request_url"] = o.RequestUrl } diff --git a/internal/httpclient/model_session_authentication_method.go b/internal/httpclient/model_session_authentication_method.go index 032dfb0cc7f6..c887f7df61c6 100644 --- a/internal/httpclient/model_session_authentication_method.go +++ b/internal/httpclient/model_session_authentication_method.go @@ -20,8 +20,9 @@ import ( type SessionAuthenticationMethod struct { Aal *AuthenticatorAssuranceLevel `json:"aal,omitempty"` // When the authentication challenge was completed. - CompletedAt *time.Time `json:"completed_at,omitempty"` - Method *string `json:"method,omitempty"` + CompletedAt *time.Time `json:"completed_at,omitempty"` + Method *string `json:"method,omitempty"` + Organization *string `json:"organization,omitempty"` // OIDC or SAML provider id used for authentication Provider *string `json:"provider,omitempty"` } @@ -139,6 +140,38 @@ func (o *SessionAuthenticationMethod) SetMethod(v string) { o.Method = &v } +// GetOrganization returns the Organization field value if set, zero value otherwise. +func (o *SessionAuthenticationMethod) GetOrganization() string { + if o == nil || o.Organization == nil { + var ret string + return ret + } + return *o.Organization +} + +// GetOrganizationOk returns a tuple with the Organization field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *SessionAuthenticationMethod) GetOrganizationOk() (*string, bool) { + if o == nil || o.Organization == nil { + return nil, false + } + return o.Organization, true +} + +// HasOrganization returns a boolean if a field has been set. +func (o *SessionAuthenticationMethod) HasOrganization() bool { + if o != nil && o.Organization != nil { + return true + } + + return false +} + +// SetOrganization gets a reference to the given string and assigns it to the Organization field. +func (o *SessionAuthenticationMethod) SetOrganization(v string) { + o.Organization = &v +} + // GetProvider returns the Provider field value if set, zero value otherwise. func (o *SessionAuthenticationMethod) GetProvider() string { if o == nil || o.Provider == nil { @@ -182,6 +215,9 @@ func (o SessionAuthenticationMethod) MarshalJSON() ([]byte, error) { if o.Method != nil { toSerialize["method"] = o.Method } + if o.Organization != nil { + toSerialize["organization"] = o.Organization + } if o.Provider != nil { toSerialize["provider"] = o.Provider } diff --git a/persistence/sql/batch/.snapshots/Test_buildInsertQueryArgs-case=Identities.json b/persistence/sql/batch/.snapshots/Test_buildInsertQueryArgs-case=Identities.json index af21f20a0c1a..1f00a62f1ad6 100644 --- a/persistence/sql/batch/.snapshots/Test_buildInsertQueryArgs-case=Identities.json +++ b/persistence/sql/batch/.snapshots/Test_buildInsertQueryArgs-case=Identities.json @@ -1,6 +1,6 @@ { "TableName": "\"identities\"", - "ColumnsDecl": "\"available_aal\", \"created_at\", \"id\", \"metadata_admin\", \"metadata_public\", \"nid\", \"schema_id\", \"state\", \"state_changed_at\", \"traits\", \"updated_at\"", + "ColumnsDecl": "\"available_aal\", \"created_at\", \"id\", \"metadata_admin\", \"metadata_public\", \"nid\", \"organization_id\", \"schema_id\", \"state\", \"state_changed_at\", \"traits\", \"updated_at\"", "Columns": [ "available_aal", "created_at", @@ -8,11 +8,12 @@ "metadata_admin", "metadata_public", "nid", + "organization_id", "schema_id", "state", "state_changed_at", "traits", "updated_at" ], - "Placeholders": "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + "Placeholders": "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),\n(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" } diff --git a/persistence/sql/migratest/fixtures/identity/0149ce5f-76a8-4efe-b2e3-431b8c6cceb6.json b/persistence/sql/migratest/fixtures/identity/0149ce5f-76a8-4efe-b2e3-431b8c6cceb6.json index 89f3c2dae2e3..ce936fc2b72c 100644 --- a/persistence/sql/migratest/fixtures/identity/0149ce5f-76a8-4efe-b2e3-431b8c6cceb6.json +++ b/persistence/sql/migratest/fixtures/identity/0149ce5f-76a8-4efe-b2e3-431b8c6cceb6.json @@ -13,5 +13,6 @@ "baz": "bar" }, "created_at": "2013-10-07T08:23:19Z", - "updated_at": "2013-10-07T08:23:19Z" + "updated_at": "2013-10-07T08:23:19Z", + "organization_id": null } diff --git a/persistence/sql/migratest/fixtures/identity/0149ce5f-76a8-4efe-b2e3-431b8c6cceb7.json b/persistence/sql/migratest/fixtures/identity/0149ce5f-76a8-4efe-b2e3-431b8c6cceb7.json index 634a2313a48e..2cf762904be8 100644 --- a/persistence/sql/migratest/fixtures/identity/0149ce5f-76a8-4efe-b2e3-431b8c6cceb7.json +++ b/persistence/sql/migratest/fixtures/identity/0149ce5f-76a8-4efe-b2e3-431b8c6cceb7.json @@ -13,5 +13,6 @@ "baz": "bar" }, "created_at": "2013-10-07T08:23:19Z", - "updated_at": "2013-10-07T08:23:19Z" + "updated_at": "2013-10-07T08:23:19Z", + "organization_id": null } diff --git a/persistence/sql/migratest/fixtures/identity/196d8c1e-4f04-40f0-94b3-5ec43996b28a.json b/persistence/sql/migratest/fixtures/identity/196d8c1e-4f04-40f0-94b3-5ec43996b28a.json index 86d19547ca63..252268bedab1 100644 --- a/persistence/sql/migratest/fixtures/identity/196d8c1e-4f04-40f0-94b3-5ec43996b28a.json +++ b/persistence/sql/migratest/fixtures/identity/196d8c1e-4f04-40f0-94b3-5ec43996b28a.json @@ -9,5 +9,6 @@ "metadata_public": null, "metadata_admin": null, "created_at": "2013-10-07T08:23:19Z", - "updated_at": "2013-10-07T08:23:19Z" + "updated_at": "2013-10-07T08:23:19Z", + "organization_id": null } diff --git a/persistence/sql/migratest/fixtures/identity/28ff0031-190b-4253-bd15-14308dec013e.json b/persistence/sql/migratest/fixtures/identity/28ff0031-190b-4253-bd15-14308dec013e.json index bed9cbb51ee4..cc42a522a469 100644 --- a/persistence/sql/migratest/fixtures/identity/28ff0031-190b-4253-bd15-14308dec013e.json +++ b/persistence/sql/migratest/fixtures/identity/28ff0031-190b-4253-bd15-14308dec013e.json @@ -13,5 +13,6 @@ "baz": "bar" }, "created_at": "2013-10-07T08:23:19Z", - "updated_at": "2013-10-07T08:23:19Z" + "updated_at": "2013-10-07T08:23:19Z", + "organization_id": null } diff --git a/persistence/sql/migratest/fixtures/identity/2ae6a5a7-2983-49e7-a4d8-7740b37c88cb.json b/persistence/sql/migratest/fixtures/identity/2ae6a5a7-2983-49e7-a4d8-7740b37c88cb.json index c4e285232067..9a5802274eb6 100644 --- a/persistence/sql/migratest/fixtures/identity/2ae6a5a7-2983-49e7-a4d8-7740b37c88cb.json +++ b/persistence/sql/migratest/fixtures/identity/2ae6a5a7-2983-49e7-a4d8-7740b37c88cb.json @@ -9,5 +9,6 @@ "metadata_public": null, "metadata_admin": null, "created_at": "2013-10-07T08:23:19Z", - "updated_at": "2013-10-07T08:23:19Z" + "updated_at": "2013-10-07T08:23:19Z", + "organization_id": null } diff --git a/persistence/sql/migratest/fixtures/identity/308929d3-41a2-43fe-a33c-75308539d841.json b/persistence/sql/migratest/fixtures/identity/308929d3-41a2-43fe-a33c-75308539d841.json index fe14d9ad2f99..798d0effced0 100644 --- a/persistence/sql/migratest/fixtures/identity/308929d3-41a2-43fe-a33c-75308539d841.json +++ b/persistence/sql/migratest/fixtures/identity/308929d3-41a2-43fe-a33c-75308539d841.json @@ -13,5 +13,6 @@ "baz": "bar" }, "created_at": "2013-10-07T08:23:19Z", - "updated_at": "2013-10-07T08:23:19Z" + "updated_at": "2013-10-07T08:23:19Z", + "organization_id": null } diff --git a/persistence/sql/migratest/fixtures/identity/359963ec-b09b-4ea0-aece-fb4dd95f304a.json b/persistence/sql/migratest/fixtures/identity/359963ec-b09b-4ea0-aece-fb4dd95f304a.json index 93d23ad3c0f8..997e385044f4 100644 --- a/persistence/sql/migratest/fixtures/identity/359963ec-b09b-4ea0-aece-fb4dd95f304a.json +++ b/persistence/sql/migratest/fixtures/identity/359963ec-b09b-4ea0-aece-fb4dd95f304a.json @@ -9,5 +9,6 @@ "metadata_public": null, "metadata_admin": null, "created_at": "2013-10-07T08:23:19Z", - "updated_at": "2013-10-07T08:23:19Z" + "updated_at": "2013-10-07T08:23:19Z", + "organization_id": null } diff --git a/persistence/sql/migratest/fixtures/identity/5ff66179-c240-4703-b0d8-494592cefff5.json b/persistence/sql/migratest/fixtures/identity/5ff66179-c240-4703-b0d8-494592cefff5.json index cf61fd2a8bed..55622d8d10d6 100644 --- a/persistence/sql/migratest/fixtures/identity/5ff66179-c240-4703-b0d8-494592cefff5.json +++ b/persistence/sql/migratest/fixtures/identity/5ff66179-c240-4703-b0d8-494592cefff5.json @@ -45,5 +45,6 @@ "metadata_public": null, "metadata_admin": null, "created_at": "2013-10-07T08:23:19Z", - "updated_at": "2013-10-07T08:23:19Z" + "updated_at": "2013-10-07T08:23:19Z", + "organization_id": null } diff --git a/persistence/sql/migratest/fixtures/identity/a251ebc2-880c-4f76-a8f3-38e6940eab0e.json b/persistence/sql/migratest/fixtures/identity/a251ebc2-880c-4f76-a8f3-38e6940eab0e.json index 9c63190a6fa7..073c8eccc4ba 100644 --- a/persistence/sql/migratest/fixtures/identity/a251ebc2-880c-4f76-a8f3-38e6940eab0e.json +++ b/persistence/sql/migratest/fixtures/identity/a251ebc2-880c-4f76-a8f3-38e6940eab0e.json @@ -62,5 +62,6 @@ "metadata_public": null, "metadata_admin": null, "created_at": "2013-10-07T08:23:19Z", - "updated_at": "2013-10-07T08:23:19Z" + "updated_at": "2013-10-07T08:23:19Z", + "organization_id": null } diff --git a/persistence/sql/migratest/fixtures/identity/d7b9addb-ac15-4bc2-9fa5-562e0bf48755.json b/persistence/sql/migratest/fixtures/identity/d7b9addb-ac15-4bc2-9fa5-562e0bf48755.json index 71f79d95eb9a..2591e1ed43bc 100644 --- a/persistence/sql/migratest/fixtures/identity/d7b9addb-ac15-4bc2-9fa5-562e0bf48755.json +++ b/persistence/sql/migratest/fixtures/identity/d7b9addb-ac15-4bc2-9fa5-562e0bf48755.json @@ -9,5 +9,6 @@ "metadata_public": null, "metadata_admin": null, "created_at": "2013-10-07T08:23:19Z", - "updated_at": "2013-10-07T08:23:19Z" + "updated_at": "2013-10-07T08:23:19Z", + "organization_id": null } diff --git a/persistence/sql/migratest/fixtures/identity/ed253b2c-48ed-4c58-9b6f-1dc963c30a66.json b/persistence/sql/migratest/fixtures/identity/ed253b2c-48ed-4c58-9b6f-1dc963c30a66.json index 6f4d055e1c7a..9a208bfaff8a 100644 --- a/persistence/sql/migratest/fixtures/identity/ed253b2c-48ed-4c58-9b6f-1dc963c30a66.json +++ b/persistence/sql/migratest/fixtures/identity/ed253b2c-48ed-4c58-9b6f-1dc963c30a66.json @@ -9,5 +9,6 @@ "metadata_public": null, "metadata_admin": null, "created_at": "2013-10-07T08:23:19Z", - "updated_at": "2013-10-07T08:23:19Z" + "updated_at": "2013-10-07T08:23:19Z", + "organization_id": null } diff --git a/persistence/sql/migratest/fixtures/login_flow/00b1517f-2467-4aaf-b0a5-82b4a27dcaf5.json b/persistence/sql/migratest/fixtures/login_flow/00b1517f-2467-4aaf-b0a5-82b4a27dcaf5.json index 17f770efbe90..837de1c52731 100644 --- a/persistence/sql/migratest/fixtures/login_flow/00b1517f-2467-4aaf-b0a5-82b4a27dcaf5.json +++ b/persistence/sql/migratest/fixtures/login_flow/00b1517f-2467-4aaf-b0a5-82b4a27dcaf5.json @@ -1,5 +1,6 @@ { "id": "00b1517f-2467-4aaf-b0a5-82b4a27dcaf5", + "organization_id": null, "oauth2_login_challenge": "challenge data", "type": "api", "expires_at": "2013-10-07T08:23:19Z", 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 ce8841aa07ff..eeaa7f9b8c04 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", + "organization_id": 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 770f0b2e2c38..cd6619eb23c0 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", + "organization_id": 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 b6cd377d812f..d5c8bac1fea6 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", + "organization_id": 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 index effdc9f1f2a0..5aca17468521 100644 --- 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 @@ -1,5 +1,6 @@ { "id": "349c945a-60f8-436a-a301-7a42c92604f9", + "organization_id": 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/38caf592-b042-4551-b92f-8d5223c2a4e2.json b/persistence/sql/migratest/fixtures/login_flow/38caf592-b042-4551-b92f-8d5223c2a4e2.json index 6eac76a4e91b..83a1fd65700e 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", + "organization_id": 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 577b054917db..7a56b04c704b 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", + "organization_id": 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 6f0fae29f575..392e31ac4aeb 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", + "organization_id": 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 64a415dfba4a..d9244b34ed63 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", + "organization_id": 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 e2ccb8f7616d..8307d8ff37c5 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", + "organization_id": 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 863594687d00..114fc6b8e0b2 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", + "organization_id": 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 138f4838c466..27c654033fa6 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", + "organization_id": 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 41bc0e84748f..bfcc30b0f79b 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", + "organization_id": 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 ae28f38c8fe4..0023c80a2a3b 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", + "organization_id": 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/cccccccc-dda4-4700-9e42-35731f2af911.json b/persistence/sql/migratest/fixtures/login_flow/cccccccc-dda4-4700-9e42-35731f2af911.json index a2b9861acec7..e48d123f8904 100644 --- a/persistence/sql/migratest/fixtures/login_flow/cccccccc-dda4-4700-9e42-35731f2af911.json +++ b/persistence/sql/migratest/fixtures/login_flow/cccccccc-dda4-4700-9e42-35731f2af911.json @@ -1,5 +1,6 @@ { "id": "cccccccc-dda4-4700-9e42-35731f2af911", + "organization_id": null, "oauth2_login_challenge": "challenge data", "type": "api", "expires_at": "2013-10-07T08:23:19Z", diff --git a/persistence/sql/migratest/fixtures/login_flow/cccccccc-dda4-4700-9e42-35731f2af91e.json b/persistence/sql/migratest/fixtures/login_flow/cccccccc-dda4-4700-9e42-35731f2af91e.json index e2d58f6dc1fe..ca25b3085c8b 100644 --- a/persistence/sql/migratest/fixtures/login_flow/cccccccc-dda4-4700-9e42-35731f2af91e.json +++ b/persistence/sql/migratest/fixtures/login_flow/cccccccc-dda4-4700-9e42-35731f2af91e.json @@ -1,5 +1,6 @@ { "id": "cccccccc-dda4-4700-9e42-35731f2af91e", + "organization_id": null, "oauth2_login_challenge": "challenge data", "type": "api", "expires_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 00a1a2d7c3e5..6b60fce7bc97 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", + "organization_id": 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 ccfcf94814a5..beb3815ee0d2 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 @@ -9,5 +9,6 @@ "method": "", "nodes": null }, + "organization_id": null, "state": "" } 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 5c110a3394f5..22559499461d 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 @@ -9,5 +9,6 @@ "method": "", "nodes": null }, + "organization_id": null, "state": "" } 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 8df52efff06b..bb9d425d6001 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 @@ -9,5 +9,6 @@ "method": "", "nodes": null }, + "organization_id": null, "state": "" } 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 d58beb9edffc..a7ccfd6f84b7 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 @@ -10,5 +10,6 @@ "method": "", "nodes": null }, + "organization_id": null, "state": "" } diff --git a/persistence/sql/migratest/fixtures/registration_flow/69c80296-36cd-4afc-921a-15369cac5bf0.json b/persistence/sql/migratest/fixtures/registration_flow/69c80296-36cd-4afc-921a-15369cac5bf0.json index 6179619c71fe..10c88c29c5a9 100644 --- a/persistence/sql/migratest/fixtures/registration_flow/69c80296-36cd-4afc-921a-15369cac5bf0.json +++ b/persistence/sql/migratest/fixtures/registration_flow/69c80296-36cd-4afc-921a-15369cac5bf0.json @@ -10,5 +10,6 @@ "method": "", "nodes": null }, + "organization_id": null, "state": "choose_method" } 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 19104b6d9f26..95d84caf5235 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 @@ -10,5 +10,6 @@ "method": "", "nodes": null }, + "organization_id": null, "state": "" } 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 616af278cd82..68f36b946d79 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 @@ -10,5 +10,6 @@ "method": "", "nodes": null }, + "organization_id": null, "state": "" } 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 a1f323ba3c4d..4226d48042ef 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 @@ -10,5 +10,6 @@ "method": "", "nodes": null }, + "organization_id": null, "state": "" } 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 1e6cc2579af2..2501f4fcef9c 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 @@ -10,5 +10,6 @@ "method": "", "nodes": null }, + "organization_id": null, "state": "" } 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 560741f9a18d..15173755e9e4 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 @@ -10,5 +10,6 @@ "method": "", "nodes": null }, + "organization_id": null, "state": "" } diff --git a/persistence/sql/migratest/fixtures/registration_flow/ef18b06e-4700-4021-9949-ef783cd86be1.json b/persistence/sql/migratest/fixtures/registration_flow/ef18b06e-4700-4021-9949-ef783cd86be1.json index ce1272433edf..da36c662bfe5 100644 --- a/persistence/sql/migratest/fixtures/registration_flow/ef18b06e-4700-4021-9949-ef783cd86be1.json +++ b/persistence/sql/migratest/fixtures/registration_flow/ef18b06e-4700-4021-9949-ef783cd86be1.json @@ -10,5 +10,6 @@ "method": "", "nodes": null }, + "organization_id": null, "state": "" } 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 index 4d1d58bdaf51..68bfeb3da8b0 100644 --- 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 @@ -10,5 +10,6 @@ "method": "", "nodes": null }, + "organization_id": null, "state": "" } 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 c7d1b8207a4e..4c10f10594e4 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 @@ -10,5 +10,6 @@ "method": "", "nodes": null }, + "organization_id": null, "state": "" } diff --git a/persistence/sql/migratest/fixtures/session/068f6bb6-d15f-436d-94f7-b3fd0489c9ef.json b/persistence/sql/migratest/fixtures/session/068f6bb6-d15f-436d-94f7-b3fd0489c9ef.json index 8c641a193e30..4c8fb26fc316 100644 --- a/persistence/sql/migratest/fixtures/session/068f6bb6-d15f-436d-94f7-b3fd0489c9ef.json +++ b/persistence/sql/migratest/fixtures/session/068f6bb6-d15f-436d-94f7-b3fd0489c9ef.json @@ -38,7 +38,8 @@ ], "metadata_public": null, "created_at": "2013-10-07T08:23:19Z", - "updated_at": "2013-10-07T08:23:19Z" + "updated_at": "2013-10-07T08:23:19Z", + "organization_id": null }, "devices": [] } diff --git a/persistence/sql/migratest/fixtures/session/7458af86-c1d8-401c-978a-8da89133f78b.json b/persistence/sql/migratest/fixtures/session/7458af86-c1d8-401c-978a-8da89133f78b.json index 990e5925ec0e..8d96bfed4e84 100644 --- a/persistence/sql/migratest/fixtures/session/7458af86-c1d8-401c-978a-8da89133f78b.json +++ b/persistence/sql/migratest/fixtures/session/7458af86-c1d8-401c-978a-8da89133f78b.json @@ -38,7 +38,8 @@ ], "metadata_public": null, "created_at": "2013-10-07T08:23:19Z", - "updated_at": "2013-10-07T08:23:19Z" + "updated_at": "2013-10-07T08:23:19Z", + "organization_id": null }, "devices": [] } diff --git a/persistence/sql/migratest/fixtures/session/7458af86-c1d8-401c-978a-8da89133f98b.json b/persistence/sql/migratest/fixtures/session/7458af86-c1d8-401c-978a-8da89133f98b.json index ccc7ed2e0a63..c033cccee191 100644 --- a/persistence/sql/migratest/fixtures/session/7458af86-c1d8-401c-978a-8da89133f98b.json +++ b/persistence/sql/migratest/fixtures/session/7458af86-c1d8-401c-978a-8da89133f98b.json @@ -38,7 +38,8 @@ ], "metadata_public": null, "created_at": "2013-10-07T08:23:19Z", - "updated_at": "2013-10-07T08:23:19Z" + "updated_at": "2013-10-07T08:23:19Z", + "organization_id": null }, "devices": [ { diff --git a/persistence/sql/migratest/fixtures/session/8571e374-38f2-4f46-8ad3-b9d914e174d3.json b/persistence/sql/migratest/fixtures/session/8571e374-38f2-4f46-8ad3-b9d914e174d3.json index 24e7ac8f3535..625530c7007b 100644 --- a/persistence/sql/migratest/fixtures/session/8571e374-38f2-4f46-8ad3-b9d914e174d3.json +++ b/persistence/sql/migratest/fixtures/session/8571e374-38f2-4f46-8ad3-b9d914e174d3.json @@ -33,7 +33,8 @@ ], "metadata_public": null, "created_at": "2013-10-07T08:23:19Z", - "updated_at": "2013-10-07T08:23:19Z" + "updated_at": "2013-10-07T08:23:19Z", + "organization_id": null }, "devices": [] } diff --git a/persistence/sql/migratest/fixtures/session/dcde5aaa-f789-4d3d-ae1f-76da8d57e67c.json b/persistence/sql/migratest/fixtures/session/dcde5aaa-f789-4d3d-ae1f-76da8d57e67c.json index dcec9dc414a3..895bfdffbeda 100644 --- a/persistence/sql/migratest/fixtures/session/dcde5aaa-f789-4d3d-ae1f-76da8d57e67c.json +++ b/persistence/sql/migratest/fixtures/session/dcde5aaa-f789-4d3d-ae1f-76da8d57e67c.json @@ -33,7 +33,8 @@ ], "metadata_public": null, "created_at": "2013-10-07T08:23:19Z", - "updated_at": "2013-10-07T08:23:19Z" + "updated_at": "2013-10-07T08:23:19Z", + "organization_id": null }, "devices": [] } diff --git a/persistence/sql/migratest/fixtures/session/f38cdebe-e567-42c9-a562-1bd4dee40998.json b/persistence/sql/migratest/fixtures/session/f38cdebe-e567-42c9-a562-1bd4dee40998.json index 6fcad6937cc0..1b4474dc4269 100644 --- a/persistence/sql/migratest/fixtures/session/f38cdebe-e567-42c9-a562-1bd4dee40998.json +++ b/persistence/sql/migratest/fixtures/session/f38cdebe-e567-42c9-a562-1bd4dee40998.json @@ -33,7 +33,8 @@ ], "metadata_public": null, "created_at": "2013-10-07T08:23:19Z", - "updated_at": "2013-10-07T08:23:19Z" + "updated_at": "2013-10-07T08:23:19Z", + "organization_id": null }, "devices": [] } diff --git a/persistence/sql/migratest/fixtures/settings_flow/194c5b05-0487-4a11-bcbc-f301c9ff9678.json b/persistence/sql/migratest/fixtures/settings_flow/194c5b05-0487-4a11-bcbc-f301c9ff9678.json index 7733d6357033..258dcd97e8b4 100644 --- a/persistence/sql/migratest/fixtures/settings_flow/194c5b05-0487-4a11-bcbc-f301c9ff9678.json +++ b/persistence/sql/migratest/fixtures/settings_flow/194c5b05-0487-4a11-bcbc-f301c9ff9678.json @@ -57,7 +57,8 @@ ], "metadata_public": null, "created_at": "2013-10-07T08:23:19Z", - "updated_at": "2013-10-07T08:23:19Z" + "updated_at": "2013-10-07T08:23:19Z", + "organization_id": null }, "state": "show_form" } diff --git a/persistence/sql/migratest/fixtures/settings_flow/19ede218-928c-4e02-ab49-b76e12b34f31.json b/persistence/sql/migratest/fixtures/settings_flow/19ede218-928c-4e02-ab49-b76e12b34f31.json index 3b7d3348a868..d14aec4ca29f 100644 --- a/persistence/sql/migratest/fixtures/settings_flow/19ede218-928c-4e02-ab49-b76e12b34f31.json +++ b/persistence/sql/migratest/fixtures/settings_flow/19ede218-928c-4e02-ab49-b76e12b34f31.json @@ -58,7 +58,8 @@ ], "metadata_public": null, "created_at": "2013-10-07T08:23:19Z", - "updated_at": "2013-10-07T08:23:19Z" + "updated_at": "2013-10-07T08:23:19Z", + "organization_id": null }, "state": "show_form" } diff --git a/persistence/sql/migratest/fixtures/settings_flow/19ede218-928c-4e02-ab49-b76e12b34f32.json b/persistence/sql/migratest/fixtures/settings_flow/19ede218-928c-4e02-ab49-b76e12b34f32.json index 4c42c9c07cd4..04e2d50e6d95 100644 --- a/persistence/sql/migratest/fixtures/settings_flow/19ede218-928c-4e02-ab49-b76e12b34f32.json +++ b/persistence/sql/migratest/fixtures/settings_flow/19ede218-928c-4e02-ab49-b76e12b34f32.json @@ -58,7 +58,8 @@ ], "metadata_public": null, "created_at": "2013-10-07T08:23:19Z", - "updated_at": "2013-10-07T08:23:19Z" + "updated_at": "2013-10-07T08:23:19Z", + "organization_id": null }, "state": "show_form" } diff --git a/persistence/sql/migratest/fixtures/settings_flow/21c5f714-3089-49d2-b387-f244d4dd9e00.json b/persistence/sql/migratest/fixtures/settings_flow/21c5f714-3089-49d2-b387-f244d4dd9e00.json index a66391f475fa..691eeee92d02 100644 --- a/persistence/sql/migratest/fixtures/settings_flow/21c5f714-3089-49d2-b387-f244d4dd9e00.json +++ b/persistence/sql/migratest/fixtures/settings_flow/21c5f714-3089-49d2-b387-f244d4dd9e00.json @@ -58,7 +58,8 @@ ], "metadata_public": null, "created_at": "2013-10-07T08:23:19Z", - "updated_at": "2013-10-07T08:23:19Z" + "updated_at": "2013-10-07T08:23:19Z", + "organization_id": null }, "state": "show_form" } diff --git a/persistence/sql/migratest/fixtures/settings_flow/74fd6c53-7651-453e-90b8-2c5adbf911bb.json b/persistence/sql/migratest/fixtures/settings_flow/74fd6c53-7651-453e-90b8-2c5adbf911bb.json index a1499fa10e1c..33055e289329 100644 --- a/persistence/sql/migratest/fixtures/settings_flow/74fd6c53-7651-453e-90b8-2c5adbf911bb.json +++ b/persistence/sql/migratest/fixtures/settings_flow/74fd6c53-7651-453e-90b8-2c5adbf911bb.json @@ -30,7 +30,8 @@ ], "metadata_public": null, "created_at": "2013-10-07T08:23:19Z", - "updated_at": "2013-10-07T08:23:19Z" + "updated_at": "2013-10-07T08:23:19Z", + "organization_id": null }, "state": "show_form" } diff --git a/persistence/sql/migratest/fixtures/settings_flow/77fe4fb3-2d4e-4532-b568-c44b0aece0aa.json b/persistence/sql/migratest/fixtures/settings_flow/77fe4fb3-2d4e-4532-b568-c44b0aece0aa.json index 0d7893fdd23c..e4b41a57eda1 100644 --- a/persistence/sql/migratest/fixtures/settings_flow/77fe4fb3-2d4e-4532-b568-c44b0aece0aa.json +++ b/persistence/sql/migratest/fixtures/settings_flow/77fe4fb3-2d4e-4532-b568-c44b0aece0aa.json @@ -58,7 +58,8 @@ ], "metadata_public": null, "created_at": "2013-10-07T08:23:19Z", - "updated_at": "2013-10-07T08:23:19Z" + "updated_at": "2013-10-07T08:23:19Z", + "organization_id": null }, "state": "show_form" } diff --git a/persistence/sql/migratest/fixtures/settings_flow/8248bb5d-8ef7-45e3-8e07-9e2003dd5352.json b/persistence/sql/migratest/fixtures/settings_flow/8248bb5d-8ef7-45e3-8e07-9e2003dd5352.json index 2f3a9a21496c..87af942e7177 100644 --- a/persistence/sql/migratest/fixtures/settings_flow/8248bb5d-8ef7-45e3-8e07-9e2003dd5352.json +++ b/persistence/sql/migratest/fixtures/settings_flow/8248bb5d-8ef7-45e3-8e07-9e2003dd5352.json @@ -58,7 +58,8 @@ ], "metadata_public": null, "created_at": "2013-10-07T08:23:19Z", - "updated_at": "2013-10-07T08:23:19Z" + "updated_at": "2013-10-07T08:23:19Z", + "organization_id": null }, "state": "show_form" } diff --git a/persistence/sql/migratest/fixtures/settings_flow/90b4f970-b9ae-42bc-a0a7-73ec750e0aa1.json b/persistence/sql/migratest/fixtures/settings_flow/90b4f970-b9ae-42bc-a0a7-73ec750e0aa1.json index b13dadb6aba2..3df5e29f2a61 100644 --- a/persistence/sql/migratest/fixtures/settings_flow/90b4f970-b9ae-42bc-a0a7-73ec750e0aa1.json +++ b/persistence/sql/migratest/fixtures/settings_flow/90b4f970-b9ae-42bc-a0a7-73ec750e0aa1.json @@ -58,7 +58,8 @@ ], "metadata_public": null, "created_at": "2013-10-07T08:23:19Z", - "updated_at": "2013-10-07T08:23:19Z" + "updated_at": "2013-10-07T08:23:19Z", + "organization_id": null }, "state": "show_form" } diff --git a/persistence/sql/migratest/fixtures/settings_flow/a79bfcf1-68ae-49de-8b23-4f96921b8341.json b/persistence/sql/migratest/fixtures/settings_flow/a79bfcf1-68ae-49de-8b23-4f96921b8341.json index cc80b32fb4ae..03890e50ef6b 100644 --- a/persistence/sql/migratest/fixtures/settings_flow/a79bfcf1-68ae-49de-8b23-4f96921b8341.json +++ b/persistence/sql/migratest/fixtures/settings_flow/a79bfcf1-68ae-49de-8b23-4f96921b8341.json @@ -58,7 +58,8 @@ ], "metadata_public": null, "created_at": "2013-10-07T08:23:19Z", - "updated_at": "2013-10-07T08:23:19Z" + "updated_at": "2013-10-07T08:23:19Z", + "organization_id": null }, "state": "show_form" } diff --git a/persistence/sql/migratest/fixtures/settings_flow/aeba85bd-1a8c-44bf-8fc3-3be83c01a3dc.json b/persistence/sql/migratest/fixtures/settings_flow/aeba85bd-1a8c-44bf-8fc3-3be83c01a3dc.json index d2409100456c..67a14d02dadb 100644 --- a/persistence/sql/migratest/fixtures/settings_flow/aeba85bd-1a8c-44bf-8fc3-3be83c01a3dc.json +++ b/persistence/sql/migratest/fixtures/settings_flow/aeba85bd-1a8c-44bf-8fc3-3be83c01a3dc.json @@ -58,7 +58,8 @@ ], "metadata_public": null, "created_at": "2013-10-07T08:23:19Z", - "updated_at": "2013-10-07T08:23:19Z" + "updated_at": "2013-10-07T08:23:19Z", + "organization_id": null }, "state": "show_form" } diff --git a/persistence/sql/migratest/fixtures/settings_flow/cdfd1eed-34a4-491d-ad0a-7579d3a0a7ba.json b/persistence/sql/migratest/fixtures/settings_flow/cdfd1eed-34a4-491d-ad0a-7579d3a0a7ba.json index 4fdbab4b561e..c4850694d35f 100644 --- a/persistence/sql/migratest/fixtures/settings_flow/cdfd1eed-34a4-491d-ad0a-7579d3a0a7ba.json +++ b/persistence/sql/migratest/fixtures/settings_flow/cdfd1eed-34a4-491d-ad0a-7579d3a0a7ba.json @@ -58,7 +58,8 @@ ], "metadata_public": null, "created_at": "2013-10-07T08:23:19Z", - "updated_at": "2013-10-07T08:23:19Z" + "updated_at": "2013-10-07T08:23:19Z", + "organization_id": null }, "state": "show_form" } diff --git a/persistence/sql/migrations/sql/20230907085000000000_add_organization_id.down.sql b/persistence/sql/migrations/sql/20230907085000000000_add_organization_id.down.sql new file mode 100644 index 000000000000..d9e10922355b --- /dev/null +++ b/persistence/sql/migrations/sql/20230907085000000000_add_organization_id.down.sql @@ -0,0 +1,3 @@ +alter table selfservice_login_flows drop column organization_id; +alter table selfservice_registration_flows drop column organization_id; +alter table identities drop column organization_id; diff --git a/persistence/sql/migrations/sql/20230907085000000000_add_organization_id.mysql.up.sql b/persistence/sql/migrations/sql/20230907085000000000_add_organization_id.mysql.up.sql new file mode 100644 index 000000000000..55974d67d24b --- /dev/null +++ b/persistence/sql/migrations/sql/20230907085000000000_add_organization_id.mysql.up.sql @@ -0,0 +1,3 @@ +alter table selfservice_login_flows add column organization_id char(36) null; +alter table selfservice_registration_flows add column organization_id char(36) null; +alter table identities add column organization_id char(36) null; diff --git a/persistence/sql/migrations/sql/20230907085000000000_add_organization_id.up.sql b/persistence/sql/migrations/sql/20230907085000000000_add_organization_id.up.sql new file mode 100644 index 000000000000..8f2be2cbadb2 --- /dev/null +++ b/persistence/sql/migrations/sql/20230907085000000000_add_organization_id.up.sql @@ -0,0 +1,3 @@ +alter table selfservice_login_flows add column organization_id uuid null; +alter table selfservice_registration_flows add column organization_id uuid null; +alter table identities add column organization_id uuid null; diff --git a/selfservice/flow/login/flow.go b/selfservice/flow/login/flow.go index 6e7426bd578c..1bd95c7b1fad 100644 --- a/selfservice/flow/login/flow.go +++ b/selfservice/flow/login/flow.go @@ -50,8 +50,9 @@ type Flow struct { // represents the id in the login UI's query parameter: http:///?flow= // // required: true - ID uuid.UUID `json:"id" faker:"-" db:"id" rw:"r"` - NID uuid.UUID `json:"-" faker:"-" db:"nid"` + ID uuid.UUID `json:"id" faker:"-" db:"id" rw:"r"` + NID uuid.UUID `json:"-" faker:"-" db:"nid"` + OrganizationID uuid.NullUUID `json:"organization_id,omitempty" faker:"-" db:"organization_id"` // Ory OAuth 2.0 Login Challenge. // diff --git a/selfservice/flow/login/handler.go b/selfservice/flow/login/handler.go index aa512f8c2574..e965d9758025 100644 --- a/selfservice/flow/login/handler.go +++ b/selfservice/flow/login/handler.go @@ -56,6 +56,7 @@ type ( config.Provider ErrorHandlerProvider sessiontokenexchange.PersistenceProvider + x.LoggingProvider } HandlerProvider interface { LoginHandler() *Handler @@ -187,8 +188,17 @@ preLoginHook: f.UI.Messages.Add(text.NewInfoLoginMFA()) } - var s Strategy - for _, s = range h.d.LoginStrategies(r.Context()) { + var strategyFilters []StrategyFilter + if rawOrg := r.URL.Query().Get("organization"); rawOrg != "" { + orgID, err := uuid.FromString(rawOrg) + if err != nil { + h.d.Logger().WithError(err).Warnf("Ignoring invalid UUID %q in query parameter `organization`.", rawOrg) + } else { + f.OrganizationID = uuid.NullUUID{UUID: orgID, Valid: true} + strategyFilters = []StrategyFilter{func(s Strategy) bool { return s.ID() == identity.CredentialsTypeOIDC }} + } + } + for _, s := range h.d.LoginStrategies(r.Context(), strategyFilters...) { if err := s.PopulateLoginMethod(r, f.RequestedAAL, f); err != nil { return nil, nil, err } @@ -360,6 +370,13 @@ type createBrowserLoginFlow struct { // required: false // in: query HydraLoginChallenge string `json:"login_challenge"` + + // An optional organization ID that should be used for logging this user in. + // This parameter is only effective in the Ory Network. + // + // required: false + // in: query + Organization string `json:"organization"` } // swagger:route GET /self-service/login/browser frontend createBrowserLoginFlow diff --git a/selfservice/flow/login/strategy.go b/selfservice/flow/login/strategy.go index 91de3d276963..818ecfea9cf0 100644 --- a/selfservice/flow/login/strategy.go +++ b/selfservice/flow/login/strategy.go @@ -55,7 +55,9 @@ func (s Strategies) RegisterPublicRoutes(r *x.RouterPublic) { } } +type StrategyFilter func(strategy Strategy) bool + type StrategyProvider interface { AllLoginStrategies() Strategies - LoginStrategies(ctx context.Context) Strategies + LoginStrategies(ctx context.Context, filters ...StrategyFilter) Strategies } diff --git a/selfservice/flow/registration/flow.go b/selfservice/flow/registration/flow.go index 085cf353c8be..494bf72383af 100644 --- a/selfservice/flow/registration/flow.go +++ b/selfservice/flow/registration/flow.go @@ -99,8 +99,9 @@ type Flow struct { UpdatedAt time.Time `json:"-" faker:"-" db:"updated_at"` // CSRFToken contains the anti-csrf token associated with this flow. Only set for browser flows. - CSRFToken string `json:"-" db:"csrf_token"` - NID uuid.UUID `json:"-" faker:"-" db:"nid"` + CSRFToken string `json:"-" db:"csrf_token"` + NID uuid.UUID `json:"-" faker:"-" db:"nid"` + OrganizationID uuid.NullUUID `json:"organization_id,omitempty" faker:"-" db:"organization_id"` // TransientPayload is used to pass data from the registration to a webhook TransientPayload json.RawMessage `json:"transient_payload,omitempty" faker:"-" db:"-"` diff --git a/selfservice/flow/registration/handler.go b/selfservice/flow/registration/handler.go index 91242f6bf26b..d58ff4c9e735 100644 --- a/selfservice/flow/registration/handler.go +++ b/selfservice/flow/registration/handler.go @@ -8,6 +8,8 @@ import ( "net/url" "time" + "github.com/gofrs/uuid" + "github.com/ory/herodot" "github.com/ory/kratos/hydra" "github.com/ory/kratos/selfservice/sessiontokenexchange" @@ -57,6 +59,7 @@ type ( FlowPersistenceProvider ErrorHandlerProvider sessiontokenexchange.PersistenceProvider + x.LoggingProvider } HandlerProvider interface { RegistrationHandler() *Handler @@ -136,7 +139,17 @@ func (h *Handler) NewRegistrationFlow(w http.ResponseWriter, r *http.Request, ft f.SessionTokenExchangeCode = e.InitCode } - for _, s := range h.d.RegistrationStrategies(r.Context()) { + var strategyFilters []StrategyFilter + if rawOrg := r.URL.Query().Get("organization"); rawOrg != "" { + orgID, err := uuid.FromString(rawOrg) + if err != nil { + h.d.Logger().WithError(err).Warnf("ignoring invalid UUID %q in query parameter `organization`", rawOrg) + } else { + f.OrganizationID = uuid.NullUUID{UUID: orgID, Valid: true} + strategyFilters = []StrategyFilter{func(s Strategy) bool { return s.ID() == identity.CredentialsTypeOIDC }} + } + } + for _, s := range h.d.RegistrationStrategies(r.Context(), strategyFilters...) { if err := s.PopulateRegistrationMethod(r, f); err != nil { return nil, err } @@ -265,6 +278,10 @@ type createBrowserRegistrationFlow struct { // required: false // in: query AfterVerificationReturnTo string `json:"after_verification_return_to"` + + // required: false + // in: query + Organization string `json:"organization"` } // swagger:route GET /self-service/registration/browser frontend createBrowserRegistrationFlow diff --git a/selfservice/flow/registration/hook.go b/selfservice/flow/registration/hook.go index a10d2a4daa07..20538ccfe1e6 100644 --- a/selfservice/flow/registration/hook.go +++ b/selfservice/flow/registration/hook.go @@ -9,6 +9,7 @@ import ( "net/http" "time" + "github.com/julienschmidt/httprouter" "go.opentelemetry.io/otel/trace" "github.com/ory/kratos/selfservice/sessiontokenexchange" @@ -167,7 +168,9 @@ func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Reque trace.SpanFromContext(r.Context()).AddEvent(events.NewRegistrationSucceeded(r.Context(), i.ID, string(a.Type), a.Active.String(), provider)) s := session.NewInactiveSession() - s.CompletedLoginForWithProvider(ct, identity.AuthenticatorAssuranceLevel1, provider) + + s.CompletedLoginForWithProvider(ct, identity.AuthenticatorAssuranceLevel1, provider, + httprouter.ParamsFromContext(r.Context()).ByName("organization")) if err := s.Activate(r, i, c, time.Now().UTC()); err != nil { return err } diff --git a/selfservice/flow/registration/strategy.go b/selfservice/flow/registration/strategy.go index 7fa8efd78cd2..7524eb350764 100644 --- a/selfservice/flow/registration/strategy.go +++ b/selfservice/flow/registration/strategy.go @@ -51,7 +51,9 @@ func (s Strategies) RegisterPublicRoutes(r *x.RouterPublic) { } } +type StrategyFilter func(strategy Strategy) bool + type StrategyProvider interface { - RegistrationStrategies(ctx context.Context) Strategies + RegistrationStrategies(ctx context.Context, filters ...StrategyFilter) Strategies AllRegistrationStrategies() Strategies } diff --git a/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=body_is_empty.json b/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=body_is_empty.json index 5cc825657c23..06206d1517e8 100644 --- a/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=body_is_empty.json +++ b/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=body_is_empty.json @@ -47,5 +47,6 @@ "admin": "data" }, "created_at": "0001-01-01T00:00:00Z", - "updated_at": "0001-01-01T00:00:00Z" + "updated_at": "0001-01-01T00:00:00Z", + "organization_id": null } diff --git a/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_has_updated_admin_metadata.json b/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_has_updated_admin_metadata.json index 5cc825657c23..06206d1517e8 100644 --- a/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_has_updated_admin_metadata.json +++ b/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_has_updated_admin_metadata.json @@ -47,5 +47,6 @@ "admin": "data" }, "created_at": "0001-01-01T00:00:00Z", - "updated_at": "0001-01-01T00:00:00Z" + "updated_at": "0001-01-01T00:00:00Z", + "organization_id": null } diff --git a/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_has_updated_public_metadata.json b/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_has_updated_public_metadata.json index 47d0200bd9e2..d3f2123e251d 100644 --- a/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_has_updated_public_metadata.json +++ b/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_has_updated_public_metadata.json @@ -47,5 +47,6 @@ "admin": "data" }, "created_at": "0001-01-01T00:00:00Z", - "updated_at": "0001-01-01T00:00:00Z" + "updated_at": "0001-01-01T00:00:00Z", + "organization_id": null } diff --git a/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_has_updated_recovery_addresses.json b/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_has_updated_recovery_addresses.json index 5468c64f6e6d..6ac68c9dad02 100644 --- a/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_has_updated_recovery_addresses.json +++ b/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_has_updated_recovery_addresses.json @@ -47,5 +47,6 @@ "admin": "data" }, "created_at": "0001-01-01T00:00:00Z", - "updated_at": "0001-01-01T00:00:00Z" + "updated_at": "0001-01-01T00:00:00Z", + "organization_id": null } diff --git a/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_has_updated_state.json b/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_has_updated_state.json index a29fca67072b..d2c8048eca70 100644 --- a/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_has_updated_state.json +++ b/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_has_updated_state.json @@ -47,5 +47,6 @@ "admin": "data" }, "created_at": "0001-01-01T00:00:00Z", - "updated_at": "0001-01-01T00:00:00Z" + "updated_at": "0001-01-01T00:00:00Z", + "organization_id": null } diff --git a/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_has_updated_traits.json b/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_has_updated_traits.json index eee811bea641..12f86f05c436 100644 --- a/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_has_updated_traits.json +++ b/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_has_updated_traits.json @@ -47,5 +47,6 @@ "admin": "data" }, "created_at": "0001-01-01T00:00:00Z", - "updated_at": "0001-01-01T00:00:00Z" + "updated_at": "0001-01-01T00:00:00Z", + "organization_id": null } diff --git a/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_has_updated_verified_addresses.json b/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_has_updated_verified_addresses.json index aac455d717b6..52f6e02e1025 100644 --- a/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_has_updated_verified_addresses.json +++ b/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_has_updated_verified_addresses.json @@ -47,5 +47,6 @@ "admin": "data" }, "created_at": "0001-01-01T00:00:00Z", - "updated_at": "0001-01-01T00:00:00Z" + "updated_at": "0001-01-01T00:00:00Z", + "organization_id": null } diff --git a/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_is_present_but_empty.json b/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_is_present_but_empty.json index 5cc825657c23..06206d1517e8 100644 --- a/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_is_present_but_empty.json +++ b/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_is_present_but_empty.json @@ -47,5 +47,6 @@ "admin": "data" }, "created_at": "0001-01-01T00:00:00Z", - "updated_at": "0001-01-01T00:00:00Z" + "updated_at": "0001-01-01T00:00:00Z", + "organization_id": null } diff --git a/selfservice/strategy/code/strategy.go b/selfservice/strategy/code/strategy.go index 229c6dfaf8d1..6044db79de0f 100644 --- a/selfservice/strategy/code/strategy.go +++ b/selfservice/strategy/code/strategy.go @@ -118,8 +118,8 @@ type ( } ) -func NewStrategy(deps strategyDependencies) *Strategy { - return &Strategy{deps: deps, dx: decoderx.NewHTTP()} +func NewStrategy(deps any) *Strategy { + return &Strategy{deps: deps.(strategyDependencies), dx: decoderx.NewHTTP()} } func (s *Strategy) ID() identity.CredentialsType { diff --git a/selfservice/strategy/link/strategy.go b/selfservice/strategy/link/strategy.go index da66e1816bf5..f5a0326b9d0b 100644 --- a/selfservice/strategy/link/strategy.go +++ b/selfservice/strategy/link/strategy.go @@ -83,8 +83,8 @@ type ( } ) -func NewStrategy(d strategyDependencies) *Strategy { - return &Strategy{d: d, dx: decoderx.NewHTTP()} +func NewStrategy(d any) *Strategy { + return &Strategy{d: d.(strategyDependencies), dx: decoderx.NewHTTP()} } func (s *Strategy) NodeGroup() node.UiNodeGroup { diff --git a/selfservice/strategy/lookup/strategy.go b/selfservice/strategy/lookup/strategy.go index 170c370509c1..13c233913f18 100644 --- a/selfservice/strategy/lookup/strategy.go +++ b/selfservice/strategy/lookup/strategy.go @@ -27,7 +27,7 @@ import ( var _ settings.Strategy = new(Strategy) var _ identity.ActiveCredentialsCounter = new(Strategy) -type registrationStrategyDependencies interface { +type lookupStrategyDependencies interface { x.LoggingProvider x.WriterProvider x.CSRFTokenGeneratorProvider @@ -65,13 +65,13 @@ type registrationStrategyDependencies interface { } type Strategy struct { - d registrationStrategyDependencies + d lookupStrategyDependencies hd *decoderx.HTTP } -func NewStrategy(d registrationStrategyDependencies) *Strategy { +func NewStrategy(d any) *Strategy { return &Strategy{ - d: d, + d: d.(lookupStrategyDependencies), hd: decoderx.NewHTTP(), } } diff --git a/selfservice/strategy/oidc/provider_apple.go b/selfservice/strategy/oidc/provider_apple.go index 74affe5afb3d..9a83429152d3 100644 --- a/selfservice/strategy/oidc/provider_apple.go +++ b/selfservice/strategy/oidc/provider_apple.go @@ -27,7 +27,7 @@ type ProviderApple struct { func NewProviderApple( config *Configuration, - reg dependencies, + reg Dependencies, ) Provider { config.IssuerURL = "https://appleid.apple.com" return &ProviderApple{ diff --git a/selfservice/strategy/oidc/provider_auth0.go b/selfservice/strategy/oidc/provider_auth0.go index 3b9f7a3dff5f..302c61eaf48e 100644 --- a/selfservice/strategy/oidc/provider_auth0.go +++ b/selfservice/strategy/oidc/provider_auth0.go @@ -32,7 +32,7 @@ type ProviderAuth0 struct { func NewProviderAuth0( config *Configuration, - reg dependencies, + reg Dependencies, ) Provider { return &ProviderAuth0{ ProviderGenericOIDC: &ProviderGenericOIDC{ diff --git a/selfservice/strategy/oidc/provider_config.go b/selfservice/strategy/oidc/provider_config.go index 45fc0734ae91..4c8275c4f709 100644 --- a/selfservice/strategy/oidc/provider_config.go +++ b/selfservice/strategy/oidc/provider_config.go @@ -104,12 +104,21 @@ type Configuration struct { // // More information: https://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter RequestedClaims json.RawMessage `json:"requested_claims"` + + // An optional organization ID that this provider belongs to. + // This parameter is only effective in the Ory Network. + OrganizationID string `json:"organization_id"` } func (p Configuration) Redir(public *url.URL) string { - return urlx.AppendPaths(public, - strings.Replace(RouteCallback, ":provider", p.ID, 1), - ).String() + if p.OrganizationID != "" { + route := RouteOrganizationCallback + route = strings.Replace(route, ":provider", p.ID, 1) + route = strings.Replace(route, ":organization", p.OrganizationID, 1) + return urlx.AppendPaths(public, route).String() + } + + return urlx.AppendPaths(public, strings.Replace(RouteCallback, ":provider", p.ID, 1)).String() } type ConfigurationCollection struct { @@ -121,7 +130,7 @@ type ConfigurationCollection struct { // // If you add a provider here, please also add a test to // provider_private_net_test.go -var supportedProviders = map[string]func(config *Configuration, reg dependencies) Provider{ +var supportedProviders = map[string]func(config *Configuration, reg Dependencies) Provider{ "generic": NewProviderGenericOIDC, "google": NewProviderGoogle, "github": NewProviderGitHub, @@ -143,7 +152,7 @@ var supportedProviders = map[string]func(config *Configuration, reg dependencies "lark": NewProviderLark, } -func (c ConfigurationCollection) Provider(id string, reg dependencies) (Provider, error) { +func (c ConfigurationCollection) Provider(id string, reg Dependencies) (Provider, error) { for k := range c.Providers { p := c.Providers[k] if p.ID == id { diff --git a/selfservice/strategy/oidc/provider_dingtalk.go b/selfservice/strategy/oidc/provider_dingtalk.go index 7b4a835e5734..36469e6e7c23 100644 --- a/selfservice/strategy/oidc/provider_dingtalk.go +++ b/selfservice/strategy/oidc/provider_dingtalk.go @@ -22,12 +22,12 @@ import ( type ProviderDingTalk struct { config *Configuration - reg dependencies + reg Dependencies } func NewProviderDingTalk( config *Configuration, - reg dependencies, + reg Dependencies, ) Provider { return &ProviderDingTalk{ config: config, diff --git a/selfservice/strategy/oidc/provider_discord.go b/selfservice/strategy/oidc/provider_discord.go index e48ce351a6dc..181e7df6d322 100644 --- a/selfservice/strategy/oidc/provider_discord.go +++ b/selfservice/strategy/oidc/provider_discord.go @@ -21,12 +21,12 @@ import ( type ProviderDiscord struct { config *Configuration - reg dependencies + reg Dependencies } func NewProviderDiscord( config *Configuration, - reg dependencies, + reg Dependencies, ) Provider { return &ProviderDiscord{ config: config, diff --git a/selfservice/strategy/oidc/provider_facebook.go b/selfservice/strategy/oidc/provider_facebook.go index 7cf89538f978..32bf1f35c0fa 100644 --- a/selfservice/strategy/oidc/provider_facebook.go +++ b/selfservice/strategy/oidc/provider_facebook.go @@ -30,7 +30,7 @@ type ProviderFacebook struct { func NewProviderFacebook( config *Configuration, - reg dependencies, + reg Dependencies, ) Provider { config.IssuerURL = "https://www.facebook.com" return &ProviderFacebook{ diff --git a/selfservice/strategy/oidc/provider_generic_oidc.go b/selfservice/strategy/oidc/provider_generic_oidc.go index 59d86f985994..a0b551649ae7 100644 --- a/selfservice/strategy/oidc/provider_generic_oidc.go +++ b/selfservice/strategy/oidc/provider_generic_oidc.go @@ -21,12 +21,12 @@ var _ Provider = new(ProviderGenericOIDC) type ProviderGenericOIDC struct { p *gooidc.Provider config *Configuration - reg dependencies + reg Dependencies } func NewProviderGenericOIDC( config *Configuration, - reg dependencies, + reg Dependencies, ) Provider { return &ProviderGenericOIDC{ config: config, diff --git a/selfservice/strategy/oidc/provider_github.go b/selfservice/strategy/oidc/provider_github.go index 8b8b97ee5f83..c805c593b4e0 100644 --- a/selfservice/strategy/oidc/provider_github.go +++ b/selfservice/strategy/oidc/provider_github.go @@ -24,12 +24,12 @@ import ( type ProviderGitHub struct { config *Configuration - reg dependencies + reg Dependencies } func NewProviderGitHub( config *Configuration, - reg dependencies, + reg Dependencies, ) Provider { return &ProviderGitHub{ config: config, diff --git a/selfservice/strategy/oidc/provider_github_app.go b/selfservice/strategy/oidc/provider_github_app.go index f48de9664547..703ba494df2c 100644 --- a/selfservice/strategy/oidc/provider_github_app.go +++ b/selfservice/strategy/oidc/provider_github_app.go @@ -21,12 +21,12 @@ import ( type ProviderGitHubApp struct { config *Configuration - reg dependencies + reg Dependencies } func NewProviderGitHubApp( config *Configuration, - reg dependencies, + reg Dependencies, ) Provider { return &ProviderGitHubApp{ config: config, diff --git a/selfservice/strategy/oidc/provider_gitlab.go b/selfservice/strategy/oidc/provider_gitlab.go index fde2506e0a63..f7493367345f 100644 --- a/selfservice/strategy/oidc/provider_gitlab.go +++ b/selfservice/strategy/oidc/provider_gitlab.go @@ -31,7 +31,7 @@ type ProviderGitLab struct { func NewProviderGitLab( config *Configuration, - reg dependencies, + reg Dependencies, ) Provider { return &ProviderGitLab{ ProviderGenericOIDC: &ProviderGenericOIDC{ diff --git a/selfservice/strategy/oidc/provider_google.go b/selfservice/strategy/oidc/provider_google.go index 54adda2b96c3..c1ccdf505383 100644 --- a/selfservice/strategy/oidc/provider_google.go +++ b/selfservice/strategy/oidc/provider_google.go @@ -20,7 +20,7 @@ type ProviderGoogle struct { func NewProviderGoogle( config *Configuration, - reg dependencies, + reg Dependencies, ) Provider { config.IssuerURL = "https://accounts.google.com" return &ProviderGoogle{ diff --git a/selfservice/strategy/oidc/provider_lark.go b/selfservice/strategy/oidc/provider_lark.go index b239a207c095..52902dc20e8c 100644 --- a/selfservice/strategy/oidc/provider_lark.go +++ b/selfservice/strategy/oidc/provider_lark.go @@ -31,7 +31,7 @@ var ( func NewProviderLark( config *Configuration, - reg dependencies, + reg Dependencies, ) Provider { return &ProviderLark{ &ProviderGenericOIDC{ diff --git a/selfservice/strategy/oidc/provider_linkedin.go b/selfservice/strategy/oidc/provider_linkedin.go index a9dde8ce37e3..052542d2b00a 100644 --- a/selfservice/strategy/oidc/provider_linkedin.go +++ b/selfservice/strategy/oidc/provider_linkedin.go @@ -65,12 +65,12 @@ const ( type ProviderLinkedIn struct { config *Configuration - reg dependencies + reg Dependencies } func NewProviderLinkedIn( config *Configuration, - reg dependencies, + reg Dependencies, ) Provider { return &ProviderLinkedIn{ config: config, diff --git a/selfservice/strategy/oidc/provider_microsoft.go b/selfservice/strategy/oidc/provider_microsoft.go index af664f7f8aca..3e31e505b358 100644 --- a/selfservice/strategy/oidc/provider_microsoft.go +++ b/selfservice/strategy/oidc/provider_microsoft.go @@ -29,7 +29,7 @@ type ProviderMicrosoft struct { func NewProviderMicrosoft( config *Configuration, - reg dependencies, + reg Dependencies, ) Provider { return &ProviderMicrosoft{ ProviderGenericOIDC: &ProviderGenericOIDC{ diff --git a/selfservice/strategy/oidc/provider_netid.go b/selfservice/strategy/oidc/provider_netid.go index a919c177728f..f8f0023878ef 100644 --- a/selfservice/strategy/oidc/provider_netid.go +++ b/selfservice/strategy/oidc/provider_netid.go @@ -34,7 +34,7 @@ type ProviderNetID struct { func NewProviderNetID( config *Configuration, - reg dependencies, + reg Dependencies, ) Provider { config.IssuerURL = fmt.Sprintf("%s://%s/", defaultBrokerScheme, defaultBrokerHost) if !stringslice.Has(config.Scope, gooidc.ScopeOpenID) { diff --git a/selfservice/strategy/oidc/provider_patreon.go b/selfservice/strategy/oidc/provider_patreon.go index dbd740ff88bf..abe1eeffd805 100644 --- a/selfservice/strategy/oidc/provider_patreon.go +++ b/selfservice/strategy/oidc/provider_patreon.go @@ -20,7 +20,7 @@ import ( type ProviderPatreon struct { config *Configuration - reg dependencies + reg Dependencies } type PatreonIdentityResponse struct { @@ -39,7 +39,7 @@ type PatreonIdentityResponse struct { func NewProviderPatreon( config *Configuration, - reg dependencies, + reg Dependencies, ) Provider { return &ProviderPatreon{ config: config, diff --git a/selfservice/strategy/oidc/provider_slack.go b/selfservice/strategy/oidc/provider_slack.go index 951b7fab1874..7c7e26c99da4 100644 --- a/selfservice/strategy/oidc/provider_slack.go +++ b/selfservice/strategy/oidc/provider_slack.go @@ -21,12 +21,12 @@ import ( type ProviderSlack struct { config *Configuration - reg dependencies + reg Dependencies } func NewProviderSlack( config *Configuration, - reg dependencies, + reg Dependencies, ) Provider { return &ProviderSlack{ config: config, diff --git a/selfservice/strategy/oidc/provider_spotify.go b/selfservice/strategy/oidc/provider_spotify.go index 3c0d95ea043d..d68671f9974e 100644 --- a/selfservice/strategy/oidc/provider_spotify.go +++ b/selfservice/strategy/oidc/provider_spotify.go @@ -24,12 +24,12 @@ import ( type ProviderSpotify struct { config *Configuration - reg dependencies + reg Dependencies } func NewProviderSpotify( config *Configuration, - reg dependencies, + reg Dependencies, ) Provider { return &ProviderSpotify{ config: config, diff --git a/selfservice/strategy/oidc/provider_test.go b/selfservice/strategy/oidc/provider_test.go index 74fdb05031fc..7c0de7c55138 100644 --- a/selfservice/strategy/oidc/provider_test.go +++ b/selfservice/strategy/oidc/provider_test.go @@ -25,14 +25,14 @@ type TestProvider struct { *ProviderGenericOIDC } -func NewTestProvider(c *Configuration, reg dependencies) Provider { +func NewTestProvider(c *Configuration, reg Dependencies) Provider { return &TestProvider{ ProviderGenericOIDC: NewProviderGenericOIDC(c, reg).(*ProviderGenericOIDC), } } func RegisterTestProvider(id string) func() { - supportedProviders[id] = func(c *Configuration, reg dependencies) Provider { + supportedProviders[id] = func(c *Configuration, reg Dependencies) Provider { return NewTestProvider(c, reg) } return func() { diff --git a/selfservice/strategy/oidc/provider_vk.go b/selfservice/strategy/oidc/provider_vk.go index 6d89170d77a1..995eed6fbe07 100644 --- a/selfservice/strategy/oidc/provider_vk.go +++ b/selfservice/strategy/oidc/provider_vk.go @@ -21,12 +21,12 @@ import ( type ProviderVK struct { config *Configuration - reg dependencies + reg Dependencies } func NewProviderVK( config *Configuration, - reg dependencies, + reg Dependencies, ) Provider { return &ProviderVK{ config: config, diff --git a/selfservice/strategy/oidc/provider_yandex.go b/selfservice/strategy/oidc/provider_yandex.go index 4c93a13a196e..dfb9267f8793 100644 --- a/selfservice/strategy/oidc/provider_yandex.go +++ b/selfservice/strategy/oidc/provider_yandex.go @@ -19,12 +19,12 @@ import ( type ProviderYandex struct { config *Configuration - reg dependencies + reg Dependencies } func NewProviderYandex( config *Configuration, - reg dependencies, + reg Dependencies, ) Provider { return &ProviderYandex{ config: config, diff --git a/selfservice/strategy/oidc/strategy.go b/selfservice/strategy/oidc/strategy.go index d772bfd0f198..70fa10585d18 100644 --- a/selfservice/strategy/oidc/strategy.go +++ b/selfservice/strategy/oidc/strategy.go @@ -56,13 +56,14 @@ import ( const ( RouteBase = "/self-service/methods/oidc" - RouteAuth = RouteBase + "/auth/:flow" - RouteCallback = RouteBase + "/callback/:provider" + RouteAuth = RouteBase + "/auth/:flow" + RouteCallback = RouteBase + "/callback/:provider" + RouteOrganizationCallback = RouteBase + "/organization/:organization/callback/:provider" ) var _ identity.ActiveCredentialsCounter = new(Strategy) -type dependencies interface { +type Dependencies interface { errorx.ManagementProvider config.Provider @@ -119,12 +120,12 @@ func isForced(req interface{}) bool { // Strategy implements selfservice.LoginStrategy, selfservice.RegistrationStrategy and selfservice.SettingsStrategy. // It supports login, registration and settings via OpenID Providers. type Strategy struct { - d dependencies + d Dependencies validator *schema.Validator dec *decoderx.HTTP } -type authCodeContainer struct { +type AuthCodeContainer struct { FlowID string `json:"flow_id"` State string `json:"state"` Traits json.RawMessage `json:"traits"` @@ -197,7 +198,7 @@ func (s *Strategy) CountActiveMultiFactorCredentials(cc map[identity.Credentials } func (s *Strategy) setRoutes(r *x.RouterPublic) { - wrappedHandleCallback := strategy.IsDisabled(s.d, s.ID().String(), s.handleCallback) + wrappedHandleCallback := strategy.IsDisabled(s.d, s.ID().String(), s.HandleCallback) if handle, _, _ := r.Lookup("GET", RouteCallback); handle == nil { r.GET(RouteCallback, wrappedHandleCallback) } @@ -236,9 +237,9 @@ func (s *Strategy) redirectToGET(w http.ResponseWriter, r *http.Request, _ httpr http.Redirect(w, r, dest.String(), http.StatusFound) } -func NewStrategy(d dependencies) *Strategy { +func NewStrategy(d any) *Strategy { return &Strategy{ - d: d, + d: d.(Dependencies), validator: schema.NewValidator(), } } @@ -282,7 +283,7 @@ func (s *Strategy) validateFlow(ctx context.Context, r *http.Request, rid uuid.U return ar, err // this must return the error } -func (s *Strategy) validateCallback(w http.ResponseWriter, r *http.Request) (flow.Flow, *authCodeContainer, error) { +func (s *Strategy) ValidateCallback(w http.ResponseWriter, r *http.Request) (flow.Flow, *AuthCodeContainer, error) { var ( codeParam = stringsx.Coalesce(r.URL.Query().Get("code"), r.URL.Query().Get("authCode")) stateParam = r.URL.Query().Get("state") @@ -307,7 +308,7 @@ func (s *Strategy) validateCallback(w http.ResponseWriter, r *http.Request) (flo return nil, nil, err } - cntnr := authCodeContainer{} + cntnr := AuthCodeContainer{} if f.GetType() == flow.TypeBrowser || !hasSessionTokenCode { if _, err := s.d.ContinuityManager().Continue(r.Context(), w, r, sessionName, continuity.WithPayload(&cntnr)); err != nil { return nil, nil, err @@ -375,13 +376,17 @@ func (s *Strategy) alreadyAuthenticated(w http.ResponseWriter, r *http.Request, return false, nil } -func (s *Strategy) handleCallback(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { +func (s *Strategy) HandleCallback(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { var ( code = stringsx.Coalesce(r.URL.Query().Get("code"), r.URL.Query().Get("authCode")) pid = ps.ByName("provider") ) - req, cntnr, err := s.validateCallback(w, r) + ctx := r.Context() + ctx = context.WithValue(ctx, httprouter.ParamsKey, ps) + r = r.WithContext(ctx) + + req, cntnr, err := s.ValidateCallback(w, r) if err != nil { if req != nil { s.forwardError(w, r, req, s.handleError(w, r, req, pid, nil, err)) diff --git a/selfservice/strategy/oidc/strategy_login.go b/selfservice/strategy/oidc/strategy_login.go index 14d44702bb75..5150eabcda52 100644 --- a/selfservice/strategy/oidc/strategy_login.go +++ b/selfservice/strategy/oidc/strategy_login.go @@ -9,6 +9,7 @@ import ( "net/http" "time" + "github.com/julienschmidt/httprouter" "golang.org/x/oauth2" "github.com/gofrs/uuid" @@ -101,7 +102,7 @@ type UpdateLoginFlowWithOidcMethod struct { IDTokenNonce string `json:"id_token_nonce,omitempty"` } -func (s *Strategy) processLogin(w http.ResponseWriter, r *http.Request, loginFlow *login.Flow, token *oauth2.Token, claims *Claims, provider Provider, container *authCodeContainer) (*registration.Flow, error) { +func (s *Strategy) processLogin(w http.ResponseWriter, r *http.Request, loginFlow *login.Flow, token *oauth2.Token, claims *Claims, provider Provider, container *AuthCodeContainer) (*registration.Flow, error) { i, c, err := s.d.PrivilegedIdentityPool().FindByCredentialsIdentifier(r.Context(), identity.CredentialsTypeOIDC, identity.OIDCUniqueID(provider.Config().ID, claims.Subject)) if err != nil { if errors.Is(err, sqlcon.ErrNoRows) { @@ -141,6 +142,7 @@ func (s *Strategy) processLogin(w http.ResponseWriter, r *http.Request, loginFlo return nil, s.handleError(w, r, loginFlow, provider.Config().ID, nil, err) } + registrationFlow.OrganizationID = loginFlow.OrganizationID registrationFlow.IDToken = loginFlow.IDToken registrationFlow.RawIDTokenNonce = loginFlow.RawIDTokenNonce registrationFlow.RequestURL, err = x.TakeOverReturnToParameter(loginFlow.RequestURL, registrationFlow.RequestURL) @@ -164,7 +166,8 @@ func (s *Strategy) processLogin(w http.ResponseWriter, r *http.Request, loginFlo } sess := session.NewInactiveSession() - sess.CompletedLoginForWithProvider(s.ID(), identity.AuthenticatorAssuranceLevel1, provider.Config().ID) + sess.CompletedLoginForWithProvider(s.ID(), identity.AuthenticatorAssuranceLevel1, provider.Config().ID, + httprouter.ParamsFromContext(r.Context()).ByName("organization")) for _, c := range oidcCredentials.Providers { if c.Subject == claims.Subject && c.Provider == provider.Config().ID { if err = s.d.LoginHookExecutor().PostLoginHook(w, r, node.OpenIDConnectGroup, loginFlow, i, sess, provider.Config().ID); err != nil { @@ -225,7 +228,7 @@ func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, if err != nil { return nil, s.handleError(w, r, f, pid, nil, err) } - _, err = s.processLogin(w, r, f, nil, claims, provider, &authCodeContainer{ + _, err = s.processLogin(w, r, f, nil, claims, provider, &AuthCodeContainer{ FlowID: f.ID.String(), Traits: p.Traits, }) @@ -240,7 +243,7 @@ func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, state.setCode(code.InitCode) } if err := s.d.ContinuityManager().Pause(r.Context(), w, r, sessionName, - continuity.WithPayload(&authCodeContainer{ + continuity.WithPayload(&AuthCodeContainer{ State: state.String(), FlowID: f.ID.String(), Traits: p.Traits, diff --git a/selfservice/strategy/oidc/strategy_registration.go b/selfservice/strategy/oidc/strategy_registration.go index 15b42ac56c6f..13c6a448c047 100644 --- a/selfservice/strategy/oidc/strategy_registration.go +++ b/selfservice/strategy/oidc/strategy_registration.go @@ -10,6 +10,9 @@ import ( "strings" "time" + "github.com/gofrs/uuid" + "github.com/julienschmidt/httprouter" + "github.com/ory/x/sqlxx" "github.com/ory/herodot" @@ -192,7 +195,7 @@ func (s *Strategy) Register(w http.ResponseWriter, r *http.Request, f *registrat if err != nil { return s.handleError(w, r, f, pid, nil, err) } - _, err = s.processRegistration(w, r, f, nil, claims, provider, &authCodeContainer{ + _, err = s.processRegistration(w, r, f, nil, claims, provider, &AuthCodeContainer{ FlowID: f.ID.String(), Traits: p.Traits, TransientPayload: f.TransientPayload, @@ -208,7 +211,7 @@ func (s *Strategy) Register(w http.ResponseWriter, r *http.Request, f *registrat state.setCode(code.InitCode) } if err := s.d.ContinuityManager().Pause(r.Context(), w, r, sessionName, - continuity.WithPayload(&authCodeContainer{ + continuity.WithPayload(&AuthCodeContainer{ State: state.String(), FlowID: f.ID.String(), Traits: p.Traits, @@ -262,7 +265,7 @@ func (s *Strategy) registrationToLogin(w http.ResponseWriter, r *http.Request, r return lf, nil } -func (s *Strategy) processRegistration(w http.ResponseWriter, r *http.Request, rf *registration.Flow, token *oauth2.Token, claims *Claims, provider Provider, container *authCodeContainer, idToken string) (*login.Flow, error) { +func (s *Strategy) processRegistration(w http.ResponseWriter, r *http.Request, rf *registration.Flow, token *oauth2.Token, claims *Claims, provider Provider, container *AuthCodeContainer, idToken string) (*login.Flow, error) { if _, _, err := s.d.PrivilegedIdentityPool().FindByCredentialsIdentifier(r.Context(), identity.CredentialsTypeOIDC, identity.OIDCUniqueID(provider.Config().ID, claims.Subject)); err == nil { // If the identity already exists, we should perform the login flow instead. @@ -339,7 +342,7 @@ func (s *Strategy) processRegistration(w http.ResponseWriter, r *http.Request, r } } - creds, err := identity.NewCredentialsOIDC(it, cat, crt, provider.Config().ID, claims.Subject) + creds, err := identity.NewCredentialsOIDC(it, cat, crt, provider.Config().ID, claims.Subject, provider.Config().OrganizationID) if err != nil { return nil, s.handleError(w, r, rf, provider.Config().ID, i.Traits, err) } @@ -352,7 +355,7 @@ func (s *Strategy) processRegistration(w http.ResponseWriter, r *http.Request, r return nil, nil } -func (s *Strategy) createIdentity(w http.ResponseWriter, r *http.Request, a *registration.Flow, claims *Claims, provider Provider, container *authCodeContainer, jn *bytes.Buffer) (*identity.Identity, []VerifiedAddress, error) { +func (s *Strategy) createIdentity(w http.ResponseWriter, r *http.Request, a *registration.Flow, claims *Claims, provider Provider, container *AuthCodeContainer, jn *bytes.Buffer) (*identity.Identity, []VerifiedAddress, error) { var jsonClaims bytes.Buffer if err := json.NewEncoder(&jsonClaims).Encode(claims); err != nil { return nil, nil, s.handleError(w, r, a, provider.Config().ID, nil, err) @@ -387,6 +390,10 @@ func (s *Strategy) createIdentity(w http.ResponseWriter, r *http.Request, a *reg return nil, nil, s.handleError(w, r, a, provider.Config().ID, i.Traits, err) } + if orgID := httprouter.ParamsFromContext(r.Context()).ByName("organization"); orgID != "" { + i.OrganizationID = uuid.NullUUID{UUID: x.ParseUUID(orgID), Valid: true} + } + s.d.Logger(). WithRequest(r). WithField("oidc_provider", provider.Config().ID). @@ -397,7 +404,7 @@ func (s *Strategy) createIdentity(w http.ResponseWriter, r *http.Request, a *reg return i, va, nil } -func (s *Strategy) setTraits(w http.ResponseWriter, r *http.Request, a *registration.Flow, claims *Claims, provider Provider, container *authCodeContainer, evaluated string, i *identity.Identity) error { +func (s *Strategy) setTraits(w http.ResponseWriter, r *http.Request, a *registration.Flow, claims *Claims, provider Provider, container *AuthCodeContainer, evaluated string, i *identity.Identity) error { jsonTraits := gjson.Get(evaluated, "identity.traits") if !jsonTraits.IsObject() { return errors.WithStack(herodot.ErrInternalServerError.WithReasonf("OpenID Connect Jsonnet mapper did not return an object for key identity.traits. Please check your Jsonnet code!")) diff --git a/selfservice/strategy/oidc/strategy_settings.go b/selfservice/strategy/oidc/strategy_settings.go index 1866cd82aaab..513f5cccdabe 100644 --- a/selfservice/strategy/oidc/strategy_settings.go +++ b/selfservice/strategy/oidc/strategy_settings.go @@ -359,7 +359,7 @@ func (s *Strategy) initLinkProvider(w http.ResponseWriter, r *http.Request, ctxU state := generateState(ctxUpdate.Flow.ID.String()).String() if err := s.d.ContinuityManager().Pause(r.Context(), w, r, sessionName, - continuity.WithPayload(&authCodeContainer{ + continuity.WithPayload(&AuthCodeContainer{ State: state, FlowID: ctxUpdate.Flow.ID.String(), Traits: p.Traits, @@ -416,7 +416,7 @@ func (s *Strategy) linkProvider(w http.ResponseWriter, r *http.Request, ctxUpdat creds, err := i.ParseCredentials(s.ID(), &conf) if errors.Is(err, herodot.ErrNotFound) { var err error - if creds, err = identity.NewCredentialsOIDC(it, cat, crt, provider.Config().ID, claims.Subject); err != nil { + if creds, err = identity.NewCredentialsOIDC(it, cat, crt, provider.Config().ID, claims.Subject, ""); err != nil { return s.handleSettingsError(w, r, ctxUpdate, p, err) } } else if err != nil { diff --git a/selfservice/strategy/password/strategy.go b/selfservice/strategy/password/strategy.go index 2993c428b701..bb750bc9ef80 100644 --- a/selfservice/strategy/password/strategy.go +++ b/selfservice/strategy/password/strategy.go @@ -76,9 +76,9 @@ type Strategy struct { hd *decoderx.HTTP } -func NewStrategy(d registrationStrategyDependencies) *Strategy { +func NewStrategy(d any) *Strategy { return &Strategy{ - d: d, + d: d.(registrationStrategyDependencies), v: validator.New(), hd: decoderx.NewHTTP(), } diff --git a/selfservice/strategy/profile/strategy.go b/selfservice/strategy/profile/strategy.go index e94d779aef61..5b8d7f368306 100644 --- a/selfservice/strategy/profile/strategy.go +++ b/selfservice/strategy/profile/strategy.go @@ -68,8 +68,8 @@ type ( } ) -func NewStrategy(d strategyDependencies) *Strategy { - return &Strategy{d: d, dc: decoderx.NewHTTP()} +func NewStrategy(d any) *Strategy { + return &Strategy{d: d.(strategyDependencies), dc: decoderx.NewHTTP()} } func (s *Strategy) SettingsStrategyID() string { diff --git a/selfservice/strategy/totp/strategy.go b/selfservice/strategy/totp/strategy.go index bb4da1d3ec2d..bcaf09069053 100644 --- a/selfservice/strategy/totp/strategy.go +++ b/selfservice/strategy/totp/strategy.go @@ -28,7 +28,7 @@ var _ login.Strategy = new(Strategy) var _ settings.Strategy = new(Strategy) var _ identity.ActiveCredentialsCounter = new(Strategy) -type registrationStrategyDependencies interface { +type totpStrategyDependencies interface { x.LoggingProvider x.WriterProvider x.CSRFTokenGeneratorProvider @@ -67,13 +67,13 @@ type registrationStrategyDependencies interface { } type Strategy struct { - d registrationStrategyDependencies + d totpStrategyDependencies hd *decoderx.HTTP } -func NewStrategy(d registrationStrategyDependencies) *Strategy { +func NewStrategy(d any) *Strategy { return &Strategy{ - d: d, + d: d.(totpStrategyDependencies), hd: decoderx.NewHTTP(), } } 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 49c3fede7254..e6376bbf7d9e 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 @@ { + "organization_id": 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 49c3fede7254..e6376bbf7d9e 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 @@ { + "organization_id": null, "type": "browser", "ui": { "method": "POST", diff --git a/selfservice/strategy/webauthn/strategy.go b/selfservice/strategy/webauthn/strategy.go index 051267efc9ba..aa4529cda620 100644 --- a/selfservice/strategy/webauthn/strategy.go +++ b/selfservice/strategy/webauthn/strategy.go @@ -27,7 +27,7 @@ var _ login.Strategy = new(Strategy) var _ settings.Strategy = new(Strategy) var _ identity.ActiveCredentialsCounter = new(Strategy) -type registrationStrategyDependencies interface { +type webauthnStrategyDependencies interface { x.LoggingProvider x.WriterProvider x.CSRFTokenGeneratorProvider @@ -67,13 +67,13 @@ type registrationStrategyDependencies interface { } type Strategy struct { - d registrationStrategyDependencies + d webauthnStrategyDependencies hd *decoderx.HTTP } -func NewStrategy(d registrationStrategyDependencies) *Strategy { +func NewStrategy(d any) *Strategy { return &Strategy{ - d: d, + d: d.(webauthnStrategyDependencies), hd: decoderx.NewHTTP(), } } diff --git a/session/session.go b/session/session.go index ceb792f66b2e..74204be4215c 100644 --- a/session/session.go +++ b/session/session.go @@ -168,8 +168,14 @@ func (s *Session) CompletedLoginFor(method identity.CredentialsType, aal identit s.AMR = append(s.AMR, AuthenticationMethod{Method: method, AAL: aal, CompletedAt: time.Now().UTC()}) } -func (s *Session) CompletedLoginForWithProvider(method identity.CredentialsType, aal identity.AuthenticatorAssuranceLevel, providerID string) { - s.AMR = append(s.AMR, AuthenticationMethod{Method: method, AAL: aal, Provider: providerID, CompletedAt: time.Now().UTC()}) +func (s *Session) CompletedLoginForWithProvider(method identity.CredentialsType, aal identity.AuthenticatorAssuranceLevel, providerID string, organizationID string) { + s.AMR = append(s.AMR, AuthenticationMethod{ + Method: method, + AAL: aal, + CompletedAt: time.Now().UTC(), + Provider: providerID, + Organization: organizationID, + }) } func (s *Session) AuthenticatedVia(method identity.CredentialsType) bool { @@ -335,6 +341,9 @@ type AuthenticationMethod struct { // OIDC or SAML provider id used for authentication Provider string `json:"provider,omitempty"` + + // The Organization id used for authentication + Organization string `json:"organization,omitempty"` } // Scan implements the Scanner interface. diff --git a/spec/api.json b/spec/api.json index d163cd2d65f6..fbc0fe874e56 100644 --- a/spec/api.json +++ b/spec/api.json @@ -825,6 +825,9 @@ "metadata_public": { "$ref": "#/components/schemas/nullJsonRawMessage" }, + "organization_id": { + "$ref": "#/components/schemas/NullUUID" + }, "recovery_addresses": { "description": "RecoveryAddresses contains all the addresses that can be used to recover an identity.", "items": { @@ -942,6 +945,9 @@ "initial_refresh_token": { "type": "string" }, + "organization": { + "type": "string" + }, "provider": { "type": "string" }, @@ -1204,6 +1210,9 @@ "oauth2_login_request": { "$ref": "#/components/schemas/OAuth2LoginRequest" }, + "organization_id": { + "$ref": "#/components/schemas/NullUUID" + }, "refresh": { "description": "Refresh stores whether this login flow should enforce re-authentication.", "type": "boolean" @@ -1619,6 +1628,9 @@ "oauth2_login_request": { "$ref": "#/components/schemas/OAuth2LoginRequest" }, + "organization_id": { + "$ref": "#/components/schemas/NullUUID" + }, "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" @@ -1770,6 +1782,9 @@ "title": "The method used", "type": "string" }, + "organization": { + "type": "string" + }, "provider": { "description": "OIDC or SAML provider id used for authentication", "type": "string" @@ -5096,6 +5111,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "organization", + "schema": { + "type": "string" + } } ], "responses": { @@ -5854,6 +5876,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "organization", + "schema": { + "type": "string" + } } ], "responses": { diff --git a/spec/swagger.json b/spec/swagger.json index df1b67be4013..176dfb093be2 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -1600,6 +1600,11 @@ "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": "string", + "name": "organization", + "in": "query" } ], "responses": { @@ -2228,6 +2233,11 @@ "description": "The URL to return the browser to after the verification flow was completed.\n\nAfter the registration flow is completed, the user will be sent a verification email.\nUpon completing the verification flow, this URL will be used to override the default\n`selfservice.flows.verification.after.default_redirect_to` value.", "name": "after_verification_return_to", "in": "query" + }, + { + "type": "string", + "name": "organization", + "in": "query" } ], "responses": { @@ -3183,6 +3193,19 @@ } } }, + "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": { "type": "object", "title": "OAuth2Client OAuth 2.0 Clients are used to perform OAuth 2.0 and OpenID Connect flows. Usually, OAuth 2.0 clients are generated for applications which want to consume your OAuth 2.0 or OpenID Connect capabilities.", @@ -3864,6 +3887,9 @@ "metadata_public": { "$ref": "#/definitions/nullJsonRawMessage" }, + "organization_id": { + "$ref": "#/definitions/NullUUID" + }, "recovery_addresses": { "description": "RecoveryAddresses contains all the addresses that can be used to recover an identity.", "type": "array", @@ -3975,6 +4001,9 @@ "initial_refresh_token": { "type": "string" }, + "organization": { + "type": "string" + }, "provider": { "type": "string" }, @@ -4235,6 +4264,9 @@ "oauth2_login_request": { "$ref": "#/definitions/OAuth2LoginRequest" }, + "organization_id": { + "$ref": "#/definitions/NullUUID" + }, "refresh": { "description": "Refresh stores whether this login flow should enforce re-authentication.", "type": "boolean" @@ -4630,6 +4662,9 @@ "oauth2_login_request": { "$ref": "#/definitions/OAuth2LoginRequest" }, + "organization_id": { + "$ref": "#/definitions/NullUUID" + }, "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" @@ -4757,6 +4792,9 @@ "method": { "$ref": "#/definitions/identityCredentialsType" }, + "organization": { + "type": "string" + }, "provider": { "description": "OIDC or SAML provider id used for authentication", "type": "string" From efea4a4a1263f18c6f978955a4741355c32ee6ff Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Thu, 21 Sep 2023 08:17:51 +0000 Subject: [PATCH 105/282] autogen(openapi): regenerate swagger spec and internal client [skip ci] --- internal/client-go/model_session_authentication_method.go | 7 ++++--- internal/httpclient/model_session_authentication_method.go | 7 ++++--- spec/api.json | 2 ++ spec/swagger.json | 2 ++ 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/internal/client-go/model_session_authentication_method.go b/internal/client-go/model_session_authentication_method.go index c887f7df61c6..17228de93141 100644 --- a/internal/client-go/model_session_authentication_method.go +++ b/internal/client-go/model_session_authentication_method.go @@ -20,9 +20,10 @@ import ( type SessionAuthenticationMethod struct { Aal *AuthenticatorAssuranceLevel `json:"aal,omitempty"` // When the authentication challenge was completed. - CompletedAt *time.Time `json:"completed_at,omitempty"` - Method *string `json:"method,omitempty"` - Organization *string `json:"organization,omitempty"` + CompletedAt *time.Time `json:"completed_at,omitempty"` + Method *string `json:"method,omitempty"` + // The Organization id used for authentication + Organization *string `json:"organization,omitempty"` // OIDC or SAML provider id used for authentication Provider *string `json:"provider,omitempty"` } diff --git a/internal/httpclient/model_session_authentication_method.go b/internal/httpclient/model_session_authentication_method.go index c887f7df61c6..17228de93141 100644 --- a/internal/httpclient/model_session_authentication_method.go +++ b/internal/httpclient/model_session_authentication_method.go @@ -20,9 +20,10 @@ import ( type SessionAuthenticationMethod struct { Aal *AuthenticatorAssuranceLevel `json:"aal,omitempty"` // When the authentication challenge was completed. - CompletedAt *time.Time `json:"completed_at,omitempty"` - Method *string `json:"method,omitempty"` - Organization *string `json:"organization,omitempty"` + CompletedAt *time.Time `json:"completed_at,omitempty"` + Method *string `json:"method,omitempty"` + // The Organization id used for authentication + Organization *string `json:"organization,omitempty"` // OIDC or SAML provider id used for authentication Provider *string `json:"provider,omitempty"` } diff --git a/spec/api.json b/spec/api.json index fbc0fe874e56..c0629d544021 100644 --- a/spec/api.json +++ b/spec/api.json @@ -1783,6 +1783,7 @@ "type": "string" }, "organization": { + "description": "The Organization id used for authentication", "type": "string" }, "provider": { @@ -5113,6 +5114,7 @@ } }, { + "description": "An optional organization ID that should be used for logging this user in.\nThis parameter is only effective in the Ory Network.", "in": "query", "name": "organization", "schema": { diff --git a/spec/swagger.json b/spec/swagger.json index 176dfb093be2..78549f804e7d 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -1603,6 +1603,7 @@ }, { "type": "string", + "description": "An optional organization ID that should be used for logging this user in.\nThis parameter is only effective in the Ory Network.", "name": "organization", "in": "query" } @@ -4793,6 +4794,7 @@ "$ref": "#/definitions/identityCredentialsType" }, "organization": { + "description": "The Organization id used for authentication", "type": "string" }, "provider": { From 70c8ddd49c8abb9c10f2ca349e01061b791c5e7b Mon Sep 17 00:00:00 2001 From: Patrik Date: Fri, 22 Sep 2023 10:45:09 +0200 Subject: [PATCH 106/282] test: fix cypress setup (#3527) --- test/e2e/cypress.config.ts | 7 +++++++ test/e2e/run.sh | 3 +++ 2 files changed, 10 insertions(+) diff --git a/test/e2e/cypress.config.ts b/test/e2e/cypress.config.ts index b2ff781b71bf..3ddc91b91270 100644 --- a/test/e2e/cypress.config.ts +++ b/test/e2e/cypress.config.ts @@ -32,6 +32,13 @@ export default defineConfig({ console.log("criPort is", criPort) }) + on("before:browser:launch", (browser, launchOptions) => { + if (browser.name.includes("chrom") && browser.isHeadless) { + launchOptions.args.push("--headless=new") + } + return launchOptions + }) + on("task", { httpRequest(params) { return got(params).then(({ body }) => body) diff --git a/test/e2e/run.sh b/test/e2e/run.sh index 6dba7949c779..cb2d813ddad0 100755 --- a/test/e2e/run.sh +++ b/test/e2e/run.sh @@ -19,6 +19,9 @@ export KRATOS_UI_REACT_URL=http://localhost:4458/ export KRATOS_UI_REACT_NATIVE_URL=http://localhost:19006/ export LOG_LEAK_SENSITIVE_VALUES=true export DEV_DISABLE_API_FLOW_ENFORCEMENT=true +export COOKIE_SECRET=kweifawskf23weas +export CSRF_COOKIE_NAME=node_csrf_token +export CSRF_COOKIE_SECRET=lkaw9oe8isedrhq2 base=$(pwd) From bee0341c5bf5708a2210146fc59f050a1b9df663 Mon Sep 17 00:00:00 2001 From: Patrik Date: Fri, 22 Sep 2023 14:21:37 +0200 Subject: [PATCH 107/282] fix: schema test errors (#3528) --- ...er-case=should_be_able_to_import_users-without_traits.json | 3 ++- .../selfServiceAfterSettings.full.yaml | 2 +- .../selfServiceAfterSettingsAuthMethod.full.yaml | 4 ++++ .../selfServiceAfterSettingsMethod.full.yaml | 1 - 4 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 test/schema/fixtures/config.schema.test.success/selfServiceAfterSettingsAuthMethod.full.yaml diff --git a/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-without_traits.json b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-without_traits.json index 32e6b205f4a3..fabb2d6ea0c6 100644 --- a/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-without_traits.json +++ b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-without_traits.json @@ -3,5 +3,6 @@ "state": "active", "traits": {}, "metadata_public": null, - "metadata_admin": null + "metadata_admin": null, + "organization_id": null } diff --git a/test/schema/fixtures/config.schema.test.success/selfServiceAfterSettings.full.yaml b/test/schema/fixtures/config.schema.test.success/selfServiceAfterSettings.full.yaml index b991589d8356..272163f88f53 100644 --- a/test/schema/fixtures/config.schema.test.success/selfServiceAfterSettings.full.yaml +++ b/test/schema/fixtures/config.schema.test.success/selfServiceAfterSettings.full.yaml @@ -1,3 +1,3 @@ default_browser_return_url: "#/definitions/defaultReturnTo" -password: "#/definitions/selfServiceAfterSettingsMethod" +password: "#/definitions/selfServiceAfterSettingsAuthMethod" profile: "#/definitions/selfServiceAfterSettingsMethod" diff --git a/test/schema/fixtures/config.schema.test.success/selfServiceAfterSettingsAuthMethod.full.yaml b/test/schema/fixtures/config.schema.test.success/selfServiceAfterSettingsAuthMethod.full.yaml new file mode 100644 index 000000000000..5e3a24ea95ed --- /dev/null +++ b/test/schema/fixtures/config.schema.test.success/selfServiceAfterSettingsAuthMethod.full.yaml @@ -0,0 +1,4 @@ +default_browser_return_url: "#/definitions/defaultReturnTo" +hooks: + - "#/definitions/selfServiceWebHook" + - "#/definitions/selfServiceSessionRevokerHook" diff --git a/test/schema/fixtures/config.schema.test.success/selfServiceAfterSettingsMethod.full.yaml b/test/schema/fixtures/config.schema.test.success/selfServiceAfterSettingsMethod.full.yaml index 5e3a24ea95ed..9938abcf7de6 100644 --- a/test/schema/fixtures/config.schema.test.success/selfServiceAfterSettingsMethod.full.yaml +++ b/test/schema/fixtures/config.schema.test.success/selfServiceAfterSettingsMethod.full.yaml @@ -1,4 +1,3 @@ default_browser_return_url: "#/definitions/defaultReturnTo" hooks: - "#/definitions/selfServiceWebHook" - - "#/definitions/selfServiceSessionRevokerHook" From 4206d2605dfa30b19e132be31b85b1a35f8dca78 Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Mon, 25 Sep 2023 15:14:15 +0200 Subject: [PATCH 108/282] test: resolve cypress issues (#3531) --- .github/workflows/ci.yaml | 2 - Makefile | 5 - README.md | 18 +- package-lock.json | 2989 +------------------------- package.json | 22 +- test/e2e/cypress.config.ts | 8 +- test/e2e/cypress/support/commands.ts | 2 +- test/e2e/package-lock.json | 523 +++-- test/e2e/package.json | 25 +- 9 files changed, 446 insertions(+), 3148 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2e0dc2ca047f..94990e8d4827 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -96,8 +96,6 @@ jobs: skip-pkg-cache: true - name: Build Kratos run: make install - - name: Run documentation tests - run: make test-docs - name: Run go-acc (tests) run: make test-coverage - name: Submit to Codecov diff --git a/Makefile b/Makefile index e0242dab683d..20416370f26e 100644 --- a/Makefile +++ b/Makefile @@ -171,11 +171,6 @@ format: .bin/goimports .bin/ory node_modules docker: DOCKER_BUILDKIT=1 DOCKER_CONTENT_TRUST=1 docker build -f .docker/Dockerfile-build --build-arg=COMMIT=$(VCS_REF) --build-arg=BUILD_DATE=$(BUILD_DATE) -t oryd/kratos:${IMAGE_TAG} . -# Runs the documentation tests -.PHONY: test-docs -test-docs: node_modules - npm run text-run - .PHONY: test-e2e test-e2e: node_modules test-resetdb source script/test-envs.sh diff --git a/README.md b/README.md index 5245196408d2..c74bb402836c 100644 --- a/README.md +++ b/README.md @@ -60,10 +60,10 @@ today! Ory offers a support plan for Ory Network Hybrid, including Ory on private cloud deployments. If you have a self-hosted solution and would like help, consider a -support plan! -The team at Ory has years of experience in cloud computing. Ory's offering is -the only official program for qualified support from the maintainers. -For more information see the **[website](https://www.ory.sh/support/)** or +support plan! The team at Ory has years of experience in cloud computing. Ory's +offering is the only official program for qualified support from the +maintainers. For more information see the +**[website](https://www.ory.sh/support/)** or **[book a meeting](https://www.ory.sh/contact/)**! ### Quickstart @@ -554,7 +554,7 @@ that your company deserves a spot here, reach out to pinniped.dev - + Adopter * Pvotal @@ -845,14 +845,6 @@ You can build a development Docker Image using: make docker -#### Documentation Tests - -To prepare documentation tests, run `npm i` to install -[Text-Runner](https://github.com/kevgo/text-runner). - -- test all documentation: make test-docs -- test an individual file: text-run - #### Preview API documentation - update the SDK including the OpenAPI specification: diff --git a/package-lock.json b/package-lock.json index 9f298427bd1c..e2e32697e06a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,85 +5,18 @@ "packages": { "": { "dependencies": { - "@openapitools/openapi-generator-cli": "^2.6.0", - "yamljs": "^0.3.0" + "@openapitools/openapi-generator-cli": "2.6.0", + "yamljs": "0.3.0" }, "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.6.0", - "dayjs": "^1.10.4", - "got": "^11.8.2", - "license-checker": "^25.0.1", + "license-checker": "25.0.1", "ory-prettier-styles": "1.3.0", - "otplib": "^12.0.1", "prettier": "2.7.1", - "prettier-plugin-packagejson": "^2.2.18", - "typescript": "^4.4.3", + "prettier-plugin-packagejson": "2.2.18", + "process": "0.11.10", "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", - "integrity": "sha512-Zp7F+R93N0yZyG34GutyTNr+okam7s/Fzc1+i3kcqOP8vk6OuajuE9qZJ6Rs+10/1JFtXFYMdyarnU1rZuJesg==", - "dev": true, - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "http-signature": "~1.3.6", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^8.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@cypress/xvfb": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz", - "integrity": "sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==", - "dev": true, - "dependencies": { - "debug": "^3.1.0", - "lodash.once": "^4.1.1" - } - }, - "node_modules/@cypress/xvfb/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, "node_modules/@hapi/hoek": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", @@ -325,71 +258,6 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" }, - "node_modules/@ory/kratos-client": { - "version": "0.0.0-next.8d3b018594f7", - "resolved": "https://registry.npmjs.org/@ory/kratos-client/-/kratos-client-0.0.0-next.8d3b018594f7.tgz", - "integrity": "sha512-TkpjBo6Z6UUEJIJCR2EDdpKVDNgQHzwDWZbOjz3xTOUoGipMBykvIfluP58Jwkpt2rIXUkt9+L+u1mFFvD/tqA==", - "dev": true, - "dependencies": { - "axios": "^0.21.1" - } - }, - "node_modules/@ory/kratos-client/node_modules/axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "dev": true, - "dependencies": { - "follow-redirects": "^1.14.0" - } - }, - "node_modules/@otplib/core": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@otplib/core/-/core-12.0.1.tgz", - "integrity": "sha512-4sGntwbA/AC+SbPhbsziRiD+jNDdIzsZ3JUyfZwjtKyc/wufl1pnSIaG4Uqx8ymPagujub0o92kgBnB89cuAMA==", - "dev": true - }, - "node_modules/@otplib/plugin-crypto": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@otplib/plugin-crypto/-/plugin-crypto-12.0.1.tgz", - "integrity": "sha512-qPuhN3QrT7ZZLcLCyKOSNhuijUi9G5guMRVrxq63r9YNOxxQjPm59gVxLM+7xGnHnM6cimY57tuKsjK7y9LM1g==", - "dev": true, - "dependencies": { - "@otplib/core": "^12.0.1" - } - }, - "node_modules/@otplib/plugin-thirty-two": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@otplib/plugin-thirty-two/-/plugin-thirty-two-12.0.1.tgz", - "integrity": "sha512-MtT+uqRso909UkbrrYpJ6XFjj9D+x2Py7KjTO9JDPhL0bJUYVu5kFP4TFZW4NFAywrAtFRxOVY261u0qwb93gA==", - "dev": true, - "dependencies": { - "@otplib/core": "^12.0.1", - "thirty-two": "^1.0.2" - } - }, - "node_modules/@otplib/preset-default": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@otplib/preset-default/-/preset-default-12.0.1.tgz", - "integrity": "sha512-xf1v9oOJRyXfluBhMdpOkr+bsE+Irt+0D5uHtvg6x1eosfmHCsCC6ej/m7FXiWqdo0+ZUI6xSKDhJwc8yfiOPQ==", - "dev": true, - "dependencies": { - "@otplib/core": "^12.0.1", - "@otplib/plugin-crypto": "^12.0.1", - "@otplib/plugin-thirty-two": "^12.0.1" - } - }, - "node_modules/@otplib/preset-v11": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@otplib/preset-v11/-/preset-v11-12.0.1.tgz", - "integrity": "sha512-9hSetMI7ECqbFiKICrNa4w70deTUfArtwXykPUvSHWOdzOlfa9ajglu7mNCntlvxycTiOAXkQGwjQCzzDEMRMg==", - "dev": true, - "dependencies": { - "@otplib/core": "^12.0.1", - "@otplib/plugin-crypto": "^12.0.1", - "@otplib/plugin-thirty-two": "^12.0.1" - } - }, "node_modules/@sideway/address": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", @@ -411,42 +279,6 @@ "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", "dev": true }, - "node_modules/@sindresorhus/is": { - "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" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" - } - }, - "node_modules/@szmarczak/http-timer": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", - "dev": true, - "dependencies": { - "defer-to-connect": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@types/cacheable-request": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.2.tgz", - "integrity": "sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA==", - "dev": true, - "dependencies": { - "@types/http-cache-semantics": "*", - "@types/keyv": "*", - "@types/node": "*", - "@types/responselike": "*" - } - }, "node_modules/@types/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", @@ -457,27 +289,6 @@ "@types/node": "*" } }, - "node_modules/@types/http-cache-semantics": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", - "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.4", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", - "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/minimatch": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", @@ -490,77 +301,12 @@ "integrity": "sha512-mqoYK2TnVjdkGk8qXAVGc/x9nSaTpSrFaGFm43BUH3IdoBV0nta6hYaGmdOvIMlbHJbUEVen3gvwpwovAZKNdQ==", "dev": true }, - "node_modules/@types/responselike": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", - "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/sinonjs__fake-timers": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz", - "integrity": "sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==", - "dev": true - }, - "node_modules/@types/sizzle": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", - "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", - "integrity": "sha512-QcJ5ZczaXAqbVD3o8mw/mEBhRvO5UAdTtbvgwL/OgoWubvNBh6/MxLBAigtcgIFaq3shon9m3POIxQaLQt4fxQ==", - "dev": true - }, - "node_modules/@types/yauzl": { - "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": { - "@types/node": "*" - } - }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-colors": { - "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" - } - }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -597,26 +343,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/arch": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", - "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -649,68 +375,11 @@ "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", "dev": true }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/async": { - "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": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true - }, "node_modules/axios": { "version": "0.27.2", "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", @@ -757,15 +426,6 @@ } ] }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dev": true, - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, "node_modules/bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -776,18 +436,6 @@ "readable-stream": "^3.4.0" } }, - "node_modules/blob-util": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", - "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==", - "dev": true - }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -832,57 +480,6 @@ "ieee754": "^1.1.13" } }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/cacheable-lookup": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", - "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "dev": true, - "engines": { - "node": ">=10.6.0" - } - }, - "node_modules/cacheable-request": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", - "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", - "dev": true, - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cachedir": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", - "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true - }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -903,49 +500,6 @@ "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" }, - "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": "sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/chrome-remote-interface": { - "version": "0.31.2", - "resolved": "https://registry.npmjs.org/chrome-remote-interface/-/chrome-remote-interface-0.31.2.tgz", - "integrity": "sha512-vpdJoI9cDRNAfV5oB2ulwXDltvu3Ov9PTblnV48VXcF4zUx1p4xvCLssc5AZ/WLYp4003YxJqLEi8FagPw2vTQ==", - "dev": true, - "dependencies": { - "commander": "2.11.x", - "ws": "^7.2.0" - }, - "bin": { - "chrome-remote-interface": "bin/client.js" - } - }, - "node_modules/chrome-remote-interface/node_modules/commander": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", - "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", - "dev": true - }, - "node_modules/ci-info": { - "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": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -968,37 +522,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cli-table3": { - "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" - }, - "engines": { - "node": "10.* || >= 12.*" - }, - "optionalDependencies": { - "@colors/colors": "1.5.0" - } - }, - "node_modules/cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", - "dev": true, - "dependencies": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/cli-width": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", @@ -1025,15 +548,6 @@ "node": ">=0.8" } }, - "node_modules/clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha512-yjLXh88P599UOyPTFX0POsd7WxnbsVsGohcwzHOLspIhhpalPw1BcqED8NblyZLKcGrL8dTgMlcaZxV2jAD41Q==", - "dev": true, - "dependencies": { - "mimic-response": "^1.0.0" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1050,12 +564,6 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/colorette": { - "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/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -1075,33 +583,11 @@ "node": ">= 12" } }, - "node_modules/common-tags": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", - "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/compare-versions": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-4.1.4.tgz", "integrity": "sha512-FemMreK9xNyL8gQevsdRMrvO4lFCkQP7qbuktn1q8ndcNk1+0mz7lgE7b/sNvbhVgY4w6tMN1FDp6aADjqw2rw==" }, - "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", @@ -1174,140 +660,6 @@ "node": "> 0.10" } }, - "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": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/cypress": { - "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": { - "@cypress/request": "^2.88.10", - "@cypress/xvfb": "^1.2.4", - "@types/node": "^14.14.31", - "@types/sinonjs__fake-timers": "8.1.1", - "@types/sizzle": "^2.3.2", - "arch": "^2.2.0", - "blob-util": "^2.0.2", - "bluebird": "^3.7.2", - "buffer": "^5.6.0", - "cachedir": "^2.3.0", - "chalk": "^4.1.0", - "check-more-types": "^2.24.0", - "cli-cursor": "^3.1.0", - "cli-table3": "~0.6.1", - "commander": "^5.1.0", - "common-tags": "^1.8.0", - "dayjs": "^1.10.4", - "debug": "^4.3.2", - "enquirer": "^2.3.6", - "eventemitter2": "^6.4.3", - "execa": "4.1.0", - "executable": "^4.1.1", - "extract-zip": "2.0.1", - "figures": "^3.2.0", - "fs-extra": "^9.1.0", - "getos": "^3.2.1", - "is-ci": "^3.0.0", - "is-installed-globally": "~0.4.0", - "lazy-ass": "^1.6.0", - "listr2": "^3.8.3", - "lodash": "^4.17.21", - "log-symbols": "^4.0.0", - "minimist": "^1.2.6", - "ospath": "^1.2.2", - "pretty-bytes": "^5.6.0", - "proxy-from-env": "1.0.0", - "request-progress": "^3.0.0", - "semver": "^7.3.2", - "supports-color": "^8.1.1", - "tmp": "~0.2.1", - "untildify": "^4.0.0", - "yauzl": "^2.10.0" - }, - "bin": { - "cypress": "bin/cypress" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/cypress/node_modules/@types/node": { - "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": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/cypress/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cypress/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/date-fns": { "version": "2.28.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz", @@ -1320,29 +672,6 @@ "url": "https://opencollective.com/date-fns" } }, - "node_modules/dayjs": { - "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.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/debuglog": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", @@ -1352,33 +681,6 @@ "node": "*" } }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decompress-response/node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/defaults": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", @@ -1387,15 +689,6 @@ "clone": "^1.0.2" } }, - "node_modules/defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -1452,42 +745,11 @@ "wcwidth": ">=1.0.1" } }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "dev": true, - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -1504,53 +766,6 @@ "node": ">=0.8.0" } }, - "node_modules/eventemitter2": { - "version": "6.4.5", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.5.tgz", - "integrity": "sha512-bXE7Dyc1i6oQElDG0jMRZJrRAn9QR2xyyFGmBdZleNmyQX0FqGYmhZIrIrpPfm/w//LTo4tVQGOGQcGCb5q9uw==", - "dev": true - }, - "node_modules/execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/executable": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", - "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", - "dev": true, - "dependencies": { - "pify": "^2.2.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, "node_modules/external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -1575,35 +790,6 @@ "node": ">=0.6.0" } }, - "node_modules/extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - }, - "engines": { - "node": ">= 10.17.0" - }, - "optionalDependencies": { - "@types/yauzl": "^2.9.1" - } - }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "dev": true, - "engines": [ - "node >=0.6.0" - ] - }, "node_modules/fast-glob": { "version": "3.2.11", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", @@ -1634,15 +820,6 @@ "reusify": "^1.0.4" } }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dev": true, - "dependencies": { - "pend": "~1.2.0" - } - }, "node_modules/figures": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", @@ -1688,29 +865,6 @@ } } }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, "node_modules/fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", @@ -1743,39 +897,6 @@ "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/getos": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz", - "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==", - "dev": true, - "dependencies": { - "async": "^3.2.0" - } - }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - } - }, "node_modules/git-hooks-list": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/git-hooks-list/-/git-hooks-list-1.0.3.tgz", @@ -1816,21 +937,6 @@ "node": ">= 6" } }, - "node_modules/global-dirs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", - "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", - "dev": true, - "dependencies": { - "ini": "2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/globby": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.0.tgz", @@ -1850,31 +956,6 @@ "node": ">=8" } }, - "node_modules/got": { - "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", - "@szmarczak/http-timer": "^4.0.5", - "@types/cacheable-request": "^6.0.1", - "@types/responselike": "^1.0.0", - "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", - "decompress-response": "^6.0.0", - "http2-wrapper": "^1.0.0-beta.5.2", - "lowercase-keys": "^2.0.0", - "p-cancelable": "^2.0.0", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=10.19.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/got?sponsor=1" - } - }, "node_modules/graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", @@ -1906,48 +987,6 @@ "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, - "node_modules/http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "dev": true - }, - "node_modules/http-signature": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", - "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^2.0.2", - "sshpk": "^1.14.1" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/http2-wrapper": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", - "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", - "dev": true, - "dependencies": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.0.0" - }, - "engines": { - "node": ">=10.19.0" - } - }, - "node_modules/human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "dev": true, - "engines": { - "node": ">=8.12.0" - } - }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -1987,15 +1026,6 @@ "node": ">= 4" } }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -2010,15 +1040,6 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "node_modules/ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/inquirer": { "version": "8.2.5", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", @@ -2044,18 +1065,6 @@ "node": ">=12.0.0" } }, - "node_modules/is-ci": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", - "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", - "dev": true, - "dependencies": { - "ci-info": "^3.2.0" - }, - "bin": { - "is-ci": "bin.js" - } - }, "node_modules/is-core-module": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", @@ -2097,22 +1106,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", - "dev": true, - "dependencies": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-interactive": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", @@ -2130,15 +1123,6 @@ "node": ">=0.12.0" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -2148,24 +1132,6 @@ "node": ">=8" } }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, "node_modules/is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", @@ -2177,18 +1143,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "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": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true - }, "node_modules/iterare": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz", @@ -2210,36 +1164,12 @@ "@sideway/pinpoint": "^2.0.0" } }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true - }, - "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": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true - }, "node_modules/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -2251,40 +1181,6 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/jsprim": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", - "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - } - }, - "node_modules/keyv": { - "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": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==", - "dev": true, - "engines": { - "node": "> 0.8" - } - }, "node_modules/license-checker": { "version": "25.0.1", "resolved": "https://registry.npmjs.org/license-checker/-/license-checker-25.0.1.tgz", @@ -2386,44 +1282,11 @@ "node": ">=4" } }, - "node_modules/listr2": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", - "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==", - "dev": true, - "dependencies": { - "cli-truncate": "^2.1.0", - "colorette": "^2.0.16", - "log-update": "^4.0.0", - "p-map": "^4.0.0", - "rfdc": "^1.3.0", - "rxjs": "^7.5.1", - "through": "^2.3.8", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "enquirer": ">= 2.3.0 < 3" - }, - "peerDependenciesMeta": { - "enquirer": { - "optional": true - } - } - }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", - "dev": true - }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -2439,82 +1302,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-update": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", - "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.3.0", - "cli-cursor": "^3.1.0", - "slice-ansi": "^4.0.0", - "wrap-ansi": "^6.2.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/log-update/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -2564,15 +1351,6 @@ "node": ">=6" } }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -2666,36 +1444,12 @@ "semver": "bin/semver" } }, - "node_modules/normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/npm-normalize-package-bin": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", "dev": true }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -2773,47 +1527,6 @@ "os-tmpdir": "^1.0.0" } }, - "node_modules/ospath": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", - "integrity": "sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==", - "dev": true - }, - "node_modules/otplib": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/otplib/-/otplib-12.0.1.tgz", - "integrity": "sha512-xDGvUOQjop7RDgxTQ+o4pOol0/3xSZzawTiPKRrHnQWAy0WjhNs/5HdIDJCrqC4MBynmjXgULc6YfioaxZeFgg==", - "dev": true, - "dependencies": { - "@otplib/core": "^12.0.1", - "@otplib/preset-default": "^12.0.1", - "@otplib/preset-v11": "^12.0.1" - } - }, - "node_modules/p-cancelable": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", - "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -2822,15 +1535,6 @@ "node": ">=0.10.0" } }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", @@ -2846,22 +1550,10 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "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": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + } }, "node_modules/picomatch": { "version": "2.3.1", @@ -2875,15 +1567,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/prettier": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", @@ -2911,56 +1594,13 @@ "prettier": ">= 1.16.0" } }, - "node_modules/pretty-bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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": "sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==", - "dev": true - }, - "node_modules/psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", "dev": true, "engines": { - "node": ">=0.6" + "node": ">= 0.6.0" } }, "node_modules/queue-microtask": { @@ -2983,18 +1623,6 @@ } ] }, - "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/read-installed": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz", @@ -3063,15 +1691,6 @@ "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" }, - "node_modules/request-progress": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", - "integrity": "sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==", - "dev": true, - "dependencies": { - "throttleit": "^1.0.0" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -3097,21 +1716,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "dev": true - }, - "node_modules/responselike": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", - "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==", - "dev": true, - "dependencies": { - "lowercase-keys": "^2.0.0" - } - }, "node_modules/restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -3134,27 +1738,6 @@ "node": ">=0.10.0" } }, - "node_modules/rfdc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", - "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", - "dev": true - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -3223,42 +1806,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "node_modules/semver": { - "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" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -3273,20 +1820,6 @@ "node": ">=8" } }, - "node_modules/slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/slide": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", @@ -3389,31 +1922,6 @@ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, - "node_modules/sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", - "dev": true, - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -3446,15 +1954,6 @@ "node": ">=8" } }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -3478,38 +1977,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/thirty-two": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/thirty-two/-/thirty-two-1.0.2.tgz", - "integrity": "sha512-OEI0IWCe+Dw46019YLl6V10Us5bi574EvlJEOcAkB29IzQ/mYD1A6RyNHLjZPiHCmuodxvgF6U+vZO1L15lxVA==", - "dev": true, - "engines": { - "node": ">=0.2.6" - } - }, - "node_modules/throttleit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", - "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": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" }, - "node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dev": true, - "dependencies": { - "rimraf": "^3.0.0" - }, - "engines": { - "node": ">=8.17.0" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -3522,19 +1994,6 @@ "node": ">=8.0" } }, - "node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -3562,24 +2021,6 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true - }, "node_modules/type-fest": { "version": "0.21.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", @@ -3591,19 +2032,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/typescript": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", - "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, "node_modules/uid": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/uid/-/uid-2.0.1.tgz", @@ -3623,15 +2051,6 @@ "node": ">= 10.0.0" } }, - "node_modules/untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -3647,6 +2066,7 @@ "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "peer": true, "bin": { "uuid": "dist/bin/uuid" } @@ -3661,20 +2081,6 @@ "spdx-expression-parse": "^3.0.0" } }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, "node_modules/wait-on": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-5.3.0.tgz", @@ -3743,21 +2149,6 @@ "webidl-conversions": "^3.0.0" } }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -3779,27 +2170,6 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, - "node_modules/ws": { - "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" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -3808,12 +2178,6 @@ "node": ">=10" } }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/yamljs": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz", @@ -3851,73 +2215,9 @@ "engines": { "node": ">=10" } - }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dev": true, - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } } }, "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", - "integrity": "sha512-Zp7F+R93N0yZyG34GutyTNr+okam7s/Fzc1+i3kcqOP8vk6OuajuE9qZJ6Rs+10/1JFtXFYMdyarnU1rZuJesg==", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "http-signature": "~1.3.6", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^8.3.2" - } - }, - "@cypress/xvfb": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz", - "integrity": "sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==", - "dev": true, - "requires": { - "debug": "^3.1.0", - "lodash.once": "^4.1.1" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, "@hapi/hoek": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", @@ -4052,83 +2352,16 @@ "iterare": "1.2.1", "path-to-regexp": "3.2.0", "tslib": "2.5.0", - "uid": "2.0.1" - }, - "dependencies": { - "tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - } - } - } - } - }, - "@ory/kratos-client": { - "version": "0.0.0-next.8d3b018594f7", - "resolved": "https://registry.npmjs.org/@ory/kratos-client/-/kratos-client-0.0.0-next.8d3b018594f7.tgz", - "integrity": "sha512-TkpjBo6Z6UUEJIJCR2EDdpKVDNgQHzwDWZbOjz3xTOUoGipMBykvIfluP58Jwkpt2rIXUkt9+L+u1mFFvD/tqA==", - "dev": true, - "requires": { - "axios": "^0.21.1" - }, - "dependencies": { - "axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "dev": true, - "requires": { - "follow-redirects": "^1.14.0" - } - } - } - }, - "@otplib/core": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@otplib/core/-/core-12.0.1.tgz", - "integrity": "sha512-4sGntwbA/AC+SbPhbsziRiD+jNDdIzsZ3JUyfZwjtKyc/wufl1pnSIaG4Uqx8ymPagujub0o92kgBnB89cuAMA==", - "dev": true - }, - "@otplib/plugin-crypto": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@otplib/plugin-crypto/-/plugin-crypto-12.0.1.tgz", - "integrity": "sha512-qPuhN3QrT7ZZLcLCyKOSNhuijUi9G5guMRVrxq63r9YNOxxQjPm59gVxLM+7xGnHnM6cimY57tuKsjK7y9LM1g==", - "dev": true, - "requires": { - "@otplib/core": "^12.0.1" - } - }, - "@otplib/plugin-thirty-two": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@otplib/plugin-thirty-two/-/plugin-thirty-two-12.0.1.tgz", - "integrity": "sha512-MtT+uqRso909UkbrrYpJ6XFjj9D+x2Py7KjTO9JDPhL0bJUYVu5kFP4TFZW4NFAywrAtFRxOVY261u0qwb93gA==", - "dev": true, - "requires": { - "@otplib/core": "^12.0.1", - "thirty-two": "^1.0.2" - } - }, - "@otplib/preset-default": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@otplib/preset-default/-/preset-default-12.0.1.tgz", - "integrity": "sha512-xf1v9oOJRyXfluBhMdpOkr+bsE+Irt+0D5uHtvg6x1eosfmHCsCC6ej/m7FXiWqdo0+ZUI6xSKDhJwc8yfiOPQ==", - "dev": true, - "requires": { - "@otplib/core": "^12.0.1", - "@otplib/plugin-crypto": "^12.0.1", - "@otplib/plugin-thirty-two": "^12.0.1" - } - }, - "@otplib/preset-v11": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@otplib/preset-v11/-/preset-v11-12.0.1.tgz", - "integrity": "sha512-9hSetMI7ECqbFiKICrNa4w70deTUfArtwXykPUvSHWOdzOlfa9ajglu7mNCntlvxycTiOAXkQGwjQCzzDEMRMg==", - "dev": true, - "requires": { - "@otplib/core": "^12.0.1", - "@otplib/plugin-crypto": "^12.0.1", - "@otplib/plugin-thirty-two": "^12.0.1" + "uid": "2.0.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + } + } + } } }, "@sideway/address": { @@ -4152,33 +2385,6 @@ "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", "dev": true }, - "@sindresorhus/is": { - "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": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", - "dev": true, - "requires": { - "defer-to-connect": "^2.0.0" - } - }, - "@types/cacheable-request": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.2.tgz", - "integrity": "sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA==", - "dev": true, - "requires": { - "@types/http-cache-semantics": "*", - "@types/keyv": "*", - "@types/node": "*", - "@types/responselike": "*" - } - }, "@types/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", @@ -4189,27 +2395,6 @@ "@types/node": "*" } }, - "@types/http-cache-semantics": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", - "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.4", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", - "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, "@types/minimatch": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", @@ -4222,71 +2407,12 @@ "integrity": "sha512-mqoYK2TnVjdkGk8qXAVGc/x9nSaTpSrFaGFm43BUH3IdoBV0nta6hYaGmdOvIMlbHJbUEVen3gvwpwovAZKNdQ==", "dev": true }, - "@types/responselike": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", - "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/sinonjs__fake-timers": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz", - "integrity": "sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==", - "dev": true - }, - "@types/sizzle": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", - "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", - "integrity": "sha512-QcJ5ZczaXAqbVD3o8mw/mEBhRvO5UAdTtbvgwL/OgoWubvNBh6/MxLBAigtcgIFaq3shon9m3POIxQaLQt4fxQ==", - "dev": true - }, - "@types/yauzl": { - "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": { - "@types/node": "*" - } - }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true }, - "aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, - "ansi-colors": { - "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": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -4308,12 +2434,6 @@ "color-convert": "^2.0.1" } }, - "arch": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", - "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", - "dev": true - }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -4340,56 +2460,11 @@ "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", "dev": true }, - "asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "dev": true - }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true - }, - "async": { - "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": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, - "at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "dev": true - }, - "aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true - }, "axios": { "version": "0.27.2", "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", @@ -4421,15 +2496,6 @@ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dev": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, "bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -4440,18 +2506,6 @@ "readable-stream": "^3.4.0" } }, - "blob-util": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", - "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==", - "dev": true - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -4479,45 +2533,6 @@ "ieee754": "^1.1.13" } }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true - }, - "cacheable-lookup": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", - "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "dev": true - }, - "cacheable-request": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", - "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", - "dev": true, - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" - } - }, - "cachedir": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", - "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", - "dev": true - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true - }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -4532,42 +2547,6 @@ "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" }, - "check-more-types": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", - "integrity": "sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==", - "dev": true - }, - "chrome-remote-interface": { - "version": "0.31.2", - "resolved": "https://registry.npmjs.org/chrome-remote-interface/-/chrome-remote-interface-0.31.2.tgz", - "integrity": "sha512-vpdJoI9cDRNAfV5oB2ulwXDltvu3Ov9PTblnV48VXcF4zUx1p4xvCLssc5AZ/WLYp4003YxJqLEi8FagPw2vTQ==", - "dev": true, - "requires": { - "commander": "2.11.x", - "ws": "^7.2.0" - }, - "dependencies": { - "commander": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", - "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", - "dev": true - } - } - }, - "ci-info": { - "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": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true - }, "cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -4581,26 +2560,6 @@ "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.8.0.tgz", "integrity": "sha512-/eG5sJcvEIwxcdYM86k5tPwn0MUzkX5YY3eImTGpJOZgVe4SdTMY14vQpcxgBzJ0wXwAYrS8E+c3uHeK4JNyzQ==" }, - "cli-table3": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.2.tgz", - "integrity": "sha512-QyavHCaIC80cMivimWu4aWHilIpiDpfm3hGmqAmXVL1UsnbLuBSMd21hTX6VY4ZSDSM73ESLeF8TOYId3rBTbw==", - "dev": true, - "requires": { - "@colors/colors": "1.5.0", - "string-width": "^4.2.0" - } - }, - "cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", - "dev": true, - "requires": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" - } - }, "cli-width": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", @@ -4621,15 +2580,6 @@ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", "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": "sha512-yjLXh88P599UOyPTFX0POsd7WxnbsVsGohcwzHOLspIhhpalPw1BcqED8NblyZLKcGrL8dTgMlcaZxV2jAD41Q==", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -4643,12 +2593,6 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "colorette": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", - "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", - "dev": true - }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -4662,27 +2606,11 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==" }, - "common-tags": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", - "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", - "dev": true - }, "compare-versions": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-4.1.4.tgz", "integrity": "sha512-FemMreK9xNyL8gQevsdRMrvO4lFCkQP7qbuktn1q8ndcNk1+0mz7lgE7b/sNvbhVgY4w6tMN1FDp6aADjqw2rw==" }, - "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", @@ -4739,160 +2667,17 @@ "easy-table": "1.1.0" } }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "cypress": { - "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", - "@cypress/xvfb": "^1.2.4", - "@types/node": "^14.14.31", - "@types/sinonjs__fake-timers": "8.1.1", - "@types/sizzle": "^2.3.2", - "arch": "^2.2.0", - "blob-util": "^2.0.2", - "bluebird": "^3.7.2", - "buffer": "^5.6.0", - "cachedir": "^2.3.0", - "chalk": "^4.1.0", - "check-more-types": "^2.24.0", - "cli-cursor": "^3.1.0", - "cli-table3": "~0.6.1", - "commander": "^5.1.0", - "common-tags": "^1.8.0", - "dayjs": "^1.10.4", - "debug": "^4.3.2", - "enquirer": "^2.3.6", - "eventemitter2": "^6.4.3", - "execa": "4.1.0", - "executable": "^4.1.1", - "extract-zip": "2.0.1", - "figures": "^3.2.0", - "fs-extra": "^9.1.0", - "getos": "^3.2.1", - "is-ci": "^3.0.0", - "is-installed-globally": "~0.4.0", - "lazy-ass": "^1.6.0", - "listr2": "^3.8.3", - "lodash": "^4.17.21", - "log-symbols": "^4.0.0", - "minimist": "^1.2.6", - "ospath": "^1.2.2", - "pretty-bytes": "^5.6.0", - "proxy-from-env": "1.0.0", - "request-progress": "^3.0.0", - "semver": "^7.3.2", - "supports-color": "^8.1.1", - "tmp": "~0.2.1", - "untildify": "^4.0.0", - "yauzl": "^2.10.0" - }, - "dependencies": { - "@types/node": { - "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": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", - "dev": true - }, - "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "dev": true, - "requires": { - "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.11.3", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.3.tgz", - "integrity": "sha512-xxwlswWOlGhzgQ4TKzASQkUhqERI3egRNqgV4ScR8wlANA/A9tZ7miXa44vTTKEq5l7vWoL5G57bG3zA+Kow0A==", - "dev": true - }, - "debug": { - "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" - } - }, "debuglog": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", "integrity": "sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==", "dev": true }, - "decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, - "requires": { - "mimic-response": "^3.1.0" - }, - "dependencies": { - "mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true - } - } - }, "defaults": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", @@ -4901,12 +2686,6 @@ "clone": "^1.0.2" } }, - "defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "dev": true - }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -4951,39 +2730,11 @@ "wcwidth": ">=1.0.1" } }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "dev": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "requires": { - "ansi-colors": "^4.1.1" - } - }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -4994,44 +2745,6 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" }, - "eventemitter2": { - "version": "6.4.5", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.5.tgz", - "integrity": "sha512-bXE7Dyc1i6oQElDG0jMRZJrRAn9QR2xyyFGmBdZleNmyQX0FqGYmhZIrIrpPfm/w//LTo4tVQGOGQcGCb5q9uw==", - "dev": true - }, - "execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - } - }, - "executable": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", - "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", - "dev": true, - "requires": { - "pify": "^2.2.0" - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, "external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -5052,24 +2765,6 @@ } } }, - "extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "dev": true, - "requires": { - "@types/yauzl": "^2.9.1", - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "dev": true - }, "fast-glob": { "version": "3.2.11", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", @@ -5097,15 +2792,6 @@ "reusify": "^1.0.4" } }, - "fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dev": true, - "requires": { - "pend": "~1.2.0" - } - }, "figures": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", @@ -5128,23 +2814,6 @@ "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": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "dev": true - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, "fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", @@ -5169,34 +2838,7 @@ "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" - }, - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "getos": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz", - "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==", - "dev": true, - "requires": { - "async": "^3.2.0" - } - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" }, "git-hooks-list": { "version": "1.0.3", @@ -5226,15 +2868,6 @@ "is-glob": "^4.0.1" } }, - "global-dirs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", - "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", - "dev": true, - "requires": { - "ini": "2.0.0" - } - }, "globby": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.0.tgz", @@ -5251,25 +2884,6 @@ "slash": "^3.0.0" } }, - "got": { - "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", - "@szmarczak/http-timer": "^4.0.5", - "@types/cacheable-request": "^6.0.1", - "@types/responselike": "^1.0.0", - "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", - "decompress-response": "^6.0.0", - "http2-wrapper": "^1.0.0-beta.5.2", - "lowercase-keys": "^2.0.0", - "p-cancelable": "^2.0.0", - "responselike": "^2.0.0" - } - }, "graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", @@ -5295,39 +2909,6 @@ "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, - "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "dev": true - }, - "http-signature": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", - "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^2.0.2", - "sshpk": "^1.14.1" - } - }, - "http2-wrapper": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", - "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", - "dev": true, - "requires": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.0.0" - } - }, - "human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "dev": true - }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -5347,12 +2928,6 @@ "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true - }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -5367,12 +2942,6 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true - }, "inquirer": { "version": "8.2.5", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", @@ -5395,15 +2964,6 @@ "wrap-ansi": "^7.0.0" } }, - "is-ci": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", - "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", - "dev": true, - "requires": { - "ci-info": "^3.2.0" - } - }, "is-core-module": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", @@ -5433,16 +2993,6 @@ "is-extglob": "^2.1.1" } }, - "is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", - "dev": true, - "requires": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" - } - }, "is-interactive": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", @@ -5454,47 +3004,17 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true - }, "is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", "dev": true }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, "is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==" }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true - }, "iterare": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz", @@ -5513,36 +3033,12 @@ "@sideway/pinpoint": "^2.0.0" } }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true - }, - "json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, "json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, - "json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true - }, "jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -5552,34 +3048,6 @@ "universalify": "^2.0.0" } }, - "jsprim": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", - "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - } - }, - "keyv": { - "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": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==", - "dev": true - }, "license-checker": { "version": "25.0.1", "resolved": "https://registry.npmjs.org/license-checker/-/license-checker-25.0.1.tgz", @@ -5665,33 +3133,11 @@ } } }, - "listr2": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", - "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==", - "dev": true, - "requires": { - "cli-truncate": "^2.1.0", - "colorette": "^2.0.16", - "log-update": "^4.0.0", - "p-map": "^4.0.0", - "rfdc": "^1.3.0", - "rxjs": "^7.5.1", - "through": "^2.3.8", - "wrap-ansi": "^7.0.0" - } - }, "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", - "dev": true - }, "log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -5701,63 +3147,6 @@ "is-unicode-supported": "^0.1.0" } }, - "log-update": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", - "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", - "dev": true, - "requires": { - "ansi-escapes": "^4.3.0", - "cli-cursor": "^3.1.0", - "slice-ansi": "^4.0.0", - "wrap-ansi": "^6.2.0" - }, - "dependencies": { - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - } - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - } - } - }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, "merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -5792,12 +3181,6 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" }, - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true - }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -5870,27 +3253,12 @@ } } }, - "normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "dev": true - }, "npm-normalize-package-bin": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", "dev": true }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -5950,49 +3318,11 @@ "os-tmpdir": "^1.0.0" } }, - "ospath": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", - "integrity": "sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==", - "dev": true - }, - "otplib": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/otplib/-/otplib-12.0.1.tgz", - "integrity": "sha512-xDGvUOQjop7RDgxTQ+o4pOol0/3xSZzawTiPKRrHnQWAy0WjhNs/5HdIDJCrqC4MBynmjXgULc6YfioaxZeFgg==", - "dev": true, - "requires": { - "@otplib/core": "^12.0.1", - "@otplib/preset-default": "^12.0.1", - "@otplib/preset-v11": "^12.0.1" - } - }, - "p-cancelable": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", - "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", - "dev": true - }, - "p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "requires": { - "aggregate-error": "^3.0.0" - } - }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, "path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", @@ -6010,30 +3340,12 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, - "pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "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": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true - }, "picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true - }, "prettier": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", @@ -6049,44 +3361,10 @@ "sort-package-json": "1.57.0" } }, - "pretty-bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", - "dev": true - }, - "proxy-from-env": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", - "integrity": "sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==", - "dev": true - }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", "dev": true }, "queue-microtask": { @@ -6095,12 +3373,6 @@ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, - "quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true - }, "read-installed": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz", @@ -6163,15 +3435,6 @@ "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" }, - "request-progress": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", - "integrity": "sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==", - "dev": true, - "requires": { - "throttleit": "^1.0.0" - } - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -6188,21 +3451,6 @@ "supports-preserve-symlinks-flag": "^1.0.0" } }, - "resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "dev": true - }, - "responselike": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", - "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==", - "dev": true, - "requires": { - "lowercase-keys": "^2.0.0" - } - }, "restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -6218,21 +3466,6 @@ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true }, - "rfdc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", - "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, "run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -6272,30 +3505,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "semver": { - "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" - } - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, "signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -6307,17 +3516,6 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, - "slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - } - }, "slide": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", @@ -6414,23 +3612,6 @@ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, - "sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", - "dev": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, "string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -6457,12 +3638,6 @@ "ansi-regex": "^5.0.1" } }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -6477,32 +3652,11 @@ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true }, - "thirty-two": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/thirty-two/-/thirty-two-1.0.2.tgz", - "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": "sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g==", - "dev": true - }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" }, - "tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dev": true, - "requires": { - "rimraf": "^3.0.0" - } - }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -6512,16 +3666,6 @@ "is-number": "^7.0.0" } }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -6543,32 +3687,11 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true - }, "type-fest": { "version": "0.21.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" }, - "typescript": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", - "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", - "dev": true - }, "uid": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/uid/-/uid-2.0.1.tgz", @@ -6582,12 +3705,6 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" }, - "untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "dev": true - }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -6602,7 +3719,8 @@ "uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "peer": true }, "validate-npm-package-license": { "version": "3.0.4", @@ -6614,17 +3732,6 @@ "spdx-expression-parse": "^3.0.0" } }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, "wait-on": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-5.3.0.tgz", @@ -6686,15 +3793,6 @@ "webidl-conversions": "^3.0.0" } }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -6710,24 +3808,11 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, - "ws": { - "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", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "yamljs": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz", @@ -6755,16 +3840,6 @@ "version": "20.2.9", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" - }, - "yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dev": true, - "requires": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } } } } diff --git a/package.json b/package.json index 27036b051249..6c2735e4db2d 100644 --- a/package.json +++ b/package.json @@ -2,31 +2,19 @@ "private": true, "scripts": { "openapi-generator-cli": "openapi-generator-cli", - "test": "cypress run --browser chrome", - "test:watch": "cypress open --browser chrome", - "text-run": "exit 0", "wait-on": "wait-on" }, "prettier": "ory-prettier-styles", "dependencies": { - "@openapitools/openapi-generator-cli": "^2.6.0", - "yamljs": "^0.3.0" + "@openapitools/openapi-generator-cli": "2.6.0", + "yamljs": "0.3.0" }, "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.6.0", - "dayjs": "^1.10.4", - "got": "^11.8.2", - "license-checker": "^25.0.1", + "license-checker": "25.0.1", "ory-prettier-styles": "1.3.0", - "otplib": "^12.0.1", "prettier": "2.7.1", - "prettier-plugin-packagejson": "^2.2.18", - "typescript": "^4.4.3", + "prettier-plugin-packagejson": "2.2.18", + "process": "0.11.10", "wait-on": "5.3.0" } } diff --git a/test/e2e/cypress.config.ts b/test/e2e/cypress.config.ts index 3ddc91b91270..45ddc9bbd0c3 100644 --- a/test/e2e/cypress.config.ts +++ b/test/e2e/cypress.config.ts @@ -4,6 +4,7 @@ import { defineConfig } from "cypress" import got from "got" const CRI = require("chrome-remote-interface") + let criPort = 0, criClient = null @@ -15,6 +16,7 @@ export default defineConfig({ video: true, videoCompression: false, screenshotOnRunFailure: true, + e2e: { retries: { runMode: 6, @@ -27,12 +29,10 @@ export default defineConfig({ specPattern: "**/*.spec.{js,ts}", baseUrl: "http://localhost:4455/", setupNodeEvents(on, config) { - on("before:browser:launch", (browser, args) => { - criPort = ensureRdpPort(args.args) + on("before:browser:launch", (browser, launchOptions) => { + criPort = ensureRdpPort(launchOptions.args) console.log("criPort is", criPort) - }) - on("before:browser:launch", (browser, launchOptions) => { if (browser.name.includes("chrom") && browser.isHeadless) { launchOptions.args.push("--headless=new") } diff --git a/test/e2e/cypress/support/commands.ts b/test/e2e/cypress/support/commands.ts index b7ccff939add..1db5571f2900 100644 --- a/test/e2e/cypress/support/commands.ts +++ b/test/e2e/cypress/support/commands.ts @@ -918,7 +918,7 @@ Cypress.Commands.add("loginMobile", ({ email, password }) => { }) Cypress.Commands.add("logout", () => { - cy.getCookies().should((cookies) => { + cy.getCookies().then((cookies) => { const c = cookies.find( ({ name }) => name.indexOf("ory_kratos_session") > -1, ) diff --git a/test/e2e/package-lock.json b/test/e2e/package-lock.json index fa3ca9753eeb..08dfd3278dc3 100644 --- a/test/e2e/package-lock.json +++ b/test/e2e/package-lock.json @@ -9,19 +9,20 @@ "version": "0.0.1", "devDependencies": { "@ory/kratos-client": "0.0.0-next.8d3b018594f7", - "@playwright/test": "^1.32.3", - "@types/node": "^16.9.6", - "@types/yamljs": "^0.2.31", - "chrome-remote-interface": "0.31.2", - "cypress": "^11.2.0", - "dayjs": "^1.10.4", - "dotenv": "^16.0.3", - "got": "^11.8.2", - "json-schema-to-typescript": "^12.0.0", - "otplib": "^12.0.1", - "typescript": "^4.7.4", + "@playwright/test": "1.32.3", + "@types/node": "16.9.6", + "@types/yamljs": "0.2.31", + "chrome-remote-interface": "0.33.0", + "cypress": "11.2.0", + "dayjs": "1.10.4", + "dotenv": "16.0.3", + "got": "11.8.2", + "json-schema-to-typescript": "12.0.0", + "otplib": "12.0.1", + "process": "0.11.10", + "typescript": "4.7.4", "wait-on": "7.0.1", - "yamljs": "^0.3.0" + "yamljs": "0.3.0" } }, "node_modules/@bcherny/json-schema-ref-parser": { @@ -43,9 +44,9 @@ } }, "node_modules/@cypress/request": { - "version": "2.88.10", - "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.10.tgz", - "integrity": "sha512-Zp7F+R93N0yZyG34GutyTNr+okam7s/Fzc1+i3kcqOP8vk6OuajuE9qZJ6Rs+10/1JFtXFYMdyarnU1rZuJesg==", + "version": "2.88.12", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.12.tgz", + "integrity": "sha512-tOn+0mDZxASFM+cuAP9szGUGPI1HwWVSvdzm7V4cCsPdFTx6qMj29CwaQmRAMIEhORIUBFBsYROYJcveK4uOjA==", "dev": true, "dependencies": { "aws-sign2": "~0.7.0", @@ -61,9 +62,9 @@ "json-stringify-safe": "~5.0.1", "mime-types": "~2.1.19", "performance-now": "^2.1.0", - "qs": "~6.5.2", + "qs": "~6.10.3", "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", + "tough-cookie": "^4.1.3", "tunnel-agent": "^0.6.0", "uuid": "^8.3.2" }, @@ -287,9 +288,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "16.11.26", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.26.tgz", - "integrity": "sha512-GZ7bu5A6+4DtG7q9GsoHXy3ALcgeIHP4NnL0Vv2wu0uUB/yQex26v0tf6/na1mm0+bS9Uw+0DFex7aaKr2qawQ==", + "version": "16.9.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.6.tgz", + "integrity": "sha512-YHUZhBOMTM3mjFkXVcK+WwAcYmyhe1wL4lfqNtzI0b3qAy7yuSetnM7QJazgE5PFmgVTNGiLOgRFfJMqW7XpSQ==", "dev": true }, "node_modules/@types/prettier": { @@ -443,7 +444,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" @@ -482,16 +483,16 @@ "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": "*" } }, "node_modules/aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", "dev": true }, "node_modules/axios": { @@ -532,7 +533,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" @@ -629,6 +630,19 @@ "node": ">=6" } }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/call-me-maybe": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", @@ -638,7 +652,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": { @@ -679,9 +693,9 @@ } }, "node_modules/chrome-remote-interface": { - "version": "0.31.2", - "resolved": "https://registry.npmjs.org/chrome-remote-interface/-/chrome-remote-interface-0.31.2.tgz", - "integrity": "sha512-vpdJoI9cDRNAfV5oB2ulwXDltvu3Ov9PTblnV48VXcF4zUx1p4xvCLssc5AZ/WLYp4003YxJqLEi8FagPw2vTQ==", + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/chrome-remote-interface/-/chrome-remote-interface-0.33.0.tgz", + "integrity": "sha512-tv/SgeBfShXk43fwFpQ9wnS7mOCPzETnzDXTNxCb6TqKOiOeIfbrJz+2NAp8GmzwizpKa058wnU1Te7apONaYg==", "dev": true, "dependencies": { "commander": "2.11.x", @@ -844,7 +858,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": { @@ -919,9 +933,9 @@ } }, "node_modules/cypress/node_modules/@types/node": { - "version": "14.18.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.12.tgz", - "integrity": "sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A==", + "version": "14.18.63", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", + "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==", "dev": true }, "node_modules/cypress/node_modules/commander": { @@ -946,7 +960,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" @@ -956,15 +970,15 @@ } }, "node_modules/dayjs": { - "version": "1.10.8", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.8.tgz", - "integrity": "sha512-wbNwDfBHHur9UOzNUjeKUOJ0fCb0a52Wx0xInmQ7Y8FstyajiV1NmK1e00cxsr9YrE9r7yAChE0VvpuY5Rnlow==", + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.4.tgz", + "integrity": "sha512-RI/Hh4kqRc1UKLOAf/T5zdMMX5DQIlDxwUe3wSyMMnEbGunnpENCdbUgM+dW7kXidZqCttBrmw7BhN4TMddkCw==", "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" @@ -1035,7 +1049,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", @@ -1221,7 +1235,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" @@ -1274,7 +1288,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": "*" @@ -1329,6 +1343,27 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-stdin": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", @@ -1368,7 +1403,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" @@ -1429,9 +1464,9 @@ } }, "node_modules/got": { - "version": "11.8.5", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.5.tgz", - "integrity": "sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==", + "version": "11.8.2", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.2.tgz", + "integrity": "sha512-D0QywKgIe30ODs+fm8wMZiAcZjypcCodPNuMz5H9Mny7RJ+IjJ10BdmGW7OM7fHXP+O7r6ZwapQ/YQmMSvB0UQ==", "dev": true, "dependencies": { "@sindresorhus/is": "^4.0.0", @@ -1439,7 +1474,7 @@ "@types/cacheable-request": "^6.0.1", "@types/responselike": "^1.0.0", "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", + "cacheable-request": "^7.0.1", "decompress-response": "^6.0.0", "http2-wrapper": "^1.0.0-beta.5.2", "lowercase-keys": "^2.0.0", @@ -1459,6 +1494,18 @@ "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", "dev": true }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -1468,6 +1515,30 @@ "node": ">=8" } }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/http-cache-semantics": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", @@ -1652,7 +1723,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": { @@ -1676,7 +1747,7 @@ "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/joi": { @@ -1713,7 +1784,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": { @@ -1759,7 +1830,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": { @@ -2091,6 +2162,15 @@ "node": ">=0.10.0" } }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -2183,7 +2263,7 @@ "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/pify": { @@ -2234,6 +2314,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/proxy-from-env": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", @@ -2241,9 +2330,9 @@ "dev": true }, "node_modules/psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", "dev": true }, "node_modules/pump": { @@ -2257,23 +2346,35 @@ } }, "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", "dev": true, "engines": { "node": ">=6" } }, "node_modules/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "version": "6.10.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.4.tgz", + "integrity": "sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==", "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, "engines": { "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, "node_modules/quick-lru": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", @@ -2295,6 +2396,12 @@ "throttleit": "^1.0.0" } }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, "node_modules/resolve-alpn": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", @@ -2380,9 +2487,9 @@ "dev": true }, "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.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -2415,6 +2522,20 @@ "node": ">=8" } }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -2581,16 +2702,27 @@ } }, "node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", "dev": true, "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" }, "engines": { - "node": ">=0.8" + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" } }, "node_modules/tslib": { @@ -2602,7 +2734,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" @@ -2614,7 +2746,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": { @@ -2666,6 +2798,16 @@ "node": ">=8" } }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -2678,7 +2820,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" @@ -2836,9 +2978,9 @@ } }, "@cypress/request": { - "version": "2.88.10", - "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.10.tgz", - "integrity": "sha512-Zp7F+R93N0yZyG34GutyTNr+okam7s/Fzc1+i3kcqOP8vk6OuajuE9qZJ6Rs+10/1JFtXFYMdyarnU1rZuJesg==", + "version": "2.88.12", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.12.tgz", + "integrity": "sha512-tOn+0mDZxASFM+cuAP9szGUGPI1HwWVSvdzm7V4cCsPdFTx6qMj29CwaQmRAMIEhORIUBFBsYROYJcveK4uOjA==", "dev": true, "requires": { "aws-sign2": "~0.7.0", @@ -2854,9 +2996,9 @@ "json-stringify-safe": "~5.0.1", "mime-types": "~2.1.19", "performance-now": "^2.1.0", - "qs": "~6.5.2", + "qs": "~6.10.3", "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", + "tough-cookie": "^4.1.3", "tunnel-agent": "^0.6.0", "uuid": "^8.3.2" } @@ -3062,9 +3204,9 @@ "dev": true }, "@types/node": { - "version": "16.11.26", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.26.tgz", - "integrity": "sha512-GZ7bu5A6+4DtG7q9GsoHXy3ALcgeIHP4NnL0Vv2wu0uUB/yQex26v0tf6/na1mm0+bS9Uw+0DFex7aaKr2qawQ==", + "version": "16.9.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.6.tgz", + "integrity": "sha512-YHUZhBOMTM3mjFkXVcK+WwAcYmyhe1wL4lfqNtzI0b3qAy7yuSetnM7QJazgE5PFmgVTNGiLOgRFfJMqW7XpSQ==", "dev": true }, "@types/prettier": { @@ -3183,7 +3325,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": { @@ -3213,13 +3355,13 @@ "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": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", "dev": true }, "axios": { @@ -3246,7 +3388,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" @@ -3317,6 +3459,16 @@ "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", "dev": true }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, "call-me-maybe": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", @@ -3326,7 +3478,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": { @@ -3357,9 +3509,9 @@ "dev": true }, "chrome-remote-interface": { - "version": "0.31.2", - "resolved": "https://registry.npmjs.org/chrome-remote-interface/-/chrome-remote-interface-0.31.2.tgz", - "integrity": "sha512-vpdJoI9cDRNAfV5oB2ulwXDltvu3Ov9PTblnV48VXcF4zUx1p4xvCLssc5AZ/WLYp4003YxJqLEi8FagPw2vTQ==", + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/chrome-remote-interface/-/chrome-remote-interface-0.33.0.tgz", + "integrity": "sha512-tv/SgeBfShXk43fwFpQ9wnS7mOCPzETnzDXTNxCb6TqKOiOeIfbrJz+2NAp8GmzwizpKa058wnU1Te7apONaYg==", "dev": true, "requires": { "commander": "2.11.x", @@ -3487,7 +3639,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": { @@ -3552,9 +3704,9 @@ }, "dependencies": { "@types/node": { - "version": "14.18.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.12.tgz", - "integrity": "sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A==", + "version": "14.18.63", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", + "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==", "dev": true }, "commander": { @@ -3578,22 +3730,22 @@ "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" } }, "dayjs": { - "version": "1.10.8", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.8.tgz", - "integrity": "sha512-wbNwDfBHHur9UOzNUjeKUOJ0fCb0a52Wx0xInmQ7Y8FstyajiV1NmK1e00cxsr9YrE9r7yAChE0VvpuY5Rnlow==", + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.4.tgz", + "integrity": "sha512-RI/Hh4kqRc1UKLOAf/T5zdMMX5DQIlDxwUe3wSyMMnEbGunnpENCdbUgM+dW7kXidZqCttBrmw7BhN4TMddkCw==", "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" @@ -3637,7 +3789,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", @@ -3798,7 +3950,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 }, "fd-slicer": { @@ -3828,7 +3980,7 @@ "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": { @@ -3867,6 +4019,24 @@ "dev": true, "optional": true }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + } + }, "get-stdin": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", @@ -3894,7 +4064,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" @@ -3933,9 +4103,9 @@ } }, "got": { - "version": "11.8.5", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.5.tgz", - "integrity": "sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==", + "version": "11.8.2", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.2.tgz", + "integrity": "sha512-D0QywKgIe30ODs+fm8wMZiAcZjypcCodPNuMz5H9Mny7RJ+IjJ10BdmGW7OM7fHXP+O7r6ZwapQ/YQmMSvB0UQ==", "dev": true, "requires": { "@sindresorhus/is": "^4.0.0", @@ -3943,7 +4113,7 @@ "@types/cacheable-request": "^6.0.1", "@types/responselike": "^1.0.0", "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", + "cacheable-request": "^7.0.1", "decompress-response": "^6.0.0", "http2-wrapper": "^1.0.0-beta.5.2", "lowercase-keys": "^2.0.0", @@ -3957,12 +4127,33 @@ "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", "dev": true }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, "http-cache-semantics": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", @@ -4091,7 +4282,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": { @@ -4109,7 +4300,7 @@ "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 }, "joi": { @@ -4145,7 +4336,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": { @@ -4185,7 +4376,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": { @@ -4437,6 +4628,12 @@ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true }, + "object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -4508,7 +4705,7 @@ "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 }, "pify": { @@ -4535,6 +4732,12 @@ "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", "dev": true }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true + }, "proxy-from-env": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", @@ -4542,9 +4745,9 @@ "dev": true }, "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", "dev": true }, "pump": { @@ -4558,15 +4761,24 @@ } }, "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", "dev": true }, "qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "version": "6.10.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.4.tgz", + "integrity": "sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", "dev": true }, "quick-lru": { @@ -4584,6 +4796,12 @@ "throttleit": "^1.0.0" } }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, "resolve-alpn": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", @@ -4646,9 +4864,9 @@ "dev": true }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -4669,6 +4887,17 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, "signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -4800,13 +5029,23 @@ } }, "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", "dev": true, "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "dependencies": { + "universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true + } } }, "tslib": { @@ -4818,7 +5057,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" @@ -4827,7 +5066,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": { @@ -4860,6 +5099,16 @@ "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", "dev": true }, + "url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -4869,7 +5118,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", diff --git a/test/e2e/package.json b/test/e2e/package.json index 7fb4aa522bc3..986fe5cae64a 100644 --- a/test/e2e/package.json +++ b/test/e2e/package.json @@ -12,18 +12,19 @@ }, "devDependencies": { "@ory/kratos-client": "0.0.0-next.8d3b018594f7", - "@playwright/test": "^1.32.3", - "@types/node": "^16.9.6", - "@types/yamljs": "^0.2.31", - "chrome-remote-interface": "0.31.2", - "cypress": "^11.2.0", - "dayjs": "^1.10.4", - "dotenv": "^16.0.3", - "got": "^11.8.2", - "json-schema-to-typescript": "^12.0.0", - "otplib": "^12.0.1", - "typescript": "^4.7.4", + "@playwright/test": "1.32.3", + "@types/node": "16.9.6", + "@types/yamljs": "0.2.31", + "chrome-remote-interface": "0.33.0", + "cypress": "11.2.0", + "dayjs": "1.10.4", + "dotenv": "16.0.3", + "got": "11.8.2", + "json-schema-to-typescript": "12.0.0", + "otplib": "12.0.1", + "process": "0.11.10", + "typescript": "4.7.4", "wait-on": "7.0.1", - "yamljs": "^0.3.0" + "yamljs": "0.3.0" } } From 7ae1271a1db08ad98de9f039ccbfc8494eb2a678 Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Tue, 26 Sep 2023 09:46:44 +0200 Subject: [PATCH 109/282] chore: ignore CVE-2023-4806 (#3532) --- .grype.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.grype.yaml b/.grype.yaml index d9727bf1ecf9..1ba341fccad5 100644 --- a/.grype.yaml +++ b/.grype.yaml @@ -3,4 +3,5 @@ ignore: - vulnerability: CVE-2015-5237 - vulnerability: CVE-2022-30065 - vulnerability: CVE-2023-2650 - - vulnerability: CVE-2023-4813 \ No newline at end of file + - vulnerability: CVE-2023-4813 + - vulnerability: CVE-2023-4806 From 461ad5297311dc650546239fc1d20a80e05f249b Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Tue, 26 Sep 2023 09:07:50 +0000 Subject: [PATCH 110/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59111de58ac4..032f2f3a8ccc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-09-20)](#2023-09-20) +- [ (2023-09-26)](#2023-09-26) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -313,7 +313,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-09-20) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-09-26) ## Breaking Changes @@ -385,6 +385,13 @@ https://github.com/ory/kratos/pull/3480 - Don't return 500 on conflict for POST /admin/identities ([#3437](https://github.com/ory/kratos/issues/3437)) ([1429949](https://github.com/ory/kratos/commit/142994932e449d9948148804502c98ef73daafff)) +- Error handling on identity import + ([#3520](https://github.com/ory/kratos/issues/3520)) + ([83bfb2d](https://github.com/ory/kratos/commit/83bfb2d2a9c69bf3a3442500b9484c1a69f8c794)): + + When importing identities without any traits, or with malformed traits, 500s + are returned. This improves the error handling and messaging. + - False-positives for requiring re-authentication on update ([#3421](https://github.com/ory/kratos/issues/3421)) ([ce8139f](https://github.com/ory/kratos/commit/ce8139f2325a8317388cbcaaa98f3f83d626657b)) @@ -453,6 +460,8 @@ https://github.com/ory/kratos/pull/3480 - Return 400 bad request for invalid login challenge ([#3404](https://github.com/ory/kratos/issues/3404)) ([ca34e9b](https://github.com/ory/kratos/commit/ca34e9b744482b41d65082f3bed52e9c4ebd7ba4)) +- Schema test errors ([#3528](https://github.com/ory/kratos/issues/3528)) + ([bee0341](https://github.com/ory/kratos/commit/bee0341c5bf5708a2210146fc59f050a1b9df663)) - Type-assert all interfaces that WebHook implements ([ffda1a0](https://github.com/ory/kratos/commit/ffda1a0dab661c5f11ad849b9287094313561b79)) - Use registry client for schema loading @@ -488,6 +497,8 @@ https://github.com/ory/kratos/pull/3480 The tokenize feature supports multiple templates, which makes it easy to use the resulting JWT in a variety of use cases. +- Add event ([#3524](https://github.com/ory/kratos/issues/3524)) + ([75031e6](https://github.com/ory/kratos/commit/75031e67bc82a820a6aba134115e8d5f93303638)) - Add GetID member functions to RecoveryAddress and Credentials ([#3474](https://github.com/ory/kratos/issues/3474)) ([085d500](https://github.com/ory/kratos/commit/085d5002df27d455057d33bd2d93dfbca0de4872)) @@ -564,6 +575,14 @@ https://github.com/ory/kratos/pull/3480 - Emit error details when we find stray cookies in an API flow ([#3496](https://github.com/ory/kratos/issues/3496)) ([df74339](https://github.com/ory/kratos/commit/df74339802d98a292abb32806eca35fb2554960b)) +- Fine-grained hooks for all available flow methods + ([#3519](https://github.com/ory/kratos/issues/3519)) + ([a37f6bd](https://github.com/ory/kratos/commit/a37f6bddc48443b2fc464699fa5c2922f64d81f6)): + + Adds fine-grained hook configurations to the post-settings flow for methods + totp, webauthn, lookup_secret and the post-login flow for totp, lookup_secret, + and code. + - Hook to revoke sessions after password changed ([#3514](https://github.com/ory/kratos/issues/3514)) ([e6af6db](https://github.com/ory/kratos/commit/e6af6db37ff5de33a656ce7804c813451395459d)), @@ -626,6 +645,8 @@ https://github.com/ory/kratos/pull/3480 "reauthenticate" will force the user to reauthenticate (similar to `prompt=login` for other Providers). +- Support for B2B SSO ([#3489](https://github.com/ory/kratos/issues/3489)) + ([0ec037a](https://github.com/ory/kratos/commit/0ec037ab298ed28fb0ac84db6a4d2b14b81e57df)) - Support multiple origins for WebAuthN ([#3380](https://github.com/ory/kratos/issues/3380)) ([013f335](https://github.com/ory/kratos/commit/013f335881831bbf90ac31b219b57118fc089fe6)): @@ -649,9 +670,13 @@ https://github.com/ory/kratos/pull/3480 - **e2e:** Logout return_to ([#3418](https://github.com/ory/kratos/issues/3418)) ([c348c12](https://github.com/ory/kratos/commit/c348c12ab3c9cdb4ce8159fe774ed179ff6a4d8a)) +- Fix cypress setup ([#3527](https://github.com/ory/kratos/issues/3527)) + ([70c8ddd](https://github.com/ory/kratos/commit/70c8ddd49c8abb9c10f2ca349e01061b791c5e7b)) - Fix e2e failures and speed up e2e tests ([#3483](https://github.com/ory/kratos/issues/3483)) ([70a6171](https://github.com/ory/kratos/commit/70a617194d61763f4b75691b22cfa76ba71ab019)) +- Resolve cypress issues ([#3531](https://github.com/ory/kratos/issues/3531)) + ([4206d26](https://github.com/ory/kratos/commit/4206d2605dfa30b19e132be31b85b1a35f8dca78)) # [1.0.0](https://github.com/ory/kratos/compare/v0.13.0...v1.0.0) (2023-07-12) From ff177db8a97f27abc3e883e79832685348602334 Mon Sep 17 00:00:00 2001 From: Patrik Date: Tue, 26 Sep 2023 19:02:20 +0200 Subject: [PATCH 111/282] fix: do not initialize parts of the registry in parallel (#3534) --- cmd/daemon/serve.go | 94 ++++++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/cmd/daemon/serve.go b/cmd/daemon/serve.go index c58afcda76b7..fbe37dc6b592 100644 --- a/cmd/daemon/serve.go +++ b/cmd/daemon/serve.go @@ -69,7 +69,7 @@ func WithContext(ctx stdctx.Context) Option { } } -func ServePublic(r driver.Registry, cmd *cobra.Command, _ []string, slOpts *servicelocatorx.Options, opts []Option) error { +func servePublic(r driver.Registry, cmd *cobra.Command, eg *errgroup.Group, slOpts *servicelocatorx.Options, opts []Option) { modifiers := NewOptions(cmd.Context(), opts) ctx := modifiers.ctx @@ -137,28 +137,30 @@ func ServePublic(r driver.Registry, cmd *cobra.Command, _ []string, slOpts *serv }) addr := c.PublicListenOn(ctx) - l.Printf("Starting the public httpd on: %s", addr) - if err := graceful.GracefulContext(ctx, func() error { - listener, err := networkx.MakeListener(addr, c.PublicSocketPermission(ctx)) - if err != nil { - return err + eg.Go(func() error { + l.Printf("Starting the public httpd on: %s", addr) + if err := graceful.GracefulContext(ctx, func() error { + listener, err := networkx.MakeListener(addr, c.PublicSocketPermission(ctx)) + if err != nil { + return err + } + + if certs == nil { + return server.Serve(listener) + } + return server.ServeTLS(listener, "", "") + }, server.Shutdown); err != nil { + if !errors.Is(err, context.Canceled) { + l.Errorf("Failed to gracefully shutdown public httpd: %s", err) + return err + } } - - if certs == nil { - return server.Serve(listener) - } - return server.ServeTLS(listener, "", "") - }, server.Shutdown); err != nil { - if !errors.Is(err, context.Canceled) { - l.Errorf("Failed to gracefully shutdown public httpd: %s", err) - return err - } - } - l.Println("Public httpd was shutdown gracefully") - return nil + l.Println("Public httpd was shutdown gracefully") + return nil + }) } -func ServeAdmin(r driver.Registry, cmd *cobra.Command, _ []string, slOpts *servicelocatorx.Options, opts []Option) error { +func serveAdmin(r driver.Registry, cmd *cobra.Command, eg *errgroup.Group, slOpts *servicelocatorx.Options, opts []Option) { modifiers := NewOptions(cmd.Context(), opts) ctx := modifiers.ctx @@ -210,25 +212,27 @@ func ServeAdmin(r driver.Registry, cmd *cobra.Command, _ []string, slOpts *servi addr := c.AdminListenOn(ctx) - l.Printf("Starting the admin httpd on: %s", addr) - if err := graceful.GracefulContext(ctx, func() error { - listener, err := networkx.MakeListener(addr, c.AdminSocketPermission(ctx)) - if err != nil { - return err - } - - if certs == nil { - return server.Serve(listener) + eg.Go(func() error { + l.Printf("Starting the admin httpd on: %s", addr) + if err := graceful.GracefulContext(ctx, func() error { + listener, err := networkx.MakeListener(addr, c.AdminSocketPermission(ctx)) + if err != nil { + return err + } + + if certs == nil { + return server.Serve(listener) + } + return server.ServeTLS(listener, "", "") + }, server.Shutdown); err != nil { + if !errors.Is(err, context.Canceled) { + l.Errorf("Failed to gracefully shutdown admin httpd: %s", err) + return err + } } - return server.ServeTLS(listener, "", "") - }, server.Shutdown); err != nil { - if !errors.Is(err, context.Canceled) { - l.Errorf("Failed to gracefully shutdown admin httpd: %s", err) - return err - } - } - l.Println("Admin httpd was shutdown gracefully") - return nil + l.Println("Admin httpd was shutdown gracefully") + return nil + }) } func sqa(ctx stdctx.Context, cmd *cobra.Command, d driver.Registry) *metricsx.Service { @@ -305,7 +309,7 @@ func sqa(ctx stdctx.Context, cmd *cobra.Command, d driver.Registry) *metricsx.Se ) } -func bgTasks(d driver.Registry, cmd *cobra.Command, _ []string, _ *servicelocatorx.Options, opts []Option) error { +func bgTasks(d driver.Registry, cmd *cobra.Command, opts []Option) error { modifiers := NewOptions(cmd.Context(), opts) ctx := modifiers.ctx @@ -317,7 +321,7 @@ func bgTasks(d driver.Registry, cmd *cobra.Command, _ []string, _ *servicelocato } func ServeAll(d driver.Registry, slOpts *servicelocatorx.Options, opts []Option) func(cmd *cobra.Command, args []string) error { - return func(cmd *cobra.Command, args []string) error { + return func(cmd *cobra.Command, _ []string) error { mods := NewOptions(cmd.Context(), opts) ctx := mods.ctx @@ -325,14 +329,10 @@ func ServeAll(d driver.Registry, slOpts *servicelocatorx.Options, opts []Option) cmd.SetContext(ctx) opts = append(opts, WithContext(ctx)) + servePublic(d, cmd, g, slOpts, opts) + serveAdmin(d, cmd, g, slOpts, opts) g.Go(func() error { - return ServePublic(d, cmd, args, slOpts, opts) - }) - g.Go(func() error { - return ServeAdmin(d, cmd, args, slOpts, opts) - }) - g.Go(func() error { - return bgTasks(d, cmd, args, slOpts, opts) + return bgTasks(d, cmd, opts) }) return g.Wait() } From 6b91dc14c1adae0425e9ee46a3df30eba64321fc Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Wed, 27 Sep 2023 08:45:51 +0000 Subject: [PATCH 112/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 032f2f3a8ccc..8cb3e3eac6e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-09-26)](#2023-09-26) +- [ (2023-09-27)](#2023-09-27) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -313,7 +313,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-09-26) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-09-27) ## Breaking Changes @@ -379,6 +379,9 @@ https://github.com/ory/kratos/pull/3480 - Do not encode full config in multiple places ([#3500](https://github.com/ory/kratos/issues/3500)) ([57a3273](https://github.com/ory/kratos/commit/57a3273055c6e8627dd0b736e881dba3fb0fe75d)) +- Do not initialize parts of the registry in parallel + ([#3534](https://github.com/ory/kratos/issues/3534)) + ([ff177db](https://github.com/ory/kratos/commit/ff177db8a97f27abc3e883e79832685348602334)) - Don't require session for OIDC verification ([#3443](https://github.com/ory/kratos/issues/3443)) ([e08f831](https://github.com/ory/kratos/commit/e08f831c2715e515bf58dc2dbb47fc3576421a5c)) From 39b0c3c03df0aec254b32c840730452d4856872b Mon Sep 17 00:00:00 2001 From: Martin Jensen Date: Mon, 2 Oct 2023 12:07:41 +0200 Subject: [PATCH 113/282] docs: add example for `allowed_return_urls` to include wildcard url (#3533) See #1528 --- embedx/config.schema.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/embedx/config.schema.json b/embedx/config.schema.json index 02f568ee71fe..2992a7d3ddda 100644 --- a/embedx/config.schema.json +++ b/embedx/config.schema.json @@ -1201,7 +1201,8 @@ [ "https://app.my-app.com/dashboard", "/dashboard", - "https://www.my-app.com/" + "https://www.my-app.com/", + "https://*.my-app.com/" ] ] }, From 2cb3ea2eaff909ac936611d5653f69e713f41b64 Mon Sep 17 00:00:00 2001 From: Patrik Date: Mon, 2 Oct 2023 12:14:28 +0200 Subject: [PATCH 114/282] feat: allow fuzzy-search on credential identifiers (#3526) This PR adds the ability to search for sub-strings and similar strings in credential identifiers. Note that the **postgres** and **CRDB** migrations create special indexes useful for this feature. To use [online schema changes](https://www.cockroachlabs.com/docs/v23.1/online-schema-changes) with cockroach, we recommend to manually copy the index definition and run it before applying migrations. The migration will then be a no-op. If you run on **mysql** (or **sqlite**), no special index is created. If desired, you can create such an index manually, and it would be highly appreciated if you could contribute its definition. This feature is a preview and will change in behavior! Similarity search is not expected to return deterministic results but are useful for humans. --- .github/workflows/ci.yaml | 6 +- cmd/identities/delete_test.go | 9 +- cmd/identities/get_test.go | 12 +- cmd/identities/helpers_test.go | 46 ++------ cmd/identities/import_test.go | 11 +- cmd/identities/list_test.go | 30 ++--- identity/handler.go | 21 +++- identity/pool.go | 9 +- identity/test/pool.go | 29 ++++- internal/client-go/api_identity.go | 22 ++-- internal/httpclient/api_identity.go | 22 ++-- .../sql/identity/persister_identity.go | 111 ++++++++++++------ ...0_identity_search_index.cockroach.down.sql | 1 + ...000_identity_search_index.cockroach.up.sql | 1 + ...71028000000_identity_search_index.down.sql | 0 ...00_identity_search_index.postgres.down.sql | 1 + ...0000_identity_search_index.postgres.up.sql | 4 + ...0171028000000_identity_search_index.up.sql | 1 + quickstart-postgres.yml | 2 +- spec/api.json | 10 +- spec/swagger.json | 8 +- 21 files changed, 216 insertions(+), 140 deletions(-) create mode 100644 persistence/sql/migrations/sql/20230920171028000000_identity_search_index.cockroach.down.sql create mode 100644 persistence/sql/migrations/sql/20230920171028000000_identity_search_index.cockroach.up.sql create mode 100644 persistence/sql/migrations/sql/20230920171028000000_identity_search_index.down.sql create mode 100644 persistence/sql/migrations/sql/20230920171028000000_identity_search_index.postgres.down.sql create mode 100644 persistence/sql/migrations/sql/20230920171028000000_identity_search_index.postgres.up.sql create mode 100644 persistence/sql/migrations/sql/20230920171028000000_identity_search_index.up.sql diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 94990e8d4827..11b0dddfae49 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -28,7 +28,7 @@ jobs: - sdk-generate services: postgres: - image: postgres:9.6 + image: postgres:11.8 env: POSTGRES_DB: postgres POSTGRES_PASSWORD: test @@ -111,7 +111,7 @@ jobs: - sdk-generate services: postgres: - image: postgres:9.6 + image: postgres:11.8 env: POSTGRES_DB: postgres POSTGRES_PASSWORD: test @@ -222,7 +222,7 @@ jobs: - sdk-generate services: postgres: - image: postgres:9.6 + image: postgres:11.8 env: POSTGRES_DB: postgres POSTGRES_PASSWORD: test diff --git a/cmd/identities/delete_test.go b/cmd/identities/delete_test.go index 70b7282b365d..15a1993c7c94 100644 --- a/cmd/identities/delete_test.go +++ b/cmd/identities/delete_test.go @@ -23,15 +23,14 @@ import ( ) func TestDeleteCmd(t *testing.T) { - c := identities.NewDeleteIdentityCmd() - reg := setup(t, c) + reg, cmd := setup(t, identities.NewDeleteIdentityCmd) t.Run("case=deletes successfully", func(t *testing.T) { // create identity to delete i := identity.NewIdentity(config.DefaultIdentityTraitsSchemaID) require.NoError(t, reg.Persister().CreateIdentity(context.Background(), i)) - stdOut := execNoErr(t, c, i.ID.String()) + stdOut := cmd.ExecNoErr(t, i.ID.String()) // expect ID and no error assert.Equal(t, i.ID.String(), gjson.Parse(stdOut).String()) @@ -44,7 +43,7 @@ func TestDeleteCmd(t *testing.T) { t.Run("case=deletes three identities", func(t *testing.T) { is, ids := makeIdentities(t, reg, 3) - stdOut := execNoErr(t, c, ids...) + stdOut := cmd.ExecNoErr(t, ids...) assert.Equal(t, `["`+strings.Join(ids, "\",\"")+"\"]\n", stdOut) @@ -55,7 +54,7 @@ func TestDeleteCmd(t *testing.T) { }) t.Run("case=fails with unknown ID", func(t *testing.T) { - stdErr := execErr(t, c, x.NewUUID().String()) + stdErr := cmd.ExecExpectedErr(t, x.NewUUID().String()) assert.Contains(t, stdErr, "Unable to locate the resource", stdErr) }) diff --git a/cmd/identities/get_test.go b/cmd/identities/get_test.go index eafe31520828..03a1291d5872 100644 --- a/cmd/identities/get_test.go +++ b/cmd/identities/get_test.go @@ -22,8 +22,7 @@ import ( ) func TestGetCmd(t *testing.T) { - c := identities.NewGetIdentityCmd() - reg := setup(t, c) + reg, cmd := setup(t, identities.NewGetIdentityCmd) t.Run("case=gets a single identity", func(t *testing.T) { i := identity.NewIdentity(config.DefaultIdentityTraitsSchemaID) @@ -31,7 +30,7 @@ func TestGetCmd(t *testing.T) { i.MetadataAdmin = []byte(`"admin"`) require.NoError(t, reg.Persister().CreateIdentity(context.Background(), i)) - stdOut := execNoErr(t, c, i.ID.String()) + stdOut := cmd.ExecNoErr(t, i.ID.String()) ij, err := json.Marshal(identity.WithCredentialsMetadataAndAdminMetadataInJSON(*i)) require.NoError(t, err) @@ -42,7 +41,7 @@ func TestGetCmd(t *testing.T) { t.Run("case=gets three identities", func(t *testing.T) { is, ids := makeIdentities(t, reg, 3) - stdOut := execNoErr(t, c, ids...) + stdOut := cmd.ExecNoErr(t, ids...) isj, err := json.Marshal(is) require.NoError(t, err) @@ -51,7 +50,7 @@ func TestGetCmd(t *testing.T) { }) t.Run("case=fails with unknown ID", func(t *testing.T) { - stdErr := execErr(t, c, x.NewUUID().String()) + stdErr := cmd.ExecExpectedErr(t, x.NewUUID().String()) assert.Contains(t, stdErr, "Unable to locate the resource", stdErr) }) @@ -100,10 +99,9 @@ func TestGetCmd(t *testing.T) { di := i.CopyWithoutCredentials() di.SetCredentials(identity.CredentialsTypeOIDC, applyCredentials("uniqueIdentifier", "accessBar", "refreshBar", "idBar", false)) - require.NoError(t, c.Flags().Set(identities.FlagIncludeCreds, "oidc")) require.NoError(t, reg.Persister().CreateIdentity(context.Background(), i)) - stdOut := execNoErr(t, c, i.ID.String()) + stdOut := cmd.ExecNoErr(t, "--"+identities.FlagIncludeCreds, "oidc", i.ID.String()) ij, err := json.Marshal(identity.WithCredentialsAndAdminMetadataInJSON(*di)) require.NoError(t, err) diff --git a/cmd/identities/helpers_test.go b/cmd/identities/helpers_test.go index b0be50ba4d4c..5997b32c7623 100644 --- a/cmd/identities/helpers_test.go +++ b/cmd/identities/helpers_test.go @@ -4,15 +4,11 @@ package identities_test import ( - "bytes" "context" - "io" "testing" "github.com/ory/x/cmdx" - "github.com/pkg/errors" - "github.com/ory/kratos/identity" "github.com/spf13/cobra" @@ -25,44 +21,20 @@ import ( "github.com/ory/kratos/internal/testhelpers" ) -func setup(t *testing.T, cmd *cobra.Command) driver.Registry { +func setup(t *testing.T, newCmd func() *cobra.Command) (driver.Registry, *cmdx.CommandExecuter) { conf, reg := internal.NewFastRegistryWithMocks(t) _, admin := testhelpers.NewKratosServerWithCSRF(t, reg) testhelpers.SetDefaultIdentitySchema(conf, "file://./stubs/identity.schema.json") // setup command - cliclient.RegisterClientFlags(cmd.Flags()) - cmdx.RegisterFormatFlags(cmd.Flags()) - require.NoError(t, cmd.Flags().Set(cliclient.FlagEndpoint, admin.URL)) - require.NoError(t, cmd.Flags().Set(cmdx.FlagFormat, string(cmdx.FormatJSON))) - return reg -} - -func exec(cmd *cobra.Command, stdIn io.Reader, args ...string) (string, string, error) { - stdOut, stdErr := &bytes.Buffer{}, &bytes.Buffer{} - cmd.SetErr(stdErr) - cmd.SetOut(stdOut) - cmd.SetIn(stdIn) - defer cmd.SetIn(nil) - if args == nil { - args = []string{} + return reg, &cmdx.CommandExecuter{ + New: func() *cobra.Command { + cmd := newCmd() + cliclient.RegisterClientFlags(cmd.Flags()) + cmdx.RegisterFormatFlags(cmd.Flags()) + return cmd + }, + PersistentArgs: []string{"--" + cliclient.FlagEndpoint, admin.URL, "--" + cmdx.FlagFormat, string(cmdx.FormatJSON)}, } - cmd.SetArgs(args) - err := cmd.Execute() - return stdOut.String(), stdErr.String(), err -} - -func execNoErr(t *testing.T, cmd *cobra.Command, args ...string) string { - stdOut, stdErr, err := exec(cmd, nil, args...) - require.NoError(t, err, "stdout: %s\nstderr: %s", stdOut, stdErr) - require.Len(t, stdErr, 0, stdOut) - return stdOut -} - -func execErr(t *testing.T, cmd *cobra.Command, args ...string) string { - stdOut, stdErr, err := exec(cmd, nil, args...) - require.True(t, errors.Is(err, cmdx.ErrNoPrintButFail)) - require.Len(t, stdOut, 0, stdErr) - return stdErr } func makeIdentities(t *testing.T, reg driver.Registry, n int) (is []*identity.Identity, ids []string) { diff --git a/cmd/identities/import_test.go b/cmd/identities/import_test.go index 567cac256957..8db159de9cff 100644 --- a/cmd/identities/import_test.go +++ b/cmd/identities/import_test.go @@ -24,8 +24,7 @@ import ( ) func TestImportCmd(t *testing.T) { - c := identities.NewImportIdentitiesCmd() - reg := setup(t, c) + reg, cmd := setup(t, identities.NewImportIdentitiesCmd) t.Run("case=imports a new identity from file", func(t *testing.T) { i := kratos.CreateIdentityBody{ @@ -40,7 +39,7 @@ func TestImportCmd(t *testing.T) { require.NoError(t, err) require.NoError(t, f.Close()) - stdOut := execNoErr(t, c, f.Name()) + stdOut := cmd.ExecNoErr(t, f.Name()) id, err := uuid.FromString(gjson.Get(stdOut, "id").String()) require.NoError(t, err) @@ -67,7 +66,7 @@ func TestImportCmd(t *testing.T) { require.NoError(t, err) require.NoError(t, f.Close()) - stdOut := execNoErr(t, c, f.Name()) + stdOut := cmd.ExecNoErr(t, f.Name()) id, err := uuid.FromString(gjson.Get(stdOut, "0.id").String()) require.NoError(t, err) @@ -94,7 +93,7 @@ func TestImportCmd(t *testing.T) { ij, err := json.Marshal(i) require.NoError(t, err) - stdOut, stdErr, err := exec(c, bytes.NewBuffer(ij)) + stdOut, stdErr, err := cmd.Exec(bytes.NewBuffer(ij)) require.NoError(t, err, "%s %s", stdOut, stdErr) id, err := uuid.FromString(gjson.Get(stdOut, "0.id").String()) @@ -116,7 +115,7 @@ func TestImportCmd(t *testing.T) { ij, err := json.Marshal(i) require.NoError(t, err) - stdOut, stdErr, err := exec(c, bytes.NewBuffer(ij)) + stdOut, stdErr, err := cmd.Exec(bytes.NewBuffer(ij)) require.NoError(t, err, "%s %s", stdOut, stdErr) id, err := uuid.FromString(gjson.Get(stdOut, "id").String()) diff --git a/cmd/identities/list_test.go b/cmd/identities/list_test.go index e8f0c2769203..d1abb614cbde 100644 --- a/cmd/identities/list_test.go +++ b/cmd/identities/list_test.go @@ -20,8 +20,7 @@ import ( ) func TestListCmd(t *testing.T) { - c := identities.NewListIdentitiesCmd() - reg := setup(t, c) + reg, cmd := setup(t, identities.NewListIdentitiesCmd) var deleteIdentities = func(t *testing.T, is []*identity.Identity) { for _, i := range is { @@ -31,13 +30,11 @@ func TestListCmd(t *testing.T) { t.Run("case=lists all identities with default pagination", func(t *testing.T) { is, ids := makeIdentities(t, reg, 5) - require.NoError(t, c.Flags().Set(cmdx.FlagQuiet, "true")) t.Cleanup(func() { - require.NoError(t, c.Flags().Set(cmdx.FlagQuiet, "false")) deleteIdentities(t, is) }) - stdOut := cmdx.ExecNoErr(t, c) + stdOut := cmd.ExecNoErr(t, "--"+cmdx.FlagQuiet) for _, i := range ids { assert.Contains(t, stdOut, i) @@ -50,25 +47,20 @@ func TestListCmd(t *testing.T) { deleteIdentities(t, is) }) - first := cmdx.ExecNoErr(t, c, "--format", "json-pretty", "--page-size", "2") + first := cmd.ExecNoErr(t, "--format", "json-pretty", "--page-size", "2") nextPageToken := gjson.Get(first, "next_page_token").String() - results := gjson.Get(first, "identities").Array() + actualIDs := gjson.Get(first, "identities.#.id").Array() for nextPageToken != "" { - next := cmdx.ExecNoErr(t, c, "--format", "json-pretty", "--page-size", "2", "--page-token", nextPageToken) - results = append(results, gjson.Get(next, "identities").Array()...) + next := cmd.ExecNoErr(t, "--page-size", "2", "--page-token", nextPageToken) + actualIDs = append(actualIDs, gjson.Get(next, "identities.#.id").Array()...) nextPageToken = gjson.Get(next, "next_page_token").String() } - assert.Len(t, results, len(ids)) - for _, expected := range ids { - var found bool - for _, actual := range results { - if actual.Get("id").String() == expected { - found = true - break - } - } - require.True(t, found, "could not find id: %s", expected) + actualIDsString := make([]string, len(actualIDs)) + for i, id := range actualIDs { + actualIDsString[i] = id.Str } + + assert.ElementsMatch(t, ids, actualIDsString) }) } diff --git a/identity/handler.go b/identity/handler.go index a878a0b0c31f..c7505b0dae6c 100644 --- a/identity/handler.go +++ b/identity/handler.go @@ -133,11 +133,22 @@ type listIdentitiesResponse struct { type listIdentitiesParameters struct { migrationpagination.RequestParameters - // CredentialsIdentifier is the identifier (username, email) of the credentials to look up. + // CredentialsIdentifier is the identifier (username, email) of the credentials to look up using exact match. + // Only one of CredentialsIdentifier and CredentialsIdentifierSimilar can be used. // // required: false // in: query CredentialsIdentifier string `json:"credentials_identifier"` + + // This is an EXPERIMENTAL parameter that WILL CHANGE. Do NOT rely on consistent, deterministic behavior. + // THIS PARAMETER WILL BE REMOVED IN AN UPCOMING RELEASE WITHOUT ANY MIGRATION PATH. + // + // CredentialsIdentifierSimilar is the (partial) identifier (username, email) of the credentials to look up using similarity search. + // Only one of CredentialsIdentifier and CredentialsIdentifierSimilar can be used. + // + // required: false + // in: query + CredentialsIdentifierSimilar string `json:"preview_credentials_identifier_similar"` } // swagger:route GET /admin/identities identity listIdentities @@ -160,7 +171,13 @@ type listIdentitiesParameters struct { func (h *Handler) list(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { page, itemsPerPage := x.ParsePagination(r) - params := ListIdentityParameters{Expand: ExpandDefault, Page: page, PerPage: itemsPerPage, CredentialsIdentifier: r.URL.Query().Get("credentials_identifier")} + params := ListIdentityParameters{ + Expand: ExpandDefault, + Page: page, + PerPage: itemsPerPage, + CredentialsIdentifier: r.URL.Query().Get("credentials_identifier"), + CredentialsIdentifierSimilar: r.URL.Query().Get("preview_credentials_identifier_similar"), + } if params.CredentialsIdentifier != "" { params.Expand = ExpandEverything } diff --git a/identity/pool.go b/identity/pool.go index 1c0cbddb47dc..1cf4888e52ae 100644 --- a/identity/pool.go +++ b/identity/pool.go @@ -13,10 +13,11 @@ import ( type ( ListIdentityParameters struct { - Expand Expandables - CredentialsIdentifier string - Page int - PerPage int + Expand Expandables + CredentialsIdentifier string + CredentialsIdentifierSimilar string + Page int + PerPage int } Pool interface { diff --git a/identity/test/pool.go b/identity/test/pool.go index f695c6dda35d..5adf9fb364b6 100644 --- a/identity/test/pool.go +++ b/identity/test/pool.go @@ -636,7 +636,8 @@ func TestPool(ctx context.Context, conf *config.Config, p persistence.Persister, t.Run("case=list", func(t *testing.T) { is, err := p.ListIdentities(ctx, identity.ListIdentityParameters{Expand: identity.ExpandDefault, Page: 0, PerPage: 25}) require.NoError(t, err) - assert.Len(t, is, len(createdIDs)) + require.NotZero(t, len(is)) + require.Len(t, is, len(createdIDs)) for _, id := range createdIDs { var found bool for _, i := range is { @@ -686,7 +687,7 @@ func TestPool(ctx context.Context, conf *config.Config, p persistence.Persister, Expand: identity.ExpandEverything, }) require.NoError(t, err) - require.True(t, len(actual) > 0) + require.Greater(t, len(actual), 0) for c, ct := range []identity.CredentialsType{ identity.CredentialsTypePassword, @@ -705,6 +706,30 @@ func TestPool(ctx context.Context, conf *config.Config, p persistence.Persister, }) } + t.Run("similarity search", func(t *testing.T) { + actual, err := p.ListIdentities(ctx, identity.ListIdentityParameters{ + CredentialsIdentifierSimilar: "find-identity-by-identifier", + Expand: identity.ExpandCredentials, + }) + require.NoError(t, err) + assert.Len(t, actual, 3) + + outer: + for _, e := range append(expectedIdentities[:2], create) { + for _, a := range actual { + if e.ID == a.ID { + assertx.EqualAsJSONExcept(t, e, a, []string{"credentials.config", "created_at", "updated_at", "state_changed_at"}) + continue outer + } + } + actualCredentials := make([]map[identity.CredentialsType]identity.Credentials, len(actual)) + for k, a := range actual { + actualCredentials[k] = a.Credentials + } + t.Fatalf("expected identity %+v not found in actual result set %+v", e.Credentials, actualCredentials) + } + }) + t.Run("only webauthn and password", func(t *testing.T) { actual, err := p.ListIdentities(ctx, identity.ListIdentityParameters{ CredentialsIdentifier: "find-identity-by-identifier-oidc@ory.sh", diff --git a/internal/client-go/api_identity.go b/internal/client-go/api_identity.go index 864934fef723..93dcc20dddd1 100644 --- a/internal/client-go/api_identity.go +++ b/internal/client-go/api_identity.go @@ -2045,13 +2045,14 @@ func (a *IdentityApiService) GetSessionExecute(r IdentityApiApiGetSessionRequest } type IdentityApiApiListIdentitiesRequest struct { - ctx context.Context - ApiService IdentityApi - perPage *int64 - page *int64 - pageSize *int64 - pageToken *string - credentialsIdentifier *string + ctx context.Context + ApiService IdentityApi + perPage *int64 + page *int64 + pageSize *int64 + pageToken *string + credentialsIdentifier *string + previewCredentialsIdentifierSimilar *string } func (r IdentityApiApiListIdentitiesRequest) PerPage(perPage int64) IdentityApiApiListIdentitiesRequest { @@ -2074,6 +2075,10 @@ func (r IdentityApiApiListIdentitiesRequest) CredentialsIdentifier(credentialsId r.credentialsIdentifier = &credentialsIdentifier return r } +func (r IdentityApiApiListIdentitiesRequest) PreviewCredentialsIdentifierSimilar(previewCredentialsIdentifierSimilar string) IdentityApiApiListIdentitiesRequest { + r.previewCredentialsIdentifierSimilar = &previewCredentialsIdentifierSimilar + return r +} func (r IdentityApiApiListIdentitiesRequest) Execute() ([]Identity, *http.Response, error) { return r.ApiService.ListIdentitiesExecute(r) @@ -2132,6 +2137,9 @@ func (a *IdentityApiService) ListIdentitiesExecute(r IdentityApiApiListIdentitie if r.credentialsIdentifier != nil { localVarQueryParams.Add("credentials_identifier", parameterToString(*r.credentialsIdentifier, "")) } + if r.previewCredentialsIdentifierSimilar != nil { + localVarQueryParams.Add("preview_credentials_identifier_similar", parameterToString(*r.previewCredentialsIdentifierSimilar, "")) + } // to determine the Content-Type header localVarHTTPContentTypes := []string{} diff --git a/internal/httpclient/api_identity.go b/internal/httpclient/api_identity.go index 864934fef723..93dcc20dddd1 100644 --- a/internal/httpclient/api_identity.go +++ b/internal/httpclient/api_identity.go @@ -2045,13 +2045,14 @@ func (a *IdentityApiService) GetSessionExecute(r IdentityApiApiGetSessionRequest } type IdentityApiApiListIdentitiesRequest struct { - ctx context.Context - ApiService IdentityApi - perPage *int64 - page *int64 - pageSize *int64 - pageToken *string - credentialsIdentifier *string + ctx context.Context + ApiService IdentityApi + perPage *int64 + page *int64 + pageSize *int64 + pageToken *string + credentialsIdentifier *string + previewCredentialsIdentifierSimilar *string } func (r IdentityApiApiListIdentitiesRequest) PerPage(perPage int64) IdentityApiApiListIdentitiesRequest { @@ -2074,6 +2075,10 @@ func (r IdentityApiApiListIdentitiesRequest) CredentialsIdentifier(credentialsId r.credentialsIdentifier = &credentialsIdentifier return r } +func (r IdentityApiApiListIdentitiesRequest) PreviewCredentialsIdentifierSimilar(previewCredentialsIdentifierSimilar string) IdentityApiApiListIdentitiesRequest { + r.previewCredentialsIdentifierSimilar = &previewCredentialsIdentifierSimilar + return r +} func (r IdentityApiApiListIdentitiesRequest) Execute() ([]Identity, *http.Response, error) { return r.ApiService.ListIdentitiesExecute(r) @@ -2132,6 +2137,9 @@ func (a *IdentityApiService) ListIdentitiesExecute(r IdentityApiApiListIdentitie if r.credentialsIdentifier != nil { localVarQueryParams.Add("credentials_identifier", parameterToString(*r.credentialsIdentifier, "")) } + if r.previewCredentialsIdentifierSimilar != nil { + localVarQueryParams.Add("preview_credentials_identifier_similar", parameterToString(*r.previewCredentialsIdentifierSimilar, "")) + } // to determine the Content-Type header localVarHTTPContentTypes := []string{} diff --git a/persistence/sql/identity/persister_identity.go b/persistence/sql/identity/persister_identity.go index e2f1d23a882f..99469f365f1b 100644 --- a/persistence/sql/identity/persister_identity.go +++ b/persistence/sql/identity/persister_identity.go @@ -666,56 +666,91 @@ func (p *IdentityPersister) ListIdentities(ctx context.Context, params identity. con := p.GetConnection(ctx) nid := p.NetworkID(ctx) - query := con.Where("identities.nid = ?", nid).Order("identities.id DESC") - // Credentials are not expanded through `EagerPreload` but manually after - // fetching the identities, hence we filter out the relevant expand options. - var expandExceptCredentials sqlxx.Expandables - for _, e := range params.Expand { - if e != identity.ExpandFieldCredentials { - expandExceptCredentials = append(expandExceptCredentials, e) + joins := "" + wheres := "" + args := []any{nid} + identifier := params.CredentialsIdentifier + identifierOperator := "=" + if identifier == "" && params.CredentialsIdentifierSimilar != "" { + identifier = params.CredentialsIdentifierSimilar + identifierOperator = "%" + switch con.Dialect.Name() { + case "postgres", "cockroach": + default: + identifier = "%" + identifier + "%" + identifierOperator = "LIKE" } } - if len(expandExceptCredentials) > 0 { - query = query.EagerPreload(expandExceptCredentials.ToEager()...) - } - if match := params.CredentialsIdentifier; len(match) > 0 { + if len(identifier) > 0 { // When filtering by credentials identifier, we most likely are looking for a username or email. It is therefore // important to normalize the identifier before querying the database. - match = NormalizeIdentifier(identity.CredentialsTypePassword, match) - query = query. - InnerJoin("identity_credentials ic", "ic.identity_id = identities.id"). - InnerJoin("identity_credential_types ict", "ict.id = ic.identity_credential_type_id"). - InnerJoin("identity_credential_identifiers ici", "ici.identity_credential_id = ic.id"). - Where("(ic.nid = ? AND ici.nid = ? AND ici.identifier = ?)", nid, nid, match). - Where("ict.name IN (?)", identity.CredentialsTypeWebAuthn, identity.CredentialsTypePassword). - Limit(1) - } else { - query = query.Paginate(params.Page+1, params.PerPage) - } - - if err := sqlcon.HandleError(query.All(&is)); err != nil { - return nil, err + identifier = NormalizeIdentifier(identity.CredentialsTypePassword, identifier) + + joins = ` +INNER JOIN identity_credentials ic ON ic.identity_id = identities.id +INNER JOIN identity_credential_types ict ON ict.id = ic.identity_credential_type_id +INNER JOIN identity_credential_identifiers ici ON ici.identity_credential_id = ic.id` + wheres = fmt.Sprintf(` +AND (ic.nid = ? AND ici.nid = ? AND ici.identifier %s ?) +AND ict.name IN (?, ?)`, identifierOperator) + args = append(args, nid, nid, identifier, identity.CredentialsTypeWebAuthn, identity.CredentialsTypePassword) + } + + // Follow up: add page token support here, will be easy. + paginator := pop.NewPaginator(params.Page+1, params.PerPage) + + if err := con.RawQuery(fmt.Sprintf(`SELECT DISTINCT identities.* +FROM identities AS identities +%s +WHERE identities.nid = ? +%s +ORDER BY identities.id DESC +LIMIT %d +OFFSET %d`, joins, wheres, paginator.PerPage, paginator.Offset), args...).All(&is); err != nil { + return nil, sqlcon.HandleError(err) } if len(is) == 0 { return is, nil } - if params.Expand.Has(identity.ExpandFieldCredentials) { - var ids []interface{} - for k := range is { - ids = append(ids, is[k].ID) - } - creds, err := QueryForCredentials(con, - Where{"identity_credentials.nid = ?", []interface{}{nid}}, - Where{"identity_credentials.identity_id IN (?)", ids}) - if err != nil { - return nil, err - } - for k := range is { - is[k].Credentials = creds[is[k].ID] + identitiesByID := make(map[uuid.UUID]*identity.Identity, len(is)) + identityIDs := make([]any, len(is)) + for k := range is { + identitiesByID[is[k].ID] = &is[k] + identityIDs[k] = is[k].ID + } + + for _, e := range params.Expand { + switch e { + case identity.ExpandFieldCredentials: + creds, err := QueryForCredentials(con, + Where{"identity_credentials.nid = ?", []any{nid}}, + Where{"identity_credentials.identity_id IN (?)", identityIDs}) + if err != nil { + return nil, err + } + for k := range is { + is[k].Credentials = creds[is[k].ID] + } + case identity.ExpandFieldVerifiableAddresses: + addrs := make([]identity.VerifiableAddress, 0) + if err := con.Where("nid = ?", nid).Where("identity_id IN (?)", identityIDs).Order("id").All(&addrs); err != nil { + return nil, sqlcon.HandleError(err) + } + for _, addr := range addrs { + identitiesByID[addr.IdentityID].VerifiableAddresses = append(identitiesByID[addr.IdentityID].VerifiableAddresses, addr) + } + case identity.ExpandFieldRecoveryAddresses: + addrs := make([]identity.RecoveryAddress, 0) + if err := con.Where("nid = ?", nid).Where("identity_id IN (?)", identityIDs).Order("id").All(&addrs); err != nil { + return nil, sqlcon.HandleError(err) + } + for _, addr := range addrs { + identitiesByID[addr.IdentityID].RecoveryAddresses = append(identitiesByID[addr.IdentityID].RecoveryAddresses, addr) + } } } diff --git a/persistence/sql/migrations/sql/20230920171028000000_identity_search_index.cockroach.down.sql b/persistence/sql/migrations/sql/20230920171028000000_identity_search_index.cockroach.down.sql new file mode 100644 index 000000000000..d1c8cdf26841 --- /dev/null +++ b/persistence/sql/migrations/sql/20230920171028000000_identity_search_index.cockroach.down.sql @@ -0,0 +1 @@ +DROP INDEX IF EXISTS identity_credential_identifiers_nid_identifier_gin; diff --git a/persistence/sql/migrations/sql/20230920171028000000_identity_search_index.cockroach.up.sql b/persistence/sql/migrations/sql/20230920171028000000_identity_search_index.cockroach.up.sql new file mode 100644 index 000000000000..f692e9943649 --- /dev/null +++ b/persistence/sql/migrations/sql/20230920171028000000_identity_search_index.cockroach.up.sql @@ -0,0 +1 @@ +CREATE INDEX IF NOT EXISTS identity_credential_identifiers_nid_identifier_gin ON identity_credential_identifiers USING GIN (nid, identifier gin_trgm_ops); diff --git a/persistence/sql/migrations/sql/20230920171028000000_identity_search_index.down.sql b/persistence/sql/migrations/sql/20230920171028000000_identity_search_index.down.sql new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/persistence/sql/migrations/sql/20230920171028000000_identity_search_index.postgres.down.sql b/persistence/sql/migrations/sql/20230920171028000000_identity_search_index.postgres.down.sql new file mode 100644 index 000000000000..159cb60805d1 --- /dev/null +++ b/persistence/sql/migrations/sql/20230920171028000000_identity_search_index.postgres.down.sql @@ -0,0 +1 @@ +DROP INDEX identity_credential_identifiers_nid_identifier_gin; diff --git a/persistence/sql/migrations/sql/20230920171028000000_identity_search_index.postgres.up.sql b/persistence/sql/migrations/sql/20230920171028000000_identity_search_index.postgres.up.sql new file mode 100644 index 000000000000..70d519fb44bc --- /dev/null +++ b/persistence/sql/migrations/sql/20230920171028000000_identity_search_index.postgres.up.sql @@ -0,0 +1,4 @@ +CREATE EXTENSION IF NOT EXISTS pg_trgm; +CREATE EXTENSION IF NOT EXISTS btree_gin; + +CREATE INDEX identity_credential_identifiers_nid_identifier_gin ON identity_credential_identifiers USING GIN (nid, identifier gin_trgm_ops); diff --git a/persistence/sql/migrations/sql/20230920171028000000_identity_search_index.up.sql b/persistence/sql/migrations/sql/20230920171028000000_identity_search_index.up.sql new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/persistence/sql/migrations/sql/20230920171028000000_identity_search_index.up.sql @@ -0,0 +1 @@ + diff --git a/quickstart-postgres.yml b/quickstart-postgres.yml index b97e3f499cfb..8c0dee47a2f3 100644 --- a/quickstart-postgres.yml +++ b/quickstart-postgres.yml @@ -10,7 +10,7 @@ services: - DSN=postgres://kratos:secret@postgresd:5432/kratos?sslmode=disable&max_conns=20&max_idle_conns=4 postgresd: - image: postgres:9.6 + image: postgres:11.8 ports: - "5432:5432" environment: diff --git a/spec/api.json b/spec/api.json index c0629d544021..f3bd1fa14d28 100644 --- a/spec/api.json +++ b/spec/api.json @@ -3459,12 +3459,20 @@ } }, { - "description": "CredentialsIdentifier is the identifier (username, email) of the credentials to look up.", + "description": "CredentialsIdentifier is the identifier (username, email) of the credentials to look up using exact match.\nOnly one of CredentialsIdentifier and CredentialsIdentifierSimilar can be used.", "in": "query", "name": "credentials_identifier", "schema": { "type": "string" } + }, + { + "description": "This is an EXPERIMENTAL parameter that WILL CHANGE. Do NOT rely on consistent, deterministic behavior.\nTHIS PARAMETER MIGHT BE REMOVED IN AN UPCOMING RELEASE WITHOUT ANY MIGRATION PATH.\n\nCredentialsIdentifierSimilar is the (partial) identifier (username, email) of the credentials to look up using similarity search.\nOnly one of CredentialsIdentifier and CredentialsIdentifierSimilar can be used.", + "in": "query", + "name": "preview_credentials_identifier_similar", + "schema": { + "type": "string" + } } ], "responses": { diff --git a/spec/swagger.json b/spec/swagger.json index 78549f804e7d..c5f8e624ae1d 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -222,9 +222,15 @@ }, { "type": "string", - "description": "CredentialsIdentifier is the identifier (username, email) of the credentials to look up.", + "description": "CredentialsIdentifier is the identifier (username, email) of the credentials to look up using exact match.\nOnly one of CredentialsIdentifier and CredentialsIdentifierSimilar can be used.", "name": "credentials_identifier", "in": "query" + }, + { + "type": "string", + "description": "This is an EXPERIMENTAL parameter that WILL CHANGE. Do NOT rely on consistent, deterministic behavior.\nTHIS PARAMETER MIGHT BE REMOVED IN AN UPCOMING RELEASE WITHOUT ANY MIGRATION PATH.\n\nCredentialsIdentifierSimilar is the (partial) identifier (username, email) of the credentials to look up using similarity search.\nOnly one of CredentialsIdentifier and CredentialsIdentifierSimilar can be used.", + "name": "preview_credentials_identifier_similar", + "in": "query" } ], "responses": { From 28826f5df159f64412554da3dbb2612415f1293e Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Mon, 2 Oct 2023 10:17:49 +0000 Subject: [PATCH 115/282] autogen(openapi): regenerate swagger spec and internal client [skip ci] --- spec/api.json | 2 +- spec/swagger.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/api.json b/spec/api.json index f3bd1fa14d28..92fce7914e85 100644 --- a/spec/api.json +++ b/spec/api.json @@ -3467,7 +3467,7 @@ } }, { - "description": "This is an EXPERIMENTAL parameter that WILL CHANGE. Do NOT rely on consistent, deterministic behavior.\nTHIS PARAMETER MIGHT BE REMOVED IN AN UPCOMING RELEASE WITHOUT ANY MIGRATION PATH.\n\nCredentialsIdentifierSimilar is the (partial) identifier (username, email) of the credentials to look up using similarity search.\nOnly one of CredentialsIdentifier and CredentialsIdentifierSimilar can be used.", + "description": "This is an EXPERIMENTAL parameter that WILL CHANGE. Do NOT rely on consistent, deterministic behavior.\nTHIS PARAMETER WILL BE REMOVED IN AN UPCOMING RELEASE WITHOUT ANY MIGRATION PATH.\n\nCredentialsIdentifierSimilar is the (partial) identifier (username, email) of the credentials to look up using similarity search.\nOnly one of CredentialsIdentifier and CredentialsIdentifierSimilar can be used.", "in": "query", "name": "preview_credentials_identifier_similar", "schema": { diff --git a/spec/swagger.json b/spec/swagger.json index c5f8e624ae1d..a2e5e859f712 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -228,7 +228,7 @@ }, { "type": "string", - "description": "This is an EXPERIMENTAL parameter that WILL CHANGE. Do NOT rely on consistent, deterministic behavior.\nTHIS PARAMETER MIGHT BE REMOVED IN AN UPCOMING RELEASE WITHOUT ANY MIGRATION PATH.\n\nCredentialsIdentifierSimilar is the (partial) identifier (username, email) of the credentials to look up using similarity search.\nOnly one of CredentialsIdentifier and CredentialsIdentifierSimilar can be used.", + "description": "This is an EXPERIMENTAL parameter that WILL CHANGE. Do NOT rely on consistent, deterministic behavior.\nTHIS PARAMETER WILL BE REMOVED IN AN UPCOMING RELEASE WITHOUT ANY MIGRATION PATH.\n\nCredentialsIdentifierSimilar is the (partial) identifier (username, email) of the credentials to look up using similarity search.\nOnly one of CredentialsIdentifier and CredentialsIdentifierSimilar can be used.", "name": "preview_credentials_identifier_similar", "in": "query" } From 046aa9bd27726f2ba453ad8c6d063294f94f92a8 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Mon, 2 Oct 2023 11:34:29 +0000 Subject: [PATCH 116/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cb3e3eac6e6..42b008153523 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-09-27)](#2023-09-27) +- [ (2023-10-02)](#2023-10-02) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -313,7 +313,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-09-27) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-10-02) ## Breaking Changes @@ -476,6 +476,10 @@ https://github.com/ory/kratos/pull/3480 ### Documentation +- Add example for `allowed_return_urls` to include wildcard url + ([#3533](https://github.com/ory/kratos/issues/3533)) + ([39b0c3c](https://github.com/ory/kratos/commit/39b0c3c03df0aec254b32c840730452d4856872b)), + closes [#1528](https://github.com/ory/kratos/issues/1528) - Remove experimental warnings ([#3406](https://github.com/ory/kratos/issues/3406)) ([d4d26e6](https://github.com/ory/kratos/commit/d4d26e6e1510c8e09346e95251f420f95ec54998)): @@ -565,6 +569,26 @@ https://github.com/ory/kratos/pull/3480 - Allow extra migrations in NewPersister ([96c1ff7](https://github.com/ory/kratos/commit/96c1ff7747ea38e23a3892f74b75ee555ed49c88)) +- Allow fuzzy-search on credential identifiers + ([#3526](https://github.com/ory/kratos/issues/3526)) + ([2cb3ea2](https://github.com/ory/kratos/commit/2cb3ea2eaff909ac936611d5653f69e713f41b64)): + + This PR adds the ability to search for sub-strings and similar strings in + credential identifiers. + + Note that the **postgres** and **CRDB** migrations create special indexes + useful for this feature. To use + [online schema changes](https://www.cockroachlabs.com/docs/v23.1/online-schema-changes) + with cockroach, we recommend to manually copy the index definition and run it + before applying migrations. The migration will then be a no-op. + + If you run on **mysql** (or **sqlite**), no special index is created. If + desired, you can create such an index manually, and it would be highly + appreciated if you could contribute its definition. + + This feature is a preview and will change in behavior! Similarity search is + not expected to return deterministic results but are useful for humans. + - Allow marking OIDC provider-verified addresses as verified during registration ([#3448](https://github.com/ory/kratos/issues/3448)) ([e7b33a1](https://github.com/ory/kratos/commit/e7b33a168bf0c0fe0492901abd3df8b6d6a08a68)), From 9b0fee30f980d860fd548e7589fa6a06e593537a Mon Sep 17 00:00:00 2001 From: Alano Terblanche <18033717+Benehiko@users.noreply.github.com> Date: Mon, 2 Oct 2023 14:57:22 +0200 Subject: [PATCH 117/282] feat: one-time code native flows (#3516) --- selfservice/strategy/code/strategy.go | 23 +- .../strategy/code/strategy_login_test.go | 179 +++++++----- .../code/strategy_registration_test.go | 216 +++++++++------ .../profiles/code/login/error.spec.ts | 126 ++++++--- .../profiles/code/login/success.spec.ts | 148 +++++++--- .../profiles/code/registration/error.spec.ts | 150 +++++++--- .../code/registration/success.spec.ts | 259 ++++++++++++++---- test/e2e/cypress/support/commands.ts | 29 +- test/e2e/cypress/support/index.d.ts | 3 +- test/e2e/run.sh | 24 +- 10 files changed, 814 insertions(+), 343 deletions(-) diff --git a/selfservice/strategy/code/strategy.go b/selfservice/strategy/code/strategy.go index 6044db79de0f..678a2bb5d6a2 100644 --- a/selfservice/strategy/code/strategy.go +++ b/selfservice/strategy/code/strategy.go @@ -150,10 +150,7 @@ func (s *Strategy) PopulateMethod(r *http.Request, f flow.Flow) error { } else if f.GetFlowName() == flow.LoginFlow { // we use the identifier label here since we don't know what // type of field the identifier is - nodes.Upsert( - node.NewInputField("identifier", nil, node.DefaultGroup, node.InputAttributeTypeText, node.WithRequiredInputAttribute). - WithMetaLabel(text.NewInfoNodeLabelID()), - ) + nodes.Upsert(node.NewInputField("identifier", "", node.DefaultGroup, node.InputAttributeTypeText, node.WithRequiredInputAttribute).WithMetaLabel(text.NewInfoNodeLabelID())) } else if f.GetFlowName() == flow.RegistrationFlow { ds, err := s.deps.Config().DefaultIdentityTraitsSchemaURL(r.Context()) if err != nil { @@ -221,6 +218,15 @@ func (s *Strategy) PopulateMethod(r *http.Request, f flow.Flow) error { // so we can retry the code flow with the same data for _, n := range f.GetUI().Nodes { if n.Group == node.DefaultGroup { + // we don't need the user to change the values here + // for better UX let's make them disabled + // when there are errors we won't hide the fields + if len(n.Messages) == 0 { + if input, ok := n.Attributes.(*node.InputAttributes); ok { + input.Type = "hidden" + n.Attributes = input + } + } freshNodes = append(freshNodes, n) } } @@ -241,6 +247,15 @@ func (s *Strategy) PopulateMethod(r *http.Request, f flow.Flow) error { } if n.Group == node.DefaultGroup { + // we don't need the user to change the values here + // for better UX let's make them disabled + // when there are errors we won't hide the fields + if len(n.Messages) == 0 { + if input, ok := n.Attributes.(*node.InputAttributes); ok { + input.Type = "hidden" + n.Attributes = input + } + } freshNodes = append(freshNodes, n) } } diff --git a/selfservice/strategy/code/strategy_login_test.go b/selfservice/strategy/code/strategy_login_test.go index fac277d0d68a..f327a36e961a 100644 --- a/selfservice/strategy/code/strategy_login_test.go +++ b/selfservice/strategy/code/strategy_login_test.go @@ -21,6 +21,7 @@ import ( "github.com/ory/kratos/driver/config" "github.com/ory/kratos/identity" "github.com/ory/kratos/internal" + oryClient "github.com/ory/kratos/internal/httpclient" "github.com/ory/kratos/internal/testhelpers" "github.com/ory/kratos/session" "github.com/ory/x/sqlxx" @@ -82,23 +83,47 @@ func TestLoginCodeStrategy(t *testing.T) { testServer *httptest.Server } - createLoginFlow := func(ctx context.Context, t *testing.T, public *httptest.Server, isSPA bool, moreIdentifiers ...string) *state { + type ApiType string + + const ( + ApiTypeBrowser ApiType = "browser" + ApiTypeSPA ApiType = "spa" + ApiTypeNative ApiType = "api" + ) + + createLoginFlow := func(ctx context.Context, t *testing.T, public *httptest.Server, apiType ApiType, moreIdentifiers ...string) *state { t.Helper() identity := createIdentity(ctx, t, moreIdentifiers...) - client := testhelpers.NewClientWithCookies(t) + var client *http.Client + if apiType == ApiTypeNative { + client = &http.Client{} + } else { + client = testhelpers.NewClientWithCookies(t) + } + client.Transport = testhelpers.NewTransportWithLogger(http.DefaultTransport, t).RoundTripper - clientInit := testhelpers.InitializeLoginFlowViaBrowser(t, client, public, false, isSPA, false, false) + + var clientInit *oryClient.LoginFlow + if apiType == ApiTypeNative { + clientInit = testhelpers.InitializeLoginFlowViaAPI(t, client, public, false) + } else { + clientInit = testhelpers.InitializeLoginFlowViaBrowser(t, client, public, false, apiType == ApiTypeSPA, false, false) + } body, err := json.Marshal(clientInit) require.NoError(t, err) csrfToken := gjson.GetBytes(body, "ui.nodes.#(attributes.name==csrf_token).attributes.value").String() - require.NotEmpty(t, csrfToken) + if apiType == ApiTypeNative { + require.Emptyf(t, csrfToken, "csrf_token should be empty in native flows, but was found in: %s", body) + } else { + require.NotEmptyf(t, csrfToken, "could not find csrf_token in: %s", body) + } loginEmail := gjson.Get(identity.Traits.String(), "email").String() - require.NotEmpty(t, loginEmail) + require.NotEmptyf(t, loginEmail, "could not find the email trait inside the identity: %s", identity.Traits.String()) return &state{ flowID: clientInit.GetId(), @@ -111,7 +136,7 @@ func TestLoginCodeStrategy(t *testing.T) { type onSubmitAssertion func(t *testing.T, s *state, body string, res *http.Response) - submitLogin := func(ctx context.Context, t *testing.T, s *state, isSPA bool, vals func(v *url.Values), mustHaveSession bool, submitAssertion onSubmitAssertion) *state { + submitLogin := func(ctx context.Context, t *testing.T, s *state, apiType ApiType, vals func(v *url.Values), mustHaveSession bool, submitAssertion onSubmitAssertion) *state { t.Helper() lf, resp, err := testhelpers.NewSDKCustomClient(s.testServer, s.client).FrontendApi.GetLoginFlow(ctx).Id(s.flowID).Execute() @@ -126,7 +151,7 @@ func TestLoginCodeStrategy(t *testing.T) { values.Set("method", "code") vals(&values) - body, resp := testhelpers.LoginMakeRequest(t, false, isSPA, lf, s.client, testhelpers.EncodeFormAsJSON(t, false, values)) + body, resp := testhelpers.LoginMakeRequest(t, apiType == ApiTypeNative, apiType == ApiTypeSPA, lf, s.client, testhelpers.EncodeFormAsJSON(t, apiType == ApiTypeNative, values)) if submitAssertion != nil { submitAssertion(t, s, body, resp) @@ -134,16 +159,23 @@ func TestLoginCodeStrategy(t *testing.T) { } if mustHaveSession { - resp, err = s.client.Get(s.testServer.URL + session.RouteWhoami) + req, err := http.NewRequest("GET", s.testServer.URL+session.RouteWhoami, nil) + require.NoError(t, err) + + if apiType == ApiTypeNative { + req.Header.Set("Authorization", "Bearer "+gjson.Get(body, "session_token").String()) + } + + resp, err = s.client.Do(req) require.NoError(t, err) require.EqualValues(t, http.StatusOK, resp.StatusCode) } else { // SPAs need to be informed that the login has not yet completed using status 400. // Browser clients will redirect back to the login URL. - if isSPA { - require.EqualValues(t, http.StatusBadRequest, resp.StatusCode) - } else { + if apiType == ApiTypeBrowser { require.EqualValues(t, http.StatusOK, resp.StatusCode) + } else { + require.EqualValues(t, http.StatusBadRequest, resp.StatusCode) } } @@ -151,25 +183,29 @@ func TestLoginCodeStrategy(t *testing.T) { } for _, tc := range []struct { - d string - isSPA bool + d string + apiType ApiType }{ { - d: "SPA client", - isSPA: true, + d: "SPA client", + apiType: ApiTypeSPA, }, { - d: "Browser client", - isSPA: false, + d: "Browser client", + apiType: ApiTypeBrowser, + }, + { + d: "Native client", + apiType: ApiTypeNative, }, } { t.Run("test="+tc.d, func(t *testing.T) { t.Run("case=email identifier should be case insensitive", func(t *testing.T) { // create login flow - s := createLoginFlow(ctx, t, public, tc.isSPA) + s := createLoginFlow(ctx, t, public, tc.apiType) // submit email - s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { v.Set("identifier", stringsx.ToUpperInitial(s.identityEmail)) }, false, nil) @@ -180,17 +216,17 @@ func TestLoginCodeStrategy(t *testing.T) { assert.NotEmpty(t, loginCode) // 3. Submit OTP - submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { v.Set("code", loginCode) }, true, nil) }) t.Run("case=should be able to log in with code", func(t *testing.T) { // create login flow - s := createLoginFlow(ctx, t, public, tc.isSPA) + s := createLoginFlow(ctx, t, public, tc.apiType) // submit email - s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { v.Set("identifier", s.identityEmail) }, false, nil) @@ -201,17 +237,17 @@ func TestLoginCodeStrategy(t *testing.T) { assert.NotEmpty(t, loginCode) // 3. Submit OTP - submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { v.Set("code", loginCode) }, true, nil) }) t.Run("case=should not be able to change submitted id on code submit", func(t *testing.T) { // create login flow - s := createLoginFlow(ctx, t, public, tc.isSPA) + s := createLoginFlow(ctx, t, public, tc.apiType) // submit email - s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { v.Set("identifier", s.identityEmail) }, false, nil) @@ -222,38 +258,34 @@ func TestLoginCodeStrategy(t *testing.T) { assert.NotEmpty(t, loginCode) // 3. Submit OTP - s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { v.Set("identifier", "not-"+s.identityEmail) v.Set("code", loginCode) }, false, func(t *testing.T, s *state, body string, resp *http.Response) { - if tc.isSPA { - require.EqualValues(t, http.StatusBadRequest, resp.StatusCode) - assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "account does not exist or has not setup sign in with code") - } else { + if tc.apiType == ApiTypeBrowser { require.EqualValues(t, http.StatusOK, resp.StatusCode) require.EqualValues(t, conf.SelfServiceFlowLoginUI(ctx).Path, resp.Request.URL.Path) - lf, resp, err := testhelpers.NewSDKCustomClient(public, s.client).FrontendApi.GetLoginFlow(ctx).Id(s.flowID).Execute() require.NoError(t, err) require.EqualValues(t, http.StatusOK, resp.StatusCode) body, err := json.Marshal(lf) require.NoError(t, err) assert.Contains(t, gjson.GetBytes(body, "ui.messages.0.text").String(), "account does not exist or has not setup sign in with code") + } else { + require.EqualValues(t, http.StatusBadRequest, resp.StatusCode) + assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "account does not exist or has not setup sign in with code") } }) }) t.Run("case=should not be able to proceed to code entry when the account is unknown", func(t *testing.T) { - s := createLoginFlow(ctx, t, public, tc.isSPA) + s := createLoginFlow(ctx, t, public, tc.apiType) // submit email - s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { v.Set("identifier", testhelpers.RandomEmail()) }, false, func(t *testing.T, s *state, body string, resp *http.Response) { - if tc.isSPA { - require.EqualValues(t, http.StatusBadRequest, resp.StatusCode) - assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "account does not exist or has not setup sign in with code") - } else { + if tc.apiType == ApiTypeBrowser { require.EqualValues(t, http.StatusOK, resp.StatusCode) require.EqualValues(t, conf.SelfServiceFlowLoginUI(ctx).Path, resp.Request.URL.Path) @@ -263,15 +295,18 @@ func TestLoginCodeStrategy(t *testing.T) { body, err := json.Marshal(lf) require.NoError(t, err) assert.Contains(t, gjson.GetBytes(body, "ui.messages.0.text").String(), "account does not exist or has not setup sign in with code") + } else { + require.EqualValues(t, http.StatusBadRequest, resp.StatusCode) + assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "account does not exist or has not setup sign in with code") } }) }) t.Run("case=should not be able to use valid code after 5 attempts", func(t *testing.T) { - s := createLoginFlow(ctx, t, public, tc.isSPA) + s := createLoginFlow(ctx, t, public, tc.apiType) // submit email - s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { v.Set("identifier", s.identityEmail) }, false, nil) @@ -282,30 +317,30 @@ func TestLoginCodeStrategy(t *testing.T) { for i := 0; i < 5; i++ { // 3. Submit OTP - s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { v.Set("code", "111111") v.Set("identifier", s.identityEmail) }, false, func(t *testing.T, s *state, body string, resp *http.Response) { - if tc.isSPA { - require.EqualValues(t, http.StatusBadRequest, resp.StatusCode) - } else { + if tc.apiType == ApiTypeBrowser { // in browser flows we redirect back to the login ui require.Equal(t, http.StatusOK, resp.StatusCode, "%s", body) + } else { + require.EqualValues(t, http.StatusBadRequest, resp.StatusCode) } assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "The login code is invalid or has already been used") }) } // 3. Submit OTP - s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { v.Set("code", loginCode) v.Set("identifier", s.identityEmail) }, false, func(t *testing.T, s *state, body string, resp *http.Response) { - if tc.isSPA { - require.EqualValues(t, http.StatusBadRequest, resp.StatusCode) - } else { + if tc.apiType == ApiTypeBrowser { // in browser flows we redirect back to the login ui require.Equal(t, http.StatusOK, resp.StatusCode, "%s", body) + } else { + require.EqualValues(t, http.StatusBadRequest, resp.StatusCode) } assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "The request was submitted too often.") }) @@ -320,10 +355,10 @@ func TestLoginCodeStrategy(t *testing.T) { conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.config.lifespan", "1h") }) - s := createLoginFlow(ctx, t, public, tc.isSPA) + s := createLoginFlow(ctx, t, public, tc.apiType) // submit email - s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { v.Set("identifier", s.identityEmail) }, false, nil) @@ -332,14 +367,11 @@ func TestLoginCodeStrategy(t *testing.T) { loginCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) assert.NotEmpty(t, loginCode) - submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { v.Set("code", loginCode) v.Set("identifier", s.identityEmail) }, false, func(t *testing.T, s *state, body string, resp *http.Response) { - if tc.isSPA { - require.EqualValues(t, http.StatusGone, resp.StatusCode) - require.Contains(t, gjson.Get(body, "error.reason").String(), "self-service flow expired 0.00 minutes ago") - } else { + if tc.apiType == ApiTypeBrowser { // with browser clients we redirect back to the UI with a new flow id as a query parameter require.Equal(t, http.StatusOK, resp.StatusCode) require.Equal(t, conf.SelfServiceFlowLoginUI(ctx).Path, resp.Request.URL.Path) @@ -350,6 +382,9 @@ func TestLoginCodeStrategy(t *testing.T) { body, err := json.Marshal(lf) require.NoError(t, err) assert.Contains(t, gjson.GetBytes(body, "ui.messages.0.text").String(), "flow expired 0.00 minutes ago") + } else { + require.EqualValues(t, http.StatusGone, resp.StatusCode) + require.Contains(t, gjson.Get(body, "error.reason").String(), "self-service flow expired 0.00 minutes ago") } }) }) @@ -357,9 +392,9 @@ func TestLoginCodeStrategy(t *testing.T) { t.Run("case=resend code should invalidate previous code", func(t *testing.T) { ctx := context.Background() - s := createLoginFlow(ctx, t, public, tc.isSPA) + s := createLoginFlow(ctx, t, public, tc.apiType) - s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { v.Set("identifier", s.identityEmail) }, false, nil) @@ -369,7 +404,7 @@ func TestLoginCodeStrategy(t *testing.T) { assert.NotEmpty(t, loginCode) // resend code - s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { v.Set("resend", "code") v.Set("identifier", s.identityEmail) }, false, nil) @@ -380,26 +415,26 @@ func TestLoginCodeStrategy(t *testing.T) { assert.NotEmpty(t, loginCode2) assert.NotEqual(t, loginCode, loginCode2) - s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { v.Set("code", loginCode) v.Set("identifier", s.identityEmail) }, false, func(t *testing.T, s *state, body string, res *http.Response) { - if tc.isSPA { - require.EqualValues(t, http.StatusBadRequest, res.StatusCode) - } else { + if tc.apiType == ApiTypeBrowser { require.EqualValues(t, http.StatusOK, res.StatusCode) + } else { + require.EqualValues(t, http.StatusBadRequest, res.StatusCode) } require.Contains(t, gjson.Get(body, "ui.messages").String(), "The login code is invalid or has already been used. Please try again") }) - s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { v.Set("code", loginCode2) v.Set("identifier", s.identityEmail) }, true, nil) }) t.Run("case=on login with un-verified address, should verify it", func(t *testing.T) { - s := createLoginFlow(ctx, t, public, tc.isSPA, testhelpers.RandomEmail()) + s := createLoginFlow(ctx, t, public, tc.apiType, testhelpers.RandomEmail()) // we need to fetch only the first email loginEmail := gjson.Get(s.identity.Traits.String(), "email_1").String() @@ -420,7 +455,7 @@ func TestLoginCodeStrategy(t *testing.T) { require.False(t, va.Verified) // submit email - s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { v.Set("identifier", s.identityEmail) }, false, nil) @@ -431,7 +466,7 @@ func TestLoginCodeStrategy(t *testing.T) { require.NotEmpty(t, loginCode) // Submit OTP - s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { v.Set("code", loginCode) v.Set("identifier", s.identityEmail) }, true, nil) @@ -453,6 +488,10 @@ func TestLoginCodeStrategy(t *testing.T) { }) t.Run("case=should not populate on 2FA request", func(t *testing.T) { + if tc.apiType == ApiTypeNative { + t.Skip("skipping test since it is not applicable to native clients") + } + ctx := context.Background() // enable webauthn 2FA method @@ -464,10 +503,10 @@ func TestLoginCodeStrategy(t *testing.T) { conf.MustSet(ctx, config.ViperKeySessionWhoAmIAAL, "aal1") }) - s := createLoginFlow(ctx, t, public, tc.isSPA) + s := createLoginFlow(ctx, t, public, tc.apiType) // submit email - s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { v.Set("identifier", s.identityEmail) }, false, nil) @@ -478,17 +517,17 @@ func TestLoginCodeStrategy(t *testing.T) { assert.NotEmpty(t, loginCode) // 3. Submit OTP - s = submitLogin(ctx, t, s, tc.isSPA, func(v *url.Values) { + s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { v.Set("code", loginCode) }, false, func(t *testing.T, s *state, body string, res *http.Response) { - if tc.isSPA { + if tc.apiType == ApiTypeSPA { require.EqualValues(t, http.StatusOK, res.StatusCode) } else { require.EqualValues(t, http.StatusOK, res.StatusCode) } }) - clientInit := testhelpers.InitializeLoginFlowViaBrowser(t, s.client, public, false, tc.isSPA, false, false, testhelpers.InitFlowWithAAL("aal2")) + clientInit := testhelpers.InitializeLoginFlowViaBrowser(t, s.client, public, false, tc.apiType == ApiTypeSPA, false, false, testhelpers.InitFlowWithAAL("aal2")) body, err := json.Marshal(clientInit) require.NoError(t, err) require.Len(t, gjson.GetBytes(body, "ui.nodes.#(group==code)").Array(), 0, "should not populate code field on 2fa request") diff --git a/selfservice/strategy/code/strategy_registration_test.go b/selfservice/strategy/code/strategy_registration_test.go index 2e4fe674fff0..e591e627f5ef 100644 --- a/selfservice/strategy/code/strategy_registration_test.go +++ b/selfservice/strategy/code/strategy_registration_test.go @@ -26,6 +26,7 @@ import ( "github.com/ory/kratos/driver/config" "github.com/ory/kratos/identity" "github.com/ory/kratos/internal" + oryClient "github.com/ory/kratos/internal/httpclient" "github.com/ory/kratos/internal/testhelpers" "github.com/ory/kratos/selfservice/flow/registration" "github.com/ory/kratos/selfservice/strategy/code" @@ -83,6 +84,14 @@ func TestRegistrationCodeStrategyDisabled(t *testing.T) { } func TestRegistrationCodeStrategy(t *testing.T) { + type ApiType string + + const ( + ApiTypeBrowser ApiType = "browser" + ApiTypeSPA ApiType = "spa" + ApiTypeNative ApiType = "api" + ) + setup := func(ctx context.Context, t *testing.T) (*config.Config, *driver.RegistryDefault, *httptest.Server) { conf, reg := internal.NewFastRegistryWithMocks(t) testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/code.identity.schema.json") @@ -103,18 +112,35 @@ func TestRegistrationCodeStrategy(t *testing.T) { return conf, reg, public } - createRegistrationFlow := func(ctx context.Context, t *testing.T, public *httptest.Server, isSPA bool) *state { + createRegistrationFlow := func(ctx context.Context, t *testing.T, public *httptest.Server, apiType ApiType) *state { t.Helper() - client := testhelpers.NewClientWithCookies(t) + var client *http.Client + + if apiType == ApiTypeNative { + client = &http.Client{} + } else { + client = testhelpers.NewClientWithCookies(t) + } + client.Transport = testhelpers.NewTransportWithLogger(http.DefaultTransport, t).RoundTripper - clientInit := testhelpers.InitializeRegistrationFlowViaBrowser(t, client, public, isSPA, false, false) + + var clientInit *oryClient.RegistrationFlow + if apiType == ApiTypeNative { + clientInit = testhelpers.InitializeRegistrationFlowViaAPI(t, client, public) + } else { + clientInit = testhelpers.InitializeRegistrationFlowViaBrowser(t, client, public, apiType == ApiTypeSPA, false, false) + } body, err := json.Marshal(clientInit) require.NoError(t, err) csrfToken := gjson.GetBytes(body, "ui.nodes.#(attributes.name==csrf_token).attributes.value").String() - require.NotEmpty(t, csrfToken) + if apiType == ApiTypeNative { + require.Emptyf(t, csrfToken, "expected an empty value for csrf_token on native api flows but got %s", body) + } else { + require.NotEmpty(t, csrfToken) + } require.Truef(t, gjson.GetBytes(body, "ui.nodes.#(attributes.name==traits.email)").Exists(), "%s", body) require.Truef(t, gjson.GetBytes(body, "ui.nodes.#(attributes.value==code)").Exists(), "%s", body) @@ -128,7 +154,7 @@ func TestRegistrationCodeStrategy(t *testing.T) { type onSubmitAssertion func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) - registerNewUser := func(ctx context.Context, t *testing.T, s *state, isSPA bool, submitAssertion onSubmitAssertion) *state { + registerNewUser := func(ctx context.Context, t *testing.T, s *state, apiType ApiType, submitAssertion onSubmitAssertion) *state { t.Helper() if s.email == "" { @@ -144,26 +170,31 @@ func TestRegistrationCodeStrategy(t *testing.T) { values.Set("traits.tos", "1") values.Set("method", "code") - body, resp := testhelpers.RegistrationMakeRequest(t, false, isSPA, rf, s.client, testhelpers.EncodeFormAsJSON(t, false, values)) + body, resp := testhelpers.RegistrationMakeRequest(t, apiType == ApiTypeNative, apiType == ApiTypeSPA, rf, s.client, testhelpers.EncodeFormAsJSON(t, apiType == ApiTypeNative, values)) if submitAssertion != nil { submitAssertion(ctx, t, s, body, resp) return s } - if isSPA { - require.EqualValues(t, http.StatusBadRequest, resp.StatusCode) - } else { + if apiType == ApiTypeBrowser { require.EqualValues(t, http.StatusOK, resp.StatusCode) + } else { + require.EqualValues(t, http.StatusBadRequest, resp.StatusCode) } + csrfToken := gjson.Get(body, "ui.nodes.#(attributes.name==csrf_token).attributes.value").String() - assert.NotEmptyf(t, csrfToken, "%s", body) + if apiType == ApiTypeNative { + assert.Emptyf(t, csrfToken, "expected an empty value for csrf_token on native api flows but got %s", body) + } else { + assert.NotEmptyf(t, csrfToken, "%s", body) + } require.Equal(t, s.email, gjson.Get(body, "ui.nodes.#(attributes.name==traits.email).attributes.value").String()) return s } - submitOTP := func(ctx context.Context, t *testing.T, reg *driver.RegistryDefault, s *state, vals func(v *url.Values), isSPA bool, submitAssertion onSubmitAssertion) *state { + submitOTP := func(ctx context.Context, t *testing.T, reg *driver.RegistryDefault, s *state, vals func(v *url.Values), apiType ApiType, submitAssertion onSubmitAssertion) *state { t.Helper() rf, resp, err := testhelpers.NewSDKCustomClient(s.testServer, s.client).FrontendApi.GetRegistrationFlow(context.Background()).Id(s.flowID).Execute() @@ -179,7 +210,7 @@ func TestRegistrationCodeStrategy(t *testing.T) { values.Set("traits.tos", "1") vals(&values) - body, resp := testhelpers.RegistrationMakeRequest(t, false, isSPA, rf, s.client, testhelpers.EncodeFormAsJSON(t, false, values)) + body, resp := testhelpers.RegistrationMakeRequest(t, apiType == ApiTypeNative, apiType == ApiTypeSPA, rf, s.client, testhelpers.EncodeFormAsJSON(t, apiType == ApiTypeNative, values)) if submitAssertion != nil { submitAssertion(ctx, t, s, body, resp) @@ -210,16 +241,20 @@ func TestRegistrationCodeStrategy(t *testing.T) { _, reg, public := setup(ctx, t) for _, tc := range []struct { - d string - isSPA bool + d string + apiType ApiType }{ { - d: "SPA client", - isSPA: true, + d: "SPA client", + apiType: ApiTypeSPA, + }, + { + d: "Browser client", + apiType: ApiTypeBrowser, }, { - d: "Browser client", - isSPA: false, + d: "Native client", + apiType: ApiTypeNative, }, } { t.Run("flow="+tc.d, func(t *testing.T) { @@ -227,10 +262,10 @@ func TestRegistrationCodeStrategy(t *testing.T) { ctx := context.Background() // 1. Initiate flow - state := createRegistrationFlow(ctx, t, public, tc.isSPA) + state := createRegistrationFlow(ctx, t, public, tc.apiType) // 2. Submit Identifier (email) - state = registerNewUser(ctx, t, state, tc.isSPA, nil) + state = registerNewUser(ctx, t, state, tc.apiType, nil) message := testhelpers.CourierExpectMessage(ctx, t, reg, state.email, "Complete your account registration") assert.Contains(t, message.Body, "please complete your account registration by entering the following code") @@ -241,20 +276,20 @@ func TestRegistrationCodeStrategy(t *testing.T) { // 3. Submit OTP state = submitOTP(ctx, t, reg, state, func(v *url.Values) { v.Set("code", registrationCode) - }, tc.isSPA, nil) + }, tc.apiType, nil) }) t.Run("case=should normalize email address on sign up", func(t *testing.T) { ctx := context.Background() // 1. Initiate flow - state := createRegistrationFlow(ctx, t, public, tc.isSPA) + state := createRegistrationFlow(ctx, t, public, tc.apiType) sourceMail := testhelpers.RandomEmail() state.email = strings.ToUpper(sourceMail) assert.NotEqual(t, sourceMail, state.email) // 2. Submit Identifier (email) - state = registerNewUser(ctx, t, state, tc.isSPA, nil) + state = registerNewUser(ctx, t, state, tc.apiType, nil) message := testhelpers.CourierExpectMessage(ctx, t, reg, sourceMail, "Complete your account registration") assert.Contains(t, message.Body, "please complete your account registration by entering the following code") @@ -265,7 +300,7 @@ func TestRegistrationCodeStrategy(t *testing.T) { // 3. Submit OTP state = submitOTP(ctx, t, reg, state, func(v *url.Values) { v.Set("code", registrationCode) - }, tc.isSPA, nil) + }, tc.apiType, nil) creds, ok := state.resultIdentity.GetCredentials(identity.CredentialsTypeCodeAuth) require.True(t, ok) @@ -276,16 +311,21 @@ func TestRegistrationCodeStrategy(t *testing.T) { t.Run("case=should be able to resend the code", func(t *testing.T) { ctx := context.Background() - s := createRegistrationFlow(ctx, t, public, tc.isSPA) + s := createRegistrationFlow(ctx, t, public, tc.apiType) - s = registerNewUser(ctx, t, s, tc.isSPA, func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) { - if tc.isSPA { - require.EqualValues(t, http.StatusBadRequest, resp.StatusCode) - } else { + s = registerNewUser(ctx, t, s, tc.apiType, func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) { + if tc.apiType == ApiTypeBrowser { require.EqualValues(t, http.StatusOK, resp.StatusCode) + } else { + require.EqualValues(t, http.StatusBadRequest, resp.StatusCode) } + csrfToken := gjson.Get(body, "ui.nodes.#(attributes.name==csrf_token).attributes.value").String() - require.NotEmptyf(t, csrfToken, "%s", body) + if tc.apiType == ApiTypeNative { + require.Empty(t, csrfToken, "expected the csrf_token to be empty but got %s", body) + } else { + require.NotEmptyf(t, csrfToken, "expected the csrf_token to exist but got %s", body) + } require.Equal(t, s.email, gjson.Get(body, "ui.nodes.#(attributes.name==traits.email).attributes.value").String()) attr := gjson.Get(body, "ui.nodes.#(attributes.name==method)#").String() @@ -304,14 +344,18 @@ func TestRegistrationCodeStrategy(t *testing.T) { // resend code s = submitOTP(ctx, t, reg, s, func(v *url.Values) { v.Set("resend", "code") - }, tc.isSPA, func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) { - if tc.isSPA { - require.EqualValues(t, http.StatusBadRequest, resp.StatusCode) - } else { + }, tc.apiType, func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) { + if tc.apiType == ApiTypeBrowser { require.Equal(t, http.StatusOK, resp.StatusCode) + } else { + require.EqualValues(t, http.StatusBadRequest, resp.StatusCode) } csrfToken := gjson.Get(body, "ui.nodes.#(attributes.name==csrf_token).attributes.value").String() - require.NotEmptyf(t, csrfToken, "%s", body) + if tc.apiType == ApiTypeNative { + assert.Emptyf(t, csrfToken, "expected an empty value for csrf_token on native api flows but got %s", body) + } else { + require.NotEmptyf(t, csrfToken, "expected to find the csrf_token but got %s", body) + } require.Containsf(t, gjson.Get(body, "ui.messages").String(), "An email containing a code has been sent to the email address you provided.", "%s", body) }) @@ -327,28 +371,28 @@ func TestRegistrationCodeStrategy(t *testing.T) { // try submit old code s = submitOTP(ctx, t, reg, s, func(v *url.Values) { v.Set("code", registrationCode) - }, tc.isSPA, func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) { - if tc.isSPA { - require.Equal(t, http.StatusBadRequest, resp.StatusCode, "%s", body) - } else { + }, tc.apiType, func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) { + if tc.apiType == ApiTypeBrowser { require.Equal(t, http.StatusOK, resp.StatusCode, "%s", body) + } else { + require.Equal(t, http.StatusBadRequest, resp.StatusCode, "%s", body) } require.Contains(t, gjson.Get(body, "ui.messages").String(), "The registration code is invalid or has already been used. Please try again") }) s = submitOTP(ctx, t, reg, s, func(v *url.Values) { v.Set("code", registrationCode2) - }, tc.isSPA, nil) + }, tc.apiType, nil) }) t.Run("case=swapping out traits should not be possible on code submit", func(t *testing.T) { ctx := context.Background() // 1. Initiate flow - s := createRegistrationFlow(ctx, t, public, tc.isSPA) + s := createRegistrationFlow(ctx, t, public, tc.apiType) // 2. Submit Identifier (email) - s = registerNewUser(ctx, t, s, tc.isSPA, nil) + s = registerNewUser(ctx, t, s, tc.apiType, nil) message := testhelpers.CourierExpectMessage(ctx, t, reg, s.email, "Complete your account registration") assert.Contains(t, message.Body, "please complete your account registration by entering the following code") @@ -360,11 +404,11 @@ func TestRegistrationCodeStrategy(t *testing.T) { // 3. Submit OTP s = submitOTP(ctx, t, reg, s, func(v *url.Values) { v.Set("code", registrationCode) - }, tc.isSPA, func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) { - if tc.isSPA { - require.Equal(t, http.StatusBadRequest, resp.StatusCode, "%s", body) - } else { + }, tc.apiType, func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) { + if tc.apiType == ApiTypeBrowser { require.Equal(t, http.StatusOK, resp.StatusCode, "%s", body) + } else { + require.Equal(t, http.StatusBadRequest, resp.StatusCode, "%s", body) } require.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "The provided traits do not match the traits previously associated with this flow.") }) @@ -374,10 +418,10 @@ func TestRegistrationCodeStrategy(t *testing.T) { ctx := context.Background() // 1. Initiate flow - s := createRegistrationFlow(ctx, t, public, tc.isSPA) + s := createRegistrationFlow(ctx, t, public, tc.apiType) // 2. Submit Identifier (email) - s = registerNewUser(ctx, t, s, tc.isSPA, nil) + s = registerNewUser(ctx, t, s, tc.apiType, nil) message := testhelpers.CourierExpectMessage(ctx, t, reg, s.email, "Complete your account registration") assert.Contains(t, message.Body, "please complete your account registration by entering the following code") @@ -389,11 +433,11 @@ func TestRegistrationCodeStrategy(t *testing.T) { s = submitOTP(ctx, t, reg, s, func(v *url.Values) { v.Set("code", registrationCode) v.Set("traits.tos", "0") - }, tc.isSPA, func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) { - if tc.isSPA { - require.Equal(t, http.StatusBadRequest, resp.StatusCode, "%s", body) - } else { + }, tc.apiType, func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) { + if tc.apiType == ApiTypeBrowser { require.Equal(t, http.StatusOK, resp.StatusCode, "%s", body) + } else { + require.Equal(t, http.StatusBadRequest, resp.StatusCode, "%s", body) } require.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "The provided traits do not match the traits previously associated with this flow.") }) @@ -403,10 +447,10 @@ func TestRegistrationCodeStrategy(t *testing.T) { ctx := context.Background() // 1. Initiate flow - s := createRegistrationFlow(ctx, t, public, tc.isSPA) + s := createRegistrationFlow(ctx, t, public, tc.apiType) // 2. Submit Identifier (email) - s = registerNewUser(ctx, t, s, tc.isSPA, nil) + s = registerNewUser(ctx, t, s, tc.apiType, nil) reg.Persister().Transaction(ctx, func(ctx context.Context, connection *pop.Connection) error { count, err := connection.RawQuery(fmt.Sprintf("SELECT * FROM %s WHERE selfservice_registration_flow_id = ?", new(code.RegistrationCode).TableName(ctx)), uuid.FromStringOrNil(s.flowID)).Count(new(code.RegistrationCode)) @@ -418,11 +462,11 @@ func TestRegistrationCodeStrategy(t *testing.T) { for i := 0; i < 5; i++ { s = submitOTP(ctx, t, reg, s, func(v *url.Values) { v.Set("code", "111111") - }, tc.isSPA, func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) { - if tc.isSPA { - require.Equal(t, http.StatusBadRequest, resp.StatusCode, "%s", body) - } else { + }, tc.apiType, func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) { + if tc.apiType == ApiTypeBrowser { require.Equal(t, http.StatusOK, resp.StatusCode, "%s", body) + } else { + require.Equal(t, http.StatusBadRequest, resp.StatusCode, "%s", body) } require.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "The registration code is invalid or has already been used") }) @@ -430,11 +474,11 @@ func TestRegistrationCodeStrategy(t *testing.T) { s = submitOTP(ctx, t, reg, s, func(v *url.Values) { v.Set("code", "111111") - }, tc.isSPA, func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) { - if tc.isSPA { - require.Equal(t, http.StatusBadRequest, resp.StatusCode, "%s", body) - } else { + }, tc.apiType, func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) { + if tc.apiType == ApiTypeBrowser { require.Equal(t, http.StatusOK, resp.StatusCode, "%s", body) + } else { + require.Equal(t, http.StatusBadRequest, resp.StatusCode, "%s", body) } require.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "The request was submitted too often.") }) @@ -448,16 +492,20 @@ func TestRegistrationCodeStrategy(t *testing.T) { conf, reg, public := setup(ctx, t) for _, tc := range []struct { - d string - isSPA bool + d string + apiType ApiType }{ { - d: "SPA client", - isSPA: true, + d: "SPA client", + apiType: ApiTypeSPA, + }, + { + d: "Browser client", + apiType: ApiTypeBrowser, }, { - d: "Browser client", - isSPA: false, + d: "Native client", + apiType: ApiTypeNative, }, } { t.Run("test="+tc.d, func(t *testing.T) { @@ -468,14 +516,11 @@ func TestRegistrationCodeStrategy(t *testing.T) { }) // 1. Initiate flow - s := createRegistrationFlow(ctx, t, public, tc.isSPA) + s := createRegistrationFlow(ctx, t, public, tc.apiType) // 2. Submit Identifier (email) - s = registerNewUser(ctx, t, s, tc.isSPA, func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) { - if tc.isSPA { - require.Equal(t, http.StatusBadRequest, resp.StatusCode) - require.Contains(t, gjson.Get(body, "ui.messages").String(), "Could not find any login identifiers") - } else { + s = registerNewUser(ctx, t, s, tc.apiType, func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) { + if tc.apiType == ApiTypeBrowser { // we expect a redirect to the registration page with the flow id require.Equal(t, http.StatusOK, resp.StatusCode) require.Equal(t, conf.SelfServiceFlowRegistrationUI(ctx).Path, resp.Request.URL.Path) @@ -486,6 +531,9 @@ func TestRegistrationCodeStrategy(t *testing.T) { require.NoError(t, err) require.Contains(t, gjson.GetBytes(body, "ui.messages").String(), "Could not find any login identifiers") + } else { + require.Equal(t, http.StatusBadRequest, resp.StatusCode) + require.Contains(t, gjson.Get(body, "ui.messages").String(), "Could not find any login identifiers") } }) }) @@ -501,10 +549,10 @@ func TestRegistrationCodeStrategy(t *testing.T) { }) // 1. Initiate flow - state := createRegistrationFlow(ctx, t, public, tc.isSPA) + state := createRegistrationFlow(ctx, t, public, tc.apiType) // 2. Submit Identifier (email) - state = registerNewUser(ctx, t, state, tc.isSPA, nil) + state = registerNewUser(ctx, t, state, tc.apiType, nil) message := testhelpers.CourierExpectMessage(ctx, t, reg, state.email, "Complete your account registration") assert.Contains(t, message.Body, "please complete your account registration by entering the following code") @@ -515,7 +563,7 @@ func TestRegistrationCodeStrategy(t *testing.T) { // 3. Submit OTP state = submitOTP(ctx, t, reg, state, func(v *url.Values) { v.Set("code", registrationCode) - }, tc.isSPA, nil) + }, tc.apiType, nil) }) t.Run("case=code should expire", func(t *testing.T) { @@ -525,10 +573,10 @@ func TestRegistrationCodeStrategy(t *testing.T) { }) // 1. Initiate flow - s := createRegistrationFlow(ctx, t, public, tc.isSPA) + s := createRegistrationFlow(ctx, t, public, tc.apiType) // 2. Submit Identifier (email) - s = registerNewUser(ctx, t, s, tc.isSPA, nil) + s = registerNewUser(ctx, t, s, tc.apiType, nil) message := testhelpers.CourierExpectMessage(ctx, t, reg, s.email, "Complete your account registration") assert.Contains(t, message.Body, "please complete your account registration by entering the following code") @@ -538,15 +586,15 @@ func TestRegistrationCodeStrategy(t *testing.T) { s = submitOTP(ctx, t, reg, s, func(v *url.Values) { v.Set("code", registrationCode) - }, tc.isSPA, func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) { - if tc.isSPA { - require.Equal(t, http.StatusGone, resp.StatusCode) - require.Containsf(t, gjson.Get(body, "error.reason").String(), "self-service flow expired 0.00 minutes ago", "%s", body) - } else { + }, tc.apiType, func(ctx context.Context, t *testing.T, s *state, body string, resp *http.Response) { + if tc.apiType == ApiTypeBrowser { // with browser clients we redirect back to the UI with a new flow id as a query parameter require.Equal(t, http.StatusOK, resp.StatusCode) require.Equal(t, conf.SelfServiceFlowRegistrationUI(ctx).Path, resp.Request.URL.Path) require.NotEqual(t, s.flowID, resp.Request.URL.Query().Get("flow")) + } else { + require.Equal(t, http.StatusGone, resp.StatusCode) + require.Containsf(t, gjson.Get(body, "error.reason").String(), "self-service flow expired 0.00 minutes ago", "%s", body) } }) }) diff --git a/test/e2e/cypress/integration/profiles/code/login/error.spec.ts b/test/e2e/cypress/integration/profiles/code/login/error.spec.ts index 899eafb0514a..3dbc3729909d 100644 --- a/test/e2e/cypress/integration/profiles/code/login/error.spec.ts +++ b/test/e2e/cypress/integration/profiles/code/login/error.spec.ts @@ -1,7 +1,7 @@ // Copyright © 2023 Ory Corp // SPDX-License-Identifier: Apache-2.0 -import { appPrefix, APP_URL, gen } from "../../../../helpers" +import { appPrefix, APP_URL, gen, MOBILE_URL } from "../../../../helpers" import { routes as express } from "../../../../helpers/express" import { routes as react } from "../../../../helpers/react" @@ -17,12 +17,31 @@ context("Login error messages with code method", () => { app: "react" as "react", profile: "code", }, + { + route: MOBILE_URL + "/Login", + app: "mobile" as "mobile", + profile: "code", + }, ].forEach(({ route, profile, app }) => { describe(`for app ${app}`, () => { + const Selectors = { + mobile: { + identity: '[data-testid="identifier"]', + code: '[data-testid="code"]', + }, + express: { + identity: 'input[name="identifier"]', + code: 'input[name="code"]', + }, + } + Selectors["react"] = Selectors["express"] + before(() => { cy.useConfigProfile(profile) cy.deleteMail() - cy.proxy(app) + if (app !== "mobile") { + cy.proxy(app) + } }) beforeEach(() => { @@ -41,10 +60,8 @@ context("Login error messages with code method", () => { it("should show error message when account identifier does not exist", () => { const email = gen.email() - cy.get('input[name="identifier"]').type(email) - cy.submitCodeForm() - - cy.url().should("contain", "login") + cy.get(Selectors[app]["identity"]).type(email) + cy.submitCodeForm(app) cy.get('[data-testid="ui/message/4000035"]').should( "contain", @@ -54,19 +71,18 @@ context("Login error messages with code method", () => { it("should show error message when code is invalid", () => { cy.get("@email").then((email) => { - cy.get('input[name="identifier"]').clear().type(email.toString()) + cy.get(Selectors[app]["identity"]).clear().type(email.toString()) }) - cy.submitCodeForm() + cy.submitCodeForm(app) - cy.url().should("contain", "login") cy.get('[data-testid="ui/message/1010014"]').should( "contain", "An email containing a code has been sent to the email address you provided", ) - cy.get('input[name="code"]').type("invalid-code") - cy.submitCodeForm() + cy.get(Selectors[app]["code"]).type("invalid-code") + cy.submitCodeForm(app) cy.get('[data-testid="ui/message/4010008"]').should( "contain", @@ -76,16 +92,31 @@ context("Login error messages with code method", () => { it("should show error message when identifier has changed", () => { cy.get("@email").then((email) => { - cy.get('input[name="identifier"]').type(email.toString()) + cy.get(Selectors[app]["identity"]).type(email.toString()) }) - cy.submitCodeForm() + cy.submitCodeForm(app) + + if (app !== "express") { + cy.intercept("POST", "/self-service/login*", (req) => { + req.body = { + ...req.body, + identifier: gen.email(), + } + req.continue() + }).as("login") + } else { + cy.get(Selectors[app]["identity"]) + .type("{selectall}{backspace}", { force: true }) + .type(gen.email(), { force: true }) + } - cy.url().should("contain", "login") - cy.get('input[name="identifier"]').clear().type(gen.email()) - cy.get('input[name="code"]').type("invalid-code") - cy.submitCodeForm() + cy.get(Selectors[app]["code"]).type("invalid-code") + cy.submitCodeForm(app) + if (app !== "express") { + cy.wait("@login") + } cy.get('[data-testid="ui/message/4000035"]').should( "contain", "This account does not exist or has not setup sign in with code.", @@ -94,30 +125,45 @@ context("Login error messages with code method", () => { it("should show error message when required fields are missing", () => { cy.get("@email").then((email) => { - cy.get('input[name="identifier"]').type(email.toString()) + cy.get(Selectors[app]["identity"]).type(email.toString()) }) - cy.submitCodeForm() - cy.url().should("contain", "login") + cy.submitCodeForm(app) - cy.removeAttribute(['input[name="code"]'], "required") - cy.submitCodeForm() + cy.removeAttribute([Selectors[app]["code"]], "required") + cy.submitCodeForm(app) - cy.get('[data-testid="ui/message/4000002"]').should( - "contain", - "Property code is missing", - ) + if (app === "mobile") { + cy.get('[data-testid="field/code"]').should( + "contain", + "Property code is missing", + ) + } else { + cy.get('[data-testid="ui/message/4000002"]').should( + "contain", + "Property code is missing", + ) + } - cy.get('input[name="code"]').type("invalid-code") - cy.removeAttribute(['input[name="identifier"]'], "required") + cy.get(Selectors[app]["code"]).type("invalid-code") + cy.removeAttribute([Selectors[app]["identity"]], "required") - cy.get('input[name="identifier"]').clear() + cy.get(Selectors[app]["identity"]).type("{selectall}{backspace}", { + force: true, + }) - cy.submitCodeForm() - cy.get('[data-testid="ui/message/4000002"]').should( - "contain", - "Property identifier is missing", - ) + cy.submitCodeForm(app) + if (app === "mobile") { + cy.get('[data-testid="field/identifier"]').should( + "contain", + "Property identifier is missing", + ) + } else { + cy.get('[data-testid="ui/message/4000002"]').should( + "contain", + "Property identifier is missing", + ) + } }) it("should show error message when code is expired", () => { @@ -134,19 +180,17 @@ context("Login error messages with code method", () => { }) cy.get("@email").then((email) => { - cy.get('input[name="identifier"]').type(email.toString()) + cy.get(Selectors[app]["identity"]).type(email.toString()) }) - cy.submitCodeForm() - - cy.url().should("contain", "login") + cy.submitCodeForm(app) cy.get("@email").then((email) => { cy.getLoginCodeFromEmail(email.toString()).should((code) => { - cy.get('input[name="code"]').type(code) + cy.get(Selectors[app]["code"]).type(code) }) }) - cy.submitCodeForm() + cy.submitCodeForm(app) // the react app does not show the error message for 410 errors // it just creates a new flow @@ -156,7 +200,7 @@ context("Login error messages with code method", () => { "The login flow expired", ) } else { - cy.get("input[name=identifier]").should("be.visible") + cy.get(Selectors[app]["identity"]).should("be.visible") } cy.noSession() diff --git a/test/e2e/cypress/integration/profiles/code/login/success.spec.ts b/test/e2e/cypress/integration/profiles/code/login/success.spec.ts index 2f882717edbd..1f6635c25aa9 100644 --- a/test/e2e/cypress/integration/profiles/code/login/success.spec.ts +++ b/test/e2e/cypress/integration/profiles/code/login/success.spec.ts @@ -1,7 +1,8 @@ // Copyright © 2023 Ory Corp // SPDX-License-Identifier: Apache-2.0 -import { gen } from "../../../../helpers" +import { Session } from "@ory/kratos-client" +import { gen, MOBILE_URL } from "../../../../helpers" import { routes as express } from "../../../../helpers/express" import { routes as react } from "../../../../helpers/react" @@ -17,12 +18,35 @@ context("Login success with code method", () => { app: "react" as "react", profile: "code", }, + { + route: MOBILE_URL + "/Login", + app: "mobile" as "mobile", + profile: "code", + }, ].forEach(({ route, profile, app }) => { describe(`for app ${app}`, () => { + const Selectors = { + mobile: { + identity: '[data-testid="identifier"]', + code: '[data-testid="code"]', + submit: '[data-testid="field/method/code"]', + resend: '[data-testid="field/resend/code"]', + }, + express: { + identity: 'input[name="identifier"]', + code: 'input[name="code"]', + submit: 'button[name="method"][value="code"]', + resend: 'button[name="resend"]', + }, + } + Selectors["react"] = Selectors["express"] + before(() => { cy.deleteMail() cy.useConfigProfile(profile) - cy.proxy(app) + if (app !== "mobile") { + cy.proxy(app) + } cy.setPostCodeRegistrationHooks([]) cy.setupHooks("login", "after", "code", []) }) @@ -39,19 +63,39 @@ context("Login success with code method", () => { it("should be able to sign in with code", () => { cy.get("@email").then((email) => { - cy.get('input[name="identifier"]').clear().type(email.toString()) - cy.submitCodeForm() + cy.get(Selectors[app]["identity"]).clear().type(email.toString()) + cy.submitCodeForm(app) cy.getLoginCodeFromEmail(email.toString()).should((code) => { - cy.get('input[name="code"]').type(code) + cy.get(Selectors[app]["code"]).type(code) - cy.get("button[name=method][value=code]").click() + cy.get(Selectors[app]["submit"]).click() }) cy.location("pathname").should("not.contain", "login") - cy.getSession().should((session) => { - const { identity } = session + if (app === "mobile") { + cy.get('[data-testid="session-token"]').then((token) => { + cy.getSession({ + expectAal: "aal1", + expectMethods: ["code"], + token: token.text(), + }).then((session) => { + cy.wrap(session).as("session") + }) + }) + + cy.get('[data-testid="session-content"]').should("contain", email) + cy.get('[data-testid="session-token"]').should("not.be.empty") + } else { + cy.getSession({ expectAal: "aal1", expectMethods: ["code"] }).then( + (session) => { + cy.wrap(session).as("session") + }, + ) + } + + cy.get("@session").then(({ identity }) => { expect(identity.id).to.not.be.empty expect(identity.verifiable_addresses).to.have.length(1) expect(identity.verifiable_addresses[0].status).to.equal( @@ -64,14 +108,14 @@ context("Login success with code method", () => { it("should be able to resend login code", () => { cy.get("@email").then((email) => { - cy.get('input[name="identifier"]').clear().type(email.toString()) - cy.submitCodeForm() + cy.get(Selectors[app]["identity"]).clear().type(email.toString()) + cy.submitCodeForm(app) cy.getLoginCodeFromEmail(email.toString()).should((code) => { cy.wrap(code).as("code1") }) - cy.get("button[name=resend]").click() + cy.get(Selectors[app]["resend"]).click() cy.getLoginCodeFromEmail(email.toString()).should((code) => { cy.wrap(code).as("code2") @@ -85,10 +129,10 @@ context("Login success with code method", () => { // attempt to submit code 1 cy.get("@code1").then((code1) => { - cy.get('input[name="code"]').clear().type(code1.toString()) + cy.get(Selectors[app]["code"]).clear().type(code1.toString()) }) - cy.get("button[name=method][value=code]").click() + cy.get(Selectors[app]["submit"]).click() cy.get("[data-testid='ui/message/4010008']").contains( "The login code is invalid or has already been used", @@ -96,15 +140,37 @@ context("Login success with code method", () => { // attempt to submit code 2 cy.get("@code2").then((code2) => { - cy.get('input[name="code"]').clear().type(code2.toString()) + cy.get(Selectors[app]["code"]).clear().type(code2.toString()) }) - cy.get('button[name="method"][value="code"]').click() + cy.get(Selectors[app]["submit"]).click() if (app === "express") { cy.get('a[href*="sessions"').click() } - cy.getSession().should((session) => { + + if (app === "mobile") { + cy.get('[data-testid="session-token"]').then((token) => { + cy.getSession({ + expectAal: "aal1", + expectMethods: ["code"], + token: token.text(), + }).then((session) => { + cy.wrap(session).as("session") + }) + }) + + cy.get('[data-testid="session-content"]').should("contain", email) + cy.get('[data-testid="session-token"]').should("not.be.empty") + } else { + cy.getSession({ expectAal: "aal1", expectMethods: ["code"] }).then( + (session) => { + cy.wrap(session).as("session") + }, + ) + } + + cy.get("@session").then((session) => { const { identity } = session expect(identity.id).to.not.be.empty expect(identity.verifiable_addresses).to.have.length(1) @@ -139,25 +205,45 @@ context("Login success with code method", () => { cy.visit(route) - cy.get('input[name="identifier"]').clear().type(email2) - cy.submitCodeForm() + cy.get(Selectors[app]["identity"]).clear().type(email2) + cy.submitCodeForm(app) cy.getLoginCodeFromEmail(email2).should((code) => { - cy.get('input[name="code"]').type(code) - cy.get("button[name=method][value=code]").click() + cy.get(Selectors[app]["code"]).type(code) + cy.get(Selectors[app]["submit"]).click() }) - cy.getSession({ expectAal: "aal1", expectMethods: ["code"] }).then( - (session) => { - expect(session.identity.verifiable_addresses).to.have.length(2) - expect(session.identity.verifiable_addresses[0].status).to.equal( - "completed", - ) - expect(session.identity.verifiable_addresses[1].status).to.equal( - "completed", - ) - }, - ) + if (app === "mobile") { + cy.get('[data-testid="session-token"]').then((token) => { + cy.getSession({ + expectAal: "aal1", + expectMethods: ["code"], + token: token.text(), + }).then((session) => { + cy.wrap(session).as("session") + }) + }) + + cy.get('[data-testid="session-content"]').should("contain", email) + cy.get('[data-testid="session-token"]').should("not.be.empty") + cy.get('[data-testid="session-content"]').should("contain", email2) + } else { + cy.getSession({ expectAal: "aal1", expectMethods: ["code"] }).then( + (session) => { + cy.wrap(session).as("session") + }, + ) + } + + cy.get("@session").then((session) => { + expect(session?.identity?.verifiable_addresses).to.have.length(2) + expect(session?.identity?.verifiable_addresses[0].status).to.equal( + "completed", + ) + expect(session.identity.verifiable_addresses[1].status).to.equal( + "completed", + ) + }) }) }) }) diff --git a/test/e2e/cypress/integration/profiles/code/registration/error.spec.ts b/test/e2e/cypress/integration/profiles/code/registration/error.spec.ts index b96e7b726380..48c8005d28e0 100644 --- a/test/e2e/cypress/integration/profiles/code/registration/error.spec.ts +++ b/test/e2e/cypress/integration/profiles/code/registration/error.spec.ts @@ -1,6 +1,7 @@ // Copyright © 2023 Ory Corp // SPDX-License-Identifier: Apache-2.0 -import { gen } from "../../../../helpers" +import { UiNode } from "@ory/kratos-client" +import { gen, MOBILE_URL } from "../../../../helpers" import { routes as express } from "../../../../helpers/express" import { routes as react } from "../../../../helpers/react" @@ -16,10 +17,33 @@ context("Registration error messages with code method", () => { app: "react" as "react", profile: "code", }, + { + route: MOBILE_URL + "/Registration", + app: "mobile" as "mobile", + profile: "code", + }, ].forEach(({ route, profile, app }) => { describe(`for app ${app}`, () => { + const Selectors = { + mobile: { + identifier: "[data-testid='field/identifier']", + email: "[data-testid='field/traits.email']", + tos: "[data-testid='traits.tos']", + code: "[data-testid='field/code']", + }, + express: { + identifier: "input[name='identifier']", + email: "input[name='traits.email']", + tos: "[name='traits.tos'] + label", + code: "input[name='code']", + }, + } + Selectors["react"] = Selectors["express"] + before(() => { - cy.proxy(app) + if (app !== "mobile") { + cy.proxy(app) + } cy.useConfigProfile(profile) cy.deleteMail() }) @@ -33,18 +57,18 @@ context("Registration error messages with code method", () => { it("should show error message when code is invalid", () => { const email = gen.email() - cy.get('input[name="traits.email"]').type(email) - cy.get('[name="traits.tos"] + label').click() + cy.get(Selectors[app]["email"]).type(email) + cy.get(Selectors[app]["tos"]).click() - cy.submitCodeForm() + cy.submitCodeForm(app) cy.get('[data-testid="ui/message/1040005"]').should( "contain", "An email containing a code has been sent to the email address you provided", ) - cy.get('input[name="code"]').type("invalid-code") - cy.submitCodeForm() + cy.get(Selectors[app]["code"]).type("invalid-code") + cy.submitCodeForm(app) cy.get('[data-testid="ui/message/4040003"]').should( "contain", @@ -55,20 +79,37 @@ context("Registration error messages with code method", () => { it("should show error message when traits have changed", () => { const email = gen.email() - cy.get('input[name="traits.email"]').type(email) - cy.get('[name="traits.tos"] + label').click() + cy.get(Selectors[app]["email"]).type(email) + cy.get(Selectors[app]["tos"]).click() - cy.submitCodeForm() + cy.submitCodeForm(app) cy.get('[data-testid="ui/message/1040005"]').should( "contain", "An email containing a code has been sent to the email address you provided", ) - cy.get('input[name="traits.email"]') - .clear() - .type("changed-email@email.com") - cy.get('input[name="code"]').type("invalid-code") - cy.submitCodeForm() + if (app !== "express") { + // the mobile app doesn't render hidden fields in the DOM + // we need to replace the request body + cy.intercept("POST", "/self-service/registration*", (req) => { + req.body = { + ...req.body, + "traits.email": "changed-email@email.com", + } + req.continue() + }).as("registration") + } else { + cy.get(Selectors[app]["email"]) + .type("{selectall}{backspace}", { force: true }) + .type("changed-email@email.com", { force: true }) + } + + cy.get(Selectors[app]["code"]).type("invalid-code") + cy.submitCodeForm(app) + + if (app !== "express") { + cy.wait("@registration") + } cy.get('[data-testid="ui/message/4000036"]').should( "contain", @@ -79,32 +120,65 @@ context("Registration error messages with code method", () => { it("should show error message when required fields are missing", () => { const email = gen.email() - cy.get('input[name="traits.email"]').type(email) - cy.get('[name="traits.tos"] + label').click() + cy.get(Selectors[app]["email"]).type(email) + cy.get(Selectors[app]["tos"]).click() - cy.submitCodeForm() + cy.submitCodeForm(app) cy.get('[data-testid="ui/message/1040005"]').should( "contain", "An email containing a code has been sent to the email address you provided", ) - cy.removeAttribute(['input[name="code"]'], "required") + cy.removeAttribute([Selectors[app]["code"]], "required") - cy.submitCodeForm() - cy.get('[data-testid="ui/message/4000002"]').should( - "contain", - "Property code is missing", - ) + cy.submitCodeForm(app) + + if (app === "mobile") { + cy.get('[data-testid="field/code"]').should( + "contain", + "Property code is missing", + ) + } else { + cy.get('[data-testid="ui/message/4000002"]').should( + "contain", + "Property code is missing", + ) + } + + if (app !== "express") { + // the mobile app doesn't render hidden fields in the DOM + // we need to replace the request body + cy.intercept("POST", "/self-service/registration*", (req) => { + delete req.body["traits.email"] + req.continue((res) => { + const emailInput = res.body.ui.nodes.find( + (n: UiNode) => + "name" in n.attributes && + n.attributes.name === "traits.email", + ) + expect(emailInput).to.not.be.undefined + expect(emailInput.messages).to.not.be.undefined + expect(emailInput.messages[0].text).to.contain("email is missing") + }) + }).as("registration") + } else { + cy.get(Selectors[app]["email"]).type("{selectall}{backspace}", { + force: true, + }) + cy.removeAttribute([Selectors[app]["email"]], "required") + } + cy.get(Selectors[app]["code"]).type("invalid-code") - cy.get('input[name="traits.email"]').clear() - cy.get('input[name="code"]').type("invalid-code") - cy.removeAttribute(['input[name="traits.email"]'], "required") + cy.submitCodeForm(app) - cy.submitCodeForm() - cy.get('[data-testid="ui/message/4000002"]').should( - "contain", - "Property email is missing", - ) + if (app !== "express") { + cy.wait("@registration") + } else { + cy.get('[data-testid="ui/message/4000002"]').should( + "contain", + "Property email is missing", + ) + } }) it("should show error message when code is expired", () => { @@ -115,18 +189,18 @@ context("Registration error messages with code method", () => { cy.visit(route) const email = gen.email() - cy.get('input[name="traits.email"]').type(email) - cy.get('[name="traits.tos"] + label').click() + cy.get(Selectors[app]["email"]).type(email) + cy.get(Selectors[app]["tos"]).click() - cy.submitCodeForm() + cy.submitCodeForm(app) cy.get('[data-testid="ui/message/1040005"]').should( "contain", "An email containing a code has been sent to the email address you provided", ) cy.getRegistrationCodeFromEmail(email).should((code) => { - cy.get('input[name="code"]').type(code) - cy.submitCodeForm() + cy.get(Selectors[app]["code"]).type(code) + cy.submitCodeForm(app) }) // in the react spa app we don't show the 410 gone error. we create a new flow. @@ -136,7 +210,7 @@ context("Registration error messages with code method", () => { "The registration flow expired", ) } else { - cy.get('input[name="traits.email"]').should("be.visible") + cy.get(Selectors[app]["email"]).should("be.visible") } cy.noSession() diff --git a/test/e2e/cypress/integration/profiles/code/registration/success.spec.ts b/test/e2e/cypress/integration/profiles/code/registration/success.spec.ts index 4ce2d0703b1d..a07cd6d51b26 100644 --- a/test/e2e/cypress/integration/profiles/code/registration/success.spec.ts +++ b/test/e2e/cypress/integration/profiles/code/registration/success.spec.ts @@ -1,7 +1,8 @@ // Copyright © 2023 Ory Corp // SPDX-License-Identifier: Apache-2.0 -import { gen } from "../../../../helpers" +import { Session } from "@ory/kratos-client" +import { gen, MOBILE_URL } from "../../../../helpers" import { routes as express } from "../../../../helpers/express" import { routes as react } from "../../../../helpers/react" @@ -21,12 +22,53 @@ context("Registration success with code method", () => { app: "react" as "react", profile: "code", }, + { + route: MOBILE_URL + "/Registration", + login: MOBILE_URL + "/Login", + recovery: MOBILE_URL + "/Recovery", + app: "mobile" as "mobile", + profile: "code", + }, ].forEach(({ route, login, recovery, profile, app }) => { describe(`for app ${app}`, () => { + const Selectors = { + mobile: { + identifier: "[data-testid='field/identifier']", + recoveryEmail: "[data-testid='field/email']", + email: "[data-testid='traits.email']", + email2: "[data-testid='traits.email2']", + tos: "[data-testid='traits.tos']", + username: "[data-testid='traits.username']", + code: "[data-testid='field/code']", + recoveryCode: "[data-testid='code']", + submitCode: "[data-testid='field/method/code']", + resendCode: "[data-testid='field/method/resend']", + submitRecovery: "[data-testid='field/method/code']", + codeHiddenMethod: "[data-testid='field/method/code']", + }, + express: { + identifier: "input[name='identifier']", + recoveryEmail: "input[name=email]", + email: "input[name='traits.email']", + email2: "input[name='traits.email2']", + tos: "[name='traits.tos'] + label", + username: "input[name='traits.username']", + code: "input[name='code']", + recoveryCode: "input[name=code]", + submitRecovery: "button[name=method][value=code]", + submitCode: "button[name='method'][value='code']", + resendCode: "button[name='resend'][value='code']", + codeHiddenMethod: "input[name='method'][value='code'][type='hidden']", + }, + } + Selectors["react"] = Selectors["express"] + before(() => { cy.deleteMail() cy.useConfigProfile(profile) - cy.proxy(app) + if (app !== "mobile") { + cy.proxy(app) + } }) beforeEach(() => { @@ -38,10 +80,10 @@ context("Registration success with code method", () => { it("should be able to resend the registration code", async () => { const email = gen.email() - cy.get(`input[name='traits.email']`).type(email) - cy.get(`[name='traits.tos'] + label`).click() + cy.get(Selectors[app]["email"]).type(email) + cy.get(`${Selectors[app]["tos"]} + label`).click() - cy.submitCodeForm() + cy.submitCodeForm(app) cy.get('[data-testid="ui/message/1040005"]').should( "contain", "An email containing a code has been sent to the email address you provided", @@ -51,11 +93,9 @@ context("Registration success with code method", () => { cy.wrap(code).as("code1"), ) - cy.get(`input[name='traits.email']`).should("have.value", email) - cy.get(`input[name='method'][value='code'][type='hidden']`).should( - "exist", - ) - cy.get(`button[name='resend'][value='code']`).click() + cy.get(Selectors[app]["email"]).should("have.value", email) + cy.get(Selectors[app]["codeHiddenMethod"]).should("exist") + cy.get(Selectors[app]["resendCode"]).click() cy.getRegistrationCodeFromEmail(email).should((code) => { cy.wrap(code).as("code2") @@ -63,9 +103,9 @@ context("Registration success with code method", () => { cy.get("@code1").then((code1) => { // previous code should not work - cy.get('input[name="code"]').clear().type(code1.toString()) + cy.get(Selectors[app]["code"]).clear().type(code1.toString()) - cy.submitCodeForm() + cy.submitCodeForm(app) cy.get('[data-testid="ui/message/4040003"]').should( "contain.text", "The registration code is invalid or has already been used. Please try again.", @@ -73,12 +113,32 @@ context("Registration success with code method", () => { }) cy.get("@code2").then((code2) => { - cy.get('input[name="code"]').clear().type(code2.toString()) - cy.submitCodeForm() + cy.get(Selectors[app]["code"]).clear().type(code2.toString()) + cy.submitCodeForm(app) }) - cy.getSession().should((session) => { - const { identity } = session + if (app === "mobile") { + cy.get('[data-testid="session-token"]').then((token) => { + cy.getSession({ + expectAal: "aal1", + expectMethods: ["code"], + token: token.text(), + }).then((session) => { + cy.wrap(session).as("session") + }) + }) + + cy.get('[data-testid="session-content"]').should("contain", email) + cy.get('[data-testid="session-token"]').should("not.be.empty") + } else { + cy.getSession({ expectAal: "aal1", expectMethods: ["code"] }).then( + (session) => { + cy.wrap(session).as("session") + }, + ) + } + + cy.get("@session").then(({ identity }) => { expect(identity.id).to.not.be.empty expect(identity.verifiable_addresses).to.have.length(1) expect(identity.verifiable_addresses[0].status).to.equal("completed") @@ -89,22 +149,42 @@ context("Registration success with code method", () => { it("should sign up and be logged in with session hook", () => { const email = gen.email() - cy.get(`input[name='traits.email']`).type(email) - cy.get(`[name='traits.tos'] + label`).click() + cy.get(Selectors[app]["email"]).type(email) + cy.get(Selectors[app]["tos"]).click() - cy.submitCodeForm() + cy.submitCodeForm(app) cy.get('[data-testid="ui/message/1040005"]').should( "contain", "An email containing a code has been sent to the email address you provided", ) cy.getRegistrationCodeFromEmail(email).should((code) => { - cy.get(`input[name=code]`).type(code) - cy.get("button[name=method][value=code]").click() + cy.get(Selectors[app]["code"]).type(code) + cy.get(Selectors[app]["submitCode"]).click() }) - cy.getSession().should((session) => { - const { identity } = session + if (app === "mobile") { + cy.get('[data-testid="session-token"]').then((token) => { + cy.getSession({ + expectAal: "aal1", + expectMethods: ["code"], + token: token.text(), + }).then((session) => { + cy.wrap(session).as("session") + }) + }) + + cy.get('[data-testid="session-content"]').should("contain", email) + cy.get('[data-testid="session-token"]').should("not.be.empty") + } else { + cy.getSession({ expectAal: "aal1", expectMethods: ["code"] }).then( + (session) => { + cy.wrap(session).as("session") + }, + ) + } + + cy.get("@session").then(({ identity }) => { expect(identity.id).to.not.be.empty expect(identity.verifiable_addresses).to.have.length(1) expect(identity.verifiable_addresses[0].status).to.equal("completed") @@ -116,31 +196,51 @@ context("Registration success with code method", () => { cy.setPostCodeRegistrationHooks([]) const email = gen.email() - cy.get(`input[name='traits.email']`).type(email) - cy.get(`[name='traits.tos'] + label`).click() + cy.get(Selectors[app]["email"]).type(email) + cy.get(Selectors[app]["tos"]).click() - cy.submitCodeForm() + cy.submitCodeForm(app) cy.get('[data-testid="ui/message/1040005"]').should( "contain", "An email containing a code has been sent to the email address you provided", ) cy.getRegistrationCodeFromEmail(email).should((code) => { - cy.get(`input[name=code]`).type(code) - cy.get("button[name=method][value=code]").click() + cy.get(Selectors[app]["code"]).type(code) + cy.get(Selectors[app]["submitCode"]).click() }) cy.visit(login) - cy.get(`input[name=identifier]`).type(email) - cy.get("button[name=method][value=code]").click() + cy.get(Selectors[app]["identifier"]).type(email) + cy.get(Selectors[app]["submitCode"]).click() cy.getLoginCodeFromEmail(email).then((code) => { - cy.get(`input[name=code]`).type(code) - cy.get("button[name=method][value=code]").click() + cy.get(Selectors[app]["code"]).type(code) + cy.get(Selectors[app]["submitCode"]).click() }) - cy.getSession().should((session) => { - const { identity } = session + if (app === "mobile") { + cy.get('[data-testid="session-token"]').then((token) => { + cy.getSession({ + expectAal: "aal1", + expectMethods: ["code"], + token: token.text(), + }).then((session) => { + cy.wrap(session).as("session") + }) + }) + + cy.get('[data-testid="session-content"]').should("contain", email) + cy.get('[data-testid="session-token"]').should("not.be.empty") + } else { + cy.getSession({ expectAal: "aal1", expectMethods: ["code"] }).then( + (session) => { + cy.wrap(session).as("session") + }, + ) + } + + cy.get("@session").then(({ identity }) => { expect(identity.id).to.not.be.empty expect(identity.verifiable_addresses).to.have.length(1) expect(identity.verifiable_addresses[0].status).to.equal("completed") @@ -149,20 +249,48 @@ context("Registration success with code method", () => { }) it("should be able to recover account when registered with code", () => { + if (app === "mobile") { + cy.log("WARNING: skipping test for mobile app") + return + } const email = gen.email() cy.registerWithCode({ email, traits: { "traits.tos": 1 } }) cy.clearAllCookies() cy.visit(recovery) - cy.get('input[name="email"]').type(email) - cy.get('button[name="method"][value="code"]').click() + cy.get(Selectors[app]["recoveryEmail"]).type(email) + cy.get(Selectors[app]["submitRecovery"]).click() - cy.recoveryEmailWithCode({ expect: { email } }) - cy.get('button[value="code"]').click() + cy.recoveryEmailWithCode({ expect: { email, enterCode: false } }).then( + () => { + cy.get("@recoveryCode").then((code) => { + cy.get(Selectors[app]["recoveryCode"]).type(code) + }) + }, + ) - cy.getSession().should((session) => { - const { identity } = session + cy.get(Selectors[app]["submitRecovery"]).click() + + if (app === "mobile") { + cy.get('[data-testid="session-token"]').then((token) => { + cy.getSession({ + expectAal: "aal1", + token: token.text(), + }).then((session) => { + cy.wrap(session).as("session") + }) + }) + + cy.get('[data-testid="session-content"]').should("contain", email) + cy.get('[data-testid="session-token"]').should("not.be.empty") + } else { + cy.getSession({ expectAal: "aal1" }).then((session) => { + cy.wrap(session).as("session") + }) + } + + cy.get("@session").then(({ identity }) => { expect(identity.id).to.not.be.empty expect(identity.traits.email).to.equal(email) }) @@ -183,15 +311,15 @@ context("Registration success with code method", () => { cy.visit(route) - cy.get(`input[name='traits.username']`).type(Math.random().toString(36)) + cy.get(Selectors[app]["username"]).type(Math.random().toString(36)) const email = gen.email() - cy.get(`input[name='traits.email']`).type(email) + cy.get(Selectors[app]["email"]).type(email) const email2 = gen.email() - cy.get(`input[name='traits.email2']`).type(email2) + cy.get(Selectors[app]["email2"]).type(email2) - cy.submitCodeForm() + cy.submitCodeForm(app) cy.get('[data-testid="ui/message/1040005"]').should( "contain", "An email containing a code has been sent to the email address you provided", @@ -200,12 +328,17 @@ context("Registration success with code method", () => { // intentionally use email 1 to sign up for the account cy.getRegistrationCodeFromEmail(email, { expectedCount: 1 }).should( (code) => { - cy.get(`input[name=code]`).type(code) - cy.get("button[name=method][value=code]").click() + cy.get(Selectors[app]["code"]).type(code) + cy.get(Selectors[app]["submitCode"]).click() }, ) - cy.logout() + if (app === "mobile") { + cy.visit(MOBILE_URL + "/Home") + cy.get('*[data-testid="logout"]').click() + } else { + cy.logout() + } // There are verification emails from the registration process in the inbox that we need to deleted // for the assertions below to pass. @@ -213,19 +346,39 @@ context("Registration success with code method", () => { // Attempt to sign in with email 2 (should fail) cy.visit(login) - cy.get(`input[name=identifier]`).type(email2) + cy.get(Selectors[app]["identifier"]).type(email2) - cy.get("button[name=method][value=code]").click() + cy.get(Selectors[app]["submitCode"]).click() cy.getLoginCodeFromEmail(email2, { expectedCount: 1, }).should((code) => { - cy.get(`input[name=code]`).type(code) - cy.get("button[name=method][value=code]").click() + cy.get(Selectors[app]["code"]).type(code) + cy.get(Selectors[app]["submitCode"]).click() }) - cy.getSession().should((session) => { - const { identity } = session + if (app === "mobile") { + cy.get('[data-testid="session-token"]').then((token) => { + cy.getSession({ + expectAal: "aal1", + expectMethods: ["code"], + token: token.text(), + }).then((session) => { + cy.wrap(session).as("session") + }) + }) + + cy.get('[data-testid="session-content"]').should("contain", email) + cy.get('[data-testid="session-token"]').should("not.be.empty") + } else { + cy.getSession({ expectAal: "aal1", expectMethods: ["code"] }).then( + (session) => { + cy.wrap(session).as("session") + }, + ) + } + + cy.get("@session").then(({ identity }) => { expect(identity.id).to.not.be.empty expect(identity.verifiable_addresses).to.have.length(2) expect( diff --git a/test/e2e/cypress/support/commands.ts b/test/e2e/cypress/support/commands.ts index 1db5571f2900..f8f2b7ad0615 100644 --- a/test/e2e/cypress/support/commands.ts +++ b/test/e2e/cypress/support/commands.ts @@ -1028,18 +1028,31 @@ Cypress.Commands.add("deleteMail", ({ atLeast = 0 } = {}) => { Cypress.Commands.add( "getSession", - ({ expectAal = "aal1", expectMethods = [] } = {}) => { + ({ expectAal = "aal1", expectMethods = [], token } = {}) => { // Do the request once to ensure we have a session (with retry) cy.request({ method: "GET", url: `${KRATOS_PUBLIC}/sessions/whoami`, + ...(token && { + auth: { + bearer: token, + }, + }), }) .its("status") // adds retry .should("eq", 200) // Return the session for further propagation return cy - .request("GET", `${KRATOS_PUBLIC}/sessions/whoami`) + .request({ + method: "GET", + url: `${KRATOS_PUBLIC}/sessions/whoami`, + ...(token && { + auth: { + bearer: token, + }, + }), + }) .then((response) => { expect(response.body.id).to.not.be.empty expect(dayjs().isBefore(dayjs(response.body.expires_at))).to.be.true @@ -1156,6 +1169,7 @@ Cypress.Commands.add( const code = extractRecoveryCode(message.body) expect(code).to.not.be.undefined expect(code.length).to.equal(6) + cy.wrap(code).as("recoveryCode") if (enterCode) { cy.get("input[name='code']").type(code) } @@ -1313,9 +1327,14 @@ Cypress.Commands.add("submitProfileForm", () => { cy.get('[name="method"][value="profile"]:disabled').should("not.exist") }) -Cypress.Commands.add("submitCodeForm", () => { - cy.get('button[name="method"][value="code"]').click() - cy.get('button[name="method"][value="code"]:disabled').should("not.exist") +Cypress.Commands.add("submitCodeForm", (app) => { + if (app === "mobile") { + cy.get('[data-testid="field/method/code"]').click() + cy.get('[data-testid="field/method/code"]:disabled').should("not.exist") + } else { + cy.get('button[name="method"][value="code"]').click() + cy.get('button[name="method"][value="code"]:disabled').should("not.exist") + } }) Cypress.Commands.add("clickWebAuthButton", (type: string) => { diff --git a/test/e2e/cypress/support/index.d.ts b/test/e2e/cypress/support/index.d.ts index 180e93260c41..1792db4a51cc 100644 --- a/test/e2e/cypress/support/index.d.ts +++ b/test/e2e/cypress/support/index.d.ts @@ -40,6 +40,7 @@ declare global { expectMethods?: Array< "password" | "webauthn" | "lookup_secret" | "totp" | "code" > + token?: string }): Chainable /** @@ -362,7 +363,7 @@ declare global { /** * Submits a code form by clicking the button with method=code */ - submitCodeForm(): Chainable + submitCodeForm(app: "mobile" | "express" | "react"): Chainable /** * Expect a CSRF error to occur diff --git a/test/e2e/run.sh b/test/e2e/run.sh index cb2d813ddad0..a5b405fe1d2e 100755 --- a/test/e2e/run.sh +++ b/test/e2e/run.sh @@ -204,31 +204,23 @@ prepare() { 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" - PORT=4456 SECURITY_MODE=cookie npm run serve \ - >"${base}/test/e2e/ui-node.e2e.log" 2>&1 & - ) - else - ( - cd "$node_ui_dir" - PORT=4456 SECURITY_MODE=cookie npm run start \ - >"${base}/test/e2e/ui-node.e2e.log" 2>&1 & - ) - fi + ( + cd "$node_ui_dir" + PORT=4456 SECURITY_MODE=cookie npm run start \ + >"${base}/test/e2e/ui-node.e2e.log" 2>&1 & + ) if [ -z ${REACT_UI_PATH+x} ]; then ( cd "$react_ui_dir" - ORY_KRATOS_URL=http://localhost:4433 npm run build - ORY_KRATOS_URL=http://localhost:4433 npm run start -- --hostname 0.0.0.0 --port 4458 \ + NEXT_PUBLIC_KRATOS_PUBLIC_URL=http://localhost:4433 npm run build + NEXT_PUBLIC_KRATOS_PUBLIC_URL=http://localhost:4433 npm run start -- --hostname 127.0.0.1 --port 4458 \ >"${base}/test/e2e/react-iu.e2e.log" 2>&1 & ) else ( cd "$react_ui_dir" - PORT=4458 ORY_KRATOS_URL=http://localhost:4433 npm run dev \ + PORT=4458 NEXT_PUBLIC_KRATOS_PUBLIC_URL=http://localhost:4433 npm run dev \ >"${base}/test/e2e/react-iu.e2e.log" 2>&1 & ) fi From 33fc9306a2c98f65db99500369fb4c9e3d45016c Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Mon, 2 Oct 2023 14:16:29 +0000 Subject: [PATCH 118/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42b008153523..a71778c57b37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -631,6 +631,9 @@ https://github.com/ory/kratos/pull/3480 - Improve performance by computing password hashes while validating ([#3508](https://github.com/ory/kratos/issues/3508)) ([a9786c5](https://github.com/ory/kratos/commit/a9786c599d09f61e2e07df5066ce94feb2d99bac)) +- One-time code native flows + ([#3516](https://github.com/ory/kratos/issues/3516)) + ([9b0fee3](https://github.com/ory/kratos/commit/9b0fee30f980d860fd548e7589fa6a06e593537a)) - Passwordless browser login and registration via code to email ([#3378](https://github.com/ory/kratos/issues/3378)) ([eaaf375](https://github.com/ory/kratos/commit/eaaf37519917612671238412a633847386d7c613)), From 1b3647c2acdad966f920c2b9e6e657c52aa50c6e Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Wed, 4 Oct 2023 14:04:00 +0200 Subject: [PATCH 119/282] fix: use org ID from session if available in login flow (#3545) --- selfservice/flow/login/handler.go | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/selfservice/flow/login/handler.go b/selfservice/flow/login/handler.go index e965d9758025..9efb5f0844db 100644 --- a/selfservice/flow/login/handler.go +++ b/selfservice/flow/login/handler.go @@ -189,15 +189,27 @@ preLoginHook: } var strategyFilters []StrategyFilter + orgID := uuid.NullUUID{ + Valid: false, + } if rawOrg := r.URL.Query().Get("organization"); rawOrg != "" { - orgID, err := uuid.FromString(rawOrg) + orgIDFromURL, err := uuid.FromString(rawOrg) if err != nil { h.d.Logger().WithError(err).Warnf("Ignoring invalid UUID %q in query parameter `organization`.", rawOrg) } else { - f.OrganizationID = uuid.NullUUID{UUID: orgID, Valid: true} - strategyFilters = []StrategyFilter{func(s Strategy) bool { return s.ID() == identity.CredentialsTypeOIDC }} + orgID = uuid.NullUUID{UUID: orgIDFromURL, Valid: true} } } + + if sess != nil && sess.Identity != nil && sess.Identity.OrganizationID.Valid { + orgID = sess.Identity.OrganizationID + } + + if orgID.Valid { + f.OrganizationID = orgID + strategyFilters = []StrategyFilter{func(s Strategy) bool { return s.ID() == identity.CredentialsTypeOIDC }} + } + for _, s := range h.d.LoginStrategies(r.Context(), strategyFilters...) { if err := s.PopulateLoginMethod(r, f.RequestedAAL, f); err != nil { return nil, nil, err From 95dc7a20f49aa682f324b70e507ec56c20159ebb Mon Sep 17 00:00:00 2001 From: Christian <57273861+cpoyatos1@users.noreply.github.com> Date: Wed, 4 Oct 2023 15:48:26 +0200 Subject: [PATCH 120/282] fix: add value code to authentication method enum (#3546) * fix: add value code to authentication method enum * chore: generate sdk --------- Co-authored-by: Alano Terblanche <18033717+Benehiko@users.noreply.github.com> --- .schema/openapi/patches/session.yaml | 1 + spec/api.json | 1 + 2 files changed, 2 insertions(+) diff --git a/.schema/openapi/patches/session.yaml b/.schema/openapi/patches/session.yaml index cc6387e1407e..bdc2f1d974b9 100644 --- a/.schema/openapi/patches/session.yaml +++ b/.schema/openapi/patches/session.yaml @@ -20,6 +20,7 @@ - link_recovery - code_recovery - password + - code - totp - oidc - webauthn diff --git a/spec/api.json b/spec/api.json index 92fce7914e85..24b8c33a63f6 100644 --- a/spec/api.json +++ b/spec/api.json @@ -1773,6 +1773,7 @@ "link_recovery", "code_recovery", "password", + "code", "totp", "oidc", "webauthn", From 8a0e4969a0af41d14692621923307a5f38382270 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Wed, 4 Oct 2023 14:49:29 +0000 Subject: [PATCH 121/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a71778c57b37..46468270b7b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-10-02)](#2023-10-02) +- [ (2023-10-04)](#2023-10-04) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -313,7 +313,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-10-02) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-10-04) ## Breaking Changes @@ -364,6 +364,14 @@ https://github.com/ory/kratos/pull/3480 - Add missing tracing & attributes in oidc strategy ([#3429](https://github.com/ory/kratos/issues/3429)) ([09bcb71](https://github.com/ory/kratos/commit/09bcb71f1f0b3238e2d0f4376a1a2290d062c6c1)) +- Add value code to authentication method enum + ([#3546](https://github.com/ory/kratos/issues/3546)) + ([95dc7a2](https://github.com/ory/kratos/commit/95dc7a20f49aa682f324b70e507ec56c20159ebb)): + + - fix: add value code to authentication method enum + + - chore: generate sdk + - Allow post recovery hooks to interrupt the flow ([#3393](https://github.com/ory/kratos/issues/3393)) ([6c1d2f1](https://github.com/ory/kratos/commit/6c1d2f1e4173cfb9a7abe2bfe4f20e47b7568d3b)) @@ -467,6 +475,9 @@ https://github.com/ory/kratos/pull/3480 ([bee0341](https://github.com/ory/kratos/commit/bee0341c5bf5708a2210146fc59f050a1b9df663)) - Type-assert all interfaces that WebHook implements ([ffda1a0](https://github.com/ory/kratos/commit/ffda1a0dab661c5f11ad849b9287094313561b79)) +- Use org ID from session if available in login flow + ([#3545](https://github.com/ory/kratos/issues/3545)) + ([1b3647c](https://github.com/ory/kratos/commit/1b3647c2acdad966f920c2b9e6e657c52aa50c6e)) - Use registry client for schema loading ([#3471](https://github.com/ory/kratos/issues/3471)) ([3a57726](https://github.com/ory/kratos/commit/3a577269980213e4415fd5fa713882990e2e7640)) From df80377f5fe6180fba5904baa5be1ba1d68eb2aa Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Fri, 6 Oct 2023 12:11:27 +0200 Subject: [PATCH 122/282] fix: using first name as last name (#3556) --- selfservice/strategy/oidc/provider_apple.go | 10 ++++++---- selfservice/strategy/oidc/provider_apple_test.go | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/selfservice/strategy/oidc/provider_apple.go b/selfservice/strategy/oidc/provider_apple.go index 9a83429152d3..27dd2b7e6635 100644 --- a/selfservice/strategy/oidc/provider_apple.go +++ b/selfservice/strategy/oidc/provider_apple.go @@ -139,13 +139,15 @@ func (a *ProviderApple) DecodeQuery(query url.Values, claims *Claims) { if claims.GivenName == "" { claims.GivenName = *firstName } + } + if lastName := name.LastName; lastName != nil { + if claims.LastName == "" { + claims.LastName = *lastName + } if claims.FamilyName == "" { - claims.FamilyName = *firstName + claims.FamilyName = *lastName } } - if lastName := name.LastName; lastName != nil && claims.LastName == "" { - claims.LastName = *lastName - } } } } diff --git a/selfservice/strategy/oidc/provider_apple_test.go b/selfservice/strategy/oidc/provider_apple_test.go index a1d754fdb48d..69d5dfd44b69 100644 --- a/selfservice/strategy/oidc/provider_apple_test.go +++ b/selfservice/strategy/oidc/provider_apple_test.go @@ -33,7 +33,7 @@ func TestDecodeQuery(t *testing.T) { givenName string lastName string }{ - {claims: &oidc.Claims{}, familyName: "first", givenName: "first", lastName: "last"}, + {claims: &oidc.Claims{}, familyName: "last", givenName: "first", lastName: "last"}, {claims: &oidc.Claims{FamilyName: "fam"}, familyName: "fam", givenName: "first", lastName: "last"}, {claims: &oidc.Claims{FamilyName: "fam", GivenName: "giv"}, familyName: "fam", givenName: "giv", lastName: "last"}, {claims: &oidc.Claims{FamilyName: "fam", GivenName: "giv", LastName: "las"}, familyName: "fam", givenName: "giv", lastName: "las"}, From d138abb6278ebb232e120bee0fb956a0f2816b8d Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Fri, 6 Oct 2023 12:13:44 +0200 Subject: [PATCH 123/282] fix: remove slow queries from update identities (#3553) --- go.mod | 5 ++-- go.sum | 8 +++---- .../sql/identity/persister_identity.go | 11 +++------ persistence/sql/update/update.go | 24 ++++++------------- script/testenv.sh | 2 +- 5 files changed, 17 insertions(+), 33 deletions(-) diff --git a/go.mod b/go.mod index dd4618fbb2b1..3b98b3d283ac 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,7 @@ go 1.19 replace ( github.com/bradleyjkemp/cupaloy/v2 => github.com/aeneasr/cupaloy/v2 v2.6.1-0.20210924214125-3dfdd01210a3 - github.com/go-sql-driver/mysql => github.com/go-sql-driver/mysql v1.7.0 - + github.com/go-sql-driver/mysql => github.com/go-sql-driver/mysql v1.7.2-0.20231005084435-37980127edfb github.com/gorilla/sessions => github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2 github.com/mattn/go-sqlite3 => github.com/mattn/go-sqlite3 v1.14.7-0.20210414154423-1157a4212dcb @@ -78,7 +77,7 @@ require ( github.com/ory/jsonschema/v3 v3.0.8 github.com/ory/mail/v3 v3.0.0 github.com/ory/nosurf v1.2.7 - github.com/ory/x v0.0.589 + github.com/ory/x v0.0.590 github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 github.com/pkg/errors v0.9.1 github.com/pquerna/otp v1.4.0 diff --git a/go.sum b/go.sum index fb96c9cdac9f..1493216aec55 100644 --- a/go.sum +++ b/go.sum @@ -282,8 +282,8 @@ github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD87 github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= -github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= -github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/go-sql-driver/mysql v1.7.2-0.20231005084435-37980127edfb h1:R5sscofA9Cyd0h2DNMbR8BHYVKj1ZTOgUah1PoU4OVU= +github.com/go-sql-driver/mysql v1.7.2-0.20231005084435-37980127edfb/go.mod h1:6gYm/zDt3ahdnMVTPeT/LfoBFsws1qZm5yI6FmVjB14= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/go-swagger/go-swagger v0.30.3 h1:HuzvdMRed/9Q8vmzVcfNBQByZVtT79DNZxZ18OprdoI= @@ -847,8 +847,8 @@ github.com/ory/nosurf v1.2.7 h1:YrHrbSensQyU6r6HT/V5+HPdVEgrOTMJiLoJABSBOp4= github.com/ory/nosurf v1.2.7/go.mod h1:d4L3ZBa7Amv55bqxCBtCs63wSlyaiCkWVl4vKf3OUxA= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2 h1:zm6sDvHy/U9XrGpixwHiuAwpp0Ock6khSVHkrv6lQQU= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/ory/x v0.0.589 h1:ZNQ+nBzTCm3jI2ZZY/1kGWSE4jEtyvDYWu0ScfLgzac= -github.com/ory/x v0.0.589/go.mod h1:ksLBEd6iW6czGpE6eNA0gCIxO1FFeqIxCZgsgwNrzMM= +github.com/ory/x v0.0.590 h1:t0+XlSlDw5pzZhdAxOB8uFp1Dp+MStPRTG8Nn/fm1PE= +github.com/ory/x v0.0.590/go.mod h1:ksLBEd6iW6czGpE6eNA0gCIxO1FFeqIxCZgsgwNrzMM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= diff --git a/persistence/sql/identity/persister_identity.go b/persistence/sql/identity/persister_identity.go index 99469f365f1b..3e8335c8027a 100644 --- a/persistence/sql/identity/persister_identity.go +++ b/persistence/sql/identity/persister_identity.go @@ -311,7 +311,6 @@ func updateAssociation[T interface { var inDB []T if err := p.GetConnection(ctx). Where("identity_id = ? AND nid = ?", i.ID, p.NetworkID(ctx)). - Order("id ASC"). All(&inDB); err != nil { return sqlcon.HandleError(err) } @@ -791,16 +790,16 @@ func (p *IdentityPersister) UpdateIdentity(ctx context.Context, i *identity.Iden i.NID = p.NetworkID(ctx) return sqlcon.HandleError(p.Transaction(ctx, func(ctx context.Context, tx *pop.Connection) error { - if count, err := tx.Where("id = ? AND nid = ?", i.ID, p.NetworkID(ctx)).Count(i); err != nil { + // This returns "ErrNoRows" if the identity does not exist + if err := update.Generic(WithTransaction(ctx, tx), tx, p.r.Tracer(ctx).Tracer(), i); err != nil { return err - } else if count == 0 { - return sql.ErrNoRows } p.normalizeAllAddressess(ctx, i) if err := updateAssociation(ctx, p, i, i.RecoveryAddresses); err != nil { return err } + if err := updateAssociation(ctx, p, i, i.VerifiableAddresses); err != nil { return err } @@ -814,10 +813,6 @@ func (p *IdentityPersister) UpdateIdentity(ctx context.Context, i *identity.Iden return sqlcon.HandleError(err) } - if err := update.Generic(WithTransaction(ctx, tx), tx, p.r.Tracer(ctx).Tracer(), i); err != nil { - return err - } - return sqlcon.HandleError(p.createIdentityCredentials(ctx, tx, i)) })) } diff --git a/persistence/sql/update/update.go b/persistence/sql/update/update.go index 2d7582060f8e..27bdf2c9cc93 100644 --- a/persistence/sql/update/update.go +++ b/persistence/sql/update/update.go @@ -42,22 +42,7 @@ func Generic(ctx context.Context, c *pop.Connection, tracer trace.Tracer, v Mode } //#nosec G201 -- TableName is static - stmt := fmt.Sprintf("SELECT COUNT(id) FROM %s AS %s WHERE %s.id = ? AND %s.nid = ?", - quoter.Quote(model.TableName()), - model.Alias(), - model.Alias(), - model.Alias(), - ) - - var count int - if err := c.Store.GetContext(ctx, &count, c.Dialect.TranslateSQL(stmt), v.GetID(), v.GetNID()); err != nil { - return sqlcon.HandleError(err) - } else if count == 0 { - return errors.WithStack(sqlcon.ErrNoRows) - } - - //#nosec G201 -- TableName is static - stmt = fmt.Sprintf("UPDATE %s AS %s SET %s WHERE %s AND %s.nid = :nid", + stmt := fmt.Sprintf("UPDATE %s AS %s SET %s WHERE %s AND %s.nid = :nid", quoter.Quote(model.TableName()), model.Alias(), cols.Writeable().QuotedUpdateString(quoter), @@ -65,8 +50,13 @@ func Generic(ctx context.Context, c *pop.Connection, tracer trace.Tracer, v Mode model.Alias(), ) - if _, err := c.Store.NamedExecContext(ctx, stmt, v); err != nil { + if result, err := c.Store.NamedExecContext(ctx, stmt, v); err != nil { return sqlcon.HandleError(err) + } else if affected, err := result.RowsAffected(); err != nil { + return sqlcon.HandleError(err) + } else if affected == 0 { + return errors.WithStack(sqlcon.ErrNoRows) } + return nil } diff --git a/script/testenv.sh b/script/testenv.sh index f7a5467a0f7f..671c5abc1b43 100755 --- a/script/testenv.sh +++ b/script/testenv.sh @@ -1,7 +1,7 @@ #!/bin/bash docker rm -f kratos_test_database_mysql kratos_test_database_postgres kratos_test_database_cockroach kratos_test_hydra || true -docker run --platform linux/amd64 --name kratos_test_database_mysql -p 3444:3306 -e MYSQL_ROOT_PASSWORD=secret -d mysql:8.0.26 +docker run --platform linux/amd64 --name kratos_test_database_mysql -p 3444:3306 -e MYSQL_ROOT_PASSWORD=secret -d mysql:8.0.34 docker run --platform linux/amd64 --name kratos_test_database_postgres -p 3445:5432 -e POSTGRES_PASSWORD=secret -e POSTGRES_DB=postgres -d postgres:11.8 postgres -c log_statement=all docker run --platform linux/amd64 --name kratos_test_database_cockroach -p 3446:26257 -p 3447:8080 -d cockroachdb/cockroach:v22.2.6 start-single-node --insecure docker run --platform linux/amd64 --name kratos_test_hydra -p 4444:4444 -p 4445:4445 -d -e DSN=memory -e URLS_SELF_ISSUER=http://localhost:4444/ -e URLS_LOGIN=http://localhost:4446/login -e URLS_CONSENT=http://localhost:4446/consent oryd/hydra:v2.0.2 serve all --dev From 043114bb7740c3aa1f4ccb9143d58f7137ef186f Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Fri, 6 Oct 2023 11:22:54 +0000 Subject: [PATCH 124/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46468270b7b5..21a1aaeaf777 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-10-04)](#2023-10-04) +- [ (2023-10-06)](#2023-10-06) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -313,7 +313,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-10-04) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-10-06) ## Breaking Changes @@ -468,6 +468,9 @@ https://github.com/ory/kratos/pull/3480 - Remove requirement for smtp section ([#3405](https://github.com/ory/kratos/issues/3405)) ([59a3f14](https://github.com/ory/kratos/commit/59a3f1469b8412e49846a500493cb02fc6eb34b1)) +- Remove slow queries from update identities + ([#3553](https://github.com/ory/kratos/issues/3553)) + ([d138abb](https://github.com/ory/kratos/commit/d138abb6278ebb232e120bee0fb956a0f2816b8d)) - Return 400 bad request for invalid login challenge ([#3404](https://github.com/ory/kratos/issues/3404)) ([ca34e9b](https://github.com/ory/kratos/commit/ca34e9b744482b41d65082f3bed52e9c4ebd7ba4)) @@ -481,6 +484,9 @@ https://github.com/ory/kratos/pull/3480 - Use registry client for schema loading ([#3471](https://github.com/ory/kratos/issues/3471)) ([3a57726](https://github.com/ory/kratos/commit/3a577269980213e4415fd5fa713882990e2e7640)) +- Using first name as last name + ([#3556](https://github.com/ory/kratos/issues/3556)) + ([df80377](https://github.com/ory/kratos/commit/df80377f5fe6180fba5904baa5be1ba1d68eb2aa)) - Wrong continue_with enum declaration ([#3522](https://github.com/ory/kratos/issues/3522)) ([4c34c24](https://github.com/ory/kratos/commit/4c34c2417db0cb1f79b42db5f33544c90b38ad87)) From 9eff0f3a611f32af7aa7f27587b3d3f4448ce915 Mon Sep 17 00:00:00 2001 From: Henning Perl Date: Mon, 9 Oct 2023 12:14:12 +0200 Subject: [PATCH 125/282] fix: ui node input attributes key added (#3561) * fix: ui node InputAttributes.Key added * fix: selfservice recovery flow add React unique key and numeric pattern * fix: remove React related key addition * test: update snapshot --------- Co-authored-by: Misa Munde --- ...t_all_the_correct_recovery_payloads_after_submission.json | 1 + selfservice/strategy/code/strategy_recovery.go | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/selfservice/strategy/code/.snapshots/TestRecovery-description=should_set_all_the_correct_recovery_payloads_after_submission.json b/selfservice/strategy/code/.snapshots/TestRecovery-description=should_set_all_the_correct_recovery_payloads_after_submission.json index 36fe7b033ce7..dbf1dcd2cbb7 100644 --- a/selfservice/strategy/code/.snapshots/TestRecovery-description=should_set_all_the_correct_recovery_payloads_after_submission.json +++ b/selfservice/strategy/code/.snapshots/TestRecovery-description=should_set_all_the_correct_recovery_payloads_after_submission.json @@ -19,6 +19,7 @@ "name": "code", "type": "text", "required": true, + "pattern": "[0-9]+", "disabled": false, "node_type": "input" }, diff --git a/selfservice/strategy/code/strategy_recovery.go b/selfservice/strategy/code/strategy_recovery.go index e4b6fae22c55..0bdc2d603801 100644 --- a/selfservice/strategy/code/strategy_recovery.go +++ b/selfservice/strategy/code/strategy_recovery.go @@ -542,7 +542,10 @@ func (s *Strategy) recoveryHandleFormSubmission(w http.ResponseWriter, r *http.R f.Active = sqlxx.NullString(s.NodeGroup()) f.State = flow.StateEmailSent f.UI.Messages.Set(text.NewRecoveryEmailWithCodeSent()) - f.UI.Nodes.Append(node.NewInputField("code", nil, node.CodeGroup, node.InputAttributeTypeText, node.WithRequiredInputAttribute). + f.UI.Nodes.Append(node.NewInputField("code", nil, node.CodeGroup, node.InputAttributeTypeText, node.WithInputAttributes(func(a *node.InputAttributes) { + a.Required = true + a.Pattern = "[0-9]+" + })). WithMetaLabel(text.NewInfoNodeLabelRecoveryCode()), ) f.UI.Nodes.Append(node.NewInputField("method", s.NodeGroup(), node.CodeGroup, node.InputAttributeTypeHidden)) From e9ed14fdbcc7bbe658471adfdf1693e8a16f60c7 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Mon, 9 Oct 2023 11:36:11 +0000 Subject: [PATCH 126/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21a1aaeaf777..34423f9d356e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-10-06)](#2023-10-06) +- [ (2023-10-09)](#2023-10-09) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -313,7 +313,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-10-06) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-10-09) ## Breaking Changes @@ -478,6 +478,18 @@ https://github.com/ory/kratos/pull/3480 ([bee0341](https://github.com/ory/kratos/commit/bee0341c5bf5708a2210146fc59f050a1b9df663)) - Type-assert all interfaces that WebHook implements ([ffda1a0](https://github.com/ory/kratos/commit/ffda1a0dab661c5f11ad849b9287094313561b79)) +- Ui node input attributes key added + ([#3561](https://github.com/ory/kratos/issues/3561)) + ([9eff0f3](https://github.com/ory/kratos/commit/9eff0f3a611f32af7aa7f27587b3d3f4448ce915)): + + - fix: ui node InputAttributes.Key added + + - fix: selfservice recovery flow add React unique key and numeric pattern + + - fix: remove React related key addition + + - test: update snapshot + - Use org ID from session if available in login flow ([#3545](https://github.com/ory/kratos/issues/3545)) ([1b3647c](https://github.com/ory/kratos/commit/1b3647c2acdad966f920c2b9e6e657c52aa50c6e)) From 05de3a29fed020593c44ea7a7b29e45197fef4f7 Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Tue, 10 Oct 2023 09:51:10 +0200 Subject: [PATCH 127/282] test: reduce logging in go tests (#3562) --- driver/registry.go | 21 ++++++++++++++------- driver/registry_default.go | 2 +- internal/driver.go | 2 +- persistence/sql/persister.go | 36 +++++++++++++++++++++++++++++++++--- 4 files changed, 49 insertions(+), 12 deletions(-) diff --git a/driver/registry.go b/driver/registry.go index 3040951d9726..31a3f650a62a 100644 --- a/driver/registry.go +++ b/driver/registry.go @@ -180,13 +180,14 @@ func NewRegistryFromDSN(ctx context.Context, c *config.Config, l *logrusx.Logger } type options struct { - skipNetworkInit bool - config *config.Config - replaceTracer func(*otelx.Tracer) *otelx.Tracer - inspect func(Registry) error - extraMigrations []fs.FS - replacementStrategies []NewStrategy - extraHooks map[string]func(config.SelfServiceHook) any + skipNetworkInit bool + config *config.Config + replaceTracer func(*otelx.Tracer) *otelx.Tracer + inspect func(Registry) error + extraMigrations []fs.FS + replacementStrategies []NewStrategy + extraHooks map[string]func(config.SelfServiceHook) any + disableMigrationLogging bool } type RegistryOption func(*options) @@ -236,6 +237,12 @@ func WithExtraMigrations(m ...fs.FS) RegistryOption { } } +func WithDisabledMigrationLogging() RegistryOption { + return func(o *options) { + o.disableMigrationLogging = true + } +} + func newOptions(os []RegistryOption) *options { o := new(options) for _, f := range os { diff --git a/driver/registry_default.go b/driver/registry_default.go index 68c460e5297c..f9c47bb30739 100644 --- a/driver/registry_default.go +++ b/driver/registry_default.go @@ -680,7 +680,7 @@ func (m *RegistryDefault) Init(ctx context.Context, ctxer contextx.Contextualize m.Logger().WithError(err).Warnf("Unable to open database, retrying.") return errors.WithStack(err) } - p, err := sql.NewPersister(ctx, m, c, o.extraMigrations...) + p, err := sql.NewPersister(ctx, m, c, sql.WithExtraMigrations(o.extraMigrations...), sql.WithDisabledLogging(o.disableMigrationLogging)) if err != nil { m.Logger().WithError(err).Warnf("Unable to initialize persister, retrying.") return err diff --git a/internal/driver.go b/internal/driver.go index 2eb79e708016..739afe03dc3a 100644 --- a/internal/driver.go +++ b/internal/driver.go @@ -81,7 +81,7 @@ func NewRegistryDefaultWithDSN(t testing.TB, dsn string) (*config.Config, *drive reg, err := driver.NewRegistryFromDSN(ctx, c, logrusx.New("", "")) require.NoError(t, err) reg.Config().MustSet(ctx, "dev", true) - require.NoError(t, reg.Init(context.Background(), &contextx.Default{}, driver.SkipNetworkInit)) + require.NoError(t, reg.Init(context.Background(), &contextx.Default{}, driver.SkipNetworkInit, driver.WithDisabledMigrationLogging())) require.NoError(t, reg.Persister().MigrateUp(context.Background())) // always migrate up actual, err := reg.Persister().DetermineNetwork(context.Background()) diff --git a/persistence/sql/persister.go b/persistence/sql/persister.go index f14abd7a557d..82df92a72314 100644 --- a/persistence/sql/persister.go +++ b/persistence/sql/persister.go @@ -13,6 +13,7 @@ import ( "github.com/gofrs/uuid" "github.com/laher/mergefs" "github.com/pkg/errors" + "github.com/sirupsen/logrus/hooks/test" "github.com/ory/kratos/driver/config" "github.com/ory/kratos/identity" @@ -23,6 +24,7 @@ import ( "github.com/ory/kratos/session" "github.com/ory/kratos/x" "github.com/ory/x/contextx" + "github.com/ory/x/logrusx" "github.com/ory/x/networkx" "github.com/ory/x/popx" ) @@ -54,17 +56,45 @@ type ( } ) -func NewPersister(ctx context.Context, r persisterDependencies, c *pop.Connection, extraMigrations ...fs.FS) (*Persister, error) { +type persisterOptions struct { + extraMigrations []fs.FS + disableLogging bool +} + +type persisterOption func(o *persisterOptions) + +func WithExtraMigrations(fss ...fs.FS) persisterOption { + return func(o *persisterOptions) { + o.extraMigrations = fss + } +} + +func WithDisabledLogging(v bool) persisterOption { + return func(o *persisterOptions) { + o.disableLogging = v + } +} + +func NewPersister(ctx context.Context, r persisterDependencies, c *pop.Connection, opts ...persisterOption) (*Persister, error) { + o := &persisterOptions{} + for _, f := range opts { + f(o) + } + logger := r.Logger() + if o.disableLogging { + inner, _ := test.NewNullLogger() + logger = logrusx.New("kratos", "", logrusx.UseLogger(inner)) + } m, err := popx.NewMigrationBox( mergefs.Merge( append( []fs.FS{ migrations, networkx.Migrations, }, - extraMigrations..., + o.extraMigrations..., )..., ), - popx.NewMigrator(c, r.Logger(), r.Tracer(ctx), 0), + popx.NewMigrator(c, logger, r.Tracer(ctx), 0), ) if err != nil { return nil, err From 5fc88baefcce476069138ed4e9c57b540be5f024 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Tue, 10 Oct 2023 08:57:26 +0000 Subject: [PATCH 128/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34423f9d356e..03b32ad3adf7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-10-09)](#2023-10-09) +- [ (2023-10-10)](#2023-10-10) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -313,7 +313,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-10-09) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-10-10) ## Breaking Changes @@ -734,6 +734,9 @@ https://github.com/ory/kratos/pull/3480 - Fix e2e failures and speed up e2e tests ([#3483](https://github.com/ory/kratos/issues/3483)) ([70a6171](https://github.com/ory/kratos/commit/70a617194d61763f4b75691b22cfa76ba71ab019)) +- Reduce logging in go tests + ([#3562](https://github.com/ory/kratos/issues/3562)) + ([05de3a2](https://github.com/ory/kratos/commit/05de3a29fed020593c44ea7a7b29e45197fef4f7)) - Resolve cypress issues ([#3531](https://github.com/ory/kratos/issues/3531)) ([4206d26](https://github.com/ory/kratos/commit/4206d2605dfa30b19e132be31b85b1a35f8dca78)) From e8b92c18bd6a801a8f0ab0d42159a5535eceb953 Mon Sep 17 00:00:00 2001 From: Patrik Date: Tue, 10 Oct 2023 12:08:20 +0200 Subject: [PATCH 129/282] chore: add more tracing to post-flow hooks (#3566) --- selfservice/flow/login/hook.go | 16 +++++- selfservice/flow/registration/hook.go | 30 +++++++++-- x/http_secure_redirect.go | 2 +- x/http_secure_redirect_test.go | 78 +++++++++++++++------------ 4 files changed, 88 insertions(+), 38 deletions(-) diff --git a/selfservice/flow/login/hook.go b/selfservice/flow/login/hook.go index b8ce1d15d3b0..69a00232b992 100644 --- a/selfservice/flow/login/hook.go +++ b/selfservice/flow/login/hook.go @@ -9,6 +9,7 @@ import ( "net/http" "time" + "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" "github.com/ory/kratos/x/events" @@ -145,6 +146,11 @@ func (e *HookExecutor) PostLoginHook( if err != nil { return err } + span.SetAttributes(otelx.StringAttrs(map[string]string{ + "return_to": returnTo.String(), + "flow_type": string(flow.TypeBrowser), + "redirect_reason": "login successful", + })...) classified := s s = s.Declassified() @@ -165,6 +171,9 @@ func (e *HookExecutor) PostLoginHook( WithField("identity_id", i.ID). WithField("flow_method", a.Active). Debug("A ExecuteLoginPostHook hook aborted early.") + + span.SetAttributes(attribute.String("redirect_reason", "aborted by hook"), attribute.String("executor", fmt.Sprintf("%T", executor))) + return nil } return e.handleLoginError(w, r, g, a, i, err) @@ -181,6 +190,7 @@ func (e *HookExecutor) PostLoginHook( } if a.Type == flow.TypeAPI { + span.SetAttributes(attribute.String("flow_type", string(flow.TypeAPI))) if err := e.d.SessionPersister().UpsertSession(r.Context(), s); err != nil { return errors.WithStack(err) } @@ -190,7 +200,7 @@ func (e *HookExecutor) PostLoginHook( WithField("identity_id", i.ID). Info("Identity authenticated successfully and was issued an Ory Kratos Session Token.") - trace.SpanFromContext(r.Context()).AddEvent(events.NewLoginSucceeded(r.Context(), &events.LoginSucceededOpts{ + span.AddEvent(events.NewLoginSucceeded(r.Context(), &events.LoginSucceededOpts{ SessionID: s.ID, IdentityID: i.ID, FlowType: string(a.Type), @@ -235,6 +245,8 @@ func (e *HookExecutor) PostLoginHook( })) if x.IsJSONRequest(r) { + span.SetAttributes(attribute.String("flow_type", "spa")) + // Browser flows rely on cookies. Adding tokens in the mix will confuse consumers. s.Token = "" @@ -251,6 +263,7 @@ func (e *HookExecutor) PostLoginHook( if err != nil { return err } + span.SetAttributes(attribute.String("return_to", postChallengeURL), attribute.String("redirect_reason", "oauth2 login challenge")) e.d.Writer().WriteError(w, r, flow.NewBrowserLocationChangeRequiredError(postChallengeURL)) return nil } @@ -286,6 +299,7 @@ func (e *HookExecutor) PostLoginHook( return err } finalReturnTo = rt + span.SetAttributes(attribute.String("return_to", rt), attribute.String("redirect_reason", "oauth2 login challenge")) } x.ContentNegotiationRedirection(w, r, s, e.d.Writer(), finalReturnTo) diff --git a/selfservice/flow/registration/hook.go b/selfservice/flow/registration/hook.go index 20538ccfe1e6..f7a7fed1d99f 100644 --- a/selfservice/flow/registration/hook.go +++ b/selfservice/flow/registration/hook.go @@ -9,8 +9,11 @@ import ( "net/http" "time" + "go.opentelemetry.io/otel/attribute" + + "github.com/ory/x/otelx" + "github.com/julienschmidt/httprouter" - "go.opentelemetry.io/otel/trace" "github.com/ory/kratos/selfservice/sessiontokenexchange" "github.com/ory/kratos/x/events" @@ -81,6 +84,7 @@ type ( x.HTTPClientProvider x.LoggingProvider x.WriterProvider + x.TracingProvider sessiontokenexchange.PersistenceProvider } HookExecutor struct { @@ -95,7 +99,12 @@ func NewHookExecutor(d executorDependencies) *HookExecutor { return &HookExecutor{d: d} } -func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Request, ct identity.CredentialsType, provider string, a *Flow, i *identity.Identity) error { +func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Request, ct identity.CredentialsType, provider string, a *Flow, i *identity.Identity) (err error) { + ctx := r.Context() + ctx, span := e.d.Tracer(ctx).Tracer().Start(ctx, "HookExecutor.PostRegistrationHook") + r = r.WithContext(ctx) + defer otelx.End(span, &err) + e.d.Logger(). WithRequest(r). WithField("identity_id", i.ID). @@ -159,13 +168,18 @@ func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Reque if err != nil { return err } + span.SetAttributes(otelx.StringAttrs(map[string]string{ + "return_to": returnTo.String(), + "flow_type": string(flow.TypeBrowser), + "redirect_reason": "registration successful", + })...) e.d.Audit(). WithRequest(r). WithField("identity_id", i.ID). Info("A new identity has registered using self-service registration.") - trace.SpanFromContext(r.Context()).AddEvent(events.NewRegistrationSucceeded(r.Context(), i.ID, string(a.Type), a.Active.String(), provider)) + span.AddEvent(events.NewRegistrationSucceeded(r.Context(), i.ID, string(a.Type), a.Active.String(), provider)) s := session.NewInactiveSession() @@ -197,6 +211,9 @@ func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Reque WithField("identity_id", i.ID). WithField("flow_method", ct). Debug("A ExecutePostRegistrationPostPersistHook hook aborted early.") + + span.SetAttributes(attribute.String("redirect_reason", "aborted by hook"), attribute.String("executor", fmt.Sprintf("%T", executor))) + return nil } @@ -210,6 +227,8 @@ func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Reque WithError(err). Error("ExecutePostRegistrationPostPersistHook hook failed with an error.") + span.SetAttributes(attribute.String("redirect_reason", "hook error"), attribute.String("executor", fmt.Sprintf("%T", executor))) + traits := i.Traits return flow.HandleHookError(w, r, a, traits, ct.ToUiNodeGroup(), err, e.d, e.d) } @@ -230,6 +249,8 @@ func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Reque Debug("Post registration execution hooks completed successfully.") if a.Type == flow.TypeAPI || x.IsJSONRequest(r) { + span.SetAttributes(attribute.String("flow_type", string(flow.TypeAPI))) + if a.IDToken != "" { // We don't want to redirect with the code, if the flow was submitted with an ID token. // This is the case for Sign in with native Apple SDK or Google SDK. @@ -265,9 +286,12 @@ func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Reque } finalReturnTo = callbackURL } + span.SetAttributes(attribute.String("redirect_reason", "oauth2 login challenge")) } else if a.ReturnToVerification != "" { finalReturnTo = a.ReturnToVerification + span.SetAttributes(attribute.String("redirect_reason", "verification requested")) } + span.SetAttributes(attribute.String("return_to", finalReturnTo)) x.ContentNegotiationRedirection(w, r, s.Declassified(), e.d.Writer(), finalReturnTo) return nil diff --git a/x/http_secure_redirect.go b/x/http_secure_redirect.go index d4d4ebbd29d7..cccbba6db2ec 100644 --- a/x/http_secure_redirect.go +++ b/x/http_secure_redirect.go @@ -143,7 +143,7 @@ func SecureRedirectTo(r *http.Request, defaultReturnTo *url.URL, opts ...SecureR return nil, errors.WithStack(herodot.ErrBadRequest. WithID(text.ErrIDRedirectURLNotAllowed). - WithReasonf("Requested return_to URL \"%s\" is not allowed.", returnTo). + WithReasonf("Requested return_to URL %q is not allowed.", returnTo). WithDebugf("Allowed domains are: %v", o.allowlist)) } diff --git a/x/http_secure_redirect_test.go b/x/http_secure_redirect_test.go index f94c474e2440..0afedc3f9e89 100644 --- a/x/http_secure_redirect_test.go +++ b/x/http_secure_redirect_test.go @@ -128,7 +128,7 @@ func TestTakeOverReturnToParameter(t *testing.T) { func TestSecureRedirectTo(t *testing.T) { newServer := func(t *testing.T, isTLS bool, isRelative bool, expectErr bool, opts func(ts *httptest.Server) []x.SecureRedirectOption) *httptest.Server { var ts *httptest.Server - f := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if opts == nil { opts = func(ts *httptest.Server) []x.SecureRedirectOption { return nil @@ -138,7 +138,7 @@ func TestSecureRedirectTo(t *testing.T) { if !isRelative { defaultReturnTo = ts.URL + defaultReturnTo } - ru, err := x.SecureRedirectTo(r, urlx.ParseOrPanic(defaultReturnTo), opts(ts)...) + returnTo, err := x.SecureRedirectTo(r, urlx.ParseOrPanic(defaultReturnTo), opts(ts)...) if expectErr { require.Error(t, err) _, _ = w.Write([]byte("error")) @@ -146,13 +146,13 @@ func TestSecureRedirectTo(t *testing.T) { } require.NoError(t, err) - _, _ = w.Write([]byte(ru.String())) + _, _ = w.Write([]byte(returnTo.String())) }) if isTLS { - ts = httptest.NewTLSServer(f) + ts = httptest.NewTLSServer(handler) } else { - ts = httptest.NewServer(f) + ts = httptest.NewServer(handler) } t.Cleanup(ts.Close) @@ -170,49 +170,61 @@ func TestSecureRedirectTo(t *testing.T) { } t.Run("case=return to a relative path with anchor works", func(t *testing.T) { - s := newServer(t, false, true, false, func(ts *httptest.Server) []x.SecureRedirectOption { - return []x.SecureRedirectOption{x.SecureRedirectAllowURLs([]url.URL{*urlx.ParseOrPanic("/foo")})} - }) - _, body := makeRequest(t, s, "?return_to=/foo/kratos%23abcd") - assert.Equal(t, body, "/foo/kratos#abcd") + returnTo, err := x.SecureRedirectTo( + httptest.NewRequest("GET", "/?return_to=/foo/kratos%23abcd", nil), + urlx.ParseOrPanic("/default-return-to"), + x.SecureRedirectAllowURLs([]url.URL{*urlx.ParseOrPanic("/foo")}), + ) + require.NoError(t, err) + assert.Equal(t, returnTo.String(), "/foo/kratos#abcd") }) t.Run("case=return to default URL if nothing is allowed", func(t *testing.T) { - s := newServer(t, false, false, false, nil) - _, body := makeRequest(t, s, "?return_to=/foo") - assert.EqualValues(t, body, s.URL+"/default-return-to") + returnTo, err := x.SecureRedirectTo( + httptest.NewRequest("GET", "/?return_to=/foo", nil), + urlx.ParseOrPanic("https://www.ory.sh/default-return-to"), + ) + require.NoError(t, err) + assert.Equal(t, returnTo.String(), "https://www.ory.sh/default-return-to") }) t.Run("case=return to foo with server baseURL if allowed", func(t *testing.T) { - s := newServer(t, false, false, false, func(ts *httptest.Server) []x.SecureRedirectOption { - return []x.SecureRedirectOption{x.SecureRedirectAllowURLs([]url.URL{*urlx.ParseOrPanic(ts.URL)})} - }) - _, body := makeRequest(t, s, "?return_to=/foo") - assert.Equal(t, body, s.URL+"/foo") + returnTo, err := x.SecureRedirectTo( + httptest.NewRequest("GET", "/?return_to=/foo", nil), + urlx.ParseOrPanic("https://www.ory.sh/default-return-to"), + x.SecureRedirectAllowURLs([]url.URL{*urlx.ParseOrPanic("https://www.ory.sh")}), + ) + require.NoError(t, err) + assert.Equal(t, returnTo.String(), "https://www.ory.sh/foo") }) t.Run("case=return to a relative path works", func(t *testing.T) { - s := newServer(t, false, true, false, func(ts *httptest.Server) []x.SecureRedirectOption { - return []x.SecureRedirectOption{x.SecureRedirectAllowURLs([]url.URL{*urlx.ParseOrPanic("/foo")})} - }) - _, body := makeRequest(t, s, "?return_to=/foo/kratos") - assert.Equal(t, body, "/foo/kratos") + returnTo, err := x.SecureRedirectTo( + httptest.NewRequest("GET", "/?return_to=/foo/kratos", nil), + urlx.ParseOrPanic("/default-return-to"), + x.SecureRedirectAllowURLs([]url.URL{*urlx.ParseOrPanic("/foo")}), + ) + require.NoError(t, err) + assert.Equal(t, returnTo.String(), "/foo/kratos") }) t.Run("case=return to a fully qualified domain is forbidden if allowlist is relative", func(t *testing.T) { - s := newServer(t, false, true, true, func(ts *httptest.Server) []x.SecureRedirectOption { - return []x.SecureRedirectOption{x.SecureRedirectAllowURLs([]url.URL{*urlx.ParseOrPanic("/foo")})} - }) - _, body := makeRequest(t, s, "?return_to=https://www.ory.sh/foo/kratos") - assert.Equal(t, body, "error") + _, err := x.SecureRedirectTo( + httptest.NewRequest("GET", "/?return_to=https://www.ory.sh/foo/kratos", nil), + urlx.ParseOrPanic("/default-return-to"), + x.SecureRedirectAllowURLs([]url.URL{*urlx.ParseOrPanic("/foo")}), + ) + require.Error(t, err) }) t.Run("case=return to another domain works", func(t *testing.T) { - s := newServer(t, false, false, false, func(ts *httptest.Server) []x.SecureRedirectOption { - return []x.SecureRedirectOption{x.SecureRedirectAllowURLs([]url.URL{*urlx.ParseOrPanic("https://www.ory.sh/foo")})} - }) - _, body := makeRequest(t, s, "?return_to=https://www.ory.sh/foo/kratos") - assert.Equal(t, body, "https://www.ory.sh/foo/kratos") + returnTo, err := x.SecureRedirectTo( + httptest.NewRequest("GET", "https://example.com/?return_to=https://www.ory.sh/foo/kratos", nil), + urlx.ParseOrPanic("https://www.ory.sh/default-return-to"), + x.SecureRedirectAllowURLs([]url.URL{*urlx.ParseOrPanic("https://www.ory.sh/foo")}), + ) + require.NoError(t, err) + assert.Equal(t, returnTo.String(), "https://www.ory.sh/foo/kratos") }) t.Run("case=return to another domain fails if host mismatches", func(t *testing.T) { From 976cd0dc3dd95c2c1992bfa82394e9fad39f34f2 Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Thu, 5 Oct 2023 15:57:25 +0200 Subject: [PATCH 130/282] fix: adjust tracing verbosity --- identity/manager.go | 15 +++++++++------ persistence/sql/identity/persister_identity.go | 5 +++-- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/identity/manager.go b/identity/manager.go index b47a03c0ac61..11220ec15f12 100644 --- a/identity/manager.go +++ b/identity/manager.go @@ -415,8 +415,9 @@ func (m *Manager) UpdateTraits(ctx context.Context, id uuid.UUID, traits Traits, } func (m *Manager) ValidateIdentity(ctx context.Context, i *Identity, o *ManagerOptions) (err error) { - ctx, span := m.r.Tracer(ctx).Tracer().Start(ctx, "identity.Manager.validate") - defer otelx.End(span, &err) + // This trace is more noisy than it's worth in diagnostic power. + // ctx, span := m.r.Tracer(ctx).Tracer().Start(ctx, "identity.Manager.validate") + // defer otelx.End(span, &err) if err := m.r.IdentityValidator().Validate(ctx, i); err != nil { if _, ok := errorsx.Cause(err).(*jsonschema.ValidationError); ok && !o.ExposeValidationErrors { @@ -429,8 +430,9 @@ func (m *Manager) ValidateIdentity(ctx context.Context, i *Identity, o *ManagerO } func (m *Manager) CountActiveFirstFactorCredentials(ctx context.Context, i *Identity) (count int, err error) { - ctx, span := m.r.Tracer(ctx).Tracer().Start(ctx, "identity.Manager.CountActiveFirstFactorCredentials") - defer otelx.End(span, &err) + // This trace is more noisy than it's worth in diagnostic power. + // ctx, span := m.r.Tracer(ctx).Tracer().Start(ctx, "identity.Manager.CountActiveFirstFactorCredentials") + // defer otelx.End(span, &err) for _, strategy := range m.r.ActiveCredentialsCounterStrategies(ctx) { current, err := strategy.CountActiveFirstFactorCredentials(i.Credentials) @@ -444,8 +446,9 @@ func (m *Manager) CountActiveFirstFactorCredentials(ctx context.Context, i *Iden } func (m *Manager) CountActiveMultiFactorCredentials(ctx context.Context, i *Identity) (count int, err error) { - ctx, span := m.r.Tracer(ctx).Tracer().Start(ctx, "identity.Manager.CountActiveMultiFactorCredentials") - defer otelx.End(span, &err) + // This trace is more noisy than it's worth in diagnostic power. + // ctx, span := m.r.Tracer(ctx).Tracer().Start(ctx, "identity.Manager.CountActiveMultiFactorCredentials") + // defer otelx.End(span, &err) for _, strategy := range m.r.ActiveCredentialsCounterStrategies(ctx) { current, err := strategy.CountActiveMultiFactorCredentials(i.Credentials) diff --git a/persistence/sql/identity/persister_identity.go b/persistence/sql/identity/persister_identity.go index 3e8335c8027a..5a31d7bd6f3d 100644 --- a/persistence/sql/identity/persister_identity.go +++ b/persistence/sql/identity/persister_identity.go @@ -945,8 +945,9 @@ func (p *IdentityPersister) validateIdentity(ctx context.Context, i *identity.Id } func (p *IdentityPersister) InjectTraitsSchemaURL(ctx context.Context, i *identity.Identity) (err error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.InjectTraitsSchemaURL") - defer otelx.End(span, &err) + // This trace is more noisy than it's worth in diagnostic power. + // ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.InjectTraitsSchemaURL") + // defer otelx.End(span, &err) ss, err := p.r.IdentityTraitsSchemas(ctx) if err != nil { From ab6dc3121535d27668fed58804a218b17b17ae43 Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Mon, 18 Sep 2023 11:31:48 +0200 Subject: [PATCH 131/282] fix: data race in test --- .../strategy/password/op_login_test.go | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/selfservice/strategy/password/op_login_test.go b/selfservice/strategy/password/op_login_test.go index fd0f00eda6d1..21e81395d62d 100644 --- a/selfservice/strategy/password/op_login_test.go +++ b/selfservice/strategy/password/op_login_test.go @@ -10,6 +10,7 @@ import ( "io" "net/http" "net/url" + "sync/atomic" "testing" "time" @@ -180,7 +181,7 @@ func TestOAuth2Provider(t *testing.T) { redirTS := testhelpers.NewRedirSessionEchoTS(t, reg) - oAuthSuccess := false + var oAuthSuccess atomic.Bool var hydraAdminClient hydraclientgo.OAuth2Api var clientAppOAuth2Config *oauth2.Config @@ -191,7 +192,7 @@ func TestOAuth2Provider(t *testing.T) { require.NoError(t, err) require.NotNil(t, token) require.NotEqual(t, "", token.AccessToken) - oAuthSuccess = true + oAuthSuccess.Store(true) t.Log("[clientAppTS] successfully exchanged code for token") } else { t.Error("[clientAppTS] code query parameter is missing") @@ -200,7 +201,8 @@ func TestOAuth2Provider(t *testing.T) { identifier, pwd := x.NewUUID().String(), "password" - testRequireLogin := true + var testRequireLogin atomic.Bool + testRequireLogin.Store(true) uiTS := testhelpers.NewHTTPTestServer(t, http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) { t.Logf("[uiTS] handling %s", r.URL) @@ -209,8 +211,8 @@ func TestOAuth2Provider(t *testing.T) { 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 { + f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, kratosPublicTS, false, false, false, !testRequireLogin.Load(), testhelpers.InitFlowWithOAuth2LoginChallenge(hlc)) + if testRequireLogin.Load() { require.NotNil(t, f) values := url.Values{"method": {"password"}, "identifier": {identifier}, "password": {pwd}, "csrf_token": {x.FakeCSRFToken}}.Encode() @@ -284,8 +286,8 @@ func TestOAuth2Provider(t *testing.T) { require.NoError(t, err) require.Equal(t, "", string(body)) require.Equal(t, http.StatusOK, res.StatusCode) - require.True(t, oAuthSuccess) - oAuthSuccess = false + require.True(t, oAuthSuccess.Load()) + oAuthSuccess.Store(false) }) conf.MustSet(ctx, config.ViperKeySessionPersistentCookie, true) @@ -299,11 +301,11 @@ func TestOAuth2Provider(t *testing.T) { require.NoError(t, err) require.Equal(t, "", string(body)) require.Equal(t, http.StatusOK, res.StatusCode) - require.True(t, oAuthSuccess) - oAuthSuccess = false + require.True(t, oAuthSuccess.Load()) + oAuthSuccess.Store(false) }) - testRequireLogin = false + testRequireLogin.Store(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) @@ -314,8 +316,8 @@ func TestOAuth2Provider(t *testing.T) { require.NoError(t, err) require.Equal(t, "", string(body)) require.Equal(t, http.StatusOK, res.StatusCode) - require.True(t, oAuthSuccess) - oAuthSuccess = false + require.True(t, oAuthSuccess.Load()) + oAuthSuccess.Store(false) }) reg.WithHydra(&AcceptWrongSubject{h: reg.Hydra().(*hydra.DefaultHydra)}) @@ -329,8 +331,8 @@ func TestOAuth2Provider(t *testing.T) { require.NoError(t, err) require.Equal(t, "", string(body)) require.Equal(t, http.StatusOK, res.StatusCode) - require.False(t, oAuthSuccess) - oAuthSuccess = false + require.False(t, oAuthSuccess.Load()) + oAuthSuccess.Store(false) }) } From e16fed1f8563509aac30886386668bb85e6dc797 Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Mon, 9 Oct 2023 16:22:42 +0200 Subject: [PATCH 132/282] fix: change ListIdentities to keyset pagination --- .vscode/settings.json | 6 + go.mod | 5 +- go.sum | 6 +- identity/handler.go | 48 ++++--- identity/handler_test.go | 82 +++++------ identity/identity.go | 9 ++ identity/pool.go | 9 +- identity/test/pool.go | 82 +++++------ internal/driver.go | 7 +- .../sql/identity/persister_identity.go | 129 +++++++++++------- persistence/sql/migratest/migration_test.go | 5 +- x/pagination.go | 42 ++++++ 12 files changed, 258 insertions(+), 172 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000000..9b853f315519 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "gopls": { + "formatting.gofumpt": true, + "formatting.local": "github.com/ory" + } +} diff --git a/go.mod b/go.mod index 3b98b3d283ac..d40791136ea9 100644 --- a/go.mod +++ b/go.mod @@ -77,7 +77,8 @@ require ( github.com/ory/jsonschema/v3 v3.0.8 github.com/ory/mail/v3 v3.0.0 github.com/ory/nosurf v1.2.7 - github.com/ory/x v0.0.590 + github.com/ory/x v0.0.591 + github.com/peterhellberg/link v1.2.0 github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 github.com/pkg/errors v0.9.1 github.com/pquerna/otp v1.4.0 @@ -92,7 +93,6 @@ require ( github.com/stretchr/testify v1.8.4 github.com/tidwall/gjson v1.14.3 github.com/tidwall/sjson v1.2.5 - github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 github.com/urfave/negroni v1.0.0 github.com/zmb3/spotify/v2 v2.0.0 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.4 @@ -261,7 +261,6 @@ require ( github.com/openzipkin/zipkin-go v0.4.1 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.7 // indirect - github.com/peterhellberg/link v1.2.0 // indirect github.com/philhofer/fwd v1.1.2 // indirect github.com/pkg/profile v1.7.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/go.sum b/go.sum index 1493216aec55..3c3a6cbe2ef7 100644 --- a/go.sum +++ b/go.sum @@ -847,8 +847,8 @@ github.com/ory/nosurf v1.2.7 h1:YrHrbSensQyU6r6HT/V5+HPdVEgrOTMJiLoJABSBOp4= github.com/ory/nosurf v1.2.7/go.mod h1:d4L3ZBa7Amv55bqxCBtCs63wSlyaiCkWVl4vKf3OUxA= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2 h1:zm6sDvHy/U9XrGpixwHiuAwpp0Ock6khSVHkrv6lQQU= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/ory/x v0.0.590 h1:t0+XlSlDw5pzZhdAxOB8uFp1Dp+MStPRTG8Nn/fm1PE= -github.com/ory/x v0.0.590/go.mod h1:ksLBEd6iW6czGpE6eNA0gCIxO1FFeqIxCZgsgwNrzMM= +github.com/ory/x v0.0.591 h1:a3hyQZIwokuRCeoPzMxbewY/y6C6r1NgX4Jn3csVZv0= +github.com/ory/x v0.0.591/go.mod h1:ksLBEd6iW6czGpE6eNA0gCIxO1FFeqIxCZgsgwNrzMM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -1032,8 +1032,6 @@ github.com/timtadh/lexmachine v0.2.2 h1:g55RnjdYazm5wnKv59pwFcBJHOyvTPfDEoz21s4P github.com/timtadh/lexmachine v0.2.2/go.mod h1:GBJvD5OAfRn/gnp92zb9KTgHLB7akKyxmVivoYCcjQI= github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0= github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= -github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y= -github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE= github.com/toqueteos/webbrowser v1.2.0 h1:tVP/gpK69Fx+qMJKsLE7TD8LuGWPnEV71wBN9rrstGQ= github.com/toqueteos/webbrowser v1.2.0/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= diff --git a/identity/handler.go b/identity/handler.go index c7505b0dae6c..b4eceae3a515 100644 --- a/identity/handler.go +++ b/identity/handler.go @@ -10,7 +10,9 @@ import ( "net/http" "time" + "github.com/ory/x/pagination/keysetpagination" "github.com/ory/x/pagination/migrationpagination" + "github.com/ory/x/pagination/pagepagination" "github.com/ory/x/sqlcon" "github.com/ory/kratos/hash" @@ -169,32 +171,45 @@ type listIdentitiesParameters struct { // 200: listIdentities // default: errorGeneric func (h *Handler) list(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { - page, itemsPerPage := x.ParsePagination(r) - - params := ListIdentityParameters{ - Expand: ExpandDefault, - Page: page, - PerPage: itemsPerPage, - CredentialsIdentifier: r.URL.Query().Get("credentials_identifier"), - CredentialsIdentifierSimilar: r.URL.Query().Get("preview_credentials_identifier_similar"), + var ( + err error + params = ListIdentityParameters{ + Expand: ExpandDefault, + CredentialsIdentifier: r.URL.Query().Get("credentials_identifier"), + CredentialsIdentifierSimilar: r.URL.Query().Get("preview_credentials_identifier_similar"), + } + ) + if params.CredentialsIdentifier != "" && params.CredentialsIdentifierSimilar != "" { + h.r.Writer().WriteError(w, r, herodot.ErrBadRequest.WithReason("Cannot pass both credentials_identifier and preview_credentials_identifier_similar.")) + return } - if params.CredentialsIdentifier != "" { + if params.CredentialsIdentifier != "" || params.CredentialsIdentifierSimilar != "" { params.Expand = ExpandEverything } + params.KeySetPagination, params.PagePagination, err = x.ParseKeysetOrPagePagination(r) + if err != nil { + h.r.Writer().WriteError(w, r, err) + return + } - is, err := h.r.IdentityPool().ListIdentities(r.Context(), params) + is, nextPage, err := h.r.IdentityPool().ListIdentities(r.Context(), params) if err != nil { h.r.Writer().WriteError(w, r, err) return } - total := int64(len(is)) - if params.CredentialsIdentifier == "" { - total, err = h.r.IdentityPool().CountIdentities(r.Context()) - if err != nil { - h.r.Writer().WriteError(w, r, err) - return + if params.PagePagination != nil { + total := int64(len(is)) + if params.CredentialsIdentifier == "" { + total, err = h.r.IdentityPool().CountIdentities(r.Context()) + if err != nil { + h.r.Writer().WriteError(w, r, err) + return + } } + pagepagination.PaginationHeader(w, urlx.AppendPaths(h.r.Config().SelfAdminURL(r.Context()), RouteCollection), total, params.PagePagination.Page, params.PagePagination.ItemsPerPage) + } else { + keysetpagination.Header(w, urlx.AppendPaths(h.r.Config().SelfAdminURL(r.Context()), RouteCollection), nextPage) } // Identities using the marshaler for including metadata_admin @@ -203,7 +218,6 @@ func (h *Handler) list(w http.ResponseWriter, r *http.Request, _ httprouter.Para isam[i] = WithCredentialsMetadataAndAdminMetadataInJSON(identity) } - migrationpagination.PaginationHeader(w, urlx.AppendPaths(h.r.Config().SelfAdminURL(r.Context()), RouteCollection), total, page, itemsPerPage) h.r.Writer().Write(w, r, isam) } diff --git a/identity/handler_test.go b/identity/handler_test.go index 934ca62946b0..f237f6643301 100644 --- a/identity/handler_test.go +++ b/identity/handler_test.go @@ -20,12 +20,11 @@ import ( "github.com/bxcodec/faker/v3" "github.com/gofrs/uuid" + "github.com/peterhellberg/link" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tidwall/gjson" - "github.com/tomnomnom/linkheader" - "github.com/ory/kratos/driver/config" "github.com/ory/kratos/hash" "github.com/ory/kratos/identity" @@ -683,7 +682,6 @@ func TestHandler(t *testing.T) { req := &identity.BatchPatchIdentitiesBody{Identities: validPatches} send(t, adminTS, "PATCH", "/identities", http.StatusOK, req) }) - }) t.Run("case=ignores create nil bodies", func(t *testing.T) { @@ -787,7 +785,6 @@ func TestHandler(t *testing.T) { for name, ts := range map[string]*httptest.Server{"public": publicTS, "admin": adminTS} { t.Run("endpoint="+name, func(t *testing.T) { - email := "UPPER" + x.NewUUID().String() + "@ory.sh" lowercaseEmail := strings.ToLower(email) var cr identity.CreateIdentityBody @@ -820,7 +817,6 @@ func TestHandler(t *testing.T) { assert.EqualValues(t, identity.StateActive, res.Get("state").String(), "%s", res.Raw) }) } - }) t.Run("case=PATCH update should not persist if schema id is invalid", func(t *testing.T) { @@ -1490,53 +1486,46 @@ func TestHandler(t *testing.T) { perPage := perPage t.Run(fmt.Sprintf("perPage=%d", perPage), func(t *testing.T) { t.Parallel() - body, res := getFull(t, ts, fmt.Sprintf("/identities?per_page=%d", perPage), http.StatusOK) + body, _ := getFull(t, ts, fmt.Sprintf("/identities?per_page=%d", perPage), http.StatusOK) assert.Len(t, body.Array(), perPage) - assert.Equal(t, strconv.Itoa(count), res.Header.Get("X-Total-Count")) }) } t.Run("iterate over next page", func(t *testing.T) { perPage := 10 - pagePath := fmt.Sprintf("/identities?per_page=%d", perPage) - run := func(t *testing.T, path string, knownIDs map[string]struct{}) (isLast bool, parsed *url.URL) { - var err error + run := func(t *testing.T, path string, knownIDs map[string]struct{}) (next *url.URL, res *http.Response) { t.Logf("Requesting %s", path) body, res := getFull(t, ts, path, http.StatusOK) - for _, link := range linkheader.Parse(res.Header.Get("Link")) { - if link.Rel != "next" { - isLast = true - continue - } - parsed, err = url.Parse(link.URL) - require.NoError(t, err) - isLast = false - break - } - for _, i := range body.Array() { - assert.NotContains(t, knownIDs, i.Get("id").String()) - knownIDs[i.Get("id").String()] = struct{}{} + id := i.Get("id").String() + _, seen := knownIDs[id] + require.Falsef(t, seen, "ID %s was previously returned from the API", id) + knownIDs[id] = struct{}{} + } + links := link.ParseResponse(res) + if link, ok := links["next"]; ok { + next, err := url.Parse(link.URI) + require.NoError(t, err) + return next, res } - return isLast, parsed + return nil, res } t.Run("using token pagination", func(t *testing.T) { knownIDs := make(map[string]struct{}) - var isLast bool var pages int - path := pagePath - for !isLast { - t.Run(fmt.Sprintf("page=%d", pages), func(t *testing.T) { - var res *url.URL - pages++ - isLast, res = run(t, path, knownIDs) - if isLast { - return - } - path = fmt.Sprintf("/identities?page_size=%s&page_token=%s", res.Query().Get("page_size"), res.Query().Get("page_token")) - }) + path := fmt.Sprintf("/identities?page_size=%d", perPage) + for { + pages++ + next, res := run(t, path, knownIDs) + assert.NotContains(t, res.Header, "X-Total-Count", "not supported in token pagination") + if next == nil { + break + } + assert.NotContains(t, next.Query(), "page") + assert.NotContains(t, next.Query(), "per_page") + path = next.Path + "?" + next.Query().Encode() } assert.Len(t, knownIDs, count) @@ -1545,19 +1534,16 @@ func TestHandler(t *testing.T) { t.Run("using page pagination", func(t *testing.T) { knownIDs := make(map[string]struct{}) - var isLast bool var pages int - path := pagePath - for !isLast { - t.Run(fmt.Sprintf("page=%d", pages), func(t *testing.T) { - var res *url.URL - pages++ - isLast, res = run(t, path, knownIDs) - if isLast { - return - } - path = fmt.Sprintf("/identities?per_page=%s&page=%s", res.Query().Get("per_page"), res.Query().Get("page")) - }) + path := fmt.Sprintf("/identities?page=0&per_page=%d", perPage) + for { + pages++ + next, res := run(t, path, knownIDs) + assert.Equal(t, strconv.Itoa(count), res.Header.Get("X-Total-Count")) + if next == nil { + break + } + path = next.Path + "?" + next.Query().Encode() } assert.Len(t, knownIDs, count) diff --git a/identity/identity.go b/identity/identity.go index 064c21121fc1..85030bd41e92 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -20,6 +20,7 @@ import ( "github.com/ory/kratos/cipher" "github.com/ory/herodot" + "github.com/ory/x/pagination/keysetpagination" "github.com/ory/x/sqlxx" "github.com/ory/kratos/driver/config" @@ -132,6 +133,14 @@ type Identity struct { OrganizationID uuid.NullUUID `json:"organization_id,omitempty" faker:"-" db:"organization_id"` } +func (i *Identity) PageToken() keysetpagination.PageToken { + return keysetpagination.StringPageToken(i.ID.String()) +} + +func DefaultPageToken() keysetpagination.PageToken { + return keysetpagination.StringPageToken(uuid.Nil.String()) +} + // Traits represent an identity's traits. The identity is able to create, modify, and delete traits // in a self-service manner. The input will always be validated against the JSON Schema defined // in `schema_url`. diff --git a/identity/pool.go b/identity/pool.go index 1cf4888e52ae..61665f056abd 100644 --- a/identity/pool.go +++ b/identity/pool.go @@ -6,6 +6,8 @@ package identity import ( "context" + "github.com/ory/kratos/x" + "github.com/ory/x/pagination/keysetpagination" "github.com/ory/x/sqlxx" "github.com/gofrs/uuid" @@ -16,13 +18,14 @@ type ( Expand Expandables CredentialsIdentifier string CredentialsIdentifierSimilar string - Page int - PerPage int + KeySetPagination []keysetpagination.Option + // DEPRECATED + PagePagination *x.Page } Pool interface { // ListIdentities lists all identities in the store given the page and itemsPerPage. - ListIdentities(ctx context.Context, params ListIdentityParameters) ([]Identity, error) + ListIdentities(ctx context.Context, params ListIdentityParameters) ([]Identity, *keysetpagination.Paginator, error) // CountIdentities counts the number of identities in the store. CountIdentities(ctx context.Context) (int64, error) diff --git a/identity/test/pool.go b/identity/test/pool.go index 5adf9fb364b6..b51a88f242ca 100644 --- a/identity/test/pool.go +++ b/identity/test/pool.go @@ -13,33 +13,25 @@ import ( "testing" "time" - "github.com/ory/x/randx" - - "github.com/tidwall/gjson" - - "github.com/ory/x/assertx" - - "github.com/ory/kratos/internal/testhelpers" - - "github.com/ory/kratos/identity" - "github.com/ory/kratos/persistence" - "github.com/bxcodec/faker/v3" - - "github.com/ory/x/sqlxx" - - "github.com/ory/x/errorsx" - "github.com/ory/x/sqlcon" - "github.com/ory/x/urlx" - - "github.com/ory/kratos/schema" - "github.com/gofrs/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/tidwall/gjson" "github.com/ory/kratos/driver/config" + "github.com/ory/kratos/identity" + "github.com/ory/kratos/internal/testhelpers" + "github.com/ory/kratos/persistence" + "github.com/ory/kratos/schema" "github.com/ory/kratos/x" + "github.com/ory/x/assertx" + "github.com/ory/x/errorsx" + "github.com/ory/x/pagination/keysetpagination" + "github.com/ory/x/randx" + "github.com/ory/x/sqlcon" + "github.com/ory/x/sqlxx" + "github.com/ory/x/urlx" ) func TestPool(ctx context.Context, conf *config.Config, p persistence.Persister, m *identity.Manager) func(t *testing.T) { @@ -88,7 +80,6 @@ func TestPool(ctx context.Context, conf *config.Config, p persistence.Persister, }) t.Run("case=expand", func(t *testing.T) { - require.NoError(t, p.GetConnection(ctx).RawQuery("DELETE FROM identities WHERE nid = ?", nid).Exec()) t.Cleanup(func() { require.NoError(t, p.GetConnection(ctx).RawQuery("DELETE FROM identities WHERE nid = ?", nid).Exec()) @@ -120,12 +111,20 @@ func TestPool(ctx context.Context, conf *config.Config, p persistence.Persister, assertion(t, actual) }) - t.Run("list", func(t *testing.T) { - actual, err := p.ListIdentities(ctx, identity.ListIdentityParameters{Expand: expand, Page: 0, PerPage: 10}) + t.Run("list/page-pagination", func(t *testing.T) { + actual, _, err := p.ListIdentities(ctx, identity.ListIdentityParameters{Expand: expand, PagePagination: &x.Page{Page: 0, ItemsPerPage: 10}}) require.NoError(t, err) require.Len(t, actual, 1) assertion(t, &actual[0]) }) + + t.Run("list/token-pagination", func(t *testing.T) { + actual, next, err := p.ListIdentities(ctx, identity.ListIdentityParameters{Expand: expand, KeySetPagination: []keysetpagination.Option{keysetpagination.WithSize(10)}}) + require.NoError(t, err) + require.Len(t, actual, 1) + require.True(t, next.IsLast()) + assertion(t, &actual[0]) + }) } t.Run("expand=nothing", func(t *testing.T) { @@ -170,7 +169,6 @@ func TestPool(ctx context.Context, conf *config.Config, p persistence.Persister, t.Run("expand=default", func(t *testing.T) { runner(t, identity.ExpandDefault, func(t *testing.T, actual *identity.Identity) { - assert.Empty(t, actual.Credentials) require.Len(t, actual.RecoveryAddresses, 1) @@ -183,7 +181,6 @@ func TestPool(ctx context.Context, conf *config.Config, p persistence.Persister, t.Run("expand=everything", func(t *testing.T) { runner(t, identity.ExpandEverything, func(t *testing.T, actual *identity.Identity) { - require.Len(t, actual.Credentials, 2) assertx.EqualAsJSONExcept(t, expected.Credentials[identity.CredentialsTypePassword], actual.Credentials[identity.CredentialsTypePassword], []string{"updated_at", "created_at"}) @@ -235,7 +232,7 @@ func TestPool(ctx context.Context, conf *config.Config, p persistence.Persister, }) var createdIDs []uuid.UUID - var passwordIdentity = func(schemaID string, credentialsID string) *identity.Identity { + passwordIdentity := func(schemaID string, credentialsID string) *identity.Identity { i := identity.NewIdentity(schemaID) i.SetCredentials(identity.CredentialsTypePassword, identity.Credentials{ Type: identity.CredentialsTypePassword, Identifiers: []string{credentialsID}, @@ -244,7 +241,7 @@ func TestPool(ctx context.Context, conf *config.Config, p persistence.Persister, return i } - var webAuthnIdentity = func(schemaID string, credentialsID string) *identity.Identity { + webAuthnIdentity := func(schemaID string, credentialsID string) *identity.Identity { i := identity.NewIdentity(schemaID) i.SetCredentials(identity.CredentialsTypeWebAuthn, identity.Credentials{ Type: identity.CredentialsTypeWebAuthn, Identifiers: []string{credentialsID}, @@ -253,7 +250,7 @@ func TestPool(ctx context.Context, conf *config.Config, p persistence.Persister, return i } - var oidcIdentity = func(schemaID string, credentialsID string) *identity.Identity { + oidcIdentity := func(schemaID string, credentialsID string) *identity.Identity { i := identity.NewIdentity(schemaID) i.SetCredentials(identity.CredentialsTypeOIDC, identity.Credentials{ Type: identity.CredentialsTypeOIDC, Identifiers: []string{credentialsID}, @@ -262,7 +259,7 @@ func TestPool(ctx context.Context, conf *config.Config, p persistence.Persister, return i } - var assertEqual = func(t *testing.T, expected, actual *identity.Identity) { + assertEqual := func(t *testing.T, expected, actual *identity.Identity) { assert.Empty(t, actual.Credentials) require.Equal(t, expected.Traits, actual.Traits) require.Equal(t, expected.ID, actual.ID) @@ -634,9 +631,9 @@ func TestPool(ctx context.Context, conf *config.Config, p persistence.Persister, }) t.Run("case=list", func(t *testing.T) { - is, err := p.ListIdentities(ctx, identity.ListIdentityParameters{Expand: identity.ExpandDefault, Page: 0, PerPage: 25}) + is, _, err := p.ListIdentities(ctx, identity.ListIdentityParameters{Expand: identity.ExpandDefault}) require.NoError(t, err) - require.NotZero(t, len(is)) + require.NotEmpty(t, is) require.Len(t, is, len(createdIDs)) for _, id := range createdIDs { var found bool @@ -653,7 +650,7 @@ func TestPool(ctx context.Context, conf *config.Config, p persistence.Persister, t.Run("no results on other network", func(t *testing.T) { _, p := testhelpers.NewNetwork(t, ctx, p) - is, err := p.ListIdentities(ctx, identity.ListIdentityParameters{Expand: identity.ExpandDefault, Page: 0, PerPage: 25}) + is, _, err := p.ListIdentities(ctx, identity.ListIdentityParameters{Expand: identity.ExpandDefault}) require.NoError(t, err) assert.Len(t, is, 0) }) @@ -683,7 +680,7 @@ func TestPool(ctx context.Context, conf *config.Config, p persistence.Persister, create.SetCredentials(identity.CredentialsTypeWebAuthn, identity.Credentials{Type: identity.CredentialsTypeWebAuthn, Identifiers: []string{"find-identity-by-identifier-common@ory.sh"}, Config: sqlxx.JSONRawMessage(`{}`)}) require.NoError(t, p.CreateIdentity(ctx, create)) - actual, err := p.ListIdentities(ctx, identity.ListIdentityParameters{ + actual, _, err := p.ListIdentities(ctx, identity.ListIdentityParameters{ Expand: identity.ExpandEverything, }) require.NoError(t, err) @@ -694,7 +691,7 @@ func TestPool(ctx context.Context, conf *config.Config, p persistence.Persister, identity.CredentialsTypeWebAuthn, } { t.Run(ct.String(), func(t *testing.T) { - actual, err := p.ListIdentities(ctx, identity.ListIdentityParameters{ + actual, _, err := p.ListIdentities(ctx, identity.ListIdentityParameters{ // Match is normalized CredentialsIdentifier: expectedIdentifiers[c], }) @@ -707,7 +704,7 @@ func TestPool(ctx context.Context, conf *config.Config, p persistence.Persister, } t.Run("similarity search", func(t *testing.T) { - actual, err := p.ListIdentities(ctx, identity.ListIdentityParameters{ + actual, _, err := p.ListIdentities(ctx, identity.ListIdentityParameters{ CredentialsIdentifierSimilar: "find-identity-by-identifier", Expand: identity.ExpandCredentials, }) @@ -731,40 +728,44 @@ func TestPool(ctx context.Context, conf *config.Config, p persistence.Persister, }) t.Run("only webauthn and password", func(t *testing.T) { - actual, err := p.ListIdentities(ctx, identity.ListIdentityParameters{ + actual, next, err := p.ListIdentities(ctx, identity.ListIdentityParameters{ CredentialsIdentifier: "find-identity-by-identifier-oidc@ory.sh", Expand: identity.ExpandEverything, }) require.NoError(t, err) assert.Len(t, actual, 0) + assert.True(t, next.IsLast()) }) t.Run("one result set even if multiple matches", func(t *testing.T) { - actual, err := p.ListIdentities(ctx, identity.ListIdentityParameters{ + actual, next, err := p.ListIdentities(ctx, identity.ListIdentityParameters{ CredentialsIdentifier: "find-identity-by-identifier-common@ory.sh", Expand: identity.ExpandEverything, }) require.NoError(t, err) assert.Len(t, actual, 1) + assert.True(t, next.IsLast()) }) t.Run("non existing identifier", func(t *testing.T) { - actual, err := p.ListIdentities(ctx, identity.ListIdentityParameters{ + actual, next, err := p.ListIdentities(ctx, identity.ListIdentityParameters{ CredentialsIdentifier: "find-identity-by-identifier-non-existing@ory.sh", Expand: identity.ExpandEverything, }) require.NoError(t, err) assert.Len(t, actual, 0) + assert.True(t, next.IsLast()) }) t.Run("not if on another network", func(t *testing.T) { _, on := testhelpers.NewNetwork(t, ctx, p) - actual, err := on.ListIdentities(ctx, identity.ListIdentityParameters{ + actual, next, err := on.ListIdentities(ctx, identity.ListIdentityParameters{ CredentialsIdentifier: expectedIdentifiers[0], Expand: identity.ExpandEverything, }) require.NoError(t, err) assert.Len(t, actual, 0) + assert.True(t, next.IsLast()) }) }) @@ -1243,7 +1244,8 @@ func NewTestIdentity(numAddresses int, prefix string, i int) *identity.Identity id.SetCredentials(identity.CredentialsTypePassword, identity.Credentials{ Type: identity.CredentialsTypePassword, Identifiers: []string{traits.Username}, - Config: sqlxx.JSONRawMessage(`{}`)}) + Config: sqlxx.JSONRawMessage(`{}`), + }) return id } diff --git a/internal/driver.go b/internal/driver.go index 739afe03dc3a..d17f2b0ca62b 100644 --- a/internal/driver.go +++ b/internal/driver.go @@ -8,6 +8,8 @@ import ( "os" "testing" + "github.com/sirupsen/logrus" + "github.com/ory/x/contextx" "github.com/ory/x/jsonnetsecure" @@ -37,7 +39,7 @@ func NewConfigurationWithDefaults(t testing.TB) *config.Config { c := config.MustNew(t, logrusx.New("", ""), os.Stderr, configx.WithValues(map[string]interface{}{ - "log.level": "trace", + "log.level": "error", config.ViperKeyDSN: dbal.NewSQLiteTestDatabase(t), config.ViperKeyHasherArgon2ConfigMemory: 16384, config.ViperKeyHasherArgon2ConfigIterations: 1, @@ -77,8 +79,7 @@ func NewRegistryDefaultWithDSN(t testing.TB, dsn string) (*config.Config, *drive ctx := context.Background() c := NewConfigurationWithDefaults(t) c.MustSet(ctx, config.ViperKeyDSN, stringsx.Coalesce(dsn, dbal.NewSQLiteTestDatabase(t))) - - reg, err := driver.NewRegistryFromDSN(ctx, c, logrusx.New("", "")) + reg, err := driver.NewRegistryFromDSN(ctx, c, logrusx.New("", "", logrusx.ForceLevel(logrus.ErrorLevel))) require.NoError(t, err) reg.Config().MustSet(ctx, "dev", true) require.NoError(t, reg.Init(context.Background(), &contextx.Default{}, driver.SkipNetworkInit, driver.WithDisabledMigrationLogging())) diff --git a/persistence/sql/identity/persister_identity.go b/persistence/sql/identity/persister_identity.go index 5a31d7bd6f3d..fadac678951f 100644 --- a/persistence/sql/identity/persister_identity.go +++ b/persistence/sql/identity/persister_identity.go @@ -12,19 +12,15 @@ import ( "sync" "time" - "github.com/ory/x/contextx" - "github.com/ory/x/pointerx" - "github.com/ory/x/popx" - - "golang.org/x/sync/errgroup" - + "github.com/gobuffalo/pop/v6" + "github.com/gofrs/uuid" + "github.com/pkg/errors" "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" + "golang.org/x/sync/errgroup" - "github.com/ory/x/otelx" - + "github.com/ory/herodot" "github.com/ory/jsonschema/v3" - "github.com/ory/x/sqlxx" - "github.com/ory/kratos/driver/config" "github.com/ory/kratos/identity" "github.com/ory/kratos/otp" @@ -32,14 +28,14 @@ import ( "github.com/ory/kratos/persistence/sql/update" "github.com/ory/kratos/schema" "github.com/ory/kratos/x" - - "github.com/gobuffalo/pop/v6" - "github.com/gofrs/uuid" - "github.com/pkg/errors" - - "github.com/ory/herodot" + "github.com/ory/x/contextx" "github.com/ory/x/errorsx" + "github.com/ory/x/otelx" + "github.com/ory/x/pagination/keysetpagination" + "github.com/ory/x/pointerx" + "github.com/ory/x/popx" "github.com/ory/x/sqlcon" + "github.com/ory/x/sqlxx" ) var ( @@ -649,17 +645,35 @@ func QueryForCredentials(con *pop.Connection, where ...Where) (map[uuid.UUID](ma return credentialsPerIdentity, nil } -func (p *IdentityPersister) ListIdentities(ctx context.Context, params identity.ListIdentityParameters) (res []identity.Identity, err error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.ListIdentities") - defer otelx.End(span, &err) - - span.SetAttributes( - attribute.Int("page", params.Page), - attribute.Int("per_page", params.PerPage), +func paginationAttributes(params *identity.ListIdentityParameters, paginator *keysetpagination.Paginator) []attribute.KeyValue { + attrs := []attribute.KeyValue{ attribute.StringSlice("expand", params.Expand.ToEager()), attribute.Bool("use:credential_identifier_filter", params.CredentialsIdentifier != ""), - attribute.String("network.id", p.NetworkID(ctx).String()), - ) + attribute.Bool("use:credential_identifier_similar_filter", params.CredentialsIdentifierSimilar != ""), + } + if params.PagePagination != nil { + attrs = append(attrs, + attribute.Int("page", params.PagePagination.Page), + attribute.Int("per_page", params.PagePagination.ItemsPerPage)) + } else { + attrs = append(attrs, + attribute.String("page_token", paginator.Token().Encode()), + attribute.Int("page_size", paginator.Size())) + } + return attrs +} + +func (p *IdentityPersister) ListIdentities(ctx context.Context, params identity.ListIdentityParameters) (_ []identity.Identity, nextPage *keysetpagination.Paginator, err error) { + paginator := keysetpagination.GetPaginator(append( + params.KeySetPagination, + keysetpagination.WithDefaultToken(identity.DefaultPageToken()), + keysetpagination.WithDefaultSize(250), + keysetpagination.WithColumn("id", "ASC"))...) + + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.ListIdentities", trace.WithAttributes(append( + paginationAttributes(¶ms, paginator), + attribute.String("network.id", p.NetworkID(ctx).String()))...)) + defer otelx.End(span, &err) is := make([]identity.Identity, 0) @@ -667,8 +681,15 @@ func (p *IdentityPersister) ListIdentities(ctx context.Context, params identity. nid := p.NetworkID(ctx) joins := "" - wheres := "" - args := []any{nid} + wheres := "identities.nid = ? AND identities.id > ?" + args := []any{nid, paginator.Token().Encode()} + limit := fmt.Sprintf("LIMIT %d", paginator.Size()+1) + if params.PagePagination != nil { + wheres = "identities.nid = ?" + args = []any{nid} + paginator := pop.NewPaginator(params.PagePagination.Page+1, params.PagePagination.ItemsPerPage) + limit = fmt.Sprintf("LIMIT %d OFFSET %d", paginator.PerPage, paginator.Offset) + } identifier := params.CredentialsIdentifier identifierOperator := "=" if identifier == "" && params.CredentialsIdentifierSimilar != "" { @@ -688,31 +709,35 @@ func (p *IdentityPersister) ListIdentities(ctx context.Context, params identity. identifier = NormalizeIdentifier(identity.CredentialsTypePassword, identifier) joins = ` -INNER JOIN identity_credentials ic ON ic.identity_id = identities.id -INNER JOIN identity_credential_types ict ON ict.id = ic.identity_credential_type_id -INNER JOIN identity_credential_identifiers ici ON ici.identity_credential_id = ic.id` - wheres = fmt.Sprintf(` -AND (ic.nid = ? AND ici.nid = ? AND ici.identifier %s ?) -AND ict.name IN (?, ?)`, identifierOperator) + INNER JOIN identity_credentials ic ON ic.identity_id = identities.id + INNER JOIN identity_credential_types ict ON ict.id = ic.identity_credential_type_id + INNER JOIN identity_credential_identifiers ici ON ici.identity_credential_id = ic.id` + wheres += fmt.Sprintf(` + AND (ic.nid = ? AND ici.nid = ? AND ici.identifier %s ?) + AND ict.name IN (?, ?)`, identifierOperator) args = append(args, nid, nid, identifier, identity.CredentialsTypeWebAuthn, identity.CredentialsTypePassword) } - // Follow up: add page token support here, will be easy. - paginator := pop.NewPaginator(params.Page+1, params.PerPage) + query := fmt.Sprintf(` + SELECT DISTINCT identities.* + FROM identities AS identities + %s + WHERE + %s + ORDER BY identities.id ASC + %s`, + joins, wheres, limit) - if err := con.RawQuery(fmt.Sprintf(`SELECT DISTINCT identities.* -FROM identities AS identities -%s -WHERE identities.nid = ? -%s -ORDER BY identities.id DESC -LIMIT %d -OFFSET %d`, joins, wheres, paginator.PerPage, paginator.Offset), args...).All(&is); err != nil { - return nil, sqlcon.HandleError(err) + if err := con.RawQuery(query, args...).All(&is); err != nil { + return nil, nil, sqlcon.HandleError(err) + } + + if params.PagePagination == nil { + is, nextPage = keysetpagination.Result(is, paginator) } if len(is) == 0 { - return is, nil + return is, nextPage, nil } identitiesByID := make(map[uuid.UUID]*identity.Identity, len(is)) @@ -729,7 +754,7 @@ OFFSET %d`, joins, wheres, paginator.PerPage, paginator.Offset), args...).All(&i Where{"identity_credentials.nid = ?", []any{nid}}, Where{"identity_credentials.identity_id IN (?)", identityIDs}) if err != nil { - return nil, err + return nil, nil, err } for k := range is { is[k].Credentials = creds[is[k].ID] @@ -737,7 +762,7 @@ OFFSET %d`, joins, wheres, paginator.PerPage, paginator.Offset), args...).All(&i case identity.ExpandFieldVerifiableAddresses: addrs := make([]identity.VerifiableAddress, 0) if err := con.Where("nid = ?", nid).Where("identity_id IN (?)", identityIDs).Order("id").All(&addrs); err != nil { - return nil, sqlcon.HandleError(err) + return nil, nil, sqlcon.HandleError(err) } for _, addr := range addrs { identitiesByID[addr.IdentityID].VerifiableAddresses = append(identitiesByID[addr.IdentityID].VerifiableAddresses, addr) @@ -745,7 +770,7 @@ OFFSET %d`, joins, wheres, paginator.PerPage, paginator.Offset), args...).All(&i case identity.ExpandFieldRecoveryAddresses: addrs := make([]identity.RecoveryAddress, 0) if err := con.Where("nid = ?", nid).Where("identity_id IN (?)", identityIDs).Order("id").All(&addrs); err != nil { - return nil, sqlcon.HandleError(err) + return nil, nil, sqlcon.HandleError(err) } for _, addr := range addrs { identitiesByID[addr.IdentityID].RecoveryAddresses = append(identitiesByID[addr.IdentityID].RecoveryAddresses, addr) @@ -761,23 +786,23 @@ OFFSET %d`, joins, wheres, paginator.PerPage, paginator.Offset), args...).All(&i i.SchemaURL = u } else { if err := p.InjectTraitsSchemaURL(ctx, i); err != nil { - return nil, err + return nil, nil, err } schemaCache[i.SchemaID] = i.SchemaURL } if err := i.Validate(); err != nil { - return nil, err + return nil, nil, err } if err := identity.UpgradeCredentials(i); err != nil { - return nil, err + return nil, nil, err } is[k] = *i } - return is, nil + return is, nextPage, nil } func (p *IdentityPersister) UpdateIdentity(ctx context.Context, i *identity.Identity) (err error) { diff --git a/persistence/sql/migratest/migration_test.go b/persistence/sql/migratest/migration_test.go index 798afd54dc79..afa101987742 100644 --- a/persistence/sql/migratest/migration_test.go +++ b/persistence/sql/migratest/migration_test.go @@ -12,6 +12,7 @@ import ( "testing" "time" + "github.com/ory/x/pagination/keysetpagination" "github.com/ory/x/servicelocatorx" "github.com/ory/kratos/identity" @@ -164,7 +165,7 @@ func testDatabase(t *testing.T, db string, c *pop.Connection) { defer wg.Done() t.Parallel() - ids, err := d.PrivilegedIdentityPool().ListIdentities(context.Background(), identity.ListIdentityParameters{Expand: identity.ExpandEverything, Page: 0, PerPage: 1000}) + ids, _, err := d.PrivilegedIdentityPool().ListIdentities(context.Background(), identity.ListIdentityParameters{Expand: identity.ExpandEverything, KeySetPagination: []keysetpagination.Option{keysetpagination.WithSize(1000)}}) require.NoError(t, err) require.NotEmpty(t, ids) @@ -192,7 +193,7 @@ func testDatabase(t *testing.T, db string, c *pop.Connection) { defer wg.Done() t.Parallel() - ids, err := d.PrivilegedIdentityPool().ListIdentities(context.Background(), identity.ListIdentityParameters{Expand: identity.ExpandNothing, Page: 0, PerPage: 1000}) + ids, _, err := d.PrivilegedIdentityPool().ListIdentities(context.Background(), identity.ListIdentityParameters{Expand: identity.ExpandNothing, KeySetPagination: []keysetpagination.Option{keysetpagination.WithSize(1000)}}) require.NoError(t, err) require.NotEmpty(t, ids) diff --git a/x/pagination.go b/x/pagination.go index c19ed06450e0..e0d6e18b01a4 100644 --- a/x/pagination.go +++ b/x/pagination.go @@ -7,7 +7,10 @@ import ( "net/http" "net/url" + "github.com/ory/herodot" + "github.com/ory/x/pagination/keysetpagination" "github.com/ory/x/pagination/migrationpagination" + "github.com/ory/x/pagination/pagepagination" ) // ParsePagination parses limit and page from *http.Request with given limits and defaults. @@ -18,3 +21,42 @@ func ParsePagination(r *http.Request) (page, itemsPerPage int) { func PaginationHeader(w http.ResponseWriter, u *url.URL, total int64, page, itemsPerPage int) { migrationpagination.PaginationHeader(w, u, total, page, itemsPerPage) } + +type Page struct { + Page, ItemsPerPage int +} + +var PagePaginationLimit = 1000 + +func ParseKeysetOrPagePagination(r *http.Request) ([]keysetpagination.Option, *Page, error) { + q := r.URL.Query() + // If we have any new-style pagination parameters, use those and ignore the rest. + if q.Has("page_token") || q.Has("page_size") { + keyset, err := keysetpagination.Parse(q, keysetpagination.NewStringPageToken) + if err != nil { + return nil, nil, herodot.ErrBadRequest.WithReason(err.Error()) + } + return keyset, nil, nil + } + // allow fallback page pagination with upper limit + if q.Has("page") { + paginator := pagepagination.PagePaginator{MaxItems: 500, DefaultItems: 250} + page, perPage := paginator.ParsePagination(r) + if page*perPage > PagePaginationLimit { + return nil, nil, herodot.ErrBadRequest.WithReasonf("Legacy pagination is not supported for enumerating over %d items. Please switch to using page_token and page_size.", PagePaginationLimit) + } + return nil, &Page{page, perPage}, nil + } + // Allow passing per_page instead of page_size if only the former is set... + if q.Has("per_page") && !q.Has("page_size") { + q.Set("page_size", q.Get("per_page")) + q.Del("per_page") + r.URL.RawQuery = q.Encode() + } + // ... and defaul to keyset pagination + keyset, err := keysetpagination.Parse(q, keysetpagination.NewStringPageToken) + if err != nil { + return nil, nil, herodot.ErrBadRequest.WithReason(err.Error()) + } + return keyset, nil, nil +} From 4be5205320eb23c8ee465c1c361fc99fda4a2d9b Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Wed, 11 Oct 2023 13:34:11 +0000 Subject: [PATCH 133/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03b32ad3adf7..978f437ecde2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-10-10)](#2023-10-10) +- [ (2023-10-11)](#2023-10-11) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -313,7 +313,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-10-10) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-10-11) ## Breaking Changes @@ -372,6 +372,8 @@ https://github.com/ory/kratos/pull/3480 - chore: generate sdk +- Adjust tracing verbosity + ([976cd0d](https://github.com/ory/kratos/commit/976cd0dc3dd95c2c1992bfa82394e9fad39f34f2)) - Allow post recovery hooks to interrupt the flow ([#3393](https://github.com/ory/kratos/issues/3393)) ([6c1d2f1](https://github.com/ory/kratos/commit/6c1d2f1e4173cfb9a7abe2bfe4f20e47b7568d3b)) @@ -381,9 +383,13 @@ https://github.com/ory/kratos/pull/3480 Fixes https://github.com/ory/kratos/issues/3321 +- Change ListIdentities to keyset pagination + ([e16fed1](https://github.com/ory/kratos/commit/e16fed1f8563509aac30886386668bb85e6dc797)) - Code method on registration and 2fa ([#3481](https://github.com/ory/kratos/issues/3481)) ([7aa2e29](https://github.com/ory/kratos/commit/7aa2e293175d0f4b6c13552cc3781f54f8caf3a0)) +- Data race in test + ([ab6dc31](https://github.com/ory/kratos/commit/ab6dc3121535d27668fed58804a218b17b17ae43)) - Do not encode full config in multiple places ([#3500](https://github.com/ory/kratos/issues/3500)) ([57a3273](https://github.com/ory/kratos/commit/57a3273055c6e8627dd0b736e881dba3fb0fe75d)) From 22f61f015495c55e58db4f31ee6882444b9a3caf Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Wed, 11 Oct 2023 16:06:56 +0200 Subject: [PATCH 134/282] fix: allow updating admin metadata from webhook responses (#3569) --- ...tity_fields-case=identity_has_updated_admin_metadata.json | 2 +- selfservice/hook/web_hook.go | 4 ++-- selfservice/hook/web_hook_integration_test.go | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_has_updated_admin_metadata.json b/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_has_updated_admin_metadata.json index 06206d1517e8..3386716ebdc5 100644 --- a/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_has_updated_admin_metadata.json +++ b/selfservice/hook/.snapshots/TestWebHooks-update_identity_fields-case=update_identity_fields-case=identity_has_updated_admin_metadata.json @@ -44,7 +44,7 @@ "public": "data" }, "metadata_admin": { - "admin": "data" + "useful": "admin metadata" }, "created_at": "0001-01-01T00:00:00Z", "updated_at": "0001-01-01T00:00:00Z", diff --git a/selfservice/hook/web_hook.go b/selfservice/hook/web_hook.go index a21b3e2e444a..b5342ea7dbc1 100644 --- a/selfservice/hook/web_hook.go +++ b/selfservice/hook/web_hook.go @@ -412,10 +412,10 @@ func parseWebhookResponse(resp *http.Response, id *identity.Identity) (err error } if resp.StatusCode == http.StatusOK { + type localIdentity identity.Identity var hookResponse struct { - Identity *identity.Identity `json:"identity"` + Identity *localIdentity `json:"identity"` } - if err := json.NewDecoder(resp.Body).Decode(&hookResponse); err != nil { return errors.Wrap(err, "webhook response could not be unmarshalled properly from JSON") } diff --git a/selfservice/hook/web_hook_integration_test.go b/selfservice/hook/web_hook_integration_test.go index c6a030b2d394..ebff7305c437 100644 --- a/selfservice/hook/web_hook_integration_test.go +++ b/selfservice/hook/web_hook_integration_test.go @@ -609,7 +609,8 @@ func TestWebHooks(t *testing.T) { Header: map[string][]string{ "Some-Header": {"Some-Value"}, "X-Forwarded-Proto": {"https"}, - "Cookie": {"Some-Cookie-1=Some-Cookie-Value; Some-Cookie-2=Some-other-Cookie-Value", "Some-Cookie-3=Third-Cookie-Value"}}, + "Cookie": {"Some-Cookie-1=Some-Cookie-Value; Some-Cookie-2=Some-other-Cookie-Value", "Some-Cookie-3=Third-Cookie-Value"}, + }, RequestURI: "/some_end_point", Method: http.MethodPost, URL: &url.URL{ @@ -712,7 +713,7 @@ func TestWebHooks(t *testing.T) { }) t.Run("case=identity has updated admin metadata", func(t *testing.T) { - actual := run(t, expected, http.StatusOK, []byte(`{"identity":{"metadata_admin":{"useful":"metadata"}}}`)) + actual := run(t, expected, http.StatusOK, []byte(`{"identity":{"metadata_admin":{"useful":"admin metadata"}}}`)) snapshotx.SnapshotT(t, &actual) }) From 200b4138a429d113ee045d16031bb0a6312c1c01 Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Thu, 12 Oct 2023 09:35:14 +0200 Subject: [PATCH 135/282] fix: increase connection-level timeouts and shutdown timeouts (#3570) The admin API is generally expected to require longer timeouts, for example during bulk identity import. --- cmd/daemon/serve.go | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/cmd/daemon/serve.go b/cmd/daemon/serve.go index fbe37dc6b592..e68523243dd5 100644 --- a/cmd/daemon/serve.go +++ b/cmd/daemon/serve.go @@ -69,6 +69,10 @@ func WithContext(ctx stdctx.Context) Option { } } +func init() { + graceful.DefaultShutdownTimeout = 120 * time.Second +} + func servePublic(r driver.Registry, cmd *cobra.Command, eg *errgroup.Group, slOpts *servicelocatorx.Options, opts []Option) { modifiers := NewOptions(cmd.Context(), opts) ctx := modifiers.ctx @@ -132,8 +136,12 @@ func servePublic(r driver.Registry, cmd *cobra.Command, eg *errgroup.Group, slOp //#nosec G112 -- the correct settings are set by graceful.WithDefaults server := graceful.WithDefaults(&http.Server{ - Handler: handler, - TLSConfig: &tls.Config{GetCertificate: certs, MinVersion: tls.VersionTLS12}, + Handler: handler, + TLSConfig: &tls.Config{GetCertificate: certs, MinVersion: tls.VersionTLS12}, + ReadHeaderTimeout: 5 * time.Second, + ReadTimeout: 15 * time.Second, + WriteTimeout: 60 * time.Second, + IdleTimeout: 120 * time.Second, }) addr := c.PublicListenOn(ctx) @@ -206,8 +214,12 @@ func serveAdmin(r driver.Registry, cmd *cobra.Command, eg *errgroup.Group, slOpt //#nosec G112 -- the correct settings are set by graceful.WithDefaults server := graceful.WithDefaults(&http.Server{ - Handler: handler, - TLSConfig: &tls.Config{GetCertificate: certs, MinVersion: tls.VersionTLS12}, + Handler: handler, + TLSConfig: &tls.Config{GetCertificate: certs, MinVersion: tls.VersionTLS12}, + ReadHeaderTimeout: 5 * time.Second, + ReadTimeout: 30 * time.Second, + WriteTimeout: 120 * time.Second, + IdleTimeout: 600 * time.Second, }) addr := c.AdminListenOn(ctx) From e2ac9ff4e2101788f1fca1b8c83f8791cce446e2 Mon Sep 17 00:00:00 2001 From: Patrik Date: Thu, 12 Oct 2023 10:39:15 +0200 Subject: [PATCH 136/282] fix: lower-case recovery & verification emails on import (#3571) Emails that contained upper-case characters would be overwritten by the identity schema extension runner, because there all emails are lower-cased. --- ...mport_users-with_not-normalized_email.json | 34 +++++++++++++++++++ ...tities-case=success-assert=identity_0.json | 10 +++--- identity/handler.go | 8 +++++ identity/handler_test.go | 29 ++++++++++++++-- 4 files changed, 74 insertions(+), 7 deletions(-) create mode 100644 identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_not-normalized_email.json diff --git a/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_not-normalized_email.json b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_not-normalized_email.json new file mode 100644 index 000000000000..c0ee70c28649 --- /dev/null +++ b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_not-normalized_email.json @@ -0,0 +1,34 @@ +{ + "credentials": { + "password": { + "type": "password", + "identifiers": [ + "uppercased@ory.sh" + ], + "config": {}, + "version": 0 + } + }, + "schema_id": "customer", + "state": "active", + "traits": { + "email": "UpperCased@ory.sh" + }, + "verifiable_addresses": [ + { + "value": "uppercased@ory.sh", + "verified": true, + "via": "email", + "status": "completed" + } + ], + "recovery_addresses": [ + { + "value": "uppercased@ory.sh", + "via": "email" + } + ], + "metadata_public": null, + "metadata_admin": null, + "organization_id": null +} diff --git a/identity/.snapshots/TestHandler-suite=PATCH_identities-case=success-assert=identity_0.json b/identity/.snapshots/TestHandler-suite=PATCH_identities-case=success-assert=identity_0.json index 467c98ce96a2..7615886a7304 100644 --- a/identity/.snapshots/TestHandler-suite=PATCH_identities-case=success-assert=identity_0.json +++ b/identity/.snapshots/TestHandler-suite=PATCH_identities-case=success-assert=identity_0.json @@ -16,11 +16,11 @@ "state": "active", "traits": { "emails": [ - "batch-import-0-0@ory.sh", - "batch-import-0-1@ory.sh", - "batch-import-0-2@ory.sh", - "batch-import-0-3@ory.sh" + "Batch-Import-0-0@ory.sh", + "Batch-Import-0-1@ory.sh", + "Batch-Import-0-2@ory.sh", + "Batch-Import-0-3@ory.sh" ], - "username": "batch-import-0-0@ory.sh" + "username": "Batch-Import-0-0@ory.sh" } } diff --git a/identity/handler.go b/identity/handler.go index b4eceae3a515..ce1a9f927ce0 100644 --- a/identity/handler.go +++ b/identity/handler.go @@ -8,6 +8,7 @@ import ( "encoding/json" "io" "net/http" + "strings" "time" "github.com/ory/x/pagination/keysetpagination" @@ -489,6 +490,13 @@ func (h *Handler) identityFromCreateIdentityBody(ctx context.Context, cr *Create MetadataAdmin: []byte(cr.MetadataAdmin), MetadataPublic: []byte(cr.MetadataPublic), } + // Lowercase all emails, because the schema extension will otherwise not find them. + for k := range i.VerifiableAddresses { + i.VerifiableAddresses[k].Value = strings.ToLower(i.VerifiableAddresses[k].Value) + } + for k := range i.RecoveryAddresses { + i.RecoveryAddresses[k].Value = strings.ToLower(i.RecoveryAddresses[k].Value) + } if err := h.importCredentials(ctx, i, cr.Credentials); err != nil { return nil, err diff --git a/identity/handler_test.go b/identity/handler_test.go index f237f6643301..5bba60754761 100644 --- a/identity/handler_test.go +++ b/identity/handler_test.go @@ -299,6 +299,31 @@ func TestHandler(t *testing.T) { }) } }) + + t.Run("with not-normalized email", func(t *testing.T) { + res := send(t, adminTS, "POST", "/identities", http.StatusCreated, identity.CreateIdentityBody{ + SchemaID: "customer", + Traits: []byte(`{"email": "UpperCased@ory.sh"}`), + VerifiableAddresses: []identity.VerifiableAddress{{ + Verified: true, + Value: "UpperCased@ory.sh", + Via: identity.VerifiableAddressTypeEmail, + Status: identity.VerifiableAddressStatusCompleted, + }}, + RecoveryAddresses: []identity.RecoveryAddress{{Value: "UpperCased@ory.sh"}}, + }) + actual, err := reg.PrivilegedIdentityPool().GetIdentityConfidential(ctx, uuid.FromStringOrNil(res.Get("id").String())) + require.NoError(t, err) + + require.Len(t, actual.VerifiableAddresses, 1) + assert.True(t, actual.VerifiableAddresses[0].Verified) + assert.Equal(t, "uppercased@ory.sh", actual.VerifiableAddresses[0].Value) + + require.Len(t, actual.RecoveryAddresses, 1) + assert.Equal(t, "uppercased@ory.sh", actual.RecoveryAddresses[0].Value) + + snapshotx.SnapshotT(t, identity.WithCredentialsAndAdminMetadataInJSON(*actual), snapshotx.ExceptNestedKeys(ignoreDefault...), snapshotx.ExceptNestedKeys("verified_at")) + }) }) t.Run("case=unable to set ID itself", func(t *testing.T) { @@ -708,7 +733,7 @@ func TestHandler(t *testing.T) { t.Run("case=success", func(t *testing.T) { patches := []*identity.BatchIdentityPatch{ - {Create: validCreateIdentityBody("batch-import", 0)}, + {Create: validCreateIdentityBody("Batch-Import", 0)}, {Create: validCreateIdentityBody("batch-import", 1)}, {Create: validCreateIdentityBody("batch-import", 2)}, {Create: validCreateIdentityBody("batch-import", 3)}, @@ -730,7 +755,7 @@ func TestHandler(t *testing.T) { "created_at", "updated_at", "state_changed_at", "verifiable_addresses", "recovery_addresses", "identifiers")) - emails := gjson.GetBytes(patch.Create.Traits, "emails") + emails := gjson.Parse(strings.ToLower(gjson.GetBytes(patch.Create.Traits, "emails").Raw)) assert.Equal(t, identityID, res.Get("id").String()) assert.EqualValues(t, patch.Create.Traits, res.Get("traits").Raw) assertJSONArrayElementsMatch(t, emails, res.Get("credentials.password.identifiers")) From b299abcfa1ebdb8bbb6bb9339f61873d5c77c44f Mon Sep 17 00:00:00 2001 From: Alano Terblanche <18033717+Benehiko@users.noreply.github.com> Date: Thu, 12 Oct 2023 13:59:21 +0200 Subject: [PATCH 137/282] fix: `oidc` does not require a method in the payload (#3564) * fix: `oidc` does not require a method in the payload * refactor: only update strategies order in test * chore: update audit messages and comments --- selfservice/flow/registration/handler_test.go | 109 ++++++++++++++++++ .../stub/registration.schema.json | 4 + .../strategy/oidc/.schema/link.schema.json | 3 + selfservice/strategy/oidc/strategy_login.go | 30 +++-- .../strategy/oidc/strategy_registration.go | 30 +++-- 5 files changed, 159 insertions(+), 17 deletions(-) diff --git a/selfservice/flow/registration/handler_test.go b/selfservice/flow/registration/handler_test.go index 1ed093609400..27df3e0868a5 100644 --- a/selfservice/flow/registration/handler_test.go +++ b/selfservice/flow/registration/handler_test.go @@ -4,6 +4,7 @@ package registration_test import ( + "bytes" "context" "encoding/json" "fmt" @@ -11,9 +12,11 @@ import ( "net/http" "net/http/httptest" "net/url" + "strings" "testing" "time" + "github.com/bxcodec/faker/v3" "github.com/gofrs/uuid" "github.com/ory/kratos/corpx" @@ -30,6 +33,8 @@ import ( "github.com/ory/kratos/internal" "github.com/ory/kratos/internal/testhelpers" "github.com/ory/kratos/selfservice/flow/registration" + "github.com/ory/kratos/selfservice/strategy/oidc" + "github.com/ory/kratos/selfservice/strategy/password" "github.com/ory/kratos/x" ) @@ -376,3 +381,107 @@ func TestGetFlow(t *testing.T) { assert.EqualValues(t, http.StatusNotFound, res.StatusCode) }) } + +// This test verifies that the password method is still executed even if the +// oidc strategy is ordered before the password strategy +// when submitting the form with both `method=password` and `provider=google`. +func TestOIDCStrategyOrder(t *testing.T) { + t.Logf("This test has been set up to validate the current incorrect `oidc` behaviour. When submitting the form, the `oidc` strategy is executed first, even if the method is set to `password`.") + + ctx := context.Background() + conf, reg := internal.NewFastRegistryWithMocks(t) + + // reorder the strategies + reg.WithSelfserviceStrategies(t, []any{ + oidc.NewStrategy(reg), + password.NewStrategy(reg), + }) + + conf.MustSet(ctx, config.ViperKeySelfServiceRegistrationEnabled, true) + testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/registration.schema.json") + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+"."+string(identity.CredentialsTypePassword), + map[string]interface{}{"enabled": true}) + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+"."+string(identity.CredentialsTypeOIDC), + map[string]interface{}{"enabled": true}) + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+"."+string(identity.CredentialsTypeCodeAuth), + map[string]interface{}{"passwordless_enabled": true}) + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+"."+string(identity.CredentialsTypeOIDC)+".config", &oidc.ConfigurationCollection{Providers: []oidc.Configuration{ + { + ID: "google", + Provider: "google", + ClientID: "1234", + ClientSecret: "1234", + }, + }}) + + public, _ := testhelpers.NewKratosServerWithCSRF(t, reg) + _ = testhelpers.NewErrorTestServer(t, reg) + _ = testhelpers.NewRedirTS(t, "", conf) + + setupRegistrationUI := func(t *testing.T, c *http.Client) *httptest.Server { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + _, err := w.Write(x.EasyGetBody(t, c, public.URL+registration.RouteGetFlow+"?id="+r.URL.Query().Get("flow"))) + require.NoError(t, err) + })) + t.Cleanup(ts.Close) + conf.MustSet(ctx, config.ViperKeySelfServiceRegistrationUI, ts.URL) + return ts + } + + t.Run("case=accept `password` method while including `provider:google`", func(t *testing.T) { + client := testhelpers.NewClientWithCookies(t) + _ = setupRegistrationUI(t, client) + body := x.EasyGetBody(t, client, public.URL+registration.RouteInitBrowserFlow) + + flow := gjson.GetBytes(body, "id").String() + + csrfToken := gjson.GetBytes(body, "ui.nodes.#(attributes.name==csrf_token).attributes.value").String() + email := faker.Email() + payload := json.RawMessage(`{"traits": {"email": "` + email + `"},"method": "password","password": "asdasdasdsa21312@#!@%","provider": "google","csrf_token": "` + csrfToken + `"}`) + + req, err := http.NewRequestWithContext(context.Background(), http.MethodPost, public.URL+registration.RouteSubmitFlow+"?flow="+flow, bytes.NewBuffer(payload)) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Accept", "application/json") + + require.NoError(t, err) + resp, err := client.Do(req) + require.NoError(t, err) + + require.Equal(t, http.StatusOK, resp.StatusCode) + + verifiableAddress, err := reg.PrivilegedIdentityPool().FindVerifiableAddressByValue(ctx, identity.VerifiableAddressTypeEmail, email) + require.NoError(t, err) + require.Equal(t, strings.ToLower(email), verifiableAddress.Value) + + id, err := reg.PrivilegedIdentityPool().GetIdentityConfidential(ctx, verifiableAddress.IdentityID) + require.NoError(t, err) + require.NotNil(t, id.ID) + + _, ok := id.GetCredentials(identity.CredentialsTypePassword) + require.True(t, ok) + }) + + t.Run("case=accept oidc flow with just `provider:google`", func(t *testing.T) { + client := testhelpers.NewClientWithCookies(t) + _ = setupRegistrationUI(t, client) + body := x.EasyGetBody(t, client, public.URL+registration.RouteInitBrowserFlow) + + flow := gjson.GetBytes(body, "id").String() + + csrfToken := gjson.GetBytes(body, "ui.nodes.#(attributes.name==csrf_token).attributes.value").String() + + payload := json.RawMessage(`{"provider": "google","csrf_token": "` + csrfToken + `"}`) + + req, err := http.NewRequestWithContext(context.Background(), http.MethodPost, public.URL+registration.RouteSubmitFlow+"?flow="+flow, bytes.NewBuffer(payload)) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Accept", "application/json") + + resp, err := client.Do(req) + require.NoError(t, err) + defer resp.Body.Close() + require.Equal(t, http.StatusUnprocessableEntity, resp.StatusCode) + b, err := io.ReadAll(resp.Body) + require.NoError(t, err) + require.Containsf(t, gjson.GetBytes(b, "error.reason").String(), "In order to complete this flow please redirect the browser to: https://accounts.google.com/o/oauth2/v2/auth", "accounts.google.com", "%s", b) + }) +} diff --git a/selfservice/flow/registration/stub/registration.schema.json b/selfservice/flow/registration/stub/registration.schema.json index 78fcb22c6587..e591660812a3 100644 --- a/selfservice/flow/registration/stub/registration.schema.json +++ b/selfservice/flow/registration/stub/registration.schema.json @@ -16,6 +16,10 @@ "credentials": { "password": { "identifier": true + }, + "code": { + "identifier": true, + "via": "email" } }, "verification": { diff --git a/selfservice/strategy/oidc/.schema/link.schema.json b/selfservice/strategy/oidc/.schema/link.schema.json index 1c174841244e..aae8e86f2626 100644 --- a/selfservice/strategy/oidc/.schema/link.schema.json +++ b/selfservice/strategy/oidc/.schema/link.schema.json @@ -17,6 +17,9 @@ "type": "object", "additionalProperties": true }, + "method": { + "type": "string" + }, "upstream_parameters": { "type": "object", "$comment": "Only the defined parameters are allowed. This is to prevent users from sending arbitrary parameters or craft URLs that cause unexpected behavior.", diff --git a/selfservice/strategy/oidc/strategy_login.go b/selfservice/strategy/oidc/strategy_login.go index 5150eabcda52..c81537015bc9 100644 --- a/selfservice/strategy/oidc/strategy_login.go +++ b/selfservice/strategy/oidc/strategy_login.go @@ -7,6 +7,7 @@ import ( "bytes" "encoding/json" "net/http" + "strings" "time" "github.com/julienschmidt/httprouter" @@ -181,13 +182,16 @@ func (s *Strategy) processLogin(w http.ResponseWriter, r *http.Request, loginFlo } func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, _ uuid.UUID) (i *identity.Identity, err error) { + ctx, span := s.d.Tracer(r.Context()).Tracer().Start(r.Context(), "selfservice.strategy.oidc.strategy.Login") + defer span.End() + if err := login.CheckAAL(f, identity.AuthenticatorAssuranceLevel1); err != nil { return nil, err } var p UpdateLoginFlowWithOidcMethod if err := s.newLinkDecoder(&p, r); err != nil { - return nil, s.handleError(w, r, f, "", nil, errors.WithStack(herodot.ErrBadRequest.WithDebug(err.Error()).WithReasonf("Unable to parse HTTP form request: %s", err.Error()))) + return nil, s.handleError(w, r, f, "", nil, err) } f.IDToken = p.IDToken @@ -198,21 +202,31 @@ func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, return nil, errors.WithStack(flow.ErrStrategyNotResponsible) } - if err := flow.MethodEnabledAndAllowed(r.Context(), f.GetFlowName(), s.SettingsStrategyID(), s.SettingsStrategyID(), s.d); err != nil { + if !strings.EqualFold(strings.ToLower(p.Method), s.SettingsStrategyID()) && p.Method != "" { + // the user is sending a method that is not oidc, but the payload includes a provider + s.d.Audit(). + WithRequest(r). + WithField("provider", p.Provider). + WithField("method", p.Method). + Warn("The payload includes a `provider` field but is using a method other than `oidc`. Therefore, social sign in will not be executed.") + return nil, errors.WithStack(flow.ErrStrategyNotResponsible) + } + + if err := flow.MethodEnabledAndAllowed(ctx, f.GetFlowName(), s.SettingsStrategyID(), s.SettingsStrategyID(), s.d); err != nil { return nil, s.handleError(w, r, f, pid, nil, err) } - provider, err := s.provider(r.Context(), r, pid) + provider, err := s.provider(ctx, r, pid) if err != nil { return nil, s.handleError(w, r, f, pid, nil, err) } - c, err := provider.OAuth2(r.Context()) + c, err := provider.OAuth2(ctx) if err != nil { return nil, s.handleError(w, r, f, pid, nil, err) } - req, err := s.validateFlow(r.Context(), r, f.ID) + req, err := s.validateFlow(ctx, r, f.ID) if err != nil { return nil, s.handleError(w, r, f, pid, nil, err) } @@ -239,10 +253,10 @@ func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, } state := generateState(f.ID.String()) - if code, hasCode, _ := s.d.SessionTokenExchangePersister().CodeForFlow(r.Context(), f.ID); hasCode { + if code, hasCode, _ := s.d.SessionTokenExchangePersister().CodeForFlow(ctx, f.ID); hasCode { state.setCode(code.InitCode) } - if err := s.d.ContinuityManager().Pause(r.Context(), w, r, sessionName, + if err := s.d.ContinuityManager().Pause(ctx, w, r, sessionName, continuity.WithPayload(&AuthCodeContainer{ State: state.String(), FlowID: f.ID.String(), @@ -253,7 +267,7 @@ func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, } f.Active = s.ID() - if err = s.d.LoginFlowPersister().UpdateLoginFlow(r.Context(), f); err != nil { + if err = s.d.LoginFlowPersister().UpdateLoginFlow(ctx, f); err != nil { return nil, s.handleError(w, r, f, pid, nil, errors.WithStack(herodot.ErrInternalServerError.WithReason("Could not update flow").WithDebug(err.Error()))) } diff --git a/selfservice/strategy/oidc/strategy_registration.go b/selfservice/strategy/oidc/strategy_registration.go index 13c6a448c047..b6747ef9ad0a 100644 --- a/selfservice/strategy/oidc/strategy_registration.go +++ b/selfservice/strategy/oidc/strategy_registration.go @@ -13,6 +13,7 @@ import ( "github.com/gofrs/uuid" "github.com/julienschmidt/httprouter" + "github.com/ory/x/otelx" "github.com/ory/x/sqlxx" "github.com/ory/herodot" @@ -151,6 +152,9 @@ func (s *Strategy) newLinkDecoder(p interface{}, r *http.Request) error { } func (s *Strategy) Register(w http.ResponseWriter, r *http.Request, f *registration.Flow, i *identity.Identity) (err error) { + ctx, span := s.d.Tracer(r.Context()).Tracer().Start(r.Context(), "selfservice.strategy.oidc.strategy.Register") + defer otelx.End(span, &err) + var p UpdateRegistrationFlowWithOidcMethod if err := s.newLinkDecoder(&p, r); err != nil { return s.handleError(w, r, f, "", nil, err) @@ -165,21 +169,31 @@ func (s *Strategy) Register(w http.ResponseWriter, r *http.Request, f *registrat return errors.WithStack(flow.ErrStrategyNotResponsible) } - if err := flow.MethodEnabledAndAllowed(r.Context(), f.GetFlowName(), s.SettingsStrategyID(), s.SettingsStrategyID(), s.d); err != nil { + if !strings.EqualFold(strings.ToLower(p.Method), s.SettingsStrategyID()) && p.Method != "" { + // the user is sending a method that is not oidc, but the payload includes a provider + s.d.Audit(). + WithRequest(r). + WithField("provider", p.Provider). + WithField("method", p.Method). + Warn("The payload includes a `provider` field but is using a method other than `oidc`. Therefore, social sign in will not be executed.") + return errors.WithStack(flow.ErrStrategyNotResponsible) + } + + if err := flow.MethodEnabledAndAllowed(ctx, f.GetFlowName(), s.SettingsStrategyID(), s.SettingsStrategyID(), s.d); err != nil { return s.handleError(w, r, f, pid, nil, err) } - provider, err := s.provider(r.Context(), r, pid) + provider, err := s.provider(ctx, r, pid) if err != nil { return s.handleError(w, r, f, pid, nil, err) } - c, err := provider.OAuth2(r.Context()) + c, err := provider.OAuth2(ctx) if err != nil { return s.handleError(w, r, f, pid, nil, err) } - req, err := s.validateFlow(r.Context(), r, f.ID) + req, err := s.validateFlow(ctx, r, f.ID) if err != nil { return s.handleError(w, r, f, pid, nil, err) } @@ -207,10 +221,10 @@ func (s *Strategy) Register(w http.ResponseWriter, r *http.Request, f *registrat } state := generateState(f.ID.String()) - if code, hasCode, _ := s.d.SessionTokenExchangePersister().CodeForFlow(r.Context(), f.ID); hasCode { + if code, hasCode, _ := s.d.SessionTokenExchangePersister().CodeForFlow(ctx, f.ID); hasCode { state.setCode(code.InitCode) } - if err := s.d.ContinuityManager().Pause(r.Context(), w, r, sessionName, + if err := s.d.ContinuityManager().Pause(ctx, w, r, sessionName, continuity.WithPayload(&AuthCodeContainer{ State: state.String(), FlowID: f.ID.String(), @@ -321,9 +335,7 @@ func (s *Strategy) processRegistration(w http.ResponseWriter, r *http.Request, r } var it string = idToken - var ( - cat, crt string - ) + var cat, crt string if token != nil { if idToken, ok := token.Extra("id_token").(string); ok { if it, err = s.d.Cipher(r.Context()).Encrypt(r.Context(), []byte(idToken)); err != nil { From 13de64dafc882c4acf7cec9300af0f3e233b0167 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Thu, 12 Oct 2023 13:05:55 +0000 Subject: [PATCH 138/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 978f437ecde2..5d87329fcb36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-10-11)](#2023-10-11) +- [ (2023-10-12)](#2023-10-12) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -313,7 +313,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-10-11) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-10-12) ## Breaking Changes @@ -348,6 +348,16 @@ https://github.com/ory/kratos/pull/3480 ### Bug Fixes +- `oidc` does not require a method in the payload + ([#3564](https://github.com/ory/kratos/issues/3564)) + ([b299abc](https://github.com/ory/kratos/commit/b299abcfa1ebdb8bbb6bb9339f61873d5c77c44f)): + + - fix: `oidc` does not require a method in the payload + + - refactor: only update strategies order in test + + - chore: update audit messages and comments + - Accept all 200 responses as OK in courier ([#3401](https://github.com/ory/kratos/issues/3401)) ([88237e2](https://github.com/ory/kratos/commit/88237e25b080a9643f6cbf7eedbf23988ba9ba7c)), @@ -377,6 +387,9 @@ https://github.com/ory/kratos/pull/3480 - Allow post recovery hooks to interrupt the flow ([#3393](https://github.com/ory/kratos/issues/3393)) ([6c1d2f1](https://github.com/ory/kratos/commit/6c1d2f1e4173cfb9a7abe2bfe4f20e47b7568d3b)) +- Allow updating admin metadata from webhook responses + ([#3569](https://github.com/ory/kratos/issues/3569)) + ([22f61f0](https://github.com/ory/kratos/commit/22f61f015495c55e58db4f31ee6882444b9a3caf)) - Carry `oauth2_login_challenge` over to registration flow ([#3419](https://github.com/ory/kratos/issues/3419)) ([76241be](https://github.com/ory/kratos/commit/76241bee3dc7fec4690346ee85bc4b9f897fdd34)): @@ -425,9 +438,23 @@ https://github.com/ory/kratos/pull/3480 - Incorrect sdk generator path ([#3488](https://github.com/ory/kratos/issues/3488)) ([ed996c0](https://github.com/ory/kratos/commit/ed996c0d25e68e8a2c7de861c546f0b0e42e9e6e)) +- Increase connection-level timeouts and shutdown timeouts + ([#3570](https://github.com/ory/kratos/issues/3570)) + ([200b413](https://github.com/ory/kratos/commit/200b4138a429d113ee045d16031bb0a6312c1c01)): + + The admin API is generally expected to require longer timeouts, for example + during bulk identity import. + - Issue session after verification after registration with OIDC SSO ([#3467](https://github.com/ory/kratos/issues/3467)) ([a28b523](https://github.com/ory/kratos/commit/a28b523238743f3873b51479eea3b86d684092f9)) +- Lower-case recovery & verification emails on import + ([#3571](https://github.com/ory/kratos/issues/3571)) + ([e2ac9ff](https://github.com/ory/kratos/commit/e2ac9ff4e2101788f1fca1b8c83f8791cce446e2)): + + Emails that contained upper-case characters would be overwritten by the + identity schema extension runner, because there all emails are lower-cased. + - Mark identity as optional in session struct ([#3463](https://github.com/ory/kratos/issues/3463)) ([7ae02ba](https://github.com/ory/kratos/commit/7ae02ba697f68c9cfae5fe8f696b2c55a3ba9ddc)), From 0a0e1f7200e226ef24de062811a05bcdd02b6acd Mon Sep 17 00:00:00 2001 From: Tristan Kenney Date: Fri, 13 Oct 2023 01:41:41 +1100 Subject: [PATCH 139/282] feat: allow importing hmac hashed passwords (#3544) The basic format is `$hmac-$$`: ``` # password = test; key=key; hash function=sha $hmac-sha1$NjcxZjU0Y2UwYzU0MGY3OGZmZTFlMjZkY2Y5YzJhMDQ3YWVhNGZkYQ==$a2V5 ``` See #2422 --- hash/hash_comparator.go | 80 +++++++++++- hash/hasher_test.go | 121 ++++++++++++++++++ ...users-with_hashed_passwords-hash=hmac.json | 21 +++ identity/handler_test.go | 4 + 4 files changed, 225 insertions(+), 1 deletion(-) create mode 100644 identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=hmac.json diff --git a/hash/hash_comparator.go b/hash/hash_comparator.go index 0200e08cad22..e68c1e663286 100644 --- a/hash/hash_comparator.go +++ b/hash/hash_comparator.go @@ -8,13 +8,16 @@ import ( "context" "crypto/aes" "crypto/cipher" + "crypto/hmac" "crypto/md5" //#nosec G501 -- compatibility for imported passwords "crypto/sha1" //#nosec G505 -- compatibility for imported passwords "crypto/sha256" "crypto/sha512" "crypto/subtle" "encoding/base64" + "encoding/hex" "fmt" + "hash" "regexp" "strings" @@ -23,6 +26,10 @@ import ( "go.opentelemetry.io/otel/attribute" "golang.org/x/crypto/argon2" "golang.org/x/crypto/bcrypt" + + //nolint:staticcheck + //lint:ignore SA1019 + "golang.org/x/crypto/md4" //#nosec G501 -- compatibility for imported passwords "golang.org/x/crypto/pbkdf2" "golang.org/x/crypto/scrypt" @@ -94,6 +101,9 @@ func Compare(ctx context.Context, password []byte, hash []byte) error { case IsMD5Hash(hash): span.SetAttributes(attribute.String("hash.type", "md5")) return CompareMD5(ctx, password, hash) + case IsHMACHash(hash): + span.SetAttributes(attribute.String("hash.type", "hmac")) + return CompareHMAC(ctx, password, hash) default: span.SetAttributes(attribute.String("hash.type", "unknown")) return errors.WithStack(ErrUnknownHashAlgorithm) @@ -270,6 +280,24 @@ func CompareMD5(_ context.Context, password []byte, hash []byte) error { return comparePasswordHashConstantTime(hash, otherHash[:]) } +func CompareHMAC(_ context.Context, password []byte, hash []byte) error { + // Extract the hash from the encoded password + hasher, hash, key, err := decodeHMACHash(string(hash)) + if err != nil { + return err + } + + mac := hmac.New(hasher, key) + _, err = mac.Write([]byte(password)) + if err != nil { + return err + } + + otherHash := []byte(hex.EncodeToString(mac.Sum(nil))) + + return comparePasswordHashConstantTime(hash, otherHash) +} + var ( isMD5CryptHash = regexp.MustCompile(`^\$md5-crypt\$`) isBcryptHash = regexp.MustCompile(`^\$2[abzy]?\$`) @@ -283,6 +311,7 @@ var ( isSHAHash = regexp.MustCompile(`^\$sha(1|256|512)\$`) isFirebaseScryptHash = regexp.MustCompile(`^\$firescrypt\$`) isMD5Hash = regexp.MustCompile(`^\$md5\$`) + isHMACHash = regexp.MustCompile(`^\$hmac-(md4|md5|sha1|sha224|sha256|sha384|sha512)\$`) ) func IsMD5CryptHash(hash []byte) bool { return isMD5CryptHash.Match(hash) } @@ -297,6 +326,7 @@ func IsSSHAHash(hash []byte) bool { return isSSHAHash.Match(hash) } func IsSHAHash(hash []byte) bool { return isSHAHash.Match(hash) } func IsFirebaseScryptHash(hash []byte) bool { return isFirebaseScryptHash.Match(hash) } func IsMD5Hash(hash []byte) bool { return isMD5Hash.Match(hash) } +func IsHMACHash(hash []byte) bool { return isHMACHash.Match(hash) } func IsValidHashFormat(hash []byte) bool { if IsMD5CryptHash(hash) || @@ -310,7 +340,8 @@ func IsValidHashFormat(hash []byte) bool { IsSSHAHash(hash) || IsSHAHash(hash) || IsFirebaseScryptHash(hash) || - IsMD5Hash(hash) { + IsMD5Hash(hash) || + IsHMACHash(hash) { return true } else { return false @@ -614,6 +645,53 @@ func decodeMD5Hash(encodedHash string) (pf, salt, hash []byte, err error) { } } +// decodeHMACHash decodes HMAC encoded password hash. +// format : $hmac-$$ +func decodeHMACHash(encodedHash string) (hasher func() hash.Hash, hash, key []byte, err error) { + parts := strings.Split(encodedHash, "$") + + if len(parts) != 4 { + return nil, nil, nil, ErrInvalidHash + } + + hashMatch := isHMACHash.FindStringSubmatch(encodedHash) + + if len(hashMatch) != 2 { + return nil, nil, nil, errors.WithStack(ErrUnknownHashAlgorithm) + } + + switch hashMatch[1] { + case "md4": + hasher = md4.New //#nosec G401 -- compatibility for imported passwords + case "md5": + hasher = md5.New //#nosec G401 -- compatibility for imported passwords + case "sha1": + hasher = sha1.New //#nosec G401 -- compatibility for imported passwords + case "sha224": + hasher = sha256.New224 + case "sha256": + hasher = sha256.New + case "sha384": + hasher = sha512.New384 + case "sha512": + hasher = sha512.New + default: + return nil, nil, nil, errors.WithStack(ErrUnknownHashAlgorithm) + } + + hash, err = base64.StdEncoding.Strict().DecodeString(parts[2]) + if err != nil { + return nil, nil, nil, err + } + + key, err = base64.StdEncoding.Strict().DecodeString(parts[3]) + if err != nil { + return nil, nil, nil, err + } + + return hasher, hash, key, nil +} + func comparePasswordHashConstantTime(hash, otherHash []byte) error { // use subtle.ConstantTimeCompare() to prevent timing attacks. if subtle.ConstantTimeCompare(hash, otherHash) == 1 { diff --git a/hash/hasher_test.go b/hash/hasher_test.go index f2fa9d4fdab7..dc715d3d141f 100644 --- a/hash/hasher_test.go +++ b/hash/hasher_test.go @@ -413,4 +413,125 @@ func TestCompare(t *testing.T) { assert.Error(t, hash.Compare(context.Background(), []byte("ory"), []byte("$sha512-crypt$$")), "shacrypt decode error: provided encoded hash has an invalid format") assert.Error(t, hash.Compare(context.Background(), []byte("ory"), []byte("$sha512-crypt$$$"))) }) + + t.Run("hmac errors", func(t *testing.T) { + t.Parallel() + + //Missing Key + assert.ErrorIs(t, hash.Compare(context.Background(), []byte("test"), []byte("$hmac-md5$ZmU4Njk3Zjc0MmQwODA0MDVkMTI3MGU2MTYzMzE2Zjk=")), hash.ErrInvalidHash) + assert.Error(t, hash.CompareHMAC(context.Background(), []byte("test"), []byte("$hmac-md5$ZmU4Njk3Zjc0MmQwODA0MDVkMTI3MGU2MTYzMzE2Zjk="))) + assert.ErrorIs(t, hash.Compare(context.Background(), []byte("test"), []byte("$hmac-md5$ZmU4Njk3Zjc0MmQwODA0MDVkMTI3MGU2MTYzMzE2Zjk=$")), hash.ErrMismatchedHashAndPassword) + assert.Error(t, hash.CompareHMAC(context.Background(), []byte("test"), []byte("$hmac-md5$ZmU4Njk3Zjc0MmQwODA0MDVkMTI3MGU2MTYzMzE2Zjk=$"))) + //Missing Password Hash + assert.ErrorIs(t, hash.Compare(context.Background(), []byte("test"), []byte("$hmac-md5$MTIzNDU=")), hash.ErrInvalidHash) + assert.Error(t, hash.CompareHMAC(context.Background(), []byte("test"), []byte("$hmac-md5$MTIzNDU="))) + assert.ErrorIs(t, hash.Compare(context.Background(), []byte("test"), []byte("$hmac-md5$$MTIzNDU=")), hash.ErrMismatchedHashAndPassword) + assert.Error(t, hash.CompareHMAC(context.Background(), []byte("test"), []byte("$hmac-md5$$MTIzNDU="))) + //Missing Password Hash and Key + assert.ErrorIs(t, hash.Compare(context.Background(), []byte("test"), []byte("$hmac-md5$")), hash.ErrInvalidHash) + assert.Error(t, hash.CompareHMAC(context.Background(), []byte("test"), []byte("$hmac-md5$"))) + //Missing Hash Algorithm + assert.ErrorIs(t, hash.Compare(context.Background(), []byte("test"), []byte("$hmac$ZmU4Njk3Zjc0MmQwODA0MDVkMTI3MGU2MTYzMzE2Zjk=$MTIzNDU=")), hash.ErrUnknownHashAlgorithm) + assert.Error(t, hash.CompareHMAC(context.Background(), []byte("test"), []byte("$hmac$ZmU4Njk3Zjc0MmQwODA0MDVkMTI3MGU2MTYzMzE2Zjk=$MTIzNDU="))) + //Missing Invalid Hash Algorithm + assert.ErrorIs(t, hash.Compare(context.Background(), []byte("test"), []byte("$hmac-invalid$ZmU4Njk3Zjc0MmQwODA0MDVkMTI3MGU2MTYzMzE2Zjk=$MTIzNDU=")), hash.ErrUnknownHashAlgorithm) + assert.Error(t, hash.CompareHMAC(context.Background(), []byte("test"), []byte("$hmac-invalid$ZmU4Njk3Zjc0MmQwODA0MDVkMTI3MGU2MTYzMzE2Zjk=$MTIzNDU="))) + + }) + + t.Run("hmac-md4", func(t *testing.T) { + t.Parallel() + + //Valid + assert.Nil(t, hash.Compare(context.Background(), []byte("test"), []byte("$hmac-md4$MWQ5ZTI4Nzc2Zjg4YmE2MTQ5YjQ0OTMyOGE4NWU4YjA=$MTIzNDU="))) + assert.Nil(t, hash.CompareHMAC(context.Background(), []byte("test"), []byte("$hmac-md4$MWQ5ZTI4Nzc2Zjg4YmE2MTQ5YjQ0OTMyOGE4NWU4YjA=$MTIzNDU="))) + //Wrong Key + assert.Error(t, hash.Compare(context.Background(), []byte("test"), []byte("$hmac-md4$MWQ5ZTI4Nzc2Zjg4YmE2MTQ5YjQ0OTMyOGE4NWU4YjA=$MTIzNA==")), hash.ErrMismatchedHashAndPassword) + //Different password + assert.Error(t, hash.Compare(context.Background(), []byte("ory"), []byte("$hmac-md4$MWQ5ZTI4Nzc2Zjg4YmE2MTQ5YjQ0OTMyOGE4NWU4YjA=$MTIzNDU="))) + }) + + t.Run("hmac-md5", func(t *testing.T) { + t.Parallel() + + //Valid + assert.Nil(t, hash.Compare(context.Background(), []byte("test"), []byte("$hmac-md5$ZmU4Njk3Zjc0MmQwODA0MDVkMTI3MGU2MTYzMzE2Zjk=$MTIzNDU="))) + assert.Nil(t, hash.CompareHMAC(context.Background(), []byte("test"), []byte("$hmac-md5$ZmU4Njk3Zjc0MmQwODA0MDVkMTI3MGU2MTYzMzE2Zjk=$MTIzNDU="))) + + //Wrong Key + assert.Error(t, hash.Compare(context.Background(), []byte("test"), []byte("$hmac-md5$ZmU4Njk3Zjc0MmQwODA0MDVkMTI3MGU2MTYzMzE2Zjk=$MTIzNA=="))) + //Different password + assert.Error(t, hash.Compare(context.Background(), []byte("ory"), []byte("$hmac-md5$ZmU4Njk3Zjc0MmQwODA0MDVkMTI3MGU2MTYzMzE2Zjk=$MTIzNDU="))) + + }) + + t.Run("hmac-sha1", func(t *testing.T) { + t.Parallel() + + //Valid + assert.Nil(t, hash.Compare(context.Background(), []byte("test"), []byte("$hmac-sha1$NDMyNjcxZTUyY2Y2YTBmYjZjZDE2NjQxYjAwNjFiZjAwOGEzNWM5MA==$MTIzNDU="))) + assert.Nil(t, hash.CompareHMAC(context.Background(), []byte("test"), []byte("$hmac-sha1$NDMyNjcxZTUyY2Y2YTBmYjZjZDE2NjQxYjAwNjFiZjAwOGEzNWM5MA==$MTIzNDU="))) + + //Wrong Key + assert.Error(t, hash.Compare(context.Background(), []byte("test"), []byte("$hmac-sha1$NDMyNjcxZTUyY2Y2YTBmYjZjZDE2NjQxYjAwNjFiZjAwOGEzNWM5MA==$MTIzNA=="))) + //Different password + assert.Error(t, hash.Compare(context.Background(), []byte("ory"), []byte("$hmac-sha1$NDMyNjcxZTUyY2Y2YTBmYjZjZDE2NjQxYjAwNjFiZjAwOGEzNWM5MA==$MTIzNDU="))) + + }) + + t.Run("hmac-sha224", func(t *testing.T) { + t.Parallel() + + //Valid + assert.Nil(t, hash.Compare(context.Background(), []byte("test"), []byte("$hmac-sha224$YmUwYmYzM2EwNGRlNDE0YjQzNjBhNmIyOThmNmIyYzI4OWQyMzk3MDUwZDFjMzliYjVmMDMyOTQ=$MTIzNDU="))) + assert.Nil(t, hash.CompareHMAC(context.Background(), []byte("test"), []byte("$hmac-sha224$YmUwYmYzM2EwNGRlNDE0YjQzNjBhNmIyOThmNmIyYzI4OWQyMzk3MDUwZDFjMzliYjVmMDMyOTQ=$MTIzNDU="))) + + //Wrong Key + assert.Error(t, hash.Compare(context.Background(), []byte("test"), []byte("$hmac-sha224$YmUwYmYzM2EwNGRlNDE0YjQzNjBhNmIyOThmNmIyYzI4OWQyMzk3MDUwZDFjMzliYjVmMDMyOTQ=$MTIzNA=="))) + //Different password + assert.Error(t, hash.Compare(context.Background(), []byte("ory"), []byte("$hmac-sha224$YmUwYmYzM2EwNGRlNDE0YjQzNjBhNmIyOThmNmIyYzI4OWQyMzk3MDUwZDFjMzliYjVmMDMyOTQ=$MTIzNDU="))) + + }) + + t.Run("hmac-sha256", func(t *testing.T) { + t.Parallel() + + //Valid + assert.Nil(t, hash.Compare(context.Background(), []byte("test"), []byte("$hmac-sha256$ZTAzMWJhMWMyOTM4YjFkMjgzZjkxOWExZGY5YWM2NmMxOTJhN2RkNzQ0MzJkNWZkNGFkYTI5OTk0MWJhMTA5Zg==$MTIzNDU="))) + assert.Nil(t, hash.CompareHMAC(context.Background(), []byte("test"), []byte("$hmac-sha256$ZTAzMWJhMWMyOTM4YjFkMjgzZjkxOWExZGY5YWM2NmMxOTJhN2RkNzQ0MzJkNWZkNGFkYTI5OTk0MWJhMTA5Zg==$MTIzNDU="))) + + //Wrong Key + assert.Error(t, hash.Compare(context.Background(), []byte("test"), []byte("$hmac-sha256$ZTAzMWJhMWMyOTM4YjFkMjgzZjkxOWExZGY5YWM2NmMxOTJhN2RkNzQ0MzJkNWZkNGFkYTI5OTk0MWJhMTA5Zg==$MTIzNA=="))) + //Different password + assert.Error(t, hash.Compare(context.Background(), []byte("ory"), []byte("$hmac-sha256$ZTAzMWJhMWMyOTM4YjFkMjgzZjkxOWExZGY5YWM2NmMxOTJhN2RkNzQ0MzJkNWZkNGFkYTI5OTk0MWJhMTA5Zg==$MTIzNDU="))) + + }) + + t.Run("hmac-sha384", func(t *testing.T) { + t.Parallel() + + //Valid + assert.Nil(t, hash.Compare(context.Background(), []byte("test"), []byte("$hmac-sha384$ZWEyMGM3NGE4Y2UzMTljNTdjZTlhZGQyYTZjNDE0MGQ4YjMwYWIwOWM4OTRiNWQ4MmZjODlhMzBhMmQzNGE5NmQ0NDY1NWRhYjQ2ZjhiYjBkNTRmYjk5YWZkZTA1MGY1$MTIzNDU="))) + assert.Nil(t, hash.CompareHMAC(context.Background(), []byte("test"), []byte("$hmac-sha384$ZWEyMGM3NGE4Y2UzMTljNTdjZTlhZGQyYTZjNDE0MGQ4YjMwYWIwOWM4OTRiNWQ4MmZjODlhMzBhMmQzNGE5NmQ0NDY1NWRhYjQ2ZjhiYjBkNTRmYjk5YWZkZTA1MGY1$MTIzNDU="))) + + //Wrong Key + assert.Error(t, hash.Compare(context.Background(), []byte("test"), []byte("$hmac-sha384$ZWEyMGM3NGE4Y2UzMTljNTdjZTlhZGQyYTZjNDE0MGQ4YjMwYWIwOWM4OTRiNWQ4MmZjODlhMzBhMmQzNGE5NmQ0NDY1NWRhYjQ2ZjhiYjBkNTRmYjk5YWZkZTA1MGY1$MTIzNA=="))) + //Different password + assert.Error(t, hash.Compare(context.Background(), []byte("ory"), []byte("$hmac-sha384$ZWEyMGM3NGE4Y2UzMTljNTdjZTlhZGQyYTZjNDE0MGQ4YjMwYWIwOWM4OTRiNWQ4MmZjODlhMzBhMmQzNGE5NmQ0NDY1NWRhYjQ2ZjhiYjBkNTRmYjk5YWZkZTA1MGY1$MTIzNDU="))) + + }) + + t.Run("hmac-sha512", func(t *testing.T) { + t.Parallel() + + //Valid + assert.Nil(t, hash.Compare(context.Background(), []byte("test"), []byte("$hmac-sha512$OTFmODY0ZTI1NmU0ZjVhYjhiMDViZGFmNGVmNGZmMGVlNTY4ODYwNWJhYTk4MTk2OTgyMzc3NzI1YTc4MzcxMTMzNzZmY2YxYTk5MGMxM2RiZDk2MGFmMmQ1YzRmODdlMGMwYTNkYjcyNjY0NjM4NGE4YzQ2MjNhZDZkN2UxZTE=$MTIzNDU="))) + assert.Nil(t, hash.CompareHMAC(context.Background(), []byte("test"), []byte("$hmac-sha512$OTFmODY0ZTI1NmU0ZjVhYjhiMDViZGFmNGVmNGZmMGVlNTY4ODYwNWJhYTk4MTk2OTgyMzc3NzI1YTc4MzcxMTMzNzZmY2YxYTk5MGMxM2RiZDk2MGFmMmQ1YzRmODdlMGMwYTNkYjcyNjY0NjM4NGE4YzQ2MjNhZDZkN2UxZTE=$MTIzNDU="))) + + //Wrong Key + assert.Error(t, hash.Compare(context.Background(), []byte("test"), []byte("$hmac-sha512$OTFmODY0ZTI1NmU0ZjVhYjhiMDViZGFmNGVmNGZmMGVlNTY4ODYwNWJhYTk4MTk2OTgyMzc3NzI1YTc4MzcxMTMzNzZmY2YxYTk5MGMxM2RiZDk2MGFmMmQ1YzRmODdlMGMwYTNkYjcyNjY0NjM4NGE4YzQ2MjNhZDZkN2UxZTE=$MTIzNA=="))) + //Different password + assert.Error(t, hash.Compare(context.Background(), []byte("ory"), []byte("$hmac-sha512$OTFmODY0ZTI1NmU0ZjVhYjhiMDViZGFmNGVmNGZmMGVlNTY4ODYwNWJhYTk4MTk2OTgyMzc3NzI1YTc4MzcxMTMzNzZmY2YxYTk5MGMxM2RiZDk2MGFmMmQ1YzRmODdlMGMwYTNkYjcyNjY0NjM4NGE4YzQ2MjNhZDZkN2UxZTE=$MTIzNDU="))) + + }) } diff --git a/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=hmac.json b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=hmac.json new file mode 100644 index 000000000000..c60f5c5c0075 --- /dev/null +++ b/identity/.snapshots/TestHandler-case=should_be_able_to_import_users-with_hashed_passwords-hash=hmac.json @@ -0,0 +1,21 @@ +{ + "credentials": { + "password": { + "type": "password", + "identifiers": [ + "import-hash-9@ory.sh" + ], + "config": { + }, + "version": 0 + } + }, + "schema_id": "default", + "state": "active", + "traits": { + "email": "import-hash-9@ory.sh" + }, + "metadata_public": null, + "metadata_admin": null, + "organization_id": null +} diff --git a/identity/handler_test.go b/identity/handler_test.go index 5bba60754761..5da5bf076b68 100644 --- a/identity/handler_test.go +++ b/identity/handler_test.go @@ -280,6 +280,10 @@ func TestHandler(t *testing.T) { name: "SSHA512", hash: "{SSHA512}xPUl/px+1cG55rUH4rzcwxdOIPSB2TingLpiJJumN2xyDWN4Ix1WQG3ihnvHaWUE8MYNkvMi5rf0C9NYixHsE6Yh59M=", pass: "test123", + }, { + name: "hmac", + hash: "$hmac-sha256$YjhhZDA4YTNhNTQ3ZTM1ODI5YjgyMWI3NTM3MDMwMWRkOGM0YjA2YmRkNzc3MWY5YjU0MWE3NTkxNDA2ODcxOA==$MTIzNDU2", + pass: "123456", }, } { t.Run("hash="+tt.name, func(t *testing.T) { From 00cf11c071344103c603c078f07196401d091780 Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Thu, 12 Oct 2023 17:01:24 +0200 Subject: [PATCH 140/282] feat: eventually consistency API controls (#3558) Adds a feature used in Ory Network which enables trading faster reads for slightly stale data. This feature depends on Cockroach functionality and configuration, and is not possible for MySQL or PostgreSQL. --- Makefile | 1 + driver/config/config.go | 7 + embedx/config.schema.json | 16 ++ go.mod | 58 +++--- go.sum | 141 +++++++------- identity/handler.go | 5 + identity/handler_test.go | 9 + identity/pool.go | 5 +- identity/test/pool.go | 53 +++++- internal/client-go/.openapi-generator/FILES | 2 + internal/client-go/README.md | 1 + internal/client-go/api_identity.go | 8 + .../model_consistency_request_parameters.go | 115 ++++++++++++ internal/httpclient/.openapi-generator/FILES | 2 + internal/httpclient/README.md | 1 + internal/httpclient/api_identity.go | 8 + .../model_consistency_request_parameters.go | 115 ++++++++++++ .../sql/identity/persister_identity.go | 177 ++++++++++-------- persistence/sql/persister_test.go | 6 +- spec/api.json | 30 +++ spec/swagger.json | 28 +++ 21 files changed, 599 insertions(+), 189 deletions(-) create mode 100644 internal/client-go/model_consistency_request_parameters.go create mode 100644 internal/httpclient/model_consistency_request_parameters.go diff --git a/Makefile b/Makefile index 20416370f26e..1b8572d3cfe0 100644 --- a/Makefile +++ b/Makefile @@ -97,6 +97,7 @@ sdk: .bin/swagger .bin/ory node_modules swagger generate spec -m -o spec/swagger.json \ -c github.com/ory/kratos \ -c github.com/ory/x/healthx \ + -c github.com/ory/x/crdbx \ -c github.com/ory/x/openapix ory dev swagger sanitize ./spec/swagger.json swagger validate ./spec/swagger.json diff --git a/driver/config/config.go b/driver/config/config.go index 6d5aa68d8900..950152f6d088 100644 --- a/driver/config/config.go +++ b/driver/config/config.go @@ -18,6 +18,8 @@ import ( "testing" "time" + "github.com/ory/x/crdbx" + "github.com/go-webauthn/webauthn/protocol" "github.com/go-webauthn/webauthn/webauthn" "github.com/gofrs/uuid" @@ -186,6 +188,7 @@ const ( ViperKeyOAuth2ProviderOverrideReturnTo = "oauth2_provider.override_return_to" ViperKeyClientHTTPNoPrivateIPRanges = "clients.http.disallow_private_ip_ranges" ViperKeyClientHTTPPrivateIPExceptionURLs = "clients.http.private_ip_exception_urls" + ViperKeyPreviewDefaultReadConsistencyLevel = "preview.default_read_consistency_level" ViperKeyVersion = "version" ) @@ -1488,3 +1491,7 @@ func (p *Config) TokenizeTemplate(ctx context.Context, key string) (_ *SessionTo return &result, nil } + +func (p *Config) DefaultConsistencyLevel(ctx context.Context) crdbx.ConsistencyLevel { + return crdbx.ConsistencyLevelFromString(p.GetProvider(ctx).String(ViperKeyPreviewDefaultReadConsistencyLevel)) +} diff --git a/embedx/config.schema.json b/embedx/config.schema.json index 2992a7d3ddda..53c5c4b288a3 100644 --- a/embedx/config.schema.json +++ b/embedx/config.schema.json @@ -2179,6 +2179,22 @@ }, "additionalProperties": false }, + "preview": { + "title": "Configure Preview Features", + "type": "object", + "properties": { + "default_read_consistency_level": { + "type": "string", + "title": "Default Read Consistency Level", + "description": "The default consistency level to use when reading from the database. Defaults to `strong` to not break existing API contracts. Only set this to `eventual` if you can accept that other read APIs will suddenly return eventually consistent results. It is only effective in Ory Network.", + "enum": [ + "strong", + "eventual" + ], + "default": "strong" + } + } + }, "serve": { "type": "object", "properties": { diff --git a/go.mod b/go.mod index d40791136ea9..a40fc7783f43 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ replace ( ) require ( - github.com/Masterminds/sprig/v3 v3.2.2 + github.com/Masterminds/sprig/v3 v3.2.3 github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 github.com/avast/retry-go/v3 v3.1.1 github.com/bradleyjkemp/cupaloy/v2 v2.8.0 @@ -32,9 +32,9 @@ require ( github.com/ghodss/yaml v1.0.0 github.com/go-crypt/crypt v0.2.9 github.com/go-errors/errors v1.0.1 - github.com/go-openapi/strfmt v0.21.3 + github.com/go-openapi/strfmt v0.21.7 github.com/go-playground/validator/v10 v10.4.1 - github.com/go-swagger/go-swagger v0.30.3 + github.com/go-swagger/go-swagger v0.30.5 github.com/go-webauthn/webauthn v0.8.4 github.com/gobuffalo/fizz v1.14.4 github.com/gobuffalo/httptest v1.5.2 @@ -49,7 +49,7 @@ require ( github.com/google/go-jsonnet v0.19.0 github.com/gorilla/sessions v1.2.1 github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69 - github.com/hashicorp/consul/api v1.18.0 + github.com/hashicorp/consul/api v1.20.0 github.com/hashicorp/go-retryablehttp v0.7.2 github.com/hashicorp/golang-lru v0.5.4 github.com/imdario/mergo v0.3.13 @@ -77,7 +77,7 @@ require ( github.com/ory/jsonschema/v3 v3.0.8 github.com/ory/mail/v3 v3.0.0 github.com/ory/nosurf v1.2.7 - github.com/ory/x v0.0.591 + github.com/ory/x v0.0.595 github.com/peterhellberg/link v1.2.0 github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 github.com/pkg/errors v0.9.1 @@ -96,13 +96,13 @@ require ( github.com/urfave/negroni v1.0.0 github.com/zmb3/spotify/v2 v2.0.0 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.4 - go.opentelemetry.io/otel v1.11.1 - go.opentelemetry.io/otel/trace v1.11.1 + go.opentelemetry.io/otel v1.14.0 + go.opentelemetry.io/otel/trace v1.14.0 golang.org/x/crypto v0.12.0 golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 golang.org/x/net v0.14.0 golang.org/x/oauth2 v0.11.0 - golang.org/x/sync v0.1.0 + golang.org/x/sync v0.2.0 golang.org/x/text v0.12.0 golang.org/x/tools/cmd/cover v0.1.0-deprecated google.golang.org/grpc v1.55.0 @@ -112,14 +112,14 @@ require ( github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver v1.5.0 // indirect - github.com/Masterminds/semver/v3 v3.1.1 // indirect + github.com/Masterminds/semver/v3 v3.2.0 // indirect github.com/Microsoft/go-winio v0.6.0 // indirect github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/a8m/envsubst v1.3.0 // indirect github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15 // indirect github.com/armon/go-metrics v0.4.0 // indirect - github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/avast/retry-go/v4 v4.3.0 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -150,15 +150,15 @@ require ( github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/analysis v0.21.4 // indirect - github.com/go-openapi/errors v0.20.3 // indirect + github.com/go-openapi/errors v0.20.4 // indirect github.com/go-openapi/inflect v0.19.0 // indirect - github.com/go-openapi/jsonpointer v0.19.5 // indirect - github.com/go-openapi/jsonreference v0.20.0 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/loads v0.21.2 // indirect - github.com/go-openapi/runtime v0.24.2 // indirect - github.com/go-openapi/spec v0.20.7 // indirect - github.com/go-openapi/swag v0.22.3 // indirect - github.com/go-openapi/validate v0.22.0 // indirect + github.com/go-openapi/runtime v0.26.0 // indirect + github.com/go-openapi/spec v0.20.9 // indirect + github.com/go-openapi/swag v0.22.4 // indirect + github.com/go-openapi/validate v0.22.1 // indirect github.com/go-playground/locales v0.13.0 // indirect github.com/go-playground/universal-translator v0.17.0 // indirect github.com/go-sql-driver/mysql v1.7.0 // indirect @@ -199,7 +199,7 @@ require ( github.com/hashicorp/go-rootcerts v1.0.2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/serf v0.10.1 // indirect - github.com/huandu/xstrings v1.3.2 // indirect + github.com/huandu/xstrings v1.3.3 // indirect github.com/ian-kent/envconf v0.0.0-20141026121121-c19809918c02 // indirect github.com/ian-kent/go-log v0.0.0-20160113211217-5731446c36ab // indirect github.com/ian-kent/goose v0.0.0-20141221090059-c3541ea826ad // indirect @@ -224,7 +224,7 @@ require ( github.com/knadh/koanf/parsers/yaml v0.1.0 // indirect github.com/knadh/koanf/providers/posflag v0.1.0 // indirect github.com/knadh/koanf/v2 v2.0.1 // indirect - github.com/kr/pretty v0.3.0 // indirect + github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/leodido/go-urn v1.2.0 // indirect github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect @@ -260,7 +260,7 @@ require ( github.com/opencontainers/runc v1.1.5 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect github.com/pelletier/go-toml v1.9.5 // indirect - github.com/pelletier/go-toml/v2 v2.0.7 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/philhofer/fwd v1.1.2 // indirect github.com/pkg/profile v1.7.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -280,9 +280,9 @@ require ( github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d // indirect github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e // indirect github.com/spf13/afero v1.9.5 // indirect - github.com/spf13/cast v1.5.0 // indirect + github.com/spf13/cast v1.5.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect - github.com/spf13/viper v1.15.0 // indirect + github.com/spf13/viper v1.16.0 // indirect github.com/subosito/gotenv v1.4.2 // indirect github.com/t-k/fluent-logger-golang v1.0.0 // indirect github.com/tidwall/match v1.1.1 // indirect @@ -296,23 +296,23 @@ require ( github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect - go.mongodb.org/mongo-driver v1.10.3 // indirect + go.mongodb.org/mongo-driver v1.11.3 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.36.4 // indirect go.opentelemetry.io/contrib/propagators/b3 v1.11.1 // indirect go.opentelemetry.io/contrib/propagators/jaeger v1.11.1 // indirect go.opentelemetry.io/contrib/samplers/jaegerremote v0.5.2 // indirect go.opentelemetry.io/otel/exporters/jaeger v1.11.1 // indirect - go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.1 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.9.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.9.0 // indirect - go.opentelemetry.io/otel/exporters/zipkin v1.11.1 // indirect + go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 // indirect; / indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.14.0 // indirect; / indirect + go.opentelemetry.io/otel/exporters/zipkin v1.14.0 // indirect; / indirect go.opentelemetry.io/otel/metric v0.33.0 // indirect - go.opentelemetry.io/otel/sdk v1.11.1 // indirect + go.opentelemetry.io/otel/sdk v1.14.0 // indirect go.opentelemetry.io/proto/otlp v0.19.0 // indirect golang.org/x/mod v0.10.0 // indirect golang.org/x/sys v0.11.0 // indirect golang.org/x/term v0.11.0 // indirect - golang.org/x/tools v0.7.0 // indirect + golang.org/x/tools v0.9.3 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc // indirect diff --git a/go.sum b/go.sum index 3c3a6cbe2ef7..a65848ab35af 100644 --- a/go.sum +++ b/go.sum @@ -45,10 +45,11 @@ github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJ github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8= -github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= +github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= +github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= +github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= @@ -78,8 +79,8 @@ github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= -github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/avast/retry-go/v3 v3.1.1 h1:49Scxf4v8PmiQ/nY0aY3p0hDueqSmc7++cBbtiDGu2g= github.com/avast/retry-go/v3 v3.1.1/go.mod h1:6cXRK369RpzFL3UQGqIUp9Q7GDrams+KsYWrfNA1/nQ= github.com/avast/retry-go/v4 v4.3.0 h1:cqI48aXx0BExKoM7XPklDpoHAg7/srPPLAfWG5z62jo= @@ -204,7 +205,7 @@ github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= -github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= @@ -242,38 +243,40 @@ github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9Qy github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.20.3 h1:rz6kiC84sqNQoqrtulzaL/VERgkoCyB6WdEkc2ujzUc= -github.com/go-openapi/errors v0.20.3/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= +github.com/go-openapi/errors v0.20.4 h1:unTcVm6PispJsMECE3zWgvG4xTiKda1LIR5rCRWLG6M= +github.com/go-openapi/errors v0.20.4/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4= github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= -github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g= github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro= github.com/go-openapi/loads v0.21.2/go.mod h1:Jq58Os6SSGz0rzh62ptiu8Z31I+OTHqmULx5e/gJbNw= -github.com/go-openapi/runtime v0.24.2 h1:yX9HMGQbz32M87ECaAhGpJjBmErO3QLcgdZj9BzGx7c= -github.com/go-openapi/runtime v0.24.2/go.mod h1:AKurw9fNre+h3ELZfk6ILsfvPN+bvvlaU/M9q/r9hpk= +github.com/go-openapi/runtime v0.26.0 h1:HYOFtG00FM1UvqrcxbEJg/SwvDRvYLQKGhw2zaQjTcc= +github.com/go-openapi/runtime v0.26.0/go.mod h1:QgRGeZwrUcSHdeh4Ka9Glvo0ug1LC5WyE+EV88plZrQ= github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= -github.com/go-openapi/spec v0.20.7 h1:1Rlu/ZrOCCob0n+JKKJAWhNWMPW8bOZRg8FJaY+0SKI= -github.com/go-openapi/spec v0.20.7/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= +github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8= +github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg= github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= -github.com/go-openapi/strfmt v0.21.2/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= -github.com/go-openapi/strfmt v0.21.3 h1:xwhj5X6CjXEZZHMWy1zKJxvW9AfHC9pkyUjLvHtKG7o= github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg= +github.com/go-openapi/strfmt v0.21.7 h1:rspiXgNWgeUzhjo1YU01do6qsahtJNByjLVbPLNHb8k= +github.com/go-openapi/strfmt v0.21.7/go.mod h1:adeGTkxE44sPyLk0JV235VQAO/ZXUr8KAzYjclFs3ew= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/validate v0.21.0/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= -github.com/go-openapi/validate v0.22.0 h1:b0QecH6VslW/TxtpKgzpO1SNG7GU2FsaqKdP1E2T50Y= -github.com/go-openapi/validate v0.22.0/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= +github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= +github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU= +github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= @@ -285,9 +288,8 @@ github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn github.com/go-sql-driver/mysql v1.7.2-0.20231005084435-37980127edfb h1:R5sscofA9Cyd0h2DNMbR8BHYVKj1ZTOgUah1PoU4OVU= github.com/go-sql-driver/mysql v1.7.2-0.20231005084435-37980127edfb/go.mod h1:6gYm/zDt3ahdnMVTPeT/LfoBFsws1qZm5yI6FmVjB14= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= -github.com/go-swagger/go-swagger v0.30.3 h1:HuzvdMRed/9Q8vmzVcfNBQByZVtT79DNZxZ18OprdoI= -github.com/go-swagger/go-swagger v0.30.3/go.mod h1:neDPes8r8PCz2JPvHRDj8BTULLh4VJUt7n6MpQqxhHM= +github.com/go-swagger/go-swagger v0.30.5 h1:SQ2+xSonWjjoEMOV5tcOnZJVlfyUfCBhGQGArS1b9+U= +github.com/go-swagger/go-swagger v0.30.5/go.mod h1:cWUhSyCNqV7J1wkkxfr5QmbcnCewetCdvEXqgPvbc/Q= github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013 h1:l9rI6sNaZgNC0LnF3MiE+qTmyBA/tZAg1rtyrGbUMK0= github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= @@ -421,7 +423,6 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-github/v27 v27.0.1 h1:sSMFSShNn4VnqCqs+qhab6TS3uQc+uVR6TD1bW6MavM= github.com/google/go-github/v27 v27.0.1/go.mod h1:/0Gr8pJ55COkmv+S/yPKCczSkUPIM/LnFyubufRNIS0= @@ -486,18 +487,15 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.12.0 h1:kr3j8iIMR4ywO/O0rvksXaJvauG github.com/grpc-ecosystem/grpc-gateway/v2 v2.12.0/go.mod h1:ummNFgdgLhhX7aIiy35vVmQNS0rWXknfPE0qe6fmFXg= github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69 h1:7xsUJsB2NrdcttQPa7JLEaGzvdbk7KvfrjgHZXOQRo0= github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69/go.mod h1:YLEMZOtU+AZ7dhN9T/IpGhXVGly2bvkJQ+zxj3WeVQo= -github.com/hashicorp/consul/api v1.18.0 h1:R7PPNzTCeN6VuQNDwwhZWJvzCtGSrNpJqfb22h3yH9g= -github.com/hashicorp/consul/api v1.18.0/go.mod h1:owRRGJ9M5xReDC5nfT8FTJrNAPbT4NM6p/k+d03q2v4= -github.com/hashicorp/consul/sdk v0.13.0 h1:lce3nFlpv8humJL8rNrrGHYSKc3q+Kxfeg3Ii1m6ZWU= -github.com/hashicorp/consul/sdk v0.13.0/go.mod h1:0hs/l5fOVhJy/VdcoaNqUSi2AUs95eF5WKtv+EYIQqE= +github.com/hashicorp/consul/api v1.20.0 h1:9IHTjNVSZ7MIwjlW3N3a7iGiykCMDpxZu8jsxFJh0yc= +github.com/hashicorp/consul/api v1.20.0/go.mod h1:nR64eD44KQ59Of/ECwt2vUmIK2DKsDzAwTmwmLl8Wpo= +github.com/hashicorp/consul/sdk v0.13.1 h1:EygWVWWMczTzXGpO93awkHFzfUka6hLYJ0qhETd+6lY= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -515,14 +513,11 @@ github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5O github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= -github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= -github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= @@ -536,9 +531,8 @@ github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4 github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= -github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= +github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/ian-kent/envconf v0.0.0-20141026121121-c19809918c02 h1:dU8zq210pt1b71X8xh9GOxC7uBHNtQ9BYC+Lb6SA/mA= github.com/ian-kent/envconf v0.0.0-20141026121121-c19809918c02/go.mod h1:1m5fo3aKG2moYtGHC4I2nFkXmG97+vCeaEIWC+mXTSI= github.com/ian-kent/go-log v0.0.0-20160113211217-5731446c36ab h1:OgrFrYWlVzY7Tc8rq7Y4ErlKo28igc70gbfJGTVWTJk= @@ -672,10 +666,10 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -768,18 +762,15 @@ github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/mikefarah/yq/v4 v4.19.1 h1:QrZCqjOBZ918aOZIfl/IwnHBv104SPfarhgO5MGd2W4= github.com/mikefarah/yq/v4 v4.19.1/go.mod h1:krTElh9V1fv3Cw7+21S8El/W/vn3f2buOOcJ4VyjsFY= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= @@ -823,7 +814,6 @@ github.com/opencontainers/runc v1.1.5 h1:L44KXEpKmfWDcS02aeGm8QNTFXTo2D+8MYGDIJ/ github.com/opencontainers/runc v1.1.5/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= -github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/openzipkin/zipkin-go v0.4.1 h1:kNd/ST2yLLWhaWrkgchya40TJabe8Hioj9udfPcEO5A= github.com/openzipkin/zipkin-go v0.4.1/go.mod h1:qY0VqDSN1pOBN94dBc6w2GJlWLiovAyg7Qt6/I9HecM= github.com/ory/analytics-go/v5 v5.0.1 h1:LX8T5B9FN8KZXOtxgN+R3I4THRRVB6+28IKgKBpXmAM= @@ -847,16 +837,16 @@ github.com/ory/nosurf v1.2.7 h1:YrHrbSensQyU6r6HT/V5+HPdVEgrOTMJiLoJABSBOp4= github.com/ory/nosurf v1.2.7/go.mod h1:d4L3ZBa7Amv55bqxCBtCs63wSlyaiCkWVl4vKf3OUxA= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2 h1:zm6sDvHy/U9XrGpixwHiuAwpp0Ock6khSVHkrv6lQQU= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/ory/x v0.0.591 h1:a3hyQZIwokuRCeoPzMxbewY/y6C6r1NgX4Jn3csVZv0= -github.com/ory/x v0.0.591/go.mod h1:ksLBEd6iW6czGpE6eNA0gCIxO1FFeqIxCZgsgwNrzMM= +github.com/ory/x v0.0.595 h1:oh2/wLyyQ6hMaFblj9u0EGzrR5tEOmnp+2as+XkER9g= +github.com/ory/x v0.0.595/go.mod h1:ksLBEd6iW6czGpE6eNA0gCIxO1FFeqIxCZgsgwNrzMM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us= -github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/peterhellberg/link v1.2.0 h1:UA5pg3Gp/E0F2WdX7GERiNrPQrM1K6CVJUUWfHa4t6c= github.com/peterhellberg/link v1.2.0/go.mod h1:gYfAh+oJgQu2SrZHg5hROVRQe1ICoK0/HHJTcE0edxc= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc= @@ -930,7 +920,6 @@ github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThC github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samber/lo v1.37.0 h1:XjVcB8g6tgUp8rsPsJ2CvhClfImrpL04YpQHXeHPhRw= github.com/samber/lo v1.37.0/go.mod h1:9vaz2O4o8oOnK23pd2TrXufcbdbJIa3b6cstBWKpopA= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= @@ -978,8 +967,8 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= -github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= +github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= @@ -989,8 +978,8 @@ github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0 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.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= -github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= +github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= +github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= github.com/sqs/goreturns v0.0.0-20181028201513-538ac6014518 h1:iD+PFTQwKEmbwSdwfvP5ld2WEI/g7qbdhmHJ2ASfYGs= 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= @@ -1008,6 +997,7 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= @@ -1068,10 +1058,9 @@ github.com/zmb3/spotify/v2 v2.0.0 h1:NHW9btztNZTrJ0+3yMNyfY5qcu1ck9s36wwzc7zrCic github.com/zmb3/spotify/v2 v2.0.0/go.mod h1:+LVh9CafHu7SedyqYmEf12Rd01dIVlEL845yNhksW0E= go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= -go.mongodb.org/mongo-driver v1.8.3/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= -go.mongodb.org/mongo-driver v1.10.3 h1:XDQEvmh6z1EUsXuIkXE9TaVeqHw6SwS1uf93jFs0HBA= -go.mongodb.org/mongo-driver v1.10.3/go.mod h1:z4XpeoU6w+9Vht+jAFyLgVrD+jGSQQe0+CBWFHNiHt8= +go.mongodb.org/mongo-driver v1.11.3 h1:Ql6K6qYHEzB6xvu4+AU0BoRoqf9vFPcc4o7MUIdPW8Y= +go.mongodb.org/mongo-driver v1.11.3/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -1088,24 +1077,24 @@ go.opentelemetry.io/contrib/propagators/jaeger v1.11.1 h1:Gw+P9NQzw4bjNGZXsoDhww go.opentelemetry.io/contrib/propagators/jaeger v1.11.1/go.mod h1:dP/N3ZFADH8azBcZfGXEFNBXpEmPTXYcNj9rkw1+2Oc= go.opentelemetry.io/contrib/samplers/jaegerremote v0.5.2 h1:Izp9RqrioK/y7J/RXy2c7zd83iKQ4N3td3AMNKNzHiI= go.opentelemetry.io/contrib/samplers/jaegerremote v0.5.2/go.mod h1:Z0aRlRERn9v/3J2K+ATa6ffKyb8/i+/My/gTzFr3dII= -go.opentelemetry.io/otel v1.11.1 h1:4WLLAmcfkmDk2ukNXJyq3/kiz/3UzCaYq6PskJsaou4= -go.opentelemetry.io/otel v1.11.1/go.mod h1:1nNhXBbWSD0nsL38H6btgnFN2k4i0sNLHNNMZMSbUGE= +go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM= +go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU= go.opentelemetry.io/otel/exporters/jaeger v1.11.1 h1:F9Io8lqWdGyIbY3/SOGki34LX/l+7OL0gXNxjqwcbuQ= go.opentelemetry.io/otel/exporters/jaeger v1.11.1/go.mod h1:lRa2w3bQ4R4QN6zYsDgy7tEezgoKEu7Ow2g35Y75+KI= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.1 h1:X2GndnMCsUPh6CiY2a+frAbNsXaPLbB0soHRYhAZ5Ig= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.1/go.mod h1:i8vjiSzbiUC7wOQplijSXMYUpNM93DtlS5CbUT+C6oQ= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.9.0 h1:NN90Cuna0CnBg8YNu1Q0V35i2E8LDByFOwHRCq/ZP9I= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.9.0/go.mod h1:0EsCXjZAiiZGnLdEUXM9YjCKuuLZMYyglh2QDXcYKVA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.9.0 h1:FAF9l8Wjxi9Ad2k/vLTfHZyzXYX72C62wBGpV3G6AIo= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.9.0/go.mod h1:smUdtylgc0YQiUr2PuifS4hBXhAS5xtR6WQhxP1wiNA= -go.opentelemetry.io/otel/exporters/zipkin v1.11.1 h1:JlJ3/oQoyqlrPDCfsSVFcHgGeHvZq+hr1VPWtiYCXTo= -go.opentelemetry.io/otel/exporters/zipkin v1.11.1/go.mod h1:T4S6aVwIS1+MHA+dJHCcPROtZe6ORwnv5vMKPRapsFw= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 h1:/fXHZHGvro6MVqV34fJzDhi7sHGpX3Ej/Qjmfn003ho= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0/go.mod h1:UFG7EBMRdXyFstOwH028U0sVf+AvukSGhF0g8+dmNG8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 h1:TKf2uAs2ueguzLaxOCBXNpHxfO/aC7PAdDsSH0IbeRQ= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0/go.mod h1:HrbCVv40OOLTABmOn1ZWty6CHXkU8DK/Urc43tHug70= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.14.0 h1:3jAYbRHQAqzLjd9I4tzxwJ8Pk/N6AqBcF6m1ZHrxG94= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.14.0/go.mod h1:+N7zNjIJv4K+DeX67XXET0P+eIciESgaFDBqh+ZJFS4= +go.opentelemetry.io/otel/exporters/zipkin v1.14.0 h1:reEVE1upBF9tcujgvSqLJS0SrI7JQPaTKP4s4rymnSs= +go.opentelemetry.io/otel/exporters/zipkin v1.14.0/go.mod h1:RcjvOAcvhzcufQP8aHmzRw1gE9g/VEZufDdo2w+s4sk= go.opentelemetry.io/otel/metric v0.33.0 h1:xQAyl7uGEYvrLAiV/09iTJlp1pZnQ9Wl793qbVvED1E= go.opentelemetry.io/otel/metric v0.33.0/go.mod h1:QlTYc+EnYNq/M2mNk1qDDMRLpqCOj2f/r5c7Fd5FYaI= -go.opentelemetry.io/otel/sdk v1.11.1 h1:F7KmQgoHljhUuJyA+9BiU+EkJfyX5nVVF4wyzWZpKxs= -go.opentelemetry.io/otel/sdk v1.11.1/go.mod h1:/l3FE4SupHJ12TduVjUkZtlfFqDCQJlOlithYrdktys= -go.opentelemetry.io/otel/trace v1.11.1 h1:ofxdnzsNrGBYXbP7t7zpUK281+go5rF7dvdIZXF8gdQ= -go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk= +go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY= +go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM= +go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M= +go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= @@ -1134,10 +1123,8 @@ golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= @@ -1147,6 +1134,7 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220517005047-85d78b3ac167/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= @@ -1235,12 +1223,12 @@ golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1 golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= @@ -1275,8 +1263,9 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1353,7 +1342,6 @@ golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1363,6 +1351,7 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1375,6 +1364,7 @@ golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20210317153231-de623e64d2a6/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= @@ -1389,6 +1379,7 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= @@ -1464,8 +1455,8 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM= +golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/tools/cmd/cover v0.1.0-deprecated h1:Rwy+mWYz6loAF+LnG1jHG/JWMHRMMC2/1XX3Ejkx9lA= golang.org/x/tools/cmd/cover v0.1.0-deprecated/go.mod h1:hMDiIvlpN1NoVgmjLjUJE9tMHyxHjFX7RuQ+rW12mSA= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/identity/handler.go b/identity/handler.go index ce1a9f927ce0..5c82f27b9164 100644 --- a/identity/handler.go +++ b/identity/handler.go @@ -11,7 +11,9 @@ import ( "strings" "time" + "github.com/ory/x/crdbx" "github.com/ory/x/pagination/keysetpagination" + "github.com/ory/x/pagination/migrationpagination" "github.com/ory/x/pagination/pagepagination" "github.com/ory/x/sqlcon" @@ -152,6 +154,8 @@ type listIdentitiesParameters struct { // required: false // in: query CredentialsIdentifierSimilar string `json:"preview_credentials_identifier_similar"` + + crdbx.ConsistencyRequestParameters } // swagger:route GET /admin/identities identity listIdentities @@ -178,6 +182,7 @@ func (h *Handler) list(w http.ResponseWriter, r *http.Request, _ httprouter.Para Expand: ExpandDefault, CredentialsIdentifier: r.URL.Query().Get("credentials_identifier"), CredentialsIdentifierSimilar: r.URL.Query().Get("preview_credentials_identifier_similar"), + ConsistencyLevel: crdbx.ConsistencyLevelFromRequest(r), } ) if params.CredentialsIdentifier != "" && params.CredentialsIdentifierSimilar != "" { diff --git a/identity/handler_test.go b/identity/handler_test.go index 5da5bf076b68..78f7cfe505d2 100644 --- a/identity/handler_test.go +++ b/identity/handler_test.go @@ -1267,6 +1267,15 @@ func TestHandler(t *testing.T) { } }) + t.Run("case=should list all identities with eventual consistency", func(t *testing.T) { + for name, ts := range map[string]*httptest.Server{"public": publicTS, "admin": adminTS} { + t.Run("endpoint="+name, func(t *testing.T) { + res := get(t, ts, "/identities?consistency=eventual", http.StatusOK) + assert.EqualValues(t, "baz", res.Get(`#(traits.bar=="baz").traits.bar`).String(), "%s", res.Raw) + }) + } + }) + t.Run("case=should not be able to update an identity that does not exist yet", func(t *testing.T) { for name, ts := range map[string]*httptest.Server{"public": publicTS, "admin": adminTS} { t.Run("endpoint="+name, func(t *testing.T) { diff --git a/identity/pool.go b/identity/pool.go index 61665f056abd..e0d14637f29a 100644 --- a/identity/pool.go +++ b/identity/pool.go @@ -6,6 +6,8 @@ package identity import ( "context" + "github.com/ory/x/crdbx" + "github.com/ory/kratos/x" "github.com/ory/x/pagination/keysetpagination" "github.com/ory/x/sqlxx" @@ -20,7 +22,8 @@ type ( CredentialsIdentifierSimilar string KeySetPagination []keysetpagination.Option // DEPRECATED - PagePagination *x.Page + PagePagination *x.Page + ConsistencyLevel crdbx.ConsistencyLevel } Pool interface { diff --git a/identity/test/pool.go b/identity/test/pool.go index b51a88f242ca..85cafd3d369f 100644 --- a/identity/test/pool.go +++ b/identity/test/pool.go @@ -13,6 +13,8 @@ import ( "testing" "time" + "github.com/ory/x/crdbx" + "github.com/bxcodec/faker/v3" "github.com/gofrs/uuid" "github.com/stretchr/testify/assert" @@ -34,7 +36,7 @@ import ( "github.com/ory/x/urlx" ) -func TestPool(ctx context.Context, conf *config.Config, p persistence.Persister, m *identity.Manager) func(t *testing.T) { +func TestPool(ctx context.Context, conf *config.Config, p persistence.Persister, m *identity.Manager, dbname string) func(t *testing.T) { return func(t *testing.T) { exampleServerURL := urlx.ParseOrPanic("http://example.com") conf.MustSet(ctx, config.ViperKeyPublicBaseURL, exampleServerURL.String()) @@ -654,6 +656,55 @@ func TestPool(ctx context.Context, conf *config.Config, p persistence.Persister, require.NoError(t, err) assert.Len(t, is, 0) }) + + t.Run("eventually consistent", func(t *testing.T) { + if dbname != "cockroach" { + t.Skipf("Test only works with cockroachdb") + return + } + + id := x.NewUUID().String() + another := oidcIdentity("", id) + require.NoError(t, p.CreateIdentity(ctx, another)) + createdIDs = append(createdIDs, another.ID) + + is, _, err := p.ListIdentities(ctx, identity.ListIdentityParameters{ + Expand: identity.ExpandDefault, + KeySetPagination: []keysetpagination.Option{keysetpagination.WithSize(25)}, + ConsistencyLevel: crdbx.ConsistencyLevelStrong, + }) + require.NoError(t, err) + require.Len(t, is, len(createdIDs)) + + var results []identity.Identity + // It takes about 4.8 seconds to replicate the data. + for i := 0; i < 8; i++ { + time.Sleep(time.Second) + + // The error here is explicitly ignored because the table / schema might not yet be replicated. + // This can lead to "ERROR: cached plan must not change result type (SQLSTATE 0A000)" whih is caused + // because the prepared query exist but the schema is not yet replicated. + is, _, _ := p.ListIdentities(ctx, identity.ListIdentityParameters{ + Expand: identity.ExpandEverything, + KeySetPagination: []keysetpagination.Option{keysetpagination.WithSize(25)}, + ConsistencyLevel: crdbx.ConsistencyLevelEventual, + }) + + if len(is) == len(createdIDs) { + results = is + } + } + require.NotZero(t, len(results)) + require.Len(t, results, len(createdIDs), "Could not find all identities after 8 seconds") + + var found bool + for _, i := range results { + if i.ID == another.ID { + found = true + } + } + require.True(t, found, id, "Unable to find created identity in eventually consistent results.") + }) }) t.Run("case=find identity by its credentials identifier", func(t *testing.T) { diff --git a/internal/client-go/.openapi-generator/FILES b/internal/client-go/.openapi-generator/FILES index 908e0021b70e..24a832963dac 100644 --- a/internal/client-go/.openapi-generator/FILES +++ b/internal/client-go/.openapi-generator/FILES @@ -11,6 +11,7 @@ client.go configuration.go docs/AuthenticatorAssuranceLevel.md docs/BatchPatchIdentitiesResponse.md +docs/ConsistencyRequestParameters.md docs/ContinueWith.md docs/ContinueWithSetOrySessionToken.md docs/ContinueWithVerificationUi.md @@ -128,6 +129,7 @@ go.mod go.sum model_authenticator_assurance_level.go model_batch_patch_identities_response.go +model_consistency_request_parameters.go model_continue_with.go model_continue_with_set_ory_session_token.go model_continue_with_verification_ui.go diff --git a/internal/client-go/README.md b/internal/client-go/README.md index 17418c7742f8..171764a11a5b 100644 --- a/internal/client-go/README.md +++ b/internal/client-go/README.md @@ -138,6 +138,7 @@ Class | Method | HTTP request | Description - [AuthenticatorAssuranceLevel](docs/AuthenticatorAssuranceLevel.md) - [BatchPatchIdentitiesResponse](docs/BatchPatchIdentitiesResponse.md) + - [ConsistencyRequestParameters](docs/ConsistencyRequestParameters.md) - [ContinueWith](docs/ContinueWith.md) - [ContinueWithSetOrySessionToken](docs/ContinueWithSetOrySessionToken.md) - [ContinueWithVerificationUi](docs/ContinueWithVerificationUi.md) diff --git a/internal/client-go/api_identity.go b/internal/client-go/api_identity.go index 93dcc20dddd1..ae406e98fae0 100644 --- a/internal/client-go/api_identity.go +++ b/internal/client-go/api_identity.go @@ -2051,6 +2051,7 @@ type IdentityApiApiListIdentitiesRequest struct { page *int64 pageSize *int64 pageToken *string + consistency *string credentialsIdentifier *string previewCredentialsIdentifierSimilar *string } @@ -2071,6 +2072,10 @@ func (r IdentityApiApiListIdentitiesRequest) PageToken(pageToken string) Identit r.pageToken = &pageToken return r } +func (r IdentityApiApiListIdentitiesRequest) Consistency(consistency string) IdentityApiApiListIdentitiesRequest { + r.consistency = &consistency + return r +} func (r IdentityApiApiListIdentitiesRequest) CredentialsIdentifier(credentialsIdentifier string) IdentityApiApiListIdentitiesRequest { r.credentialsIdentifier = &credentialsIdentifier return r @@ -2134,6 +2139,9 @@ func (a *IdentityApiService) ListIdentitiesExecute(r IdentityApiApiListIdentitie if r.pageToken != nil { localVarQueryParams.Add("page_token", parameterToString(*r.pageToken, "")) } + if r.consistency != nil { + localVarQueryParams.Add("consistency", parameterToString(*r.consistency, "")) + } if r.credentialsIdentifier != nil { localVarQueryParams.Add("credentials_identifier", parameterToString(*r.credentialsIdentifier, "")) } diff --git a/internal/client-go/model_consistency_request_parameters.go b/internal/client-go/model_consistency_request_parameters.go new file mode 100644 index 000000000000..6c48a4d6bb47 --- /dev/null +++ b/internal/client-go/model_consistency_request_parameters.go @@ -0,0 +1,115 @@ +/* + * Ory Identities API + * + * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. + * + * API version: + * Contact: office@ory.sh + */ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +import ( + "encoding/json" +) + +// ConsistencyRequestParameters Control API consistency guarantees +type ConsistencyRequestParameters struct { + // Read Consistency Level (preview) The read consistency level determines the consistency guarantee for reads: strong (slow): The read is guaranteed to return the most recent data committed at the start of the read. eventual (very fast): The result will return data that is about 4.8 seconds old. The default consistency guarantee can be changed in the Ory Network Console or using the Ory CLI with `ory patch project --replace '/previews/default_read_consistency_level=\"strong\"'`. Setting the default consistency level to `eventual` may cause regressions in the future as we add consistency controls to more APIs. Currently, the following APIs will be affected by this setting: `GET /admin/identities` This feature is in preview and only available in Ory Network. ConsistencyLevelUnset ConsistencyLevelUnset is the unset / default consistency level. strong ConsistencyLevelStrong ConsistencyLevelStrong is the strong consistency level. eventual ConsistencyLevelEventual ConsistencyLevelEventual is the eventual consistency level using follower read timestamps. + Consistency *string `json:"consistency,omitempty"` +} + +// NewConsistencyRequestParameters instantiates a new ConsistencyRequestParameters 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 NewConsistencyRequestParameters() *ConsistencyRequestParameters { + this := ConsistencyRequestParameters{} + return &this +} + +// NewConsistencyRequestParametersWithDefaults instantiates a new ConsistencyRequestParameters 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 NewConsistencyRequestParametersWithDefaults() *ConsistencyRequestParameters { + this := ConsistencyRequestParameters{} + return &this +} + +// GetConsistency returns the Consistency field value if set, zero value otherwise. +func (o *ConsistencyRequestParameters) GetConsistency() string { + if o == nil || o.Consistency == nil { + var ret string + return ret + } + return *o.Consistency +} + +// GetConsistencyOk returns a tuple with the Consistency field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ConsistencyRequestParameters) GetConsistencyOk() (*string, bool) { + if o == nil || o.Consistency == nil { + return nil, false + } + return o.Consistency, true +} + +// HasConsistency returns a boolean if a field has been set. +func (o *ConsistencyRequestParameters) HasConsistency() bool { + if o != nil && o.Consistency != nil { + return true + } + + return false +} + +// SetConsistency gets a reference to the given string and assigns it to the Consistency field. +func (o *ConsistencyRequestParameters) SetConsistency(v string) { + o.Consistency = &v +} + +func (o ConsistencyRequestParameters) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if o.Consistency != nil { + toSerialize["consistency"] = o.Consistency + } + return json.Marshal(toSerialize) +} + +type NullableConsistencyRequestParameters struct { + value *ConsistencyRequestParameters + isSet bool +} + +func (v NullableConsistencyRequestParameters) Get() *ConsistencyRequestParameters { + return v.value +} + +func (v *NullableConsistencyRequestParameters) Set(val *ConsistencyRequestParameters) { + v.value = val + v.isSet = true +} + +func (v NullableConsistencyRequestParameters) IsSet() bool { + return v.isSet +} + +func (v *NullableConsistencyRequestParameters) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableConsistencyRequestParameters(val *ConsistencyRequestParameters) *NullableConsistencyRequestParameters { + return &NullableConsistencyRequestParameters{value: val, isSet: true} +} + +func (v NullableConsistencyRequestParameters) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableConsistencyRequestParameters) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/httpclient/.openapi-generator/FILES b/internal/httpclient/.openapi-generator/FILES index 908e0021b70e..24a832963dac 100644 --- a/internal/httpclient/.openapi-generator/FILES +++ b/internal/httpclient/.openapi-generator/FILES @@ -11,6 +11,7 @@ client.go configuration.go docs/AuthenticatorAssuranceLevel.md docs/BatchPatchIdentitiesResponse.md +docs/ConsistencyRequestParameters.md docs/ContinueWith.md docs/ContinueWithSetOrySessionToken.md docs/ContinueWithVerificationUi.md @@ -128,6 +129,7 @@ go.mod go.sum model_authenticator_assurance_level.go model_batch_patch_identities_response.go +model_consistency_request_parameters.go model_continue_with.go model_continue_with_set_ory_session_token.go model_continue_with_verification_ui.go diff --git a/internal/httpclient/README.md b/internal/httpclient/README.md index 17418c7742f8..171764a11a5b 100644 --- a/internal/httpclient/README.md +++ b/internal/httpclient/README.md @@ -138,6 +138,7 @@ Class | Method | HTTP request | Description - [AuthenticatorAssuranceLevel](docs/AuthenticatorAssuranceLevel.md) - [BatchPatchIdentitiesResponse](docs/BatchPatchIdentitiesResponse.md) + - [ConsistencyRequestParameters](docs/ConsistencyRequestParameters.md) - [ContinueWith](docs/ContinueWith.md) - [ContinueWithSetOrySessionToken](docs/ContinueWithSetOrySessionToken.md) - [ContinueWithVerificationUi](docs/ContinueWithVerificationUi.md) diff --git a/internal/httpclient/api_identity.go b/internal/httpclient/api_identity.go index 93dcc20dddd1..ae406e98fae0 100644 --- a/internal/httpclient/api_identity.go +++ b/internal/httpclient/api_identity.go @@ -2051,6 +2051,7 @@ type IdentityApiApiListIdentitiesRequest struct { page *int64 pageSize *int64 pageToken *string + consistency *string credentialsIdentifier *string previewCredentialsIdentifierSimilar *string } @@ -2071,6 +2072,10 @@ func (r IdentityApiApiListIdentitiesRequest) PageToken(pageToken string) Identit r.pageToken = &pageToken return r } +func (r IdentityApiApiListIdentitiesRequest) Consistency(consistency string) IdentityApiApiListIdentitiesRequest { + r.consistency = &consistency + return r +} func (r IdentityApiApiListIdentitiesRequest) CredentialsIdentifier(credentialsIdentifier string) IdentityApiApiListIdentitiesRequest { r.credentialsIdentifier = &credentialsIdentifier return r @@ -2134,6 +2139,9 @@ func (a *IdentityApiService) ListIdentitiesExecute(r IdentityApiApiListIdentitie if r.pageToken != nil { localVarQueryParams.Add("page_token", parameterToString(*r.pageToken, "")) } + if r.consistency != nil { + localVarQueryParams.Add("consistency", parameterToString(*r.consistency, "")) + } if r.credentialsIdentifier != nil { localVarQueryParams.Add("credentials_identifier", parameterToString(*r.credentialsIdentifier, "")) } diff --git a/internal/httpclient/model_consistency_request_parameters.go b/internal/httpclient/model_consistency_request_parameters.go new file mode 100644 index 000000000000..6c48a4d6bb47 --- /dev/null +++ b/internal/httpclient/model_consistency_request_parameters.go @@ -0,0 +1,115 @@ +/* + * Ory Identities API + * + * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. + * + * API version: + * Contact: office@ory.sh + */ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +import ( + "encoding/json" +) + +// ConsistencyRequestParameters Control API consistency guarantees +type ConsistencyRequestParameters struct { + // Read Consistency Level (preview) The read consistency level determines the consistency guarantee for reads: strong (slow): The read is guaranteed to return the most recent data committed at the start of the read. eventual (very fast): The result will return data that is about 4.8 seconds old. The default consistency guarantee can be changed in the Ory Network Console or using the Ory CLI with `ory patch project --replace '/previews/default_read_consistency_level=\"strong\"'`. Setting the default consistency level to `eventual` may cause regressions in the future as we add consistency controls to more APIs. Currently, the following APIs will be affected by this setting: `GET /admin/identities` This feature is in preview and only available in Ory Network. ConsistencyLevelUnset ConsistencyLevelUnset is the unset / default consistency level. strong ConsistencyLevelStrong ConsistencyLevelStrong is the strong consistency level. eventual ConsistencyLevelEventual ConsistencyLevelEventual is the eventual consistency level using follower read timestamps. + Consistency *string `json:"consistency,omitempty"` +} + +// NewConsistencyRequestParameters instantiates a new ConsistencyRequestParameters 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 NewConsistencyRequestParameters() *ConsistencyRequestParameters { + this := ConsistencyRequestParameters{} + return &this +} + +// NewConsistencyRequestParametersWithDefaults instantiates a new ConsistencyRequestParameters 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 NewConsistencyRequestParametersWithDefaults() *ConsistencyRequestParameters { + this := ConsistencyRequestParameters{} + return &this +} + +// GetConsistency returns the Consistency field value if set, zero value otherwise. +func (o *ConsistencyRequestParameters) GetConsistency() string { + if o == nil || o.Consistency == nil { + var ret string + return ret + } + return *o.Consistency +} + +// GetConsistencyOk returns a tuple with the Consistency field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ConsistencyRequestParameters) GetConsistencyOk() (*string, bool) { + if o == nil || o.Consistency == nil { + return nil, false + } + return o.Consistency, true +} + +// HasConsistency returns a boolean if a field has been set. +func (o *ConsistencyRequestParameters) HasConsistency() bool { + if o != nil && o.Consistency != nil { + return true + } + + return false +} + +// SetConsistency gets a reference to the given string and assigns it to the Consistency field. +func (o *ConsistencyRequestParameters) SetConsistency(v string) { + o.Consistency = &v +} + +func (o ConsistencyRequestParameters) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if o.Consistency != nil { + toSerialize["consistency"] = o.Consistency + } + return json.Marshal(toSerialize) +} + +type NullableConsistencyRequestParameters struct { + value *ConsistencyRequestParameters + isSet bool +} + +func (v NullableConsistencyRequestParameters) Get() *ConsistencyRequestParameters { + return v.value +} + +func (v *NullableConsistencyRequestParameters) Set(val *ConsistencyRequestParameters) { + v.value = val + v.isSet = true +} + +func (v NullableConsistencyRequestParameters) IsSet() bool { + return v.isSet +} + +func (v *NullableConsistencyRequestParameters) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableConsistencyRequestParameters(val *ConsistencyRequestParameters) *NullableConsistencyRequestParameters { + return &NullableConsistencyRequestParameters{value: val, isSet: true} +} + +func (v NullableConsistencyRequestParameters) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableConsistencyRequestParameters) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/persistence/sql/identity/persister_identity.go b/persistence/sql/identity/persister_identity.go index fadac678951f..2d457fa42985 100644 --- a/persistence/sql/identity/persister_identity.go +++ b/persistence/sql/identity/persister_identity.go @@ -12,6 +12,8 @@ import ( "sync" "time" + "github.com/ory/x/crdbx" + "github.com/gobuffalo/pop/v6" "github.com/gofrs/uuid" "github.com/pkg/errors" @@ -675,50 +677,60 @@ func (p *IdentityPersister) ListIdentities(ctx context.Context, params identity. attribute.String("network.id", p.NetworkID(ctx).String()))...)) defer otelx.End(span, &err) - is := make([]identity.Identity, 0) - - con := p.GetConnection(ctx) nid := p.NetworkID(ctx) + var is []identity.Identity - joins := "" - wheres := "identities.nid = ? AND identities.id > ?" - args := []any{nid, paginator.Token().Encode()} - limit := fmt.Sprintf("LIMIT %d", paginator.Size()+1) - if params.PagePagination != nil { - wheres = "identities.nid = ?" - args = []any{nid} - paginator := pop.NewPaginator(params.PagePagination.Page+1, params.PagePagination.ItemsPerPage) - limit = fmt.Sprintf("LIMIT %d OFFSET %d", paginator.PerPage, paginator.Offset) - } - identifier := params.CredentialsIdentifier - identifierOperator := "=" - if identifier == "" && params.CredentialsIdentifierSimilar != "" { - identifier = params.CredentialsIdentifierSimilar - identifierOperator = "%" - switch con.Dialect.Name() { - case "postgres", "cockroach": - default: - identifier = "%" + identifier + "%" - identifierOperator = "LIKE" - } - } - - if len(identifier) > 0 { - // When filtering by credentials identifier, we most likely are looking for a username or email. It is therefore - // important to normalize the identifier before querying the database. - identifier = NormalizeIdentifier(identity.CredentialsTypePassword, identifier) - - joins = ` + if err = p.Transaction(ctx, func(ctx context.Context, con *pop.Connection) error { + is = make([]identity.Identity, 0) // Make sure we reset this to 0 in case of retries. + nextPage = nil + + if err := crdbx.SetTransactionReadOnly(con); err != nil { + return err + } + + if err := crdbx.SetTransactionConsistency(con, params.ConsistencyLevel, p.r.Config().DefaultConsistencyLevel(ctx)); err != nil { + return err + } + + joins := "" + wheres := "identities.nid = ? AND identities.id > ?" + args := []any{nid, paginator.Token().Encode()} + limit := fmt.Sprintf("LIMIT %d", paginator.Size()+1) + if params.PagePagination != nil { + wheres = "identities.nid = ?" + args = []any{nid} + paginator := pop.NewPaginator(params.PagePagination.Page+1, params.PagePagination.ItemsPerPage) + limit = fmt.Sprintf("LIMIT %d OFFSET %d", paginator.PerPage, paginator.Offset) + } + identifier := params.CredentialsIdentifier + identifierOperator := "=" + if identifier == "" && params.CredentialsIdentifierSimilar != "" { + identifier = params.CredentialsIdentifierSimilar + identifierOperator = "%" + switch con.Dialect.Name() { + case "postgres", "cockroach": + default: + identifier = "%" + identifier + "%" + identifierOperator = "LIKE" + } + } + + if len(identifier) > 0 { + // When filtering by credentials identifier, we most likely are looking for a username or email. It is therefore + // important to normalize the identifier before querying the database. + identifier = NormalizeIdentifier(identity.CredentialsTypePassword, identifier) + + joins = ` INNER JOIN identity_credentials ic ON ic.identity_id = identities.id INNER JOIN identity_credential_types ict ON ict.id = ic.identity_credential_type_id INNER JOIN identity_credential_identifiers ici ON ici.identity_credential_id = ic.id` - wheres += fmt.Sprintf(` + wheres += fmt.Sprintf(` AND (ic.nid = ? AND ici.nid = ? AND ici.identifier %s ?) AND ict.name IN (?, ?)`, identifierOperator) - args = append(args, nid, nid, identifier, identity.CredentialsTypeWebAuthn, identity.CredentialsTypePassword) - } + args = append(args, nid, nid, identifier, identity.CredentialsTypeWebAuthn, identity.CredentialsTypePassword) + } - query := fmt.Sprintf(` + query := fmt.Sprintf(` SELECT DISTINCT identities.* FROM identities AS identities %s @@ -726,56 +738,61 @@ func (p *IdentityPersister) ListIdentities(ctx context.Context, params identity. %s ORDER BY identities.id ASC %s`, - joins, wheres, limit) + joins, wheres, limit) - if err := con.RawQuery(query, args...).All(&is); err != nil { - return nil, nil, sqlcon.HandleError(err) - } - - if params.PagePagination == nil { - is, nextPage = keysetpagination.Result(is, paginator) - } + if err := con.RawQuery(query, args...).All(&is); err != nil { + return sqlcon.HandleError(err) + } - if len(is) == 0 { - return is, nextPage, nil - } + if params.PagePagination == nil { + is, nextPage = keysetpagination.Result(is, paginator) + } - identitiesByID := make(map[uuid.UUID]*identity.Identity, len(is)) - identityIDs := make([]any, len(is)) - for k := range is { - identitiesByID[is[k].ID] = &is[k] - identityIDs[k] = is[k].ID - } + if len(is) == 0 { + return nil + } - for _, e := range params.Expand { - switch e { - case identity.ExpandFieldCredentials: - creds, err := QueryForCredentials(con, - Where{"identity_credentials.nid = ?", []any{nid}}, - Where{"identity_credentials.identity_id IN (?)", identityIDs}) - if err != nil { - return nil, nil, err - } - for k := range is { - is[k].Credentials = creds[is[k].ID] - } - case identity.ExpandFieldVerifiableAddresses: - addrs := make([]identity.VerifiableAddress, 0) - if err := con.Where("nid = ?", nid).Where("identity_id IN (?)", identityIDs).Order("id").All(&addrs); err != nil { - return nil, nil, sqlcon.HandleError(err) - } - for _, addr := range addrs { - identitiesByID[addr.IdentityID].VerifiableAddresses = append(identitiesByID[addr.IdentityID].VerifiableAddresses, addr) - } - case identity.ExpandFieldRecoveryAddresses: - addrs := make([]identity.RecoveryAddress, 0) - if err := con.Where("nid = ?", nid).Where("identity_id IN (?)", identityIDs).Order("id").All(&addrs); err != nil { - return nil, nil, sqlcon.HandleError(err) - } - for _, addr := range addrs { - identitiesByID[addr.IdentityID].RecoveryAddresses = append(identitiesByID[addr.IdentityID].RecoveryAddresses, addr) + identitiesByID := make(map[uuid.UUID]*identity.Identity, len(is)) + identityIDs := make([]any, len(is)) + for k := range is { + identitiesByID[is[k].ID] = &is[k] + identityIDs[k] = is[k].ID + } + + for _, e := range params.Expand { + switch e { + case identity.ExpandFieldCredentials: + creds, err := QueryForCredentials(con, + Where{"identity_credentials.nid = ?", []any{nid}}, + Where{"identity_credentials.identity_id IN (?)", identityIDs}) + if err != nil { + return err + } + for k := range is { + is[k].Credentials = creds[is[k].ID] + } + case identity.ExpandFieldVerifiableAddresses: + addrs := make([]identity.VerifiableAddress, 0) + if err := con.Where("nid = ?", nid).Where("identity_id IN (?)", identityIDs).Order("id").All(&addrs); err != nil { + return sqlcon.HandleError(err) + } + for _, addr := range addrs { + identitiesByID[addr.IdentityID].VerifiableAddresses = append(identitiesByID[addr.IdentityID].VerifiableAddresses, addr) + } + case identity.ExpandFieldRecoveryAddresses: + addrs := make([]identity.RecoveryAddress, 0) + if err := con.Where("nid = ?", nid).Where("identity_id IN (?)", identityIDs).Order("id").All(&addrs); err != nil { + return sqlcon.HandleError(err) + } + for _, addr := range addrs { + identitiesByID[addr.IdentityID].RecoveryAddresses = append(identitiesByID[addr.IdentityID].RecoveryAddresses, addr) + } } } + + return nil + }); err != nil { + return nil, nil, err } schemaCache := map[string]string{} diff --git a/persistence/sql/persister_test.go b/persistence/sql/persister_test.go index 548df5268cc7..088c7cb13e19 100644 --- a/persistence/sql/persister_test.go +++ b/persistence/sql/persister_test.go @@ -104,8 +104,8 @@ func createCleanDatabases(t testing.TB) map[string]*driver.RegistryDefault { var l sync.Mutex if !testing.Short() { funcs := map[string]func(t testing.TB) string{ - "postgres": dockertest.RunTestPostgreSQL, - "mysql": dockertest.RunTestMySQL, + //"postgres": dockertest.RunTestPostgreSQL, + //"mysql": dockertest.RunTestMySQL, "cockroach": dockertest.NewLocalTestCRDBServer, } @@ -220,7 +220,7 @@ func TestPersister(t *testing.T) { t.Run("contract=identity.TestPool", func(t *testing.T) { pop.SetLogger(pl(t)) - identity.TestPool(ctx, conf, p, reg.IdentityManager())(t) + identity.TestPool(ctx, conf, p, reg.IdentityManager(), name)(t) }) t.Run("contract=registration.TestFlowPersister", func(t *testing.T) { pop.SetLogger(pl(t)) diff --git a/spec/api.json b/spec/api.json index 24b8c33a63f6..e7f7e6360031 100644 --- a/spec/api.json +++ b/spec/api.json @@ -457,6 +457,22 @@ }, "type": "object" }, + "consistencyRequestParameters": { + "description": "Control API consistency guarantees", + "properties": { + "consistency": { + "description": "Read Consistency Level (preview)\n\nThe read consistency level determines the consistency guarantee for reads:\n\nstrong (slow): The read is guaranteed to return the most recent data committed at the start of the read.\neventual (very fast): The result will return data that is about 4.8 seconds old.\n\nThe default consistency guarantee can be changed in the Ory Network Console or using the Ory CLI with\n`ory patch project --replace '/previews/default_read_consistency_level=\"strong\"'`.\n\nSetting the default consistency level to `eventual` may cause regressions in the future as we add consistency\ncontrols to more APIs. Currently, the following APIs will be affected by this setting:\n\n`GET /admin/identities`\n\nThis feature is in preview and only available in Ory Network.\n ConsistencyLevelUnset ConsistencyLevelUnset is the unset / default consistency level.\nstrong ConsistencyLevelStrong ConsistencyLevelStrong is the strong consistency level.\neventual ConsistencyLevelEventual ConsistencyLevelEventual is the eventual consistency level using follower read timestamps.", + "enum": [ + "", + "strong", + "eventual" + ], + "type": "string", + "x-go-enum-desc": " ConsistencyLevelUnset ConsistencyLevelUnset is the unset / default consistency level.\nstrong ConsistencyLevelStrong ConsistencyLevelStrong is the strong consistency level.\neventual ConsistencyLevelEventual ConsistencyLevelEventual is the eventual consistency level using follower read timestamps." + } + }, + "type": "object" + }, "continueWith": { "discriminator": { "mapping": { @@ -3459,6 +3475,20 @@ "type": "string" } }, + { + "description": "Read Consistency Level (preview)\n\nThe read consistency level determines the consistency guarantee for reads:\n\nstrong (slow): The read is guaranteed to return the most recent data committed at the start of the read.\neventual (very fast): The result will return data that is about 4.8 seconds old.\n\nThe default consistency guarantee can be changed in the Ory Network Console or using the Ory CLI with\n`ory patch project --replace '/previews/default_read_consistency_level=\"strong\"'`.\n\nSetting the default consistency level to `eventual` may cause regressions in the future as we add consistency\ncontrols to more APIs. Currently, the following APIs will be affected by this setting:\n\n`GET /admin/identities`\n\nThis feature is in preview and only available in Ory Network.\n ConsistencyLevelUnset ConsistencyLevelUnset is the unset / default consistency level.\nstrong ConsistencyLevelStrong ConsistencyLevelStrong is the strong consistency level.\neventual ConsistencyLevelEventual ConsistencyLevelEventual is the eventual consistency level using follower read timestamps.", + "in": "query", + "name": "consistency", + "schema": { + "enum": [ + "", + "strong", + "eventual" + ], + "type": "string" + }, + "x-go-enum-desc": " ConsistencyLevelUnset ConsistencyLevelUnset is the unset / default consistency level.\nstrong ConsistencyLevelStrong ConsistencyLevelStrong is the strong consistency level.\neventual ConsistencyLevelEventual ConsistencyLevelEventual is the eventual consistency level using follower read timestamps." + }, { "description": "CredentialsIdentifier is the identifier (username, email) of the credentials to look up using exact match.\nOnly one of CredentialsIdentifier and CredentialsIdentifierSimilar can be used.", "in": "query", diff --git a/spec/swagger.json b/spec/swagger.json index a2e5e859f712..a61ca10e51b4 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -220,6 +220,18 @@ "name": "page_token", "in": "query" }, + { + "enum": [ + "", + "strong", + "eventual" + ], + "type": "string", + "x-go-enum-desc": " ConsistencyLevelUnset ConsistencyLevelUnset is the unset / default consistency level.\nstrong ConsistencyLevelStrong ConsistencyLevelStrong is the strong consistency level.\neventual ConsistencyLevelEventual ConsistencyLevelEventual is the eventual consistency level using follower read timestamps.", + "description": "Read Consistency Level (preview)\n\nThe read consistency level determines the consistency guarantee for reads:\n\nstrong (slow): The read is guaranteed to return the most recent data committed at the start of the read.\neventual (very fast): The result will return data that is about 4.8 seconds old.\n\nThe default consistency guarantee can be changed in the Ory Network Console or using the Ory CLI with\n`ory patch project --replace '/previews/default_read_consistency_level=\"strong\"'`.\n\nSetting the default consistency level to `eventual` may cause regressions in the future as we add consistency\ncontrols to more APIs. Currently, the following APIs will be affected by this setting:\n\n`GET /admin/identities`\n\nThis feature is in preview and only available in Ory Network.\n ConsistencyLevelUnset ConsistencyLevelUnset is the unset / default consistency level.\nstrong ConsistencyLevelStrong ConsistencyLevelStrong is the strong consistency level.\neventual ConsistencyLevelEventual ConsistencyLevelEventual is the eventual consistency level using follower read timestamps.", + "name": "consistency", + "in": "query" + }, { "type": "string", "description": "CredentialsIdentifier is the identifier (username, email) of the credentials to look up using exact match.\nOnly one of CredentialsIdentifier and CredentialsIdentifierSimilar can be used.", @@ -3538,6 +3550,22 @@ } } }, + "consistencyRequestParameters": { + "description": "Control API consistency guarantees", + "type": "object", + "properties": { + "consistency": { + "description": "Read Consistency Level (preview)\n\nThe read consistency level determines the consistency guarantee for reads:\n\nstrong (slow): The read is guaranteed to return the most recent data committed at the start of the read.\neventual (very fast): The result will return data that is about 4.8 seconds old.\n\nThe default consistency guarantee can be changed in the Ory Network Console or using the Ory CLI with\n`ory patch project --replace '/previews/default_read_consistency_level=\"strong\"'`.\n\nSetting the default consistency level to `eventual` may cause regressions in the future as we add consistency\ncontrols to more APIs. Currently, the following APIs will be affected by this setting:\n\n`GET /admin/identities`\n\nThis feature is in preview and only available in Ory Network.\n ConsistencyLevelUnset ConsistencyLevelUnset is the unset / default consistency level.\nstrong ConsistencyLevelStrong ConsistencyLevelStrong is the strong consistency level.\neventual ConsistencyLevelEventual ConsistencyLevelEventual is the eventual consistency level using follower read timestamps.", + "type": "string", + "enum": [ + "", + "strong", + "eventual" + ], + "x-go-enum-desc": " ConsistencyLevelUnset ConsistencyLevelUnset is the unset / default consistency level.\nstrong ConsistencyLevelStrong ConsistencyLevelStrong is the strong consistency level.\neventual ConsistencyLevelEventual ConsistencyLevelEventual is the eventual consistency level using follower read timestamps." + } + } + }, "continueWith": { }, "continueWithSetOrySessionToken": { From 566d1ca0edb1f1f77a3a2bc93c18c227734043b7 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Thu, 12 Oct 2023 16:12:15 +0000 Subject: [PATCH 141/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d87329fcb36..5c9776f20eb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -651,6 +651,19 @@ https://github.com/ory/kratos/pull/3480 This feature is a preview and will change in behavior! Similarity search is not expected to return deterministic results but are useful for humans. +- Allow importing hmac hashed passwords + ([#3544](https://github.com/ory/kratos/issues/3544)) + ([0a0e1f7](https://github.com/ory/kratos/commit/0a0e1f7200e226ef24de062811a05bcdd02b6acd)), + closes [#2422](https://github.com/ory/kratos/issues/2422): + + The basic format is + `$hmac-$$`: + + ``` + # password = test; key=key; hash function=sha + $hmac-sha1$NjcxZjU0Y2UwYzU0MGY3OGZmZTFlMjZkY2Y5YzJhMDQ3YWVhNGZkYQ==$a2V5 + ``` + - Allow marking OIDC provider-verified addresses as verified during registration ([#3448](https://github.com/ory/kratos/issues/3448)) ([e7b33a1](https://github.com/ory/kratos/commit/e7b33a168bf0c0fe0492901abd3df8b6d6a08a68)), @@ -664,6 +677,16 @@ https://github.com/ory/kratos/pull/3480 - Emit error details when we find stray cookies in an API flow ([#3496](https://github.com/ory/kratos/issues/3496)) ([df74339](https://github.com/ory/kratos/commit/df74339802d98a292abb32806eca35fb2554960b)) +- Eventually consistency API controls + ([#3558](https://github.com/ory/kratos/issues/3558)) + ([00cf11c](https://github.com/ory/kratos/commit/00cf11c071344103c603c078f07196401d091780)): + + Adds a feature used in Ory Network which enables trading faster reads for + slightly stale data. + + This feature depends on Cockroach functionality and configuration, and is not + possible for MySQL or PostgreSQL. + - Fine-grained hooks for all available flow methods ([#3519](https://github.com/ory/kratos/issues/3519)) ([a37f6bd](https://github.com/ory/kratos/commit/a37f6bddc48443b2fc464699fa5c2922f64d81f6)): From 525554d30a9a0aceb1ff811a5cdb1116badf566d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Oct 2023 09:28:40 +0200 Subject: [PATCH 142/282] chore(deps): bump golang.org/x/net from 0.14.0 to 0.17.0 (#3573) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.14.0 to 0.17.0. - [Commits](https://github.com/golang/net/compare/v0.14.0...v0.17.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 10 +++++----- go.sum | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index a40fc7783f43..1b52289fb58f 100644 --- a/go.mod +++ b/go.mod @@ -98,12 +98,12 @@ require ( go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.4 go.opentelemetry.io/otel v1.14.0 go.opentelemetry.io/otel/trace v1.14.0 - golang.org/x/crypto v0.12.0 + golang.org/x/crypto v0.14.0 golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 - golang.org/x/net v0.14.0 + golang.org/x/net v0.17.0 golang.org/x/oauth2 v0.11.0 golang.org/x/sync v0.2.0 - golang.org/x/text v0.12.0 + golang.org/x/text v0.13.0 golang.org/x/tools/cmd/cover v0.1.0-deprecated google.golang.org/grpc v1.55.0 ) @@ -310,8 +310,8 @@ require ( go.opentelemetry.io/otel/sdk v1.14.0 // indirect go.opentelemetry.io/proto/otlp v0.19.0 // indirect golang.org/x/mod v0.10.0 // indirect - golang.org/x/sys v0.11.0 // indirect - golang.org/x/term v0.11.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/term v0.13.0 // indirect golang.org/x/tools v0.9.3 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index a65848ab35af..76c7ba81b427 100644 --- a/go.sum +++ b/go.sum @@ -1136,8 +1136,8 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= -golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1232,8 +1232,8 @@ golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1355,8 +1355,8 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20191110171634-ad39bd3f0407/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1368,8 +1368,8 @@ golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= -golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= 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= @@ -1383,8 +1383,8 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From 048af1d0e98bc0cb0c613ca9309b97d56a63e404 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Fri, 13 Oct 2023 08:38:37 +0000 Subject: [PATCH 143/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c9776f20eb1..8d25d265a8c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-10-12)](#2023-10-12) +- [ (2023-10-13)](#2023-10-13) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -313,7 +313,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-10-12) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-10-13) ## Breaking Changes From c804cb2bebbefc97073cf3b8fa250c3eefc58894 Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Fri, 13 Oct 2023 13:55:38 +0200 Subject: [PATCH 144/282] fix: tracing improvements --- persistence/sql/identity/persister_identity.go | 6 +++--- selfservice/hook/show_verification_ui.go | 6 ++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/persistence/sql/identity/persister_identity.go b/persistence/sql/identity/persister_identity.go index 2d457fa42985..73aa9300a6a9 100644 --- a/persistence/sql/identity/persister_identity.go +++ b/persistence/sql/identity/persister_identity.go @@ -192,9 +192,6 @@ var credentialsTypes = struct { } func (p *IdentityPersister) findIdentityCredentialsType(ctx context.Context, ct identity.CredentialsType) (_ *identity.CredentialsTypeTable, err error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.findIdentityCredentialsType") - defer otelx.End(span, &err) - credentialsTypes.RLock() v, ok := credentialsTypes.m[ct] credentialsTypes.RUnlock() @@ -203,6 +200,9 @@ func (p *IdentityPersister) findIdentityCredentialsType(ctx context.Context, ct return v, nil } + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.findIdentityCredentialsType") + defer otelx.End(span, &err) + var m identity.CredentialsTypeTable if err := p.GetConnection(ctx).Where("name = ?", ct).First(&m); err != nil { return nil, sqlcon.HandleError(err) diff --git a/selfservice/hook/show_verification_ui.go b/selfservice/hook/show_verification_ui.go index d9ea9b54ee01..1f7e83ce5c12 100644 --- a/selfservice/hook/show_verification_ui.go +++ b/selfservice/hook/show_verification_ui.go @@ -15,9 +15,7 @@ import ( "github.com/ory/x/otelx" ) -var ( - _ registration.PostHookPostPersistExecutor = new(ShowVerificationUIHook) -) +var _ registration.PostHookPostPersistExecutor = new(ShowVerificationUIHook) type ( showVerificationUIDependencies interface { @@ -42,7 +40,7 @@ func NewShowVerificationUIHook(d showVerificationUIDependencies) *ShowVerificati // ExecutePostRegistrationPostPersistHook adds redirect headers and status code if the request is a browser request. // If the request is not a browser request, this hook does nothing. func (e *ShowVerificationUIHook) ExecutePostRegistrationPostPersistHook(_ http.ResponseWriter, r *http.Request, f *registration.Flow, _ *session.Session) error { - return otelx.WithSpan(r.Context(), "selfservice.hook.SessionIssuer.ExecutePostRegistrationPostPersistHook", func(ctx context.Context) error { + return otelx.WithSpan(r.Context(), "selfservice.hook.ShowVerificationUIHook.ExecutePostRegistrationPostPersistHook", func(ctx context.Context) error { return e.execute(r.WithContext(ctx), f) }) } From fb229c982c6f7d7a4f5f0f84ffc971a576906160 Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Fri, 13 Oct 2023 14:53:34 +0200 Subject: [PATCH 145/282] fix: always return relative URLs in the Link header for pagination --- courier/handler.go | 13 +++++++------ identity/handler.go | 6 ++++-- identity/handler_test.go | 4 ++-- schema/handler.go | 4 +--- session/handler.go | 8 ++++---- x/pagination.go | 4 ++-- 6 files changed, 20 insertions(+), 19 deletions(-) diff --git a/courier/handler.go b/courier/handler.go index d10a9dc0209f..15af1ad2eef5 100644 --- a/courier/handler.go +++ b/courier/handler.go @@ -19,9 +19,11 @@ import ( "github.com/ory/kratos/x" ) -const AdminRouteCourier = "/courier" -const AdminRouteListMessages = AdminRouteCourier + "/messages" -const AdminRouteGetMessage = AdminRouteCourier + "/messages/:msgID" +const ( + AdminRouteCourier = "/courier" + AdminRouteListMessages = AdminRouteCourier + "/messages" + AdminRouteGetMessage = AdminRouteCourier + "/messages/:msgID" +) type ( handlerDependencies interface { @@ -128,7 +130,8 @@ func (h *Handler) listCourierMessages(w http.ResponseWriter, r *http.Request, _ } w.Header().Set("X-Total-Count", fmt.Sprint(tc)) - keysetpagination.Header(w, r.URL, nextPage) + u := *r.URL + keysetpagination.Header(w, &u, nextPage) h.r.Writer().Write(w, r, l) } @@ -137,7 +140,6 @@ func parseMessagesFilter(r *http.Request) (ListCourierMessagesParameters, []keys if r.URL.Query().Has("status") { ms, err := ToMessageStatus(r.URL.Query().Get("status")) - if err != nil { return ListCourierMessagesParameters{}, nil, err } @@ -190,7 +192,6 @@ type getCourierMessage struct { // default: errorGeneric func (h *Handler) getCourierMessage(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { msgID, err := uuid.FromString(ps.ByName("msgID")) - if err != nil { h.r.Writer().WriteError(w, r, herodot.ErrBadRequest.WithError(err.Error()).WithDebugf("could not parse parameter {id} as UUID, got %s", ps.ByName("id"))) return diff --git a/identity/handler.go b/identity/handler.go index 5c82f27b9164..2749396632b3 100644 --- a/identity/handler.go +++ b/identity/handler.go @@ -213,9 +213,11 @@ func (h *Handler) list(w http.ResponseWriter, r *http.Request, _ httprouter.Para return } } - pagepagination.PaginationHeader(w, urlx.AppendPaths(h.r.Config().SelfAdminURL(r.Context()), RouteCollection), total, params.PagePagination.Page, params.PagePagination.ItemsPerPage) + u := *r.URL + pagepagination.PaginationHeader(w, &u, total, params.PagePagination.Page, params.PagePagination.ItemsPerPage) } else { - keysetpagination.Header(w, urlx.AppendPaths(h.r.Config().SelfAdminURL(r.Context()), RouteCollection), nextPage) + u := *r.URL + keysetpagination.Header(w, &u, nextPage) } // Identities using the marshaler for including metadata_admin diff --git a/identity/handler_test.go b/identity/handler_test.go index 78f7cfe505d2..43d432b55eb4 100644 --- a/identity/handler_test.go +++ b/identity/handler_test.go @@ -1553,7 +1553,7 @@ func TestHandler(t *testing.T) { t.Run("using token pagination", func(t *testing.T) { knownIDs := make(map[string]struct{}) var pages int - path := fmt.Sprintf("/identities?page_size=%d", perPage) + path := fmt.Sprintf("/admin/identities?page_size=%d", perPage) for { pages++ next, res := run(t, path, knownIDs) @@ -1573,7 +1573,7 @@ func TestHandler(t *testing.T) { t.Run("using page pagination", func(t *testing.T) { knownIDs := make(map[string]struct{}) var pages int - path := fmt.Sprintf("/identities?page=0&per_page=%d", perPage) + path := fmt.Sprintf("/admin/identities?page=0&per_page=%d", perPage) for { pages++ next, res := run(t, path, knownIDs) diff --git a/schema/handler.go b/schema/handler.go index 74056cae1d95..3cbcc529417e 100644 --- a/schema/handler.go +++ b/schema/handler.go @@ -17,8 +17,6 @@ import ( "github.com/ory/x/pagination/migrationpagination" - "github.com/ory/x/urlx" - "github.com/ory/kratos/driver/config" "github.com/julienschmidt/httprouter" @@ -233,7 +231,7 @@ func (h *Handler) getAll(w http.ResponseWriter, r *http.Request, ps httprouter.P }) } - x.PaginationHeader(w, urlx.AppendPaths(h.r.Config().SelfPublicURL(r.Context()), fmt.Sprintf("/%s", SchemasPath)), int64(total), page, itemsPerPage) + x.PaginationHeader(w, *r.URL, int64(total), page, itemsPerPage) h.r.Writer().Write(w, r, ss) } diff --git a/session/handler.go b/session/handler.go index 0fcfd9ad2103..fd3b8ac1deea 100644 --- a/session/handler.go +++ b/session/handler.go @@ -21,7 +21,6 @@ import ( "github.com/pkg/errors" "github.com/ory/x/decoderx" - "github.com/ory/x/urlx" "github.com/ory/herodot" @@ -409,7 +408,8 @@ func (h *Handler) adminListSessions(w http.ResponseWriter, r *http.Request, ps h } w.Header().Set("x-total-count", fmt.Sprint(total)) - keysetpagination.Header(w, r.URL, nextPage) + u := *r.URL + keysetpagination.Header(w, &u, nextPage) h.r.Writer().Write(w, r, sess) } @@ -616,7 +616,7 @@ func (h *Handler) listIdentitySessions(w http.ResponseWriter, r *http.Request, p return } - x.PaginationHeader(w, urlx.AppendPaths(h.r.Config().SelfAdminURL(r.Context()), RouteCollection), total, page, perPage) + x.PaginationHeader(w, *r.URL, total, page, perPage) h.r.Writer().Write(w, r, sess) } @@ -822,7 +822,7 @@ func (h *Handler) listMySessions(w http.ResponseWriter, r *http.Request, _ httpr return } - x.PaginationHeader(w, urlx.AppendPaths(h.r.Config().SelfAdminURL(r.Context()), RouteCollection), total, page, perPage) + x.PaginationHeader(w, *r.URL, total, page, perPage) h.r.Writer().Write(w, r, sess) } diff --git a/x/pagination.go b/x/pagination.go index e0d6e18b01a4..7e31cd8f7d2e 100644 --- a/x/pagination.go +++ b/x/pagination.go @@ -18,8 +18,8 @@ func ParsePagination(r *http.Request) (page, itemsPerPage int) { return migrationpagination.NewDefaultPaginator().ParsePagination(r) } -func PaginationHeader(w http.ResponseWriter, u *url.URL, total int64, page, itemsPerPage int) { - migrationpagination.PaginationHeader(w, u, total, page, itemsPerPage) +func PaginationHeader(w http.ResponseWriter, u url.URL, total int64, page, itemsPerPage int) { + migrationpagination.PaginationHeader(w, &u, total, page, itemsPerPage) } type Page struct { From 4f8ea02ce45590208b9d9cab5137f127a5010660 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Fri, 13 Oct 2023 19:17:08 +0000 Subject: [PATCH 146/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d25d265a8c3..684324c041c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -390,6 +390,8 @@ https://github.com/ory/kratos/pull/3480 - Allow updating admin metadata from webhook responses ([#3569](https://github.com/ory/kratos/issues/3569)) ([22f61f0](https://github.com/ory/kratos/commit/22f61f015495c55e58db4f31ee6882444b9a3caf)) +- Always return relative URLs in the Link header for pagination + ([fb229c9](https://github.com/ory/kratos/commit/fb229c982c6f7d7a4f5f0f84ffc971a576906160)) - Carry `oauth2_login_challenge` over to registration flow ([#3419](https://github.com/ory/kratos/issues/3419)) ([76241be](https://github.com/ory/kratos/commit/76241bee3dc7fec4690346ee85bc4b9f897fdd34)): @@ -509,6 +511,8 @@ https://github.com/ory/kratos/pull/3480 ([ca34e9b](https://github.com/ory/kratos/commit/ca34e9b744482b41d65082f3bed52e9c4ebd7ba4)) - Schema test errors ([#3528](https://github.com/ory/kratos/issues/3528)) ([bee0341](https://github.com/ory/kratos/commit/bee0341c5bf5708a2210146fc59f050a1b9df663)) +- Tracing improvements + ([c804cb2](https://github.com/ory/kratos/commit/c804cb2bebbefc97073cf3b8fa250c3eefc58894)) - Type-assert all interfaces that WebHook implements ([ffda1a0](https://github.com/ory/kratos/commit/ffda1a0dab661c5f11ad849b9287094313561b79)) - Ui node input attributes key added From df18c09e0089743e8aee17540d277b9572252e06 Mon Sep 17 00:00:00 2001 From: BrandonNoad Date: Mon, 16 Oct 2023 05:28:29 -0300 Subject: [PATCH 147/282] fix: respond with 422 when SPA identity requires AAL2 (#3572) If you submit a browser login flow with an `Accept` header of `application/json`, but the login flow requires AAL2, then there is no way for the code to know it needs to redirect the user to the 2FA page. Instead of responding with the `Session` in this scenario, this PR changes the behaviour to respond with a `browser_location_change_required` error (status `422`) to indicate that the browser needs to open a specific URL, /self-service/login/browser?aal=aal2. Co-authored-by: Henning Perl --- selfservice/flow/login/hook.go | 14 ++++++++++---- selfservice/flow/login/hook_test.go | 15 +++++++-------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/selfservice/flow/login/hook.go b/selfservice/flow/login/hook.go index 69a00232b992..1bff4122ad1f 100644 --- a/selfservice/flow/login/hook.go +++ b/selfservice/flow/login/hook.go @@ -268,11 +268,17 @@ func (e *HookExecutor) PostLoginHook( return nil } - response := &APIFlowResponse{Session: s} - 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 + // If we detect that whoami would require a higher AAL, we redirect! + if _, err := e.requiresAAL2(r, s, a); err != nil { + if aalErr := new(session.ErrAALNotSatisfied); errors.As(err, &aalErr) { + span.SetAttributes(attribute.String("return_to", aalErr.RedirectTo), attribute.String("redirect_reason", "requires aal2")) + e.d.Writer().WriteError(w, r, flow.NewBrowserLocationChangeRequiredError(aalErr.RedirectTo)) + return nil + } + return err } + + response := &APIFlowResponse{Session: s} e.d.Writer().Write(w, r, response) return nil } diff --git a/selfservice/flow/login/hook_test.go b/selfservice/flow/login/hook_test.go index 52e66a45ab62..ea3bd84bac72 100644 --- a/selfservice/flow/login/hook_test.go +++ b/selfservice/flow/login/hook_test.go @@ -206,14 +206,14 @@ func TestLoginExecutor(t *testing.T) { assert.EqualValues(t, "https://www.ory.sh/", res.Request.URL.String()) }) - t.Run("api client returns the token but not the identity", func(t *testing.T) { + t.Run("api client returns the session with identity and the token", func(t *testing.T) { res, body := makeRequestPost(t, newServer(t, flow.TypeAPI, useIdentity), true, url.Values{}) assert.EqualValues(t, http.StatusOK, res.StatusCode) assert.NotEmpty(t, gjson.Get(body, "session.identity").String()) assert.NotEmpty(t, gjson.Get(body, "session_token").String()) }) - t.Run("browser JSON client returns the token but not the identity", func(t *testing.T) { + t.Run("browser JSON client returns the session with identity but not the token", func(t *testing.T) { res, body := makeRequestPost(t, newServer(t, flow.TypeBrowser, useIdentity), true, url.Values{}) assert.EqualValues(t, http.StatusOK, res.StatusCode) assert.NotEmpty(t, gjson.Get(body, "session.id").String()) @@ -242,19 +242,18 @@ func TestLoginExecutor(t *testing.T) { assert.Contains(t, res.Request.URL.String(), "/self-service/login/browser?aal=aal2") }) - t.Run("api client returns the token but not the identity", func(t *testing.T) { + t.Run("api client returns the token and the session without the identity", func(t *testing.T) { res, body := makeRequestPost(t, newServer(t, flow.TypeAPI, useIdentity), true, url.Values{}) assert.EqualValues(t, http.StatusOK, res.StatusCode) assert.Empty(t, gjson.Get(body, "session.identity").String()) assert.NotEmpty(t, gjson.Get(body, "session_token").String()) }) - t.Run("browser JSON client returns the token but not the identity", func(t *testing.T) { + t.Run("browser JSON client", func(t *testing.T) { res, body := makeRequestPost(t, newServer(t, flow.TypeBrowser, useIdentity), true, url.Values{}) - assert.EqualValues(t, http.StatusOK, res.StatusCode) - assert.NotEmpty(t, gjson.Get(body, "session.id").String()) - assert.Empty(t, gjson.Get(body, "session.identity").String()) - assert.Empty(t, gjson.Get(body, "session_token").String()) + assert.EqualValues(t, http.StatusUnprocessableEntity, res.StatusCode) + assert.NotEmpty(t, gjson.Get(body, "redirect_browser_to").String()) + assert.Contains(t, gjson.Get(body, "redirect_browser_to").String(), "/self-service/login/browser?aal=aal2", "%s", body) }) }) }) From ceed7d5478c5cca894587698c57f676dda100b27 Mon Sep 17 00:00:00 2001 From: Alano Terblanche <18033717+Benehiko@users.noreply.github.com> Date: Mon, 16 Oct 2023 16:44:09 +0200 Subject: [PATCH 148/282] feat: login with code on any credential type (#3549) Should be able to login with the `code` credential even if the user did not register on the `code` credential. Only `identifier` matching is done and validation based on the identity schema. --- driver/config/config.go | 6 +- driver/config/config_test.go | 1 + embedx/config.schema.json | 532 ++++-------------- identity/pool.go | 3 + identity/test/pool.go | 43 ++ .../sql/identity/persister_identity.go | 44 ++ selfservice/strategy/code/strategy_login.go | 50 +- .../strategy/code/strategy_login_test.go | 90 ++- .../profiles/code/login/error.spec.ts | 7 +- .../profiles/code/login/success.spec.ts | 71 ++- .../profiles/code/registration/error.spec.ts | 11 +- .../code/registration/success.spec.ts | 23 +- test/e2e/profiles/code/.kratos.yml | 8 +- 13 files changed, 439 insertions(+), 450 deletions(-) diff --git a/driver/config/config.go b/driver/config/config.go index 950152f6d088..4fa461dfbc0e 100644 --- a/driver/config/config.go +++ b/driver/config/config.go @@ -231,7 +231,8 @@ type ( } SelfServiceStrategyCode struct { *SelfServiceStrategy - PasswordlessEnabled bool `json:"passwordless_enabled"` + PasswordlessEnabled bool `json:"passwordless_enabled"` + PasswordlessLoginFallbackEnabled bool `json:"passwordless_login_fallback_enabled"` } Schema struct { ID string `json:"id" koanf:"id"` @@ -763,7 +764,8 @@ func (p *Config) SelfServiceCodeStrategy(ctx context.Context) *SelfServiceStrate Enabled: pp.BoolF(basePath+".enabled", true), Config: config, }, - PasswordlessEnabled: pp.BoolF(basePath+".passwordless_enabled", false), + PasswordlessEnabled: pp.BoolF(basePath+".passwordless_enabled", false), + PasswordlessLoginFallbackEnabled: pp.BoolF(basePath+".passwordless_login_fallback_enabled", false), } } diff --git a/driver/config/config_test.go b/driver/config/config_test.go index dee0baa5e657..052c6808290f 100644 --- a/driver/config/config_test.go +++ b/driver/config/config_test.go @@ -567,6 +567,7 @@ func TestViperProvider_Defaults(t *testing.T) { assert.True(t, p.SelfServiceStrategy(ctx, "code").Enabled) assert.False(t, p.SelfServiceStrategy(ctx, "oidc").Enabled) assert.False(t, p.SelfServiceCodeStrategy(ctx).PasswordlessEnabled) + assert.False(t, p.SelfServiceCodeStrategy(ctx).PasswordlessLoginFallbackEnabled) assert.False(t, p.SelfServiceFlowRecoveryNotifyUnknownRecipients(ctx)) assert.False(t, p.SelfServiceFlowVerificationNotifyUnknownRecipients(ctx)) }) diff --git a/embedx/config.schema.json b/embedx/config.schema.json index 53c5c4b288a3..15b6c8c38b4a 100644 --- a/embedx/config.schema.json +++ b/embedx/config.schema.json @@ -43,10 +43,7 @@ "description": "Ory Kratos redirects to this URL per default on completion of self-service flows and other browser interaction. Read this [article for more information on browser redirects](https://www.ory.sh/kratos/docs/concepts/browser-redirect-flow-completion).", "type": "string", "format": "uri-reference", - "examples": [ - "https://my-app.com/dashboard", - "/dashboard" - ] + "examples": ["https://my-app.com/dashboard", "/dashboard"] }, "selfServiceSessionRevokerHook": { "type": "object", @@ -56,9 +53,7 @@ } }, "additionalProperties": false, - "required": [ - "hook" - ] + "required": ["hook"] }, "selfServiceSessionIssuerHook": { "type": "object", @@ -68,9 +63,7 @@ } }, "additionalProperties": false, - "required": [ - "hook" - ] + "required": ["hook"] }, "selfServiceRequireVerifiedAddressHook": { "type": "object", @@ -80,9 +73,7 @@ } }, "additionalProperties": false, - "required": [ - "hook" - ] + "required": ["hook"] }, "selfServiceShowVerificationUIHook": { "type": "object", @@ -92,9 +83,7 @@ } }, "additionalProperties": false, - "required": [ - "hook" - ] + "required": ["hook"] }, "b2bSSOHook": { "type": "object", @@ -108,10 +97,7 @@ } }, "additionalProperties": false, - "required": [ - "hook", - "config" - ] + "required": ["hook", "config"] }, "webHookAuthBasicAuthProperties": { "properties": { @@ -131,17 +117,11 @@ } }, "additionalProperties": false, - "required": [ - "user", - "password" - ] + "required": ["user", "password"] } }, "additionalProperties": false, - "required": [ - "type", - "config" - ] + "required": ["type", "config"] }, "httpRequestConfig": { "type": "object", @@ -149,9 +129,7 @@ "url": { "title": "HTTP address of API endpoint", "description": "This URL will be used to send the emails to.", - "examples": [ - "https://example.com/api/v1/email" - ], + "examples": ["https://example.com/api/v1/email"], "type": "string", "pattern": "^https?://" }, @@ -216,25 +194,15 @@ "in": { "type": "string", "description": "How the api key should be transferred", - "enum": [ - "header", - "cookie" - ] + "enum": ["header", "cookie"] } }, "additionalProperties": false, - "required": [ - "name", - "value", - "in" - ] + "required": ["name", "value", "in"] } }, "additionalProperties": false, - "required": [ - "type", - "config" - ] + "required": ["type", "config"] }, "selfServiceWebHook": { "type": "object", @@ -273,10 +241,7 @@ "const": true } }, - "required": [ - "ignore", - "parse" - ] + "required": ["ignore", "parse"] } }, "url": { @@ -337,46 +302,30 @@ "response": { "properties": { "ignore": { - "enum": [ - true - ] + "enum": [true] } }, - "required": [ - "ignore" - ] + "required": ["ignore"] } }, - "required": [ - "response" - ] + "required": ["response"] } }, { "properties": { "can_interrupt": { - "enum": [ - false - ] + "enum": [false] } }, - "require": [ - "can_interrupt" - ] + "require": ["can_interrupt"] } ], "additionalProperties": false, - "required": [ - "url", - "method" - ] + "required": ["url", "method"] } }, "additionalProperties": false, - "required": [ - "hook", - "config" - ] + "required": ["hook", "config"] }, "OIDCClaims": { "title": "OpenID Connect claims", @@ -409,9 +358,7 @@ "essential": true }, "acr": { - "values": [ - "urn:mace:incommon:iap:silver" - ] + "values": ["urn:mace:incommon:iap:silver"] } } } @@ -459,9 +406,7 @@ "properties": { "id": { "type": "string", - "examples": [ - "google" - ] + "examples": ["google"] }, "provider": { "title": "Provider", @@ -488,9 +433,7 @@ "linkedin", "lark" ], - "examples": [ - "google" - ] + "examples": ["google"] }, "label": { "title": "Optional string which will be used when generating labels for UI buttons.", @@ -505,23 +448,17 @@ "issuer_url": { "type": "string", "format": "uri", - "examples": [ - "https://accounts.google.com" - ] + "examples": ["https://accounts.google.com"] }, "auth_url": { "type": "string", "format": "uri", - "examples": [ - "https://accounts.google.com/o/oauth2/v2/auth" - ] + "examples": ["https://accounts.google.com/o/oauth2/v2/auth"] }, "token_url": { "type": "string", "format": "uri", - "examples": [ - "https://www.googleapis.com/oauth2/v4/token" - ] + "examples": ["https://www.googleapis.com/oauth2/v4/token"] }, "mapper_url": { "title": "Jsonnet Mapper URL", @@ -538,10 +475,7 @@ "type": "array", "items": { "type": "string", - "examples": [ - "offline_access", - "profile" - ] + "examples": ["offline_access", "profile"] } }, "microsoft_tenant": { @@ -560,30 +494,21 @@ "title": "Microsoft subject source", "description": "Controls which source the subject identifier is taken from by microsoft provider. If set to `userinfo` (the default) then the identifier is taken from the `sub` field of OIDC ID token or data received from `/userinfo` standard OIDC endpoint. If set to `me` then the `id` field of data structure received from `https://graph.microsoft.com/v1.0/me` is taken as an identifier.", "type": "string", - "enum": [ - "userinfo", - "me" - ], + "enum": ["userinfo", "me"], "default": "userinfo", - "examples": [ - "userinfo" - ] + "examples": ["userinfo"] }, "apple_team_id": { "title": "Apple Developer Team ID", "description": "Apple Developer Team ID needed for generating a JWT token for client secret", "type": "string", - "examples": [ - "KP76DQS54M" - ] + "examples": ["KP76DQS54M"] }, "apple_private_key_id": { "title": "Apple Private Key Identifier", "description": "Sign In with Apple Private Key Identifier needed for generating a JWT token for client secret", "type": "string", - "examples": [ - "UX56C66723" - ] + "examples": ["UX56C66723"] }, "apple_private_key": { "title": "Apple Private Key", @@ -600,18 +525,11 @@ "title": "Organization ID", "description": "The ID of the organization that this provider belongs to. Only effective in the Ory Network.", "type": "string", - "examples": [ - "12345678-1234-1234-1234-123456789012" - ] + "examples": ["12345678-1234-1234-1234-123456789012"] } }, "additionalProperties": false, - "required": [ - "id", - "provider", - "client_id", - "mapper_url" - ], + "required": ["id", "provider", "client_id", "mapper_url"], "allOf": [ { "if": { @@ -620,23 +538,17 @@ "const": "microsoft" } }, - "required": [ - "provider" - ] + "required": ["provider"] }, "then": { - "required": [ - "microsoft_tenant" - ] + "required": ["microsoft_tenant"] }, "else": { "not": { "properties": { "microsoft_tenant": {} }, - "required": [ - "microsoft_tenant" - ] + "required": ["microsoft_tenant"] } } }, @@ -647,9 +559,7 @@ "const": "apple" } }, - "required": [ - "provider" - ] + "required": ["provider"] }, "then": { "not": { @@ -659,9 +569,7 @@ "minLength": 1 } }, - "required": [ - "client_secret" - ] + "required": ["client_secret"] }, "required": [ "apple_private_key_id", @@ -670,9 +578,7 @@ ] }, "else": { - "required": [ - "client_secret" - ], + "required": ["client_secret"], "allOf": [ { "not": { @@ -682,9 +588,7 @@ "minLength": 1 } }, - "required": [ - "apple_team_id" - ] + "required": ["apple_team_id"] } }, { @@ -695,9 +599,7 @@ "minLength": 1 } }, - "required": [ - "apple_private_key_id" - ] + "required": ["apple_private_key_id"] } }, { @@ -708,9 +610,7 @@ "minLength": 1 } }, - "required": [ - "apple_private_key" - ] + "required": ["apple_private_key"] } } ] @@ -884,10 +784,7 @@ "title": "Required Authenticator Assurance Level", "description": "Sets what Authenticator Assurance Level (used for 2FA) is required to access this feature. If set to `highest_available` then this endpoint requires the highest AAL the identity has set up. If set to `aal1` then the identity can access this feature without 2FA.", "type": "string", - "enum": [ - "aal1", - "highest_available" - ], + "enum": ["aal1", "highest_available"], "default": "highest_available" }, "selfServiceAfterSettings": { @@ -1068,9 +965,7 @@ "path": { "title": "Path to PEM-encoded Fle", "type": "string", - "examples": [ - "path/to/file.pem" - ] + "examples": ["path/to/file.pem"] }, "base64": { "title": "Base64 Encoded Inline", @@ -1118,9 +1013,7 @@ "$ref": "#/definitions/emailCourierTemplate" } }, - "required": [ - "email" - ] + "required": ["email"] }, "valid": { "additionalProperties": false, @@ -1130,9 +1023,7 @@ "$ref": "#/definitions/emailCourierTemplate" } }, - "required": [ - "email" - ] + "required": ["email"] } } }, @@ -1182,9 +1073,7 @@ "selfservice": { "type": "object", "additionalProperties": false, - "required": [ - "default_browser_return_url" - ], + "required": ["default_browser_return_url"], "properties": { "default_browser_return_url": { "$ref": "#/definitions/defaultReturnTo" @@ -1219,30 +1108,20 @@ "description": "URL where the Settings UI is hosted. Check the [reference implementation](https://github.com/ory/kratos-selfservice-ui-node).", "type": "string", "format": "uri-reference", - "examples": [ - "https://my-app.com/user/settings" - ], + "examples": ["https://my-app.com/user/settings"], "default": "https://www.ory.sh/kratos/docs/fallback/settings" }, "lifespan": { "type": "string", "pattern": "^([0-9]+(ns|us|ms|s|m|h))+$", "default": "1h", - "examples": [ - "1h", - "1m", - "1s" - ] + "examples": ["1h", "1m", "1s"] }, "privileged_session_max_age": { "type": "string", "pattern": "^([0-9]+(ns|us|ms|s|m|h))+$", "default": "1h", - "examples": [ - "1h", - "1m", - "1s" - ] + "examples": ["1h", "1m", "1s"] }, "required_aal": { "$ref": "#/definitions/featureRequiredAal" @@ -1291,20 +1170,14 @@ "description": "URL where the Registration UI is hosted. Check the [reference implementation](https://github.com/ory/kratos-selfservice-ui-node).", "type": "string", "format": "uri-reference", - "examples": [ - "https://my-app.com/signup" - ], + "examples": ["https://my-app.com/signup"], "default": "https://www.ory.sh/kratos/docs/fallback/registration" }, "lifespan": { "type": "string", "pattern": "^([0-9]+(ns|us|ms|s|m|h))+$", "default": "1h", - "examples": [ - "1h", - "1m", - "1s" - ] + "examples": ["1h", "1m", "1s"] }, "before": { "$ref": "#/definitions/selfServiceBeforeRegistration" @@ -1323,20 +1196,14 @@ "description": "URL where the Login UI is hosted. Check the [reference implementation](https://github.com/ory/kratos-selfservice-ui-node).", "type": "string", "format": "uri-reference", - "examples": [ - "https://my-app.com/login" - ], + "examples": ["https://my-app.com/login"], "default": "https://www.ory.sh/kratos/docs/fallback/login" }, "lifespan": { "type": "string", "pattern": "^([0-9]+(ns|us|ms|s|m|h))+$", "default": "1h", - "examples": [ - "1h", - "1m", - "1s" - ] + "examples": ["1h", "1m", "1s"] }, "before": { "$ref": "#/definitions/selfServiceBeforeLogin" @@ -1362,9 +1229,7 @@ "description": "URL where the Ory Verify UI is hosted. This is the page where users activate and / or verify their email or telephone number. Check the [reference implementation](https://github.com/ory/kratos-selfservice-ui-node).", "type": "string", "format": "uri-reference", - "examples": [ - "https://my-app.com/verify" - ], + "examples": ["https://my-app.com/verify"], "default": "https://www.ory.sh/kratos/docs/fallback/verification" }, "after": { @@ -1376,11 +1241,7 @@ "type": "string", "pattern": "^([0-9]+(ns|us|ms|s|m|h))+$", "default": "1h", - "examples": [ - "1h", - "1m", - "1s" - ] + "examples": ["1h", "1m", "1s"] }, "before": { "$ref": "#/definitions/selfServiceBeforeVerification" @@ -1389,10 +1250,7 @@ "title": "Verification Strategy", "description": "The strategy to use for verification requests", "type": "string", - "enum": [ - "link", - "code" - ], + "enum": ["link", "code"], "default": "code" }, "notify_unknown_recipients": { @@ -1419,9 +1277,7 @@ "description": "URL where the Ory Recovery UI is hosted. This is the page where users request and complete account recovery. Check the [reference implementation](https://github.com/ory/kratos-selfservice-ui-node).", "type": "string", "format": "uri-reference", - "examples": [ - "https://my-app.com/verify" - ], + "examples": ["https://my-app.com/verify"], "default": "https://www.ory.sh/kratos/docs/fallback/recovery" }, "after": { @@ -1433,11 +1289,7 @@ "type": "string", "pattern": "^([0-9]+(ns|us|ms|s|m|h))+$", "default": "1h", - "examples": [ - "1h", - "1m", - "1s" - ] + "examples": ["1h", "1m", "1s"] }, "before": { "$ref": "#/definitions/selfServiceBeforeRecovery" @@ -1446,10 +1298,7 @@ "title": "Recovery Strategy", "description": "The strategy to use for recovery requests", "type": "string", - "enum": [ - "link", - "code" - ], + "enum": ["link", "code"], "default": "code" }, "notify_unknown_recipients": { @@ -1469,9 +1318,7 @@ "description": "URL where the Ory Kratos Error UI is hosted. Check the [reference implementation](https://github.com/ory/kratos-selfservice-ui-node).", "type": "string", "format": "uri-reference", - "examples": [ - "https://my-app.com/kratos-error" - ], + "examples": ["https://my-app.com/kratos-error"], "default": "https://www.ory.sh/kratos/docs/fallback/error" } } @@ -1510,20 +1357,14 @@ "base_url": { "title": "Override the base URL which should be used as the base for recovery and verification links.", "type": "string", - "examples": [ - "https://my-app.com" - ] + "examples": ["https://my-app.com"] }, "lifespan": { "title": "How long a link is valid for", "type": "string", "pattern": "^([0-9]+(ns|us|ms|s|m|h))+$", "default": "1h", - "examples": [ - "1h", - "1m", - "1s" - ] + "examples": ["1h", "1m", "1s"] } } } @@ -1538,6 +1379,12 @@ "title": "Enables Login and Registration with the Code Method", "default": false }, + "passwordless_login_fallback_enabled": { + "type": "boolean", + "title": "Passwordless Login Fallback Enabled", + "description": "This setting allows the code method to always login a user with code if they have registered with another authentication method such as password or social sign in.", + "default": false + }, "enabled": { "type": "boolean", "title": "Enables Code Method", @@ -1553,11 +1400,7 @@ "type": "string", "pattern": "^([0-9]+(ns|us|ms|s|m|h))+$", "default": "1h", - "examples": [ - "1h", - "1m", - "1s" - ] + "examples": ["1h", "1m", "1s"] } } } @@ -1680,17 +1523,13 @@ "type": "string", "title": "Relying Party Display Name", "description": "An name to help the user identify this RP.", - "examples": [ - "Ory Foundation" - ] + "examples": ["Ory Foundation"] }, "id": { "type": "string", "title": "Relying Party Identifier", "description": "The id must be a subset of the domain currently in the browser.", - "examples": [ - "ory.sh" - ] + "examples": ["ory.sh"] }, "origin": { "type": "string", @@ -1698,9 +1537,7 @@ "description": "An explicit RP origin. If left empty, this defaults to `id`, prepended with the current protocol schema (HTTP or HTTPS).", "format": "uri", "deprecationMessage": "This field is deprecated. Use `origins` instead.", - "examples": [ - "https://www.ory.sh" - ] + "examples": ["https://www.ory.sh"] }, "origins": { "type": "array", @@ -1721,18 +1558,13 @@ "description": "An icon to help the user identify this RP.", "format": "uri", "deprecationMessage": "This field is deprecated and ignored due to security considerations.", - "examples": [ - "https://www.ory.sh/an-icon.png" - ] + "examples": ["https://www.ory.sh/an-icon.png"] } }, "type": "object", "oneOf": [ { - "required": [ - "id", - "display_name" - ], + "required": ["id", "display_name"], "properties": { "origin": { "not": {} @@ -1743,11 +1575,7 @@ } }, { - "required": [ - "id", - "display_name", - "origin" - ], + "required": ["id", "display_name", "origin"], "properties": { "origin": { "type": "string" @@ -1758,11 +1586,7 @@ } }, { - "required": [ - "id", - "display_name", - "origins" - ], + "required": ["id", "display_name", "origins"], "properties": { "origin": { "not": {} @@ -1787,14 +1611,10 @@ "const": true } }, - "required": [ - "enabled" - ] + "required": ["enabled"] }, "then": { - "required": [ - "config" - ] + "required": ["config"] } }, "oidc": { @@ -1817,9 +1637,7 @@ "title": "Base URL for OAuth2 Redirect URIs", "description": "Can be used to modify the base URL for OAuth2 Redirect URLs. If unset, the Public Base URL will be used.", "format": "uri", - "examples": [ - "https://auth.myexample.org/" - ] + "examples": ["https://auth.myexample.org/"] }, "providers": { "title": "OpenID Connect and OAuth2 Providers", @@ -1924,9 +1742,7 @@ "$ref": "#/definitions/emailCourierTemplate" } }, - "required": [ - "email" - ] + "required": ["email"] } } }, @@ -1942,9 +1758,7 @@ "$ref": "#/definitions/emailCourierTemplate" } }, - "required": [ - "email" - ] + "required": ["email"] } } } @@ -1954,27 +1768,19 @@ "type": "string", "title": "Override message templates", "description": "You can override certain or all message templates by pointing this key to the path where the templates are located.", - "examples": [ - "/conf/courier-templates" - ] + "examples": ["/conf/courier-templates"] }, "message_retries": { "description": "Defines the maximum number of times the sending of a message is retried after it failed before it is marked as abandoned", "type": "integer", "default": 5, - "examples": [ - 10, - 60 - ] + "examples": [10, 60] }, "delivery_strategy": { "title": "Delivery Strategy", "description": "Defines how emails will be sent, either through SMTP (default) or HTTP.", "type": "string", - "enum": [ - "smtp", - "http" - ], + "enum": ["smtp", "http"], "default": "smtp" }, "http": { @@ -2031,9 +1837,7 @@ "title": "SMTP Sender Name", "description": "The recipient of an email will see this as the sender name.", "type": "string", - "examples": [ - "Bob" - ] + "examples": ["Bob"] }, "headers": { "title": "SMTP Headers", @@ -2057,9 +1861,7 @@ "default": "localhost" } }, - "required": [ - "connection_uri" - ], + "required": ["connection_uri"], "additionalProperties": false }, "sms": { @@ -2084,9 +1886,7 @@ "url": { "title": "HTTP address of API endpoint", "description": "This URL will be used to connect to the SMS provider.", - "examples": [ - "https://api.twillio.com/sms/send" - ], + "examples": ["https://api.twillio.com/sms/send"], "type": "string", "pattern": "^https?:\\/\\/.*" }, @@ -2128,19 +1928,14 @@ }, "additionalProperties": false }, - "required": [ - "url", - "method" - ], + "required": ["url", "method"], "additionalProperties": false } }, "additionalProperties": false } }, - "required": [ - "smtp" - ], + "required": ["smtp"], "additionalProperties": false }, "oauth2_provider": { @@ -2218,9 +2013,7 @@ "description": "The URL where the admin endpoint is exposed at.", "type": "string", "format": "uri", - "examples": [ - "https://kratos.private-network:4434/" - ] + "examples": ["https://kratos.private-network:4434/"] }, "host": { "title": "Admin Host", @@ -2234,9 +2027,7 @@ "type": "integer", "minimum": 1, "maximum": 65535, - "examples": [ - 4434 - ], + "examples": [4434], "default": 4434 }, "socket": { @@ -2295,9 +2086,7 @@ ] }, "uniqueItems": true, - "default": [ - "*" - ], + "default": ["*"], "examples": [ [ "https://example.com", @@ -2309,13 +2098,7 @@ "allowed_methods": { "type": "array", "description": "A list of HTTP methods the user agent is allowed to use with cross-domain requests.", - "default": [ - "POST", - "GET", - "PUT", - "PATCH", - "DELETE" - ], + "default": ["POST", "GET", "PUT", "PATCH", "DELETE"], "items": { "type": "string", "enum": [ @@ -2346,9 +2129,7 @@ "exposed_headers": { "type": "array", "description": "Sets which headers are safe to expose to the API of a CORS API specification.", - "default": [ - "Content-Type" - ], + "default": ["Content-Type"], "items": { "type": "string" } @@ -2391,9 +2172,7 @@ "type": "integer", "minimum": 1, "maximum": 65535, - "examples": [ - 4433 - ], + "examples": [4433], "default": 4433 }, "socket": { @@ -2443,10 +2222,7 @@ "format": { "description": "The log format can either be text or JSON.", "type": "string", - "enum": [ - "json", - "text" - ] + "enum": ["json", "text"] } }, "additionalProperties": false @@ -2487,9 +2263,7 @@ "id": { "title": "The schema's ID.", "type": "string", - "examples": [ - "employee" - ] + "examples": ["employee"] }, "url": { "type": "string", @@ -2503,16 +2277,11 @@ ] } }, - "required": [ - "id", - "url" - ] + "required": ["id", "url"] } } }, - "required": [ - "schemas" - ], + "required": ["schemas"], "additionalProperties": false }, "secrets": { @@ -2561,10 +2330,7 @@ "description": "One of the values: argon2, bcrypt.\nAny other hashes will be migrated to the set algorithm once an identity authenticates using their password.", "type": "string", "default": "bcrypt", - "enum": [ - "argon2", - "bcrypt" - ] + "enum": ["argon2", "bcrypt"] }, "argon2": { "title": "Configuration for the Argon2id hasher.", @@ -2620,9 +2386,7 @@ "title": "Configuration for the Bcrypt hasher. Minimum is 4 when --dev flag is used and 12 otherwise.", "type": "object", "additionalProperties": false, - "required": [ - "cost" - ], + "required": ["cost"], "properties": { "cost": { "type": "integer", @@ -2644,11 +2408,7 @@ "description": "One of the values: noop, aes, xchacha20-poly1305", "type": "string", "default": "noop", - "enum": [ - "noop", - "aes", - "xchacha20-poly1305" - ] + "enum": ["noop", "aes", "xchacha20-poly1305"] } } }, @@ -2672,11 +2432,7 @@ "title": "HTTP Cookie Same Site Configuration", "description": "Sets the session and CSRF cookie SameSite.", "type": "string", - "enum": [ - "Strict", - "Lax", - "None" - ], + "enum": ["Strict", "Lax", "None"], "default": "Lax" } }, @@ -2706,9 +2462,7 @@ "patternProperties": { "[a-zA-Z0-9-_.]+": { "type": "object", - "required": [ - "jwks_url" - ], + "required": ["jwks_url"], "properties": { "ttl": { "type": "string", @@ -2741,11 +2495,7 @@ "type": "string", "pattern": "^([0-9]+(ns|us|ms|s|m|h))+$", "default": "24h", - "examples": [ - "1h", - "1m", - "1s" - ] + "examples": ["1h", "1m", "1s"] }, "cookie": { "type": "object", @@ -2776,11 +2526,7 @@ "title": "Session Cookie SameSite Configuration", "description": "Sets the session cookie SameSite. Overrides `cookies.same_site`.", "type": "string", - "enum": [ - "Strict", - "Lax", - "None" - ] + "enum": ["Strict", "Lax", "None"] } }, "additionalProperties": false @@ -2790,11 +2536,7 @@ "description": "Sets when a session can be extended. Settings this value to `24h` will prevent the session from being extended before until 24 hours before it expires. This setting prevents excessive writes to the database. We highly recommend setting this value.", "type": "string", "pattern": "^([0-9]+(ns|us|ms|s|m|h))+$", - "examples": [ - "1h", - "1m", - "1s" - ] + "examples": ["1h", "1m", "1s"] } } }, @@ -2803,9 +2545,7 @@ "description": "SemVer according to https://semver.org/ prefixed with `v` as in our releases.", "type": "string", "pattern": "^(v(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?)|$", - "examples": [ - "v0.5.0-alpha.1" - ] + "examples": ["v0.5.0-alpha.1"] }, "dev": { "type": "boolean" @@ -2829,9 +2569,7 @@ "type": "integer", "minimum": 0, "maximum": 65535, - "examples": [ - 4434 - ], + "examples": [4434], "default": 0 }, "config": { @@ -2906,14 +2644,10 @@ "const": true } }, - "required": [ - "enabled" - ] + "required": ["enabled"] } }, - "required": [ - "verification" - ] + "required": ["verification"] }, { "properties": { @@ -2923,31 +2657,21 @@ "const": true } }, - "required": [ - "enabled" - ] + "required": ["enabled"] } }, - "required": [ - "recovery" - ] + "required": ["recovery"] } ] } }, - "required": [ - "flows" - ] + "required": ["flows"] } }, - "required": [ - "selfservice" - ] + "required": ["selfservice"] }, "then": { - "required": [ - "courier" - ] + "required": ["courier"] } }, { @@ -2966,33 +2690,21 @@ ] } }, - "required": [ - "algorithm" - ] + "required": ["algorithm"] } }, - "required": [ - "ciphers" - ] + "required": ["ciphers"] }, "then": { - "required": [ - "secrets" - ], + "required": ["secrets"], "properties": { "secrets": { - "required": [ - "cipher" - ] + "required": ["cipher"] } } } } ], - "required": [ - "identity", - "dsn", - "selfservice" - ], + "required": ["identity", "dsn", "selfservice"], "additionalProperties": false } diff --git a/identity/pool.go b/identity/pool.go index e0d14637f29a..46083d3d525b 100644 --- a/identity/pool.go +++ b/identity/pool.go @@ -91,5 +91,8 @@ type ( // InjectTraitsSchemaURL sets the identity's traits JSON schema URL from the schema's ID. InjectTraitsSchemaURL(ctx context.Context, i *Identity) error + + // FindIdentityByAnyCaseSensitiveCredentialIdentifier returns an identity by matching the identifier to any of the identity's credentials. + FindIdentityByCredentialIdentifier(ctx context.Context, identifier string, caseSensitive bool) (*Identity, error) } ) diff --git a/identity/test/pool.go b/identity/test/pool.go index 85cafd3d369f..f5e96960ac00 100644 --- a/identity/test/pool.go +++ b/identity/test/pool.go @@ -846,6 +846,49 @@ func TestPool(ctx context.Context, conf *config.Config, p persistence.Persister, }) }) + t.Run("case=find identity only by credentials identifier", func(t *testing.T) { + expected := passwordIdentity("", "find-credentials-identifier-only@ory.sh") + expected.Traits = identity.Traits(`{}`) + + require.NoError(t, p.CreateIdentity(ctx, expected)) + createdIDs = append(createdIDs, expected.ID) + + actual, err := p.FindIdentityByCredentialIdentifier(ctx, "find-credentials-IDENTIFIER-only@ory.sh", false) + require.NoError(t, err) + + expected.Credentials = nil + assertEqual(t, expected, actual) + + t.Run("not if on another network", func(t *testing.T) { + _, p := testhelpers.NewNetwork(t, ctx, p) + _, err := p.FindIdentityByCredentialIdentifier(ctx, "find-credentials-IDENTIFIER-only@ory.sh", false) + require.ErrorIs(t, err, sqlcon.ErrNoRows) + }) + }) + + t.Run("case=find identity only by credentials identifier case sensitive", func(t *testing.T) { + expected := passwordIdentity("", "find-credentials-identifier-only-ci@ory.sh") + expected.Traits = identity.Traits(`{}`) + + require.NoError(t, p.CreateIdentity(ctx, expected)) + createdIDs = append(createdIDs, expected.ID) + + _, err := p.FindIdentityByCredentialIdentifier(ctx, "find-credentials-IDENTIFIER-only-ci@ory.sh", true) + require.ErrorIs(t, err, sqlcon.ErrNoRows) + + actual, err := p.FindIdentityByCredentialIdentifier(ctx, "find-credentials-identifier-only-ci@ory.sh", true) + require.NoError(t, err) + + expected.Credentials = nil + assertEqual(t, expected, actual) + + t.Run("not if on another network", func(t *testing.T) { + _, p := testhelpers.NewNetwork(t, ctx, p) + _, err := p.FindIdentityByCredentialIdentifier(ctx, "find-credentials-identifier-only-ci@ory.sh", true) + require.ErrorIs(t, err, sqlcon.ErrNoRows) + }) + }) + t.Run("case=find identity by its credentials respects cases", func(t *testing.T) { caseSensitive := "6Q(%ZKd~8u_(5uea@ory.sh" caseInsensitiveWithSpaces := " 6Q(%ZKD~8U_(5uea@ORY.sh " diff --git a/persistence/sql/identity/persister_identity.go b/persistence/sql/identity/persister_identity.go index 73aa9300a6a9..6e3566b7721c 100644 --- a/persistence/sql/identity/persister_identity.go +++ b/persistence/sql/identity/persister_identity.go @@ -127,12 +127,56 @@ func NormalizeIdentifier(ct identity.CredentialsType, match string) string { return match case identity.CredentialsTypePassword: fallthrough + case identity.CredentialsTypeCodeAuth: + fallthrough case identity.CredentialsTypeWebAuthn: return stringToLowerTrim(match) } return match } +func (p *IdentityPersister) FindIdentityByCredentialIdentifier(ctx context.Context, identifier string, caseSensitive bool) (_ *identity.Identity, err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.FindIdentityByCredentialIdentifier") + defer otelx.End(span, &err) + + var find struct { + IdentityID uuid.UUID `db:"identity_id"` + } + + if !caseSensitive { + identifier = NormalizeIdentifier(identity.CredentialsTypePassword, identifier) + } + + nid := p.NetworkID(ctx) + if err := p.GetConnection(ctx).RawQuery(` +SELECT ic.identity_id +FROM identity_credentials ic +INNER JOIN identity_credential_identifiers ici + ON ic.id = ici.identity_credential_id +WHERE ici.identifier = ? +AND ic.nid = ? +AND ici.nid = ? +LIMIT 1`, + identifier, + nid, + nid, + ).First(&find); err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, sqlcon.HandleError(err) + } + + return nil, sqlcon.HandleError(err) + } + + i, err := p.GetIdentity(ctx, find.IdentityID, identity.ExpandDefault) + if err != nil { + return nil, err + } + + // we don't need the credentials. we just need the identity. + return i.CopyWithoutCredentials(), nil +} + func (p *IdentityPersister) FindByCredentialsIdentifier(ctx context.Context, ct identity.CredentialsType, match string) (_ *identity.Identity, _ *identity.Credentials, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.FindByCredentialsIdentifier") defer otelx.End(span, &err) diff --git a/selfservice/strategy/code/strategy_login.go b/selfservice/strategy/code/strategy_login.go index 7be603861c8b..297ec75f9c57 100644 --- a/selfservice/strategy/code/strategy_login.go +++ b/selfservice/strategy/code/strategy_login.go @@ -5,9 +5,12 @@ package code import ( "context" + "database/sql" "net/http" "strings" + "github.com/ory/x/sqlcon" + "github.com/gofrs/uuid" "github.com/pkg/errors" @@ -93,20 +96,35 @@ func (s *Strategy) PopulateLoginMethod(r *http.Request, requestedAAL identity.Au return s.PopulateMethod(r, lf) } -func (s *Strategy) getIdentity(ctx context.Context, identifier string) (_ *identity.Identity, _ *identity.Credentials, err error) { +// findIdentityByIdentifier returns the identity and the code credential for the given identifier. +// If the identity does not have a code credential and PasswordlessLoginFallbackEnabled is false, an error is returned. +// If the identity does not have a code credential and PasswordlessLoginFallbackEnabled is true, the identity and no credential are returned. +func (s *Strategy) findIdentityByIdentifier(ctx context.Context, identifier string) (_ *identity.Identity, isFallback bool, err error) { ctx, span := s.deps.Tracer(ctx).Tracer().Start(ctx, "selfservice.strategy.code.strategy.getIdentity") defer otelx.End(span, &err) - i, cred, err := s.deps.PrivilegedIdentityPool().FindByCredentialsIdentifier(ctx, s.ID(), identifier) - if err != nil { - return nil, nil, errors.WithStack(schema.NewNoCodeAuthnCredentials()) + id, cred, err := s.deps.PrivilegedIdentityPool().FindByCredentialsIdentifier(ctx, s.ID(), identifier) + if errors.Is(err, sqlcon.ErrNoRows) && s.deps.Config().SelfServiceCodeStrategy(ctx).PasswordlessLoginFallbackEnabled { + // we might be able to do a fallback login since we could not find a credential on this identifier + // Case insensitive because we only care about emails. + id, err := s.deps.PrivilegedIdentityPool().FindIdentityByCredentialIdentifier(ctx, identifier, false) + if err != nil { + return nil, false, errors.WithStack(schema.NewNoCodeAuthnCredentials()) + } + + // we don't know if the user has verified the code yet, so we just return the identity + // and let the caller decide what to do with it + return id, true, nil + } else if err != nil { + return nil, false, errors.WithStack(schema.NewNoCodeAuthnCredentials()) } if len(cred.Identifiers) == 0 { - return nil, nil, errors.WithStack(schema.NewNoCodeAuthnCredentials()) + return nil, false, errors.WithStack(schema.NewNoCodeAuthnCredentials()) } - return i, cred, nil + // we don't need the code credential, we just need to know that it exists + return id, false, nil } func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, _ uuid.UUID) (_ *identity.Identity, err error) { @@ -168,7 +186,7 @@ func (s *Strategy) loginSendEmail(ctx context.Context, w http.ResponseWriter, r p.Identifier = maybeNormalizeEmail(p.Identifier) // Step 1: Get the identity - i, _, err := s.getIdentity(ctx, p.Identifier) + i, _, err := s.findIdentityByIdentifier(ctx, p.Identifier) if err != nil { return err } @@ -237,7 +255,7 @@ func (s *Strategy) loginVerifyCode(ctx context.Context, r *http.Request, f *logi p.Identifier = maybeNormalizeEmail(p.Identifier) // Step 1: Get the identity - i, _, err := s.getIdentity(ctx, p.Identifier) + i, isFallback, err := s.findIdentityByIdentifier(ctx, p.Identifier) if err != nil { return nil, err } @@ -255,6 +273,22 @@ func (s *Strategy) loginVerifyCode(ctx context.Context, r *http.Request, f *logi return nil, errors.WithStack(err) } + // the code is correct, if the login happened through a different credential, we need to update the identity + if isFallback && s.deps.Config().SelfServiceCodeStrategy(ctx).PasswordlessLoginFallbackEnabled { + if err := i.SetCredentialsWithConfig( + s.ID(), + // p.Identifier was normalized prior. + identity.Credentials{Type: s.ID(), Identifiers: []string{p.Identifier}}, + &identity.CredentialsCode{UsedAt: sql.NullTime{}}, + ); err != nil { + return nil, errors.WithStack(err) + } + + if err := s.deps.PrivilegedIdentityPool().UpdateIdentity(ctx, i); err != nil { + return nil, errors.WithStack(err) + } + } + // Step 2: The code was correct f.Active = identity.CredentialsTypeCodeAuth diff --git a/selfservice/strategy/code/strategy_login_test.go b/selfservice/strategy/code/strategy_login_test.go index f327a36e961a..05f98354ca5c 100644 --- a/selfservice/strategy/code/strategy_login_test.go +++ b/selfservice/strategy/code/strategy_login_test.go @@ -41,7 +41,7 @@ func TestLoginCodeStrategy(t *testing.T) { public, _, _, _ := testhelpers.NewKratosServerWithCSRFAndRouters(t, reg) - createIdentity := func(ctx context.Context, t *testing.T, moreIdentifiers ...string) *identity.Identity { + createIdentity := func(ctx context.Context, t *testing.T, withoutCodeCredential bool, moreIdentifiers ...string) *identity.Identity { t.Helper() i := identity.NewIdentity(config.DefaultIdentityTraitsSchemaID) email := testhelpers.RandomEmail() @@ -57,7 +57,9 @@ func TestLoginCodeStrategy(t *testing.T) { identity.CredentialsTypePassword: {Identifiers: append([]string{email}, moreIdentifiers...), Type: identity.CredentialsTypePassword, Config: sqlxx.JSONRawMessage("{\"some\" : \"secret\"}")}, identity.CredentialsTypeOIDC: {Type: identity.CredentialsTypeOIDC, Identifiers: append([]string{email}, moreIdentifiers...), Config: sqlxx.JSONRawMessage("{\"some\" : \"secret\"}")}, identity.CredentialsTypeWebAuthn: {Type: identity.CredentialsTypeWebAuthn, Identifiers: append([]string{email}, moreIdentifiers...), Config: sqlxx.JSONRawMessage("{\"some\" : \"secret\", \"user_handle\": \"rVIFaWRcTTuQLkXFmQWpgA==\"}")}, - identity.CredentialsTypeCodeAuth: {Type: identity.CredentialsTypeCodeAuth, Identifiers: append([]string{email}, moreIdentifiers...), Config: sqlxx.JSONRawMessage("{\"address_type\": \"email\", \"used_at\": \"2023-07-26T16:59:06+02:00\"}")}, + } + if !withoutCodeCredential { + credentials[identity.CredentialsTypeCodeAuth] = identity.Credentials{Type: identity.CredentialsTypeCodeAuth, Identifiers: append([]string{email}, moreIdentifiers...), Config: sqlxx.JSONRawMessage("{\"address_type\": \"email\", \"used_at\": \"2023-07-26T16:59:06+02:00\"}")} } i.Credentials = credentials @@ -91,10 +93,10 @@ func TestLoginCodeStrategy(t *testing.T) { ApiTypeNative ApiType = "api" ) - createLoginFlow := func(ctx context.Context, t *testing.T, public *httptest.Server, apiType ApiType, moreIdentifiers ...string) *state { + createLoginFlow := func(ctx context.Context, t *testing.T, public *httptest.Server, apiType ApiType, withoutCodeCredential bool, moreIdentifiers ...string) *state { t.Helper() - identity := createIdentity(ctx, t, moreIdentifiers...) + identity := createIdentity(ctx, t, withoutCodeCredential, moreIdentifiers...) var client *http.Client if apiType == ApiTypeNative { @@ -202,7 +204,7 @@ func TestLoginCodeStrategy(t *testing.T) { t.Run("test="+tc.d, func(t *testing.T) { t.Run("case=email identifier should be case insensitive", func(t *testing.T) { // create login flow - s := createLoginFlow(ctx, t, public, tc.apiType) + s := createLoginFlow(ctx, t, public, tc.apiType, false) // submit email s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { @@ -223,7 +225,7 @@ func TestLoginCodeStrategy(t *testing.T) { t.Run("case=should be able to log in with code", func(t *testing.T) { // create login flow - s := createLoginFlow(ctx, t, public, tc.apiType) + s := createLoginFlow(ctx, t, public, tc.apiType, false) // submit email s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { @@ -242,9 +244,71 @@ func TestLoginCodeStrategy(t *testing.T) { }, true, nil) }) + t.Run("case=should login without code credential on any existing credential", func(t *testing.T) { + ctx := context.Background() + + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.passwordless_login_fallback_enabled", true) + + t.Cleanup(func() { + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.passwordless_login_fallback_enabled", false) + }) + + s := createLoginFlow(ctx, t, public, tc.apiType, true) + + // submit email + s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { + v.Set("identifier", s.identityEmail) + }, false, nil) + + message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Login to your account") + assert.Contains(t, message.Body, "please login to your account by entering the following code") + + loginCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) + assert.NotEmpty(t, loginCode) + + // submit code + s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { + v.Set("code", loginCode) + }, true, nil) + + // assert that the identity contains a code credential + identity, cred, err := reg.PrivilegedIdentityPool().FindByCredentialsIdentifier(ctx, identity.CredentialsTypeCodeAuth, s.identityEmail) + require.NoError(t, err) + require.NotNil(t, cred) + assert.Equal(t, identity.ID, cred.IdentityID) + }) + + t.Run("case=should not login with any credential if not set", func(t *testing.T) { + ctx := context.Background() + + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.passwordless_login_fallback_enabled", false) + + s := createLoginFlow(ctx, t, public, tc.apiType, true) + + // submit email + s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { + v.Set("identifier", s.identityEmail) + }, false, func(t *testing.T, s *state, body string, resp *http.Response) { + if tc.apiType == ApiTypeBrowser { + require.EqualValues(t, http.StatusOK, resp.StatusCode) + require.EqualValues(t, conf.SelfServiceFlowLoginUI(ctx).Path, resp.Request.URL.Path) + + lf, resp, err := testhelpers.NewSDKCustomClient(public, s.client).FrontendApi.GetLoginFlow(ctx).Id(s.flowID).Execute() + require.NoError(t, err) + require.EqualValues(t, http.StatusOK, resp.StatusCode) + body, err := json.Marshal(lf) + require.NoError(t, err) + assert.Contains(t, gjson.GetBytes(body, "ui.messages.0.text").String(), "account does not exist or has not setup sign in with code") + } else { + require.EqualValues(t, http.StatusBadRequest, resp.StatusCode) + assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "account does not exist or has not setup sign in with code") + } + }) + }) + t.Run("case=should not be able to change submitted id on code submit", func(t *testing.T) { // create login flow - s := createLoginFlow(ctx, t, public, tc.apiType) + s := createLoginFlow(ctx, t, public, tc.apiType, false) // submit email s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { @@ -279,7 +343,7 @@ func TestLoginCodeStrategy(t *testing.T) { }) t.Run("case=should not be able to proceed to code entry when the account is unknown", func(t *testing.T) { - s := createLoginFlow(ctx, t, public, tc.apiType) + s := createLoginFlow(ctx, t, public, tc.apiType, false) // submit email s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { @@ -303,7 +367,7 @@ func TestLoginCodeStrategy(t *testing.T) { }) t.Run("case=should not be able to use valid code after 5 attempts", func(t *testing.T) { - s := createLoginFlow(ctx, t, public, tc.apiType) + s := createLoginFlow(ctx, t, public, tc.apiType, false) // submit email s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { @@ -355,7 +419,7 @@ func TestLoginCodeStrategy(t *testing.T) { conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.config.lifespan", "1h") }) - s := createLoginFlow(ctx, t, public, tc.apiType) + s := createLoginFlow(ctx, t, public, tc.apiType, false) // submit email s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { @@ -392,7 +456,7 @@ func TestLoginCodeStrategy(t *testing.T) { t.Run("case=resend code should invalidate previous code", func(t *testing.T) { ctx := context.Background() - s := createLoginFlow(ctx, t, public, tc.apiType) + s := createLoginFlow(ctx, t, public, tc.apiType, false) s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { v.Set("identifier", s.identityEmail) @@ -434,7 +498,7 @@ func TestLoginCodeStrategy(t *testing.T) { }) t.Run("case=on login with un-verified address, should verify it", func(t *testing.T) { - s := createLoginFlow(ctx, t, public, tc.apiType, testhelpers.RandomEmail()) + s := createLoginFlow(ctx, t, public, tc.apiType, false, testhelpers.RandomEmail()) // we need to fetch only the first email loginEmail := gjson.Get(s.identity.Traits.String(), "email_1").String() @@ -503,7 +567,7 @@ func TestLoginCodeStrategy(t *testing.T) { conf.MustSet(ctx, config.ViperKeySessionWhoAmIAAL, "aal1") }) - s := createLoginFlow(ctx, t, public, tc.apiType) + s := createLoginFlow(ctx, t, public, tc.apiType, false) // submit email s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { diff --git a/test/e2e/cypress/integration/profiles/code/login/error.spec.ts b/test/e2e/cypress/integration/profiles/code/login/error.spec.ts index 3dbc3729909d..4541d92eca49 100644 --- a/test/e2e/cypress/integration/profiles/code/login/error.spec.ts +++ b/test/e2e/cypress/integration/profiles/code/login/error.spec.ts @@ -30,11 +30,14 @@ context("Login error messages with code method", () => { code: '[data-testid="code"]', }, express: { + identity: '[data-testid="login-flow-code"] input[name="identifier"]', + code: 'input[name="code"]', + }, + react: { identity: 'input[name="identifier"]', code: 'input[name="code"]', }, } - Selectors["react"] = Selectors["express"] before(() => { cy.useConfigProfile(profile) @@ -185,7 +188,7 @@ context("Login error messages with code method", () => { cy.submitCodeForm(app) cy.get("@email").then((email) => { - cy.getLoginCodeFromEmail(email.toString()).should((code) => { + cy.getLoginCodeFromEmail(email.toString()).then((code) => { cy.get(Selectors[app]["code"]).type(code) }) }) diff --git a/test/e2e/cypress/integration/profiles/code/login/success.spec.ts b/test/e2e/cypress/integration/profiles/code/login/success.spec.ts index 1f6635c25aa9..958f367612ab 100644 --- a/test/e2e/cypress/integration/profiles/code/login/success.spec.ts +++ b/test/e2e/cypress/integration/profiles/code/login/success.spec.ts @@ -33,13 +33,18 @@ context("Login success with code method", () => { resend: '[data-testid="field/resend/code"]', }, express: { + identity: '[data-testid="login-flow-code"] input[name="identifier"]', + code: 'input[name="code"]', + submit: 'button[name="method"][value="code"]', + resend: 'button[name="resend"]', + }, + react: { identity: 'input[name="identifier"]', code: 'input[name="code"]', submit: 'button[name="method"][value="code"]', resend: 'button[name="resend"]', }, } - Selectors["react"] = Selectors["express"] before(() => { cy.deleteMail() @@ -66,7 +71,7 @@ context("Login success with code method", () => { cy.get(Selectors[app]["identity"]).clear().type(email.toString()) cy.submitCodeForm(app) - cy.getLoginCodeFromEmail(email.toString()).should((code) => { + cy.getLoginCodeFromEmail(email.toString()).then((code) => { cy.get(Selectors[app]["code"]).type(code) cy.get(Selectors[app]["submit"]).click() @@ -106,18 +111,74 @@ context("Login success with code method", () => { }) }) + it("should be able to sign in with code on account registered with password", () => { + const email = gen.email() + // register account with password + cy.register({ + email, + password: gen.password(), + fields: { "traits.tos": 1 }, + }) + + cy.getVerificationCodeFromEmail(email).then((code) => { + expect(code).to.not.be.empty + cy.deleteMail() + }) + + cy.clearAllCookies() + + cy.visit(route) + + cy.get(Selectors[app]["identity"]).clear().type(email) + cy.submitCodeForm(app) + + cy.getLoginCodeFromEmail(email).then((code) => { + cy.get(Selectors[app]["code"]).type(code) + + cy.get(Selectors[app]["submit"]).click() + }) + + if (app === "mobile") { + cy.get('[data-testid="session-token"]').then((token) => { + cy.getSession({ + expectAal: "aal1", + expectMethods: ["code"], + token: token.text(), + }).then((session) => { + cy.wrap(session).as("session") + }) + }) + + cy.get('[data-testid="session-content"]').should("contain", email) + cy.get('[data-testid="session-token"]').should("not.be.empty") + } else { + cy.getSession({ expectAal: "aal1", expectMethods: ["code"] }).then( + (session) => { + cy.wrap(session).as("session") + }, + ) + } + + cy.get("@session").then(({ identity }) => { + expect(identity.id).to.not.be.empty + expect(identity.verifiable_addresses).to.have.length(1) + expect(identity.verifiable_addresses[0].status).to.equal("completed") + expect(identity.traits.email).to.equal(email) + }) + }) + it("should be able to resend login code", () => { cy.get("@email").then((email) => { cy.get(Selectors[app]["identity"]).clear().type(email.toString()) cy.submitCodeForm(app) - cy.getLoginCodeFromEmail(email.toString()).should((code) => { + cy.getLoginCodeFromEmail(email.toString()).then((code) => { cy.wrap(code).as("code1") }) cy.get(Selectors[app]["resend"]).click() - cy.getLoginCodeFromEmail(email.toString()).should((code) => { + cy.getLoginCodeFromEmail(email.toString()).then((code) => { cy.wrap(code).as("code2") }) @@ -208,7 +269,7 @@ context("Login success with code method", () => { cy.get(Selectors[app]["identity"]).clear().type(email2) cy.submitCodeForm(app) - cy.getLoginCodeFromEmail(email2).should((code) => { + cy.getLoginCodeFromEmail(email2).then((code) => { cy.get(Selectors[app]["code"]).type(code) cy.get(Selectors[app]["submit"]).click() }) diff --git a/test/e2e/cypress/integration/profiles/code/registration/error.spec.ts b/test/e2e/cypress/integration/profiles/code/registration/error.spec.ts index 48c8005d28e0..ef435991f736 100644 --- a/test/e2e/cypress/integration/profiles/code/registration/error.spec.ts +++ b/test/e2e/cypress/integration/profiles/code/registration/error.spec.ts @@ -32,13 +32,20 @@ context("Registration error messages with code method", () => { code: "[data-testid='field/code']", }, express: { + identifier: + "[data-testid='registration-flow-code'] input[name='identifier']", + email: + "[data-testid='registration-flow-code'] input[name='traits.email']", + tos: "[data-testid='registration-flow-code'] [name='traits.tos'] + label", + code: "input[name='code']", + }, + react: { identifier: "input[name='identifier']", email: "input[name='traits.email']", tos: "[name='traits.tos'] + label", code: "input[name='code']", }, } - Selectors["react"] = Selectors["express"] before(() => { if (app !== "mobile") { @@ -198,7 +205,7 @@ context("Registration error messages with code method", () => { "An email containing a code has been sent to the email address you provided", ) - cy.getRegistrationCodeFromEmail(email).should((code) => { + cy.getRegistrationCodeFromEmail(email).then((code) => { cy.get(Selectors[app]["code"]).type(code) cy.submitCodeForm(app) }) diff --git a/test/e2e/cypress/integration/profiles/code/registration/success.spec.ts b/test/e2e/cypress/integration/profiles/code/registration/success.spec.ts index a07cd6d51b26..cdc5e8019219 100644 --- a/test/e2e/cypress/integration/profiles/code/registration/success.spec.ts +++ b/test/e2e/cypress/integration/profiles/code/registration/success.spec.ts @@ -47,6 +47,24 @@ context("Registration success with code method", () => { codeHiddenMethod: "[data-testid='field/method/code']", }, express: { + identifier: + "[data-testid='login-flow-code'] input[name='identifier']", + recoveryEmail: "input[name=email]", + email: + "[data-testid='registration-flow-code'] input[name='traits.email']", + email2: + "[data-testid='registration-flow-code'] input[name='traits.email2']", + tos: "[data-testid='registration-flow-code'] [name='traits.tos'] + label", + username: + "[data-testid='registration-flow-code'] input[name='traits.username']", + code: "input[name='code']", + recoveryCode: "input[name=code]", + submitRecovery: "button[name=method][value=code]", + submitCode: "button[name='method'][value='code']", + resendCode: "button[name='resend'][value='code']", + codeHiddenMethod: "input[name='method'][value='code'][type='hidden']", + }, + react: { identifier: "input[name='identifier']", recoveryEmail: "input[name=email]", email: "input[name='traits.email']", @@ -61,7 +79,6 @@ context("Registration success with code method", () => { codeHiddenMethod: "input[name='method'][value='code'][type='hidden']", }, } - Selectors["react"] = Selectors["express"] before(() => { cy.deleteMail() @@ -89,7 +106,7 @@ context("Registration success with code method", () => { "An email containing a code has been sent to the email address you provided", ) - cy.getRegistrationCodeFromEmail(email).should((code) => + cy.getRegistrationCodeFromEmail(email).then((code) => cy.wrap(code).as("code1"), ) @@ -97,7 +114,7 @@ context("Registration success with code method", () => { cy.get(Selectors[app]["codeHiddenMethod"]).should("exist") cy.get(Selectors[app]["resendCode"]).click() - cy.getRegistrationCodeFromEmail(email).should((code) => { + cy.getRegistrationCodeFromEmail(email).then((code) => { cy.wrap(code).as("code2") }) diff --git a/test/e2e/profiles/code/.kratos.yml b/test/e2e/profiles/code/.kratos.yml index ec69fb050fab..2d1e3457e8f0 100644 --- a/test/e2e/profiles/code/.kratos.yml +++ b/test/e2e/profiles/code/.kratos.yml @@ -13,16 +13,14 @@ selfservice: after: code: hooks: - - - hook: session + - hook: session login: ui_url: http://localhost:4455/login after: code: hooks: - - - hook: require_verified_address + - hook: require_verified_address error: ui_url: http://localhost:4455/error verification: @@ -35,7 +33,7 @@ selfservice: ui_url: http://localhost:4455/recovery methods: password: - enabled: false + enabled: true code: passwordless_enabled: true enabled: true From 4b7fd0d688ca00307ffa296be940293cc20ea558 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Mon, 16 Oct 2023 15:57:42 +0000 Subject: [PATCH 149/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 684324c041c1..0e41661115f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-10-13)](#2023-10-13) +- [ (2023-10-16)](#2023-10-16) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -313,7 +313,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-10-13) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-10-16) ## Breaking Changes @@ -506,6 +506,18 @@ https://github.com/ory/kratos/pull/3480 - Remove slow queries from update identities ([#3553](https://github.com/ory/kratos/issues/3553)) ([d138abb](https://github.com/ory/kratos/commit/d138abb6278ebb232e120bee0fb956a0f2816b8d)) +- Respond with 422 when SPA identity requires AAL2 + ([#3572](https://github.com/ory/kratos/issues/3572)) + ([df18c09](https://github.com/ory/kratos/commit/df18c09e0089743e8aee17540d277b9572252e06)): + + If you submit a browser login flow with an `Accept` header of + `application/json`, but the login flow requires AAL2, then there is no way for + the code to know it needs to redirect the user to the 2FA page. Instead of + responding with the `Session` in this scenario, this PR changes the behaviour + to respond with a `browser_location_change_required` error (status `422`) to + indicate that the browser needs to open a specific URL, + /self-service/login/browser?aal=aal2. + - Return 400 bad request for invalid login challenge ([#3404](https://github.com/ory/kratos/issues/3404)) ([ca34e9b](https://github.com/ory/kratos/commit/ca34e9b744482b41d65082f3bed52e9c4ebd7ba4)) @@ -720,6 +732,14 @@ https://github.com/ory/kratos/pull/3480 - Improve performance by computing password hashes while validating ([#3508](https://github.com/ory/kratos/issues/3508)) ([a9786c5](https://github.com/ory/kratos/commit/a9786c599d09f61e2e07df5066ce94feb2d99bac)) +- Login with code on any credential type + ([#3549](https://github.com/ory/kratos/issues/3549)) + ([ceed7d5](https://github.com/ory/kratos/commit/ceed7d5478c5cca894587698c57f676dda100b27)): + + Should be able to login with the `code` credential even if the user did not + register on the `code` credential. Only `identifier` matching is done and + validation based on the identity schema. + - One-time code native flows ([#3516](https://github.com/ory/kratos/issues/3516)) ([9b0fee3](https://github.com/ory/kratos/commit/9b0fee30f980d860fd548e7589fa6a06e593537a)) From 569b14aba864761236bd3d5a48e4e69f10ea6c86 Mon Sep 17 00:00:00 2001 From: Alano Terblanche <18033717+Benehiko@users.noreply.github.com> Date: Thu, 19 Oct 2023 10:28:25 +0200 Subject: [PATCH 150/282] fix: auto migrate old accounts to use code credential (#3581) --- driver/config/config.go | 6 +- driver/config/config_test.go | 18 ++++- selfservice/strategy/code/strategy_login.go | 10 +-- .../strategy/code/strategy_login_test.go | 69 ++++++++++++------- .../code/stub/code.identity.schema.json | 3 + .../password/stub/registration.schema.json | 5 +- .../profiles/code/login/error.spec.ts | 2 +- test/e2e/profiles/code/.kratos.yml | 1 + 8 files changed, 75 insertions(+), 39 deletions(-) diff --git a/driver/config/config.go b/driver/config/config.go index 4fa461dfbc0e..950152f6d088 100644 --- a/driver/config/config.go +++ b/driver/config/config.go @@ -231,8 +231,7 @@ type ( } SelfServiceStrategyCode struct { *SelfServiceStrategy - PasswordlessEnabled bool `json:"passwordless_enabled"` - PasswordlessLoginFallbackEnabled bool `json:"passwordless_login_fallback_enabled"` + PasswordlessEnabled bool `json:"passwordless_enabled"` } Schema struct { ID string `json:"id" koanf:"id"` @@ -764,8 +763,7 @@ func (p *Config) SelfServiceCodeStrategy(ctx context.Context) *SelfServiceStrate Enabled: pp.BoolF(basePath+".enabled", true), Config: config, }, - PasswordlessEnabled: pp.BoolF(basePath+".passwordless_enabled", false), - PasswordlessLoginFallbackEnabled: pp.BoolF(basePath+".passwordless_login_fallback_enabled", false), + PasswordlessEnabled: pp.BoolF(basePath+".passwordless_enabled", false), } } diff --git a/driver/config/config_test.go b/driver/config/config_test.go index 052c6808290f..602a4971a74e 100644 --- a/driver/config/config_test.go +++ b/driver/config/config_test.go @@ -567,7 +567,6 @@ func TestViperProvider_Defaults(t *testing.T) { assert.True(t, p.SelfServiceStrategy(ctx, "code").Enabled) assert.False(t, p.SelfServiceStrategy(ctx, "oidc").Enabled) assert.False(t, p.SelfServiceCodeStrategy(ctx).PasswordlessEnabled) - assert.False(t, p.SelfServiceCodeStrategy(ctx).PasswordlessLoginFallbackEnabled) assert.False(t, p.SelfServiceFlowRecoveryNotifyUnknownRecipients(ctx)) assert.False(t, p.SelfServiceFlowVerificationNotifyUnknownRecipients(ctx)) }) @@ -1092,6 +1091,23 @@ func TestPasswordless(t *testing.T) { assert.False(t, conf.WebAuthnForPasswordless(ctx)) } +func TestPasswordlessCode(t *testing.T) { + t.Parallel() + + ctx := context.Background() + + conf, err := config.New(ctx, logrusx.New("", ""), os.Stderr, + configx.SkipValidation(), + configx.WithValue(config.ViperKeySelfServiceStrategyConfig+".code", map[string]interface{}{ + "passwordless_enabled": true, + "passwordless_login_fallback_enabled": true, + "config": map[string]interface{}{}, + })) + require.NoError(t, err) + + assert.True(t, conf.SelfServiceCodeStrategy(ctx).PasswordlessEnabled) +} + func TestChangeMinPasswordLength(t *testing.T) { t.Parallel() t.Run("case=must fail on minimum password length below enforced minimum", func(t *testing.T) { diff --git a/selfservice/strategy/code/strategy_login.go b/selfservice/strategy/code/strategy_login.go index 297ec75f9c57..e837e6f7756d 100644 --- a/selfservice/strategy/code/strategy_login.go +++ b/selfservice/strategy/code/strategy_login.go @@ -97,14 +97,16 @@ func (s *Strategy) PopulateLoginMethod(r *http.Request, requestedAAL identity.Au } // findIdentityByIdentifier returns the identity and the code credential for the given identifier. -// If the identity does not have a code credential and PasswordlessLoginFallbackEnabled is false, an error is returned. -// If the identity does not have a code credential and PasswordlessLoginFallbackEnabled is true, the identity and no credential are returned. +// If the identity does not have a code credential, it will attempt to find +// the identity through other credentials matching the identifier. +// the fallback mechanism is used for migration purposes of old accounts that do not have a code credential. func (s *Strategy) findIdentityByIdentifier(ctx context.Context, identifier string) (_ *identity.Identity, isFallback bool, err error) { ctx, span := s.deps.Tracer(ctx).Tracer().Start(ctx, "selfservice.strategy.code.strategy.getIdentity") defer otelx.End(span, &err) id, cred, err := s.deps.PrivilegedIdentityPool().FindByCredentialsIdentifier(ctx, s.ID(), identifier) - if errors.Is(err, sqlcon.ErrNoRows) && s.deps.Config().SelfServiceCodeStrategy(ctx).PasswordlessLoginFallbackEnabled { + if errors.Is(err, sqlcon.ErrNoRows) { + // this is a migration for old identities that do not have a code credential // we might be able to do a fallback login since we could not find a credential on this identifier // Case insensitive because we only care about emails. id, err := s.deps.PrivilegedIdentityPool().FindIdentityByCredentialIdentifier(ctx, identifier, false) @@ -274,7 +276,7 @@ func (s *Strategy) loginVerifyCode(ctx context.Context, r *http.Request, f *logi } // the code is correct, if the login happened through a different credential, we need to update the identity - if isFallback && s.deps.Config().SelfServiceCodeStrategy(ctx).PasswordlessLoginFallbackEnabled { + if isFallback { if err := i.SetCredentialsWithConfig( s.ID(), // p.Identifier was normalized prior. diff --git a/selfservice/strategy/code/strategy_login_test.go b/selfservice/strategy/code/strategy_login_test.go index 05f98354ca5c..cda8ef3c05a9 100644 --- a/selfservice/strategy/code/strategy_login_test.go +++ b/selfservice/strategy/code/strategy_login_test.go @@ -12,6 +12,7 @@ import ( "net/url" "testing" + "github.com/ory/x/sqlcon" "github.com/ory/x/stringsx" "github.com/stretchr/testify/assert" @@ -24,6 +25,7 @@ import ( oryClient "github.com/ory/kratos/internal/httpclient" "github.com/ory/kratos/internal/testhelpers" "github.com/ory/kratos/session" + "github.com/ory/kratos/x" "github.com/ory/x/sqlxx" ) @@ -244,17 +246,34 @@ func TestLoginCodeStrategy(t *testing.T) { }, true, nil) }) - t.Run("case=should login without code credential on any existing credential", func(t *testing.T) { + t.Run("case=new identities automatically have login with code", func(t *testing.T) { ctx := context.Background() - conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.passwordless_login_fallback_enabled", true) + conf.MustSet(ctx, config.ViperKeySelfServiceRegistrationEnabled, true) + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".password.enabled", true) - t.Cleanup(func() { - conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.passwordless_login_fallback_enabled", false) - }) + client := testhelpers.NewClientWithCookies(t) + client.Transport = testhelpers.NewTransportWithLogger(http.DefaultTransport, t).RoundTripper + + registrationFlow := testhelpers.InitializeRegistrationFlowViaBrowser(t, client, public, tc.apiType == ApiTypeNative, false, false) + + email := testhelpers.RandomEmail() + + values := testhelpers.SDKFormFieldsToURLValues(registrationFlow.Ui.Nodes) + values.Set("traits.email", email) + values.Set("method", "password") + values.Set("traits.tos", "1") + values.Set("password", x.NewUUID().String()) + + _, resp := testhelpers.RegistrationMakeRequest(t, tc.apiType == ApiTypeNative, tc.apiType == ApiTypeSPA, registrationFlow, client, testhelpers.EncodeFormAsJSON(t, tc.apiType == ApiTypeNative, values)) + require.EqualValues(t, http.StatusOK, resp.StatusCode) + + _, _, err := reg.PrivilegedIdentityPool().FindByCredentialsIdentifier(ctx, identity.CredentialsTypeCodeAuth, email) + require.NoError(t, err, sqlcon.ErrNoRows) s := createLoginFlow(ctx, t, public, tc.apiType, true) + s.identityEmail = email // submit email s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { v.Set("identifier", s.identityEmail) @@ -278,32 +297,32 @@ func TestLoginCodeStrategy(t *testing.T) { assert.Equal(t, identity.ID, cred.IdentityID) }) - t.Run("case=should not login with any credential if not set", func(t *testing.T) { - ctx := context.Background() - - conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.passwordless_login_fallback_enabled", false) - + t.Run("case=old identities should be able to login with code", func(t *testing.T) { + // createLoginFlow uses the persister layer to create the identity + // we pass in `true` to not do automatic code credential creation s := createLoginFlow(ctx, t, public, tc.apiType, true) // submit email s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { v.Set("identifier", s.identityEmail) - }, false, func(t *testing.T, s *state, body string, resp *http.Response) { - if tc.apiType == ApiTypeBrowser { - require.EqualValues(t, http.StatusOK, resp.StatusCode) - require.EqualValues(t, conf.SelfServiceFlowLoginUI(ctx).Path, resp.Request.URL.Path) + }, false, nil) - lf, resp, err := testhelpers.NewSDKCustomClient(public, s.client).FrontendApi.GetLoginFlow(ctx).Id(s.flowID).Execute() - require.NoError(t, err) - require.EqualValues(t, http.StatusOK, resp.StatusCode) - body, err := json.Marshal(lf) - require.NoError(t, err) - assert.Contains(t, gjson.GetBytes(body, "ui.messages.0.text").String(), "account does not exist or has not setup sign in with code") - } else { - require.EqualValues(t, http.StatusBadRequest, resp.StatusCode) - assert.Contains(t, gjson.Get(body, "ui.messages.0.text").String(), "account does not exist or has not setup sign in with code") - } - }) + message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Login to your account") + assert.Contains(t, message.Body, "please login to your account by entering the following code") + + loginCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) + assert.NotEmpty(t, loginCode) + + // submit code + s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { + v.Set("code", loginCode) + }, true, nil) + + // assert that the identity contains a code credential + identity, cred, err := reg.PrivilegedIdentityPool().FindByCredentialsIdentifier(ctx, identity.CredentialsTypeCodeAuth, s.identityEmail) + require.NoError(t, err) + require.NotNil(t, cred) + assert.Equal(t, identity.ID, cred.IdentityID) }) t.Run("case=should not be able to change submitted id on code submit", func(t *testing.T) { diff --git a/selfservice/strategy/code/stub/code.identity.schema.json b/selfservice/strategy/code/stub/code.identity.schema.json index f6907db3d9ed..a7a4e4448442 100644 --- a/selfservice/strategy/code/stub/code.identity.schema.json +++ b/selfservice/strategy/code/stub/code.identity.schema.json @@ -16,6 +16,9 @@ "code": { "identifier": true, "via": "email" + }, + "password": { + "identifier": true } }, "verification": { diff --git a/selfservice/strategy/password/stub/registration.schema.json b/selfservice/strategy/password/stub/registration.schema.json index 2867d732c759..deb697ccd83c 100644 --- a/selfservice/strategy/password/stub/registration.schema.json +++ b/selfservice/strategy/password/stub/registration.schema.json @@ -22,10 +22,7 @@ } } }, - "required": [ - "foobar", - "username" - ] + "required": ["foobar", "username"] } }, "additionalProperties": false diff --git a/test/e2e/cypress/integration/profiles/code/login/error.spec.ts b/test/e2e/cypress/integration/profiles/code/login/error.spec.ts index 4541d92eca49..95c65c425512 100644 --- a/test/e2e/cypress/integration/profiles/code/login/error.spec.ts +++ b/test/e2e/cypress/integration/profiles/code/login/error.spec.ts @@ -1,7 +1,7 @@ // Copyright © 2023 Ory Corp // SPDX-License-Identifier: Apache-2.0 -import { appPrefix, APP_URL, gen, MOBILE_URL } from "../../../../helpers" +import { gen, MOBILE_URL } from "../../../../helpers" import { routes as express } from "../../../../helpers/express" import { routes as react } from "../../../../helpers/react" diff --git a/test/e2e/profiles/code/.kratos.yml b/test/e2e/profiles/code/.kratos.yml index 2d1e3457e8f0..58f050aa83e9 100644 --- a/test/e2e/profiles/code/.kratos.yml +++ b/test/e2e/profiles/code/.kratos.yml @@ -36,6 +36,7 @@ selfservice: enabled: true code: passwordless_enabled: true + passwordless_login_fallback_enabled: false enabled: true config: lifespan: 1h From 7b633794af5c2dbffcbe118fbde91a4fe32af507 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Thu, 19 Oct 2023 09:46:18 +0000 Subject: [PATCH 151/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e41661115f3..0fbd63775a73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-10-16)](#2023-10-16) +- [ (2023-10-19)](#2023-10-19) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -313,7 +313,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-10-16) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-10-19) ## Breaking Changes @@ -392,6 +392,9 @@ https://github.com/ory/kratos/pull/3480 ([22f61f0](https://github.com/ory/kratos/commit/22f61f015495c55e58db4f31ee6882444b9a3caf)) - Always return relative URLs in the Link header for pagination ([fb229c9](https://github.com/ory/kratos/commit/fb229c982c6f7d7a4f5f0f84ffc971a576906160)) +- Auto migrate old accounts to use code credential + ([#3581](https://github.com/ory/kratos/issues/3581)) + ([569b14a](https://github.com/ory/kratos/commit/569b14aba864761236bd3d5a48e4e69f10ea6c86)) - Carry `oauth2_login_challenge` over to registration flow ([#3419](https://github.com/ory/kratos/issues/3419)) ([76241be](https://github.com/ory/kratos/commit/76241bee3dc7fec4690346ee85bc4b9f897fdd34)): From c5b4aaa2df5d010b62a99ccf45850583daad3a66 Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Thu, 19 Oct 2023 12:31:23 +0200 Subject: [PATCH 152/282] fix: add max-age to default cors headers (#3584) --- embedx/config.schema.json | 5 ++++- test/e2e/playwright/setup/default_config.ts | 9 ++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/embedx/config.schema.json b/embedx/config.schema.json index 15b6c8c38b4a..03898eec012b 100644 --- a/embedx/config.schema.json +++ b/embedx/config.schema.json @@ -2120,7 +2120,10 @@ "default": [ "Authorization", "Content-Type", - "X-Session-Token" + "Max-Age", + "X-Session-Token", + "X-XSRF-TOKEN", + "X-CSRF-TOKEN" ], "items": { "type": "string" diff --git a/test/e2e/playwright/setup/default_config.ts b/test/e2e/playwright/setup/default_config.ts index 6cb3466b479c..6437383f9638 100644 --- a/test/e2e/playwright/setup/default_config.ts +++ b/test/e2e/playwright/setup/default_config.ts @@ -19,7 +19,14 @@ export const default_config: OryKratosConfiguration = { cors: { enabled: true, allowed_origins: ["http://localhost:3000", "http://localhost:19006"], - allowed_headers: ["Authorization", "Content-Type", "X-Session-Token"], + allowed_headers: [ + "Authorization", + "Content-Type", + "Max-Age", + "X-Session-Token", + "X-XSRF-TOKEN", + "X-CSRF-TOKEN", + ], }, }, }, From afed81d6e75f3d5c7060d0938bff9eb528b11215 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Thu, 19 Oct 2023 11:49:41 +0000 Subject: [PATCH 153/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fbd63775a73..636f28017155 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -371,6 +371,9 @@ https://github.com/ory/kratos/pull/3480 Part of https://github.com/ory/network/issues/320 +- Add max-age to default cors headers + ([#3584](https://github.com/ory/kratos/issues/3584)) + ([c5b4aaa](https://github.com/ory/kratos/commit/c5b4aaa2df5d010b62a99ccf45850583daad3a66)) - Add missing tracing & attributes in oidc strategy ([#3429](https://github.com/ory/kratos/issues/3429)) ([09bcb71](https://github.com/ory/kratos/commit/09bcb71f1f0b3238e2d0f4376a1a2290d062c6c1)) From 31faa2b6cbdeb3008d0c0c9a1e7a8691fe06437c Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Wed, 27 Sep 2023 15:36:17 +0200 Subject: [PATCH 154/282] chore: bump to Go 1.21 --- .github/workflows/ci.yaml | 6 +++--- .github/workflows/format.yml | 2 +- .github/workflows/licenses.yml | 2 +- go.mod | 6 ++---- go.sum | 28 ++++++++++++++++++++++++---- test/e2e/.go-version | 2 +- test/e2e/mock/webhook/Dockerfile | 2 +- 7 files changed, 33 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 11b0dddfae49..d03794b582e1 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -77,7 +77,7 @@ jobs: fetch-depth: 2 - uses: actions/setup-go@v4 with: - go-version: "1.19" + go-version: "1.21" - run: go list -json > go.list - name: Run nancy uses: sonatype-nexus-community/nancy-github-action@v1.0.2 @@ -169,7 +169,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v4 with: - go-version: "1.19" + go-version: "1.21" - name: Install selfservice-ui-react-native uses: actions/checkout@v3 @@ -272,7 +272,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v4 with: - go-version: "1.19" + go-version: "1.21" - run: go build -tags sqlite,json1 . - name: Install selfservice-ui-react-native diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index a7a720ebc0a7..b59c85d31b22 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -11,7 +11,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: - go-version: 1.19 + go-version: "1.21" - run: make format - name: Indicate formatting issues run: git diff HEAD --exit-code --color diff --git a/.github/workflows/licenses.yml b/.github/workflows/licenses.yml index a4592c63ceda..8871ccb2c542 100644 --- a/.github/workflows/licenses.yml +++ b/.github/workflows/licenses.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-go@v2 with: - go-version: "1.18" + go-version: "1.21" - uses: actions/setup-node@v2 with: node-version: "18" diff --git a/go.mod b/go.mod index 1b52289fb58f..ddb4cbf0ae79 100644 --- a/go.mod +++ b/go.mod @@ -1,14 +1,12 @@ module github.com/ory/kratos -go 1.19 +go 1.21 replace ( - github.com/bradleyjkemp/cupaloy/v2 => github.com/aeneasr/cupaloy/v2 v2.6.1-0.20210924214125-3dfdd01210a3 - github.com/go-sql-driver/mysql => github.com/go-sql-driver/mysql v1.7.2-0.20231005084435-37980127edfb github.com/gorilla/sessions => github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2 - github.com/mattn/go-sqlite3 => github.com/mattn/go-sqlite3 v1.14.7-0.20210414154423-1157a4212dcb + github.com/mattn/go-sqlite3 => github.com/mattn/go-sqlite3 v1.14.16 // Use the internal httpclient which can be generated in this codebase but mark it as the // official SDK, allowing for the Ory CLI to consume Ory Kratos' CLI commands. diff --git a/go.sum b/go.sum index 76c7ba81b427..1b8575a549a3 100644 --- a/go.sum +++ b/go.sum @@ -59,8 +59,6 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/a8m/envsubst v1.3.0 h1:GmXKmVssap0YtlU3E230W98RWtWCyIZzjtf1apWWyAg= github.com/a8m/envsubst v1.3.0/go.mod h1:MVUTQNGQ3tsjOOtKCNd+fl8RzhsXcDvvAEzkhGtlsbY= -github.com/aeneasr/cupaloy/v2 v2.6.1-0.20210924214125-3dfdd01210a3 h1:/SkiUr3JJzun9QN9cpUVCPri2ZwOFJ3ani+F3vdoCiY= -github.com/aeneasr/cupaloy/v2 v2.6.1-0.20210924214125-3dfdd01210a3/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -99,6 +97,8 @@ github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dR github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oMMlVBbn9M= +github.com/bradleyjkemp/cupaloy/v2 v2.8.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0= github.com/bwmarrin/discordgo v0.23.0 h1://ARp8qUrRZvDGMkfAjtcC20WOvsMtTgi+KrdKnl6eY= github.com/bwmarrin/discordgo v0.23.0/go.mod h1:c1WtWUGN6nREDmzIpyTp/iD3VYt4Fpx+bVyfBG7JE+M= github.com/bxcodec/faker/v3 v3.3.1 h1:G7uldFk+iO/ES7W4v7JlI/WU9FQ6op9VJ15YZlDEhGQ= @@ -206,6 +206,7 @@ github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBd github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= @@ -291,6 +292,7 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-swagger/go-swagger v0.30.5 h1:SQ2+xSonWjjoEMOV5tcOnZJVlfyUfCBhGQGArS1b9+U= github.com/go-swagger/go-swagger v0.30.5/go.mod h1:cWUhSyCNqV7J1wkkxfr5QmbcnCewetCdvEXqgPvbc/Q= github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013 h1:l9rI6sNaZgNC0LnF3MiE+qTmyBA/tZAg1rtyrGbUMK0= +github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013/go.mod h1:b65mBPzqzZWxOZGxSWrqs4GInLIn+u99Q9q7p+GKni0= github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-webauthn/webauthn v0.8.4 h1:/emQ9b9Rj4flWO94Fo8KJeYvZ6VzPywXsmqyDA/WicY= @@ -327,6 +329,7 @@ github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+ github.com/gobuffalo/helpers v0.6.7 h1:C9CedoRSfgWg2ZoIkVXgjI5kgmSpL34Z3qdnzpfNVd8= github.com/gobuffalo/helpers v0.6.7/go.mod h1:j0u1iC1VqlCaJEEVkZN8Ia3TEzfj/zoXANqyJExTMTA= github.com/gobuffalo/here v0.6.7 h1:hpfhh+kt2y9JLDfhYUxxCRxQol540jsVfKUZzjlbp8o= +github.com/gobuffalo/here v0.6.7/go.mod h1:vuCfanjqckTuRlqAitJz6QC4ABNnS27wLb816UhsPcc= github.com/gobuffalo/httptest v1.5.2 h1:GpGy520SfY1QEmyPvaqmznTpG4gEQqQ82HtHqyNEreM= github.com/gobuffalo/httptest v1.5.2/go.mod h1:FA23yjsWLGj92mVV74Qtc8eqluc11VqcWr8/C1vxt4g= github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= @@ -424,6 +427,7 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github/v27 v27.0.1 h1:sSMFSShNn4VnqCqs+qhab6TS3uQc+uVR6TD1bW6MavM= github.com/google/go-github/v27 v27.0.1/go.mod h1:/0Gr8pJ55COkmv+S/yPKCczSkUPIM/LnFyubufRNIS0= github.com/google/go-github/v38 v38.1.0 h1:C6h1FkaITcBFK7gAmq4eFzt6gbhEhk7L5z6R3Uva+po= @@ -490,8 +494,10 @@ github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69/go.mod h1:YLEMZO github.com/hashicorp/consul/api v1.20.0 h1:9IHTjNVSZ7MIwjlW3N3a7iGiykCMDpxZu8jsxFJh0yc= github.com/hashicorp/consul/api v1.20.0/go.mod h1:nR64eD44KQ59Of/ECwt2vUmIK2DKsDzAwTmwmLl8Wpo= github.com/hashicorp/consul/sdk v0.13.1 h1:EygWVWWMczTzXGpO93awkHFzfUka6hLYJ0qhETd+6lY= +github.com/hashicorp/consul/sdk v0.13.1/go.mod h1:SW/mM4LbKfqmMvcFu8v+eiQQ7oitXEFeiBe9StxERb0= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= @@ -506,6 +512,7 @@ github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iP github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0= github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= @@ -513,11 +520,14 @@ github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5O github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= +github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= @@ -658,6 +668,7 @@ github.com/knadh/koanf/parsers/yaml v0.1.0/go.mod h1:cvbUDC7AL23pImuQP0oRw/hPucc github.com/knadh/koanf/providers/posflag v0.1.0 h1:mKJlLrKPcAP7Ootf4pBZWJ6J+4wHYujwipe7Ie3qW6U= github.com/knadh/koanf/providers/posflag v0.1.0/go.mod h1:SYg03v/t8ISBNrMBRMlojH8OsKowbkXV7giIbBVgbz0= github.com/knadh/koanf/providers/rawbytes v0.1.0 h1:dpzgu2KO6uf6oCb4aP05KDmKmAmI51k5pe8RYKQ0qME= +github.com/knadh/koanf/providers/rawbytes v0.1.0/go.mod h1:mMTB1/IcJ/yE++A2iEZbY1MLygX7vttU+C+S/YmPu9c= github.com/knadh/koanf/v2 v2.0.1 h1:1dYGITt1I23x8cfx8ZnldtezdyaZtfAuRtIFOiRzK7g= github.com/knadh/koanf/v2 v2.0.1/go.mod h1:ZeiIlIDXTE7w1lMT6UVcNiRAS2/rCeLn/GdLNvY1Dus= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -726,6 +737,7 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= github.com/markbates/pkger v0.17.1 h1:/MKEtWqtc0mZvu9OinB9UzVN9iYCwLWuyUv4Bw+PCno= +github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= @@ -747,8 +759,8 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-sqlite3 v1.14.7-0.20210414154423-1157a4212dcb h1:ax2vG2unlxsjwS7PMRo4FECIfAdQLowd6ejWYwPQhBo= -github.com/mattn/go-sqlite3 v1.14.7-0.20210414154423-1157a4212dcb/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mattn/goveralls v0.0.7 h1:vzy0i4a2iDzEFMdXIxcanRadkr0FBvSBKUmj0P8SPlQ= github.com/mattn/goveralls v0.0.7/go.mod h1:h8b4ow6FxSPMQHF6o2ve3qsclnffZjYTNEKmLesRwqw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -789,11 +801,13 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwd github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/nyaruka/phonenumbers v1.1.6 h1:DcueYq7QrOArAprAYNoQfDgp0KetO4LqtnBtQC6Wyes= github.com/nyaruka/phonenumbers v1.1.6/go.mod h1:yShPJHDSH3aTKzCbXyVxNpbl2kA+F+Ne5Pun/MvFRos= github.com/ogier/pflag v0.0.1 h1:RW6JSWSu/RkSatfcLtogGfFgpim5p7ARQ10ECk5O750= @@ -803,9 +817,11 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c= +github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= @@ -1103,6 +1119,7 @@ go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= @@ -1389,6 +1406,7 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= +golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -1561,6 +1579,7 @@ google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ5 google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= google.golang.org/grpc/examples v0.0.0-20210304020650-930c79186c99 h1:qA8rMbz1wQ4DOFfM2ouD29DG9aHWBm6ZOy9BGxiUMmY= +google.golang.org/grpc/examples v0.0.0-20210304020650-930c79186c99/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= 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= @@ -1625,6 +1644,7 @@ gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= gorm.io/gorm v1.23.5/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.2.0 h1:I0DwBVMGAx26dttAj1BtJLAkVGncrkkUXfJLC4Flt/I= +gotest.tools/v3 v3.2.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A= 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= diff --git a/test/e2e/.go-version b/test/e2e/.go-version index 6681c8c19ab4..2844977405c2 100644 --- a/test/e2e/.go-version +++ b/test/e2e/.go-version @@ -1 +1 @@ -1.19.8 +1.21.1 diff --git a/test/e2e/mock/webhook/Dockerfile b/test/e2e/mock/webhook/Dockerfile index 1806cdf396e9..91faa9b4b778 100644 --- a/test/e2e/mock/webhook/Dockerfile +++ b/test/e2e/mock/webhook/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.19-alpine AS build +FROM golang:1.21-alpine AS build WORKDIR /build From e1fb8bfe06f59e212c4780b702d8e90a39355134 Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Wed, 4 Oct 2023 13:02:45 +0200 Subject: [PATCH 155/282] chore: move test helpers from package x to package testhelpers --- continuity/manager_test.go | 38 ++--- go.mod | 56 +++---- go.sum | 144 +++++++----------- internal/testhelpers/http.go | 38 +++++ internal/testhelpers/identity.go | 4 +- .../testhelpers/selfservice_verification.go | 2 +- internal/testhelpers/session.go | 38 ++++- selfservice/flow/login/handler_test.go | 51 ++++--- selfservice/flow/recovery/handler_test.go | 24 +-- selfservice/flow/registration/handler_test.go | 31 ++-- selfservice/flow/registration/hook_test.go | 2 +- selfservice/flow/settings/handler_test.go | 6 +- selfservice/flow/verification/handler_test.go | 22 +-- .../strategy/link/strategy_recovery_test.go | 2 +- selfservice/strategy/password/login_test.go | 56 +++---- session/handler_test.go | 7 +- session/manager_http_test.go | 24 +-- session/session_test.go | 17 +-- x/http.go | 79 ---------- 19 files changed, 303 insertions(+), 338 deletions(-) diff --git a/continuity/manager_test.go b/continuity/manager_test.go index 8bfad92d6815..6790137faa80 100644 --- a/continuity/manager_test.go +++ b/continuity/manager_test.go @@ -53,7 +53,7 @@ func TestManager(t *testing.T) { i := identity.NewIdentity("") require.NoError(t, reg.PrivilegedIdentityPool().CreateIdentity(context.Background(), i)) - var newServer = func(t *testing.T, p continuity.Manager, tc *persisterTestCase) *httptest.Server { + newServer := func(t *testing.T, p continuity.Manager, tc *persisterTestCase) *httptest.Server { writer := herodot.NewJSONWriter(logrusx.New("", "")) router := httprouter.New() router.PUT("/:name", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { @@ -103,8 +103,8 @@ func TestManager(t *testing.T) { return ts } - var newClient = func() *http.Client { - return &http.Client{Jar: x.EasyCookieJar(t, nil)} + newClient := func() *http.Client { + return &http.Client{Jar: testhelpers.EasyCookieJar(t, nil)} } p := reg.ContinuityManager() @@ -114,12 +114,12 @@ func TestManager(t *testing.T) { ts := newServer(t, p, new(persisterTestCase)) href := ts.URL + "/" + x.NewUUID().String() - res, err := cl.Do(x.NewTestHTTPRequest(t, "PUT", href, nil)) + res, err := cl.Do(testhelpers.NewTestHTTPRequest(t, "PUT", href, nil)) require.NoError(t, err) require.NoError(t, res.Body.Close()) require.Equal(t, http.StatusNoContent, res.StatusCode) - req := x.NewTestHTTPRequest(t, "GET", href, nil) + req := testhelpers.NewTestHTTPRequest(t, "GET", href, nil) require.Len(t, res.Cookies(), 1) for _, c := range res.Cookies() { // Change something in the string @@ -143,21 +143,21 @@ func TestManager(t *testing.T) { ts := newServer(t, p, tc) href := ts.URL + "/" + x.NewUUID().String() - res, err := http.DefaultClient.Do(x.NewTestHTTPRequest(t, "PUT", href, nil)) + res, err := http.DefaultClient.Do(testhelpers.NewTestHTTPRequest(t, "PUT", href, nil)) require.NoError(t, err) require.NoError(t, res.Body.Close()) require.Equal(t, http.StatusNoContent, res.StatusCode) // We change the key to another one href = ts.URL + "/" + x.NewUUID().String() - req := x.NewTestHTTPRequest(t, "GET", href, nil) + req := testhelpers.NewTestHTTPRequest(t, "GET", href, nil) require.Len(t, res.Cookies(), 1) for _, c := range res.Cookies() { req.AddCookie(c) } tc.ro = []continuity.ManagerOption{continuity.WithPayload(&persisterTestPayload{"bar"})} - res, err = http.DefaultClient.Do(x.NewTestHTTPRequest(t, "PUT", href, nil)) + res, err = http.DefaultClient.Do(testhelpers.NewTestHTTPRequest(t, "PUT", href, nil)) require.NoError(t, err) require.NoError(t, res.Body.Close()) require.Equal(t, http.StatusNoContent, res.StatusCode) @@ -196,13 +196,13 @@ func TestManager(t *testing.T) { t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { cl := newClient() ts := newServer(t, p, &tc) - var genid = func() string { + genid := func() string { return ts.URL + "/" + x.NewUUID().String() } t.Run("case=resume non-existing session", func(t *testing.T) { href := genid() - res, err := cl.Do(x.NewTestHTTPRequest(t, "GET", href, nil)) + res, err := cl.Do(testhelpers.NewTestHTTPRequest(t, "GET", href, nil)) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, res.Body.Close()) }) @@ -213,12 +213,12 @@ func TestManager(t *testing.T) { t.Run("case=pause and resume session", func(t *testing.T) { href := genid() - res, err := cl.Do(x.NewTestHTTPRequest(t, "PUT", href, nil)) + res, err := cl.Do(testhelpers.NewTestHTTPRequest(t, "PUT", href, nil)) require.NoError(t, err) require.NoError(t, res.Body.Close()) require.Equal(t, http.StatusNoContent, res.StatusCode) - res, err = cl.Do(x.NewTestHTTPRequest(t, "GET", href, nil)) + res, err = cl.Do(testhelpers.NewTestHTTPRequest(t, "GET", href, nil)) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, res.Body.Close()) }) @@ -238,16 +238,16 @@ func TestManager(t *testing.T) { t.Run("case=pause and retry session", func(t *testing.T) { href := genid() - res, err := cl.Do(x.NewTestHTTPRequest(t, "PUT", href, nil)) + res, err := cl.Do(testhelpers.NewTestHTTPRequest(t, "PUT", href, nil)) require.NoError(t, err) require.NoError(t, res.Body.Close()) require.Equal(t, http.StatusNoContent, res.StatusCode) - res, err = cl.Do(x.NewTestHTTPRequest(t, "GET", href, nil)) + res, err = cl.Do(testhelpers.NewTestHTTPRequest(t, "GET", href, nil)) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, res.Body.Close()) }) - res, err = cl.Do(x.NewTestHTTPRequest(t, "GET", href, nil)) + res, err = cl.Do(testhelpers.NewTestHTTPRequest(t, "GET", href, nil)) require.NoError(t, err) require.Equal(t, http.StatusBadRequest, res.StatusCode) body := ioutilx.MustReadAll(res.Body) @@ -257,7 +257,7 @@ func TestManager(t *testing.T) { t.Run("case=pause and resume session in the same request", func(t *testing.T) { href := genid() - res, err := cl.Do(x.NewTestHTTPRequest(t, "POST", href, nil)) + res, err := cl.Do(testhelpers.NewTestHTTPRequest(t, "POST", href, nil)) require.NoError(t, err) require.Equal(t, http.StatusOK, res.StatusCode) t.Cleanup(func() { require.NoError(t, res.Body.Close()) }) @@ -272,17 +272,17 @@ func TestManager(t *testing.T) { t.Run("case=pause, abort, and continue session with failure", func(t *testing.T) { href := genid() - res, err := cl.Do(x.NewTestHTTPRequest(t, "PUT", href, nil)) + res, err := cl.Do(testhelpers.NewTestHTTPRequest(t, "PUT", href, nil)) require.NoError(t, err) require.NoError(t, res.Body.Close()) require.Equal(t, http.StatusNoContent, res.StatusCode) - res, err = cl.Do(x.NewTestHTTPRequest(t, "DELETE", href, nil)) + res, err = cl.Do(testhelpers.NewTestHTTPRequest(t, "DELETE", href, nil)) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, res.Body.Close()) }) require.Equal(t, http.StatusNoContent, res.StatusCode) - res, err = cl.Do(x.NewTestHTTPRequest(t, "GET", href, nil)) + res, err = cl.Do(testhelpers.NewTestHTTPRequest(t, "GET", href, nil)) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, res.Body.Close()) }) diff --git a/go.mod b/go.mod index ddb4cbf0ae79..2faa0b8e604e 100644 --- a/go.mod +++ b/go.mod @@ -93,19 +93,21 @@ require ( github.com/tidwall/sjson v1.2.5 github.com/urfave/negroni v1.0.0 github.com/zmb3/spotify/v2 v2.0.0 - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.4 - go.opentelemetry.io/otel v1.14.0 - go.opentelemetry.io/otel/trace v1.14.0 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 + go.opentelemetry.io/otel v1.19.0 + go.opentelemetry.io/otel/trace v1.19.0 golang.org/x/crypto v0.14.0 golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 golang.org/x/net v0.17.0 - golang.org/x/oauth2 v0.11.0 - golang.org/x/sync v0.2.0 + golang.org/x/oauth2 v0.12.0 + golang.org/x/sync v0.3.0 golang.org/x/text v0.13.0 golang.org/x/tools/cmd/cover v0.1.0-deprecated - google.golang.org/grpc v1.55.0 + google.golang.org/grpc v1.59.0 ) +require go.opentelemetry.io/otel/sdk v1.19.0 + require ( github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Masterminds/goutils v1.1.1 // indirect @@ -123,7 +125,7 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/bmatcuk/doublestar v1.3.4 // indirect github.com/boombuler/barcode v1.0.1 // indirect - github.com/cenkalti/backoff/v4 v4.2.0 // indirect + github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cockroachdb/cockroach-go/v2 v2.2.16 // indirect github.com/containerd/continuity v0.3.0 // indirect @@ -145,7 +147,7 @@ require ( github.com/fxamacker/cbor/v2 v2.4.0 // indirect github.com/go-crypt/x v0.2.1 // indirect github.com/go-jose/go-jose/v3 v3.0.0 // indirect - github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/analysis v0.21.4 // indirect github.com/go-openapi/errors v0.20.4 // indirect @@ -174,14 +176,14 @@ require ( github.com/goccy/go-yaml v1.9.6 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/glog v1.1.0 // indirect + github.com/golang/glog v1.1.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/btree v1.0.1 // indirect github.com/google/go-querystring v1.0.0 // indirect github.com/google/go-tpm v0.9.0 // indirect github.com/google/pprof v0.0.0-20221010195024-131d412537ea // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect - github.com/google/uuid v1.3.0 // indirect + github.com/google/uuid v1.3.1 // indirect github.com/gorilla/context v1.1.1 // indirect github.com/gorilla/css v1.0.0 // indirect github.com/gorilla/handlers v1.5.1 // indirect @@ -190,7 +192,7 @@ require ( github.com/gorilla/securecookie v1.1.1 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.12.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-hclog v1.2.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect @@ -256,7 +258,7 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc2 // indirect github.com/opencontainers/runc v1.1.5 // indirect - github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/openzipkin/zipkin-go v0.4.2 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/philhofer/fwd v1.1.2 // indirect @@ -268,7 +270,7 @@ require ( github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect github.com/rjeczalik/notify v0.0.0-20181126183243-629144ba06a1 // indirect - github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/seatgeek/logrus-gelf-formatter v0.0.0-20210414080842-5b05eb8ff761 // indirect github.com/segmentio/backo-go v1.0.1 // indirect github.com/sergi/go-diff v1.2.0 // indirect @@ -295,27 +297,25 @@ require ( github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect go.mongodb.org/mongo-driver v1.11.3 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.36.4 // indirect - go.opentelemetry.io/contrib/propagators/b3 v1.11.1 // indirect - go.opentelemetry.io/contrib/propagators/jaeger v1.11.1 // indirect - go.opentelemetry.io/contrib/samplers/jaegerremote v0.5.2 // indirect - go.opentelemetry.io/otel/exporters/jaeger v1.11.1 // indirect - go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 // indirect; / indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.14.0 // indirect; / indirect - go.opentelemetry.io/otel/exporters/zipkin v1.14.0 // indirect; / indirect - go.opentelemetry.io/otel/metric v0.33.0 // indirect - go.opentelemetry.io/otel/sdk v1.14.0 // indirect - go.opentelemetry.io/proto/otlp v0.19.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.45.0 // indirect + go.opentelemetry.io/contrib/propagators/b3 v1.20.0 // indirect + go.opentelemetry.io/contrib/propagators/jaeger v1.20.0 // indirect + go.opentelemetry.io/contrib/samplers/jaegerremote v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect; / indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 // indirect; / indirect + go.opentelemetry.io/otel/exporters/zipkin v1.19.0 // indirect; / indirect + go.opentelemetry.io/otel/metric v1.19.0 // indirect + go.opentelemetry.io/proto/otlp v1.0.0 // indirect golang.org/x/mod v0.10.0 // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/term v0.13.0 // indirect golang.org/x/tools v0.9.3 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect + google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect diff --git a/go.sum b/go.sum index 1b8575a549a3..60177cd8b6ce 100644 --- a/go.sum +++ b/go.sum @@ -54,7 +54,6 @@ github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2y github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= 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.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/a8m/envsubst v1.3.0 h1:GmXKmVssap0YtlU3E230W98RWtWCyIZzjtf1apWWyAg= @@ -67,7 +66,6 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15 h1:AUNCr9CiJuwrRYS3XieqF+Z9B9gNxo/eANAJCF2eiN4= github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= @@ -105,10 +103,9 @@ github.com/bxcodec/faker/v3 v3.3.1 h1:G7uldFk+iO/ES7W4v7JlI/WU9FQ6op9VJ15YZlDEhG github.com/bxcodec/faker/v3 v3.3.1/go.mod h1:gF31YgnMSMKgkvl+fyEo1xuSMbEuieyqfeslGYFjneM= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4= -github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= +github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= @@ -124,11 +121,6 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/cockroach-go/v2 v2.2.16 h1:t9dmZuC9J2W8IDQDSIGXmP+fBuEJSsrGXxWQz4cYqBY= @@ -186,8 +178,6 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= @@ -234,8 +224,8 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= @@ -377,9 +367,8 @@ github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVI github.com/golang/gddo v0.0.0-20190904175337-72a348e765d2 h1:xisWqjiKEff2B0KfFYGpCqc3M3zdTz+OHQHRc09FeYk= 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/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= -github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= -github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= +github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= +github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= 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= @@ -460,8 +449,8 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaU github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.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/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= @@ -485,10 +474,8 @@ github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWm github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.12.0 h1:kr3j8iIMR4ywO/O0rvksXaJvauGGCMg2zAZIiNZ9uIQ= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.12.0/go.mod h1:ummNFgdgLhhX7aIiy35vVmQNS0rWXknfPE0qe6fmFXg= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 h1:RtRsiaGvWxcwd8y3BiRZxsylPT8hLWZ5SPcfI+3IDNk= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0/go.mod h1:TzP6duP4Py2pHLVPPQp42aoYI92+PCrVotyR5e8Vqlk= github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69 h1:7xsUJsB2NrdcttQPa7JLEaGzvdbk7KvfrjgHZXOQRo0= github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69/go.mod h1:YLEMZOtU+AZ7dhN9T/IpGhXVGly2bvkJQ+zxj3WeVQo= github.com/hashicorp/consul/api v1.20.0 h1:9IHTjNVSZ7MIwjlW3N3a7iGiykCMDpxZu8jsxFJh0yc= @@ -540,6 +527,7 @@ github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= @@ -806,8 +794,6 @@ github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/nyaruka/phonenumbers v1.1.6 h1:DcueYq7QrOArAprAYNoQfDgp0KetO4LqtnBtQC6Wyes= github.com/nyaruka/phonenumbers v1.1.6/go.mod h1:yShPJHDSH3aTKzCbXyVxNpbl2kA+F+Ne5Pun/MvFRos= github.com/ogier/pflag v0.0.1 h1:RW6JSWSu/RkSatfcLtogGfFgpim5p7ARQ10ECk5O750= @@ -815,13 +801,12 @@ github.com/ogier/pflag v0.0.1/go.mod h1:zkFki7tvTa0tafRvTBIZTvzYyAu6kQhPZFnshFFP github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU= github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= -github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c= -github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= @@ -830,8 +815,8 @@ github.com/opencontainers/runc v1.1.5 h1:L44KXEpKmfWDcS02aeGm8QNTFXTo2D+8MYGDIJ/ github.com/opencontainers/runc v1.1.5/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= -github.com/openzipkin/zipkin-go v0.4.1 h1:kNd/ST2yLLWhaWrkgchya40TJabe8Hioj9udfPcEO5A= -github.com/openzipkin/zipkin-go v0.4.1/go.mod h1:qY0VqDSN1pOBN94dBc6w2GJlWLiovAyg7Qt6/I9HecM= +github.com/openzipkin/zipkin-go v0.4.2 h1:zjqfqHjUpPmB3c1GlCvvgsM1G4LkvqQbBDueDOCg/jA= +github.com/openzipkin/zipkin-go v0.4.2/go.mod h1:ZeVkFjuuBiSy13y8vpSDCjMi9GoI3hPpCJSBx/EYFhY= github.com/ory/analytics-go/v5 v5.0.1 h1:LX8T5B9FN8KZXOtxgN+R3I4THRRVB6+28IKgKBpXmAM= github.com/ory/analytics-go/v5 v5.0.1/go.mod h1:lWCiCjAaJkKfgR/BN5DCLMol8BjKS1x+4jxBxff/FF0= github.com/ory/dockertest/v3 v3.9.1 h1:v4dkG+dlu76goxMiTT2j8zV7s4oPPEppKT8K8p2f1kY= @@ -920,14 +905,14 @@ github.com/rakutentech/jwk-go v1.1.3 h1:PiLwepKyUaW+QFG3ki78DIO2+b4IVK3nMhlxM70z github.com/rakutentech/jwk-go v1.1.3/go.mod h1:LtzSv4/+Iti1nnNeVQiP6l5cI74GBStbhyXCYvgPZFk= github.com/rjeczalik/notify v0.0.0-20181126183243-629144ba06a1 h1:FLWDC+iIP9BWgYKvWKKtOUZux35LIQNAuIzp/63RQJU= github.com/rjeczalik/notify v0.0.0-20181126183243-629144ba06a1/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= 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.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= @@ -979,7 +964,6 @@ github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d h1:yKm7XZV6j9 github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e h1:qpG93cPwA5f7s/ZPBJnGOYQNK/vKsaDaseuKT5Asee8= 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.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= @@ -1083,37 +1067,34 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.36.4 h1:toN8e0U4RWQL4f8H+1eFtaeWe/IkSM3+81qJEDOgShs= -go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.36.4/go.mod h1:u4OeI4ujQmFbpZOOysLUfYrRWOmEVmvzkM2zExVorXM= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.4 h1:aUEBEdCa6iamGzg6fuYxDA8ThxvOG240mAvWDU+XLio= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.4/go.mod h1:l2MdsbKTocpPS5nQZscqTR9jd8u96VYZdcpF8Sye7mA= -go.opentelemetry.io/contrib/propagators/b3 v1.11.1 h1:icQ6ttRV+r/2fnU46BIo/g/mPu6Rs5Ug8Rtohe3KqzI= -go.opentelemetry.io/contrib/propagators/b3 v1.11.1/go.mod h1:ECIveyMXgnl4gorxFcA7RYjJY/Ql9n20ubhbfDc3QfA= -go.opentelemetry.io/contrib/propagators/jaeger v1.11.1 h1:Gw+P9NQzw4bjNGZXsoDhwwDWLnk4Y1waF8MQZAq/eYM= -go.opentelemetry.io/contrib/propagators/jaeger v1.11.1/go.mod h1:dP/N3ZFADH8azBcZfGXEFNBXpEmPTXYcNj9rkw1+2Oc= -go.opentelemetry.io/contrib/samplers/jaegerremote v0.5.2 h1:Izp9RqrioK/y7J/RXy2c7zd83iKQ4N3td3AMNKNzHiI= -go.opentelemetry.io/contrib/samplers/jaegerremote v0.5.2/go.mod h1:Z0aRlRERn9v/3J2K+ATa6ffKyb8/i+/My/gTzFr3dII= -go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM= -go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU= -go.opentelemetry.io/otel/exporters/jaeger v1.11.1 h1:F9Io8lqWdGyIbY3/SOGki34LX/l+7OL0gXNxjqwcbuQ= -go.opentelemetry.io/otel/exporters/jaeger v1.11.1/go.mod h1:lRa2w3bQ4R4QN6zYsDgy7tEezgoKEu7Ow2g35Y75+KI= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 h1:/fXHZHGvro6MVqV34fJzDhi7sHGpX3Ej/Qjmfn003ho= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0/go.mod h1:UFG7EBMRdXyFstOwH028U0sVf+AvukSGhF0g8+dmNG8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 h1:TKf2uAs2ueguzLaxOCBXNpHxfO/aC7PAdDsSH0IbeRQ= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0/go.mod h1:HrbCVv40OOLTABmOn1ZWty6CHXkU8DK/Urc43tHug70= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.14.0 h1:3jAYbRHQAqzLjd9I4tzxwJ8Pk/N6AqBcF6m1ZHrxG94= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.14.0/go.mod h1:+N7zNjIJv4K+DeX67XXET0P+eIciESgaFDBqh+ZJFS4= -go.opentelemetry.io/otel/exporters/zipkin v1.14.0 h1:reEVE1upBF9tcujgvSqLJS0SrI7JQPaTKP4s4rymnSs= -go.opentelemetry.io/otel/exporters/zipkin v1.14.0/go.mod h1:RcjvOAcvhzcufQP8aHmzRw1gE9g/VEZufDdo2w+s4sk= -go.opentelemetry.io/otel/metric v0.33.0 h1:xQAyl7uGEYvrLAiV/09iTJlp1pZnQ9Wl793qbVvED1E= -go.opentelemetry.io/otel/metric v0.33.0/go.mod h1:QlTYc+EnYNq/M2mNk1qDDMRLpqCOj2f/r5c7Fd5FYaI= -go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY= -go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM= -go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M= -go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= -go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.45.0 h1:2ea0IkZBsWH+HA2GkD+7+hRw2u97jzdFyRtXuO14a1s= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.45.0/go.mod h1:4m3RnBBb+7dB9d21y510oO1pdB1V4J6smNf14WXcBFQ= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q= +go.opentelemetry.io/contrib/propagators/b3 v1.20.0 h1:Yty9Vs4F3D6/liF1o6FNt0PvN85h/BJJ6DQKJ3nrcM0= +go.opentelemetry.io/contrib/propagators/b3 v1.20.0/go.mod h1:On4VgbkqYL18kbJlWsa18+cMNe6rYpBnPi1ARI/BrsU= +go.opentelemetry.io/contrib/propagators/jaeger v1.20.0 h1:iVhNKkMIpzyZqxk8jkDU2n4DFTD+FbpGacvooxEvyyc= +go.opentelemetry.io/contrib/propagators/jaeger v1.20.0/go.mod h1:cpSABr0cm/AH/HhbJjn+AudBVUMgZWdfN3Gb+ZqxSZc= +go.opentelemetry.io/contrib/samplers/jaegerremote v0.14.0 h1:Xg9iU9DF9V9zC6NI8sJthYqHlSWsWAQMTXM8QIErKlc= +go.opentelemetry.io/contrib/samplers/jaegerremote v0.14.0/go.mod h1:ExRuq62/gYluX5fzTTZif5WujyG51ail4APTbBUu+S4= +go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= +go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= +go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4= +go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU= +go.opentelemetry.io/otel/exporters/zipkin v1.19.0 h1:EGY0h5mGliP9o/nIkVuLI0vRiQqmsYOcbwCuotksO1o= +go.opentelemetry.io/otel/exporters/zipkin v1.19.0/go.mod h1:JQgTGJP11yi3o4GHzIWYodhPisxANdqxF1eHwDSnJrI= +go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= +go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= +go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= +go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= +go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= +go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= +go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= +go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= 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.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1262,10 +1243,9 @@ 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-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210810183815-faf39c7919d5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= -golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= +golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= +golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= 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= @@ -1281,8 +1261,8 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= -golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1535,7 +1515,6 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= @@ -1549,13 +1528,12 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc h1:8DyZCyvI8mE1IdLy/60bS+52xfymkE72wv1asokgtao= -google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= -google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc h1:kVKPf/IiYSBWEWtkIn6wZXwWGCnLKcC8oWfZvXjsGnM= -google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc h1:XSJ8Vk1SWuNr8S18z1NZSziL0CPIXLCCMDOEFtHBOFc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b h1:+YaDE2r2OG8t/z5qmsh7Y+XXwCbvadxxZ0YY6mTdrVA= +google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI= +google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b h1:CIC2YMXmIhYw6evmhPxBKJ4fmLbOFtXQN/GV3XOZR8k= +google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b h1:ZlWIi1wSK56/8hn4QcBp/j9M7Gt3U/3hZw3mC7vDICo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:swOH3j0KzcDDgGUWr+SNpyTen5YrXjS3eyPzFYKc6lc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1569,15 +1547,11 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= -google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/grpc/examples v0.0.0-20210304020650-930c79186c99 h1:qA8rMbz1wQ4DOFfM2ouD29DG9aHWBm6ZOy9BGxiUMmY= google.golang.org/grpc/examples v0.0.0-20210304020650-930c79186c99/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -1606,6 +1580,7 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/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= @@ -1624,7 +1599,6 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD gopkg.in/validator.v2 v2.0.0-20180514200540-135c24b11c19/go.mod h1:o4V0GXN9/CAmCsvJ0oXYZvrZOe7syiDZSN1GWGZTGzc= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/internal/testhelpers/http.go b/internal/testhelpers/http.go index 444a3360cfed..5523de9d5368 100644 --- a/internal/testhelpers/http.go +++ b/internal/testhelpers/http.go @@ -117,3 +117,41 @@ func HTTPPostForm(t *testing.T, client *http.Client, remote string, in *url.Valu return payload, res } + +func NewTestHTTPRequest(t *testing.T, method, url string, body io.Reader) *http.Request { + req, err := http.NewRequest(method, url, body) + require.NoError(t, err) + return req +} + +func EasyGet(t *testing.T, c *http.Client, url string) (*http.Response, []byte) { + res, err := c.Get(url) + require.NoError(t, err) + defer res.Body.Close() + body, err := io.ReadAll(res.Body) + require.NoError(t, err) + return res, body +} + +func EasyGetJSON(t *testing.T, c *http.Client, url string) (*http.Response, []byte) { + req, err := http.NewRequest("GET", url, nil) + require.NoError(t, err) + req.Header.Set("Accept", "application/json") + res, err := c.Do(req) + require.NoError(t, err) + defer res.Body.Close() + body, err := io.ReadAll(res.Body) + require.NoError(t, err) + return res, body +} + +func EasyGetBody(t *testing.T, c *http.Client, url string) []byte { + _, body := EasyGet(t, c, url) // nolint: bodyclose + return body +} + +func EasyCookieJar(t *testing.T, o *cookiejar.Options) *cookiejar.Jar { + cj, err := cookiejar.New(o) + require.NoError(t, err) + return cj +} diff --git a/internal/testhelpers/identity.go b/internal/testhelpers/identity.go index 7029e376d58c..5c7cdd5be692 100644 --- a/internal/testhelpers/identity.go +++ b/internal/testhelpers/identity.go @@ -7,8 +7,6 @@ import ( "testing" "time" - "github.com/ory/kratos/x" - "github.com/stretchr/testify/require" "github.com/ory/kratos/driver" @@ -18,7 +16,7 @@ import ( ) func CreateSession(t *testing.T, reg driver.Registry) *session.Session { - req := x.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) + req := NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) i := identity.NewIdentity(config.DefaultIdentityTraitsSchemaID) require.NoError(t, reg.PrivilegedIdentityPool().CreateIdentity(req.Context(), i)) sess, err := session.NewActiveSession(req, i, reg.Config(), time.Now().UTC(), identity.CredentialsTypePassword, identity.AuthenticatorAssuranceLevel1) diff --git a/internal/testhelpers/selfservice_verification.go b/internal/testhelpers/selfservice_verification.go index c1b84f3d5430..757f21adb30a 100644 --- a/internal/testhelpers/selfservice_verification.go +++ b/internal/testhelpers/selfservice_verification.go @@ -150,7 +150,7 @@ func SubmitRecoveryForm( func PersistNewRecoveryFlow(t *testing.T, strategy recovery.Strategy, conf *config.Config, reg *driver.RegistryDefault) *recovery.Flow { t.Helper() - req := x.NewTestHTTPRequest(t, "GET", conf.SelfPublicURL(context.Background()).String()+"/test", nil) + req := NewTestHTTPRequest(t, "GET", conf.SelfPublicURL(context.Background()).String()+"/test", nil) f, err := recovery.NewFlow(conf, conf.SelfServiceFlowRecoveryRequestLifespan(context.Background()), reg.GenerateCSRFToken(req), req, strategy, flow.TypeBrowser) require.NoError(t, err, "Expected no error when creating a new recovery flow: %s", err) diff --git a/internal/testhelpers/session.go b/internal/testhelpers/session.go index b96c5ef47f00..91a2da5abda2 100644 --- a/internal/testhelpers/session.go +++ b/internal/testhelpers/session.go @@ -134,14 +134,14 @@ func NewHTTPClientWithSessionToken(t *testing.T, reg *driver.RegistryDefault, se maybePersistSession(t, reg, sess) return &http.Client{ - Transport: x.NewTransportWithHeader(http.Header{ + Transport: NewTransportWithHeader(t, http.Header{ "Authorization": {"Bearer " + sess.Token}, }), } } func NewHTTPClientWithArbitrarySessionToken(t *testing.T, reg *driver.RegistryDefault) *http.Client { - req := x.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) + req := NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) s, err := session.NewActiveSession(req, &identity.Identity{ID: x.NewUUID(), State: identity.StateActive}, NewSessionLifespanProvider(time.Hour), @@ -155,7 +155,7 @@ func NewHTTPClientWithArbitrarySessionToken(t *testing.T, reg *driver.RegistryDe } func NewHTTPClientWithArbitrarySessionCookie(t *testing.T, reg *driver.RegistryDefault) *http.Client { - req := x.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) + req := NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) s, err := session.NewActiveSession(req, &identity.Identity{ID: x.NewUUID(), State: identity.StateActive, Traits: []byte("{}")}, NewSessionLifespanProvider(time.Hour), @@ -169,7 +169,7 @@ func NewHTTPClientWithArbitrarySessionCookie(t *testing.T, reg *driver.RegistryD } func NewNoRedirectHTTPClientWithArbitrarySessionCookie(t *testing.T, reg *driver.RegistryDefault) *http.Client { - req := x.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) + req := NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) s, err := session.NewActiveSession(req, &identity.Identity{ID: x.NewUUID(), State: identity.StateActive}, NewSessionLifespanProvider(time.Hour), @@ -183,7 +183,7 @@ func NewNoRedirectHTTPClientWithArbitrarySessionCookie(t *testing.T, reg *driver } func NewHTTPClientWithIdentitySessionCookie(t *testing.T, reg *driver.RegistryDefault, id *identity.Identity) *http.Client { - req := x.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) + req := NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) s, err := session.NewActiveSession(req, id, NewSessionLifespanProvider(time.Hour), @@ -197,7 +197,7 @@ func NewHTTPClientWithIdentitySessionCookie(t *testing.T, reg *driver.RegistryDe } func NewHTTPClientWithIdentitySessionToken(t *testing.T, reg *driver.RegistryDefault, id *identity.Identity) *http.Client { - req := x.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) + req := NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) s, err := session.NewActiveSession(req, id, NewSessionLifespanProvider(time.Hour), @@ -222,10 +222,32 @@ func EnsureAAL(t *testing.T, c *http.Client, ts *httptest.Server, aal string, me assert.Len(t, gjson.GetBytes(sess, "authentication_methods").Array(), 1+len(methods)) } -func NewAuthorizedTransport(t *testing.T, reg *driver.RegistryDefault, sess *session.Session) *x.TransportWithHeader { +func NewAuthorizedTransport(t *testing.T, reg *driver.RegistryDefault, sess *session.Session) *TransportWithHeader { maybePersistSession(t, reg, sess) - return x.NewTransportWithHeader(http.Header{ + return NewTransportWithHeader(t, http.Header{ "Authorization": {"Bearer " + sess.Token}, }) } + +func NewTransportWithHeader(t *testing.T, h http.Header) *TransportWithHeader { + if t == nil { + panic("This function is for testing use only.") + } + return &TransportWithHeader{ + RoundTripper: http.DefaultTransport, + h: h, + } +} + +type TransportWithHeader struct { + http.RoundTripper + h http.Header +} + +func (ct *TransportWithHeader) RoundTrip(req *http.Request) (*http.Response, error) { + for k := range ct.h { + req.Header.Set(k, ct.h.Get(k)) + } + return ct.RoundTripper.RoundTrip(req) +} diff --git a/selfservice/flow/login/handler_test.go b/selfservice/flow/login/handler_test.go index ada0814aaf1d..85daee4e65a9 100644 --- a/selfservice/flow/login/handler_test.go +++ b/selfservice/flow/login/handler_test.go @@ -85,7 +85,7 @@ func TestFlowLifecycle(t *testing.T) { if isAPI { route = login.RouteInitAPIFlow } - req := x.NewTestHTTPRequest(t, "GET", ts.URL+route, nil) + req := testhelpers.NewTestHTTPRequest(t, "GET", ts.URL+route, nil) req.URL.RawQuery = extQuery.Encode() body, res := testhelpers.MockMakeAuthenticatedRequest(t, reg, conf, router.Router, req) if isAPI { @@ -100,7 +100,7 @@ func TestFlowLifecycle(t *testing.T) { route = login.RouteInitAPIFlow } client := ts.Client() - req := x.NewTestHTTPRequest(t, "GET", ts.URL+route, nil) + req := testhelpers.NewTestHTTPRequest(t, "GET", ts.URL+route, nil) req.URL.RawQuery = extQuery.Encode() res, err := client.Do(req) @@ -147,7 +147,8 @@ func TestFlowLifecycle(t *testing.T) { Type: identity.CredentialsTypePassword, Identifiers: []string{id1mail}, Config: sqlxx.JSONRawMessage(`{"hashed_password":"$2a$08$.cOYmAd.vCpDOoiVJrO5B.hjTLKQQ6cAK40u8uB.FnZDyPvVvQ9Q."}`), // foobar - }}, + }, + }, State: identity.StateActive, Traits: identity.Traits(`{"username":"` + id1mail + `"}`), } @@ -157,7 +158,8 @@ func TestFlowLifecycle(t *testing.T) { Type: identity.CredentialsTypePassword, Identifiers: []string{id2mail}, Config: sqlxx.JSONRawMessage(`{"hashed_password":"$2a$08$.cOYmAd.vCpDOoiVJrO5B.hjTLKQQ6cAK40u8uB.FnZDyPvVvQ9Q."}`), // foobar - }}, + }, + }, State: identity.StateActive, Traits: identity.Traits(`{"username":"` + id2mail + `"}`), } @@ -168,8 +170,10 @@ func TestFlowLifecycle(t *testing.T) { t.Run("lifecycle=submit", func(t *testing.T) { t.Run("interaction=unauthenticated", func(t *testing.T) { run := func(t *testing.T, tt flow.Type, aal string, values url.Values) (string, *http.Response) { - f := login.Flow{Type: tt, ExpiresAt: time.Now().Add(time.Minute), IssuedAt: time.Now(), - UI: container.New(""), Refresh: false, RequestedAAL: identity.AuthenticatorAssuranceLevel(aal)} + f := login.Flow{ + Type: tt, ExpiresAt: time.Now().Add(time.Minute), IssuedAt: time.Now(), + UI: container.New(""), Refresh: false, RequestedAAL: identity.AuthenticatorAssuranceLevel(aal), + } require.NoError(t, reg.LoginFlowPersister().CreateLoginFlow(context.Background(), &f)) res, err := http.PostForm(ts.URL+login.RouteSubmitFlow+"?flow="+f.ID.String(), values) @@ -339,8 +343,10 @@ func TestFlowLifecycle(t *testing.T) { t.Run("case=ensure aal is checked for upgradeability on session", func(t *testing.T) { run := func(t *testing.T, tt flow.Type, values url.Values) (string, *http.Response) { - f := login.Flow{Type: tt, ExpiresAt: time.Now().Add(time.Minute), IssuedAt: time.Now(), - UI: container.New(""), Refresh: false, RequestedAAL: "aal1"} + f := login.Flow{ + Type: tt, ExpiresAt: time.Now().Add(time.Minute), IssuedAt: time.Now(), + UI: container.New(""), Refresh: false, RequestedAAL: "aal1", + } require.NoError(t, reg.LoginFlowPersister().CreateLoginFlow(context.Background(), &f)) req, err := http.NewRequest("GET", ts.URL+login.RouteSubmitFlow+"?flow="+f.ID.String(), strings.NewReader(values.Encode())) @@ -371,8 +377,10 @@ func TestFlowLifecycle(t *testing.T) { expired := time.Now().Add(-time.Minute) run := func(t *testing.T, tt flow.Type, aal string, values string, isSPA bool) (string, *http.Response) { - f := login.Flow{Type: tt, ExpiresAt: expired, IssuedAt: time.Now(), - UI: container.New(""), Refresh: false, RequestedAAL: identity.AuthenticatorAssuranceLevel(aal)} + f := login.Flow{ + Type: tt, ExpiresAt: expired, IssuedAt: time.Now(), + UI: container.New(""), Refresh: false, RequestedAAL: identity.AuthenticatorAssuranceLevel(aal), + } require.NoError(t, reg.LoginFlowPersister().CreateLoginFlow(context.Background(), &f)) req, err := http.NewRequest("POST", ts.URL+login.RouteSubmitFlow+"?flow="+f.ID.String(), strings.NewReader(values)) @@ -428,7 +436,7 @@ func TestFlowLifecycle(t *testing.T) { key, err := totp.NewKey(context.Background(), "foo", reg) require.NoError(t, err) email := testhelpers.RandomEmail() - var id = &identity.Identity{ + id := &identity.Identity{ Credentials: map[identity.CredentialsType]identity.Credentials{ "password": { Type: "password", @@ -737,7 +745,7 @@ func TestFlowLifecycle(t *testing.T) { require.Contains(t, res.Request.URL.String(), loginTS.URL) c := ts.Client() - req := x.NewTestHTTPRequest(t, "GET", ts.URL+login.RouteGetFlow, nil) + req := testhelpers.NewTestHTTPRequest(t, "GET", ts.URL+login.RouteGetFlow, nil) req.URL.RawQuery = url.Values{"id": {res.Request.URL.Query().Get("flow")}}.Encode() res, err := c.Do(req) @@ -792,7 +800,7 @@ func TestGetFlow(t *testing.T) { setupLoginUI := func(t *testing.T, c *http.Client) *httptest.Server { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // It is important that we use a HTTP request to fetch the flow because that will show us if CSRF works or not - _, err := w.Write(x.EasyGetBody(t, c, public.URL+login.RouteGetFlow+"?id="+r.URL.Query().Get("flow"))) + _, err := w.Write(testhelpers.EasyGetBody(t, c, public.URL+login.RouteGetFlow+"?id="+r.URL.Query().Get("flow"))) require.NoError(t, err) })) conf.MustSet(ctx, config.ViperKeySelfServiceLoginUI, ts.URL) @@ -803,12 +811,13 @@ func TestGetFlow(t *testing.T) { _ = testhelpers.NewLoginUIFlowEchoServer(t, reg) conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+"."+string(identity.CredentialsTypePassword), map[string]interface{}{ - "enabled": true}) + "enabled": true, + }) t.Run("case=fetching successful", func(t *testing.T) { client := testhelpers.NewClientWithCookies(t) setupLoginUI(t, client) - body := x.EasyGetBody(t, client, public.URL+login.RouteInitBrowserFlow) + body := testhelpers.EasyGetBody(t, client, public.URL+login.RouteInitBrowserFlow) assert.NotEmpty(t, gjson.GetBytes(body, "ui.nodes.#(attributes.name==csrf_token).attributes.value").String(), "%s", body) assert.NotEmpty(t, gjson.GetBytes(body, "id").String(), "%s", body) @@ -820,7 +829,7 @@ func TestGetFlow(t *testing.T) { t.Run("case=csrf cookie missing", func(t *testing.T) { client := http.DefaultClient setupLoginUI(t, client) - body := x.EasyGetBody(t, client, public.URL+login.RouteInitBrowserFlow) + body := testhelpers.EasyGetBody(t, client, public.URL+login.RouteInitBrowserFlow) assert.EqualValues(t, x.ErrInvalidCSRFToken.ReasonField, gjson.GetBytes(body, "error.reason").String(), "%s", body) }) @@ -828,7 +837,7 @@ func TestGetFlow(t *testing.T) { t.Run("case=expired", func(t *testing.T) { client := testhelpers.NewClientWithCookies(t) setupLoginUI(t, client) - body := x.EasyGetBody(t, client, public.URL+login.RouteInitBrowserFlow) + body := testhelpers.EasyGetBody(t, client, public.URL+login.RouteInitBrowserFlow) // Expire the flow f, err := reg.LoginFlowPersister().GetLoginFlow(context.Background(), uuid.FromStringOrNil(gjson.GetBytes(body, "id").String())) @@ -837,7 +846,7 @@ func TestGetFlow(t *testing.T) { require.NoError(t, reg.LoginFlowPersister().UpdateLoginFlow(context.Background(), f)) // Try the flow but it is expired - res, body := x.EasyGet(t, client, public.URL+login.RouteGetFlow+"?id="+f.ID.String()) + res, body := testhelpers.EasyGet(t, client, public.URL+login.RouteGetFlow+"?id="+f.ID.String()) assert.EqualValues(t, http.StatusGone, res.StatusCode) assert.Equal(t, public.URL+login.RouteInitBrowserFlow, gjson.GetBytes(body, "error.details.redirect_to").String(), "%s", body) }) @@ -848,7 +857,7 @@ func TestGetFlow(t *testing.T) { client := testhelpers.NewClientWithCookies(t) setupLoginUI(t, client) - body := x.EasyGetBody(t, client, public.URL+login.RouteInitBrowserFlow+"?return_to="+returnTo) + body := testhelpers.EasyGetBody(t, client, public.URL+login.RouteInitBrowserFlow+"?return_to="+returnTo) // Expire the flow f, err := reg.LoginFlowPersister().GetLoginFlow(context.Background(), uuid.FromStringOrNil(gjson.GetBytes(body, "id").String())) @@ -858,7 +867,7 @@ func TestGetFlow(t *testing.T) { // Retrieve the flow and verify that return_to is in the response getURL := fmt.Sprintf("%s%s?id=%s&return_to=%s", public.URL, login.RouteGetFlow, f.ID, returnTo) - getBody := x.EasyGetBody(t, client, getURL) + getBody := testhelpers.EasyGetBody(t, client, getURL) assert.Equal(t, gjson.GetBytes(getBody, "error.details.return_to").String(), returnTo) // submit the flow but it is expired @@ -878,7 +887,7 @@ func TestGetFlow(t *testing.T) { client := testhelpers.NewClientWithCookies(t) setupLoginUI(t, client) - res, _ := x.EasyGet(t, client, public.URL+login.RouteGetFlow+"?id="+x.NewUUID().String()) + res, _ := testhelpers.EasyGet(t, client, public.URL+login.RouteGetFlow+"?id="+x.NewUUID().String()) assert.EqualValues(t, http.StatusNotFound, res.StatusCode) }) } diff --git a/selfservice/flow/recovery/handler_test.go b/selfservice/flow/recovery/handler_test.go index 7d204e3846f0..0d8bf26d42b3 100644 --- a/selfservice/flow/recovery/handler_test.go +++ b/selfservice/flow/recovery/handler_test.go @@ -48,13 +48,13 @@ func TestHandlerRedirectOnAuthenticated(t *testing.T) { testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/identity.schema.json") t.Run("does redirect to default on authenticated request", func(t *testing.T) { - body, res := testhelpers.MockMakeAuthenticatedRequest(t, reg, conf, router.Router, x.NewTestHTTPRequest(t, "GET", ts.URL+recovery.RouteInitBrowserFlow, nil)) + body, res := testhelpers.MockMakeAuthenticatedRequest(t, reg, conf, router.Router, testhelpers.NewTestHTTPRequest(t, "GET", ts.URL+recovery.RouteInitBrowserFlow, nil)) assert.Contains(t, res.Request.URL.String(), redirTS.URL, "%+v", res) assert.EqualValues(t, "already authenticated", string(body)) }) t.Run("does redirect to default on authenticated request", func(t *testing.T) { - body, res := testhelpers.MockMakeAuthenticatedRequest(t, reg, conf, router.Router, x.NewTestHTTPRequest(t, "GET", ts.URL+recovery.RouteInitAPIFlow, nil)) + body, res := testhelpers.MockMakeAuthenticatedRequest(t, reg, conf, router.Router, testhelpers.NewTestHTTPRequest(t, "GET", ts.URL+recovery.RouteInitAPIFlow, nil)) assert.Contains(t, res.Request.URL.String(), recovery.RouteInitAPIFlow) assert.EqualValues(t, text.ErrIDAlreadyLoggedIn, gjson.GetBytes(body, "error.id").Str) assertx.EqualAsJSON(t, recovery.ErrAlreadyLoggedIn, json.RawMessage(gjson.GetBytes(body, "error").Raw)) @@ -90,7 +90,7 @@ func TestInitFlow(t *testing.T) { if isAPI { route = recovery.RouteInitAPIFlow } - req := x.NewTestHTTPRequest(t, "GET", publicTS.URL+route, nil) + req := testhelpers.NewTestHTTPRequest(t, "GET", publicTS.URL+route, nil) if isSPA { req.Header.Set("Accept", "application/json") } @@ -118,7 +118,7 @@ func TestInitFlow(t *testing.T) { initSPAFlow := func(t *testing.T, hc *http.Client, isSPA bool) (*http.Response, []byte) { route := recovery.RouteInitBrowserFlow c := publicTS.Client() - req := x.NewTestHTTPRequest(t, "GET", publicTS.URL+route, nil) + req := testhelpers.NewTestHTTPRequest(t, "GET", publicTS.URL+route, nil) if isSPA { req.Header.Set("Accept", "application/json") } @@ -215,7 +215,7 @@ func TestGetFlow(t *testing.T) { setupRecoveryTS := func(t *testing.T, c *http.Client) *httptest.Server { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - _, err := w.Write(x.EasyGetBody(t, c, public.URL+recovery.RouteGetFlow+"?id="+r.URL.Query().Get("flow"))) + _, err := w.Write(testhelpers.EasyGetBody(t, c, public.URL+recovery.RouteGetFlow+"?id="+r.URL.Query().Get("flow"))) require.NoError(t, err) })) t.Cleanup(ts.Close) @@ -226,7 +226,7 @@ func TestGetFlow(t *testing.T) { t.Run("case=csrf cookie missing", func(t *testing.T) { client := http.DefaultClient setupRecoveryTS(t, client) - body := x.EasyGetBody(t, client, public.URL+recovery.RouteInitBrowserFlow) + body := testhelpers.EasyGetBody(t, client, public.URL+recovery.RouteInitBrowserFlow) assert.EqualValues(t, x.ErrInvalidCSRFToken.ReasonField, gjson.GetBytes(body, "error.reason").String(), "%s", body) }) @@ -234,7 +234,7 @@ func TestGetFlow(t *testing.T) { t.Run("case=valid", func(t *testing.T) { client := testhelpers.NewClientWithCookies(t) setupRecoveryTS(t, client) - body := x.EasyGetBody(t, client, public.URL+recovery.RouteInitBrowserFlow) + body := testhelpers.EasyGetBody(t, client, public.URL+recovery.RouteInitBrowserFlow) assert.NotEmpty(t, gjson.GetBytes(body, "ui.nodes.#(attributes.name==csrf_token).attributes.value").String(), "%s", body) assert.NotEmpty(t, gjson.GetBytes(body, "id").String(), "%s", body) assert.Empty(t, gjson.GetBytes(body, "headers").Value(), "%s", body) @@ -245,7 +245,7 @@ func TestGetFlow(t *testing.T) { t.Run("case=expired", func(t *testing.T) { client := testhelpers.NewClientWithCookies(t) setupRecoveryTS(t, client) - body := x.EasyGetBody(t, client, public.URL+recovery.RouteInitBrowserFlow) + body := testhelpers.EasyGetBody(t, client, public.URL+recovery.RouteInitBrowserFlow) // Expire the flow f, err := reg.RecoveryFlowPersister().GetRecoveryFlow(context.Background(), uuid.FromStringOrNil(gjson.GetBytes(body, "id").String())) @@ -253,7 +253,7 @@ func TestGetFlow(t *testing.T) { f.ExpiresAt = time.Now().Add(-time.Second) require.NoError(t, reg.RecoveryFlowPersister().UpdateRecoveryFlow(context.Background(), f)) - res, body := x.EasyGet(t, client, public.URL+recovery.RouteGetFlow+"?id="+f.ID.String()) + res, body := testhelpers.EasyGet(t, client, public.URL+recovery.RouteGetFlow+"?id="+f.ID.String()) assert.EqualValues(t, http.StatusGone, res.StatusCode) assert.Equal(t, public.URL+recovery.RouteInitBrowserFlow, gjson.GetBytes(body, "error.details.redirect_to").String(), "%s", body) }) @@ -263,7 +263,7 @@ func TestGetFlow(t *testing.T) { conf.MustSet(ctx, config.ViperKeyURLsAllowedReturnToDomains, []string{returnTo}) client := testhelpers.NewClientWithCookies(t) setupRecoveryTS(t, client) - body := x.EasyGetBody(t, client, public.URL+recovery.RouteInitBrowserFlow+"?return_to="+returnTo) + body := testhelpers.EasyGetBody(t, client, public.URL+recovery.RouteInitBrowserFlow+"?return_to="+returnTo) // Expire the flow f, err := reg.RecoveryFlowPersister().GetRecoveryFlow(context.Background(), uuid.FromStringOrNil(gjson.GetBytes(body, "id").String())) @@ -273,7 +273,7 @@ func TestGetFlow(t *testing.T) { // Retrieve the flow and verify that return_to is in the response getURL := fmt.Sprintf("%s%s?id=%s&return_to=%s", public.URL, recovery.RouteGetFlow, f.ID, returnTo) - getBody := x.EasyGetBody(t, client, getURL) + getBody := testhelpers.EasyGetBody(t, client, getURL) assert.Equal(t, gjson.GetBytes(getBody, "error.details.return_to").String(), returnTo) // submit the flow but it is expired @@ -293,7 +293,7 @@ func TestGetFlow(t *testing.T) { client := testhelpers.NewClientWithCookies(t) setupRecoveryTS(t, client) - res, _ := x.EasyGet(t, client, public.URL+recovery.RouteGetFlow+"?id="+x.NewUUID().String()) + res, _ := testhelpers.EasyGet(t, client, public.URL+recovery.RouteGetFlow+"?id="+x.NewUUID().String()) assert.EqualValues(t, http.StatusNotFound, res.StatusCode) }) } diff --git a/selfservice/flow/registration/handler_test.go b/selfservice/flow/registration/handler_test.go index 27df3e0868a5..2bdfeb6e8540 100644 --- a/selfservice/flow/registration/handler_test.go +++ b/selfservice/flow/registration/handler_test.go @@ -58,19 +58,19 @@ func TestHandlerRedirectOnAuthenticated(t *testing.T) { testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/identity.schema.json") t.Run("does redirect to default on authenticated request", func(t *testing.T) { - body, res := testhelpers.MockMakeAuthenticatedRequest(t, reg, conf, router.Router, x.NewTestHTTPRequest(t, "GET", ts.URL+registration.RouteInitBrowserFlow, nil)) + body, res := testhelpers.MockMakeAuthenticatedRequest(t, reg, conf, router.Router, testhelpers.NewTestHTTPRequest(t, "GET", ts.URL+registration.RouteInitBrowserFlow, nil)) assert.Contains(t, res.Request.URL.String(), redirTS.URL) assert.EqualValues(t, "already authenticated", string(body)) }) t.Run("does redirect to default on authenticated request", func(t *testing.T) { - body, res := testhelpers.MockMakeAuthenticatedRequest(t, reg, conf, router.Router, x.NewTestHTTPRequest(t, "GET", ts.URL+registration.RouteInitAPIFlow, nil)) + body, res := testhelpers.MockMakeAuthenticatedRequest(t, reg, conf, router.Router, testhelpers.NewTestHTTPRequest(t, "GET", ts.URL+registration.RouteInitAPIFlow, nil)) assert.Contains(t, res.Request.URL.String(), registration.RouteInitAPIFlow) assertx.EqualAsJSON(t, registration.ErrAlreadyLoggedIn, json.RawMessage(gjson.GetBytes(body, "error").Raw)) }) t.Run("does redirect to return_to url on authenticated request", func(t *testing.T) { - body, res := testhelpers.MockMakeAuthenticatedRequest(t, reg, conf, router.Router, x.NewTestHTTPRequest(t, "GET", ts.URL+registration.RouteInitBrowserFlow+"?return_to="+returnToTS.URL, nil)) + body, res := testhelpers.MockMakeAuthenticatedRequest(t, reg, conf, router.Router, testhelpers.NewTestHTTPRequest(t, "GET", ts.URL+registration.RouteInitBrowserFlow+"?return_to="+returnToTS.URL, nil)) assert.Contains(t, res.Request.URL.String(), returnToTS.URL) assert.EqualValues(t, "return_to", string(body)) }) @@ -103,7 +103,7 @@ func TestInitFlow(t *testing.T) { if isAPI { route = registration.RouteInitAPIFlow } - req := x.NewTestHTTPRequest(t, "GET", publicTS.URL+route, nil) + req := testhelpers.NewTestHTTPRequest(t, "GET", publicTS.URL+route, nil) if isSPA { req.Header.Set("Accept", "application/json") } @@ -297,7 +297,7 @@ func TestGetFlow(t *testing.T) { setupRegistrationUI := func(t *testing.T, c *http.Client) *httptest.Server { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - _, err := w.Write(x.EasyGetBody(t, c, public.URL+registration.RouteGetFlow+"?id="+r.URL.Query().Get("flow"))) + _, err := w.Write(testhelpers.EasyGetBody(t, c, public.URL+registration.RouteGetFlow+"?id="+r.URL.Query().Get("flow"))) require.NoError(t, err) })) t.Cleanup(ts.Close) @@ -308,7 +308,7 @@ func TestGetFlow(t *testing.T) { t.Run("case=valid", func(t *testing.T) { client := testhelpers.NewClientWithCookies(t) _ = setupRegistrationUI(t, client) - body := x.EasyGetBody(t, client, public.URL+registration.RouteInitBrowserFlow) + body := testhelpers.EasyGetBody(t, client, public.URL+registration.RouteInitBrowserFlow) assert.NotEmpty(t, gjson.GetBytes(body, "ui.nodes.#(attributes.name==csrf_token).attributes.value").String(), "%s", body) assert.NotEmpty(t, gjson.GetBytes(body, "id").String(), "%s", body) @@ -320,7 +320,7 @@ func TestGetFlow(t *testing.T) { t.Run("case=csrf cookie missing", func(t *testing.T) { client := http.DefaultClient _ = setupRegistrationUI(t, client) - body := x.EasyGetBody(t, client, public.URL+registration.RouteInitBrowserFlow) + body := testhelpers.EasyGetBody(t, client, public.URL+registration.RouteInitBrowserFlow) assert.EqualValues(t, x.ErrInvalidCSRFToken.ReasonField, gjson.GetBytes(body, "error.reason").String(), "%s", body) }) @@ -328,7 +328,7 @@ func TestGetFlow(t *testing.T) { t.Run("case=expired", func(t *testing.T) { client := testhelpers.NewClientWithCookies(t) setupRegistrationUI(t, client) - body := x.EasyGetBody(t, client, public.URL+registration.RouteInitBrowserFlow) + body := testhelpers.EasyGetBody(t, client, public.URL+registration.RouteInitBrowserFlow) // Expire the flow f, err := reg.RegistrationFlowPersister().GetRegistrationFlow(context.Background(), uuid.FromStringOrNil(gjson.GetBytes(body, "id").String())) @@ -336,7 +336,7 @@ func TestGetFlow(t *testing.T) { f.ExpiresAt = time.Now().Add(-time.Second) require.NoError(t, reg.RegistrationFlowPersister().UpdateRegistrationFlow(context.Background(), f)) - res, body := x.EasyGet(t, client, public.URL+registration.RouteGetFlow+"?id="+f.ID.String()) + res, body := testhelpers.EasyGet(t, client, public.URL+registration.RouteGetFlow+"?id="+f.ID.String()) assert.EqualValues(t, http.StatusGone, res.StatusCode) assert.Equal(t, public.URL+registration.RouteInitBrowserFlow, gjson.GetBytes(body, "error.details.redirect_to").String(), "%s", body) }) @@ -347,7 +347,7 @@ func TestGetFlow(t *testing.T) { client := testhelpers.NewClientWithCookies(t) setupRegistrationUI(t, client) - body := x.EasyGetBody(t, client, public.URL+registration.RouteInitBrowserFlow+"?return_to="+returnTo) + body := testhelpers.EasyGetBody(t, client, public.URL+registration.RouteInitBrowserFlow+"?return_to="+returnTo) // Expire the flow f, err := reg.RegistrationFlowPersister().GetRegistrationFlow(context.Background(), uuid.FromStringOrNil(gjson.GetBytes(body, "id").String())) @@ -357,7 +357,7 @@ func TestGetFlow(t *testing.T) { // Retrieve the flow and verify that return_to is in the response getURL := fmt.Sprintf("%s%s?id=%s&return_to=%s", public.URL, registration.RouteGetFlow, f.ID, returnTo) - getBody := x.EasyGetBody(t, client, getURL) + getBody := testhelpers.EasyGetBody(t, client, getURL) assert.Equal(t, gjson.GetBytes(getBody, "error.details.return_to").String(), returnTo) // submit the flow but it is expired @@ -377,7 +377,7 @@ func TestGetFlow(t *testing.T) { client := testhelpers.NewClientWithCookies(t) setupRegistrationUI(t, client) - res, _ := x.EasyGet(t, client, public.URL+registration.RouteGetFlow+"?id="+x.NewUUID().String()) + res, _ := testhelpers.EasyGet(t, client, public.URL+registration.RouteGetFlow+"?id="+x.NewUUID().String()) assert.EqualValues(t, http.StatusNotFound, res.StatusCode) }) } @@ -420,7 +420,7 @@ func TestOIDCStrategyOrder(t *testing.T) { setupRegistrationUI := func(t *testing.T, c *http.Client) *httptest.Server { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - _, err := w.Write(x.EasyGetBody(t, c, public.URL+registration.RouteGetFlow+"?id="+r.URL.Query().Get("flow"))) + _, err := w.Write(testhelpers.EasyGetBody(t, c, public.URL+registration.RouteGetFlow+"?id="+r.URL.Query().Get("flow"))) require.NoError(t, err) })) t.Cleanup(ts.Close) @@ -431,7 +431,7 @@ func TestOIDCStrategyOrder(t *testing.T) { t.Run("case=accept `password` method while including `provider:google`", func(t *testing.T) { client := testhelpers.NewClientWithCookies(t) _ = setupRegistrationUI(t, client) - body := x.EasyGetBody(t, client, public.URL+registration.RouteInitBrowserFlow) + body := testhelpers.EasyGetBody(t, client, public.URL+registration.RouteInitBrowserFlow) flow := gjson.GetBytes(body, "id").String() @@ -464,7 +464,7 @@ func TestOIDCStrategyOrder(t *testing.T) { t.Run("case=accept oidc flow with just `provider:google`", func(t *testing.T) { client := testhelpers.NewClientWithCookies(t) _ = setupRegistrationUI(t, client) - body := x.EasyGetBody(t, client, public.URL+registration.RouteInitBrowserFlow) + body := testhelpers.EasyGetBody(t, client, public.URL+registration.RouteInitBrowserFlow) flow := gjson.GetBytes(body, "id").String() @@ -473,6 +473,7 @@ func TestOIDCStrategyOrder(t *testing.T) { payload := json.RawMessage(`{"provider": "google","csrf_token": "` + csrfToken + `"}`) req, err := http.NewRequestWithContext(context.Background(), http.MethodPost, public.URL+registration.RouteSubmitFlow+"?flow="+flow, bytes.NewBuffer(payload)) + require.NoError(t, err) req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") diff --git a/selfservice/flow/registration/hook_test.go b/selfservice/flow/registration/hook_test.go index c6f396b64514..3761692e3f45 100644 --- a/selfservice/flow/registration/hook_test.go +++ b/selfservice/flow/registration/hook_test.go @@ -246,7 +246,7 @@ func TestRegistrationExecutor(t *testing.T) { i := testhelpers.SelfServiceHookFakeIdentity(t) i.Traits = identity.Traits(`{"email": "verifiable4@ory.sh"}`) - jar := x.EasyCookieJar(t, nil) + jar := testhelpers.EasyCookieJar(t, nil) s := newServer(t, i, flow.TypeBrowser) s.Client().Jar = jar res, _ := makeRequestPost(t, s, false, url.Values{}) diff --git a/selfservice/flow/settings/handler_test.go b/selfservice/flow/settings/handler_test.go index 0a2789466fce..a24e598c64aa 100644 --- a/selfservice/flow/settings/handler_test.go +++ b/selfservice/flow/settings/handler_test.go @@ -110,7 +110,7 @@ func TestHandler(t *testing.T) { require.NoError(t, err) reqURL.RawQuery = op.query.Encode() - req := x.NewTestHTTPRequest(t, "GET", reqURL.String(), nil) + req := testhelpers.NewTestHTTPRequest(t, "GET", reqURL.String(), nil) if isSPA || isAPI { req.Header.Set("Accept", "application/json") } @@ -357,7 +357,7 @@ func TestHandler(t *testing.T) { conf.MustSet(ctx, config.ViperKeyURLsAllowedReturnToDomains, []string{returnTo}) client := testhelpers.NewHTTPClientWithArbitrarySessionToken(t, reg) - body := x.EasyGetBody(t, client, publicTS.URL+settings.RouteInitBrowserFlow+"?return_to="+returnTo) + body := testhelpers.EasyGetBody(t, client, publicTS.URL+settings.RouteInitBrowserFlow+"?return_to="+returnTo) // Expire the flow f, err := reg.SettingsFlowPersister().GetSettingsFlow(context.Background(), uuid.FromStringOrNil(gjson.GetBytes(body, "id").String())) @@ -367,7 +367,7 @@ func TestHandler(t *testing.T) { // Retrieve the flow and verify that return_to is in the response getURL := fmt.Sprintf("%s%s?id=%s&return_to=%s", publicTS.URL, settings.RouteGetFlow, f.ID, returnTo) - getBody := x.EasyGetBody(t, client, getURL) + getBody := testhelpers.EasyGetBody(t, client, getURL) assert.Equal(t, gjson.GetBytes(getBody, "error.details.return_to").String(), returnTo) // submit the flow but it is expired diff --git a/selfservice/flow/verification/handler_test.go b/selfservice/flow/verification/handler_test.go index 266cc9022431..6f37956b6055 100644 --- a/selfservice/flow/verification/handler_test.go +++ b/selfservice/flow/verification/handler_test.go @@ -41,7 +41,7 @@ func TestGetFlow(t *testing.T) { setupVerificationUI := func(t *testing.T, c *http.Client) *httptest.Server { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - _, err := w.Write(x.EasyGetBody(t, c, public.URL+verification.RouteGetFlow+"?id="+r.URL.Query().Get("flow"))) + _, err := w.Write(testhelpers.EasyGetBody(t, c, public.URL+verification.RouteGetFlow+"?id="+r.URL.Query().Get("flow"))) require.NoError(t, err) })) t.Cleanup(ts.Close) @@ -68,7 +68,7 @@ func TestGetFlow(t *testing.T) { t.Run("type=browser", func(t *testing.T) { client := testhelpers.NewClientWithCookies(t) _ = setupVerificationUI(t, client) - res, body := x.EasyGet(t, client, public.URL+verification.RouteInitBrowserFlow) + res, body := testhelpers.EasyGet(t, client, public.URL+verification.RouteInitBrowserFlow) require.NotEqualValues(t, res.Request.URL.String(), public.URL+verification.RouteInitBrowserFlow) assertFlowPayload(t, body, false) }) @@ -76,7 +76,7 @@ func TestGetFlow(t *testing.T) { t.Run("type=spa", func(t *testing.T) { client := testhelpers.NewClientWithCookies(t) _ = setupVerificationUI(t, client) - res, body := x.EasyGetJSON(t, client, public.URL+verification.RouteInitBrowserFlow) + res, body := testhelpers.EasyGetJSON(t, client, public.URL+verification.RouteInitBrowserFlow) require.EqualValues(t, res.Request.URL.String(), public.URL+verification.RouteInitBrowserFlow) assertFlowPayload(t, body, false) }) @@ -84,7 +84,7 @@ func TestGetFlow(t *testing.T) { t.Run("type=api", func(t *testing.T) { client := testhelpers.NewClientWithCookies(t) _ = setupVerificationUI(t, client) - res, body := x.EasyGet(t, client, public.URL+verification.RouteInitAPIFlow) + res, body := testhelpers.EasyGet(t, client, public.URL+verification.RouteInitAPIFlow) assert.Len(t, res.Header.Get("Set-Cookie"), 0) assertFlowPayload(t, body, true) }) @@ -93,7 +93,7 @@ func TestGetFlow(t *testing.T) { t.Run("case=csrf cookie missing", func(t *testing.T) { client := http.DefaultClient _ = setupVerificationUI(t, client) - body := x.EasyGetBody(t, client, public.URL+verification.RouteInitBrowserFlow) + body := testhelpers.EasyGetBody(t, client, public.URL+verification.RouteInitBrowserFlow) assert.EqualValues(t, x.ErrInvalidCSRFToken.ReasonField, gjson.GetBytes(body, "error.reason").String(), "%s", body) }) @@ -101,7 +101,7 @@ func TestGetFlow(t *testing.T) { t.Run("case=expired", func(t *testing.T) { client := testhelpers.NewClientWithCookies(t) _ = setupVerificationUI(t, client) - body := x.EasyGetBody(t, client, public.URL+verification.RouteInitBrowserFlow) + body := testhelpers.EasyGetBody(t, client, public.URL+verification.RouteInitBrowserFlow) // Expire the flow f, err := reg.VerificationFlowPersister().GetVerificationFlow(context.Background(), uuid.FromStringOrNil(gjson.GetBytes(body, "id").String())) @@ -109,7 +109,7 @@ func TestGetFlow(t *testing.T) { f.ExpiresAt = time.Now().Add(-time.Second) require.NoError(t, reg.VerificationFlowPersister().UpdateVerificationFlow(context.Background(), f)) - res, body := x.EasyGet(t, client, public.URL+verification.RouteGetFlow+"?id="+f.ID.String()) + res, body := testhelpers.EasyGet(t, client, public.URL+verification.RouteGetFlow+"?id="+f.ID.String()) assert.EqualValues(t, http.StatusGone, res.StatusCode) assert.Equal(t, public.URL+verification.RouteInitBrowserFlow, gjson.GetBytes(body, "error.details.redirect_to").String(), "%s", body) }) @@ -120,7 +120,7 @@ func TestGetFlow(t *testing.T) { client := testhelpers.NewClientWithCookies(t) _ = setupVerificationUI(t, client) - body := x.EasyGetBody(t, client, public.URL+verification.RouteInitBrowserFlow+"?return_to="+returnTo) + body := testhelpers.EasyGetBody(t, client, public.URL+verification.RouteInitBrowserFlow+"?return_to="+returnTo) // Expire the flow f, err := reg.VerificationFlowPersister().GetVerificationFlow(context.Background(), uuid.FromStringOrNil(gjson.GetBytes(body, "id").String())) @@ -130,7 +130,7 @@ func TestGetFlow(t *testing.T) { // Retrieve the flow and verify that return_to is in the response getURL := fmt.Sprintf("%s%s?id=%s&return_to=%s", public.URL, verification.RouteGetFlow, f.ID, returnTo) - getBody := x.EasyGetBody(t, client, getURL) + getBody := testhelpers.EasyGetBody(t, client, getURL) assert.Equal(t, gjson.GetBytes(getBody, "error.details.return_to").String(), returnTo) // submit the flow but it is expired @@ -161,7 +161,7 @@ func TestGetFlow(t *testing.T) { client := testhelpers.NewClientWithCookies(t) _ = setupVerificationUI(t, client) - res, _ := x.EasyGet(t, client, public.URL+verification.RouteGetFlow+"?id="+x.NewUUID().String()) + res, _ := testhelpers.EasyGet(t, client, public.URL+verification.RouteGetFlow+"?id="+x.NewUUID().String()) assert.EqualValues(t, http.StatusNotFound, res.StatusCode) }) @@ -245,7 +245,7 @@ func TestPostFlow(t *testing.T) { t.Run("case=fails without a session", func(t *testing.T) { client := testhelpers.NewClientWithCookies(t) ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - _, err := w.Write(x.EasyGetBody(t, client, public.URL+verification.RouteGetFlow+"?id="+r.URL.Query().Get("flow"))) + _, err := w.Write(testhelpers.EasyGetBody(t, client, public.URL+verification.RouteGetFlow+"?id="+r.URL.Query().Get("flow"))) require.NoError(t, err) })) t.Cleanup(ts.Close) diff --git a/selfservice/strategy/link/strategy_recovery_test.go b/selfservice/strategy/link/strategy_recovery_test.go index 71518cda33be..d470d8af6ce3 100644 --- a/selfservice/strategy/link/strategy_recovery_test.go +++ b/selfservice/strategy/link/strategy_recovery_test.go @@ -642,7 +642,7 @@ func TestRecovery(t *testing.T) { cl.CheckRedirect = func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse } - res, err := do(cl, x.NewTestHTTPRequest(t, "GET", recoveryLink, nil)) + res, err := do(cl, testhelpers.NewTestHTTPRequest(t, "GET", recoveryLink, nil)) require.NoError(t, err) require.NoError(t, res.Body.Close()) assert.Equal(t, http.StatusSeeOther, res.StatusCode) diff --git a/selfservice/strategy/password/login_test.go b/selfservice/strategy/password/login_test.go index c6357ff6920f..8d8879cce91c 100644 --- a/selfservice/strategy/password/login_test.go +++ b/selfservice/strategy/password/login_test.go @@ -151,7 +151,7 @@ func TestCompleteLogin(t *testing.T) { }) t.Run("should return an error because the request does not exist", func(t *testing.T) { - var check = func(t *testing.T, actual string) { + check := func(t *testing.T, actual string) { assert.Equal(t, int64(http.StatusNotFound), gjson.Get(actual, "code").Int(), "%s", actual) assert.Equal(t, "Not Found", gjson.Get(actual, "status").String(), "%s", actual) assert.Contains(t, gjson.Get(actual, "message").String(), "Unable to locate the resource", "%s", actual) @@ -159,7 +159,8 @@ func TestCompleteLogin(t *testing.T) { fakeFlow := &kratos.LoginFlow{ Ui: kratos.UiContainer{ - Action: publicTS.URL + login.RouteSubmitFlow + "?flow=" + x.NewUUID().String()}, + Action: publicTS.URL + login.RouteSubmitFlow + "?flow=" + x.NewUUID().String(), + }, } t.Run("type=api", func(t *testing.T) { @@ -229,7 +230,7 @@ func TestCompleteLogin(t *testing.T) { }) t.Run("case=should have correct CSRF behavior", func(t *testing.T) { - var values = url.Values{ + values := url.Values{ "method": {"password"}, "csrf_token": {"invalid_token"}, "identifier": {"login-identifier-csrf-browser"}, @@ -300,7 +301,7 @@ func TestCompleteLogin(t *testing.T) { }) }) - var expectValidationError = func(t *testing.T, isAPI, refresh, isSPA bool, values func(url.Values)) string { + expectValidationError := func(t *testing.T, isAPI, refresh, isSPA bool, values func(url.Values)) string { return testhelpers.SubmitLoginForm(t, isAPI, nil, publicTS, values, isSPA, refresh, testhelpers.ExpectStatusCode(isAPI || isSPA, http.StatusBadRequest, http.StatusOK), @@ -308,7 +309,7 @@ func TestCompleteLogin(t *testing.T) { } t.Run("should return an error because the credentials are invalid (user does not exist)", func(t *testing.T) { - var check = func(t *testing.T, body string, start time.Time) { + check := func(t *testing.T, body string, start time.Time) { delay := time.Since(start) minConfiguredDelay := conf.HasherArgon2(ctx).ExpectedDuration - conf.HasherArgon2(ctx).ExpectedDeviation assert.GreaterOrEqual(t, delay, minConfiguredDelay) @@ -317,7 +318,7 @@ func TestCompleteLogin(t *testing.T) { assert.Equal(t, text.NewErrorValidationInvalidCredentials().Text, gjson.Get(body, "ui.messages.0.text").String(), body) } - var values = func(v url.Values) { + values := func(v url.Values) { v.Set("identifier", "identifier") v.Set("password", "password") } @@ -339,7 +340,7 @@ func TestCompleteLogin(t *testing.T) { }) t.Run("should return an error because no identifier is set", func(t *testing.T) { - var check = func(t *testing.T, body string) { + check := func(t *testing.T, body string) { assert.NotEmpty(t, gjson.Get(body, "id").String(), "%s", body) assert.Contains(t, gjson.Get(body, "ui.action").String(), publicTS.URL+login.RouteSubmitFlow, "%s", body) @@ -351,7 +352,7 @@ func TestCompleteLogin(t *testing.T) { assert.Empty(t, gjson.Get(body, "ui.nodes.#(attributes.name==password).attributes.value").String()) } - var values = func(v url.Values) { + values := func(v url.Values) { v.Del("identifier") v.Set("method", identity.CredentialsTypePassword.String()) v.Set("password", "password") @@ -371,7 +372,7 @@ func TestCompleteLogin(t *testing.T) { }) t.Run("should return an error because no password is set", func(t *testing.T) { - var check = func(t *testing.T, body string) { + check := func(t *testing.T, body string) { assert.NotEmpty(t, gjson.Get(body, "id").String(), "%s", body) assert.Contains(t, gjson.Get(body, "ui.action").String(), publicTS.URL+login.RouteSubmitFlow, "%s", body) @@ -384,7 +385,7 @@ func TestCompleteLogin(t *testing.T) { assert.Empty(t, gjson.Get(body, "ui.nodes.#(attributes.name==password).attributes.value").String()) } - var values = func(v url.Values) { + values := func(v url.Values) { v.Set("identifier", "identifier") v.Del("password") } @@ -399,7 +400,7 @@ func TestCompleteLogin(t *testing.T) { }) t.Run("should return an error both identifier and password are missing", func(t *testing.T) { - var check = func(t *testing.T, body string) { + check := func(t *testing.T, body string) { assert.NotEmpty(t, gjson.Get(body, "id").String(), "%s", body) assert.Contains(t, gjson.Get(body, "ui.action").String(), publicTS.URL+login.RouteSubmitFlow, "%s", body) @@ -412,7 +413,7 @@ func TestCompleteLogin(t *testing.T) { assert.Empty(t, gjson.Get(body, "ui.nodes.#(attributes.name==password).attributes.value").String()) } - var values = func(v url.Values) { + values := func(v url.Values) { v.Set("password", "") v.Set("identifier", "") } @@ -431,7 +432,7 @@ func TestCompleteLogin(t *testing.T) { }) t.Run("should return an error because the credentials are invalid (password not correct)", func(t *testing.T) { - var check = func(t *testing.T, body string) { + check := func(t *testing.T, body string) { assert.NotEmpty(t, gjson.Get(body, "id").String(), "%s", body) assert.Contains(t, gjson.Get(body, "ui.action").String(), publicTS.URL+login.RouteSubmitFlow, "%s", body) @@ -449,7 +450,7 @@ func TestCompleteLogin(t *testing.T) { identifier, pwd := x.NewUUID().String(), "password" createIdentity(ctx, reg, t, identifier, pwd) - var values = func(v url.Values) { + values := func(v url.Values) { v.Set("identifier", identifier) v.Set("password", "not-password") } @@ -470,7 +471,7 @@ func TestCompleteLogin(t *testing.T) { identifier, pwd := x.NewUUID().String(), "password" createIdentity(ctx, reg, t, identifier, pwd) - var values = func(v url.Values) { + values := func(v url.Values) { v.Set("identifier", identifier) v.Set("password", pwd) } @@ -596,7 +597,7 @@ func TestCompleteLogin(t *testing.T) { assert.NotEmpty(t, st, "%s", body) t.Run("retry with different refresh", func(t *testing.T) { - c := &http.Client{Transport: x.NewTransportWithHeader(http.Header{"Authorization": {"Bearer " + st}})} + c := &http.Client{Transport: testhelpers.NewTransportWithHeader(t, http.Header{"Authorization": {"Bearer " + st}})} t.Run("redirect to returnTS if refresh is missing", func(t *testing.T) { res, err := c.Do(testhelpers.NewHTTPGetJSONRequest(t, publicTS.URL+login.RouteInitAPIFlow)) @@ -650,17 +651,17 @@ func TestCompleteLogin(t *testing.T) { t.Run("case=should return an error because not passing validation and reset previous errors and values", func(t *testing.T) { testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/login.schema.json") - var check = func(t *testing.T, actual string) { + check := func(t *testing.T, actual string) { assert.NotEmpty(t, gjson.Get(actual, "id").String(), "%s", actual) assert.Contains(t, gjson.Get(actual, "ui.action").String(), publicTS.URL+login.RouteSubmitFlow, "%s", actual) } - var checkFirst = func(t *testing.T, actual string) { + checkFirst := func(t *testing.T, actual string) { check(t, actual) assert.Contains(t, gjson.Get(actual, "ui.nodes.#(attributes.name==identifier).messages.0").String(), "Property identifier is missing.", "%s", actual) } - var checkSecond = func(t *testing.T, actual string) { + checkSecond := func(t *testing.T, actual string) { check(t, actual) assert.Empty(t, gjson.Get(actual, "ui.nodes.#(attributes.name==identifier).attributes.error")) @@ -670,13 +671,13 @@ func TestCompleteLogin(t *testing.T) { assert.Contains(t, gjson.Get(actual, "ui.nodes.#(attributes.name==password).messages.0").String(), "Property password is missing.", "%s", actual) } - var valuesFirst = func(v url.Values) url.Values { + valuesFirst := func(v url.Values) url.Values { v.Del("identifier") v.Set("password", x.NewUUID().String()) return v } - var valuesSecond = func(v url.Values) url.Values { + valuesSecond := func(v url.Values) url.Values { v.Set("identifier", "identifier") v.Del("password") return v @@ -709,8 +710,10 @@ func TestCompleteLogin(t *testing.T) { browserClient := testhelpers.NewClientWithCookies(t) f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, publicTS, false, false, false, false) - values := url.Values{"method": {"password"}, "identifier": {identifier}, - "password": {pwd}, "csrf_token": {x.FakeCSRFToken}}.Encode() + values := url.Values{ + "method": {"password"}, "identifier": {identifier}, + "password": {pwd}, "csrf_token": {x.FakeCSRFToken}, + }.Encode() body1, res := testhelpers.LoginMakeRequest(t, false, false, f, browserClient, values) assert.EqualValues(t, http.StatusOK, res.StatusCode) @@ -776,13 +779,13 @@ func TestCompleteLogin(t *testing.T) { identifier, pwd := x.NewUUID().String(), "password" createIdentity(ctx, reg, t, identifier, pwd) - var values = func(v url.Values) { + values := func(v url.Values) { v.Set("method", "password") v.Set("identifier", identifier) v.Set("password", pwd) } - var check = func(t *testing.T, body string) { + check := func(t *testing.T, body string) { assert.NotEmpty(t, gjson.Get(body, "id").String(), "%s", body) assert.Contains(t, gjson.Get(body, "ui.action").String(), publicTS.URL+login.RouteSubmitFlow, "%s", body) @@ -801,7 +804,6 @@ func TestCompleteLogin(t *testing.T) { t.Run("type=api", func(t *testing.T) { check(t, expectValidationError(t, true, false, false, values)) }) - }) t.Run("should upgrade password not primary hashing algorithm", func(t *testing.T) { @@ -836,7 +838,7 @@ func TestCompleteLogin(t *testing.T) { }, })) - var values = func(v url.Values) { + values := func(v url.Values) { v.Set("identifier", identifier) v.Set("method", identity.CredentialsTypePassword.String()) v.Set("password", pwd) diff --git a/session/handler_test.go b/session/handler_test.go index b565381a986c..b24644880cc7 100644 --- a/session/handler_test.go +++ b/session/handler_test.go @@ -73,7 +73,8 @@ func TestSessionWhoAmI(t *testing.T) { ID: x.NewUUID(), State: identity.StateActive, Credentials: map[identity.CredentialsType]identity.Credentials{ - identity.CredentialsTypePassword: {Type: identity.CredentialsTypePassword, + identity.CredentialsTypePassword: { + Type: identity.CredentialsTypePassword, Identifiers: []string{x.NewUUID().String()}, Config: []byte(`{"hashed_password":"$argon2id$v=19$m=32,t=2,p=4$cm94YnRVOW5jZzFzcVE4bQ$MNzk5BtR2vUhrp6qQEjRNw"}`), }, @@ -559,7 +560,7 @@ func TestHandlerAdminSessionManagement(t *testing.T) { return http.ErrUseLastResponse } - req := x.NewTestHTTPRequest(t, "GET", ts.URL+"/admin/sessions/whoami", nil) + req := testhelpers.NewTestHTTPRequest(t, "GET", ts.URL+"/admin/sessions/whoami", nil) res, err := client.Do(req) require.NoError(t, err) require.Equal(t, http.StatusTemporaryRedirect, res.StatusCode) @@ -1058,7 +1059,7 @@ func TestHandlerRefreshSessionBySessionID(t *testing.T) { }) t.Run("case=should return 404 when calling puplic server", func(t *testing.T) { - req := x.NewTestHTTPRequest(t, "PATCH", publicServer.URL+"/sessions/"+s.ID.String()+"/extend", nil) + req := testhelpers.NewTestHTTPRequest(t, "PATCH", publicServer.URL+"/sessions/"+s.ID.String()+"/extend", nil) res, err := publicServer.Client().Do(req) require.NoError(t, err) diff --git a/session/manager_http_test.go b/session/manager_http_test.go index c3b93b2d3c10..8a1e166da25c 100644 --- a/session/manager_http_test.go +++ b/session/manager_http_test.go @@ -108,8 +108,8 @@ func TestManagerHTTP(t *testing.T) { } t.Run("case=immutability", func(t *testing.T) { - cookie1 := getCookie(t, x.NewTestHTTPRequest(t, "GET", "https://baseurl.com/bar", nil)) - cookie2 := getCookie(t, x.NewTestHTTPRequest(t, "GET", "https://baseurl.com/bar", nil)) + cookie1 := getCookie(t, testhelpers.NewTestHTTPRequest(t, "GET", "https://baseurl.com/bar", nil)) + cookie2 := getCookie(t, testhelpers.NewTestHTTPRequest(t, "GET", "https://baseurl.com/bar", nil)) assert.NotEqual(t, cookie1.Value, cookie2.Value) }) @@ -151,7 +151,7 @@ func TestManagerHTTP(t *testing.T) { }) t.Run("suite=SessionAddAuthenticationMethod", func(t *testing.T) { - req := x.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) + req := testhelpers.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) conf, reg := internal.NewFastRegistryWithMocks(t) testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/identity.schema.json") @@ -214,7 +214,7 @@ func TestManagerHTTP(t *testing.T) { reg.RegisterPublicRoutes(context.Background(), rp) t.Run("case=valid", func(t *testing.T) { - req := x.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) + req := testhelpers.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) conf.MustSet(req.Context(), config.ViperKeySessionLifespan, "1m") i := identity.Identity{Traits: []byte("{}")} @@ -230,7 +230,7 @@ func TestManagerHTTP(t *testing.T) { }) t.Run("case=key rotation", func(t *testing.T) { - req := x.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) + req := testhelpers.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) original := conf.GetProvider(ctx).Strings(config.ViperKeySecretsCookie) t.Cleanup(func() { conf.MustSet(ctx, config.ViperKeySecretsCookie, original) @@ -256,7 +256,7 @@ func TestManagerHTTP(t *testing.T) { }) t.Run("case=no panic on invalid cookie name", func(t *testing.T) { - req := x.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) + req := testhelpers.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) conf.MustSet(ctx, config.ViperKeySessionLifespan, "1m") conf.MustSet(ctx, config.ViperKeySessionName, "$%˜\"") t.Cleanup(func() { @@ -279,7 +279,7 @@ func TestManagerHTTP(t *testing.T) { }) t.Run("case=valid bearer auth as fallback", func(t *testing.T) { - req := x.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) + req := testhelpers.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) conf.MustSet(ctx, config.ViperKeySessionLifespan, "1m") i := identity.Identity{Traits: []byte("{}"), State: identity.StateActive} @@ -300,7 +300,7 @@ func TestManagerHTTP(t *testing.T) { }) t.Run("case=valid x-session-token auth even if bearer is set", func(t *testing.T) { - req := x.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) + req := testhelpers.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) conf.MustSet(ctx, config.ViperKeySessionLifespan, "1m") i := identity.Identity{Traits: []byte("{}"), State: identity.StateActive} @@ -321,7 +321,7 @@ func TestManagerHTTP(t *testing.T) { }) t.Run("case=expired", func(t *testing.T) { - req := x.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) + req := testhelpers.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) conf.MustSet(ctx, config.ViperKeySessionLifespan, "1ns") t.Cleanup(func() { conf.MustSet(ctx, config.ViperKeySessionLifespan, "1m") @@ -342,7 +342,7 @@ func TestManagerHTTP(t *testing.T) { }) t.Run("case=revoked", func(t *testing.T) { - req := x.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) + req := testhelpers.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) i := identity.Identity{Traits: []byte("{}")} require.NoError(t, reg.PrivilegedIdentityPool().CreateIdentity(context.Background(), &i)) s, _ = session.NewActiveSession(req, &i, conf, time.Now(), identity.CredentialsTypePassword, identity.AuthenticatorAssuranceLevel1) @@ -365,7 +365,7 @@ func TestManagerHTTP(t *testing.T) { conf.MustSet(ctx, config.ViperKeySessionLifespan, "1m") t.Run("required_aal=aal2", func(t *testing.T) { - req := x.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) + req := testhelpers.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) run := func(t *testing.T, complete []identity.CredentialsType, requested string, i *identity.Identity, expectedError error) { s := session.NewInactiveSession() for _, m := range complete { @@ -594,7 +594,7 @@ func TestDoesSessionSatisfy(t *testing.T) { require.NoError(t, reg.PrivilegedIdentityPool().DeleteIdentity(context.Background(), id.ID)) }) - req := x.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) + req := testhelpers.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) s := session.NewInactiveSession() for _, m := range tc.amr { s.CompletedLoginFor(m.Method, m.AAL) diff --git a/session/session_test.go b/session/session_test.go index 6bb735c66c9d..4e1efe3b647a 100644 --- a/session/session_test.go +++ b/session/session_test.go @@ -9,8 +9,6 @@ import ( "testing" "time" - "github.com/ory/kratos/x" - "github.com/stretchr/testify/require" "github.com/stretchr/testify/assert" @@ -18,6 +16,7 @@ import ( "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/session" ) @@ -27,7 +26,7 @@ func TestSession(t *testing.T) { authAt := time.Now() t.Run("case=active session", func(t *testing.T) { - req := x.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) + req := testhelpers.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) i := new(identity.Identity) i.State = identity.StateActive @@ -60,7 +59,7 @@ func TestSession(t *testing.T) { }) t.Run("case=activate", func(t *testing.T) { - req := x.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) + req := testhelpers.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) s := session.NewInactiveSession() require.NoError(t, s.Activate(req, &identity.Identity{State: identity.StateActive}, conf, authAt)) @@ -94,7 +93,7 @@ func TestSession(t *testing.T) { }, } { t.Run("case=parse "+tc.input, func(t *testing.T) { - req := x.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) + req := testhelpers.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) req.Header["User-Agent"] = []string{"Mozilla/5.0 (X11; Linux x86_64)", "AppleWebKit/537.36 (KHTML, like Gecko)", "Chrome/51.0.2704.103 Safari/537.36"} req.Header.Set("X-Forwarded-For", tc.input) @@ -113,7 +112,7 @@ func TestSession(t *testing.T) { }) t.Run("case=client information reverse proxy real IP set", func(t *testing.T) { - req := x.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) + req := testhelpers.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) req.Header["User-Agent"] = []string{"Mozilla/5.0 (X11; Linux x86_64)", "AppleWebKit/537.36 (KHTML, like Gecko)", "Chrome/51.0.2704.103 Safari/537.36"} req.Header.Set("X-Real-IP", "54.155.246.155") req.Header["X-Forwarded-For"] = []string{"54.155.246.232", "10.145.1.10"} @@ -133,7 +132,7 @@ func TestSession(t *testing.T) { }) t.Run("case=client information CF true client IP set", func(t *testing.T) { - req := x.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) + req := testhelpers.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) req.Header["User-Agent"] = []string{"Mozilla/5.0 (X11; Linux x86_64)", "AppleWebKit/537.36 (KHTML, like Gecko)", "Chrome/51.0.2704.103 Safari/537.36"} req.Header.Set("True-Client-IP", "54.155.246.155") req.Header.Set("X-Forwarded-For", "217.73.188.139,162.158.203.149, 172.19.2.7") @@ -153,7 +152,7 @@ func TestSession(t *testing.T) { }) t.Run("case=client information CF", func(t *testing.T) { - req := x.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) + req := testhelpers.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) req.Header["User-Agent"] = []string{"Mozilla/5.0 (X11; Linux x86_64)", "AppleWebKit/537.36 (KHTML, like Gecko)", "Chrome/51.0.2704.103 Safari/537.36"} req.Header.Set("True-Client-IP", "54.155.246.232") req.Header.Set("Cf-Ipcity", "Munich") @@ -341,7 +340,7 @@ func TestSession(t *testing.T) { } t.Run("case=session refresh", func(t *testing.T) { - req := x.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) + req := testhelpers.NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) conf.MustSet(ctx, config.ViperKeySessionLifespan, "24h") conf.MustSet(ctx, config.ViperKeySessionRefreshMinTimeLeft, "12h") diff --git a/x/http.go b/x/http.go index 2ee9254f9827..380ca14a1034 100644 --- a/x/http.go +++ b/x/http.go @@ -5,11 +5,8 @@ package x import ( "context" - "io" "net/http" - "net/http/cookiejar" "net/url" - "testing" "github.com/ory/x/httpx" @@ -19,49 +16,9 @@ import ( "github.com/ory/herodot" - "github.com/stretchr/testify/require" - "github.com/ory/x/stringsx" ) -func NewTestHTTPRequest(t *testing.T, method, url string, body io.Reader) *http.Request { - req, err := http.NewRequest(method, url, body) - require.NoError(t, err) - return req -} - -func EasyGet(t *testing.T, c *http.Client, url string) (*http.Response, []byte) { - res, err := c.Get(url) - require.NoError(t, err) - defer res.Body.Close() - body, err := io.ReadAll(res.Body) - require.NoError(t, err) - return res, body -} - -func EasyGetJSON(t *testing.T, c *http.Client, url string) (*http.Response, []byte) { - req, err := http.NewRequest("GET", url, nil) - require.NoError(t, err) - req.Header.Set("Accept", "application/json") - res, err := c.Do(req) - require.NoError(t, err) - defer res.Body.Close() - body, err := io.ReadAll(res.Body) - require.NoError(t, err) - return res, body -} - -func EasyGetBody(t *testing.T, c *http.Client, url string) []byte { - _, body := EasyGet(t, c, url) // nolint: bodyclose - return body -} - -func EasyCookieJar(t *testing.T, o *cookiejar.Options) *cookiejar.Jar { - cj, err := cookiejar.New(o) - require.NoError(t, err) - return cj -} - func RequestURL(r *http.Request) *url.URL { source := *r.URL source.Host = stringsx.Coalesce(source.Host, r.Header.Get("X-Forwarded-Host"), r.Host) @@ -80,42 +37,6 @@ func RequestURL(r *http.Request) *url.URL { return &source } -func NewTransportWithHeader(h http.Header) *TransportWithHeader { - return &TransportWithHeader{ - RoundTripper: http.DefaultTransport, - h: h, - } -} - -type TransportWithHeader struct { - http.RoundTripper - h http.Header -} - -func (ct *TransportWithHeader) RoundTrip(req *http.Request) (*http.Response, error) { - for k := range ct.h { - req.Header.Set(k, ct.h.Get(k)) - } - return ct.RoundTripper.RoundTrip(req) -} - -func NewTransportWithHost(host string) *TransportWithHost { - return &TransportWithHost{ - RoundTripper: http.DefaultTransport, - host: host, - } -} - -type TransportWithHost struct { - http.RoundTripper - host string -} - -func (ct *TransportWithHost) RoundTrip(req *http.Request) (*http.Response, error) { - req.Host = ct.host - return ct.RoundTripper.RoundTrip(req) -} - func AcceptToRedirectOrJSON( w http.ResponseWriter, r *http.Request, writer herodot.Writer, out interface{}, redirectTo string, ) { From 18b89ea588d129fa88379f7b0d7f4fd00ec6023d Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Wed, 18 Oct 2023 13:20:18 +0200 Subject: [PATCH 156/282] fix: specify correct minimum versions in migratest --- persistence/sql/migratest/migration_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/persistence/sql/migratest/migration_test.go b/persistence/sql/migratest/migration_test.go index afa101987742..93513badc4c7 100644 --- a/persistence/sql/migratest/migration_test.go +++ b/persistence/sql/migratest/migration_test.go @@ -87,7 +87,7 @@ func TestMigrations_Postgres(t *testing.T) { t.Skip("skipping testing in short mode") } t.Parallel() - testDatabase(t, "postgres", dockertest.ConnectToTestPostgreSQLPop(t)) + testDatabase(t, "postgres", dockertest.ConnectPop(t, dockertest.RunTestPostgreSQLWithVersion(t, "11.8"))) } func TestMigrations_Mysql(t *testing.T) { @@ -95,7 +95,7 @@ func TestMigrations_Mysql(t *testing.T) { t.Skip("skipping testing in short mode") } t.Parallel() - testDatabase(t, "mysql", dockertest.ConnectToTestMySQLPop(t)) + testDatabase(t, "mysql", dockertest.ConnectPop(t, dockertest.RunTestMySQLWithVersion(t, "8.0.34"))) } func TestMigrations_Cockroach(t *testing.T) { @@ -103,7 +103,7 @@ func TestMigrations_Cockroach(t *testing.T) { t.Skip("skipping testing in short mode") } t.Parallel() - testDatabase(t, "cockroach", dockertest.ConnectToTestCockroachDBPop(t)) + testDatabase(t, "cockroach", dockertest.ConnectPop(t, dockertest.RunTestCockroachDBWithVersion(t, "latest-v23.1"))) } func testDatabase(t *testing.T, db string, c *pop.Connection) { From 9c8a25eb0d3e06df182565d3d959d57e5dccfed8 Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Fri, 29 Sep 2023 11:56:41 +0200 Subject: [PATCH 157/282] feat: webhook analytic events --- .github/workflows/ci.yaml | 2 +- Makefile | 2 +- embedx/config.schema.json | 5 + selfservice/hook/web_hook.go | 67 ++++-- selfservice/hook/web_hook_integration_test.go | 197 ++++++++++++++++-- x/events/events.go | 58 ++++++ 6 files changed, 285 insertions(+), 46 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index d03794b582e1..a99b8f5b2e80 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -91,7 +91,7 @@ jobs: GOGC: 100 with: args: --timeout 10m0s - version: v1.50.1 + version: v1.54.2 skip-go-installation: true skip-pkg-cache: true - name: Build Kratos diff --git a/Makefile b/Makefile index 1b8572d3cfe0..6720b30e44f1 100644 --- a/Makefile +++ b/Makefile @@ -49,7 +49,7 @@ docs/swagger: npx @redocly/openapi-cli preview-docs spec/swagger.json .bin/golangci-lint: Makefile - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -d -b .bin v1.52.2 + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -d -b .bin v1.54.2 .bin/hydra: Makefile bash <(curl https://raw.githubusercontent.com/ory/meta/master/install.sh) -d -b .bin hydra v2.2.0-rc.3 diff --git a/embedx/config.schema.json b/embedx/config.schema.json index 03898eec012b..0443ae5ae4f3 100644 --- a/embedx/config.schema.json +++ b/embedx/config.schema.json @@ -280,6 +280,11 @@ "default": false, "description": "Deprecated, please use `response.parse` instead. If enabled allows the web hook to interrupt / abort the self-service flow. It only applies to certain flows (registration/verification/login/settings) and requires a valid response format." }, + "emit_analytics_event": { + "type": "boolean", + "default": true, + "description": "Emit tracing events for this webhook on delivery or error" + }, "auth": { "type": "object", "title": "Auth mechanisms", diff --git a/selfservice/hook/web_hook.go b/selfservice/hook/web_hook.go index b5342ea7dbc1..a7b46415c67a 100644 --- a/selfservice/hook/web_hook.go +++ b/selfservice/hook/web_hook.go @@ -7,11 +7,13 @@ import ( "context" "encoding/json" "fmt" + "io" "net/http" + "net/http/httputil" "time" - "github.com/ory/herodot" - + "github.com/gofrs/uuid" + "github.com/hashicorp/go-retryablehttp" "github.com/pkg/errors" "github.com/tidwall/gjson" "go.opentelemetry.io/otel/attribute" @@ -20,10 +22,7 @@ import ( "go.opentelemetry.io/otel/trace" grpccodes "google.golang.org/grpc/codes" - "github.com/ory/kratos/ui/node" - "github.com/ory/x/jsonnetsecure" - "github.com/ory/x/otelx" - + "github.com/ory/herodot" "github.com/ory/kratos/identity" "github.com/ory/kratos/request" "github.com/ory/kratos/schema" @@ -35,7 +34,11 @@ import ( "github.com/ory/kratos/selfservice/flow/verification" "github.com/ory/kratos/session" "github.com/ory/kratos/text" + "github.com/ory/kratos/ui/node" "github.com/ory/kratos/x" + "github.com/ory/kratos/x/events" + "github.com/ory/x/jsonnetsecure" + "github.com/ory/x/otelx" ) var _ interface { @@ -221,10 +224,7 @@ func (e *WebHook) ExecutePostRegistrationPostPersistHook(_ http.ResponseWriter, // We want to decouple the request from the hook execution, so that the hooks still execute even // if the request is canceled. - var cancel context.CancelFunc - ctx := trace.ContextWithSpan(context.Background(), trace.SpanFromContext(req.Context())) - ctx, cancel = context.WithTimeout(ctx, 5*time.Minute) - defer cancel() + ctx := context.WithoutCancel(req.Context()) return otelx.WithSpan(ctx, "selfservice.hook.WebHook.ExecutePostRegistrationPostPersistHook", func(ctx context.Context) error { return e.execute(ctx, &templateContext{ @@ -288,6 +288,7 @@ func (e *WebHook) execute(ctx context.Context, data *templateContext) error { ignoreResponse = gjson.GetBytes(e.conf, "response.ignore").Bool() canInterrupt = gjson.GetBytes(e.conf, "can_interrupt").Bool() parseResponse = gjson.GetBytes(e.conf, "response.parse").Bool() + emitEvent = gjson.GetBytes(e.conf, "emit_analytics_event").Bool() || !gjson.GetBytes(e.conf, "emit_analytics_event").Exists() // default true tracer = trace.SpanFromContext(ctx).TracerProvider().Tracer("kratos-webhooks") ) if ignoreResponse && (parseResponse || canInterrupt) { @@ -296,27 +297,30 @@ func (e *WebHook) execute(ctx context.Context, data *templateContext) error { makeRequest := func() (finalErr error) { if ignoreResponse { - // This is one of the few places where spawning a context.Background() is ok. We need to do this - // because the function runs asynchronously and we don't want to cancel the request if the - // incoming request context is cancelled. + // This means we want to run this closure asynchronously and not be + // canceled when the parent context is canceled. // - // The webhook will still cancel after 30 seconds as that is the configured timeout for the HTTP client. - var cancel context.CancelFunc - ctx = trace.ContextWithSpan(context.Background(), trace.SpanFromContext(ctx)) - ctx, cancel = context.WithTimeout(ctx, 5*time.Minute) - defer cancel() + // The webhook will still cancel after 30 seconds as that is the + // configured timeout for the HTTP client. + ctx = context.WithoutCancel(ctx) } ctx, span := tracer.Start(ctx, "selfservice.webhook") defer otelx.End(span, &finalErr) - startTime := time.Now() - defer func() { + if emitEvent { + instrumentHTTPClientForEvents(ctx, httpClient) + } + + defer func(startTime time.Time) { traceID, spanID := span.SpanContext().TraceID(), span.SpanContext().SpanID() logger := e.deps.Logger().WithField("otel", map[string]string{ "trace_id": traceID.String(), "span_id": spanID.String(), }).WithField("duration", time.Since(startTime)) if finalErr != nil { + if emitEvent && !errors.Is(finalErr, context.Canceled) { + span.AddEvent(events.NewWebhookFailed(ctx, finalErr)) + } if ignoreResponse { logger.WithError(finalErr).Warning("Webhook request failed but the error was ignored because the configuration indicated that the upstream response should be ignored") } else { @@ -325,7 +329,7 @@ func (e *WebHook) execute(ctx context.Context, data *templateContext) error { } else { logger.Info("Webhook request succeeded") } - }() + }(time.Now()) builder, err := request.NewBuilder(ctx, e.conf, e.deps) if err != nil { @@ -372,6 +376,7 @@ func (e *WebHook) execute(ctx context.Context, data *templateContext) error { return errors.WithStack(err) } defer resp.Body.Close() + resp.Body = io.NopCloser(io.LimitReader(resp.Body, 5<<20)) // read at most 5 MB from the response span.SetAttributes(semconv.HTTPAttributesFromHTTPStatusCode(resp.StatusCode)...) if resp.StatusCode >= http.StatusBadRequest { @@ -499,3 +504,23 @@ func isTimeoutError(err error) bool { var te interface{ Timeout() bool } return errors.As(err, &te) && te.Timeout() || errors.Is(err, context.DeadlineExceeded) } + +func instrumentHTTPClientForEvents(ctx context.Context, httpClient *retryablehttp.Client) { + var ( + attempt = 0 + requestID uuid.UUID + reqBody []byte + ) + httpClient.RequestLogHook = func(_ retryablehttp.Logger, req *http.Request, retryNumber int) { + attempt = retryNumber + 1 + requestID = uuid.Must(uuid.NewV4()) + req.Header.Set("Ory-Webhook-Request-ID", requestID.String()) + reqBody, _ = httputil.DumpRequestOut(req, true) + } + httpClient.ResponseLogHook = func(_ retryablehttp.Logger, res *http.Response) { + res.Body = io.NopCloser(io.LimitReader(res.Body, 5<<20)) // read at most 5 MB from the response + resBody, _ := httputil.DumpResponse(res, true) + resBody = resBody[:min(len(resBody), 2<<10)] // truncate response body to 2 kB for event + trace.SpanFromContext(ctx).AddEvent(events.NewWebhookDelivered(ctx, res.Request.URL, reqBody, res.StatusCode, resBody, attempt, requestID)) + } +} diff --git a/selfservice/hook/web_hook_integration_test.go b/selfservice/hook/web_hook_integration_test.go index ebff7305c437..0670ecb170fd 100644 --- a/selfservice/hook/web_hook_integration_test.go +++ b/selfservice/hook/web_hook_integration_test.go @@ -19,39 +19,33 @@ import ( "testing" "time" - "github.com/ory/x/snapshotx" - + "github.com/julienschmidt/httprouter" "github.com/sirupsen/logrus/hooks/test" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - - "github.com/ory/kratos/schema" - "github.com/ory/kratos/text" - "github.com/ory/x/jsonnetsecure" - "github.com/ory/x/otelx" + sdktrace "go.opentelemetry.io/otel/sdk/trace" + "go.opentelemetry.io/otel/sdk/trace/tracetest" + "golang.org/x/exp/slices" "github.com/ory/kratos/driver/config" + "github.com/ory/kratos/identity" "github.com/ory/kratos/internal" - "github.com/ory/kratos/selfservice/hook" - "github.com/ory/kratos/ui/node" - "github.com/ory/x/logrusx" - + "github.com/ory/kratos/schema" + "github.com/ory/kratos/selfservice/flow" + "github.com/ory/kratos/selfservice/flow/login" "github.com/ory/kratos/selfservice/flow/recovery" "github.com/ory/kratos/selfservice/flow/registration" "github.com/ory/kratos/selfservice/flow/settings" "github.com/ory/kratos/selfservice/flow/verification" - - "github.com/ory/kratos/selfservice/flow" - - "github.com/julienschmidt/httprouter" - - "github.com/ory/kratos/identity" - "github.com/ory/kratos/x" - + "github.com/ory/kratos/selfservice/hook" "github.com/ory/kratos/session" - - "github.com/ory/kratos/selfservice/flow/login" - - "github.com/stretchr/testify/assert" + "github.com/ory/kratos/text" + "github.com/ory/kratos/ui/node" + "github.com/ory/kratos/x" + "github.com/ory/x/jsonnetsecure" + "github.com/ory/x/logrusx" + "github.com/ory/x/otelx" + "github.com/ory/x/snapshotx" ) func TestWebHooks(t *testing.T) { @@ -1131,3 +1125,160 @@ func TestAsyncWebhook(t *testing.T) { } require.True(t, found) } + +func TestWebhookEvents(t *testing.T) { + t.Parallel() + _, reg := internal.NewFastRegistryWithMocks(t) + logger := logrusx.New("kratos", "test") + whDeps := struct { + x.SimpleLoggerWithClient + *jsonnetsecure.TestProvider + }{ + x.SimpleLoggerWithClient{L: logger, C: reg.HTTPClient(context.Background()), T: otelx.NewNoop(logger, &otelx.Config{ServiceName: "kratos"})}, + jsonnetsecure.NewTestProvider(t), + } + + req := &http.Request{ + Header: map[string][]string{"Some-Header": {"Some-Value"}}, + Host: "www.ory.sh", + TLS: new(tls.ConnectionState), + URL: &url.URL{Path: "/some_end_point"}, + Method: http.MethodPost, + } + s := &session.Session{ID: x.NewUUID(), Identity: &identity.Identity{ID: x.NewUUID()}} + _ = s + f := &login.Flow{ID: x.NewUUID()} + + webhookReceiver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/ok" { + w.WriteHeader(200) + w.Write([]byte("ok")) + } else { + w.WriteHeader(400) + w.Write([]byte("fail")) + } + })) + t.Cleanup(webhookReceiver.Close) + + t.Run("sucess", func(t *testing.T) { + wh := hook.NewWebHook(&whDeps, json.RawMessage(fmt.Sprintf(` + { + "url": %q, + "method": "GET", + "body": "file://stub/test_body.jsonnet", + "response": { + "ignore": false, + "parse": false + } + }`, webhookReceiver.URL+"/ok"))) + + recorder := tracetest.NewSpanRecorder() + tracer := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(recorder)).Tracer("test") + ctx, span := tracer.Start(context.Background(), "parent") + defer span.End() + + r1 := req.Clone(ctx) + + require.NoError(t, wh.ExecuteLoginPreHook(nil, r1, f)) + + ended := recorder.Ended() + require.NotEmpty(t, ended) + + i := slices.IndexFunc(ended, func(sp sdktrace.ReadOnlySpan) bool { + return sp.Name() == "selfservice.webhook" + }) + require.GreaterOrEqual(t, i, 0) + + events := ended[i].Events() + i = slices.IndexFunc(events, func(ev sdktrace.Event) bool { + return ev.Name == "WebhookDelivered" + }) + require.GreaterOrEqual(t, i, 0) + + i = slices.IndexFunc(events, func(ev sdktrace.Event) bool { + return ev.Name == "WebhookFailed" + }) + require.Equal(t, -1, i) + }) + + t.Run("failed", func(t *testing.T) { + wh := hook.NewWebHook(&whDeps, json.RawMessage(fmt.Sprintf(` + { + "url": %q, + "method": "GET", + "body": "file://stub/test_body.jsonnet", + "response": { + "ignore": false, + "parse": false + } + }`, webhookReceiver.URL+"/fail"))) + + recorder := tracetest.NewSpanRecorder() + tracer := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(recorder)).Tracer("test") + ctx, span := tracer.Start(context.Background(), "parent") + defer span.End() + + r1 := req.Clone(ctx) + require.Error(t, wh.ExecuteLoginPreHook(nil, r1, f)) + + ended := recorder.Ended() + require.NotEmpty(t, ended) + + i := slices.IndexFunc(ended, func(sp sdktrace.ReadOnlySpan) bool { + return sp.Name() == "selfservice.webhook" + }) + require.GreaterOrEqual(t, i, 0) + + events := ended[i].Events() + i = slices.IndexFunc(events, func(ev sdktrace.Event) bool { + return ev.Name == "WebhookDelivered" + }) + require.GreaterOrEqual(t, i, 0) + + i = slices.IndexFunc(events, func(ev sdktrace.Event) bool { + return ev.Name == "WebhookFailed" + }) + require.GreaterOrEqual(t, i, 0) + }) + + t.Run("event disabled", func(t *testing.T) { + wh := hook.NewWebHook(&whDeps, json.RawMessage(fmt.Sprintf(` + { + "url": %q, + "method": "GET", + "body": "file://stub/test_body.jsonnet", + "response": { + "ignore": false, + "parse": false + }, + "emit_analytics_event": false + }`, webhookReceiver.URL+"/fail"))) + + recorder := tracetest.NewSpanRecorder() + tracer := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(recorder)).Tracer("test") + ctx, span := tracer.Start(context.Background(), "parent") + defer span.End() + + r1 := req.Clone(ctx) + require.Error(t, wh.ExecuteLoginPreHook(nil, r1, f)) + + ended := recorder.Ended() + require.NotEmpty(t, ended) + + i := slices.IndexFunc(ended, func(sp sdktrace.ReadOnlySpan) bool { + return sp.Name() == "selfservice.webhook" + }) + require.GreaterOrEqual(t, i, 0) + + events := ended[i].Events() + i = slices.IndexFunc(events, func(ev sdktrace.Event) bool { + return ev.Name == "WebhookDelivered" + }) + require.Equal(t, -1, i) + + i = slices.IndexFunc(events, func(ev sdktrace.Event) bool { + return ev.Name == "WebhookFailed" + }) + require.Equal(t, -1, i) + }) +} diff --git a/x/events/events.go b/x/events/events.go index 35992663319f..9a44adfb3860 100644 --- a/x/events/events.go +++ b/x/events/events.go @@ -5,6 +5,7 @@ package events import ( "context" + "net/url" "time" "github.com/gofrs/uuid" @@ -32,6 +33,8 @@ const ( VerificationSucceeded semconv.Event = "VerificationSucceeded" IdentityCreated semconv.Event = "IdentityCreated" IdentityUpdated semconv.Event = "IdentityUpdated" + WebhookDelivered semconv.Event = "WebhookDelivered" + WebhookFailed semconv.Event = "WebhookFailed" ) const ( @@ -43,6 +46,12 @@ const ( attributeKeyLoginRequestedAAL semconv.AttributeKey = "LoginRequestedAAL" attributeKeyLoginRequestedPrivilegedSession semconv.AttributeKey = "LoginRequestedPrivilegedSession" attributeKeyTokenizedSessionTTL semconv.AttributeKey = "TokenizedSessionTTL" + attributeKeyWebhookURL semconv.AttributeKey = "WebhookURL" + attributeKeyWebhookRequestBody semconv.AttributeKey = "WebhookRequestBody" + attributeKeyWebhookResponseBody semconv.AttributeKey = "WebhookResponseBody" + attributeKeyWebhookResponseStatusCode semconv.AttributeKey = "WebhookResponseStatusCode" + attributeKeyWebhookAttemptNumber semconv.AttributeKey = "WebhookAttemptNumber" + attributeKeyWebhookRequestID semconv.AttributeKey = "WebhookRequestID" ) func attrSessionID(val uuid.UUID) otelattr.KeyValue { @@ -77,6 +86,30 @@ func attrSelfServiceSSOProviderUsed(val string) otelattr.KeyValue { return otelattr.String(attributeKeySelfServiceSSOProviderUsed.String(), val) } +func attrWebhookURL(URL *url.URL) otelattr.KeyValue { + return otelattr.String(attributeKeyWebhookURL.String(), URL.Redacted()) +} + +func attrWebhookReq(body []byte) otelattr.KeyValue { + return otelattr.String(attributeKeyWebhookRequestBody.String(), string(body)) +} + +func attrWebhookRes(body []byte) otelattr.KeyValue { + return otelattr.String(attributeKeyWebhookResponseBody.String(), string(body)) +} + +func attrWebhookStatus(status int) otelattr.KeyValue { + return otelattr.Int(attributeKeyWebhookResponseStatusCode.String(), status) +} + +func attrWebhookAttempt(n int) otelattr.KeyValue { + return otelattr.Int(attributeKeyWebhookAttemptNumber.String(), n) +} + +func attrWebhookRequestID(id uuid.UUID) otelattr.KeyValue { + return otelattr.String(attributeKeyWebhookRequestID.String(), id.String()) +} + func NewSessionIssued(ctx context.Context, aal string, sessionID, identityID uuid.UUID) (string, trace.EventOption) { return SessionIssued.String(), trace.WithAttributes( @@ -263,3 +296,28 @@ func NewSessionJWTIssued(ctx context.Context, sessionID, identityID uuid.UUID, t )..., ) } + +func NewWebhookDelivered(ctx context.Context, URL *url.URL, reqBody []byte, status int, resBody []byte, attempt int, requestID uuid.UUID) (string, trace.EventOption) { + return WebhookDelivered.String(), + trace.WithAttributes( + append( + semconv.AttributesFromContext(ctx), + attrWebhookReq(reqBody), + attrWebhookRes(resBody), + attrWebhookStatus(status), + attrWebhookURL(URL), + attrWebhookAttempt(attempt), + attrWebhookRequestID(requestID), + )..., + ) +} + +func NewWebhookFailed(ctx context.Context, err error) (string, trace.EventOption) { + return WebhookFailed.String(), + trace.WithAttributes( + append( + semconv.AttributesFromContext(ctx), + otelattr.String("Error", err.Error()), + )..., + ) +} From aa8c93677a8f682f7693afe69f1baf1887355e0a Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Mon, 23 Oct 2023 12:31:59 +0200 Subject: [PATCH 158/282] feat: add WebhookSucceeded event --- selfservice/hook/web_hook.go | 3 +++ selfservice/hook/web_hook_integration_test.go | 17 ++++++++++++++++- x/events/events.go | 6 ++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/selfservice/hook/web_hook.go b/selfservice/hook/web_hook.go index a7b46415c67a..c06d47a216ba 100644 --- a/selfservice/hook/web_hook.go +++ b/selfservice/hook/web_hook.go @@ -328,6 +328,9 @@ func (e *WebHook) execute(ctx context.Context, data *templateContext) error { } } else { logger.Info("Webhook request succeeded") + if emitEvent { + span.AddEvent(events.NewWebhookSucceeded(ctx)) + } } }(time.Now()) diff --git a/selfservice/hook/web_hook_integration_test.go b/selfservice/hook/web_hook_integration_test.go index 0670ecb170fd..447ddbea4ef8 100644 --- a/selfservice/hook/web_hook_integration_test.go +++ b/selfservice/hook/web_hook_integration_test.go @@ -1160,7 +1160,7 @@ func TestWebhookEvents(t *testing.T) { })) t.Cleanup(webhookReceiver.Close) - t.Run("sucess", func(t *testing.T) { + t.Run("success", func(t *testing.T) { wh := hook.NewWebHook(&whDeps, json.RawMessage(fmt.Sprintf(` { "url": %q, @@ -1195,6 +1195,11 @@ func TestWebhookEvents(t *testing.T) { }) require.GreaterOrEqual(t, i, 0) + i = slices.IndexFunc(events, func(ev sdktrace.Event) bool { + return ev.Name == "WebhookSucceeded" + }) + require.GreaterOrEqual(t, i, 0) + i = slices.IndexFunc(events, func(ev sdktrace.Event) bool { return ev.Name == "WebhookFailed" }) @@ -1239,6 +1244,11 @@ func TestWebhookEvents(t *testing.T) { return ev.Name == "WebhookFailed" }) require.GreaterOrEqual(t, i, 0) + + i = slices.IndexFunc(events, func(ev sdktrace.Event) bool { + return ev.Name == "WebhookSucceeded" + }) + require.Equal(t, i, -1) }) t.Run("event disabled", func(t *testing.T) { @@ -1280,5 +1290,10 @@ func TestWebhookEvents(t *testing.T) { return ev.Name == "WebhookFailed" }) require.Equal(t, -1, i) + + i = slices.IndexFunc(events, func(ev sdktrace.Event) bool { + return ev.Name == "WebhookSucceeded" + }) + require.Equal(t, i, -1) }) } diff --git a/x/events/events.go b/x/events/events.go index 9a44adfb3860..52e921112d12 100644 --- a/x/events/events.go +++ b/x/events/events.go @@ -34,6 +34,7 @@ const ( IdentityCreated semconv.Event = "IdentityCreated" IdentityUpdated semconv.Event = "IdentityUpdated" WebhookDelivered semconv.Event = "WebhookDelivered" + WebhookSucceeded semconv.Event = "WebhookSucceeded" WebhookFailed semconv.Event = "WebhookFailed" ) @@ -312,6 +313,11 @@ func NewWebhookDelivered(ctx context.Context, URL *url.URL, reqBody []byte, stat ) } +func NewWebhookSucceeded(ctx context.Context) (string, trace.EventOption) { + return WebhookSucceeded.String(), + trace.WithAttributes(semconv.AttributesFromContext(ctx)...) +} + func NewWebhookFailed(ctx context.Context, err error) (string, trace.EventOption) { return WebhookFailed.String(), trace.WithAttributes( From 6a0a9149b9828ba994bec9b48a43f9d70245f43f Mon Sep 17 00:00:00 2001 From: Alano Terblanche <18033717+Benehiko@users.noreply.github.com> Date: Mon, 23 Oct 2023 17:24:57 +0200 Subject: [PATCH 159/282] fix: on verification required after registration, preserve return_to (#3589) * fix: on verification required after registration, preserve return_to * test: return_to on verification flow * chore: refactor Co-authored-by: Jonas Hungershausen --------- Co-authored-by: Jonas Hungershausen --- selfservice/flow/verification/flow.go | 6 +++- selfservice/flow/verification/flow_test.go | 2 +- selfservice/hook/show_verification_ui.go | 5 +-- selfservice/hook/verification.go | 34 ++++++++++++------- .../verification/registration/success.spec.ts | 21 ++++++++++++ 5 files changed, 51 insertions(+), 17 deletions(-) diff --git a/selfservice/flow/verification/flow.go b/selfservice/flow/verification/flow.go index 28a71e47a977..264e356da476 100644 --- a/selfservice/flow/verification/flow.go +++ b/selfservice/flow/verification/flow.go @@ -185,7 +185,11 @@ func NewPostHookFlow(conf *config.Config, exp time.Duration, csrf string, r *htt requestURL = new(url.URL) } query := requestURL.Query() - query.Set("return_to", query.Get("after_verification_return_to")) + // we need to keep the return_to in-tact if the `after_verification_return_to` is empty + // otherwise we take the `after_verification_return_to` query parameter over the current `return_to` + if afterVerificationReturn := query.Get("after_verification_return_to"); afterVerificationReturn != "" { + query.Set("return_to", afterVerificationReturn) + } query.Del("after_verification_return_to") requestURL.RawQuery = query.Encode() f.RequestURL = requestURL.String() diff --git a/selfservice/flow/verification/flow_test.go b/selfservice/flow/verification/flow_test.go index 3485f3454fc4..e05482ffa39d 100644 --- a/selfservice/flow/verification/flow_test.go +++ b/selfservice/flow/verification/flow_test.go @@ -108,7 +108,7 @@ func TestNewPostHookFlow(t *testing.T) { }) t.Run("case=return_to supplied", func(t *testing.T) { - expectReturnTo(t, url.Values{"return_to": {"http://foo.com/original_flow_callback"}}, "") + expectReturnTo(t, url.Values{"return_to": {"http://foo.com/original_flow_callback"}}, "http://foo.com/original_flow_callback") }) t.Run("case=return_to and after_verification_return_to supplied", func(t *testing.T) { diff --git a/selfservice/hook/show_verification_ui.go b/selfservice/hook/show_verification_ui.go index 1f7e83ce5c12..51f29a2aa6ce 100644 --- a/selfservice/hook/show_verification_ui.go +++ b/selfservice/hook/show_verification_ui.go @@ -59,9 +59,10 @@ func (e *ShowVerificationUIHook) execute(r *http.Request, f *registration.Flow) } } + ctx := r.Context() if vf != nil { - redir := e.d.Config().SelfServiceFlowVerificationUI(r.Context()) - f.ReturnToVerification = vf.AppendTo(redir).String() + redirURL := e.d.Config().SelfServiceFlowVerificationUI(ctx) + f.ReturnToVerification = vf.AppendTo(redirURL).String() } return nil diff --git a/selfservice/hook/verification.go b/selfservice/hook/verification.go index e041164f372d..c75cf1ce073b 100644 --- a/selfservice/hook/verification.go +++ b/selfservice/hook/verification.go @@ -70,29 +70,37 @@ func (e *Verifier) do( ) error { // This is called after the identity has been created so we can safely assume that all addresses are available // already. + ctx := r.Context() - strategy, err := e.r.GetActiveVerificationStrategy(r.Context()) + strategy, err := e.r.GetActiveVerificationStrategy(ctx) if err != nil { return err } + isBrowserFlow := f.GetType() == flow.TypeBrowser + isRegistrationFlow := f.GetFlowName() == flow.RegistrationFlow + for k := range i.VerifiableAddresses { address := &i.VerifiableAddresses[k] if address.Status != identity.VerifiableAddressStatusPending { continue } - csrf := "" + + var csrf string + // TODO: this is pretty ugly, we should probably have a better way to handle CSRF tokens here. - if f.GetType() != flow.TypeBrowser { - } else if _, ok := f.(*registration.Flow); ok { - // If this hook is executed from a registration flow, we need to regenerate the CSRF token. - csrf = e.r.CSRFHandler().RegenerateToken(w, r) - } else { - // If it came from a settings flow, there already is a CSRF token, so we can just use that. - csrf = e.r.GenerateCSRFToken(r) + if isBrowserFlow { + if isRegistrationFlow { + // If this hook is executed from a registration flow, we need to regenerate the CSRF token. + csrf = e.r.CSRFHandler().RegenerateToken(w, r) + } else { + // If it came from a settings flow, there already is a CSRF token, so we can just use that. + csrf = e.r.GenerateCSRFToken(r) + } } + verificationFlow, err := verification.NewPostHookFlow(e.r.Config(), - e.r.Config().SelfServiceFlowVerificationRequestLifespan(r.Context()), + e.r.Config().SelfServiceFlowVerificationRequestLifespan(ctx), csrf, r, strategy, f) if err != nil { return err @@ -108,17 +116,17 @@ func (e *Verifier) do( return err } - if err := e.r.VerificationFlowPersister().CreateVerificationFlow(r.Context(), verificationFlow); err != nil { + if err := e.r.VerificationFlowPersister().CreateVerificationFlow(ctx, verificationFlow); err != nil { return err } - if err := strategy.SendVerificationEmail(r.Context(), verificationFlow, i, address); err != nil { + if err := strategy.SendVerificationEmail(ctx, verificationFlow, i, address); err != nil { return err } flowURL := "" if verificationFlow.Type == flow.TypeBrowser { - flowURL = verificationFlow.AppendTo(e.r.Config().SelfServiceFlowVerificationUI(r.Context())).String() + flowURL = verificationFlow.AppendTo(e.r.Config().SelfServiceFlowVerificationUI(ctx)).String() } f.AddContinueWith(flow.NewContinueWithVerificationUI(verificationFlow, address.Value, flowURL)) diff --git a/test/e2e/cypress/integration/profiles/verification/registration/success.spec.ts b/test/e2e/cypress/integration/profiles/verification/registration/success.spec.ts index eac70c02e597..5065b5f2e30d 100644 --- a/test/e2e/cypress/integration/profiles/verification/registration/success.spec.ts +++ b/test/e2e/cypress/integration/profiles/verification/registration/success.spec.ts @@ -70,6 +70,7 @@ context("Account Verification Registration Success", () => { email, password, query: { + return_to: "http://localhost:4455/verification_return_to_callback", after_verification_return_to: "http://localhost:4455/verification_callback", }, @@ -83,6 +84,26 @@ context("Account Verification Registration Success", () => { }, }) }) + + it("is redirected to `return_to` after verification", () => { + cy.clearAllCookies() + const { email, password } = gen.identity() + cy.register({ + email, + password, + query: { + return_to: "http://localhost:4455/verification_return_to_callback", + }, + }) + cy.login({ email, password }) + cy.verifyEmail({ + expect: { + email, + password, + redirectTo: "http://localhost:4455/verification_return_to_callback", + }, + }) + }) }) }) }) From 1343bbbfa11ff3e7fcbc0f233b858d13fd40c66d Mon Sep 17 00:00:00 2001 From: Dawid Danieluk <32909532+nxy7@users.noreply.github.com> Date: Fri, 27 Oct 2023 11:45:00 +0200 Subject: [PATCH 160/282] fix: change shebangs and makefile from /bin/bash to /usr/bin/env bash (#3597) * makefile fix Signed-off-by: nxy7 * shebangs changed to /usr/bin/env bash Signed-off-by: nxy7 --------- Signed-off-by: nxy7 --- Makefile | 2 +- script/add-down-migrations.sh | 4 ++-- script/debug-entrypoint.sh | 2 +- script/test-envs.sh | 2 +- script/testenv.sh | 2 +- test/e2e/run.sh | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 6720b30e44f1..59fd30158bdb 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -SHELL=/bin/bash -o pipefail +SHELL=/usr/bin/env bash -o pipefail # EXECUTABLES = docker-compose docker node npm go # K := $(foreach exec,$(EXECUTABLES),\ diff --git a/script/add-down-migrations.sh b/script/add-down-migrations.sh index 57bf58254f66..d2339af7879b 100755 --- a/script/add-down-migrations.sh +++ b/script/add-down-migrations.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # This script adds empty down migrations for any migration that misses them. # Adding them is necessary because if the down migration is missing, the @@ -17,4 +17,4 @@ for f in $(find . -name "*.up.sql"); do echo "Adding empty down migration for $f" touch $dir/$migra_name.down.sql fi -done \ No newline at end of file +done diff --git a/script/debug-entrypoint.sh b/script/debug-entrypoint.sh index 28b0e15c1eab..7fd87d1a730f 100755 --- a/script/debug-entrypoint.sh +++ b/script/debug-entrypoint.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash FILE_CHANGE_LOG_FILE=/tmp/changes.log SERVICE_ARGS="$@" diff --git a/script/test-envs.sh b/script/test-envs.sh index 426034b99a62..28ba4e3d584e 100755 --- a/script/test-envs.sh +++ b/script/test-envs.sh @@ -1,4 +1,4 @@ -#! /bin/bash +#!/usr/bin/env bash export TEST_DATABASE_MYSQL="mysql://root:secret@(127.0.0.1:3444)/mysql?parseTime=true&multiStatements=true" export TEST_DATABASE_POSTGRESQL="postgres://postgres:secret@127.0.0.1:3445/postgres?sslmode=disable" diff --git a/script/testenv.sh b/script/testenv.sh index 671c5abc1b43..15977c10fc8b 100755 --- a/script/testenv.sh +++ b/script/testenv.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash docker rm -f kratos_test_database_mysql kratos_test_database_postgres kratos_test_database_cockroach kratos_test_hydra || true docker run --platform linux/amd64 --name kratos_test_database_mysql -p 3444:3306 -e MYSQL_ROOT_PASSWORD=secret -d mysql:8.0.34 diff --git a/test/e2e/run.sh b/test/e2e/run.sh index a5b405fe1d2e..863a70bb910b 100755 --- a/test/e2e/run.sh +++ b/test/e2e/run.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash echo "Running Ory Kratos E2E Tests..." echo "" From 3e3c78967523676cbce9a227d574c2f7f4ea314d Mon Sep 17 00:00:00 2001 From: Krzysztof Bogacki Date: Fri, 27 Oct 2023 11:45:15 +0200 Subject: [PATCH 161/282] fix: consider OIDC registration flows errored with duplicate credential to be completed by strategy (#3525) Returning anything else here may cause Kratos to respond with two concatenated JSON objects: new login flow with actual error message as the first one and a very confusing '500, aborted registration hook execution' as the second one. --- selfservice/strategy/oidc/strategy.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfservice/strategy/oidc/strategy.go b/selfservice/strategy/oidc/strategy.go index 70fa10585d18..8031868f993f 100644 --- a/selfservice/strategy/oidc/strategy.go +++ b/selfservice/strategy/oidc/strategy.go @@ -552,7 +552,7 @@ func (s *Strategy) handleError(w http.ResponseWriter, r *http.Request, f flow.Fl // return a new login flow with the error message embedded in the login flow. x.AcceptToRedirectOrJSON(w, r, s.d.Writer(), lf, lf.AppendTo(s.d.Config().SelfServiceFlowLoginUI(r.Context())).String()) // ensure the function does not continue to execute - return registration.ErrHookAbortFlow + return flow.ErrCompletedByStrategy } rf.UI.Nodes = node.Nodes{} From fdf4956d9218cfa1d2227c4880e48f9bbdaeb95d Mon Sep 17 00:00:00 2001 From: Ferdynand Naczynski Date: Fri, 27 Oct 2023 12:21:47 +0200 Subject: [PATCH 162/282] fix: return HTTP 400 if key unmarshal fails (#3594) * fix: return HTTP 400 if key unmarshal fails * fix: apply reviewer's suggestion, prepare for bump * fix: follow up reviewer suggestion from ory/x * chore: bump ory/x --- go.mod | 2 +- go.sum | 4 ++-- session/stub/jwk.es512.broken.json | 14 ++++++++++++++ session/tokenizer_test.go | 9 +++++++++ 4 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 session/stub/jwk.es512.broken.json diff --git a/go.mod b/go.mod index 2faa0b8e604e..1c3c89f958f1 100644 --- a/go.mod +++ b/go.mod @@ -75,7 +75,7 @@ require ( github.com/ory/jsonschema/v3 v3.0.8 github.com/ory/mail/v3 v3.0.0 github.com/ory/nosurf v1.2.7 - github.com/ory/x v0.0.595 + github.com/ory/x v0.0.597 github.com/peterhellberg/link v1.2.0 github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 github.com/pkg/errors v0.9.1 diff --git a/go.sum b/go.sum index 60177cd8b6ce..d1c3f65c3160 100644 --- a/go.sum +++ b/go.sum @@ -838,8 +838,8 @@ github.com/ory/nosurf v1.2.7 h1:YrHrbSensQyU6r6HT/V5+HPdVEgrOTMJiLoJABSBOp4= github.com/ory/nosurf v1.2.7/go.mod h1:d4L3ZBa7Amv55bqxCBtCs63wSlyaiCkWVl4vKf3OUxA= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2 h1:zm6sDvHy/U9XrGpixwHiuAwpp0Ock6khSVHkrv6lQQU= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/ory/x v0.0.595 h1:oh2/wLyyQ6hMaFblj9u0EGzrR5tEOmnp+2as+XkER9g= -github.com/ory/x v0.0.595/go.mod h1:ksLBEd6iW6czGpE6eNA0gCIxO1FFeqIxCZgsgwNrzMM= +github.com/ory/x v0.0.597 h1:msBfbEE5Ps8MXR3VxxIVUvei+f1o7cE/XKoIytuTqVQ= +github.com/ory/x v0.0.597/go.mod h1:ksLBEd6iW6czGpE6eNA0gCIxO1FFeqIxCZgsgwNrzMM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= diff --git a/session/stub/jwk.es512.broken.json b/session/stub/jwk.es512.broken.json new file mode 100644 index 000000000000..e645648bce1a --- /dev/null +++ b/session/stub/jwk.es512.broken.json @@ -0,0 +1,14 @@ +{ + "keys": [ + { + "use": "sig", + "kty": "EC", + "kid": "bc7f7afc-6742-427c-bb9e-164fe0f8b6a7", + "crv": "P-521", + "alg": "ES512", + "x": "ASj36HQOpsWiaGyzK1F0GkxXRt37R01M-OCWFk8rFqH8UnFBk0qnCmVYWv3pwVPPsN0CfFiaXTrV1gUSapkkDgWY", + "y": "ALf5bqXExUq6FzQNQg01hDhR2lOKzkrC02Bc6Alld8Zji3-echbimNZltoOi4MhXbSJeWHpU8wzb3v9XAAW4eovn", + "d": "ALP0Sf7cmcELc9CQ2bWd6Qs-YxMu0N9EYZhDmR6qbYdGnvv-lcGy_ySoEJD0vPMKagA8PHDvFhC7ORwP-sBIJ4O_" + } + ] + diff --git a/session/tokenizer_test.go b/session/tokenizer_test.go index bb69b222b83e..e6e1621e7cd8 100644 --- a/session/tokenizer_test.go +++ b/session/tokenizer_test.go @@ -10,6 +10,8 @@ import ( "testing" "time" + "github.com/ory/herodot" + "github.com/gofrs/uuid" "github.com/golang-jwt/jwt/v5" "github.com/lestrrat-go/jwx/jwk" @@ -115,4 +117,11 @@ func TestTokenizer(t *testing.T) { snapshotx.SnapshotT(t, token.Claims, snapshotx.ExceptPaths("jti")) }) + + t.Run("case=rs512-with-broken-keyfile", func(t *testing.T) { + tid := "rs512-template" + setTokenizeConfig(conf, tid, "jwk.es512.broken.json", "file://stub/rs512-template.jsonnet") + err := tkn.TokenizeSession(ctx, tid, s) + require.ErrorIs(t, err, herodot.ErrBadRequest) + }) } From 985474c600a202f73763292fbb816950c1687afd Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Fri, 27 Oct 2023 11:36:37 +0000 Subject: [PATCH 163/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 51 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 636f28017155..98725d9b1c75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-10-19)](#2023-10-19) +- [ (2023-10-27)](#2023-10-27) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -313,7 +313,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-10-19) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-10-27) ## Breaking Changes @@ -406,9 +406,27 @@ https://github.com/ory/kratos/pull/3480 - Change ListIdentities to keyset pagination ([e16fed1](https://github.com/ory/kratos/commit/e16fed1f8563509aac30886386668bb85e6dc797)) +- Change shebangs and makefile from /bin/bash to /usr/bin/env bash + ([#3597](https://github.com/ory/kratos/issues/3597)) + ([1343bbb](https://github.com/ory/kratos/commit/1343bbbfa11ff3e7fcbc0f233b858d13fd40c66d)): + + - makefile fix + + - shebangs changed to /usr/bin/env bash + + Signed-off-by: nxy7 + - Code method on registration and 2fa ([#3481](https://github.com/ory/kratos/issues/3481)) ([7aa2e29](https://github.com/ory/kratos/commit/7aa2e293175d0f4b6c13552cc3781f54f8caf3a0)) +- Consider OIDC registration flows errored with duplicate credential to be + completed by strategy ([#3525](https://github.com/ory/kratos/issues/3525)) + ([3e3c789](https://github.com/ory/kratos/commit/3e3c78967523676cbce9a227d574c2f7f4ea314d)): + + Returning anything else here may cause Kratos to respond with two concatenated + JSON objects: new login flow with actual error message as the first one and a + very confusing '500, aborted registration hook execution' as the second one. + - Data race in test ([ab6dc31](https://github.com/ory/kratos/commit/ab6dc3121535d27668fed58804a218b17b17ae43)) - Do not encode full config in multiple places @@ -471,6 +489,16 @@ https://github.com/ory/kratos/pull/3480 The identity is not always available in the session struct, for example when AAL2 is required. +- On verification required after registration, preserve return_to + ([#3589](https://github.com/ory/kratos/issues/3589)) + ([6a0a914](https://github.com/ory/kratos/commit/6a0a9149b9828ba994bec9b48a43f9d70245f43f)): + + - fix: on verification required after registration, preserve return_to + + - test: return_to on verification flow + + - chore: refactor + - Pass context ([#3452](https://github.com/ory/kratos/issues/3452)) ([c492bdc](https://github.com/ory/kratos/commit/c492bdcd0c5dbdf527ae523d879a6c1eeb9c4cdf)) - Properly normalize OIDC verified emails @@ -527,8 +555,22 @@ https://github.com/ory/kratos/pull/3480 - Return 400 bad request for invalid login challenge ([#3404](https://github.com/ory/kratos/issues/3404)) ([ca34e9b](https://github.com/ory/kratos/commit/ca34e9b744482b41d65082f3bed52e9c4ebd7ba4)) +- Return HTTP 400 if key unmarshal fails + ([#3594](https://github.com/ory/kratos/issues/3594)) + ([fdf4956](https://github.com/ory/kratos/commit/fdf4956d9218cfa1d2227c4880e48f9bbdaeb95d)): + + - fix: return HTTP 400 if key unmarshal fails + + - fix: apply reviewer's suggestion, prepare for bump + + - fix: follow up reviewer suggestion from ory/x + + - chore: bump ory/x + - Schema test errors ([#3528](https://github.com/ory/kratos/issues/3528)) ([bee0341](https://github.com/ory/kratos/commit/bee0341c5bf5708a2210146fc59f050a1b9df663)) +- Specify correct minimum versions in migratest + ([18b89ea](https://github.com/ory/kratos/commit/18b89ea588d129fa88379f7b0d7f4fd00ec6023d)) - Tracing improvements ([c804cb2](https://github.com/ory/kratos/commit/c804cb2bebbefc97073cf3b8fa250c3eefc58894)) - Type-assert all interfaces that WebHook implements @@ -599,6 +641,8 @@ https://github.com/ory/kratos/pull/3480 - Add OpenTelemetry span for password hash comparison ([#3383](https://github.com/ory/kratos/issues/3383)) ([e3fcf0c](https://github.com/ory/kratos/commit/e3fcf0c31db9742ed61bcf783e37ee119ed19d42)) +- Add WebhookSucceeded event + ([aa8c936](https://github.com/ory/kratos/commit/aa8c93677a8f682f7693afe69f1baf1887355e0a)) - Added various new text messages ([ea91483](https://github.com/ory/kratos/commit/ea914834e6bb626de2977e228af2b40935ccc980)): @@ -811,6 +855,9 @@ https://github.com/ory/kratos/pull/3480 - fix: upgrade hydra in tests +- Webhook analytic events + ([9c8a25e](https://github.com/ory/kratos/commit/9c8a25eb0d3e06df182565d3d959d57e5dccfed8)) + ### Tests - **e2e:** Logout return_to ([#3418](https://github.com/ory/kratos/issues/3418)) From 7a47827cfd58ef68ebfbbeaf5ed86c394ba2bd5e Mon Sep 17 00:00:00 2001 From: Alano Terblanche <18033717+Benehiko@users.noreply.github.com> Date: Mon, 30 Oct 2023 11:42:19 +0100 Subject: [PATCH 164/282] fix: registration should accept hydra login (#3592) * fix: registration should accept hydra login * fix: oauth2 registration flow with session * wip: registration oauth flow tests * wip: refactor oauth flows test * wip: refactor op_registration_test * wip: oauth provider registration test * wip: refactor oauth flows test * fix(test): oauth provider login * style: format --- hydra/fake.go | 12 +- internal/testhelpers/selfservice_login.go | 7 + .../testhelpers/selfservice_registration.go | 7 + selfservice/flow/registration/flow_test.go | 6 +- selfservice/flow/registration/handler.go | 87 +- selfservice/flow/registration/handler_test.go | 32 + .../strategy/password/op_helpers_test.go | 221 ++++ .../strategy/password/op_login_test.go | 950 ++++++++++++---- .../strategy/password/op_registration_test.go | 1011 +++++++++++++---- .../oidc-provider/registration.spec.ts | 118 +- 10 files changed, 1986 insertions(+), 465 deletions(-) create mode 100644 selfservice/strategy/password/op_helpers_test.go diff --git a/hydra/fake.go b/hydra/fake.go index 9050833bb64b..ef27af19932e 100644 --- a/hydra/fake.go +++ b/hydra/fake.go @@ -19,12 +19,17 @@ const ( var ErrFakeAcceptLoginRequestFailed = errors.New("failed to accept login request") -type FakeHydra struct{} +type FakeHydra struct { + Skip bool + RequestURL string +} var _ Hydra = &FakeHydra{} func NewFake() *FakeHydra { - return &FakeHydra{} + return &FakeHydra{ + RequestURL: "https://www.ory.sh", + } } func (h *FakeHydra) AcceptLoginRequest(_ context.Context, params AcceptLoginRequestParams) (string, error) { @@ -47,7 +52,8 @@ func (h *FakeHydra) GetLoginRequest(_ context.Context, loginChallenge string) (* return nil, herodot.ErrBadRequest.WithReasonf("Unable to get OAuth 2.0 Login Challenge.") case FakeValidLoginChallenge: return &hydraclientgo.OAuth2LoginRequest{ - RequestUrl: "https://www.ory.sh", + RequestUrl: h.RequestURL, + Skip: h.Skip, }, nil default: panic("unknown fake login_challenge " + loginChallenge) diff --git a/internal/testhelpers/selfservice_login.go b/internal/testhelpers/selfservice_login.go index f9766d7bb905..bedba03fee16 100644 --- a/internal/testhelpers/selfservice_login.go +++ b/internal/testhelpers/selfservice_login.go @@ -193,6 +193,13 @@ func LoginMakeRequest( return string(ioutilx.MustReadAll(res.Body)), res } +func GetLoginFlow(t *testing.T, client *http.Client, ts *httptest.Server, flowID string) *kratos.LoginFlow { + publicClient := NewSDKCustomClient(ts, client) + rs, _, err := publicClient.FrontendApi.GetLoginFlow(context.Background()).Id(flowID).Execute() + require.NoError(t, err) + return rs +} + // SubmitLoginForm initiates a login flow (for Browser and API!), fills out the form and modifies // the form values with `withValues`, and submits the form. Returns the body and checks for expectedStatusCode and // expectedURL on completion diff --git a/internal/testhelpers/selfservice_registration.go b/internal/testhelpers/selfservice_registration.go index e285f8f8b2bd..0cab8517e541 100644 --- a/internal/testhelpers/selfservice_registration.go +++ b/internal/testhelpers/selfservice_registration.go @@ -83,6 +83,13 @@ func InitializeRegistrationFlowViaAPI(t *testing.T, client *http.Client, ts *htt return rs } +func GetRegistrationFlow(t *testing.T, client *http.Client, ts *httptest.Server, flowID string) *kratos.RegistrationFlow { + rs, _, err := NewSDKCustomClient(ts, client).FrontendApi.GetRegistrationFlow(context.Background()).Id(flowID).Execute() + require.NoError(t, err) + assert.Empty(t, rs.Active) + return rs +} + func RegistrationMakeRequest( t *testing.T, isAPI bool, diff --git a/selfservice/flow/registration/flow_test.go b/selfservice/flow/registration/flow_test.go index d72e0c437921..aa199becd6b5 100644 --- a/selfservice/flow/registration/flow_test.go +++ b/selfservice/flow/registration/flow_test.go @@ -68,7 +68,8 @@ func TestNewFlow(t *testing.T) { t.Run("case=1", func(t *testing.T) { r, err := registration.NewFlow(conf, 0, "csrf", &http.Request{ URL: urlx.ParseOrPanic("/?refresh=true"), - Host: "ory.sh"}, flow.TypeAPI) + Host: "ory.sh", + }, flow.TypeAPI) require.NoError(t, err) assert.Equal(t, r.IssuedAt, r.ExpiresAt) assert.Equal(t, flow.TypeAPI, r.Type) @@ -78,7 +79,8 @@ func TestNewFlow(t *testing.T) { t.Run("case=2", func(t *testing.T) { r, err := registration.NewFlow(conf, 0, "csrf", &http.Request{ URL: urlx.ParseOrPanic("https://ory.sh/"), - Host: "ory.sh"}, flow.TypeBrowser) + Host: "ory.sh", + }, flow.TypeBrowser) require.NoError(t, err) assert.Equal(t, "https://ory.sh/", r.RequestURL) }) diff --git a/selfservice/flow/registration/handler.go b/selfservice/flow/registration/handler.go index d58ff4c9e735..2857fa459ee5 100644 --- a/selfservice/flow/registration/handler.go +++ b/selfservice/flow/registration/handler.go @@ -27,10 +27,10 @@ import ( "github.com/ory/x/sqlxx" "github.com/ory/x/urlx" + hydraclientgo "github.com/ory/hydra-client-go/v2" "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" ) @@ -318,27 +318,78 @@ type createBrowserRegistrationFlow struct { // 303: emptyResponse // default: errorGeneric func (h *Handler) createBrowserRegistrationFlow(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + ctx := r.Context() + a, err := h.NewRegistrationFlow(w, r, flow.TypeBrowser) if err != nil { - h.d.SelfServiceErrorManager().Forward(r.Context(), w, r, err) + h.d.SelfServiceErrorManager().Forward(ctx, w, r, err) return } - 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() + var ( + hydraLoginRequest *hydraclientgo.OAuth2LoginRequest + hydraLoginChallenge sqlxx.NullString + ) + if r.URL.Query().Has("login_challenge") { + var err error + hydraLoginChallenge, err = hydra.GetLoginChallengeID(h.d.Config(), r) + if err != nil { + h.d.SelfServiceErrorManager().Forward(ctx, w, r, err) + return + } + + hydraLoginRequest, err = h.d.Hydra().GetLoginRequest(ctx, hydraLoginChallenge.String()) + if err != nil { + h.d.SelfServiceErrorManager().Forward(ctx, w, r, err) + return + } + + // on OAuth2 flows, we need to use the RequestURL + // as the ReturnTo URL. + // This is because a user might want to switch between + // different flows, such as login to registration and login to recovery. + // After completing a complex flow, such as recovery, we want the user + // to be redirected back to the original OAuth2 login flow. + if hydraLoginRequest.RequestUrl != "" && h.d.Config().OAuth2ProviderOverrideReturnTo(r.Context()) { + q := r.URL.Query() + // replace the return_to query parameter + q.Set("return_to", hydraLoginRequest.RequestUrl) + r.URL.RawQuery = q.Encode() + } + } + if sess, err := h.d.SessionManager().FetchFromRequest(ctx, r); err == nil { + if hydraLoginRequest != nil { + if hydraLoginRequest.GetSkip() { + rt, err := h.d.Hydra().AcceptLoginRequest(r.Context(), + hydra.AcceptLoginRequestParams{ + LoginChallenge: string(hydraLoginChallenge), + IdentityID: sess.IdentityID.String(), + SessionID: sess.ID.String(), + AuthenticationMethods: 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 + } + + // hydra indicates that we cannot skip the login request + // so we must perform the login flow. + // we directly go to the login handler from here + // copy over any query parameters, such as `return_to` and `login_challenge` + loginURL := urlx.CopyWithQuery(urlx.AppendPaths(h.d.Config().SelfPublicURL(ctx), "/self-service/login/browser"), x.RequestURL(r).Query()) http.Redirect( w, r, - urlx.CopyWithQuery(logoutUrl, url.Values{ - "token": {sess.LogoutToken}, - "return_to": {self}, - }).String(), + loginURL.String(), http.StatusFound, ) return @@ -349,12 +400,12 @@ func (h *Handler) createBrowserRegistrationFlow(w http.ResponseWriter, r *http.R 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())), + returnTo, redirErr := x.SecureRedirectTo(r, h.d.Config().SelfServiceBrowserDefaultReturnTo(ctx), + x.SecureRedirectAllowSelfServiceURLs(h.d.Config().SelfPublicURL(ctx)), + x.SecureRedirectAllowURLs(h.d.Config().SelfServiceBrowserAllowedReturnToDomains(ctx)), ) if redirErr != nil { - h.d.SelfServiceErrorManager().Forward(r.Context(), w, r, redirErr) + h.d.SelfServiceErrorManager().Forward(ctx, w, r, redirErr) return } @@ -362,7 +413,7 @@ func (h *Handler) createBrowserRegistrationFlow(w http.ResponseWriter, r *http.R return } - redirTo := a.AppendTo(h.d.Config().SelfServiceFlowRegistrationUI(r.Context())).String() + redirTo := a.AppendTo(h.d.Config().SelfServiceFlowRegistrationUI(ctx)).String() x.AcceptToRedirectOrJSON(w, r, h.d.Writer(), a, redirTo) } diff --git a/selfservice/flow/registration/handler_test.go b/selfservice/flow/registration/handler_test.go index 2bdfeb6e8540..1dac094b91c6 100644 --- a/selfservice/flow/registration/handler_test.go +++ b/selfservice/flow/registration/handler_test.go @@ -20,6 +20,7 @@ import ( "github.com/gofrs/uuid" "github.com/ory/kratos/corpx" + "github.com/ory/kratos/hydra" "github.com/ory/x/urlx" "github.com/stretchr/testify/assert" @@ -32,6 +33,7 @@ import ( "github.com/ory/kratos/identity" "github.com/ory/kratos/internal" "github.com/ory/kratos/internal/testhelpers" + "github.com/ory/kratos/selfservice/flow/login" "github.com/ory/kratos/selfservice/flow/registration" "github.com/ory/kratos/selfservice/strategy/oidc" "github.com/ory/kratos/selfservice/strategy/password" @@ -45,6 +47,8 @@ func init() { func TestHandlerRedirectOnAuthenticated(t *testing.T) { ctx := context.Background() conf, reg := internal.NewFastRegistryWithMocks(t) + fakeHydra := hydra.NewFake() + reg.WithHydra(fakeHydra) router := x.NewRouterPublic() ts, _ := testhelpers.NewKratosServerWithRouters(t, reg, router, x.NewRouterAdmin()) @@ -74,6 +78,34 @@ func TestHandlerRedirectOnAuthenticated(t *testing.T) { assert.Contains(t, res.Request.URL.String(), returnToTS.URL) assert.EqualValues(t, "return_to", string(body)) }) + + t.Run("oauth2 with session and skip=false is redirected to login", func(t *testing.T) { + conf.MustSet(ctx, config.ViperKeyOAuth2ProviderURL, "https://fake-hydra") + + fakeHydra.RequestURL = "https://www.ory.sh/oauth2/auth?audience=&client_id=foo&login_verifier=" + fakeHydra.Skip = false + + client := testhelpers.NewClientWithCookies(t) + client.CheckRedirect = func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + } + _, res := testhelpers.MockMakeAuthenticatedRequestWithClient(t, reg, conf, router.Router, testhelpers.NewTestHTTPRequest(t, "GET", ts.URL+registration.RouteInitBrowserFlow+"?login_challenge="+hydra.FakeValidLoginChallenge, nil), client) + assert.Contains(t, res.Header.Get("location"), login.RouteInitBrowserFlow) + }) + + t.Run("oauth2 with session and skip=true is accepted", func(t *testing.T) { + conf.MustSet(ctx, config.ViperKeyOAuth2ProviderURL, "https://fake-hydra") + + fakeHydra.Skip = true + fakeHydra.RequestURL = "https://www.ory.sh/oauth2/auth?audience=&client_id=foo&login_verifier=" + + client := testhelpers.NewClientWithCookies(t) + client.CheckRedirect = func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + } + _, res := testhelpers.MockMakeAuthenticatedRequestWithClient(t, reg, conf, router.Router, testhelpers.NewTestHTTPRequest(t, "GET", ts.URL+registration.RouteInitBrowserFlow+"?login_challenge="+hydra.FakeValidLoginChallenge, nil), client) + assert.Contains(t, res.Header.Get("location"), hydra.FakePostLoginURL) + }) } func TestInitFlow(t *testing.T) { diff --git a/selfservice/strategy/password/op_helpers_test.go b/selfservice/strategy/password/op_helpers_test.go new file mode 100644 index 000000000000..824de913be69 --- /dev/null +++ b/selfservice/strategy/password/op_helpers_test.go @@ -0,0 +1,221 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package password_test + +import ( + "context" + "fmt" + "io" + "net/http" + "net/http/httptest" + "testing" + "time" + + "golang.org/x/oauth2" + + "github.com/gofrs/uuid" + "github.com/pkg/errors" + "github.com/stretchr/testify/require" + + "github.com/ory/dockertest/v3" + "github.com/ory/dockertest/v3/docker" + hydraclientgo "github.com/ory/hydra-client-go/v2" + "github.com/ory/x/logrusx" + "github.com/ory/x/resilience" + "github.com/ory/x/urlx" + + "github.com/phayes/freeport" +) + +type clientAppConfig struct { + client *oauth2.Config + expectToken bool + state *clientAppState +} + +type clientAppState struct { + visits int64 + tokens int64 +} + +type callTrace string + +const ( + RegistrationUI callTrace = "registration-ui" + RegistrationWithOAuth2LoginChallenge = "registration-with-oauth2-login-challenge" + RegistrationWithFlowID = "registration-with-flow-id" + LoginUI = "login-ui" + LoginWithOAuth2LoginChallenge = "login-with-oauth2-login-challenge" + LoginWithFlowID = "login-with-flow-id" + Consent = "consent" + ConsentWithChallenge = "consent-with-challenge" + ConsentAccept = "consent-accept" + ConsentSkip = "consent-skip" + ConsentClientSkip = "consent-client-skip" + CodeExchange = "code-exchange" + CodeExchangeWithToken = "code-exchange-with-token" +) + +type testContextKey string + +const ( + TestUIConfig testContextKey = "test-ui-config" + TestOAuthClientState = "test-oauth-client-state" +) + +type testConfig struct { + identifier string + password string + browserClient *http.Client + kratosPublicTS *httptest.Server + clientAppTS *httptest.Server + hydraAdminClient hydraclientgo.OAuth2Api + consentRemember bool + requestedScope []string + callTrace *[]callTrace +} + +func createHydraOAuth2ApiClient(url string) hydraclientgo.OAuth2Api { + configuration := hydraclientgo.NewConfiguration() + configuration.Host = urlx.ParseOrPanic(url).Host + configuration.Servers = hydraclientgo.ServerConfigurations{{URL: url}} + + return hydraclientgo.NewAPIClient(configuration).OAuth2Api +} + +func createOAuth2Client(t *testing.T, ctx context.Context, hydraAdmin hydraclientgo.OAuth2Api, redirectURIs []string, scope string, skipConsent bool) string { + t.Helper() + + 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, + SkipConsent: &skipConsent, + }, + ).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 { + t.Helper() + + 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) + + hydraResource, err := pool.RunWithOptions(&dockertest.RunOptions{ + Repository: "oryd/hydra", + Tag: "v2.2.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", + "SECRETS_SYSTEM=someverylongsecretthatis32byteslong", + }, + 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, hydraResource.Close()) + }) + + require.NoError(t, hydraResource.Expire(uint(60*5))) + + require.NotEmpty(t, hydraResource.GetPort("4444/tcp"), "%+v", hydraResource.Container.NetworkSettings.Ports) + require.NotEmpty(t, hydraResource.GetPort("4445/tcp"), "%+v", hydraResource.Container) + + hydraPublic = "http://127.0.0.1:" + hydraResource.GetPort("4444/tcp") + hydraAdmin = "http://127.0.0.1:" + hydraResource.GetPort("4445/tcp") + + go pool.Client.Logs(docker.LogsOptions{ + ErrorStream: TestLogWriter{T: t, streamName: "hydra-stderr"}, + OutputStream: TestLogWriter{T: t, streamName: "hydra-stdout"}, + Stdout: false, + Stderr: true, + Follow: true, + Container: hydraResource.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 doOAuthFlow(t *testing.T, ctx context.Context, oauthClient *oauth2.Config, browserClient *http.Client) { + t.Helper() + + authCodeURL := makeAuthCodeURL(t, oauthClient, "", false) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, authCodeURL, nil) + require.NoError(t, err) + res, err := browserClient.Do(req) + require.NoError(t, err) + + body, err := io.ReadAll(res.Body) + require.NoError(t, err) + + require.NoError(t, res.Body.Close()) + require.Equal(t, "", string(body)) + require.Equal(t, http.StatusOK, res.StatusCode) +} diff --git a/selfservice/strategy/password/op_login_test.go b/selfservice/strategy/password/op_login_test.go index 21e81395d62d..64232072d736 100644 --- a/selfservice/strategy/password/op_login_test.go +++ b/selfservice/strategy/password/op_login_test.go @@ -7,27 +7,19 @@ import ( "context" _ "embed" "fmt" - "io" "net/http" "net/url" + "strings" "sync/atomic" "testing" - "time" - "github.com/phayes/freeport" - "github.com/pkg/errors" + "github.com/julienschmidt/httprouter" "github.com/tidwall/gjson" + "github.com/urfave/negroni" "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/v2" "github.com/stretchr/testify/assert" @@ -38,131 +30,10 @@ import ( "github.com/ory/kratos/identity" "github.com/ory/kratos/internal" "github.com/ory/kratos/internal/testhelpers" + "github.com/ory/kratos/selfservice/flow/login" "github.com/ory/kratos/x" ) -func createHydraOAuth2ApiClient(url string) hydraclientgo.OAuth2Api { - configuration := hydraclientgo.NewConfiguration() - configuration.Host = urlx.ParseOrPanic(url).Host - configuration.Servers = hydraclientgo.ServerConfigurations{{URL: url}} - - return hydraclientgo.NewAPIClient(configuration).OAuth2Api -} - -func createOAuth2Client(t *testing.T, ctx context.Context, hydraAdmin hydraclientgo.OAuth2Api, 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) - - hydraResource, err := pool.RunWithOptions(&dockertest.RunOptions{ - Repository: "oryd/hydra", - Tag: "v2.2.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", - "SECRETS_SYSTEM=someverylongsecretthatis32byteslong", - }, - 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, hydraResource.Close()) - }) - - require.NoError(t, hydraResource.Expire(uint(60*5))) - - require.NotEmpty(t, hydraResource.GetPort("4444/tcp"), "%+v", hydraResource.Container.NetworkSettings.Ports) - require.NotEmpty(t, hydraResource.GetPort("4445/tcp"), "%+v", hydraResource.Container) - - hydraPublic = "http://127.0.0.1:" + hydraResource.GetPort("4444/tcp") - hydraAdmin = "http://127.0.0.1:" + hydraResource.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: hydraResource.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) @@ -172,87 +43,174 @@ func TestOAuth2Provider(t *testing.T) { map[string]interface{}{"enabled": true}, ) + var testRequireLogin atomic.Bool + testRequireLogin.Store(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) - var oAuthSuccess atomic.Bool - var hydraAdminClient hydraclientgo.OAuth2Api - var clientAppOAuth2Config *oauth2.Config + router.GET("/login-ts", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + t.Log("[loginTS] navigated to the login ui") + c := r.Context().Value(TestUIConfig).(*testConfig) + *c.callTrace = append(*c.callTrace, LoginUI) - clientAppTS := testhelpers.NewHTTPTestServer(t, http.HandlerFunc(func(_ 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")) + q := r.URL.Query() + hlc := r.URL.Query().Get("login_challenge") + if hlc != "" { + *c.callTrace = append(*c.callTrace, LoginWithOAuth2LoginChallenge) + + loginUrl, err := url.Parse(c.kratosPublicTS.URL + login.RouteInitBrowserFlow) require.NoError(t, err) - require.NotNil(t, token) - require.NotEqual(t, "", token.AccessToken) - oAuthSuccess.Store(true) - t.Log("[clientAppTS] successfully exchanged code for token") - } else { - t.Error("[clientAppTS] code query parameter is missing") - } - })) - identifier, pwd := x.NewUUID().String(), "password" + q := loginUrl.Query() + q.Set("login_challenge", hlc) + loginUrl.RawQuery = q.Encode() - var testRequireLogin atomic.Bool - testRequireLogin.Store(true) + req, err := http.NewRequest("GET", loginUrl.String(), nil) + require.NoError(t, err) - uiTS := testhelpers.NewHTTPTestServer(t, http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) { - t.Logf("[uiTS] handling %s", r.URL) - q := r.URL.Query() + resp, err := c.browserClient.Do(req) + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode) + require.NoError(t, resp.Body.Close()) - 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.Load(), testhelpers.InitFlowWithOAuth2LoginChallenge(hlc)) - if testRequireLogin.Load() { - require.NotNil(t, f) + // if the registration page redirects us to the login page + // we will sign in which means we might have a session + var oryCookie *http.Cookie + currentURL, err := url.Parse(kratosPublicTS.URL) + require.NoError(t, err) - values := url.Values{"method": {"password"}, "identifier": {identifier}, "password": {pwd}, "csrf_token": {x.FakeCSRFToken}}.Encode() - _, res := testhelpers.LoginMakeRequest(t, false, false, f, browserClient, values) + for _, c := range c.browserClient.Jar.Cookies(currentURL) { + if c.Name == config.DefaultSessionCookieName { + oryCookie = c + break + } + } - 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") + // in some cases the initialize login flow already navigated to the consent page + // in which case no flow exists, but a session cookie does + if oryCookie != nil && !resp.Request.URL.Query().Has("flow") { + t.Logf("[loginTS] found a session cookie: %s", oryCookie.String()) + return } - return - } - if q.Has("consent_challenge") { - kratosUIHandleConsent(t, r, browserClient, hydraAdminClient, clientAppTS.URL) + flowID := resp.Request.URL.Query().Get("flow") + lf := testhelpers.GetLoginFlow(t, c.browserClient, c.kratosPublicTS, flowID) + require.NotNil(t, lf) + + values := url.Values{"method": {"password"}, "identifier": {c.identifier}, "password": {c.password}, "csrf_token": {x.FakeCSRFToken}}.Encode() + _, res := testhelpers.LoginMakeRequest(t, false, false, lf, c.browserClient, values) + assert.EqualValues(t, http.StatusOK, res.StatusCode) return } if q.Has("flow") { - t.Log("[uiTS] no operaton; the flow should be completed by the handler that initialized it") + *c.callTrace = append(*c.callTrace, LoginWithFlowID) + t.Log("[loginTS] login flow is ignored here since it will be handled by the code above, we just need to return") return } + }) + + router.GET("/consent", func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { + t.Log("[consentTS] navigated to the consent ui") + c := r.Context().Value(TestUIConfig).(*testConfig) + *c.callTrace = append(*c.callTrace, Consent) + + q := r.URL.Query() + consentChallenge := q.Get("consent_challenge") + assert.NotEmpty(t, consentChallenge) + + if consentChallenge != "" { + *c.callTrace = append(*c.callTrace, ConsentWithChallenge) + } + + cr, resp, err := c.hydraAdminClient.GetOAuth2ConsentRequest(ctx).ConsentChallenge(q.Get("consent_challenge")).Execute() + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + assert.ElementsMatch(t, cr.RequestedScope, c.requestedScope) + + if cr.GetSkip() { + *c.callTrace = append(*c.callTrace, ConsentSkip) + } + + if cr.Client.GetSkipConsent() { + *c.callTrace = append(*c.callTrace, ConsentClientSkip) + } + + completedAcceptRequest, resp, err := c.hydraAdminClient.AcceptOAuth2ConsentRequest(r.Context()).AcceptOAuth2ConsentRequest(hydraclientgo.AcceptOAuth2ConsentRequest{ + Remember: &c.consentRemember, + GrantScope: c.requestedScope, + }).ConsentChallenge(q.Get("consent_challenge")).Execute() + + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + + if completedAcceptRequest != nil { + *c.callTrace = append(*c.callTrace, ConsentAccept) + } + assert.NotNil(t, completedAcceptRequest) + + t.Logf("[consentTS] navigating to %s", completedAcceptRequest.RedirectTo) + resp, err = c.browserClient.Get(completedAcceptRequest.RedirectTo) + require.NoError(t, err) + require.Equal(t, c.clientAppTS.URL, fmt.Sprintf("%s://%s", resp.Request.URL.Scheme, resp.Request.URL.Host)) + }) + + kratosUIMiddleware := negroni.New() + kratosUIMiddleware.UseFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { + // add the context from the global context to each request + next(rw, r.WithContext(ctx)) + }) + kratosUIMiddleware.UseHandler(router) + + kratosUITS := testhelpers.NewHTTPTestServer(t, kratosUIMiddleware) - t.Errorf("[uiTS] unexpected query %#v", q) - })) + clientAppTSMiddleware := negroni.New() + clientAppTSMiddleware.UseFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { + // add the context from the global context to each request + next(rw, r.WithContext(ctx)) + }) + clientAppTSMiddleware.UseHandlerFunc(func(w http.ResponseWriter, r *http.Request) { + c := ctx.Value(TestOAuthClientState).(*clientAppConfig) + kc := ctx.Value(TestUIConfig).(*testConfig) + *kc.callTrace = append(*kc.callTrace, CodeExchange) + + 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) + + if token != nil && token.AccessToken != "" { + t.Log("[clientAppTS] successfully exchanged code for token") + *kc.callTrace = append(*kc.callTrace, CodeExchangeWithToken) + c.state.tokens += 1 + } else { + t.Log("[clientAppTS] did not receive a token") + } + } else { + t.Error("[clientAppTS] code query parameter is missing") + } + }) + // A new OAuth client which will also function as the callback for the code exchange + clientAppTS := testhelpers.NewHTTPTestServer(t, clientAppTSMiddleware) 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.ViperKeySelfServiceLoginUI, kratosUITS.URL+"/login-ts") conf.MustSet(ctx, config.ViperKeySelfServiceBrowserDefaultReturnTo, redirTS.URL+"/return-ts") + conf.MustSet(ctx, config.ViperKeySessionPersistentCookie, true) testhelpers.SetDefaultIdentitySchemaFromRaw(conf, loginSchema) - createIdentity(ctx, reg, t, identifier, pwd) - hydraAdmin, hydraPublic := newHydra(t, uiTS.URL, uiTS.URL) + hydraAdmin, hydraPublic := newHydra(t, kratosUITS.URL+"/login-ts", kratosUITS.URL+"/consent") conf.MustSet(ctx, config.ViperKeyOAuth2ProviderURL, hydraAdmin) - hydraAdminClient = createHydraOAuth2ApiClient(hydraAdmin) - clientID := createOAuth2Client(t, ctx, hydraAdminClient, []string{clientAppTS.URL}, "profile email") + hydraAdminClient := createHydraOAuth2ApiClient(hydraAdmin) - t.Run("should sign in the user without OAuth2", func(t *testing.T) { + loginToAccount := func(t *testing.T, browserClient *http.Client, identifier, pwd string) { f := testhelpers.InitializeLoginFlowViaBrowser(t, browserClient, kratosPublicTS, false, false, false, false) values := url.Values{"method": {"password"}, "identifier": {identifier}, "password": {pwd}, "csrf_token": {x.FakeCSRFToken}}.Encode() @@ -261,78 +219,594 @@ func TestOAuth2Provider(t *testing.T) { 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) + // This is the default case, where the user is prompted for login and consent. + + conf.MustSet(ctx, config.ViperKeySessionPersistentCookie, false) + + t.Cleanup(func() { + conf.MustSet(ctx, config.ViperKeySessionPersistentCookie, true) + }) + browserClient := testhelpers.NewClientWithCookieJar(t, nil, false) + + identifier, pwd := x.NewUUID().String(), "password" + createIdentity(ctx, reg, t, identifier, pwd) + + scopes := []string{"profile", "email"} + clientID := createOAuth2Client(t, ctx, hydraAdminClient, []string{clientAppTS.URL}, strings.Join(scopes, " "), false) + oauthClient := &oauth2.Config{ + ClientID: clientID, + ClientSecret: "client-secret", + Endpoint: oauth2.Endpoint{ + AuthURL: hydraPublic + "/oauth2/auth", + TokenURL: hydraPublic + "/oauth2/token", + AuthStyle: oauth2.AuthStyleInParams, + }, + Scopes: scopes, + RedirectURL: clientAppTS.URL, + } - 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.Load()) - oAuthSuccess.Store(false) + clientAS := clientAppState{ + visits: 0, + tokens: 0, + } + + ctx = context.WithValue(ctx, TestOAuthClientState, &clientAppConfig{ + client: oauthClient, + state: &clientAS, + expectToken: true, + }) + + ct := make([]callTrace, 0) + + tc := &testConfig{ + browserClient: browserClient, + kratosPublicTS: kratosPublicTS, + hydraAdminClient: hydraAdminClient, + clientAppTS: clientAppTS, + callTrace: &ct, + requestedScope: scopes, + consentRemember: true, + identifier: identifier, + password: pwd, + } + ctx = context.WithValue(ctx, TestUIConfig, tc) + + doOAuthFlow(t, ctx, oauthClient, browserClient) + + assert.EqualValues(t, clientAppState{ + visits: 1, + tokens: 1, + }, clientAS) + + expected := []callTrace{ + LoginUI, + LoginWithOAuth2LoginChallenge, + LoginUI, + LoginWithFlowID, + Consent, + ConsentWithChallenge, + ConsentAccept, + CodeExchange, + CodeExchangeWithToken, + } + require.ElementsMatch(t, expected, ct) }) - 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) + // This test verifies that when Kratos is set + // to SessionPersistentCookie=false, the user is not + // remembered from the previous OAuth2 flow. + // The user must then re-authenticate and re-consent. + browserClient := testhelpers.NewClientWithCookieJar(t, nil, false) + + identifier, pwd := x.NewUUID().String(), "password" + createIdentity(ctx, reg, t, identifier, pwd) + + scopes := []string{"profile", "email"} + clientID := createOAuth2Client(t, ctx, hydraAdminClient, []string{clientAppTS.URL}, strings.Join(scopes, " "), false) + + oauthClient := &oauth2.Config{ + ClientID: clientID, + ClientSecret: "client-secret", + Endpoint: oauth2.Endpoint{ + AuthURL: hydraPublic + "/oauth2/auth", + TokenURL: hydraPublic + "/oauth2/token", + AuthStyle: oauth2.AuthStyleInParams, + }, + Scopes: scopes, + RedirectURL: clientAppTS.URL, + } - 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.Load()) - oAuthSuccess.Store(false) + clientAS := clientAppState{ + visits: 0, + tokens: 0, + } + + ctx = context.WithValue(ctx, TestOAuthClientState, &clientAppConfig{ + client: oauthClient, + state: &clientAS, + expectToken: true, + }) + + ct := make([]callTrace, 0) + + tc := &testConfig{ + password: pwd, + identifier: identifier, + hydraAdminClient: hydraAdminClient, + browserClient: browserClient, + kratosPublicTS: kratosPublicTS, + clientAppTS: clientAppTS, + callTrace: &ct, + requestedScope: scopes, + consentRemember: false, + } + ctx = context.WithValue(ctx, TestUIConfig, tc) + + conf.MustSet(ctx, config.ViperKeySessionPersistentCookie, false) + + doOAuthFlow(t, ctx, oauthClient, browserClient) + + assert.EqualValues(t, clientAppState{ + visits: 1, + tokens: 1, + }, clientAS) + + expected := []callTrace{ + LoginUI, + LoginWithOAuth2LoginChallenge, + LoginUI, + LoginWithFlowID, + Consent, + ConsentWithChallenge, + ConsentAccept, + CodeExchange, + CodeExchangeWithToken, + } + require.ElementsMatch(t, expected, ct) + + // Reset the call trace + ct = []callTrace{} + + conf.MustSet(ctx, config.ViperKeySessionPersistentCookie, true) + doOAuthFlow(t, ctx, oauthClient, browserClient) + + assert.EqualValues(t, clientAppState{ + visits: 2, + tokens: 2, + }, clientAS) + + expected = []callTrace{ + LoginUI, + LoginWithOAuth2LoginChallenge, + LoginUI, + LoginWithFlowID, + Consent, + ConsentWithChallenge, + ConsentAccept, + CodeExchange, + CodeExchangeWithToken, + } + require.ElementsMatch(t, expected, ct) }) - testRequireLogin.Store(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) + // This test verifies that when Kratos is set + // to SessionPersistentCookie=true, the user is + // remembered from the previous OAuth2 flow. + // The user must then only re-consent. + conf.MustSet(ctx, config.ViperKeySessionPersistentCookie, true) + + browserClient := testhelpers.NewClientWithCookieJar(t, nil, false) + + identifier, pwd := x.NewUUID().String(), "password" + + createIdentity(ctx, reg, t, identifier, pwd) + + scopes := []string{"profile", "email"} + clientID := createOAuth2Client(t, ctx, hydraAdminClient, []string{clientAppTS.URL}, strings.Join(scopes, " "), false) + oauthClient := &oauth2.Config{ + ClientID: clientID, + ClientSecret: "client-secret", + Endpoint: oauth2.Endpoint{ + AuthURL: hydraPublic + "/oauth2/auth", + TokenURL: hydraPublic + "/oauth2/token", + AuthStyle: oauth2.AuthStyleInParams, + }, + Scopes: scopes, + RedirectURL: clientAppTS.URL, + } - 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.Load()) - oAuthSuccess.Store(false) + clientAS := clientAppState{ + visits: 0, + tokens: 0, + } + + ctx = context.WithValue(ctx, TestOAuthClientState, &clientAppConfig{ + client: oauthClient, + state: &clientAS, + expectToken: true, + }) + + ct := make([]callTrace, 0) + + tc := &testConfig{ + hydraAdminClient: hydraAdminClient, + browserClient: browserClient, + kratosPublicTS: kratosPublicTS, + clientAppTS: clientAppTS, + callTrace: &ct, + requestedScope: scopes, + consentRemember: false, + password: pwd, + identifier: identifier, + } + ctx = context.WithValue(ctx, TestUIConfig, tc) + + doOAuthFlow(t, ctx, oauthClient, browserClient) + + assert.EqualValues(t, clientAppState{ + visits: 1, + tokens: 1, + }, clientAS) + + expected := []callTrace{ + LoginUI, + LoginWithOAuth2LoginChallenge, + LoginUI, + LoginWithFlowID, + Consent, + ConsentWithChallenge, + ConsentAccept, + CodeExchange, + CodeExchangeWithToken, + } + require.ElementsMatch(t, expected, ct) + + // reset the call trace + ct = []callTrace{} + + doOAuthFlow(t, ctx, oauthClient, browserClient) + + assert.EqualValues(t, clientAppState{ + visits: 2, + tokens: 2, + }, clientAS) + + expected = []callTrace{ + LoginUI, + LoginWithOAuth2LoginChallenge, + Consent, + ConsentWithChallenge, + ConsentAccept, + CodeExchange, + CodeExchangeWithToken, + } + + require.ElementsMatch(t, expected, ct) + }) + + t.Run("should prompt login even with session with OAuth flow", func(t *testing.T) { + browserClient := testhelpers.NewClientWithCookieJar(t, nil, false) + + identifier, pwd := x.NewUUID().String(), "password" + createIdentity(ctx, reg, t, identifier, pwd) + + scopes := []string{"profile", "email"} + clientID := createOAuth2Client(t, ctx, hydraAdminClient, []string{clientAppTS.URL}, strings.Join(scopes, " "), false) + oauthClient := &oauth2.Config{ + ClientID: clientID, + ClientSecret: "client-secret", + Endpoint: oauth2.Endpoint{ + AuthURL: hydraPublic + "/oauth2/auth", + TokenURL: hydraPublic + "/oauth2/token", + AuthStyle: oauth2.AuthStyleInParams, + }, + Scopes: scopes, + RedirectURL: clientAppTS.URL, + } + + ct := make([]callTrace, 0) + + tc := &testConfig{ + browserClient: browserClient, + kratosPublicTS: kratosPublicTS, + clientAppTS: clientAppTS, + callTrace: &ct, + requestedScope: scopes, + hydraAdminClient: hydraAdminClient, + identifier: identifier, + password: pwd, + consentRemember: false, + } + + ctx = context.WithValue(ctx, TestUIConfig, tc) + + clientAS := clientAppState{ + visits: 0, + tokens: 0, + } + + ctx = context.WithValue(ctx, TestOAuthClientState, &clientAppConfig{ + client: oauthClient, + state: &clientAS, + expectToken: true, + }) + + loginToAccount(t, browserClient, identifier, pwd) + + doOAuthFlow(t, ctx, oauthClient, browserClient) + + assert.EqualValues(t, clientAppState{ + visits: 1, + tokens: 1, + }, clientAS) + + require.ElementsMatch(t, []callTrace{ + LoginUI, + LoginWithFlowID, + LoginUI, + LoginWithOAuth2LoginChallenge, + LoginUI, + LoginWithFlowID, + Consent, + ConsentWithChallenge, + ConsentAccept, + CodeExchange, + CodeExchangeWithToken, + }, ct) + }) + + t.Run("first party clients can skip consent", func(t *testing.T) { + browserClient := testhelpers.NewClientWithCookieJar(t, nil, false) + + identifier, pwd := x.NewUUID().String(), "password" + createIdentity(ctx, reg, t, identifier, pwd) + + clientSkipConsent := true + scopes := []string{"profile", "email"} + clientID := createOAuth2Client(t, ctx, hydraAdminClient, []string{clientAppTS.URL}, strings.Join(scopes, " "), clientSkipConsent) + oauthClient := &oauth2.Config{ + ClientID: clientID, + ClientSecret: "client-secret", + Endpoint: oauth2.Endpoint{ + AuthURL: hydraPublic + "/oauth2/auth", + TokenURL: hydraPublic + "/oauth2/token", + AuthStyle: oauth2.AuthStyleInParams, + }, + Scopes: scopes, + RedirectURL: clientAppTS.URL, + } + + ct := make([]callTrace, 0) + + tc := &testConfig{ + browserClient: browserClient, + kratosPublicTS: kratosPublicTS, + clientAppTS: clientAppTS, + callTrace: &ct, + requestedScope: scopes, + hydraAdminClient: hydraAdminClient, + identifier: identifier, + password: pwd, + consentRemember: false, + } + + ctx = context.WithValue(ctx, TestUIConfig, tc) + + clientAS := clientAppState{ + visits: 0, + tokens: 0, + } + + ctx = context.WithValue(ctx, TestOAuthClientState, &clientAppConfig{ + client: oauthClient, + state: &clientAS, + expectToken: true, + }) + + doOAuthFlow(t, ctx, oauthClient, browserClient) + + assert.EqualValues(t, clientAppState{ + visits: 1, + tokens: 1, + }, clientAS) + + require.ElementsMatch(t, []callTrace{ + LoginUI, + LoginWithOAuth2LoginChallenge, + LoginUI, + LoginWithFlowID, + Consent, + ConsentWithChallenge, + ConsentClientSkip, + ConsentAccept, + CodeExchange, + CodeExchangeWithToken, + }, ct) + }) + + t.Run("oauth flow with consent remember, skips consent", func(t *testing.T) { + browserClient := testhelpers.NewClientWithCookieJar(t, nil, false) + + identifier, pwd := x.NewUUID().String(), "password" + createIdentity(ctx, reg, t, identifier, pwd) + + scopes := []string{"profile", "email"} + clientID := createOAuth2Client(t, ctx, hydraAdminClient, []string{clientAppTS.URL}, strings.Join(scopes, " "), false) + oauthClient := &oauth2.Config{ + ClientID: clientID, + ClientSecret: "client-secret", + Endpoint: oauth2.Endpoint{ + AuthURL: hydraPublic + "/oauth2/auth", + TokenURL: hydraPublic + "/oauth2/token", + AuthStyle: oauth2.AuthStyleInParams, + }, + Scopes: scopes, + RedirectURL: clientAppTS.URL, + } + + ct := make([]callTrace, 0) + + tc := &testConfig{ + browserClient: browserClient, + kratosPublicTS: kratosPublicTS, + clientAppTS: clientAppTS, + callTrace: &ct, + requestedScope: scopes, + hydraAdminClient: hydraAdminClient, + identifier: identifier, + password: pwd, + consentRemember: true, + } + + ctx = context.WithValue(ctx, TestUIConfig, tc) + + clientAS := clientAppState{ + visits: 0, + tokens: 0, + } + + ctx = context.WithValue(ctx, TestOAuthClientState, &clientAppConfig{ + client: oauthClient, + state: &clientAS, + expectToken: true, + }) + + doOAuthFlow(t, ctx, oauthClient, browserClient) + + assert.EqualValues(t, clientAppState{ + visits: 1, + tokens: 1, + }, clientAS) + + require.ElementsMatch(t, []callTrace{ + LoginUI, + LoginWithOAuth2LoginChallenge, + LoginUI, + LoginWithFlowID, + Consent, + ConsentWithChallenge, + ConsentAccept, + CodeExchange, + CodeExchangeWithToken, + }, ct) + + // reset the call trace + ct = []callTrace{} + clientAS = clientAppState{ + visits: 0, + tokens: 0, + } + doOAuthFlow(t, ctx, oauthClient, browserClient) + + assert.EqualValues(t, clientAppState{ + visits: 1, + tokens: 1, + }, clientAS) + + require.ElementsMatch(t, []callTrace{ + LoginUI, + LoginWithOAuth2LoginChallenge, + Consent, + ConsentWithChallenge, + ConsentSkip, + ConsentAccept, + CodeExchange, + CodeExchangeWithToken, + }, ct) }) - 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) + browserClient := testhelpers.NewClientWithCookieJar(t, nil, false) + + identifier, pwd := x.NewUUID().String(), "password" + createIdentity(ctx, reg, t, identifier, pwd) + + scopes := []string{"profile", "email"} + clientID := createOAuth2Client(t, ctx, hydraAdminClient, []string{clientAppTS.URL}, strings.Join(scopes, " "), false) + oauthClient := &oauth2.Config{ + ClientID: clientID, + ClientSecret: "client-secret", + Endpoint: oauth2.Endpoint{ + AuthURL: hydraPublic + "/oauth2/auth", + TokenURL: hydraPublic + "/oauth2/token", + AuthStyle: oauth2.AuthStyleInParams, + }, + Scopes: scopes, + RedirectURL: clientAppTS.URL, + } - 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.Load()) - oAuthSuccess.Store(false) + ct := make([]callTrace, 0) + + tc := &testConfig{ + browserClient: browserClient, + kratosPublicTS: kratosPublicTS, + clientAppTS: clientAppTS, + callTrace: &ct, + requestedScope: scopes, + hydraAdminClient: hydraAdminClient, + identifier: identifier, + password: pwd, + consentRemember: false, + } + + ctx = context.WithValue(ctx, TestUIConfig, tc) + + clientAS := clientAppState{ + visits: 0, + tokens: 0, + } + + ctx = context.WithValue(ctx, TestOAuthClientState, &clientAppConfig{ + client: oauthClient, + state: &clientAS, + expectToken: false, + }) + + doOAuthFlow(t, ctx, oauthClient, browserClient) + + assert.EqualValues(t, clientAppState{ + visits: 1, + tokens: 1, + }, clientAS) + + require.ElementsMatch(t, []callTrace{ + LoginUI, + LoginWithFlowID, + LoginUI, + LoginWithOAuth2LoginChallenge, + Consent, + ConsentWithChallenge, + ConsentAccept, + CodeExchange, + CodeExchangeWithToken, + }, ct) + + // reset the call trace + ct = []callTrace{} + clientAS = clientAppState{ + visits: 0, + tokens: 0, + } + + reg.WithHydra(&AcceptWrongSubject{h: reg.Hydra().(*hydra.DefaultHydra)}) + + doOAuthFlow(t, ctx, oauthClient, browserClient) + + assert.EqualValues(t, clientAppState{ + visits: 0, + tokens: 0, + }, clientAS) + + expected := []callTrace{ + LoginUI, + LoginWithOAuth2LoginChallenge, + } + require.ElementsMatch(t, expected, ct) }) } diff --git a/selfservice/strategy/password/op_registration_test.go b/selfservice/strategy/password/op_registration_test.go index f947e9a63007..55e9907aba07 100644 --- a/selfservice/strategy/password/op_registration_test.go +++ b/selfservice/strategy/password/op_registration_test.go @@ -9,11 +9,15 @@ import ( "fmt" "io" "net/http" - "net/http/httptest" + "net/url" + "strings" "testing" "golang.org/x/oauth2" + "github.com/julienschmidt/httprouter" + "github.com/urfave/negroni" + hydraclientgo "github.com/ory/hydra-client-go/v2" "github.com/stretchr/testify/assert" @@ -23,148 +27,216 @@ import ( "github.com/ory/kratos/identity" "github.com/ory/kratos/internal" "github.com/ory/kratos/internal/testhelpers" + "github.com/ory/kratos/selfservice/flow/registration" "github.com/ory/kratos/x" ) -type clientAppConfig struct { - client *oauth2.Config - expectToken bool - state clientAppState -} +func TestOAuth2ProviderRegistration(t *testing.T) { + ctx := context.Background() + conf, reg := internal.NewFastRegistryWithMocks(t) -type clientAppState struct { - visits int64 - tokens int64 -} + kratosPublicTS, _ := testhelpers.NewKratosServerWithRouters(t, reg, x.NewRouterPublic(), x.NewRouterAdmin()) + errTS := testhelpers.NewErrorTestServer(t, reg) + redirTS := testhelpers.NewRedirSessionEchoTS(t, reg) -type kratosUIConfig struct { - expectLoginScreen bool - identifier string - password string - browserClient *http.Client - kratosPublicTS *httptest.Server - clientAppTS *httptest.Server - hydraAdminClient hydraclientgo.OAuth2Api -} + var hydraAdminClient hydraclientgo.OAuth2Api -func newClientAppTS(t *testing.T, c *clientAppConfig) *httptest.Server { - return testhelpers.NewHTTPTestServer(t, http.HandlerFunc(func(_ 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) + router := x.NewRouterPublic() + + const ( + TestUIConfig = "test-ui-config" + TestOAuthClientState = "test-oauth-client-state" + ) + + router.GET("/login-ts", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + t.Log("[loginTS] navigated to the login ui") + c := r.Context().Value(TestUIConfig).(*testConfig) + *c.callTrace = append(*c.callTrace, LoginUI) + + q := r.URL.Query() + hlc := r.URL.Query().Get("login_challenge") + + if hlc != "" { + *c.callTrace = append(*c.callTrace, LoginWithOAuth2LoginChallenge) + return } - })) -} -func kratosUIHandleConsent(t *testing.T, req *http.Request, client *http.Client, haa hydraclientgo.OAuth2Api, clientAppURL string) { - q := req.URL.Query() - cr, resp, err := haa.GetOAuth2ConsentRequest(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.AcceptOAuth2ConsentRequest(context.Background()).AcceptOAuth2ConsentRequest(hydraclientgo.AcceptOAuth2ConsentRequest{ - 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")) -} + if q.Has("flow") { + *c.callTrace = append(*c.callTrace, LoginWithFlowID) + lf := testhelpers.GetLoginFlow(t, c.browserClient, c.kratosPublicTS, q.Get("flow")) + require.NotNil(t, lf) + values := testhelpers.SDKFormFieldsToURLValues(lf.Ui.Nodes) + values.Set("password", c.password) + + _, _ = testhelpers.LoginMakeRequest(t, false, false, lf, c.browserClient, values.Encode()) + t.Log("[loginTS] login flow is ignored here since it will be handled by the code above, we just need to return") + return + } + }) + + router.GET("/registration-ts", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + t.Log("[registrationTS] navigated to the registration ui") + c := r.Context().Value(TestUIConfig).(*testConfig) + *c.callTrace = append(*c.callTrace, RegistrationUI) -func newKratosUITS(t *testing.T, c *kratosUIConfig) *httptest.Server { - return testhelpers.NewHTTPTestServer(t, http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) { - t.Logf("[uiTS] handling %s", r.URL) q := r.URL.Query() + hlc := q.Get("login_challenge") - 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) + if hlc != "" { + *c.callTrace = append(*c.callTrace, RegistrationWithOAuth2LoginChallenge) + t.Log("[registrationTS] initializing a new OpenID Provider flow through the registration endpoint") + registrationUrl, err := url.Parse(c.kratosPublicTS.URL + registration.RouteInitBrowserFlow) + require.NoError(t, err) - values := testhelpers.SDKFormFieldsToURLValues(f.Ui.Nodes) - values.Set("traits.foobar", c.identifier) - values.Set("traits.username", c.identifier) - values.Set("password", c.password) + q := registrationUrl.Query() + q.Set("login_challenge", hlc) + registrationUrl.RawQuery = q.Encode() - _, res := testhelpers.RegistrationMakeRequest(t, false, false, f, c.browserClient, values.Encode()) + req, err := http.NewRequest("GET", registrationUrl.String(), nil) + require.NoError(t, err) - 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") + resp, err := c.browserClient.Do(req) + require.NoError(t, err) + assert.EqualValues(t, http.StatusOK, resp.StatusCode) + require.NoError(t, resp.Body.Close()) + + // if the registration page redirects us to the login page + // we will sign in which means we might have a session + var oryCookie *http.Cookie + currentURL, err := url.Parse(kratosPublicTS.URL) + require.NoError(t, err) + + for _, c := range c.browserClient.Jar.Cookies(currentURL) { + if c.Name == config.DefaultSessionCookieName { + oryCookie = c + break + } } - return - } - if q.Has("consent_challenge") { - kratosUIHandleConsent(t, r, c.browserClient, c.hydraAdminClient, c.clientAppTS.URL) + if oryCookie != nil { + t.Log("[registrationTS] we expect to have been at the login screen and got an active flow. This means we have a session now") + return + } + + flowID := resp.Request.URL.Query().Get("flow") + assert.NotEmpty(t, flowID) + + f := testhelpers.GetRegistrationFlow(t, c.browserClient, c.kratosPublicTS, flowID) + require.NotNil(t, f) + + // continue the registration flow here + 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) return } if q.Has("flow") { - t.Log("[uiTS] no operaton; the flow should be completed by the handler that initialized it") + *c.callTrace = append(*c.callTrace, RegistrationWithFlowID) + t.Log("[registrationTS] registration flow is ignored here since it will be handled by the code above, we just need to return") return } + }) - t.Errorf("[uiTS] unexpected query %#v", q) - })) -} + router.GET("/consent", func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { + t.Log("[consentTS] navigated to the consent ui") + c := r.Context().Value(TestUIConfig).(*testConfig) + *c.callTrace = append(*c.callTrace, Consent) -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) + q := r.URL.Query() + consentChallenge := q.Get("consent_challenge") + assert.NotEmpty(t, consentChallenge) - var hydraAdminClient hydraclientgo.OAuth2Api + if consentChallenge != "" { + *c.callTrace = append(*c.callTrace, ConsentWithChallenge) + } - cac := &clientAppConfig{} - clientAppTS := newClientAppTS(t, cac) + cr, resp, err := hydraAdminClient.GetOAuth2ConsentRequest(ctx).ConsentChallenge(q.Get("consent_challenge")).Execute() + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + assert.ElementsMatch(t, cr.RequestedScope, c.requestedScope) - kuc := &kratosUIConfig{} - kratosUITS := newKratosUITS(t, kuc) + if cr.GetSkip() { + *c.callTrace = append(*c.callTrace, ConsentSkip) + } + + if cr.Client.GetSkipConsent() { + *c.callTrace = append(*c.callTrace, ConsentClientSkip) + } - hydraAdmin, hydraPublic := newHydra(t, kratosUITS.URL, kratosUITS.URL) + completedAcceptRequest, resp, err := hydraAdminClient.AcceptOAuth2ConsentRequest(r.Context()).AcceptOAuth2ConsentRequest(hydraclientgo.AcceptOAuth2ConsentRequest{ + Remember: &c.consentRemember, + GrantScope: c.requestedScope, + }).ConsentChallenge(q.Get("consent_challenge")).Execute() + + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + + if completedAcceptRequest != nil { + *c.callTrace = append(*c.callTrace, ConsentAccept) + } + assert.NotNil(t, completedAcceptRequest) + + t.Logf("[consentTS] navigating to %s", completedAcceptRequest.RedirectTo) + resp, err = c.browserClient.Get(completedAcceptRequest.RedirectTo) + require.NoError(t, err) + require.Equal(t, c.clientAppTS.URL, fmt.Sprintf("%s://%s", resp.Request.URL.Scheme, resp.Request.URL.Host)) + }) + + kratosUIMiddleware := negroni.New() + kratosUIMiddleware.UseFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { + // add the context from the global context to each request + next(rw, r.WithContext(ctx)) + }) + kratosUIMiddleware.UseHandler(router) + + kratosUITS := testhelpers.NewHTTPTestServer(t, kratosUIMiddleware) + + clientAppTSMiddleware := negroni.New() + clientAppTSMiddleware.UseFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { + // add the context from the global context to each request + next(rw, r.WithContext(ctx)) + }) + clientAppTSMiddleware.UseHandlerFunc(func(w http.ResponseWriter, r *http.Request) { + c := ctx.Value(TestOAuthClientState).(*clientAppConfig) + kc := ctx.Value(TestUIConfig).(*testConfig) + *kc.callTrace = append(*kc.callTrace, CodeExchange) + + 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) + + if token != nil && token.AccessToken != "" { + t.Log("[clientAppTS] successfully exchanged code for token") + *kc.callTrace = append(*kc.callTrace, CodeExchangeWithToken) + c.state.tokens += 1 + } else { + t.Log("[clientAppTS] did not receive a token") + } + } else { + t.Error("[clientAppTS] code query parameter is missing") + } + }) + // A new OAuth client which will also function as the callback for the code exchange + clientAppTS := testhelpers.NewHTTPTestServer(t, clientAppTSMiddleware) + + // we want to test if the registration ui is used if the flow contains an oauth2 login challenge + // so we will have Hydra redirect to the base path of the test kratos ui server which + // will then initiate the registration flow + hydraAdmin, hydraPublic := newHydra(t, kratosUITS.URL+"/registration-ts", kratosUITS.URL+"/consent") hydraAdminClient = createHydraOAuth2ApiClient(hydraAdmin) - 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+"/") 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.ViperKeySelfServiceRegistrationUI, kratosUITS.URL+"/registration-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}) @@ -172,108 +244,643 @@ func TestOAuth2ProviderRegistration(t *testing.T) { 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, - }, + doOAuthFlow := func(t *testing.T, ctx context.Context, oauthClient *oauth2.Config, browserClient *http.Client) { + t.Helper() + + authCodeURL := makeAuthCodeURL(t, oauthClient, "", false) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, authCodeURL, nil) + require.NoError(t, err) + res, err := browserClient.Do(req) + require.NoError(t, err) + + body, err := io.ReadAll(res.Body) + require.NoError(t, err) + + require.NoError(t, res.Body.Close()) + require.Equal(t, "", string(body)) + require.Equal(t, http.StatusOK, res.StatusCode) + } + + registerNewAccount := func(t *testing.T, ctx context.Context, browserClient *http.Client, identifier, password string) { + // we need to create a new session directly with kratos + f := testhelpers.InitializeRegistrationFlowViaBrowser(t, browserClient, kratosPublicTS, false, false, false) + require.NotNil(t, f) + + values := testhelpers.SDKFormFieldsToURLValues(f.Ui.Nodes) + values.Set("traits.foobar", identifier) + values.Set("traits.username", identifier) + values.Set("password", password) + + _, resp := testhelpers.RegistrationMakeRequest(t, false, false, f, browserClient, values.Encode()) + require.EqualValues(t, http.StatusOK, resp.StatusCode) + + var cookie *http.Cookie + currentURL, err := url.Parse(kratosPublicTS.URL) + require.NoError(t, err) + + for _, c := range browserClient.Jar.Cookies(currentURL) { + if c.Name == config.DefaultSessionCookieName { + cookie = c + break + } + } + + require.NotNil(t, cookie, "expected exactly one session cookie to be set but got none") + } + + // important, we will set the persistent cookie to false for most of the tests here + // once this is true, the behavior of the consent flow changes + conf.MustSet(ctx, config.ViperKeySessionPersistentCookie, false) + + t.Run("case=should accept oauth login request on registration", func(t *testing.T) { + // this test initiates a new OAuth2 flow which goes directly to the registration page + // we then create a new account through the registration flow + // and expect the OAuth2 flow to succeed + scopes := []string{"profile", "email"} + clientID := createOAuth2Client(t, ctx, hydraAdminClient, []string{clientAppTS.URL}, strings.Join(scopes, " "), false) + + oauth2Client := &oauth2.Config{ + ClientID: clientID, + ClientSecret: "client-secret", + Endpoint: oauth2.Endpoint{ + AuthURL: hydraPublic + "/oauth2/auth", + TokenURL: hydraPublic + "/oauth2/token", + AuthStyle: oauth2.AuthStyleInParams, }, - }, - { - name: "should fail because the persistent Hydra session doesn't match the new Kratos session subject", - configure: func(c *config.Config) { + Scopes: scopes, + RedirectURL: clientAppTS.URL, + } + browserClient := testhelpers.NewClientWithCookieJar(t, nil, false) + + identifier := x.NewUUID().String() + password := x.NewUUID().String() + + ct := make([]callTrace, 0) + + ctx = context.WithValue(ctx, TestUIConfig, &testConfig{ + identifier: identifier, + password: password, + browserClient: browserClient, + kratosPublicTS: kratosPublicTS, + clientAppTS: clientAppTS, + hydraAdminClient: hydraAdminClient, + consentRemember: true, + callTrace: &ct, + requestedScope: scopes, + }) + + clientAS := clientAppState{ + visits: 0, + tokens: 0, + } + + ctx = context.WithValue(ctx, TestOAuthClientState, &clientAppConfig{ + client: oauth2Client, + expectToken: true, + state: &clientAS, + }) + + doOAuthFlow(t, ctx, + oauth2Client, + browserClient) + + assert.EqualValues(t, clientAppState{ + visits: 1, + tokens: 1, + }, clientAS) + + expected := []callTrace{ + RegistrationUI, + RegistrationWithOAuth2LoginChallenge, + RegistrationUI, + RegistrationWithFlowID, + Consent, + ConsentWithChallenge, + ConsentAccept, + CodeExchange, + CodeExchangeWithToken, + } + require.ElementsMatch(t, expected, ct, "expected the call trace to match") + }) + + t.Run("case=registration with session should redirect to login to re-authenticate and to consent", func(t *testing.T) { + // this test registers a new account which sets a session + // we then initiate a new OAuth2 flow which should redirect us to the registration page + // the registration page does a session validation and retrieves the loginRequest from Hydra + // which in this case will indicate we cannot skip the login flow (since the there is no previous OAuth flow associated) + // we then get redirected to the the login page with refresh=true + // we then sign in and expect to be redirected to the consent page + // and then back to the client app + scopes := []string{"profile", "email", "offline_access"} + + clientID := createOAuth2Client(t, ctx, hydraAdminClient, []string{clientAppTS.URL}, strings.Join(scopes, " "), false) + + oauthClient := &oauth2.Config{ + ClientID: clientID, + ClientSecret: "client-secret", + Endpoint: oauth2.Endpoint{ + AuthURL: hydraPublic + "/oauth2/auth", + TokenURL: hydraPublic + "/oauth2/token", + AuthStyle: oauth2.AuthStyleInParams, }, - cac: clientAppConfig{ - client: defaultClient, - expectToken: false, + Scopes: scopes, + RedirectURL: clientAppTS.URL, + } + + browserClient := testhelpers.NewClientWithCookieJar(t, nil, false) + identifier := x.NewUUID().String() + password := x.NewUUID().String() + + ct := make([]callTrace, 0) + + tc := &testConfig{ + identifier: identifier, + password: password, + browserClient: browserClient, + kratosPublicTS: kratosPublicTS, + clientAppTS: clientAppTS, + hydraAdminClient: hydraAdminClient, + consentRemember: true, + requestedScope: scopes, + callTrace: &ct, + } + + ctx = context.WithValue(ctx, TestUIConfig, tc) + + clientAS := clientAppState{ + visits: 0, + tokens: 0, + } + + ctx = context.WithValue(ctx, TestOAuthClientState, &clientAppConfig{ + client: oauthClient, + expectToken: true, + state: &clientAS, + }) + + registerNewAccount(t, ctx, browserClient, identifier, password) + + require.ElementsMatch(t, []callTrace{ + RegistrationUI, + RegistrationWithFlowID, + }, ct, "expected the call trace to match") + + // reset the call trace + ct = []callTrace{} + tc.callTrace = &ct + + doOAuthFlow(t, ctx, oauthClient, browserClient) + + assert.EqualValues(t, clientAppState{ + visits: 1, + tokens: 1, + }, clientAS) + + expected := []callTrace{ + RegistrationUI, + RegistrationWithOAuth2LoginChallenge, + LoginUI, + LoginWithFlowID, + Consent, + ConsentWithChallenge, + ConsentAccept, + CodeExchange, + CodeExchangeWithToken, + } + require.ElementsMatch(t, expected, ct, "expected the call trace to match") + }) + + t.Run("case=registration should redirect to login if session exists and skip=false", func(t *testing.T) { + // we dont want to skip the consent page here + // we want the registration page to redirect to the login page + // since we have a session but do not skip the consent page + clientSkipConsent := false + consentRemember := false + + scopes := []string{"profile", "email", "offline_access"} + + clientID := createOAuth2Client(t, ctx, hydraAdminClient, []string{clientAppTS.URL}, strings.Join(scopes, " "), clientSkipConsent) + oauthClient := &oauth2.Config{ + ClientID: clientID, + ClientSecret: "client-secret", + Endpoint: oauth2.Endpoint{ + AuthURL: hydraPublic + "/oauth2/auth", + TokenURL: hydraPublic + "/oauth2/token", + AuthStyle: oauth2.AuthStyleInParams, }, - kuc: kratosUIConfig{ - expectLoginScreen: true, - identifier: x.NewUUID().String(), - password: x.NewUUID().String(), - browserClient: sharedBrowserClient, - kratosPublicTS: kratosPublicTS, - clientAppTS: clientAppTS, - hydraAdminClient: hydraAdminClient, + Scopes: scopes, + RedirectURL: clientAppTS.URL, + } + + browserClient := testhelpers.NewClientWithCookieJar(t, nil, false) + identifier := x.NewUUID().String() + password := x.NewUUID().String() + + ct := make([]callTrace, 0) + + tc := &testConfig{ + identifier: identifier, + password: password, + browserClient: browserClient, + kratosPublicTS: kratosPublicTS, + clientAppTS: clientAppTS, + hydraAdminClient: hydraAdminClient, + consentRemember: consentRemember, + requestedScope: scopes, + callTrace: &ct, + } + + clientAppConfig := &clientAppConfig{ + client: oauthClient, + expectToken: true, + } + + expected := []callTrace{ + RegistrationUI, + RegistrationWithOAuth2LoginChallenge, + RegistrationUI, + RegistrationWithFlowID, + Consent, + ConsentWithChallenge, + ConsentAccept, + CodeExchange, + CodeExchangeWithToken, + } + + // set the global context values + ctx = context.WithValue(ctx, TestUIConfig, tc) + ctx = context.WithValue(ctx, TestOAuthClientState, clientAppConfig) + + doSuccessfulOAuthFlow := func(t *testing.T) { + t.Helper() + + clientAS := clientAppState{ + visits: 0, + tokens: 0, + } + clientAppConfig.state = &clientAS + + doOAuthFlow(t, ctx, + oauthClient, + browserClient) + assert.EqualValues(t, clientAppState{ + visits: 1, + tokens: 1, + }, clientAS) + + require.ElementsMatchf(t, expected, ct, "expected the call trace to match") + } + + doSuccessfulOAuthFlow(t) + + // reset our state on the client app + clientAS := clientAppState{ + visits: 0, + tokens: 0, + } + + clientAppConfig.state = &clientAS + + // we should now have a session, but not skip the consent page + doOAuthFlow(t, ctx, oauthClient, browserClient) + assert.EqualValues(t, clientAppState{ + visits: 1, + tokens: 1, + }, clientAS) + + expected = append(expected, + RegistrationUI, + RegistrationWithOAuth2LoginChallenge, + LoginUI, + LoginWithFlowID, + Consent, + ConsentWithChallenge, + ConsentAccept, + CodeExchange, + CodeExchangeWithToken, + ) + require.ElementsMatchf(t, expected, ct, "expected the call trace to match") + }) + + t.Run("case=consent should be skipped if client is configured to skip", func(t *testing.T) { + clientSkipConsent := true + scopes := []string{"profile", "email", "offline_access"} + clientID := createOAuth2Client(t, ctx, hydraAdminClient, []string{clientAppTS.URL}, strings.Join(scopes, " "), clientSkipConsent) + + oauthClient := &oauth2.Config{ + ClientID: clientID, + ClientSecret: "client-secret", + Endpoint: oauth2.Endpoint{ + AuthURL: hydraPublic + "/oauth2/auth", + TokenURL: hydraPublic + "/oauth2/token", + AuthStyle: oauth2.AuthStyleInParams, }, - expected: state{ - cas: clientAppState{ - visits: 0, - tokens: 0, - }, + Scopes: scopes, + RedirectURL: clientAppTS.URL, + } + + browserClient := testhelpers.NewClientWithCookieJar(t, nil, false) + identifier := x.NewUUID().String() + password := x.NewUUID().String() + + ct := make([]callTrace, 0) + + tc := &testConfig{ + identifier: identifier, + password: password, + browserClient: browserClient, + kratosPublicTS: kratosPublicTS, + clientAppTS: clientAppTS, + hydraAdminClient: hydraAdminClient, + consentRemember: false, + requestedScope: scopes, + callTrace: &ct, + } + + clientAppConfig := &clientAppConfig{ + client: oauthClient, + expectToken: true, + } + + expected := []callTrace{ + RegistrationUI, + RegistrationWithOAuth2LoginChallenge, + RegistrationUI, + RegistrationWithFlowID, + Consent, + ConsentWithChallenge, + ConsentClientSkip, + ConsentAccept, + CodeExchange, + CodeExchangeWithToken, + } + + // set the global context values + ctx = context.WithValue(ctx, TestUIConfig, tc) + ctx = context.WithValue(ctx, TestOAuthClientState, clientAppConfig) + + clientAS := clientAppState{ + visits: 0, + tokens: 0, + } + clientAppConfig.state = &clientAS + + doOAuthFlow(t, ctx, + oauthClient, + browserClient) + assert.EqualValues(t, clientAppState{ + visits: 1, + tokens: 1, + }, clientAS) + + require.ElementsMatchf(t, expected, ct, "expected the call trace to match") + }) + + t.Run("case=consent should be skipped if user has a session and has already consented", func(t *testing.T) { + conf.MustSet(ctx, config.ViperKeySessionPersistentCookie, true) + t.Cleanup(func() { + conf.MustSet(ctx, config.ViperKeySessionPersistentCookie, false) + }) + + consentRemember := true + + scopes := []string{"profile", "email", "offline_access"} + + clientID := createOAuth2Client(t, ctx, hydraAdminClient, []string{clientAppTS.URL}, strings.Join(scopes, " "), false) + oauthClient := &oauth2.Config{ + ClientID: clientID, + ClientSecret: "client-secret", + Endpoint: oauth2.Endpoint{ + AuthURL: hydraPublic + "/oauth2/auth", + TokenURL: hydraPublic + "/oauth2/token", + AuthStyle: oauth2.AuthStyleInParams, }, - }, - } { - t.Run(tc.name, func(t *testing.T) { - *cac = tc.cac - *kuc = tc.kuc - tc.configure(conf) + Scopes: scopes, + RedirectURL: clientAppTS.URL, + } + + browserClient := testhelpers.NewClientWithCookieJar(t, nil, false) + identifier := x.NewUUID().String() + password := x.NewUUID().String() + + ct := make([]callTrace, 0) + + kratosUIConfig := &testConfig{ + identifier: identifier, + password: password, + browserClient: browserClient, + kratosPublicTS: kratosPublicTS, + clientAppTS: clientAppTS, + hydraAdminClient: hydraAdminClient, + consentRemember: consentRemember, + requestedScope: scopes, + callTrace: &ct, + } - authCodeURL := makeAuthCodeURL(t, cac.client, "", false) - res, err := tc.kuc.browserClient.Get(authCodeURL) + clientAppConfig := &clientAppConfig{ + client: oauthClient, + expectToken: true, + } - 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) + expected := []callTrace{ + RegistrationUI, + RegistrationWithOAuth2LoginChallenge, + RegistrationUI, + RegistrationWithFlowID, + Consent, + ConsentWithChallenge, + ConsentAccept, + CodeExchange, + CodeExchangeWithToken, + } + + // set the global context values + ctx = context.WithValue(ctx, TestUIConfig, kratosUIConfig) + ctx = context.WithValue(ctx, TestOAuthClientState, clientAppConfig) + + doSuccessfulOAuthFlow := func(t *testing.T) { + t.Helper() + + clientAS := clientAppState{ + visits: 0, + tokens: 0, + } + clientAppConfig.state = &clientAS + + doOAuthFlow(t, ctx, + oauthClient, + browserClient) + assert.EqualValues(t, clientAppState{ + visits: 1, + tokens: 1, + }, clientAS) + + require.ElementsMatchf(t, expected, ct, "expected the call trace to match") + } + + doSuccessfulOAuthFlow(t) + + // reset our state on the client app + clientAS := clientAppState{ + visits: 0, + tokens: 0, + } + + clientAppConfig.state = &clientAS + + // reset the call trace + ct = []callTrace{} + kratosUIConfig.callTrace = &ct + + // we should now have a session, but not skip the consent page + doOAuthFlow(t, ctx, oauthClient, browserClient) + assert.EqualValues(t, clientAppState{ + visits: 1, + tokens: 1, + }, clientAS) + + expected = []callTrace{ + RegistrationUI, + RegistrationWithOAuth2LoginChallenge, + Consent, + ConsentWithChallenge, + ConsentSkip, + ConsentAccept, + CodeExchange, + CodeExchangeWithToken, + } + require.ElementsMatchf(t, expected, ct, "expected the call trace to match") + }) + + t.Run("case=should fail because the persistent Hydra session doesn't match the new Kratos session subject", func(t *testing.T) { + conf.MustSet(ctx, config.ViperKeySessionPersistentCookie, true) + t.Cleanup(func() { + conf.MustSet(ctx, config.ViperKeySessionPersistentCookie, false) }) - } + + // this test re-uses the previous oauthClient + // but creates a new user account through the registration flow + // since the session with the new user does not match the hydra session it should fail + scopes := []string{"profile", "email", "offline_access"} + clientID := createOAuth2Client(t, ctx, hydraAdminClient, []string{clientAppTS.URL}, strings.Join(scopes, " "), false) + + oauthClient := &oauth2.Config{ + ClientID: clientID, + ClientSecret: "client-secret", + Endpoint: oauth2.Endpoint{ + AuthURL: hydraPublic + "/oauth2/auth", + TokenURL: hydraPublic + "/oauth2/token", + AuthStyle: oauth2.AuthStyleInParams, + }, + Scopes: scopes, + RedirectURL: clientAppTS.URL, + } + + browserClient := testhelpers.NewClientWithCookieJar(t, nil, false) + + ct := make([]callTrace, 0) + + kratosUIConfig := &testConfig{ + identifier: x.NewUUID().String(), + password: x.NewUUID().String(), + kratosPublicTS: kratosPublicTS, + browserClient: browserClient, + clientAppTS: clientAppTS, + hydraAdminClient: hydraAdminClient, + consentRemember: true, + callTrace: &ct, + requestedScope: scopes, + } + + ctx = context.WithValue(ctx, TestUIConfig, kratosUIConfig) + + clientAppConfig := &clientAppConfig{ + client: oauthClient, + expectToken: false, + } + + ctx = context.WithValue(ctx, TestOAuthClientState, clientAppConfig) + + expected := []callTrace{ + RegistrationUI, + RegistrationWithOAuth2LoginChallenge, + RegistrationUI, + RegistrationWithFlowID, + Consent, + ConsentWithChallenge, + ConsentAccept, + CodeExchange, + CodeExchangeWithToken, + } + + doSuccessfulOAuthFlow := func(t *testing.T) { + t.Helper() + + clientAS := clientAppState{ + visits: 0, + tokens: 0, + } + clientAppConfig.state = &clientAS + + doOAuthFlow(t, ctx, + oauthClient, + browserClient) + + assert.EqualValues(t, clientAppState{ + visits: 1, + tokens: 1, + }, clientAS) + + require.ElementsMatch(t, expected, ct, "expected the call trace to match") + } + + doSuccessfulOAuthFlow(t) + + clientAS := clientAppState{ + visits: 0, + tokens: 0, + } + clientAppConfig.state = &clientAS + + currentURL, err := url.Parse(kratosPublicTS.URL) + require.NoError(t, err) + cookies := browserClient.Jar.Cookies(currentURL) + + // remove the kratos session so we can register a new account + for _, c := range cookies { + if c.Name == config.DefaultSessionCookieName { + c.MaxAge = -1 + c.Value = "" + break + } + } + browserClient.Jar.SetCookies(currentURL, cookies) + + kratosUIConfig.identifier = x.NewUUID().String() + kratosUIConfig.password = x.NewUUID().String() + + // reset the call trace + ct = []callTrace{} + kratosUIConfig.callTrace = &ct + + doOAuthFlow(t, ctx, + oauthClient, + browserClient) + + assert.EqualValues(t, clientAppState{ + visits: 0, + tokens: 0, + }, clientAS) + + expected = []callTrace{ + RegistrationUI, + RegistrationWithOAuth2LoginChallenge, + RegistrationUI, + RegistrationWithFlowID, + } + require.ElementsMatch(t, expected, ct, "expected the call trace to match") + }) } diff --git a/test/e2e/cypress/integration/profiles/oidc-provider/registration.spec.ts b/test/e2e/cypress/integration/profiles/oidc-provider/registration.spec.ts index 1452844f3c18..f29e3665e5f7 100644 --- a/test/e2e/cypress/integration/profiles/oidc-provider/registration.spec.ts +++ b/test/e2e/cypress/integration/profiles/oidc-provider/registration.spec.ts @@ -1,8 +1,7 @@ // Copyright © 2023 Ory Corp // SPDX-License-Identifier: Apache-2.0 -import { gen } from "../../../helpers" -import * as uuid from "uuid" +import { APP_URL, gen } from "../../../helpers" import * as oauth2 from "../../../helpers/oauth2" import * as httpbin from "../../../helpers/httpbin" @@ -66,4 +65,119 @@ context("OpenID Provider", () => { expect(idToken.amr).to.deep.equal(["password"]) }) }) + + it("registration with session, skip=false and skip=true", () => { + const email = gen.email() + const password = gen.password() + + cy.register({ + email, + password, + fields: { + "traits.website": "https://www.ory.sh", + "traits.tos": "1", + "traits.age": 22, + }, + }) + + const url = oauth2.getDefaultAuthorizeURL(client) + + cy.request(url).then((res) => { + const lastResp = res.allRequestResponses[1]["Request URL"] + const login_challenge = new URL(lastResp).searchParams.get( + "login_challenge", + ) + expect(login_challenge).to.not.be.null + cy.visit( + APP_URL + + "/self-service/registration/browser?login_challenge=" + + login_challenge, + ) + }) + + cy.url().should("contain", "/login") + cy.get("[data-testid='login-flow']").should("exist") + cy.get("[data-testid='login-flow'] [name='password']").type(password) + cy.get( + "[data-testid='login-flow'] button[name='method'][value='password']", + ).click() + + // we want to skip the consent flow here + // so we ask to remember the user + cy.get("[name='remember']").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", "password"]) + }) + + // use the hydra origin to make a new OAuth request from it + 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 = "http://localhost:4744/health/ready" + }) + }) + .then(() => { + // we don't want to redirect here since we only want the login challenge from hydra + // we reusing the challenge to navigate to the registration page + cy.request({ + url: oauth2.getDefaultAuthorizeURL(client), + followRedirect: false, + }) + .then((res) => { + expect(res.redirectedToUrl).to.include("login_challenge") + return new URL(res.redirectedToUrl).searchParams.get( + "login_challenge", + ) + }) + .then((login_challenge) => { + cy.get("body").then((body$) => { + const appWindow = body$[0].ownerDocument.defaultView + const appIframe = + appWindow.parent.document.querySelector("iframe") + + return new Promise((resolve) => { + appIframe.onload = () => resolve(undefined) + appWindow.location.href = + APP_URL + + "/self-service/registration/browser?login_challenge=" + + login_challenge + }) + }) + }) + }) + + 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", "password"]) + }) + }) }) From 9c608b991874d839782d9219f2fc27d0d4a398af Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Mon, 30 Oct 2023 11:51:57 +0100 Subject: [PATCH 165/282] fix: respect gomail.SendError in mail queue (#3600) --- courier/courier.go | 15 ++++++++------- courier/courier_dispatcher.go | 16 ++++++++++------ courier/courier_dispatcher_test.go | 1 + courier/smtp.go | 8 +++++++- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/courier/courier.go b/courier/courier.go index a1eeed13e111..7a7f022b68c9 100644 --- a/courier/courier.go +++ b/courier/courier.go @@ -39,6 +39,7 @@ type ( SetGetEmailTemplateType(f func(t EmailTemplate) (TemplateType, error)) SetNewEmailTemplateFromMessage(f func(d template.Dependencies, msg Message) (EmailTemplate, error)) UseBackoff(b backoff.BackOff) + FailOnDispatchError() } Provider interface { @@ -50,12 +51,12 @@ type ( } courier struct { - smsClient *smsClient - smtpClient *smtpClient - httpClient *httpClient - deps Dependencies - failOnError bool - backoff backoff.BackOff + smsClient *smsClient + smtpClient *smtpClient + httpClient *httpClient + deps Dependencies + failOnDispatchError bool + backoff backoff.BackOff } ) @@ -74,7 +75,7 @@ func NewCourier(ctx context.Context, deps Dependencies) (Courier, error) { } func (c *courier) FailOnDispatchError() { - c.failOnError = true + c.failOnDispatchError = true } func (c *courier) Work(ctx context.Context) error { diff --git a/courier/courier_dispatcher.go b/courier/courier_dispatcher.go index dbf3bfb7e795..9969b76ec3f2 100644 --- a/courier/courier_dispatcher.go +++ b/courier/courier_dispatcher.go @@ -73,36 +73,40 @@ func (c *courier) DispatchQueue(ctx context.Context) error { Error(`Unable to set the retried message's status to "abandoned".`) return err } + // Skip the message c.deps.Logger(). WithField("message_id", msg.ID). WithField("message_nid", msg.NID). Warnf(`Message was abandoned because it did not deliver after %d attempts`, msg.SendCount) - } else if err := c.DispatchMessage(ctx, msg); err != nil { - if err := c.deps.CourierPersister().RecordDispatch(ctx, msg.ID, CourierMessageDispatchStatusFailed, err); err != nil { c.deps.Logger(). WithError(err). WithField("message_id", msg.ID). WithField("message_nid", msg.NID). Error(`Unable to record failure log entry.`) + if c.failOnDispatchError { + return err + } } for _, replace := range messages[k:] { if err := c.deps.CourierPersister().SetMessageStatus(ctx, replace.ID, MessageStatusQueued); err != nil { - if c.failOnError { - return err - } c.deps.Logger(). WithError(err). WithField("message_id", replace.ID). WithField("message_nid", replace.NID). Error(`Unable to reset the failed message's status to "queued".`) + if c.failOnDispatchError { + return err + } } } - return err + if c.failOnDispatchError { + return err + } } else if err := c.deps.CourierPersister().RecordDispatch(ctx, msg.ID, CourierMessageDispatchStatusSuccess, nil); err != nil { c.deps.Logger(). WithError(err). diff --git a/courier/courier_dispatcher_test.go b/courier/courier_dispatcher_test.go index e0ad2b61b371..528badf2de02 100644 --- a/courier/courier_dispatcher_test.go +++ b/courier/courier_dispatcher_test.go @@ -66,6 +66,7 @@ func TestDispatchQueue(t *testing.T) { c, err := reg.Courier(ctx) require.NoError(t, err) + c.FailOnDispatchError() ctx, cancel := context.WithCancel(ctx) defer cancel() diff --git a/courier/smtp.go b/courier/smtp.go index 23bb60700d3d..3de84b00384c 100644 --- a/courier/smtp.go +++ b/courier/smtp.go @@ -215,7 +215,12 @@ func (c *courier) dispatchEmail(ctx context.Context, msg Message) error { Error("Unable to send email using SMTP connection.") var protoErr *textproto.Error - if containsProtoErr := errors.As(err, &protoErr); containsProtoErr && protoErr.Code >= 500 { + var mailErr *gomail.SendError + + switch { + case errors.As(err, &mailErr) && mailErr.Index >= 500: + fallthrough + case errors.As(err, &protoErr) && protoErr.Code >= 500: // See https://en.wikipedia.org/wiki/List_of_SMTP_server_return_codes // If the SMTP server responds with 5xx, sending the message should not be retried (without changing something about the request) if err := c.deps.CourierPersister().SetMessageStatus(ctx, msg.ID, MessageStatusAbandoned); err != nil { @@ -227,6 +232,7 @@ func (c *courier) dispatchEmail(ctx context.Context, msg Message) error { return err } } + return errors.WithStack(herodot.ErrInternalServerError. WithError(err.Error()).WithReason("failed to send email via smtp")) } From 0e4be57e41e1152f4be22f490541c2c099cfe3fe Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Mon, 30 Oct 2023 15:25:20 +0100 Subject: [PATCH 166/282] feat: parametrize courier worker (#3601) Allows one to parametrize how many messages the courier will fetch and how often it will fetch messages. --- courier/courier.go | 3 ++- courier/courier_dispatcher.go | 3 ++- driver/config/config.go | 12 ++++++++++++ embedx/config.schema.json | 17 +++++++++++++++++ 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/courier/courier.go b/courier/courier.go index 7a7f022b68c9..b42a580fc061 100644 --- a/courier/courier.go +++ b/courier/courier.go @@ -100,6 +100,7 @@ func (c *courier) UseBackoff(b backoff.BackOff) { } func (c *courier) watchMessages(ctx context.Context, errChan chan error) { + wait := c.deps.CourierConfig().CourierWorkerPullWait(ctx) c.backoff.Reset() for { if err := backoff.Retry(func() error { @@ -108,6 +109,6 @@ func (c *courier) watchMessages(ctx context.Context, errChan chan error) { errChan <- err return } - time.Sleep(time.Second) + time.Sleep(wait) } } diff --git a/courier/courier_dispatcher.go b/courier/courier_dispatcher.go index 9969b76ec3f2..8470c024fca4 100644 --- a/courier/courier_dispatcher.go +++ b/courier/courier_dispatcher.go @@ -54,8 +54,9 @@ func (c *courier) DispatchMessage(ctx context.Context, msg Message) error { func (c *courier) DispatchQueue(ctx context.Context) error { maxRetries := c.deps.CourierConfig().CourierMessageRetries(ctx) + pullCount := c.deps.CourierConfig().CourierWorkerPullCount(ctx) - messages, err := c.deps.CourierPersister().NextMessages(ctx, 10) + messages, err := c.deps.CourierPersister().NextMessages(ctx, uint8(pullCount)) if err != nil { if errors.Is(err, ErrQueueEmpty) { return nil diff --git a/driver/config/config.go b/driver/config/config.go index 950152f6d088..edec657e10ae 100644 --- a/driver/config/config.go +++ b/driver/config/config.go @@ -77,6 +77,8 @@ const ( ViperKeyCourierSMSEnabled = "courier.sms.enabled" ViperKeyCourierSMSFrom = "courier.sms.from" ViperKeyCourierMessageRetries = "courier.message_retries" + ViperKeyCourierWorkerPullCount = "courier.worker.pull_count" + ViperKeyCourierWorkerPullWait = "courier.worker.pull_wait" ViperKeySecretsDefault = "secrets.default" ViperKeySecretsCookie = "secrets.cookie" ViperKeySecretsCipher = "secrets.cipher" @@ -289,6 +291,8 @@ type ( CourierTemplatesLoginCodeValid(ctx context.Context) *CourierEmailTemplate CourierTemplatesRegistrationCodeValid(ctx context.Context) *CourierEmailTemplate CourierMessageRetries(ctx context.Context) int + CourierWorkerPullCount(ctx context.Context) int + CourierWorkerPullWait(ctx context.Context) time.Duration } ) @@ -1110,6 +1114,14 @@ func (p *Config) CourierMessageRetries(ctx context.Context) int { return p.GetProvider(ctx).IntF(ViperKeyCourierMessageRetries, 5) } +func (p *Config) CourierWorkerPullCount(ctx context.Context) int { + return p.GetProvider(ctx).Int(ViperKeyCourierWorkerPullCount) +} + +func (p *Config) CourierWorkerPullWait(ctx context.Context) time.Duration { + return p.GetProvider(ctx).Duration(ViperKeyCourierWorkerPullWait) +} + func (p *Config) CourierSMTPHeaders(ctx context.Context) map[string]string { return p.GetProvider(ctx).StringMap(ViperKeyCourierSMTPHeaders) } diff --git a/embedx/config.schema.json b/embedx/config.schema.json index 0443ae5ae4f3..0f1cfd03546d 100644 --- a/embedx/config.schema.json +++ b/embedx/config.schema.json @@ -1781,6 +1781,23 @@ "default": 5, "examples": [10, 60] }, + "worker": { + "description": "Configures the dispatch worker.", + "type": "object", + "properties": { + "pull_count": { + "description": "Defines how many messages are pulled from the queue at once.", + "type": "integer", + "default": 10 + }, + "pull_wait": { + "description": "Defines how long the worker waits before pulling messages from the queue again.", + "type": "string", + "pattern": "^([0-9]+(ns|us|ms|s|m|h))+$", + "default": "1s" + } + } + }, "delivery_strategy": { "title": "Delivery Strategy", "description": "Defines how emails will be sent, either through SMTP (default) or HTTP.", From dffcdef6933b94e3c2f442a71dcd50ffc705e9db Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Mon, 30 Oct 2023 15:42:03 +0000 Subject: [PATCH 167/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98725d9b1c75..16f75c02aee3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-10-27)](#2023-10-27) +- [ (2023-10-30)](#2023-10-30) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -313,7 +313,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-10-27) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-10-30) ## Breaking Changes @@ -525,6 +525,28 @@ https://github.com/ory/kratos/pull/3480 - style: format +- Registration should accept hydra login + ([#3592](https://github.com/ory/kratos/issues/3592)) + ([7a47827](https://github.com/ory/kratos/commit/7a47827cfd58ef68ebfbbeaf5ed86c394ba2bd5e)): + + - fix: registration should accept hydra login + + - fix: oauth2 registration flow with session + + - wip: registration oauth flow tests + + - wip: refactor oauth flows test + + - wip: refactor op_registration_test + + - wip: oauth provider registration test + + - wip: refactor oauth flows test + + - fix(test): oauth provider login + + - style: format + - Registration with verification ([#3451](https://github.com/ory/kratos/issues/3451)) ([77c3196](https://github.com/ory/kratos/commit/77c3196fd60c5927b84e9a7f6546f80ac2d78ee5)) @@ -540,6 +562,9 @@ https://github.com/ory/kratos/pull/3480 - Remove slow queries from update identities ([#3553](https://github.com/ory/kratos/issues/3553)) ([d138abb](https://github.com/ory/kratos/commit/d138abb6278ebb232e120bee0fb956a0f2816b8d)) +- Respect gomail.SendError in mail queue + ([#3600](https://github.com/ory/kratos/issues/3600)) + ([9c608b9](https://github.com/ory/kratos/commit/9c608b991874d839782d9219f2fc27d0d4a398af)) - Respond with 422 when SPA identity requires AAL2 ([#3572](https://github.com/ory/kratos/issues/3572)) ([df18c09](https://github.com/ory/kratos/commit/df18c09e0089743e8aee17540d277b9572252e06)): @@ -793,6 +818,13 @@ https://github.com/ory/kratos/pull/3480 - One-time code native flows ([#3516](https://github.com/ory/kratos/issues/3516)) ([9b0fee3](https://github.com/ory/kratos/commit/9b0fee30f980d860fd548e7589fa6a06e593537a)) +- Parametrize courier worker + ([#3601](https://github.com/ory/kratos/issues/3601)) + ([0e4be57](https://github.com/ory/kratos/commit/0e4be57e41e1152f4be22f490541c2c099cfe3fe)): + + Allows one to parametrize how many messages the courier will fetch and how + often it will fetch messages. + - Passwordless browser login and registration via code to email ([#3378](https://github.com/ory/kratos/issues/3378)) ([eaaf375](https://github.com/ory/kratos/commit/eaaf37519917612671238412a633847386d7c613)), From a639e562f216a43038625b7fa6a75165dc66ba61 Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Tue, 31 Oct 2023 10:23:18 +0100 Subject: [PATCH 168/282] chore: fix email address in courier log line (#3585) --- selfservice/strategy/code/code_sender.go | 2 +- selfservice/strategy/link/sender.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/selfservice/strategy/code/code_sender.go b/selfservice/strategy/code/code_sender.go index d3667aea3b07..3317fafdb2e4 100644 --- a/selfservice/strategy/code/code_sender.go +++ b/selfservice/strategy/code/code_sender.go @@ -252,7 +252,7 @@ func (s *Sender) SendVerificationCode(ctx context.Context, f *verification.Flow, s.deps.Audit(). WithField("via", via). WithField("strategy", "code"). - WithSensitiveField("email_address", address). + WithSensitiveField("email_address", to). WithField("was_notified", notifyUnknownRecipients). Info("Address verification was requested for an unknown address.") if !notifyUnknownRecipients { diff --git a/selfservice/strategy/link/sender.go b/selfservice/strategy/link/sender.go index 99b6f22732fc..d58f167335d7 100644 --- a/selfservice/strategy/link/sender.go +++ b/selfservice/strategy/link/sender.go @@ -123,7 +123,7 @@ func (s *Sender) SendVerificationLink(ctx context.Context, f *verification.Flow, s.r.Audit(). WithField("via", via). WithField("strategy", "link"). - WithSensitiveField("email_address", address). + WithSensitiveField("email_address", to). WithField("was_notified", notifyUnknownRecipients). Info("Address verification was requested for an unknown address.") if !notifyUnknownRecipients { From 316cd4aacfe31efafa7d737a7c476e2c794e9c9b Mon Sep 17 00:00:00 2001 From: Patrik Date: Mon, 6 Nov 2023 15:58:17 +0100 Subject: [PATCH 169/282] chore: simplify courier code (#3603) --- courier/courier.go | 52 ++++---- courier/courier_dispatcher.go | 35 ++---- courier/courier_dispatcher_test.go | 9 +- courier/handler_test.go | 16 +-- courier/message.go | 15 +-- courier/message_test.go | 7 +- courier/persistence.go | 5 - courier/test/persistence.go | 117 ++++++------------ persistence/sql/persister_courier.go | 61 +-------- selfservice/hook/verification_test.go | 6 +- selfservice/strategy/code/code_sender_test.go | 14 ++- selfservice/strategy/link/sender.go | 3 +- selfservice/strategy/link/sender_test.go | 24 ++-- selfservice/strategy/profile/strategy_test.go | 13 +- 14 files changed, 138 insertions(+), 239 deletions(-) diff --git a/courier/courier.go b/courier/courier.go index b42a580fc061..1598344c3d2a 100644 --- a/courier/courier.go +++ b/courier/courier.go @@ -65,12 +65,17 @@ func NewCourier(ctx context.Context, deps Dependencies) (Courier, error) { if err != nil { return nil, err } + + expBackoff := backoff.NewExponentialBackOff() + // never stop retrying + expBackoff.MaxElapsedTime = 0 + return &courier{ smsClient: newSMS(ctx, deps), smtpClient: smtp, httpClient: newHTTP(ctx, deps), deps: deps, - backoff: backoff.NewExponentialBackOff(), + backoff: expBackoff, }, nil } @@ -79,36 +84,29 @@ func (c *courier) FailOnDispatchError() { } func (c *courier) Work(ctx context.Context) error { - errChan := make(chan error) - defer close(errChan) - - go c.watchMessages(ctx, errChan) - - select { - case <-ctx.Done(): - if errors.Is(ctx.Err(), context.Canceled) { - return nil + wait := c.deps.CourierConfig().CourierWorkerPullWait(ctx) + for { + select { + case <-ctx.Done(): + if errors.Is(ctx.Err(), context.Canceled) { + return nil + } + return ctx.Err() + case <-time.After(wait): + if err := backoff.Retry(func() error { + if err := c.DispatchQueue(ctx); err != nil { + return err + } + // when we succeed, we want to reset the backoff + c.backoff.Reset() + return nil + }, c.backoff); err != nil { + return err + } } - return ctx.Err() - case err := <-errChan: - return err } } func (c *courier) UseBackoff(b backoff.BackOff) { c.backoff = b } - -func (c *courier) watchMessages(ctx context.Context, errChan chan error) { - wait := c.deps.CourierConfig().CourierWorkerPullWait(ctx) - c.backoff.Reset() - for { - if err := backoff.Retry(func() error { - return c.DispatchQueue(ctx) - }, c.backoff); err != nil { - errChan <- err - return - } - time.Sleep(wait) - } -} diff --git a/courier/courier_dispatcher.go b/courier/courier_dispatcher.go index 8470c024fca4..33d909e59fb2 100644 --- a/courier/courier_dispatcher.go +++ b/courier/courier_dispatcher.go @@ -58,13 +58,10 @@ func (c *courier) DispatchQueue(ctx context.Context) error { messages, err := c.deps.CourierPersister().NextMessages(ctx, uint8(pullCount)) if err != nil { - if errors.Is(err, ErrQueueEmpty) { - return nil - } return err } - for k, msg := range messages { + for _, msg := range messages { if msg.SendCount > maxRetries { if err := c.deps.CourierPersister().SetMessageStatus(ctx, msg.ID, MessageStatusAbandoned); err != nil { c.deps.Logger(). @@ -80,41 +77,33 @@ func (c *courier) DispatchQueue(ctx context.Context) error { WithField("message_id", msg.ID). WithField("message_nid", msg.NID). Warnf(`Message was abandoned because it did not deliver after %d attempts`, msg.SendCount) - } else if err := c.DispatchMessage(ctx, msg); err != nil { + continue + } + + if err := c.DispatchMessage(ctx, msg); err != nil { if err := c.deps.CourierPersister().RecordDispatch(ctx, msg.ID, CourierMessageDispatchStatusFailed, err); err != nil { c.deps.Logger(). WithError(err). WithField("message_id", msg.ID). WithField("message_nid", msg.NID). Error(`Unable to record failure log entry.`) - if c.failOnDispatchError { - return err - } - } - - for _, replace := range messages[k:] { - if err := c.deps.CourierPersister().SetMessageStatus(ctx, replace.ID, MessageStatusQueued); err != nil { - c.deps.Logger(). - WithError(err). - WithField("message_id", replace.ID). - WithField("message_nid", replace.NID). - Error(`Unable to reset the failed message's status to "queued".`) - if c.failOnDispatchError { - return err - } - } + return err } if c.failOnDispatchError { return err } - } else if err := c.deps.CourierPersister().RecordDispatch(ctx, msg.ID, CourierMessageDispatchStatusSuccess, nil); err != nil { + // an error happened, but we want to ignore it + continue + } + + if err := c.deps.CourierPersister().RecordDispatch(ctx, msg.ID, CourierMessageDispatchStatusSuccess, nil); err != nil { c.deps.Logger(). WithError(err). WithField("message_id", msg.ID). WithField("message_nid", msg.NID). Error(`Unable to record success log entry.`) - // continue with execution, as the message was successfully dispatched + return err } } diff --git a/courier/courier_dispatcher_test.go b/courier/courier_dispatcher_test.go index 528badf2de02..b621072c9997 100644 --- a/courier/courier_dispatcher_test.go +++ b/courier/courier_dispatcher_test.go @@ -44,15 +44,16 @@ func TestDispatchMessageWithInvalidSMTP(t *testing.T) { t.Run("case=failed sending", func(t *testing.T) { id := queueNewMessage(t, ctx, c, reg) - message, err := reg.CourierPersister().LatestQueuedMessage(ctx) + messages, err := reg.CourierPersister().NextMessages(ctx, 10) require.NoError(t, err) - require.Equal(t, id, message.ID) + require.Len(t, messages, 1) + require.Equal(t, id, messages[0].ID) - err = c.DispatchMessage(ctx, *message) + err = c.DispatchMessage(ctx, messages[0]) // sending the email fails, because there is no SMTP server at foo.url require.Error(t, err) - messages, err := reg.CourierPersister().NextMessages(ctx, 10) + messages, err = reg.CourierPersister().NextMessages(ctx, 10) require.NoError(t, err) require.Len(t, messages, 1) }) diff --git a/courier/handler_test.go b/courier/handler_test.go index b8920a5bc5f9..74c47bae5c53 100644 --- a/courier/handler_test.go +++ b/courier/handler_test.go @@ -96,7 +96,7 @@ func TestHandler(t *testing.T) { t.Run("case=list messages", func(t *testing.T) { // Arrange test data const msgCount = 10 // total message count - const procCount = 5 // how many messages' status should be equal to `processing` + const sentCount = 5 // how many messages' status should be equal to `processing` const rcptOryCount = 2 // how many messages' recipient should be equal to `noreply@ory.sh` messages := make([]courier.Message, msgCount) @@ -109,8 +109,8 @@ func TestHandler(t *testing.T) { } require.NoError(t, reg.CourierPersister().AddMessage(context.Background(), &messages[i])) } - for i := 0; i < procCount; i++ { - require.NoError(t, reg.CourierPersister().SetMessageStatus(context.Background(), messages[i].ID, courier.MessageStatusProcessing)) + for i := 0; i < sentCount; i++ { + require.NoError(t, reg.CourierPersister().SetMessageStatus(context.Background(), messages[i].ID, courier.MessageStatusSent)) } t.Run("paging", func(t *testing.T) { @@ -146,7 +146,7 @@ func TestHandler(t *testing.T) { for _, tc := range tss { t.Run("endpoint="+tc.name, func(t *testing.T) { parsed := getList(t, tc.name, qs) - assert.Len(t, parsed.Array(), msgCount-procCount) + assert.Len(t, parsed.Array(), msgCount-sentCount) for _, item := range parsed.Array() { assert.Equal(t, "queued", item.Get("status").String()) @@ -154,16 +154,16 @@ func TestHandler(t *testing.T) { }) } }) - t.Run("case=should return all processing messages", func(t *testing.T) { - qs := fmt.Sprintf(`?page_token=%s&page_size=250&status=processing`, defaultPageToken) + t.Run("case=should return all sent messages", func(t *testing.T) { + qs := fmt.Sprintf(`?page_token=%s&page_size=250&status=sent`, defaultPageToken) for _, tc := range tss { t.Run("endpoint="+tc.name, func(t *testing.T) { parsed := getList(t, tc.name, qs) - assert.Len(t, parsed.Array(), procCount) + assert.Len(t, parsed.Array(), sentCount) for _, item := range parsed.Array() { - assert.Equal(t, "processing", item.Get("status").String()) + assert.Equal(t, "sent", item.Get("status").String()) } }) } diff --git a/courier/message.go b/courier/message.go index 9ba9cf9cdb6c..9cf4399cc8b9 100644 --- a/courier/message.go +++ b/courier/message.go @@ -24,15 +24,14 @@ type MessageStatus int const ( MessageStatusQueued MessageStatus = iota + 1 MessageStatusSent - MessageStatusProcessing + _ MessageStatusAbandoned ) const ( - messageStatusQueuedText = "queued" - messageStatusSentText = "sent" - messageStatusProcessingText = "processing" - messageStatusAbandonedText = "abandoned" + messageStatusQueuedText = "queued" + messageStatusSentText = "sent" + messageStatusAbandonedText = "abandoned" ) func ToMessageStatus(str string) (MessageStatus, error) { @@ -41,8 +40,6 @@ func ToMessageStatus(str string) (MessageStatus, error) { return MessageStatusQueued, nil case s.AddCase(MessageStatusSent.String()): return MessageStatusSent, nil - case s.AddCase(MessageStatusProcessing.String()): - return MessageStatusProcessing, nil case s.AddCase(MessageStatusAbandoned.String()): return MessageStatusAbandoned, nil default: @@ -56,8 +53,6 @@ func (ms MessageStatus) String() string { return messageStatusQueuedText case MessageStatusSent: return messageStatusSentText - case MessageStatusProcessing: - return messageStatusProcessingText case MessageStatusAbandoned: return messageStatusAbandonedText default: @@ -67,7 +62,7 @@ func (ms MessageStatus) String() string { func (ms MessageStatus) IsValid() error { switch ms { - case MessageStatusQueued, MessageStatusSent, MessageStatusProcessing, MessageStatusAbandoned: + case MessageStatusQueued, MessageStatusSent, MessageStatusAbandoned: return nil default: return errors.WithStack(herodot.ErrBadRequest.WithReason("Message status is not valid")) diff --git a/courier/message_test.go b/courier/message_test.go index e8db6713bcf5..bb3af52ab71c 100644 --- a/courier/message_test.go +++ b/courier/message_test.go @@ -20,10 +20,9 @@ func TestMessageStatusValidity(t *testing.T) { func TestToMessageStatus(t *testing.T) { t.Run("case=should return corresponding MessageStatus for given str", func(t *testing.T) { for str, exp := range map[string]courier.MessageStatus{ - "queued": courier.MessageStatusQueued, - "sent": courier.MessageStatusSent, - "processing": courier.MessageStatusProcessing, - "abandoned": courier.MessageStatusAbandoned, + "queued": courier.MessageStatusQueued, + "sent": courier.MessageStatusSent, + "abandoned": courier.MessageStatusAbandoned, } { result, err := courier.ToMessageStatus(str) require.NoError(t, err) diff --git a/courier/persistence.go b/courier/persistence.go index 4e5834f7faca..a8547327250a 100644 --- a/courier/persistence.go +++ b/courier/persistence.go @@ -7,13 +7,10 @@ import ( "context" "github.com/gofrs/uuid" - "github.com/pkg/errors" "github.com/ory/x/pagination/keysetpagination" ) -var ErrQueueEmpty = errors.New("queue is empty") - type ( Persister interface { AddMessage(context.Context, *Message) error @@ -22,8 +19,6 @@ type ( SetMessageStatus(context.Context, uuid.UUID, MessageStatus) error - LatestQueuedMessage(ctx context.Context) (*Message, error) - IncrementMessageSendCount(context.Context, uuid.UUID) error // ListMessages lists all messages in the store given the page, itemsPerPage, status and recipient. diff --git a/courier/test/persistence.go b/courier/test/persistence.go index fad80efe1742..2a6e33650c84 100644 --- a/courier/test/persistence.go +++ b/courier/test/persistence.go @@ -6,10 +6,11 @@ package test import ( "context" "errors" - "fmt" "testing" "time" + "github.com/ory/x/pointerx" + "github.com/gobuffalo/pop/v6" "github.com/gofrs/uuid" "github.com/tidwall/gjson" @@ -38,85 +39,54 @@ func TestPersister(ctx context.Context, newNetworkUnlessExisting NetworkWrapper, t.Run("case=no messages in queue", func(t *testing.T) { m, err := p.NextMessages(ctx, 10) - require.ErrorIs(t, err, courier.ErrQueueEmpty) + require.NoError(t, err) assert.Len(t, m, 0) - - _, err = p.LatestQueuedMessage(ctx) - require.ErrorIs(t, err, courier.ErrQueueEmpty) }) messages := make([]courier.Message, 5) t.Run("case=add messages to the queue", func(t *testing.T) { + start := time.Now().UTC() for k := range messages { + pop.SetNowFunc(func() time.Time { + return start.Add(time.Duration(k) * time.Second) + }) require.NoError(t, faker.FakeData(&messages[k])) require.NoError(t, p.AddMessage(ctx, &messages[k])) - time.Sleep(time.Second) // wait a bit so that the timestamp ordering works in MySQL. } + pop.SetNowFunc(time.Now) }) - t.Run("case=latest message in queue", func(t *testing.T) { - expected, err := p.LatestQueuedMessage(ctx) + t.Run("case=get queued messages", func(t *testing.T) { + actual, err := p.NextMessages(ctx, 10) require.NoError(t, err) - - actual := messages[len(messages)-1] - assert.Equal(t, expected.ID, actual.ID) - assert.Equal(t, expected.Subject, actual.Subject) - }) - - t.Run("case=pull messages from the queue", func(t *testing.T) { - for k, expected := range messages { - expected.Status = courier.MessageStatusProcessing - t.Run(fmt.Sprintf("message=%d", k), func(t *testing.T) { - messages, err := p.NextMessages(ctx, 1) - require.NoError(t, err) - require.Len(t, messages, 1) - - actual := messages[0] - assert.Equal(t, expected.ID, actual.ID) - assert.Equal(t, expected.Subject, actual.Subject) - assert.Equal(t, expected.Body, actual.Body) - assert.Equal(t, expected.Status, actual.Status) - assert.Equal(t, expected.Type, actual.Type) - assert.Equal(t, expected.Recipient, actual.Recipient) - }) - } - - _, err := p.NextMessages(ctx, 10) - require.ErrorIs(t, err, courier.ErrQueueEmpty) + assert.ElementsMatch(t, messages, actual) }) t.Run("case=setting message status", func(t *testing.T) { - require.NoError(t, p.SetMessageStatus(ctx, messages[0].ID, courier.MessageStatusQueued)) - ms, err := p.NextMessages(ctx, 1) - require.NoError(t, err) - require.Len(t, ms, 1) - assert.Equal(t, messages[0].ID, ms[0].ID) - require.NoError(t, p.SetMessageStatus(ctx, messages[0].ID, courier.MessageStatusSent)) - _, err = p.NextMessages(ctx, 1) - require.ErrorIs(t, err, courier.ErrQueueEmpty) + require.NoError(t, p.SetMessageStatus(ctx, messages[1].ID, courier.MessageStatusAbandoned)) + require.NoError(t, p.SetMessageStatus(ctx, messages[2].ID, courier.MessageStatusQueued)) - require.NoError(t, p.SetMessageStatus(ctx, messages[0].ID, courier.MessageStatusAbandoned)) - _, err = p.NextMessages(ctx, 1) - require.ErrorIs(t, err, courier.ErrQueueEmpty) + ms, err := p.NextMessages(ctx, 10) + require.NoError(t, err) + assert.ElementsMatch(t, messages[2:], ms) + + require.NoError(t, p.SetMessageStatus(ctx, messages[0].ID, courier.MessageStatusQueued)) + require.NoError(t, p.SetMessageStatus(ctx, messages[1].ID, courier.MessageStatusQueued)) }) t.Run("case=incrementing send count", func(t *testing.T) { originalSendCount := messages[0].SendCount - require.NoError(t, p.SetMessageStatus(ctx, messages[0].ID, courier.MessageStatusQueued)) require.NoError(t, p.IncrementMessageSendCount(ctx, messages[0].ID)) - ms, err := p.NextMessages(ctx, 1) + message, err := p.FetchMessage(ctx, messages[0].ID) require.NoError(t, err) - require.Len(t, ms, 1) - assert.Equal(t, messages[0].ID, ms[0].ID) - assert.Equal(t, originalSendCount+1, ms[0].SendCount) + assert.Equal(t, originalSendCount+1, message.SendCount) }) t.Run("case=list messages", func(t *testing.T) { - status := courier.MessageStatusProcessing filter := courier.ListCourierMessagesParameters{ - Status: &status, + Status: pointerx.Ptr(courier.MessageStatusQueued), } ms, total, _, err := p.ListMessages(ctx, filter, []keysetpagination.Option{}) @@ -141,24 +111,24 @@ func TestPersister(ctx context.Context, newNetworkUnlessExisting NetworkWrapper, nid2, p2 := newNetwork(t, ctx) const timeFormat = "2006-01-02 15:04:05.99999" msg1 := courier.Message{ - ID: uuid.FromStringOrNil("10000000-0000-0000-0000-000000000000"), + ID: uuid.Must(uuid.FromString("10000000-0000-0000-0000-000000000000")), NID: nid1, - Status: courier.MessageStatusProcessing, + Status: courier.MessageStatusQueued, } err = p1.GetConnection(ctx).Create(&msg1) require.NoError(t, err) msg2 := courier.Message{ - ID: uuid.FromStringOrNil("20000000-0000-0000-0000-000000000000"), + ID: uuid.Must(uuid.FromString("20000000-0000-0000-0000-000000000000")), NID: nid1, - Status: courier.MessageStatusProcessing, + Status: courier.MessageStatusQueued, } err = p1.GetConnection(ctx).Create(&msg2) require.NoError(t, err) msg3 := courier.Message{ - ID: uuid.FromStringOrNil("30000000-0000-0000-0000-000000000000"), + ID: uuid.Must(uuid.FromString("30000000-0000-0000-0000-000000000000")), NID: nid2, - Status: courier.MessageStatusProcessing, + Status: courier.MessageStatusQueued, } err = p2.GetConnection(ctx).Create(&msg3) require.NoError(t, err) @@ -193,16 +163,8 @@ func TestPersister(ctx context.Context, newNetworkUnlessExisting NetworkWrapper, assert.EqualValues(t, nid, expected.NID) assert.EqualValues(t, nid, p.NetworkID(ctx)) - actual, err := p.LatestQueuedMessage(ctx) + actual, err := p.FetchMessage(ctx, expected.ID) require.NoError(t, err) - assert.EqualValues(t, expected.ID, actual.ID) - assert.EqualValues(t, nid, actual.NID) - - actuals, err := p.NextMessages(ctx, 255) - require.NoError(t, err) - - actual = &actuals[0] - assert.EqualValues(t, expected.ID, actual.ID) assert.EqualValues(t, nid, actual.NID) }) @@ -216,32 +178,25 @@ func TestPersister(ctx context.Context, newNetworkUnlessExisting NetworkWrapper, assert.EqualValues(t, nid, expected.NID) assert.EqualValues(t, nid, p.NetworkID(ctx)) - actual, err := p.LatestQueuedMessage(ctx) - require.NoError(t, err) - assert.EqualValues(t, id, actual.ID) - assert.EqualValues(t, nid, actual.NID) - - actuals, err := p.NextMessages(ctx, 255) + actual, err := p.FetchMessage(ctx, id) require.NoError(t, err) - - actual = &actuals[0] - assert.EqualValues(t, id, actual.ID) assert.EqualValues(t, nid, actual.NID) }) t.Run("can not get on another network", func(t *testing.T) { _, p := newNetwork(t, ctx) - _, err := p.LatestQueuedMessage(ctx) - require.ErrorIs(t, err, courier.ErrQueueEmpty) + actual, err := p.NextMessages(ctx, 255) + require.NoError(t, err) + assert.Len(t, actual, 0) - _, err = p.NextMessages(ctx, 255) - require.ErrorIs(t, err, courier.ErrQueueEmpty) + _, err = p.FetchMessage(ctx, id) + assert.ErrorIs(t, err, sqlcon.ErrNoRows) }) t.Run("can not update on another network", func(t *testing.T) { _, p := newNetwork(t, ctx) - err := p.SetMessageStatus(ctx, id, courier.MessageStatusProcessing) + err := p.SetMessageStatus(ctx, id, courier.MessageStatusAbandoned) require.ErrorIs(t, err, sqlcon.ErrNoRows) }) diff --git a/persistence/sql/persister_courier.go b/persistence/sql/persister_courier.go index 437d9132e1d0..c706f8d547b1 100644 --- a/persistence/sql/persister_courier.go +++ b/persistence/sql/persister_courier.go @@ -5,10 +5,8 @@ package sql import ( "context" - "database/sql" "encoding/json" - "github.com/gobuffalo/pop/v6" "github.com/gofrs/uuid" "github.com/pkg/errors" @@ -18,7 +16,6 @@ import ( "github.com/ory/x/uuidx" "github.com/ory/kratos/courier" - "github.com/ory/kratos/persistence/sql/update" ) var _ courier.Persister = new(Persister) @@ -70,66 +67,18 @@ func (p *Persister) NextMessages(ctx context.Context, limit uint8) (messages []c ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.NextMessages") defer span.End() - if err := p.Transaction(ctx, func(ctx context.Context, tx *pop.Connection) error { - var m []courier.Message - if err := tx. - Where("nid = ? AND status = ?", - p.NetworkID(ctx), - courier.MessageStatusQueued, - ). - Order("created_at ASC"). - Limit(int(limit)). - All(&m); err != nil { - return err - } - - if len(m) == 0 { - return sql.ErrNoRows - } - - for i := range m { - message := &m[i] - message.Status = courier.MessageStatusProcessing - if err := update.Generic(ctx, p.GetConnection(ctx), p.r.Tracer(ctx).Tracer(), message, "status"); err != nil { - return err - } - } - - messages = m - return nil - }); err != nil { - if errors.Cause(err) == sql.ErrNoRows { - return nil, errors.WithStack(courier.ErrQueueEmpty) - } - return nil, sqlcon.HandleError(err) - } - - if len(messages) == 0 { - return nil, errors.WithStack(courier.ErrQueueEmpty) - } - - return messages, nil -} - -func (p *Persister) LatestQueuedMessage(ctx context.Context) (*courier.Message, error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.LatestQueuedMessage") - defer span.End() - - var m courier.Message - if err := p.GetConnection(ctx). + if err := p.Connection(ctx). Where("nid = ? AND status = ?", p.NetworkID(ctx), courier.MessageStatusQueued, ). - Order("created_at DESC"). - First(&m); err != nil { - if errors.Is(err, sql.ErrNoRows) { - return nil, errors.WithStack(courier.ErrQueueEmpty) - } + Order("created_at ASC"). + Limit(int(limit)). + All(&messages); err != nil { return nil, sqlcon.HandleError(err) } - return &m, nil + return messages, nil } func (p *Persister) SetMessageStatus(ctx context.Context, id uuid.UUID, ms courier.MessageStatus) error { diff --git a/selfservice/hook/verification_test.go b/selfservice/hook/verification_test.go index 652df7bec61c..8a60a2dfeb9d 100644 --- a/selfservice/hook/verification_test.go +++ b/selfservice/hook/verification_test.go @@ -11,6 +11,7 @@ import ( "time" "github.com/ory/kratos/courier" + "github.com/ory/kratos/internal/testhelpers" "github.com/stretchr/testify/assert" @@ -99,6 +100,9 @@ func TestVerifier(t *testing.T) { require.NoError(t, err) require.Len(t, messages, 2) + require.NoError(t, reg.CourierPersister().SetMessageStatus(context.Background(), messages[0].ID, courier.MessageStatusSent)) + require.NoError(t, reg.CourierPersister().SetMessageStatus(context.Background(), messages[1].ID, courier.MessageStatusSent)) + recipients := make([]string, len(messages)) for k, m := range messages { recipients[k] = m.Recipient @@ -131,7 +135,7 @@ func TestVerifier(t *testing.T) { require.NoError(t, err) messages, err = reg.CourierPersister().NextMessages(context.Background(), 12) - require.EqualError(t, err, courier.ErrQueueEmpty.Error()) + require.NoError(t, err) assert.Len(t, messages, 0) }) } diff --git a/selfservice/strategy/code/code_sender_test.go b/selfservice/strategy/code/code_sender_test.go index e5ba75826eb5..40ad1e03967e 100644 --- a/selfservice/strategy/code/code_sender_test.go +++ b/selfservice/strategy/code/code_sender_test.go @@ -65,6 +65,9 @@ func TestSender(t *testing.T) { require.NoError(t, err) require.Len(t, messages, 2) + require.NoError(t, reg.CourierPersister().SetMessageStatus(ctx, messages[0].ID, courier.MessageStatusSent)) + require.NoError(t, reg.CourierPersister().SetMessageStatus(ctx, messages[1].ID, courier.MessageStatusSent)) + assert.EqualValues(t, "tracked@ory.sh", messages[0].Recipient) assert.Contains(t, messages[0].Subject, "Recover access to your account") @@ -90,6 +93,9 @@ func TestSender(t *testing.T) { require.NoError(t, err) require.Len(t, messages, 2) + require.NoError(t, reg.CourierPersister().SetMessageStatus(ctx, messages[0].ID, courier.MessageStatusSent)) + require.NoError(t, reg.CourierPersister().SetMessageStatus(ctx, messages[1].ID, courier.MessageStatusSent)) + assert.EqualValues(t, "tracked@ory.sh", messages[0].Recipient) assert.Equal(t, messages[0].Subject, subject+" valid") assert.Contains(t, messages[0].Body, body) @@ -121,6 +127,9 @@ func TestSender(t *testing.T) { require.NoError(t, err) require.Len(t, messages, 2) + require.NoError(t, reg.CourierPersister().SetMessageStatus(ctx, messages[0].ID, courier.MessageStatusSent)) + require.NoError(t, reg.CourierPersister().SetMessageStatus(ctx, messages[1].ID, courier.MessageStatusSent)) + assert.EqualValues(t, "tracked@ory.sh", messages[0].Recipient) assert.Contains(t, messages[0].Subject, "Please verify your email address") @@ -146,6 +155,9 @@ func TestSender(t *testing.T) { require.NoError(t, err) require.Len(t, messages, 2) + require.NoError(t, reg.CourierPersister().SetMessageStatus(ctx, messages[0].ID, courier.MessageStatusSent)) + require.NoError(t, reg.CourierPersister().SetMessageStatus(ctx, messages[1].ID, courier.MessageStatusSent)) + assert.EqualValues(t, "tracked@ory.sh", messages[0].Recipient) assert.Equal(t, messages[0].Subject, subject+" valid") assert.Contains(t, messages[0].Body, body) @@ -206,7 +218,7 @@ func TestSender(t *testing.T) { messages, err := reg.CourierPersister().NextMessages(ctx, 0) - require.ErrorIs(t, err, courier.ErrQueueEmpty) + require.NoError(t, err) require.Len(t, messages, 0) }) } diff --git a/selfservice/strategy/link/sender.go b/selfservice/strategy/link/sender.go index d58f167335d7..4190cf7988a6 100644 --- a/selfservice/strategy/link/sender.go +++ b/selfservice/strategy/link/sender.go @@ -5,6 +5,7 @@ package link import ( "context" + stderrors "errors" "net/url" "github.com/hashicorp/go-retryablehttp" @@ -51,7 +52,7 @@ type ( } ) -var ErrUnknownAddress = errors.New("verification requested for unknown address") +var ErrUnknownAddress = stderrors.New("verification requested for unknown address") func NewSender(r senderDependencies) *Sender { return &Sender{r: r} diff --git a/selfservice/strategy/link/sender_test.go b/selfservice/strategy/link/sender_test.go index 8fd62e038f3e..de0dc767d6da 100644 --- a/selfservice/strategy/link/sender_test.go +++ b/selfservice/strategy/link/sender_test.go @@ -10,7 +10,6 @@ import ( "io" "net/http" "net/http/httptest" - "sync" "testing" "time" @@ -62,6 +61,9 @@ func TestManager(t *testing.T) { require.NoError(t, err) require.Len(t, messages, 2) + require.NoError(t, reg.CourierPersister().SetMessageStatus(context.Background(), messages[0].ID, courier.MessageStatusSent)) + require.NoError(t, reg.CourierPersister().SetMessageStatus(context.Background(), messages[1].ID, courier.MessageStatusSent)) + assert.EqualValues(t, "tracked@ory.sh", messages[0].Recipient) assert.Contains(t, messages[0].Subject, "Recover access to your account") assert.Contains(t, messages[0].Body, urlx.AppendPaths(conf.SelfServiceLinkMethodBaseURL(ctx), recovery.RouteSubmitFlow).String()+"?") @@ -76,8 +78,6 @@ func TestManager(t *testing.T) { }) t.Run("method=SendRecoveryLink via HTTP", func(t *testing.T) { - var wg sync.WaitGroup - wg.Add(2) type requestBody struct { Recipient string RecoveryURL string `json:"recovery_url"` @@ -92,7 +92,6 @@ func TestManager(t *testing.T) { var message requestBody require.NoError(t, json.Unmarshal(b, &message)) messages = append(messages, &message) - wg.Done() })) t.Cleanup(srv.Close) requestConfig := fmt.Sprintf(`{"url": "%s"}`, srv.URL) @@ -102,12 +101,6 @@ func TestManager(t *testing.T) { cour, err := reg.Courier(ctx) require.NoError(t, err) - ctx, cancel := context.WithCancel(ctx) - defer t.Cleanup(cancel) - go func() { - require.NoError(t, cour.Work(ctx)) - }() - s, err := reg.RecoveryStrategies(ctx).Strategy("link") require.NoError(t, err) f, err := recovery.NewFlow(conf, time.Hour, "", u, s, flow.TypeBrowser) @@ -116,9 +109,9 @@ func TestManager(t *testing.T) { require.NoError(t, reg.RecoveryFlowPersister().CreateRecoveryFlow(context.Background(), f)) require.NoError(t, reg.LinkSender().SendRecoveryLink(context.Background(), f, "email", "tracked@ory.sh")) - require.EqualError(t, reg.LinkSender().SendRecoveryLink(context.Background(), f, "email", "not-tracked@ory.sh"), link.ErrUnknownAddress.Error()) + require.ErrorIs(t, reg.LinkSender().SendRecoveryLink(context.Background(), f, "email", "not-tracked@ory.sh"), link.ErrUnknownAddress) - wg.Wait() + require.NoError(t, cour.DispatchQueue(ctx)) assert.EqualValues(t, "tracked@ory.sh", messages[0].To) assert.Contains(t, messages[0].Subject, "Recover access to your account") @@ -139,11 +132,14 @@ func TestManager(t *testing.T) { require.NoError(t, reg.VerificationFlowPersister().CreateVerificationFlow(context.Background(), f)) require.NoError(t, reg.LinkSender().SendVerificationLink(context.Background(), f, "email", "tracked@ory.sh")) - require.EqualError(t, reg.LinkSender().SendVerificationLink(context.Background(), f, "email", "not-tracked@ory.sh"), link.ErrUnknownAddress.Error()) + require.ErrorIs(t, reg.LinkSender().SendVerificationLink(context.Background(), f, "email", "not-tracked@ory.sh"), link.ErrUnknownAddress) messages, err := reg.CourierPersister().NextMessages(context.Background(), 12) require.NoError(t, err) require.Len(t, messages, 2) + require.NoError(t, reg.CourierPersister().SetMessageStatus(context.Background(), messages[0].ID, courier.MessageStatusSent)) + require.NoError(t, reg.CourierPersister().SetMessageStatus(context.Background(), messages[1].ID, courier.MessageStatusSent)) + assert.EqualValues(t, "tracked@ory.sh", messages[0].Recipient) assert.Contains(t, messages[0].Subject, "Please verify") assert.Contains(t, messages[0].Body, urlx.AppendPaths(conf.SelfServiceLinkMethodBaseURL(ctx), verification.RouteSubmitFlow).String()+"?") @@ -207,7 +203,7 @@ func TestManager(t *testing.T) { messages, err := reg.CourierPersister().NextMessages(context.Background(), 0) - require.ErrorIs(t, err, courier.ErrQueueEmpty) + require.NoError(t, err) require.Len(t, messages, 0) }) } diff --git a/selfservice/strategy/profile/strategy_test.go b/selfservice/strategy/profile/strategy_test.go index f67407fe799f..d489e344a6ce 100644 --- a/selfservice/strategy/profile/strategy_test.go +++ b/selfservice/strategy/profile/strategy_test.go @@ -17,6 +17,8 @@ import ( "testing" "time" + "github.com/ory/kratos/courier" + "github.com/ory/x/jsonx" kratos "github.com/ory/kratos/internal/httpclient" @@ -531,9 +533,12 @@ func TestStrategyTraits(t *testing.T) { assert.EqualValues(t, flow.StateSuccess, gjson.Get(actual, "state").String(), "%s", actual) assert.Equal(t, newEmail, gjson.Get(actual, "ui.nodes.#(attributes.name==traits.email).attributes.value").Value(), "%s", actual) - m, err := reg.CourierPersister().LatestQueuedMessage(context.Background()) + ms, err := reg.CourierPersister().NextMessages(ctx, 10) require.NoError(t, err) - assert.Contains(t, m.Subject, "verify your email address") + require.Len(t, ms, 1) + assert.Contains(t, ms[0].Subject, "verify your email address") + + require.NoError(t, reg.CourierPersister().SetMessageStatus(ctx, ms[0].ID, courier.MessageStatusSent)) } payload := func(newEmail string) func(v url.Values) { @@ -550,13 +555,13 @@ func TestStrategyTraits(t *testing.T) { }) t.Run("type=spa", func(t *testing.T) { - newEmail := "update-verify-browser@mail.com" + newEmail := "update-verify-browser-1@mail.com" actual := expectSuccess(t, false, true, browserUser1, payload(newEmail)) check(t, actual, newEmail) }) t.Run("type=browser", func(t *testing.T) { - newEmail := "update-verify-browser@mail.com" + newEmail := "update-verify-browser-2@mail.com" actual := expectSuccess(t, false, false, browserUser1, payload(newEmail)) check(t, actual, newEmail) }) From 3b75f3700ec21e3d39751f069a593e5c9235a6bc Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Mon, 6 Nov 2023 15:59:56 +0000 Subject: [PATCH 170/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16f75c02aee3..61e062d397b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-10-30)](#2023-10-30) +- [ (2023-11-06)](#2023-11-06) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -313,7 +313,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-10-30) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-11-06) ## Breaking Changes From b784949d03b849d9d1d594977f75f5843b7b5da8 Mon Sep 17 00:00:00 2001 From: Henning Perl Date: Wed, 8 Nov 2023 10:12:09 +0100 Subject: [PATCH 171/282] feat: link oidc credentials when login (#3563) When user tries to login with OIDC for the first time but has already registered before with email/password a credentials identifier conflict may be detected by Kratos. In this case user needs to login with email/password first and then link OIDC credentials on a settings screen. This PR simplifies UX and allows user to link OIDC credentials to existing account right in the login flow, without switching to settings flow. Closes #2727 Closes #3222 --- cmd/clidoc/main.go | 5 + identity/manager.go | 79 ++++--- identity/manager_test.go | 63 ++++++ schema/errors.go | 10 + selfservice/flow/continue_with.go | 3 +- selfservice/flow/duplicate_credentials.go | 61 ++++++ selfservice/flow/flow.go | 4 +- selfservice/flow/login/flow.go | 8 + selfservice/flow/login/flow_test.go | 34 +++ selfservice/flow/login/handler.go | 8 +- selfservice/flow/login/hook.go | 63 +++++- selfservice/flow/login/hook_test.go | 59 ++++- selfservice/flow/login/strategy.go | 9 +- selfservice/flow/registration/flow.go | 24 +- selfservice/flow/registration/handler.go | 25 +-- selfservice/flow/registration/hook.go | 84 ++++--- ...rategy-method=TestPopulateLoginMethod.json | 22 ++ ...ategy-method=TestPopulateSignUpMethod.json | 22 ++ selfservice/strategy/oidc/strategy.go | 79 ++++++- .../strategy/oidc/strategy_registration.go | 2 + .../strategy/oidc/strategy_settings.go | 56 +++-- selfservice/strategy/oidc/strategy_test.go | 207 ++++++++++++++++-- .../strategy/password/registration_test.go | 3 +- session/manager_http.go | 2 +- session/session.go | 10 +- .../profiles/oidc/login/success.spec.ts | 40 +++- .../oidc/registration/success.spec.ts | 2 +- .../profiles/oidc/settings/success.spec.ts | 4 +- .../verification/settings/success.spec.ts | 12 +- text/id.go | 23 +- text/message_login.go | 45 ++++ text/message_node.go | 8 + text/message_validation.go | 5 +- 33 files changed, 905 insertions(+), 176 deletions(-) create mode 100644 selfservice/flow/duplicate_credentials.go diff --git a/cmd/clidoc/main.go b/cmd/clidoc/main.go index a9e96b909922..6a9ff0610017 100644 --- a/cmd/clidoc/main.go +++ b/cmd/clidoc/main.go @@ -119,10 +119,13 @@ func init() { "NewInfoLoginTOTPLabel": text.NewInfoLoginTOTPLabel(), "NewInfoLoginLookupLabel": text.NewInfoLoginLookupLabel(), "NewInfoLogin": text.NewInfoLogin(), + "NewInfoLoginAndLink": text.NewInfoLoginAndLink(), + "NewInfoLoginLinkMessage": text.NewInfoLoginLinkMessage("{duplicteIdentifier}", "{provider}", "{newLoginUrl}"), "NewInfoLoginTOTP": text.NewInfoLoginTOTP(), "NewInfoLoginLookup": text.NewInfoLoginLookup(), "NewInfoLoginVerify": text.NewInfoLoginVerify(), "NewInfoLoginWith": text.NewInfoLoginWith("{provider}"), + "NewInfoLoginWithAndLink": text.NewInfoLoginWithAndLink("{provider}"), "NewErrorValidationLoginFlowExpired": text.NewErrorValidationLoginFlowExpired(aSecondAgo), "NewErrorValidationLoginNoStrategyFound": text.NewErrorValidationLoginNoStrategyFound(), "NewErrorValidationRegistrationNoStrategyFound": text.NewErrorValidationRegistrationNoStrategyFound(), @@ -144,6 +147,7 @@ func init() { "NewErrorValidationRecoveryStateFailure": text.NewErrorValidationRecoveryStateFailure(), "NewInfoNodeInputEmail": text.NewInfoNodeInputEmail(), "NewInfoNodeResendOTP": text.NewInfoNodeResendOTP(), + "NewInfoNodeLoginAndLinkCredential": text.NewInfoNodeLoginAndLinkCredential(), "NewInfoNodeLabelContinue": text.NewInfoNodeLabelContinue(), "NewInfoSelfServiceSettingsRegisterWebAuthn": text.NewInfoSelfServiceSettingsRegisterWebAuthn(), "NewInfoLoginWebAuthnPasswordless": text.NewInfoLoginWebAuthnPasswordless(), @@ -163,6 +167,7 @@ func init() { "NewInfoSelfServiceLoginCode": text.NewInfoSelfServiceLoginCode(), "NewErrorValidationRegistrationRetrySuccessful": text.NewErrorValidationRegistrationRetrySuccessful(), "NewInfoSelfServiceRegistrationRegisterCode": text.NewInfoSelfServiceRegistrationRegisterCode(), + "NewErrorValidationLoginLinkedCredentialsDoNotMatch": text.NewErrorValidationLoginLinkedCredentialsDoNotMatch(), } } diff --git a/identity/manager.go b/identity/manager.go index 11220ec15f12..9bd02ce7451c 100644 --- a/identity/manager.go +++ b/identity/manager.go @@ -110,12 +110,7 @@ func (m *Manager) Create(ctx context.Context, i *Identity, opts ...ManagerOption return nil } -func (m *Manager) findExistingAuthMethod(ctx context.Context, e error, i *Identity) (err error) { - if !m.r.Config().SelfServiceFlowRegistrationLoginHints(ctx) { - return &ErrDuplicateCredentials{error: e} - } - // First we try to find the conflict in the identifiers table. This is most likely to have a conflict. - var found *Identity +func (m *Manager) ConflictingIdentity(ctx context.Context, i *Identity) (found *Identity, foundConflictAddress string, err error) { for ct, cred := range i.Credentials { for _, id := range cred.Identifiers { found, _, err = m.r.PrivilegedIdentityPool().FindByCredentialsIdentifier(ctx, ct, id) @@ -125,53 +120,65 @@ func (m *Manager) findExistingAuthMethod(ctx context.Context, e error, i *Identi // FindByCredentialsIdentifier does not expand identity credentials. if err = m.r.PrivilegedIdentityPool().HydrateIdentityAssociations(ctx, found, ExpandCredentials); err != nil { - return err + return nil, "", err } + + return found, id, nil } } // If the conflict is not in the identifiers table, it is coming from the verifiable or recovery address. - var foundConflictAddress string - if found == nil { - for _, va := range i.VerifiableAddresses { - conflictingAddress, err := m.r.PrivilegedIdentityPool().FindVerifiableAddressByValue(ctx, va.Via, va.Value) - if errors.Is(err, sqlcon.ErrNoRows) { - continue - } else if err != nil { - return err - } + for _, va := range i.VerifiableAddresses { + conflictingAddress, err := m.r.PrivilegedIdentityPool().FindVerifiableAddressByValue(ctx, va.Via, va.Value) + if errors.Is(err, sqlcon.ErrNoRows) { + continue + } else if err != nil { + return nil, "", err + } - foundConflictAddress = conflictingAddress.Value - found, err = m.r.PrivilegedIdentityPool().GetIdentity(ctx, conflictingAddress.IdentityID, ExpandCredentials) - if err != nil { - return err - } + foundConflictAddress = conflictingAddress.Value + found, err = m.r.PrivilegedIdentityPool().GetIdentity(ctx, conflictingAddress.IdentityID, ExpandCredentials) + if err != nil { + return nil, "", err } + + return found, foundConflictAddress, nil } // Last option: check the recovery address - if found == nil { - for _, va := range i.RecoveryAddresses { - conflictingAddress, err := m.r.PrivilegedIdentityPool().FindRecoveryAddressByValue(ctx, va.Via, va.Value) - if errors.Is(err, sqlcon.ErrNoRows) { - continue - } else if err != nil { - return err - } + for _, va := range i.RecoveryAddresses { + conflictingAddress, err := m.r.PrivilegedIdentityPool().FindRecoveryAddressByValue(ctx, va.Via, va.Value) + if errors.Is(err, sqlcon.ErrNoRows) { + continue + } else if err != nil { + return nil, "", err + } - foundConflictAddress = conflictingAddress.Value - found, err = m.r.PrivilegedIdentityPool().GetIdentity(ctx, conflictingAddress.IdentityID, ExpandCredentials) - if err != nil { - return err - } + foundConflictAddress = conflictingAddress.Value + found, err = m.r.PrivilegedIdentityPool().GetIdentity(ctx, conflictingAddress.IdentityID, ExpandCredentials) + if err != nil { + return nil, "", err } + + return found, foundConflictAddress, nil } - // Still not found? Return generic error. - if found == nil { + return nil, "", sqlcon.ErrNoRows +} + +func (m *Manager) findExistingAuthMethod(ctx context.Context, e error, i *Identity) (err error) { + if !m.r.Config().SelfServiceFlowRegistrationLoginHints(ctx) { return &ErrDuplicateCredentials{error: e} } + found, foundConflictAddress, err := m.ConflictingIdentity(ctx, i) + if err != nil { + if errors.Is(err, sqlcon.ErrNoRows) { + return &ErrDuplicateCredentials{error: e} + } + return err + } + // We need to sort the credentials for the error message to be deterministic. var creds []Credentials for _, cred := range found.Credentials { diff --git a/identity/manager_test.go b/identity/manager_test.go index 800d84590470..81001c9ba9c6 100644 --- a/identity/manager_test.go +++ b/identity/manager_test.go @@ -10,6 +10,7 @@ import ( "time" "github.com/ory/x/pointerx" + "github.com/ory/x/sqlcon" "github.com/gofrs/uuid" @@ -556,6 +557,68 @@ func TestManager(t *testing.T) { checkExtensionFields(fromStore, "email-updatetraits-1@ory.sh")(t) }) }) + + t.Run("method=ConflictingIdentity", func(t *testing.T) { + ctx := context.Background() + + conflicOnIdentifier := identity.NewIdentity(config.DefaultIdentityTraitsSchemaID) + conflicOnIdentifier.Traits = identity.Traits(`{"email":"conflict-on-identifier@example.com"}`) + require.NoError(t, reg.IdentityManager().Create(ctx, conflicOnIdentifier)) + + conflicOnVerifiableAddress := identity.NewIdentity(config.DefaultIdentityTraitsSchemaID) + conflicOnVerifiableAddress.Traits = identity.Traits(`{"email":"user-va@example.com", "email_verify":"conflict-on-va@example.com"}`) + require.NoError(t, reg.IdentityManager().Create(ctx, conflicOnVerifiableAddress)) + + conflicOnRecoveryAddress := identity.NewIdentity(config.DefaultIdentityTraitsSchemaID) + conflicOnRecoveryAddress.Traits = identity.Traits(`{"email":"user-ra@example.com", "email_recovery":"conflict-on-ra@example.com"}`) + require.NoError(t, reg.IdentityManager().Create(ctx, conflicOnRecoveryAddress)) + + t.Run("case=returns not found if no conflict", func(t *testing.T) { + found, foundConflictAddress, err := reg.IdentityManager().ConflictingIdentity(ctx, &identity.Identity{ + Credentials: map[identity.CredentialsType]identity.Credentials{ + identity.CredentialsTypePassword: {Identifiers: []string{"no-conflict@example.com"}}, + }, + }) + assert.ErrorIs(t, err, sqlcon.ErrNoRows) + assert.Nil(t, found) + assert.Empty(t, foundConflictAddress) + }) + + t.Run("case=conflict on identifier", func(t *testing.T) { + found, foundConflictAddress, err := reg.IdentityManager().ConflictingIdentity(ctx, &identity.Identity{ + Credentials: map[identity.CredentialsType]identity.Credentials{ + identity.CredentialsTypePassword: {Identifiers: []string{"conflict-on-identifier@example.com"}}, + }, + }) + require.NoError(t, err) + assert.Equal(t, conflicOnIdentifier.ID, found.ID) + assert.Equal(t, "conflict-on-identifier@example.com", foundConflictAddress) + }) + + t.Run("case=conflict on verifiable address", func(t *testing.T) { + found, foundConflictAddress, err := reg.IdentityManager().ConflictingIdentity(ctx, &identity.Identity{ + VerifiableAddresses: []identity.VerifiableAddress{{ + Value: "conflict-on-va@example.com", + Via: "email", + }}, + }) + require.NoError(t, err) + assert.Equal(t, conflicOnVerifiableAddress.ID, found.ID) + assert.Equal(t, "conflict-on-va@example.com", foundConflictAddress) + }) + + t.Run("case=conflict on recovery address", func(t *testing.T) { + found, foundConflictAddress, err := reg.IdentityManager().ConflictingIdentity(ctx, &identity.Identity{ + RecoveryAddresses: []identity.RecoveryAddress{{ + Value: "conflict-on-ra@example.com", + Via: "email", + }}, + }) + require.NoError(t, err) + assert.Equal(t, conflicOnRecoveryAddress.ID, found.ID) + assert.Equal(t, "conflict-on-ra@example.com", foundConflictAddress) + }) + }) } func TestManagerNoDefaultNamedSchema(t *testing.T) { diff --git a/schema/errors.go b/schema/errors.go index 55957a10460c..d72e02af7d11 100644 --- a/schema/errors.go +++ b/schema/errors.go @@ -349,3 +349,13 @@ func NewLoginCodeInvalid() error { Messages: new(text.Messages).Add(text.NewErrorValidationLoginCodeInvalidOrAlreadyUsed()), }) } + +func NewLinkedCredentialsDoNotMatch() error { + return errors.WithStack(&ValidationError{ + ValidationError: &jsonschema.ValidationError{ + Message: `linked credentials do not match; please start a new flow`, + InstancePtr: "#/", + }, + Messages: new(text.Messages).Add(text.NewErrorValidationLoginLinkedCredentialsDoNotMatch()), + }) +} diff --git a/selfservice/flow/continue_with.go b/selfservice/flow/continue_with.go index 5d6eb6ff1619..a54af5abef5a 100644 --- a/selfservice/flow/continue_with.go +++ b/selfservice/flow/continue_with.go @@ -17,9 +17,8 @@ type ContinueWith any // swagger:enum ContinueWithActionSetOrySessionToken type ContinueWithActionSetOrySessionToken string -// #nosec G101 -- only a key constant const ( - ContinueWithActionSetOrySessionTokenString ContinueWithActionSetOrySessionToken = "set_ory_session_token" + ContinueWithActionSetOrySessionTokenString ContinueWithActionSetOrySessionToken = "set_ory_session_token" // #nosec G101 -- only a key constant ) var _ ContinueWith = new(ContinueWithSetOrySessionToken) diff --git a/selfservice/flow/duplicate_credentials.go b/selfservice/flow/duplicate_credentials.go new file mode 100644 index 000000000000..ddba57251ed2 --- /dev/null +++ b/selfservice/flow/duplicate_credentials.go @@ -0,0 +1,61 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package flow + +import ( + "encoding/json" + + "github.com/tidwall/gjson" + "github.com/tidwall/sjson" + + "github.com/ory/kratos/identity" + "github.com/ory/x/sqlxx" +) + +const internalContextDuplicateCredentialsPath = "registration_duplicate_credentials" + +type DuplicateCredentialsData struct { + CredentialsType identity.CredentialsType + CredentialsConfig sqlxx.JSONRawMessage + DuplicateIdentifier string +} + +type InternalContexter interface { + EnsureInternalContext() + GetInternalContext() sqlxx.JSONRawMessage + SetInternalContext(sqlxx.JSONRawMessage) +} + +// SetDuplicateCredentials sets the duplicate credentials data in the flow's internal context. +func SetDuplicateCredentials(flow InternalContexter, creds DuplicateCredentialsData) error { + if flow.GetInternalContext() == nil { + flow.EnsureInternalContext() + } + bytes, err := sjson.SetBytes( + flow.GetInternalContext(), + internalContextDuplicateCredentialsPath, + creds, + ) + if err != nil { + return err + } + flow.SetInternalContext(bytes) + + return nil +} + +// DuplicateCredentials returns the duplicate credentials data from the flow's internal context. +func DuplicateCredentials(flow InternalContexter) (*DuplicateCredentialsData, error) { + if flow.GetInternalContext() == nil { + flow.EnsureInternalContext() + } + raw := gjson.GetBytes(flow.GetInternalContext(), internalContextDuplicateCredentialsPath) + if !raw.IsObject() { + return nil, nil + } + var creds DuplicateCredentialsData + err := json.Unmarshal([]byte(raw.Raw), &creds) + + return &creds, err +} diff --git a/selfservice/flow/flow.go b/selfservice/flow/flow.go index be486e3723ae..ee9fbba6638d 100644 --- a/selfservice/flow/flow.go +++ b/selfservice/flow/flow.go @@ -8,15 +8,13 @@ import ( "net/http" "net/url" + "github.com/gofrs/uuid" "github.com/pkg/errors" "github.com/ory/herodot" "github.com/ory/kratos/driver/config" "github.com/ory/kratos/ui/container" "github.com/ory/kratos/x" - - "github.com/gofrs/uuid" - "github.com/ory/x/urlx" ) diff --git a/selfservice/flow/login/flow.go b/selfservice/flow/login/flow.go index 1bd95c7b1fad..5dd8422cdb84 100644 --- a/selfservice/flow/login/flow.go +++ b/selfservice/flow/login/flow.go @@ -231,6 +231,14 @@ func (f *Flow) EnsureInternalContext() { } } +func (f *Flow) GetInternalContext() sqlxx.JSONRawMessage { + return f.InternalContext +} + +func (f *Flow) SetInternalContext(bytes sqlxx.JSONRawMessage) { + f.InternalContext = bytes +} + func (f Flow) MarshalJSON() ([]byte, error) { type local Flow f.SetReturnTo() diff --git a/selfservice/flow/login/flow_test.go b/selfservice/flow/login/flow_test.go index 1c7f1e200a53..c33ac1dc99e3 100644 --- a/selfservice/flow/login/flow_test.go +++ b/selfservice/flow/login/flow_test.go @@ -17,6 +17,7 @@ import ( "github.com/tidwall/gjson" "github.com/ory/x/jsonx" + "github.com/ory/x/sqlxx" "github.com/ory/kratos/driver/config" "github.com/ory/kratos/identity" @@ -35,6 +36,7 @@ import ( ) func TestFakeFlow(t *testing.T) { + t.Parallel() var r login.Flow require.NoError(t, faker.FakeData(&r)) @@ -47,6 +49,7 @@ func TestFakeFlow(t *testing.T) { } func TestNewFlow(t *testing.T) { + t.Parallel() ctx := context.Background() conf, _ := internal.NewFastRegistryWithMocks(t) @@ -130,6 +133,7 @@ func TestNewFlow(t *testing.T) { } func TestFlow(t *testing.T) { + t.Parallel() r := &login.Flow{ID: x.NewUUID()} assert.Equal(t, r.ID, r.GetID()) @@ -154,6 +158,7 @@ func TestFlow(t *testing.T) { } func TestGetType(t *testing.T) { + t.Parallel() for _, ft := range []flow.Type{ flow.TypeAPI, flow.TypeBrowser, @@ -166,18 +171,21 @@ func TestGetType(t *testing.T) { } func TestGetRequestURL(t *testing.T) { + t.Parallel() expectedURL := "http://foo/bar/baz" f := &login.Flow{RequestURL: expectedURL} assert.Equal(t, expectedURL, f.GetRequestURL()) } func TestFlowEncodeJSON(t *testing.T) { + t.Parallel() assert.EqualValues(t, "", gjson.Get(jsonx.TestMarshalJSONString(t, &login.Flow{RequestURL: "https://foo.bar?foo=bar"}), "return_to").String()) assert.EqualValues(t, "/bar", gjson.Get(jsonx.TestMarshalJSONString(t, &login.Flow{RequestURL: "https://foo.bar?return_to=/bar"}), "return_to").String()) assert.EqualValues(t, "/bar", gjson.Get(jsonx.TestMarshalJSONString(t, login.Flow{RequestURL: "https://foo.bar?return_to=/bar"}), "return_to").String()) } func TestFlowDontOverrideReturnTo(t *testing.T) { + t.Parallel() f := &login.Flow{ReturnTo: "/foo"} f.SetReturnTo() assert.Equal(t, "/foo", f.ReturnTo) @@ -186,3 +194,29 @@ func TestFlowDontOverrideReturnTo(t *testing.T) { f.SetReturnTo() assert.Equal(t, "/bar", f.ReturnTo) } + +func TestDuplicateCredentials(t *testing.T) { + t.Parallel() + t.Run("case=returns previous data", func(t *testing.T) { + t.Parallel() + f := new(login.Flow) + dc := flow.DuplicateCredentialsData{ + CredentialsType: "foo", + CredentialsConfig: sqlxx.JSONRawMessage(`{"bar":"baz"}`), + DuplicateIdentifier: "bar", + } + + require.NoError(t, flow.SetDuplicateCredentials(f, dc)) + actual, err := flow.DuplicateCredentials(f) + require.NoError(t, err) + assert.Equal(t, dc, *actual) + }) + + t.Run("case=returns nil data", func(t *testing.T) { + t.Parallel() + f := new(login.Flow) + actual, err := flow.DuplicateCredentials(f) + require.NoError(t, err) + assert.Nil(t, actual) + }) +} diff --git a/selfservice/flow/login/handler.go b/selfservice/flow/login/handler.go index 9efb5f0844db..096a657c0869 100644 --- a/selfservice/flow/login/handler.go +++ b/selfservice/flow/login/handler.go @@ -100,6 +100,12 @@ func WithFlowReturnTo(returnTo string) FlowOption { } } +func WithInternalContext(internalContext []byte) FlowOption { + return func(f *Flow) { + f.InternalContext = internalContext + } +} + func WithFormErrorMessage(messages []text.Message) FlowOption { return func(f *Flow) { for i := range messages { @@ -793,7 +799,7 @@ continueLogin: } method := ss.CompletedAuthenticationMethod(r.Context()) - sess.CompletedLoginFor(method.Method, method.AAL) + sess.CompletedLoginForMethod(method) i = interim break } diff --git a/selfservice/flow/login/hook.go b/selfservice/flow/login/hook.go index 1bff4122ad1f..2af0c3daf1fc 100644 --- a/selfservice/flow/login/hook.go +++ b/selfservice/flow/login/hook.go @@ -9,22 +9,22 @@ import ( "net/http" "time" + "github.com/gofrs/uuid" + "github.com/pkg/errors" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" - "github.com/ory/kratos/x/events" - - "github.com/pkg/errors" - "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" "github.com/ory/kratos/selfservice/sessiontokenexchange" "github.com/ory/kratos/session" "github.com/ory/kratos/ui/container" "github.com/ory/kratos/ui/node" "github.com/ory/kratos/x" + "github.com/ory/kratos/x/events" "github.com/ory/x/otelx" ) @@ -47,6 +47,7 @@ type ( executorDependencies interface { config.Provider hydra.Provider + identity.PrivilegedPoolProvider session.ManagementProvider session.PersistenceProvider x.CSRFTokenGeneratorProvider @@ -55,7 +56,9 @@ type ( x.TracingProvider sessiontokenexchange.PersistenceProvider + FlowPersistenceProvider HooksProvider + StrategyProvider } HookExecutor struct { d executorDependencies @@ -129,6 +132,10 @@ func (e *HookExecutor) PostLoginHook( r = r.WithContext(ctx) defer otelx.End(span, &err) + if err := e.maybeLinkCredentials(r.Context(), s, i, a); err != nil { + return err + } + if err := s.Activate(r, i, e.d.Config(), time.Now().UTC()); err != nil { return err } @@ -321,3 +328,51 @@ func (e *HookExecutor) PreLoginHook(w http.ResponseWriter, r *http.Request, a *F return nil } + +// maybeLinkCredentials links the identity with the credentials of the inner context of the login flow. +func (e *HookExecutor) maybeLinkCredentials(ctx context.Context, sess *session.Session, ident *identity.Identity, loginFlow *Flow) error { + lc, err := flow.DuplicateCredentials(loginFlow) + if err != nil { + return err + } else if lc == nil { + return nil + } + + if err := e.checkDuplicateCredentialsIdentifierMatch(ctx, ident.ID, lc.DuplicateIdentifier); err != nil { + return err + } + strategy, err := e.d.AllLoginStrategies().Strategy(lc.CredentialsType) + if err != nil { + return err + } + + linkableStrategy, ok := strategy.(LinkableStrategy) + if !ok { + // This should never happen because we check for this in the registration flow. + return errors.Errorf("strategy is not linkable: %T", linkableStrategy) + } + + if err := linkableStrategy.Link(ctx, ident, lc.CredentialsConfig); err != nil { + return err + } + + method := strategy.CompletedAuthenticationMethod(ctx) + sess.CompletedLoginForMethod(method) + + return nil +} + +func (e *HookExecutor) checkDuplicateCredentialsIdentifierMatch(ctx context.Context, identityID uuid.UUID, match string) error { + i, err := e.d.PrivilegedIdentityPool().GetIdentityConfidential(ctx, identityID) + if err != nil { + return err + } + for _, credentials := range i.Credentials { + for _, identifier := range credentials.Identifiers { + if identifier == match { + return nil + } + } + } + return schema.NewLinkedCredentialsDoNotMatch() +} diff --git a/selfservice/flow/login/hook_test.go b/selfservice/flow/login/hook_test.go index ea3bd84bac72..052973317ca2 100644 --- a/selfservice/flow/login/hook_test.go +++ b/selfservice/flow/login/hook_test.go @@ -12,14 +12,15 @@ import ( "github.com/stretchr/testify/require" - "github.com/ory/kratos/hydra" - "github.com/ory/kratos/session" - "github.com/gobuffalo/httptest" "github.com/julienschmidt/httprouter" "github.com/stretchr/testify/assert" "github.com/tidwall/gjson" + "github.com/ory/kratos/hydra" + "github.com/ory/kratos/schema" + "github.com/ory/kratos/session" + "github.com/ory/kratos/driver/config" "github.com/ory/kratos/identity" "github.com/ory/kratos/internal" @@ -256,6 +257,58 @@ func TestLoginExecutor(t *testing.T) { assert.Contains(t, gjson.Get(body, "redirect_browser_to").String(), "/self-service/login/browser?aal=aal2", "%s", body) }) }) + + }) + t.Run("case=maybe links credential", func(t *testing.T) { + t.Cleanup(testhelpers.SelfServiceHookConfigReset(t, conf)) + + email := testhelpers.RandomEmail() + useIdentity := &identity.Identity{Credentials: map[identity.CredentialsType]identity.Credentials{ + identity.CredentialsTypePassword: { + Type: identity.CredentialsTypePassword, + Config: []byte(`{"hashed_password": "$argon2id$v=19$m=32,t=2,p=4$cm94YnRVOW5jZzFzcVE4bQ$MNzk5BtR2vUhrp6qQEjRNw"}`), + Identifiers: []string{email}, + }, + }} + require.NoError(t, reg.Persister().CreateIdentity(context.Background(), useIdentity)) + + credsOIDC, err := identity.NewCredentialsOIDC( + "id-token", + "access-token", + "refresh-token", + "my-provider", + email, + "", + ) + require.NoError(t, err) + + t.Run("sub-case=links matching identity", func(t *testing.T) { + res, _ := makeRequestPost(t, newServer(t, flow.TypeBrowser, useIdentity, func(l *login.Flow) { + require.NoError(t, flow.SetDuplicateCredentials(l, flow.DuplicateCredentialsData{ + CredentialsType: identity.CredentialsTypeOIDC, + CredentialsConfig: credsOIDC.Config, + DuplicateIdentifier: email, + })) + }), false, url.Values{}) + assert.EqualValues(t, http.StatusOK, res.StatusCode) + assert.EqualValues(t, "https://www.ory.sh/", res.Request.URL.String()) + + ident, err := reg.Persister().GetIdentity(ctx, useIdentity.ID, identity.ExpandCredentials) + require.NoError(t, err) + assert.Equal(t, 2, len(ident.Credentials)) + }) + + t.Run("sub-case=errors on non-matching identity", func(t *testing.T) { + res, body := makeRequestPost(t, newServer(t, flow.TypeBrowser, useIdentity, func(l *login.Flow) { + require.NoError(t, flow.SetDuplicateCredentials(l, flow.DuplicateCredentialsData{ + CredentialsType: identity.CredentialsTypeOIDC, + CredentialsConfig: credsOIDC.Config, + DuplicateIdentifier: "wrong@example.com", + })) + }), false, url.Values{}) + assert.EqualValues(t, http.StatusInternalServerError, res.StatusCode) + assert.Equal(t, schema.NewLinkedCredentialsDoNotMatch().Error(), body, "%s", body) + }) }) t.Run("type=api", func(t *testing.T) { diff --git a/selfservice/flow/login/strategy.go b/selfservice/flow/login/strategy.go index 818ecfea9cf0..c8ad84986a55 100644 --- a/selfservice/flow/login/strategy.go +++ b/selfservice/flow/login/strategy.go @@ -8,14 +8,13 @@ import ( "net/http" "github.com/gofrs/uuid" - - "github.com/ory/kratos/session" - "github.com/pkg/errors" "github.com/ory/kratos/identity" + "github.com/ory/kratos/session" "github.com/ory/kratos/ui/node" "github.com/ory/kratos/x" + "github.com/ory/x/sqlxx" ) type Strategy interface { @@ -29,6 +28,10 @@ type Strategy interface { type Strategies []Strategy +type LinkableStrategy interface { + Link(ctx context.Context, i *identity.Identity, credentials sqlxx.JSONRawMessage) error +} + func (s Strategies) Strategy(id identity.CredentialsType) (Strategy, error) { ids := make([]identity.CredentialsType, len(s)) for k, ss := range s { diff --git a/selfservice/flow/registration/flow.go b/selfservice/flow/registration/flow.go index 494bf72383af..b3dae8a6a1c5 100644 --- a/selfservice/flow/registration/flow.go +++ b/selfservice/flow/registration/flow.go @@ -11,25 +11,19 @@ import ( "time" "github.com/gobuffalo/pop/v6" - + "github.com/gofrs/uuid" + "github.com/pkg/errors" "github.com/tidwall/gjson" - "github.com/ory/x/sqlxx" - hydraclientgo "github.com/ory/hydra-client-go/v2" - "github.com/ory/kratos/driver/config" "github.com/ory/kratos/hydra" - "github.com/ory/kratos/ui/container" - - "github.com/gofrs/uuid" - "github.com/pkg/errors" - - "github.com/ory/x/urlx" - "github.com/ory/kratos/identity" "github.com/ory/kratos/selfservice/flow" + "github.com/ory/kratos/ui/container" "github.com/ory/kratos/x" + "github.com/ory/x/sqlxx" + "github.com/ory/x/urlx" ) // swagger:model registrationFlow @@ -208,6 +202,14 @@ func (f *Flow) EnsureInternalContext() { } } +func (f *Flow) GetInternalContext() sqlxx.JSONRawMessage { + return f.InternalContext +} + +func (f *Flow) SetInternalContext(bytes sqlxx.JSONRawMessage) { + f.InternalContext = bytes +} + func (f Flow) MarshalJSON() ([]byte, error) { type local Flow f.SetReturnTo() diff --git a/selfservice/flow/registration/handler.go b/selfservice/flow/registration/handler.go index 2857fa459ee5..8cfe59e4d6d9 100644 --- a/selfservice/flow/registration/handler.go +++ b/selfservice/flow/registration/handler.go @@ -9,30 +9,25 @@ import ( "time" "github.com/gofrs/uuid" - - "github.com/ory/herodot" - "github.com/ory/kratos/hydra" - "github.com/ory/kratos/selfservice/sessiontokenexchange" - "github.com/ory/kratos/text" - "github.com/ory/nosurf" - - "github.com/ory/kratos/schema" - - "github.com/ory/kratos/identity" - "github.com/ory/kratos/ui/node" - "github.com/julienschmidt/httprouter" "github.com/pkg/errors" - "github.com/ory/x/sqlxx" - "github.com/ory/x/urlx" - + "github.com/ory/herodot" hydraclientgo "github.com/ory/hydra-client-go/v2" "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/errorx" "github.com/ory/kratos/selfservice/flow" + "github.com/ory/kratos/selfservice/sessiontokenexchange" "github.com/ory/kratos/session" + "github.com/ory/kratos/text" + "github.com/ory/kratos/ui/node" "github.com/ory/kratos/x" + "github.com/ory/nosurf" + "github.com/ory/x/sqlxx" + "github.com/ory/x/urlx" ) const ( diff --git a/selfservice/flow/registration/hook.go b/selfservice/flow/registration/hook.go index f7a7fed1d99f..6a997009c1c5 100644 --- a/selfservice/flow/registration/hook.go +++ b/selfservice/flow/registration/hook.go @@ -9,23 +9,21 @@ import ( "net/http" "time" - "go.opentelemetry.io/otel/attribute" - - "github.com/ory/x/otelx" - "github.com/julienschmidt/httprouter" - - "github.com/ory/kratos/selfservice/sessiontokenexchange" - "github.com/ory/kratos/x/events" - "github.com/pkg/errors" + "go.opentelemetry.io/otel/attribute" "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/selfservice/flow/login" + "github.com/ory/kratos/selfservice/sessiontokenexchange" "github.com/ory/kratos/session" "github.com/ory/kratos/x" + "github.com/ory/kratos/x/events" + "github.com/ory/x/otelx" + "github.com/ory/x/sqlcon" ) type ( @@ -75,10 +73,14 @@ type ( executorDependencies interface { config.Provider identity.ManagementProvider + identity.PrivilegedPoolProvider identity.ValidationProvider + login.FlowPersistenceProvider + login.StrategyProvider session.PersistenceProvider session.ManagementProvider HooksProvider + FlowPersistenceProvider hydra.Provider x.CSRFTokenGeneratorProvider x.HTTPClientProvider @@ -99,7 +101,7 @@ func NewHookExecutor(d executorDependencies) *HookExecutor { return &HookExecutor{d: d} } -func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Request, ct identity.CredentialsType, provider string, a *Flow, i *identity.Identity) (err error) { +func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Request, ct identity.CredentialsType, provider string, registrationFlow *Flow, i *identity.Identity) (err error) { ctx := r.Context() ctx, span := e.d.Tracer(ctx).Tracer().Start(ctx, "HookExecutor.PostRegistrationHook") r = r.WithContext(ctx) @@ -111,7 +113,7 @@ func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Reque WithField("flow_method", ct). Debug("Running PostRegistrationPrePersistHooks.") for k, executor := range e.d.PostRegistrationPrePersistHooks(r.Context(), ct) { - if err := executor.ExecutePostRegistrationPrePersistHook(w, r, a, i); err != nil { + if err := executor.ExecutePostRegistrationPrePersistHook(w, r, registrationFlow, i); err != nil { if errors.Is(err, ErrHookAbortFlow) { e.d.Logger(). WithRequest(r). @@ -135,7 +137,7 @@ func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Reque Error("ExecutePostRegistrationPostPersistHook hook failed with an error.") traits := i.Traits - return flow.HandleHookError(w, r, a, traits, ct.ToUiNodeGroup(), err, e.d, e.d) + return flow.HandleHookError(w, r, registrationFlow, traits, ct.ToUiNodeGroup(), err, e.d, e.d) } e.d.Logger().WithRequest(r). @@ -153,14 +155,36 @@ func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Reque // We're now creating the identity because any of the hooks could trigger a "redirect" or a "session" which // would imply that the identity has to exist already. } else if err := e.d.IdentityManager().Create(r.Context(), i); err != nil { + if errors.Is(err, sqlcon.ErrUniqueViolation) { + strategy, err := e.d.AllLoginStrategies().Strategy(ct) + if err != nil { + return err + } + + if _, ok := strategy.(login.LinkableStrategy); ok { + duplicateIdentifier, err := e.getDuplicateIdentifier(r.Context(), i) + if err != nil { + return err + } + registrationDuplicateCredentials := flow.DuplicateCredentialsData{ + CredentialsType: ct, + CredentialsConfig: i.Credentials[ct].Config, + DuplicateIdentifier: duplicateIdentifier, + } + + if err := flow.SetDuplicateCredentials(registrationFlow, registrationDuplicateCredentials); err != nil { + return err + } + } + } return err } // Verify the redirect URL before we do any other processing. c := e.d.Config() returnTo, err := x.SecureRedirectTo(r, c.SelfServiceBrowserDefaultReturnTo(r.Context()), - x.SecureRedirectReturnTo(a.ReturnTo), - x.SecureRedirectUseSourceURL(a.RequestURL), + x.SecureRedirectReturnTo(registrationFlow.ReturnTo), + x.SecureRedirectUseSourceURL(registrationFlow.RequestURL), x.SecureRedirectAllowURLs(c.SelfServiceBrowserAllowedReturnToDomains(r.Context())), x.SecureRedirectAllowSelfServiceURLs(c.SelfPublicURL(r.Context())), x.SecureRedirectOverrideDefaultReturnTo(c.SelfServiceFlowRegistrationReturnTo(r.Context(), ct.String())), @@ -179,7 +203,7 @@ func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Reque WithField("identity_id", i.ID). Info("A new identity has registered using self-service registration.") - span.AddEvent(events.NewRegistrationSucceeded(r.Context(), i.ID, string(a.Type), a.Active.String(), provider)) + span.AddEvent(events.NewRegistrationSucceeded(r.Context(), i.ID, string(registrationFlow.Type), registrationFlow.Active.String(), provider)) s := session.NewInactiveSession() @@ -201,7 +225,7 @@ func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Reque WithField("flow_method", ct). Debug("Running PostRegistrationPostPersistHooks.") for k, executor := range e.d.PostRegistrationPostPersistHooks(r.Context(), ct) { - if err := executor.ExecutePostRegistrationPostPersistHook(w, r, a, s); err != nil { + if err := executor.ExecutePostRegistrationPostPersistHook(w, r, registrationFlow, s); err != nil { if errors.Is(err, ErrHookAbortFlow) { e.d.Logger(). WithRequest(r). @@ -230,7 +254,7 @@ func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Reque span.SetAttributes(attribute.String("redirect_reason", "hook error"), attribute.String("executor", fmt.Sprintf("%T", executor))) traits := i.Traits - return flow.HandleHookError(w, r, a, traits, ct.ToUiNodeGroup(), err, e.d, e.d) + return flow.HandleHookError(w, r, registrationFlow, traits, ct.ToUiNodeGroup(), err, e.d, e.d) } e.d.Logger().WithRequest(r). @@ -248,13 +272,13 @@ func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Reque WithField("identity_id", i.ID). Debug("Post registration execution hooks completed successfully.") - if a.Type == flow.TypeAPI || x.IsJSONRequest(r) { + if registrationFlow.Type == flow.TypeAPI || x.IsJSONRequest(r) { span.SetAttributes(attribute.String("flow_type", string(flow.TypeAPI))) - if a.IDToken != "" { + if registrationFlow.IDToken != "" { // We don't want to redirect with the code, if the flow was submitted with an ID token. // This is the case for Sign in with native Apple SDK or Google SDK. - } else if handled, err := e.d.SessionManager().MaybeRedirectAPICodeFlow(w, r, a, s.ID, ct.ToUiNodeGroup()); err != nil { + } else if handled, err := e.d.SessionManager().MaybeRedirectAPICodeFlow(w, r, registrationFlow, s.ID, ct.ToUiNodeGroup()); err != nil { return errors.WithStack(err) } else if handled { return nil @@ -262,21 +286,21 @@ func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Reque e.d.Writer().Write(w, r, &APIFlowResponse{ Identity: i, - ContinueWith: a.ContinueWith(), + ContinueWith: registrationFlow.ContinueWith(), }) return nil } finalReturnTo := returnTo.String() - if a.OAuth2LoginChallenge != "" { - if a.ReturnToVerification != "" { + if registrationFlow.OAuth2LoginChallenge != "" { + if registrationFlow.ReturnToVerification != "" { // Special case: If Kratos is used as a login UI *and* we want to show the verification UI, // redirect to the verification URL first and then return to Hydra. - finalReturnTo = a.ReturnToVerification + finalReturnTo = registrationFlow.ReturnToVerification } else { callbackURL, err := e.d.Hydra().AcceptLoginRequest(r.Context(), hydra.AcceptLoginRequestParams{ - LoginChallenge: string(a.OAuth2LoginChallenge), + LoginChallenge: string(registrationFlow.OAuth2LoginChallenge), IdentityID: i.ID.String(), SessionID: s.ID.String(), AuthenticationMethods: s.AMR, @@ -287,8 +311,8 @@ func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Reque finalReturnTo = callbackURL } span.SetAttributes(attribute.String("redirect_reason", "oauth2 login challenge")) - } else if a.ReturnToVerification != "" { - finalReturnTo = a.ReturnToVerification + } else if registrationFlow.ReturnToVerification != "" { + finalReturnTo = registrationFlow.ReturnToVerification span.SetAttributes(attribute.String("redirect_reason", "verification requested")) } span.SetAttributes(attribute.String("return_to", finalReturnTo)) @@ -297,6 +321,14 @@ func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Reque return nil } +func (e *HookExecutor) getDuplicateIdentifier(ctx context.Context, i *identity.Identity) (string, error) { + _, id, err := e.d.IdentityManager().ConflictingIdentity(ctx, i) + if err != nil { + return "", err + } + return id, nil +} + func (e *HookExecutor) PreRegistrationHook(w http.ResponseWriter, r *http.Request, a *Flow) error { for _, executor := range e.d.PreRegistrationHooks(r.Context()) { if err := executor.ExecuteRegistrationPreHook(w, r, a); err != nil { diff --git a/selfservice/strategy/oidc/.snapshots/TestStrategy-method=TestPopulateLoginMethod.json b/selfservice/strategy/oidc/.snapshots/TestStrategy-method=TestPopulateLoginMethod.json index 9a93294a6040..04eba3e43565 100644 --- a/selfservice/strategy/oidc/.snapshots/TestStrategy-method=TestPopulateLoginMethod.json +++ b/selfservice/strategy/oidc/.snapshots/TestStrategy-method=TestPopulateLoginMethod.json @@ -36,6 +36,28 @@ } } }, + { + "type": "input", + "group": "oidc", + "attributes": { + "name": "provider", + "type": "submit", + "value": "secondProvider", + "disabled": false, + "node_type": "input" + }, + "messages": [], + "meta": { + "label": { + "id": 1010002, + "text": "Sign in with secondProvider", + "type": "info", + "context": { + "provider": "secondProvider" + } + } + } + }, { "type": "input", "group": "oidc", diff --git a/selfservice/strategy/oidc/.snapshots/TestStrategy-method=TestPopulateSignUpMethod.json b/selfservice/strategy/oidc/.snapshots/TestStrategy-method=TestPopulateSignUpMethod.json index 699d8d10ec62..e9b5dc03f8e6 100644 --- a/selfservice/strategy/oidc/.snapshots/TestStrategy-method=TestPopulateSignUpMethod.json +++ b/selfservice/strategy/oidc/.snapshots/TestStrategy-method=TestPopulateSignUpMethod.json @@ -36,6 +36,28 @@ } } }, + { + "type": "input", + "group": "oidc", + "attributes": { + "name": "provider", + "type": "submit", + "value": "secondProvider", + "disabled": false, + "node_type": "input" + }, + "messages": [], + "meta": { + "label": { + "id": 1040002, + "text": "Sign up with secondProvider", + "type": "info", + "context": { + "provider": "secondProvider" + } + } + } + }, { "type": "input", "group": "oidc", diff --git a/selfservice/strategy/oidc/strategy.go b/selfservice/strategy/oidc/strategy.go index 8031868f993f..2e536c8a35cf 100644 --- a/selfservice/strategy/oidc/strategy.go +++ b/selfservice/strategy/oidc/strategy.go @@ -11,9 +11,12 @@ import ( "encoding/json" "fmt" "net/http" + "net/url" "path/filepath" "strings" + "github.com/ory/x/urlx" + "go.opentelemetry.io/otel/attribute" "golang.org/x/oauth2" @@ -544,13 +547,48 @@ func (s *Strategy) handleError(w http.ResponseWriter, r *http.Request, f flow.Fl // This is kinda hacky and will probably need to be updated at some point. if dup := new(identity.ErrDuplicateCredentials); errors.As(err, &dup) { - rf.UI.Messages.Add(text.NewErrorValidationDuplicateCredentialsOnOIDCLink()) + err = schema.NewDuplicateCredentialsError(dup) + + if validationErr := new(schema.ValidationError); errors.As(err, &validationErr) { + for _, m := range validationErr.Messages { + m := m + rf.UI.Messages.Add(&m) + } + } else { + rf.UI.Messages.Add(text.NewErrorValidationDuplicateCredentialsOnOIDCLink()) + } + lf, err := s.registrationToLogin(w, r, rf, provider) if err != nil { return err } // return a new login flow with the error message embedded in the login flow. - x.AcceptToRedirectOrJSON(w, r, s.d.Writer(), lf, lf.AppendTo(s.d.Config().SelfServiceFlowLoginUI(r.Context())).String()) + redirectURL := lf.AppendTo(s.d.Config().SelfServiceFlowLoginUI(r.Context())) + if dc, err := flow.DuplicateCredentials(lf); err == nil && dc != nil { + redirectURL = urlx.CopyWithQuery(redirectURL, url.Values{"no_org_ui": {"true"}}) + + for i, n := range lf.UI.Nodes { + if n.Meta == nil || n.Meta.Label == nil { + continue + } + switch n.Meta.Label.ID { + case text.InfoSelfServiceLogin: + lf.UI.Nodes[i].Meta.Label = text.NewInfoLoginAndLink() + case text.InfoSelfServiceLoginWith: + p := gjson.GetBytes(n.Meta.Label.Context, "provider").String() + lf.UI.Nodes[i].Meta.Label = text.NewInfoLoginWithAndLink(p) + } + } + + newLoginURL := s.d.Config().SelfServiceFlowLoginUI(r.Context()).String() + lf.UI.Messages.Add(text.NewInfoLoginLinkMessage(dc.DuplicateIdentifier, provider, newLoginURL)) + + err := s.d.LoginFlowPersister().UpdateLoginFlow(r.Context(), lf) + if err != nil { + return err + } + } + x.AcceptToRedirectOrJSON(w, r, s.d.Writer(), lf, redirectURL.String()) // ensure the function does not continue to execute return flow.ErrCompletedByStrategy } @@ -630,3 +668,40 @@ func (s *Strategy) processIDToken(w http.ResponseWriter, r *http.Request, provid return claims, nil } + +func (s *Strategy) linkCredentials(ctx context.Context, i *identity.Identity, idToken, accessToken, refreshToken, provider, subject, organization string) error { + if err := s.d.PrivilegedIdentityPool().HydrateIdentityAssociations(ctx, i, identity.ExpandCredentials); err != nil { + return err + } + var conf identity.CredentialsOIDC + creds, err := i.ParseCredentials(s.ID(), &conf) + if errors.Is(err, herodot.ErrNotFound) { + var err error + if creds, err = identity.NewCredentialsOIDC(idToken, accessToken, refreshToken, provider, subject, organization); err != nil { + return err + } + } else if err != nil { + return err + } else { + creds.Identifiers = append(creds.Identifiers, identity.OIDCUniqueID(provider, subject)) + conf.Providers = append(conf.Providers, identity.CredentialsOIDCProvider{ + Subject: subject, Provider: provider, + InitialAccessToken: accessToken, + InitialRefreshToken: refreshToken, + InitialIDToken: idToken, + Organization: organization, + }) + + creds.Config, err = json.Marshal(conf) + if err != nil { + return err + } + } + + i.Credentials[s.ID()] = *creds + if orgID, err := uuid.FromString(organization); err == nil { + i.OrganizationID = uuid.NullUUID{UUID: orgID, Valid: true} + } + + return nil +} diff --git a/selfservice/strategy/oidc/strategy_registration.go b/selfservice/strategy/oidc/strategy_registration.go index b6747ef9ad0a..d07e6c6fa8ed 100644 --- a/selfservice/strategy/oidc/strategy_registration.go +++ b/selfservice/strategy/oidc/strategy_registration.go @@ -261,6 +261,8 @@ func (s *Strategy) registrationToLogin(w http.ResponseWriter, r *http.Request, r opts = append(opts, login.WithFormErrorMessage(rf.UI.Messages)) } + opts = append(opts, login.WithInternalContext(rf.InternalContext)) + lf, _, err := s.d.LoginHandler().NewLoginFlow(w, r, rf.Type, opts...) if err != nil { return nil, err diff --git a/selfservice/strategy/oidc/strategy_settings.go b/selfservice/strategy/oidc/strategy_settings.go index 513f5cccdabe..a38e4e0b40d9 100644 --- a/selfservice/strategy/oidc/strategy_settings.go +++ b/selfservice/strategy/oidc/strategy_settings.go @@ -11,6 +11,8 @@ import ( "net/http" "time" + "github.com/ory/x/sqlxx" + "github.com/tidwall/sjson" "golang.org/x/oauth2" @@ -412,31 +414,10 @@ func (s *Strategy) linkProvider(w http.ResponseWriter, r *http.Request, ctxUpdat return s.handleSettingsError(w, r, ctxUpdate, p, err) } - var conf identity.CredentialsOIDC - creds, err := i.ParseCredentials(s.ID(), &conf) - if errors.Is(err, herodot.ErrNotFound) { - var err error - if creds, err = identity.NewCredentialsOIDC(it, cat, crt, provider.Config().ID, claims.Subject, ""); err != nil { - return s.handleSettingsError(w, r, ctxUpdate, p, err) - } - } else if err != nil { + if err := s.linkCredentials(r.Context(), i, it, cat, crt, provider.Config().ID, claims.Subject, provider.Config().OrganizationID); err != nil { return s.handleSettingsError(w, r, ctxUpdate, p, err) - } else { - creds.Identifiers = append(creds.Identifiers, identity.OIDCUniqueID(provider.Config().ID, claims.Subject)) - conf.Providers = append(conf.Providers, identity.CredentialsOIDCProvider{ - Subject: claims.Subject, Provider: provider.Config().ID, - InitialAccessToken: cat, - InitialRefreshToken: crt, - InitialIDToken: it, - }) - - creds.Config, err = json.Marshal(conf) - if err != nil { - return s.handleSettingsError(w, r, ctxUpdate, p, err) - } } - i.Credentials[s.ID()] = *creds if err := s.d.SettingsHookExecutor().PostSettingsHook(w, r, s.SettingsStrategyID(), ctxUpdate, i, settings.WithCallback(func(ctxUpdate *settings.UpdateContext) error { return s.PopulateSettingsMethod(r, ctxUpdate.Session.Identity, ctxUpdate.Flow) })); err != nil { @@ -533,3 +514,34 @@ func (s *Strategy) handleSettingsError(w http.ResponseWriter, r *http.Request, c return err } + +func (s *Strategy) Link(ctx context.Context, i *identity.Identity, credentialsConfig sqlxx.JSONRawMessage) error { + var credentialsOIDCConfig identity.CredentialsOIDC + if err := json.Unmarshal(credentialsConfig, &credentialsOIDCConfig); err != nil { + return err + } + if len(credentialsOIDCConfig.Providers) != 1 { + return errors.New("No oidc provider was set") + } + var credentialsOIDCProvider = credentialsOIDCConfig.Providers[0] + + if err := s.linkCredentials( + ctx, + i, + credentialsOIDCProvider.InitialIDToken, + credentialsOIDCProvider.InitialAccessToken, + credentialsOIDCProvider.InitialRefreshToken, + credentialsOIDCProvider.Provider, + credentialsOIDCProvider.Subject, + credentialsOIDCProvider.Organization, + ); err != nil { + return err + } + + options := []identity.ManagerOption{identity.ManagerAllowWriteProtectedTraits} + if err := s.d.IdentityManager().Update(ctx, i, options...); err != nil { + return err + } + + return nil +} diff --git a/selfservice/strategy/oidc/strategy_test.go b/selfservice/strategy/oidc/strategy_test.go index 5d0a542ea7bd..cdbff20e0477 100644 --- a/selfservice/strategy/oidc/strategy_test.go +++ b/selfservice/strategy/oidc/strategy_test.go @@ -13,10 +13,13 @@ import ( "net/http/cookiejar" "net/http/httptest" "net/url" + "strconv" "strings" "testing" "time" + "github.com/ory/x/sqlxx" + "github.com/ory/kratos/hydra" "github.com/ory/kratos/selfservice/sessiontokenexchange" "github.com/ory/kratos/session" @@ -75,6 +78,7 @@ func TestStrategy(t *testing.T) { t, conf, newOIDCProvider(t, ts, remotePublic, remoteAdmin, "valid"), + newOIDCProvider(t, ts, remotePublic, remoteAdmin, "secondProvider"), oidc.Configuration{ Provider: "generic", ID: "invalid-issuer", @@ -217,8 +221,8 @@ func TestStrategy(t *testing.T) { var assertSystemErrorWithReason = func(t *testing.T, res *http.Response, body []byte, code int, reason string) { require.Contains(t, res.Request.URL.String(), errTS.URL, "%s", body) - assert.Equal(t, int64(code), gjson.GetBytes(body, "code").Int(), "%s", body) - assert.Contains(t, gjson.GetBytes(body, "reason").String(), reason, "%s", body) + assert.Equal(t, int64(code), gjson.GetBytes(body, "code").Int(), "%s", prettyJSON(t, body)) + assert.Contains(t, gjson.GetBytes(body, "reason").String(), reason, "%s", prettyJSON(t, body)) } // assert system error (redirect to error endpoint) @@ -232,15 +236,15 @@ func TestStrategy(t *testing.T) { // assert ui error (redirect to login/registration ui endpoint) var assertUIError = func(t *testing.T, res *http.Response, body []byte, reason string) { require.Contains(t, res.Request.URL.String(), uiTS.URL, "status: %d, body: %s", res.StatusCode, body) - assert.Contains(t, gjson.GetBytes(body, "ui.messages.0.text").String(), reason, "%s", body) + assert.Contains(t, gjson.GetBytes(body, "ui.messages.0.text").String(), reason, "%s", prettyJSON(t, body)) } // assert identity (success) var assertIdentity = func(t *testing.T, res *http.Response, body []byte) { - assert.Contains(t, res.Request.URL.String(), returnTS.URL) - assert.Equal(t, subject, gjson.GetBytes(body, "identity.traits.subject").String(), "%s", body) - assert.Equal(t, claims.traits.website, gjson.GetBytes(body, "identity.traits.website").String(), "%s", body) - assert.Equal(t, claims.metadataPublic.picture, gjson.GetBytes(body, "identity.metadata_public.picture").String(), "%s", body) + assert.Contains(t, res.Request.URL.String(), returnTS.URL, "%s", body) + assert.Equal(t, subject, gjson.GetBytes(body, "identity.traits.subject").String(), "%s", prettyJSON(t, body)) + assert.Equal(t, claims.traits.website, gjson.GetBytes(body, "identity.traits.website").String(), "%s", prettyJSON(t, body)) + assert.Equal(t, claims.metadataPublic.picture, gjson.GetBytes(body, "identity.metadata_public.picture").String(), "%s", prettyJSON(t, body)) } var newLoginFlow = func(t *testing.T, requestURL string, exp time.Duration, flowType flow.Type) (req *login.Flow) { @@ -433,23 +437,25 @@ func TestStrategy(t *testing.T) { }) }) + expectTokens := func(t *testing.T, provider string, body []byte) uuid.UUID { + id := uuid.FromStringOrNil(gjson.GetBytes(body, "identity.id").String()) + i, err := reg.PrivilegedIdentityPool().GetIdentityConfidential(context.Background(), id) + require.NoError(t, err) + c := i.Credentials[identity.CredentialsTypeOIDC].Config + assert.NotEmpty(t, gjson.GetBytes(c, "providers.0.initial_access_token").String()) + assertx.EqualAsJSONExcept( + t, + json.RawMessage(fmt.Sprintf(`{"providers": [{"subject":"%s","provider":"%s"}]}`, subject, provider)), + json.RawMessage(c), + []string{"providers.0.initial_id_token", "providers.0.initial_access_token", "providers.0.initial_refresh_token"}, + ) + return id + } + t.Run("case=register and then login", func(t *testing.T) { subject = "register-then-login@ory.sh" scope = []string{"openid", "offline"} - expectTokens := func(t *testing.T, provider string, body []byte) { - i, err := reg.PrivilegedIdentityPool().GetIdentityConfidential(context.Background(), uuid.FromStringOrNil(gjson.GetBytes(body, "identity.id").String())) - require.NoError(t, err) - c := i.Credentials[identity.CredentialsTypeOIDC].Config - assert.NotEmpty(t, gjson.GetBytes(c, "providers.0.initial_access_token").String()) - assertx.EqualAsJSONExcept( - t, - json.RawMessage(fmt.Sprintf(`{"providers": [{"subject":"%s","provider":"%s"}]}`, subject, provider)), - json.RawMessage(c), - []string{"providers.0.initial_id_token", "providers.0.initial_access_token", "providers.0.initial_refresh_token"}, - ) - } - t.Run("case=should pass registration", func(t *testing.T) { r := newBrowserRegistrationFlow(t, returnTS.URL, time.Minute) action := assertFormValues(t, r.ID, "valid") @@ -879,7 +885,7 @@ func TestStrategy(t *testing.T) { r := newBrowserRegistrationFlow(t, returnTS.URL, time.Minute) action := assertFormValues(t, r.ID, "valid") res, body := makeRequest(t, "valid", action, url.Values{}) - assertUIError(t, res, body, "An account with the same identifier (email, phone, username, ...) exists already. Please sign in to your existing account and link your social profile in the settings page.") + assertUIError(t, res, body, "An account with the same identifier (email, phone, username, ...) exists already.") require.Contains(t, gjson.GetBytes(body, "ui.action").String(), "/self-service/login") }) @@ -1068,6 +1074,158 @@ func TestStrategy(t *testing.T) { }) }) + t.Run("case=registration should start new login flow if duplicate credentials detected", func(t *testing.T) { + require.NoError(t, reg.Config().Set(ctx, config.ViperKeySelfServiceRegistrationLoginHints, true)) + loginWithOIDC := func(t *testing.T, c *http.Client, flowID uuid.UUID, provider string) (*http.Response, []byte) { + action := assertFormValues(t, flowID, provider) + res, err := c.PostForm(action, url.Values{"provider": {provider}}) + require.NoError(t, err, action) + body, err := io.ReadAll(res.Body) + require.NoError(t, res.Body.Close()) + require.NoError(t, err) + return res, body + } + + checkCredentialsLinked := func(res *http.Response, body []byte, identityID uuid.UUID, provider string) { + assert.Contains(t, res.Request.URL.String(), returnTS.URL, "%s", body) + assert.Equal(t, strings.ToLower(subject), gjson.GetBytes(body, "identity.traits.subject").String(), "%s", body) + i, err := reg.PrivilegedIdentityPool().GetIdentityConfidential(ctx, identityID) + require.NoError(t, err) + assert.NotEmpty(t, i.Credentials["oidc"], "%+v", i.Credentials) + assert.Equal(t, provider, gjson.GetBytes(i.Credentials["oidc"].Config, "providers.0.provider").String(), + "%s", string(i.Credentials["oidc"].Config[:])) + assert.Contains(t, gjson.GetBytes(body, "authentication_methods").String(), "oidc", "%s", body) + } + + t.Run("case=second login is password", func(t *testing.T) { + subject = "new-login-if-email-exist-with-password-strategy@ory.sh" + subject2 := "new-login-subject2@ory.sh" + scope = []string{"openid"} + password := "lwkj52sdkjf" + + var i *identity.Identity + t.Run("step=create password identity", func(t *testing.T) { + i = identity.NewIdentity(config.DefaultIdentityTraitsSchemaID) + p, err := reg.Hasher(ctx).Generate(ctx, []byte(password)) + require.NoError(t, err) + i.SetCredentials(identity.CredentialsTypePassword, identity.Credentials{ + Identifiers: []string{subject}, + Config: sqlxx.JSONRawMessage(`{"hashed_password":"` + string(p) + `"}`), + }) + i.Traits = identity.Traits(`{"subject":"` + subject + `"}`) + require.NoError(t, reg.PrivilegedIdentityPool().CreateIdentity(context.Background(), i)) + + i2 := identity.NewIdentity(config.DefaultIdentityTraitsSchemaID) + i2.SetCredentials(identity.CredentialsTypePassword, identity.Credentials{ + Identifiers: []string{subject2}, + Config: sqlxx.JSONRawMessage(`{"hashed_password":"` + string(p) + `"}`), + }) + i2.Traits = identity.Traits(`{"subject":"` + subject2 + `"}`) + require.NoError(t, reg.PrivilegedIdentityPool().CreateIdentity(context.Background(), i2)) + }) + + client := testhelpers.NewClientWithCookieJar(t, nil, false) + loginFlow := newLoginFlow(t, returnTS.URL, time.Minute, flow.TypeBrowser) + + var linkingLoginFlow struct { + ID string + UIAction string + CSRFToken string + } + + // To test that the subject is normalized properly + subject = strings.ToUpper(subject) + + t.Run("step=should fail login and start a new flow", func(t *testing.T) { + res, body := loginWithOIDC(t, client, loginFlow.ID, "valid") + assert.True(t, res.Request.URL.Query().Has("no_org_ui")) + assertUIError(t, res, body, "You tried signing in with new-login-if-email-exist-with-password-strategy@ory.sh which is already in use by another account. You can sign in using your password.") + assert.Equal(t, "password", gjson.GetBytes(body, "ui.messages.#(id==4000028).context.available_credential_types.0").String()) + assert.Equal(t, "new-login-if-email-exist-with-password-strategy@ory.sh", gjson.GetBytes(body, "ui.messages.#(id==4000028).context.credential_identifier_hint").String()) + linkingLoginFlow.ID = gjson.GetBytes(body, "id").String() + linkingLoginFlow.UIAction = gjson.GetBytes(body, "ui.action").String() + linkingLoginFlow.CSRFToken = gjson.GetBytes(body, `ui.nodes.#(attributes.name=="csrf_token").attributes.value`).String() + assert.NotEqual(t, loginFlow.ID.String(), linkingLoginFlow.ID, "should have started a new flow") + }) + + t.Run("step=should fail login if existing identity identifier doesn't match", func(t *testing.T) { + res, err := client.PostForm(linkingLoginFlow.UIAction, url.Values{ + "csrf_token": {linkingLoginFlow.CSRFToken}, + "method": {"password"}, + "identifier": {subject2}, + "password": {password}}) + require.NoError(t, err, linkingLoginFlow.UIAction) + body, err := io.ReadAll(res.Body) + require.NoError(t, res.Body.Close()) + require.NoError(t, err) + assert.Equal(t, + strconv.Itoa(int(text.ErrorValidationLoginLinkedCredentialsDoNotMatch)), + gjson.GetBytes(body, "ui.messages.0.id").String(), + prettyJSON(t, body), + ) + }) + + t.Run("step=should link oidc credentials to existing identity", func(t *testing.T) { + res, err := client.PostForm(linkingLoginFlow.UIAction, url.Values{ + "csrf_token": {linkingLoginFlow.CSRFToken}, + "method": {"password"}, + "identifier": {subject}, + "password": {password}}) + require.NoError(t, err, linkingLoginFlow.UIAction) + body, err := io.ReadAll(res.Body) + require.NoError(t, res.Body.Close()) + require.NoError(t, err) + checkCredentialsLinked(res, body, i.ID, "valid") + }) + }) + + t.Run("case=second login is OIDC", func(t *testing.T) { + email1 := "existing-oidc-identity-1@ory.sh" + email2 := "existing-oidc-identity-2@ory.sh" + scope = []string{"openid", "offline"} + + var identityID uuid.UUID + t.Run("step=create OIDC identity", func(t *testing.T) { + subject = email1 + r := newRegistrationFlow(t, returnTS.URL, time.Minute, flow.TypeBrowser) + action := assertFormValues(t, r.ID, "secondProvider") + res, body := makeRequest(t, "secondProvider", action, url.Values{}) + assertIdentity(t, res, body) + identityID = expectTokens(t, "secondProvider", body) + + subject = email2 + r = newRegistrationFlow(t, returnTS.URL, time.Minute, flow.TypeBrowser) + action = assertFormValues(t, r.ID, "valid") + res, body = makeRequest(t, "valid", action, url.Values{}) + assertIdentity(t, res, body) + expectTokens(t, "valid", body) + }) + + subject = email1 + client := testhelpers.NewClientWithCookieJar(t, nil, false) + loginFlow := newLoginFlow(t, returnTS.URL, time.Minute, flow.TypeBrowser) + var linkingLoginFlow struct{ ID string } + t.Run("step=should fail login and start a new login", func(t *testing.T) { + res, body := loginWithOIDC(t, client, loginFlow.ID, "valid") + assertUIError(t, res, body, "You tried signing in with existing-oidc-identity-1@ory.sh which is already in use by another account. You can sign in using social sign in. You can sign in using one of the following social sign in providers: Secondprovider.") + linkingLoginFlow.ID = gjson.GetBytes(body, "id").String() + assert.NotEqual(t, loginFlow.ID.String(), linkingLoginFlow.ID, "should have started a new flow") + }) + + subject = email2 + t.Run("step=should fail login if existing identity identifier doesn't match", func(t *testing.T) { + res, body := loginWithOIDC(t, client, uuid.Must(uuid.FromString(linkingLoginFlow.ID)), "valid") + assertUIError(t, res, body, "Linked credentials do not match.") + }) + + subject = email1 + t.Run("step=should link oidc credentials to existing identity", func(t *testing.T) { + res, body := loginWithOIDC(t, client, uuid.Must(uuid.FromString(linkingLoginFlow.ID)), "secondProvider") + checkCredentialsLinked(res, body, identityID, "secondProvider") + }) + }) + }) + t.Run("method=TestPopulateSignUpMethod", func(t *testing.T) { conf.MustSet(ctx, config.ViperKeyPublicBaseURL, "https://foo/") @@ -1089,6 +1247,13 @@ func TestStrategy(t *testing.T) { }) } +func prettyJSON(t *testing.T, body []byte) string { + var out bytes.Buffer + require.NoError(t, json.Indent(&out, body, "", "\t")) + + return out.String() +} + func TestCountActiveFirstFactorCredentials(t *testing.T) { _, reg := internal.NewFastRegistryWithMocks(t) strategy := oidc.NewStrategy(reg) diff --git a/selfservice/strategy/password/registration_test.go b/selfservice/strategy/password/registration_test.go index 2311741daad7..ddcf26a20883 100644 --- a/selfservice/strategy/password/registration_test.go +++ b/selfservice/strategy/password/registration_test.go @@ -5,6 +5,7 @@ package password_test import ( "context" + _ "embed" "fmt" "net/http" "net/http/httptest" @@ -31,8 +32,6 @@ import ( "github.com/ory/kratos/selfservice/flow/registration" "github.com/ory/x/assertx" - _ "embed" - "github.com/ory/kratos/x" ) diff --git a/session/manager_http.go b/session/manager_http.go index e1c31f94f03f..fbd6574e0b2c 100644 --- a/session/manager_http.go +++ b/session/manager_http.go @@ -364,7 +364,7 @@ func (s *ManagerHTTP) SessionAddAuthenticationMethods(ctx context.Context, sid u return err } for _, m := range ams { - sess.CompletedLoginFor(m.Method, m.AAL) + sess.CompletedLoginForMethod(m) } sess.SetAuthenticatorAssuranceLevel() return s.r.SessionPersister().UpsertSession(ctx, sess) diff --git a/session/session.go b/session/session.go index 74204be4215c..d11a05e3bf05 100644 --- a/session/session.go +++ b/session/session.go @@ -164,15 +164,19 @@ func (s Session) TableName(ctx context.Context) string { return "sessions" } +func (s *Session) CompletedLoginForMethod(method AuthenticationMethod) { + method.CompletedAt = time.Now().UTC() + s.AMR = append(s.AMR, method) +} + func (s *Session) CompletedLoginFor(method identity.CredentialsType, aal identity.AuthenticatorAssuranceLevel) { - s.AMR = append(s.AMR, AuthenticationMethod{Method: method, AAL: aal, CompletedAt: time.Now().UTC()}) + s.CompletedLoginForMethod(AuthenticationMethod{Method: method, AAL: aal}) } func (s *Session) CompletedLoginForWithProvider(method identity.CredentialsType, aal identity.AuthenticatorAssuranceLevel, providerID string, organizationID string) { - s.AMR = append(s.AMR, AuthenticationMethod{ + s.CompletedLoginForMethod(AuthenticationMethod{ Method: method, AAL: aal, - CompletedAt: time.Now().UTC(), Provider: providerID, Organization: organizationID, }) diff --git a/test/e2e/cypress/integration/profiles/oidc/login/success.spec.ts b/test/e2e/cypress/integration/profiles/oidc/login/success.spec.ts index 51ccf8574a6f..866f4344eda6 100644 --- a/test/e2e/cypress/integration/profiles/oidc/login/success.spec.ts +++ b/test/e2e/cypress/integration/profiles/oidc/login/success.spec.ts @@ -1,6 +1,6 @@ // Copyright © 2023 Ory Corp // SPDX-License-Identifier: Apache-2.0 -import { gen, website } from "../../../../helpers" +import { appPrefix, gen, website } from "../../../../helpers" import { routes as express } from "../../../../helpers/express" import { routes as react } from "../../../../helpers/react" @@ -9,16 +9,18 @@ context("Social Sign In Successes", () => { { login: react.login, registration: react.registration, + settings: react.settings, app: "react" as "react", profile: "spa", }, { login: express.login, registration: express.registration, + settings: express.settings, app: "express" as "express", profile: "oidc", }, - ].forEach(({ login, registration, profile, app }) => { + ].forEach(({ login, registration, profile, app, settings }) => { describe(`for app ${app}`, () => { before(() => { cy.useConfigProfile(profile) @@ -37,6 +39,40 @@ context("Social Sign In Successes", () => { cy.loginOidc({ app, url: login }) }) + it.only("should be able to sign up and link existing account", () => { + const email = gen.email() + const password = gen.password() + + // Create a new account + cy.registerApi({ + email, + password, + fields: { "traits.website": website }, + }) + + // Try to log in with the same identifier through OIDC. This should fail and create a new login flow. + cy.registerOidc({ + app, + email, + website, + expectSession: false, + }) + cy.noSession() + + // Log in with the same identifier through the login flow. This should link the accounts. + cy.get(`${appPrefix(app)}input[name="identifier"]`).type(email) + cy.get('input[name="password"]').type(password) + cy.submitPasswordForm() + cy.location("pathname").should("not.contain", "/login") + cy.getSession() + + // Hydra OIDC should now be linked + cy.visit(settings) + cy.get('[value="hydra"]') + .should("have.attr", "name", "unlink") + .should("contain.text", "Unlink hydra") + }) + it("should be able to sign up with redirects", () => { const email = gen.email() cy.registerOidc({ diff --git a/test/e2e/cypress/integration/profiles/oidc/registration/success.spec.ts b/test/e2e/cypress/integration/profiles/oidc/registration/success.spec.ts index ca2e2700ef7a..fe32cbbf61a2 100644 --- a/test/e2e/cypress/integration/profiles/oidc/registration/success.spec.ts +++ b/test/e2e/cypress/integration/profiles/oidc/registration/success.spec.ts @@ -244,7 +244,7 @@ context("Social Sign Up Successes", () => { route: registration, }) - cy.get('[data-testid="ui/message/4000027"]').should("be.visible") + cy.get('[data-testid="ui/message/1010016"]').should("be.visible") cy.location("href").should("contain", "/login") diff --git a/test/e2e/cypress/integration/profiles/oidc/settings/success.spec.ts b/test/e2e/cypress/integration/profiles/oidc/settings/success.spec.ts index 69f8e0f7d737..dadbc06d9453 100644 --- a/test/e2e/cypress/integration/profiles/oidc/settings/success.spec.ts +++ b/test/e2e/cypress/integration/profiles/oidc/settings/success.spec.ts @@ -42,9 +42,9 @@ context("Social Sign In Settings Success", () => { cy.get('input[name="traits.website"]').clear().type(website) cy.triggerOidc(app, "hydra") - cy.get('[data-testid="ui/message/4000027"]').should( + cy.get('[data-testid="ui/message/1010016"]').should( "contain.text", - "An account with the same identifier", + "Signing in will link your account", ) cy.noSession() diff --git a/test/e2e/cypress/integration/profiles/verification/settings/success.spec.ts b/test/e2e/cypress/integration/profiles/verification/settings/success.spec.ts index bba960f280ae..d17ee11b9dda 100644 --- a/test/e2e/cypress/integration/profiles/verification/settings/success.spec.ts +++ b/test/e2e/cypress/integration/profiles/verification/settings/success.spec.ts @@ -50,12 +50,14 @@ context("Account Verification Settings Success", () => { .clear() .type(email) cy.get('[value="profile"]').click() - cy.expectSettingsSaved() - cy.get('input[name="traits.email"]').should("contain.value", email) - cy.getSession().then( - assertVerifiableAddress({ isVerified: false, email }), - ) + if (app == "express") { + cy.expectSettingsSaved() + cy.get('input[name="traits.email"]').should("contain.value", email) + cy.getSession().then( + assertVerifiableAddress({ isVerified: false, email }), + ) + } cy.verifyEmail({ expect: { email } }) }) diff --git a/text/id.go b/text/id.go index c0274db092ef..fa8184f0ffaf 100644 --- a/text/id.go +++ b/text/id.go @@ -25,6 +25,9 @@ const ( InfoSelfServiceLoginContinue // 1010013 InfoSelfServiceLoginEmailWithCodeSent // 1010014 InfoSelfServiceLoginCode // 1010015 + InfoSelfServiceLoginLink // 1010016 + InfoSelfServiceLoginAndLink // 1010017 + InfoSelfServiceLoginWithAndLink // 1010018 ) const ( @@ -89,6 +92,7 @@ const ( InfoNodeLabelVerificationCode // 1070011 InfoNodeLabelRegistrationCode // 1070012 InfoNodeLabelLoginCode // 1070013 + InfoNodeLabelLoginAndLinkCredential ) const ( @@ -139,15 +143,16 @@ const ( ) const ( - ErrorValidationLogin ID = 4010000 + iota // 4010000 - ErrorValidationLoginFlowExpired // 4010001 - ErrorValidationLoginNoStrategyFound // 4010002 - ErrorValidationRegistrationNoStrategyFound // 4010003 - ErrorValidationSettingsNoStrategyFound // 4010004 - ErrorValidationRecoveryNoStrategyFound // 4010005 - ErrorValidationVerificationNoStrategyFound // 4010006 - ErrorValidationLoginRetrySuccess // 4010007 - ErrorValidationLoginCodeInvalidOrAlreadyUsed // 4010008 + ErrorValidationLogin ID = 4010000 + iota // 4010000 + ErrorValidationLoginFlowExpired // 4010001 + ErrorValidationLoginNoStrategyFound // 4010002 + ErrorValidationRegistrationNoStrategyFound // 4010003 + ErrorValidationSettingsNoStrategyFound // 4010004 + ErrorValidationRecoveryNoStrategyFound // 4010005 + ErrorValidationVerificationNoStrategyFound // 4010006 + ErrorValidationLoginRetrySuccess // 4010007 + ErrorValidationLoginCodeInvalidOrAlreadyUsed // 4010008 + ErrorValidationLoginLinkedCredentialsDoNotMatch // 4010009 ) const ( diff --git a/text/message_login.go b/text/message_login.go index 3afa27da46bf..4918cb893701 100644 --- a/text/message_login.go +++ b/text/message_login.go @@ -56,6 +56,31 @@ func NewInfoLogin() *Message { } } +func NewInfoLoginLinkMessage(dupIdentifier, provider, newLoginURL string) *Message { + return &Message{ + ID: InfoSelfServiceLoginLink, + Type: Info, + Text: fmt.Sprintf( + "Signing in will link your account to %q at provider %q. If you do not wish to link that account, please start a new login flow.", + dupIdentifier, + provider, + ), + Context: context(map[string]any{ + "duplicateIdentifier": dupIdentifier, + "provider": provider, + "newLoginUrl": newLoginURL, + }), + } +} + +func NewInfoLoginAndLink() *Message { + return &Message{ + ID: InfoSelfServiceLoginAndLink, + Text: "Sign in and link", + Type: Info, + } +} + func NewInfoLoginTOTP() *Message { return &Message{ ID: InfoLoginTOTP, @@ -91,6 +116,18 @@ func NewInfoLoginWith(provider string) *Message { } } +func NewInfoLoginWithAndLink(provider string) *Message { + + return &Message{ + ID: InfoSelfServiceLoginWithAndLink, + Text: fmt.Sprintf("Sign in with %s and link credential", provider), + Type: Info, + Context: context(map[string]any{ + "provider": provider, + }), + } +} + func NewErrorValidationLoginFlowExpired(expiredAt time.Time) *Message { return &Message{ ID: ErrorValidationLoginFlowExpired, @@ -198,3 +235,11 @@ func NewInfoSelfServiceLoginCode() *Message { Text: "Sign in with code", } } + +func NewErrorValidationLoginLinkedCredentialsDoNotMatch() *Message { + return &Message{ + ID: ErrorValidationLoginLinkedCredentialsDoNotMatch, + Text: "Linked credentials do not match.", + Type: Error, + } +} diff --git a/text/message_node.go b/text/message_node.go index 3af122ae542b..e2dfb7d6dc32 100644 --- a/text/message_node.go +++ b/text/message_node.go @@ -109,3 +109,11 @@ func NewInfoNodeResendOTP() *Message { Type: Info, } } + +func NewInfoNodeLoginAndLinkCredential() *Message { + return &Message{ + ID: InfoNodeLabelLoginAndLinkCredential, + Text: "Login and link credential", + Type: Info, + } +} diff --git a/text/message_validation.go b/text/message_validation.go index 205c27304cdb..28396180c0c5 100644 --- a/text/message_validation.go +++ b/text/message_validation.go @@ -317,8 +317,9 @@ func NewErrorValidationDuplicateCredentialsWithHints(availableCredentialTypes [] func NewErrorValidationDuplicateCredentialsOnOIDCLink() *Message { return &Message{ - ID: ErrorValidationDuplicateCredentialsOnOIDCLink, - Text: "An account with the same identifier (email, phone, username, ...) exists already. Please sign in to your existing account and link your social profile in the settings page.", + ID: ErrorValidationDuplicateCredentialsOnOIDCLink, + Text: "An account with the same identifier (email, phone, username, ...) exists already. " + + "Please sign in to your existing account to link your social profile.", Type: Error, } } From 58bd38fc4bf9736c3bfecc2adb6f55f998870f16 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Wed, 8 Nov 2023 10:11:59 +0000 Subject: [PATCH 172/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61e062d397b4..e773e2ef3475 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-11-06)](#2023-11-06) +- [ (2023-11-08)](#2023-11-08) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -313,7 +313,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-11-06) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-11-08) ## Breaking Changes @@ -807,6 +807,19 @@ https://github.com/ory/kratos/pull/3480 - Improve performance by computing password hashes while validating ([#3508](https://github.com/ory/kratos/issues/3508)) ([a9786c5](https://github.com/ory/kratos/commit/a9786c599d09f61e2e07df5066ce94feb2d99bac)) +- Link oidc credentials when login + ([#3563](https://github.com/ory/kratos/issues/3563)) + ([b784949](https://github.com/ory/kratos/commit/b784949d03b849d9d1d594977f75f5843b7b5da8)), + closes [#2727](https://github.com/ory/kratos/issues/2727) + [#3222](https://github.com/ory/kratos/issues/3222): + + When user tries to login with OIDC for the first time but has already + registered before with email/password a credentials identifier conflict may be + detected by Kratos. In this case user needs to login with email/password first + and then link OIDC credentials on a settings screen. This PR simplifies UX and + allows user to link OIDC credentials to existing account right in the login + flow, without switching to settings flow. + - Login with code on any credential type ([#3549](https://github.com/ory/kratos/issues/3549)) ([ceed7d5](https://github.com/ory/kratos/commit/ceed7d5478c5cca894587698c57f676dda100b27)): From 52639e695e307a7799158b7b79b011af3bfd1ac7 Mon Sep 17 00:00:00 2001 From: Henning Perl Date: Wed, 8 Nov 2023 12:05:29 +0100 Subject: [PATCH 173/282] fix: re-add exported symbols (#3611) --- courier/message.go | 15 ++++++++++----- courier/message_test.go | 7 ++++--- courier/persistence.go | 3 +++ 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/courier/message.go b/courier/message.go index 9cf4399cc8b9..9ba9cf9cdb6c 100644 --- a/courier/message.go +++ b/courier/message.go @@ -24,14 +24,15 @@ type MessageStatus int const ( MessageStatusQueued MessageStatus = iota + 1 MessageStatusSent - _ + MessageStatusProcessing MessageStatusAbandoned ) const ( - messageStatusQueuedText = "queued" - messageStatusSentText = "sent" - messageStatusAbandonedText = "abandoned" + messageStatusQueuedText = "queued" + messageStatusSentText = "sent" + messageStatusProcessingText = "processing" + messageStatusAbandonedText = "abandoned" ) func ToMessageStatus(str string) (MessageStatus, error) { @@ -40,6 +41,8 @@ func ToMessageStatus(str string) (MessageStatus, error) { return MessageStatusQueued, nil case s.AddCase(MessageStatusSent.String()): return MessageStatusSent, nil + case s.AddCase(MessageStatusProcessing.String()): + return MessageStatusProcessing, nil case s.AddCase(MessageStatusAbandoned.String()): return MessageStatusAbandoned, nil default: @@ -53,6 +56,8 @@ func (ms MessageStatus) String() string { return messageStatusQueuedText case MessageStatusSent: return messageStatusSentText + case MessageStatusProcessing: + return messageStatusProcessingText case MessageStatusAbandoned: return messageStatusAbandonedText default: @@ -62,7 +67,7 @@ func (ms MessageStatus) String() string { func (ms MessageStatus) IsValid() error { switch ms { - case MessageStatusQueued, MessageStatusSent, MessageStatusAbandoned: + case MessageStatusQueued, MessageStatusSent, MessageStatusProcessing, MessageStatusAbandoned: return nil default: return errors.WithStack(herodot.ErrBadRequest.WithReason("Message status is not valid")) diff --git a/courier/message_test.go b/courier/message_test.go index bb3af52ab71c..e8db6713bcf5 100644 --- a/courier/message_test.go +++ b/courier/message_test.go @@ -20,9 +20,10 @@ func TestMessageStatusValidity(t *testing.T) { func TestToMessageStatus(t *testing.T) { t.Run("case=should return corresponding MessageStatus for given str", func(t *testing.T) { for str, exp := range map[string]courier.MessageStatus{ - "queued": courier.MessageStatusQueued, - "sent": courier.MessageStatusSent, - "abandoned": courier.MessageStatusAbandoned, + "queued": courier.MessageStatusQueued, + "sent": courier.MessageStatusSent, + "processing": courier.MessageStatusProcessing, + "abandoned": courier.MessageStatusAbandoned, } { result, err := courier.ToMessageStatus(str) require.NoError(t, err) diff --git a/courier/persistence.go b/courier/persistence.go index a8547327250a..6bb2d4fa6230 100644 --- a/courier/persistence.go +++ b/courier/persistence.go @@ -5,12 +5,15 @@ package courier import ( "context" + "errors" "github.com/gofrs/uuid" "github.com/ory/x/pagination/keysetpagination" ) +var ErrQueueEmpty = errors.New("queue is empty") + type ( Persister interface { AddMessage(context.Context, *Message) error From 8150bdb04a1202fdab8db47a98f8803d7480c613 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Wed, 8 Nov 2023 12:02:29 +0000 Subject: [PATCH 174/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e773e2ef3475..e4ffabf6b906 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -504,6 +504,8 @@ https://github.com/ory/kratos/pull/3480 - Properly normalize OIDC verified emails ([#3450](https://github.com/ory/kratos/issues/3450)) ([703b910](https://github.com/ory/kratos/commit/703b910927d879558bfeb0fd2c3339b1d301fac8)) +- Re-add exported symbols ([#3611](https://github.com/ory/kratos/issues/3611)) + ([52639e6](https://github.com/ory/kratos/commit/52639e695e307a7799158b7b79b011af3bfd1ac7)) - Redirect to verification URL even if login_challenge is set ([#3412](https://github.com/ory/kratos/issues/3412)) ([cd9e6a0](https://github.com/ory/kratos/commit/cd9e6a0e1e4cb4957d2a50ae3d288ebb0591e42d)): From 8cc83bc75bf43ce629f6fe15ddf70745fc419058 Mon Sep 17 00:00:00 2001 From: Henning Perl Date: Wed, 8 Nov 2023 14:53:05 +0100 Subject: [PATCH 175/282] Revert "fix: re-add exported symbols (#3611)" This reverts commit 52639e695e307a7799158b7b79b011af3bfd1ac7. --- courier/message.go | 15 +++++---------- courier/message_test.go | 7 +++---- courier/persistence.go | 3 --- 3 files changed, 8 insertions(+), 17 deletions(-) diff --git a/courier/message.go b/courier/message.go index 9ba9cf9cdb6c..9cf4399cc8b9 100644 --- a/courier/message.go +++ b/courier/message.go @@ -24,15 +24,14 @@ type MessageStatus int const ( MessageStatusQueued MessageStatus = iota + 1 MessageStatusSent - MessageStatusProcessing + _ MessageStatusAbandoned ) const ( - messageStatusQueuedText = "queued" - messageStatusSentText = "sent" - messageStatusProcessingText = "processing" - messageStatusAbandonedText = "abandoned" + messageStatusQueuedText = "queued" + messageStatusSentText = "sent" + messageStatusAbandonedText = "abandoned" ) func ToMessageStatus(str string) (MessageStatus, error) { @@ -41,8 +40,6 @@ func ToMessageStatus(str string) (MessageStatus, error) { return MessageStatusQueued, nil case s.AddCase(MessageStatusSent.String()): return MessageStatusSent, nil - case s.AddCase(MessageStatusProcessing.String()): - return MessageStatusProcessing, nil case s.AddCase(MessageStatusAbandoned.String()): return MessageStatusAbandoned, nil default: @@ -56,8 +53,6 @@ func (ms MessageStatus) String() string { return messageStatusQueuedText case MessageStatusSent: return messageStatusSentText - case MessageStatusProcessing: - return messageStatusProcessingText case MessageStatusAbandoned: return messageStatusAbandonedText default: @@ -67,7 +62,7 @@ func (ms MessageStatus) String() string { func (ms MessageStatus) IsValid() error { switch ms { - case MessageStatusQueued, MessageStatusSent, MessageStatusProcessing, MessageStatusAbandoned: + case MessageStatusQueued, MessageStatusSent, MessageStatusAbandoned: return nil default: return errors.WithStack(herodot.ErrBadRequest.WithReason("Message status is not valid")) diff --git a/courier/message_test.go b/courier/message_test.go index e8db6713bcf5..bb3af52ab71c 100644 --- a/courier/message_test.go +++ b/courier/message_test.go @@ -20,10 +20,9 @@ func TestMessageStatusValidity(t *testing.T) { func TestToMessageStatus(t *testing.T) { t.Run("case=should return corresponding MessageStatus for given str", func(t *testing.T) { for str, exp := range map[string]courier.MessageStatus{ - "queued": courier.MessageStatusQueued, - "sent": courier.MessageStatusSent, - "processing": courier.MessageStatusProcessing, - "abandoned": courier.MessageStatusAbandoned, + "queued": courier.MessageStatusQueued, + "sent": courier.MessageStatusSent, + "abandoned": courier.MessageStatusAbandoned, } { result, err := courier.ToMessageStatus(str) require.NoError(t, err) diff --git a/courier/persistence.go b/courier/persistence.go index 6bb2d4fa6230..a8547327250a 100644 --- a/courier/persistence.go +++ b/courier/persistence.go @@ -5,15 +5,12 @@ package courier import ( "context" - "errors" "github.com/gofrs/uuid" "github.com/ory/x/pagination/keysetpagination" ) -var ErrQueueEmpty = errors.New("queue is empty") - type ( Persister interface { AddMessage(context.Context, *Message) error From 7c54c9f36c86142c8e071a5359c71cf6213a1a69 Mon Sep 17 00:00:00 2001 From: Henning Perl Date: Wed, 8 Nov 2023 14:53:24 +0100 Subject: [PATCH 176/282] Revert "chore: simplify courier code (#3603)" This reverts commit 316cd4aacfe31efafa7d737a7c476e2c794e9c9b. --- courier/courier.go | 52 ++++---- courier/courier_dispatcher.go | 35 ++++-- courier/courier_dispatcher_test.go | 9 +- courier/handler_test.go | 16 +-- courier/message.go | 15 ++- courier/message_test.go | 7 +- courier/persistence.go | 5 + courier/test/persistence.go | 117 ++++++++++++------ persistence/sql/persister_courier.go | 61 ++++++++- selfservice/hook/verification_test.go | 6 +- selfservice/strategy/code/code_sender_test.go | 14 +-- selfservice/strategy/link/sender.go | 3 +- selfservice/strategy/link/sender_test.go | 24 ++-- selfservice/strategy/profile/strategy_test.go | 13 +- 14 files changed, 239 insertions(+), 138 deletions(-) diff --git a/courier/courier.go b/courier/courier.go index 1598344c3d2a..b42a580fc061 100644 --- a/courier/courier.go +++ b/courier/courier.go @@ -65,17 +65,12 @@ func NewCourier(ctx context.Context, deps Dependencies) (Courier, error) { if err != nil { return nil, err } - - expBackoff := backoff.NewExponentialBackOff() - // never stop retrying - expBackoff.MaxElapsedTime = 0 - return &courier{ smsClient: newSMS(ctx, deps), smtpClient: smtp, httpClient: newHTTP(ctx, deps), deps: deps, - backoff: expBackoff, + backoff: backoff.NewExponentialBackOff(), }, nil } @@ -84,29 +79,36 @@ func (c *courier) FailOnDispatchError() { } func (c *courier) Work(ctx context.Context) error { - wait := c.deps.CourierConfig().CourierWorkerPullWait(ctx) - for { - select { - case <-ctx.Done(): - if errors.Is(ctx.Err(), context.Canceled) { - return nil - } - return ctx.Err() - case <-time.After(wait): - if err := backoff.Retry(func() error { - if err := c.DispatchQueue(ctx); err != nil { - return err - } - // when we succeed, we want to reset the backoff - c.backoff.Reset() - return nil - }, c.backoff); err != nil { - return err - } + errChan := make(chan error) + defer close(errChan) + + go c.watchMessages(ctx, errChan) + + select { + case <-ctx.Done(): + if errors.Is(ctx.Err(), context.Canceled) { + return nil } + return ctx.Err() + case err := <-errChan: + return err } } func (c *courier) UseBackoff(b backoff.BackOff) { c.backoff = b } + +func (c *courier) watchMessages(ctx context.Context, errChan chan error) { + wait := c.deps.CourierConfig().CourierWorkerPullWait(ctx) + c.backoff.Reset() + for { + if err := backoff.Retry(func() error { + return c.DispatchQueue(ctx) + }, c.backoff); err != nil { + errChan <- err + return + } + time.Sleep(wait) + } +} diff --git a/courier/courier_dispatcher.go b/courier/courier_dispatcher.go index 33d909e59fb2..8470c024fca4 100644 --- a/courier/courier_dispatcher.go +++ b/courier/courier_dispatcher.go @@ -58,10 +58,13 @@ func (c *courier) DispatchQueue(ctx context.Context) error { messages, err := c.deps.CourierPersister().NextMessages(ctx, uint8(pullCount)) if err != nil { + if errors.Is(err, ErrQueueEmpty) { + return nil + } return err } - for _, msg := range messages { + for k, msg := range messages { if msg.SendCount > maxRetries { if err := c.deps.CourierPersister().SetMessageStatus(ctx, msg.ID, MessageStatusAbandoned); err != nil { c.deps.Logger(). @@ -77,33 +80,41 @@ func (c *courier) DispatchQueue(ctx context.Context) error { WithField("message_id", msg.ID). WithField("message_nid", msg.NID). Warnf(`Message was abandoned because it did not deliver after %d attempts`, msg.SendCount) - continue - } - - if err := c.DispatchMessage(ctx, msg); err != nil { + } else if err := c.DispatchMessage(ctx, msg); err != nil { if err := c.deps.CourierPersister().RecordDispatch(ctx, msg.ID, CourierMessageDispatchStatusFailed, err); err != nil { c.deps.Logger(). WithError(err). WithField("message_id", msg.ID). WithField("message_nid", msg.NID). Error(`Unable to record failure log entry.`) - return err + if c.failOnDispatchError { + return err + } + } + + for _, replace := range messages[k:] { + if err := c.deps.CourierPersister().SetMessageStatus(ctx, replace.ID, MessageStatusQueued); err != nil { + c.deps.Logger(). + WithError(err). + WithField("message_id", replace.ID). + WithField("message_nid", replace.NID). + Error(`Unable to reset the failed message's status to "queued".`) + if c.failOnDispatchError { + return err + } + } } if c.failOnDispatchError { return err } - // an error happened, but we want to ignore it - continue - } - - if err := c.deps.CourierPersister().RecordDispatch(ctx, msg.ID, CourierMessageDispatchStatusSuccess, nil); err != nil { + } else if err := c.deps.CourierPersister().RecordDispatch(ctx, msg.ID, CourierMessageDispatchStatusSuccess, nil); err != nil { c.deps.Logger(). WithError(err). WithField("message_id", msg.ID). WithField("message_nid", msg.NID). Error(`Unable to record success log entry.`) - return err + // continue with execution, as the message was successfully dispatched } } diff --git a/courier/courier_dispatcher_test.go b/courier/courier_dispatcher_test.go index b621072c9997..528badf2de02 100644 --- a/courier/courier_dispatcher_test.go +++ b/courier/courier_dispatcher_test.go @@ -44,16 +44,15 @@ func TestDispatchMessageWithInvalidSMTP(t *testing.T) { t.Run("case=failed sending", func(t *testing.T) { id := queueNewMessage(t, ctx, c, reg) - messages, err := reg.CourierPersister().NextMessages(ctx, 10) + message, err := reg.CourierPersister().LatestQueuedMessage(ctx) require.NoError(t, err) - require.Len(t, messages, 1) - require.Equal(t, id, messages[0].ID) + require.Equal(t, id, message.ID) - err = c.DispatchMessage(ctx, messages[0]) + err = c.DispatchMessage(ctx, *message) // sending the email fails, because there is no SMTP server at foo.url require.Error(t, err) - messages, err = reg.CourierPersister().NextMessages(ctx, 10) + messages, err := reg.CourierPersister().NextMessages(ctx, 10) require.NoError(t, err) require.Len(t, messages, 1) }) diff --git a/courier/handler_test.go b/courier/handler_test.go index 74c47bae5c53..b8920a5bc5f9 100644 --- a/courier/handler_test.go +++ b/courier/handler_test.go @@ -96,7 +96,7 @@ func TestHandler(t *testing.T) { t.Run("case=list messages", func(t *testing.T) { // Arrange test data const msgCount = 10 // total message count - const sentCount = 5 // how many messages' status should be equal to `processing` + const procCount = 5 // how many messages' status should be equal to `processing` const rcptOryCount = 2 // how many messages' recipient should be equal to `noreply@ory.sh` messages := make([]courier.Message, msgCount) @@ -109,8 +109,8 @@ func TestHandler(t *testing.T) { } require.NoError(t, reg.CourierPersister().AddMessage(context.Background(), &messages[i])) } - for i := 0; i < sentCount; i++ { - require.NoError(t, reg.CourierPersister().SetMessageStatus(context.Background(), messages[i].ID, courier.MessageStatusSent)) + for i := 0; i < procCount; i++ { + require.NoError(t, reg.CourierPersister().SetMessageStatus(context.Background(), messages[i].ID, courier.MessageStatusProcessing)) } t.Run("paging", func(t *testing.T) { @@ -146,7 +146,7 @@ func TestHandler(t *testing.T) { for _, tc := range tss { t.Run("endpoint="+tc.name, func(t *testing.T) { parsed := getList(t, tc.name, qs) - assert.Len(t, parsed.Array(), msgCount-sentCount) + assert.Len(t, parsed.Array(), msgCount-procCount) for _, item := range parsed.Array() { assert.Equal(t, "queued", item.Get("status").String()) @@ -154,16 +154,16 @@ func TestHandler(t *testing.T) { }) } }) - t.Run("case=should return all sent messages", func(t *testing.T) { - qs := fmt.Sprintf(`?page_token=%s&page_size=250&status=sent`, defaultPageToken) + t.Run("case=should return all processing messages", func(t *testing.T) { + qs := fmt.Sprintf(`?page_token=%s&page_size=250&status=processing`, defaultPageToken) for _, tc := range tss { t.Run("endpoint="+tc.name, func(t *testing.T) { parsed := getList(t, tc.name, qs) - assert.Len(t, parsed.Array(), sentCount) + assert.Len(t, parsed.Array(), procCount) for _, item := range parsed.Array() { - assert.Equal(t, "sent", item.Get("status").String()) + assert.Equal(t, "processing", item.Get("status").String()) } }) } diff --git a/courier/message.go b/courier/message.go index 9cf4399cc8b9..9ba9cf9cdb6c 100644 --- a/courier/message.go +++ b/courier/message.go @@ -24,14 +24,15 @@ type MessageStatus int const ( MessageStatusQueued MessageStatus = iota + 1 MessageStatusSent - _ + MessageStatusProcessing MessageStatusAbandoned ) const ( - messageStatusQueuedText = "queued" - messageStatusSentText = "sent" - messageStatusAbandonedText = "abandoned" + messageStatusQueuedText = "queued" + messageStatusSentText = "sent" + messageStatusProcessingText = "processing" + messageStatusAbandonedText = "abandoned" ) func ToMessageStatus(str string) (MessageStatus, error) { @@ -40,6 +41,8 @@ func ToMessageStatus(str string) (MessageStatus, error) { return MessageStatusQueued, nil case s.AddCase(MessageStatusSent.String()): return MessageStatusSent, nil + case s.AddCase(MessageStatusProcessing.String()): + return MessageStatusProcessing, nil case s.AddCase(MessageStatusAbandoned.String()): return MessageStatusAbandoned, nil default: @@ -53,6 +56,8 @@ func (ms MessageStatus) String() string { return messageStatusQueuedText case MessageStatusSent: return messageStatusSentText + case MessageStatusProcessing: + return messageStatusProcessingText case MessageStatusAbandoned: return messageStatusAbandonedText default: @@ -62,7 +67,7 @@ func (ms MessageStatus) String() string { func (ms MessageStatus) IsValid() error { switch ms { - case MessageStatusQueued, MessageStatusSent, MessageStatusAbandoned: + case MessageStatusQueued, MessageStatusSent, MessageStatusProcessing, MessageStatusAbandoned: return nil default: return errors.WithStack(herodot.ErrBadRequest.WithReason("Message status is not valid")) diff --git a/courier/message_test.go b/courier/message_test.go index bb3af52ab71c..e8db6713bcf5 100644 --- a/courier/message_test.go +++ b/courier/message_test.go @@ -20,9 +20,10 @@ func TestMessageStatusValidity(t *testing.T) { func TestToMessageStatus(t *testing.T) { t.Run("case=should return corresponding MessageStatus for given str", func(t *testing.T) { for str, exp := range map[string]courier.MessageStatus{ - "queued": courier.MessageStatusQueued, - "sent": courier.MessageStatusSent, - "abandoned": courier.MessageStatusAbandoned, + "queued": courier.MessageStatusQueued, + "sent": courier.MessageStatusSent, + "processing": courier.MessageStatusProcessing, + "abandoned": courier.MessageStatusAbandoned, } { result, err := courier.ToMessageStatus(str) require.NoError(t, err) diff --git a/courier/persistence.go b/courier/persistence.go index a8547327250a..4e5834f7faca 100644 --- a/courier/persistence.go +++ b/courier/persistence.go @@ -7,10 +7,13 @@ import ( "context" "github.com/gofrs/uuid" + "github.com/pkg/errors" "github.com/ory/x/pagination/keysetpagination" ) +var ErrQueueEmpty = errors.New("queue is empty") + type ( Persister interface { AddMessage(context.Context, *Message) error @@ -19,6 +22,8 @@ type ( SetMessageStatus(context.Context, uuid.UUID, MessageStatus) error + LatestQueuedMessage(ctx context.Context) (*Message, error) + IncrementMessageSendCount(context.Context, uuid.UUID) error // ListMessages lists all messages in the store given the page, itemsPerPage, status and recipient. diff --git a/courier/test/persistence.go b/courier/test/persistence.go index 2a6e33650c84..fad80efe1742 100644 --- a/courier/test/persistence.go +++ b/courier/test/persistence.go @@ -6,11 +6,10 @@ package test import ( "context" "errors" + "fmt" "testing" "time" - "github.com/ory/x/pointerx" - "github.com/gobuffalo/pop/v6" "github.com/gofrs/uuid" "github.com/tidwall/gjson" @@ -39,54 +38,85 @@ func TestPersister(ctx context.Context, newNetworkUnlessExisting NetworkWrapper, t.Run("case=no messages in queue", func(t *testing.T) { m, err := p.NextMessages(ctx, 10) - require.NoError(t, err) + require.ErrorIs(t, err, courier.ErrQueueEmpty) assert.Len(t, m, 0) + + _, err = p.LatestQueuedMessage(ctx) + require.ErrorIs(t, err, courier.ErrQueueEmpty) }) messages := make([]courier.Message, 5) t.Run("case=add messages to the queue", func(t *testing.T) { - start := time.Now().UTC() for k := range messages { - pop.SetNowFunc(func() time.Time { - return start.Add(time.Duration(k) * time.Second) - }) require.NoError(t, faker.FakeData(&messages[k])) require.NoError(t, p.AddMessage(ctx, &messages[k])) + time.Sleep(time.Second) // wait a bit so that the timestamp ordering works in MySQL. } - pop.SetNowFunc(time.Now) }) - t.Run("case=get queued messages", func(t *testing.T) { - actual, err := p.NextMessages(ctx, 10) + t.Run("case=latest message in queue", func(t *testing.T) { + expected, err := p.LatestQueuedMessage(ctx) require.NoError(t, err) - assert.ElementsMatch(t, messages, actual) + + actual := messages[len(messages)-1] + assert.Equal(t, expected.ID, actual.ID) + assert.Equal(t, expected.Subject, actual.Subject) }) - t.Run("case=setting message status", func(t *testing.T) { - require.NoError(t, p.SetMessageStatus(ctx, messages[0].ID, courier.MessageStatusSent)) - require.NoError(t, p.SetMessageStatus(ctx, messages[1].ID, courier.MessageStatusAbandoned)) - require.NoError(t, p.SetMessageStatus(ctx, messages[2].ID, courier.MessageStatusQueued)) + t.Run("case=pull messages from the queue", func(t *testing.T) { + for k, expected := range messages { + expected.Status = courier.MessageStatusProcessing + t.Run(fmt.Sprintf("message=%d", k), func(t *testing.T) { + messages, err := p.NextMessages(ctx, 1) + require.NoError(t, err) + require.Len(t, messages, 1) + + actual := messages[0] + assert.Equal(t, expected.ID, actual.ID) + assert.Equal(t, expected.Subject, actual.Subject) + assert.Equal(t, expected.Body, actual.Body) + assert.Equal(t, expected.Status, actual.Status) + assert.Equal(t, expected.Type, actual.Type) + assert.Equal(t, expected.Recipient, actual.Recipient) + }) + } - ms, err := p.NextMessages(ctx, 10) - require.NoError(t, err) - assert.ElementsMatch(t, messages[2:], ms) + _, err := p.NextMessages(ctx, 10) + require.ErrorIs(t, err, courier.ErrQueueEmpty) + }) + t.Run("case=setting message status", func(t *testing.T) { require.NoError(t, p.SetMessageStatus(ctx, messages[0].ID, courier.MessageStatusQueued)) - require.NoError(t, p.SetMessageStatus(ctx, messages[1].ID, courier.MessageStatusQueued)) + ms, err := p.NextMessages(ctx, 1) + require.NoError(t, err) + require.Len(t, ms, 1) + assert.Equal(t, messages[0].ID, ms[0].ID) + + require.NoError(t, p.SetMessageStatus(ctx, messages[0].ID, courier.MessageStatusSent)) + _, err = p.NextMessages(ctx, 1) + require.ErrorIs(t, err, courier.ErrQueueEmpty) + + require.NoError(t, p.SetMessageStatus(ctx, messages[0].ID, courier.MessageStatusAbandoned)) + _, err = p.NextMessages(ctx, 1) + require.ErrorIs(t, err, courier.ErrQueueEmpty) }) t.Run("case=incrementing send count", func(t *testing.T) { originalSendCount := messages[0].SendCount + require.NoError(t, p.SetMessageStatus(ctx, messages[0].ID, courier.MessageStatusQueued)) require.NoError(t, p.IncrementMessageSendCount(ctx, messages[0].ID)) - message, err := p.FetchMessage(ctx, messages[0].ID) + ms, err := p.NextMessages(ctx, 1) require.NoError(t, err) - assert.Equal(t, originalSendCount+1, message.SendCount) + require.Len(t, ms, 1) + assert.Equal(t, messages[0].ID, ms[0].ID) + assert.Equal(t, originalSendCount+1, ms[0].SendCount) }) t.Run("case=list messages", func(t *testing.T) { + status := courier.MessageStatusProcessing filter := courier.ListCourierMessagesParameters{ - Status: pointerx.Ptr(courier.MessageStatusQueued), + Status: &status, } ms, total, _, err := p.ListMessages(ctx, filter, []keysetpagination.Option{}) @@ -111,24 +141,24 @@ func TestPersister(ctx context.Context, newNetworkUnlessExisting NetworkWrapper, nid2, p2 := newNetwork(t, ctx) const timeFormat = "2006-01-02 15:04:05.99999" msg1 := courier.Message{ - ID: uuid.Must(uuid.FromString("10000000-0000-0000-0000-000000000000")), + ID: uuid.FromStringOrNil("10000000-0000-0000-0000-000000000000"), NID: nid1, - Status: courier.MessageStatusQueued, + Status: courier.MessageStatusProcessing, } err = p1.GetConnection(ctx).Create(&msg1) require.NoError(t, err) msg2 := courier.Message{ - ID: uuid.Must(uuid.FromString("20000000-0000-0000-0000-000000000000")), + ID: uuid.FromStringOrNil("20000000-0000-0000-0000-000000000000"), NID: nid1, - Status: courier.MessageStatusQueued, + Status: courier.MessageStatusProcessing, } err = p1.GetConnection(ctx).Create(&msg2) require.NoError(t, err) msg3 := courier.Message{ - ID: uuid.Must(uuid.FromString("30000000-0000-0000-0000-000000000000")), + ID: uuid.FromStringOrNil("30000000-0000-0000-0000-000000000000"), NID: nid2, - Status: courier.MessageStatusQueued, + Status: courier.MessageStatusProcessing, } err = p2.GetConnection(ctx).Create(&msg3) require.NoError(t, err) @@ -163,8 +193,16 @@ func TestPersister(ctx context.Context, newNetworkUnlessExisting NetworkWrapper, assert.EqualValues(t, nid, expected.NID) assert.EqualValues(t, nid, p.NetworkID(ctx)) - actual, err := p.FetchMessage(ctx, expected.ID) + actual, err := p.LatestQueuedMessage(ctx) require.NoError(t, err) + assert.EqualValues(t, expected.ID, actual.ID) + assert.EqualValues(t, nid, actual.NID) + + actuals, err := p.NextMessages(ctx, 255) + require.NoError(t, err) + + actual = &actuals[0] + assert.EqualValues(t, expected.ID, actual.ID) assert.EqualValues(t, nid, actual.NID) }) @@ -178,25 +216,32 @@ func TestPersister(ctx context.Context, newNetworkUnlessExisting NetworkWrapper, assert.EqualValues(t, nid, expected.NID) assert.EqualValues(t, nid, p.NetworkID(ctx)) - actual, err := p.FetchMessage(ctx, id) + actual, err := p.LatestQueuedMessage(ctx) + require.NoError(t, err) + assert.EqualValues(t, id, actual.ID) + assert.EqualValues(t, nid, actual.NID) + + actuals, err := p.NextMessages(ctx, 255) require.NoError(t, err) + + actual = &actuals[0] + assert.EqualValues(t, id, actual.ID) assert.EqualValues(t, nid, actual.NID) }) t.Run("can not get on another network", func(t *testing.T) { _, p := newNetwork(t, ctx) - actual, err := p.NextMessages(ctx, 255) - require.NoError(t, err) - assert.Len(t, actual, 0) + _, err := p.LatestQueuedMessage(ctx) + require.ErrorIs(t, err, courier.ErrQueueEmpty) - _, err = p.FetchMessage(ctx, id) - assert.ErrorIs(t, err, sqlcon.ErrNoRows) + _, err = p.NextMessages(ctx, 255) + require.ErrorIs(t, err, courier.ErrQueueEmpty) }) t.Run("can not update on another network", func(t *testing.T) { _, p := newNetwork(t, ctx) - err := p.SetMessageStatus(ctx, id, courier.MessageStatusAbandoned) + err := p.SetMessageStatus(ctx, id, courier.MessageStatusProcessing) require.ErrorIs(t, err, sqlcon.ErrNoRows) }) diff --git a/persistence/sql/persister_courier.go b/persistence/sql/persister_courier.go index c706f8d547b1..437d9132e1d0 100644 --- a/persistence/sql/persister_courier.go +++ b/persistence/sql/persister_courier.go @@ -5,8 +5,10 @@ package sql import ( "context" + "database/sql" "encoding/json" + "github.com/gobuffalo/pop/v6" "github.com/gofrs/uuid" "github.com/pkg/errors" @@ -16,6 +18,7 @@ import ( "github.com/ory/x/uuidx" "github.com/ory/kratos/courier" + "github.com/ory/kratos/persistence/sql/update" ) var _ courier.Persister = new(Persister) @@ -67,18 +70,66 @@ func (p *Persister) NextMessages(ctx context.Context, limit uint8) (messages []c ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.NextMessages") defer span.End() - if err := p.Connection(ctx). + if err := p.Transaction(ctx, func(ctx context.Context, tx *pop.Connection) error { + var m []courier.Message + if err := tx. + Where("nid = ? AND status = ?", + p.NetworkID(ctx), + courier.MessageStatusQueued, + ). + Order("created_at ASC"). + Limit(int(limit)). + All(&m); err != nil { + return err + } + + if len(m) == 0 { + return sql.ErrNoRows + } + + for i := range m { + message := &m[i] + message.Status = courier.MessageStatusProcessing + if err := update.Generic(ctx, p.GetConnection(ctx), p.r.Tracer(ctx).Tracer(), message, "status"); err != nil { + return err + } + } + + messages = m + return nil + }); err != nil { + if errors.Cause(err) == sql.ErrNoRows { + return nil, errors.WithStack(courier.ErrQueueEmpty) + } + return nil, sqlcon.HandleError(err) + } + + if len(messages) == 0 { + return nil, errors.WithStack(courier.ErrQueueEmpty) + } + + return messages, nil +} + +func (p *Persister) LatestQueuedMessage(ctx context.Context) (*courier.Message, error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.LatestQueuedMessage") + defer span.End() + + var m courier.Message + if err := p.GetConnection(ctx). Where("nid = ? AND status = ?", p.NetworkID(ctx), courier.MessageStatusQueued, ). - Order("created_at ASC"). - Limit(int(limit)). - All(&messages); err != nil { + Order("created_at DESC"). + First(&m); err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, errors.WithStack(courier.ErrQueueEmpty) + } return nil, sqlcon.HandleError(err) } - return messages, nil + return &m, nil } func (p *Persister) SetMessageStatus(ctx context.Context, id uuid.UUID, ms courier.MessageStatus) error { diff --git a/selfservice/hook/verification_test.go b/selfservice/hook/verification_test.go index 8a60a2dfeb9d..652df7bec61c 100644 --- a/selfservice/hook/verification_test.go +++ b/selfservice/hook/verification_test.go @@ -11,7 +11,6 @@ import ( "time" "github.com/ory/kratos/courier" - "github.com/ory/kratos/internal/testhelpers" "github.com/stretchr/testify/assert" @@ -100,9 +99,6 @@ func TestVerifier(t *testing.T) { require.NoError(t, err) require.Len(t, messages, 2) - require.NoError(t, reg.CourierPersister().SetMessageStatus(context.Background(), messages[0].ID, courier.MessageStatusSent)) - require.NoError(t, reg.CourierPersister().SetMessageStatus(context.Background(), messages[1].ID, courier.MessageStatusSent)) - recipients := make([]string, len(messages)) for k, m := range messages { recipients[k] = m.Recipient @@ -135,7 +131,7 @@ func TestVerifier(t *testing.T) { require.NoError(t, err) messages, err = reg.CourierPersister().NextMessages(context.Background(), 12) - require.NoError(t, err) + require.EqualError(t, err, courier.ErrQueueEmpty.Error()) assert.Len(t, messages, 0) }) } diff --git a/selfservice/strategy/code/code_sender_test.go b/selfservice/strategy/code/code_sender_test.go index 40ad1e03967e..e5ba75826eb5 100644 --- a/selfservice/strategy/code/code_sender_test.go +++ b/selfservice/strategy/code/code_sender_test.go @@ -65,9 +65,6 @@ func TestSender(t *testing.T) { require.NoError(t, err) require.Len(t, messages, 2) - require.NoError(t, reg.CourierPersister().SetMessageStatus(ctx, messages[0].ID, courier.MessageStatusSent)) - require.NoError(t, reg.CourierPersister().SetMessageStatus(ctx, messages[1].ID, courier.MessageStatusSent)) - assert.EqualValues(t, "tracked@ory.sh", messages[0].Recipient) assert.Contains(t, messages[0].Subject, "Recover access to your account") @@ -93,9 +90,6 @@ func TestSender(t *testing.T) { require.NoError(t, err) require.Len(t, messages, 2) - require.NoError(t, reg.CourierPersister().SetMessageStatus(ctx, messages[0].ID, courier.MessageStatusSent)) - require.NoError(t, reg.CourierPersister().SetMessageStatus(ctx, messages[1].ID, courier.MessageStatusSent)) - assert.EqualValues(t, "tracked@ory.sh", messages[0].Recipient) assert.Equal(t, messages[0].Subject, subject+" valid") assert.Contains(t, messages[0].Body, body) @@ -127,9 +121,6 @@ func TestSender(t *testing.T) { require.NoError(t, err) require.Len(t, messages, 2) - require.NoError(t, reg.CourierPersister().SetMessageStatus(ctx, messages[0].ID, courier.MessageStatusSent)) - require.NoError(t, reg.CourierPersister().SetMessageStatus(ctx, messages[1].ID, courier.MessageStatusSent)) - assert.EqualValues(t, "tracked@ory.sh", messages[0].Recipient) assert.Contains(t, messages[0].Subject, "Please verify your email address") @@ -155,9 +146,6 @@ func TestSender(t *testing.T) { require.NoError(t, err) require.Len(t, messages, 2) - require.NoError(t, reg.CourierPersister().SetMessageStatus(ctx, messages[0].ID, courier.MessageStatusSent)) - require.NoError(t, reg.CourierPersister().SetMessageStatus(ctx, messages[1].ID, courier.MessageStatusSent)) - assert.EqualValues(t, "tracked@ory.sh", messages[0].Recipient) assert.Equal(t, messages[0].Subject, subject+" valid") assert.Contains(t, messages[0].Body, body) @@ -218,7 +206,7 @@ func TestSender(t *testing.T) { messages, err := reg.CourierPersister().NextMessages(ctx, 0) - require.NoError(t, err) + require.ErrorIs(t, err, courier.ErrQueueEmpty) require.Len(t, messages, 0) }) } diff --git a/selfservice/strategy/link/sender.go b/selfservice/strategy/link/sender.go index 4190cf7988a6..d58f167335d7 100644 --- a/selfservice/strategy/link/sender.go +++ b/selfservice/strategy/link/sender.go @@ -5,7 +5,6 @@ package link import ( "context" - stderrors "errors" "net/url" "github.com/hashicorp/go-retryablehttp" @@ -52,7 +51,7 @@ type ( } ) -var ErrUnknownAddress = stderrors.New("verification requested for unknown address") +var ErrUnknownAddress = errors.New("verification requested for unknown address") func NewSender(r senderDependencies) *Sender { return &Sender{r: r} diff --git a/selfservice/strategy/link/sender_test.go b/selfservice/strategy/link/sender_test.go index de0dc767d6da..8fd62e038f3e 100644 --- a/selfservice/strategy/link/sender_test.go +++ b/selfservice/strategy/link/sender_test.go @@ -10,6 +10,7 @@ import ( "io" "net/http" "net/http/httptest" + "sync" "testing" "time" @@ -61,9 +62,6 @@ func TestManager(t *testing.T) { require.NoError(t, err) require.Len(t, messages, 2) - require.NoError(t, reg.CourierPersister().SetMessageStatus(context.Background(), messages[0].ID, courier.MessageStatusSent)) - require.NoError(t, reg.CourierPersister().SetMessageStatus(context.Background(), messages[1].ID, courier.MessageStatusSent)) - assert.EqualValues(t, "tracked@ory.sh", messages[0].Recipient) assert.Contains(t, messages[0].Subject, "Recover access to your account") assert.Contains(t, messages[0].Body, urlx.AppendPaths(conf.SelfServiceLinkMethodBaseURL(ctx), recovery.RouteSubmitFlow).String()+"?") @@ -78,6 +76,8 @@ func TestManager(t *testing.T) { }) t.Run("method=SendRecoveryLink via HTTP", func(t *testing.T) { + var wg sync.WaitGroup + wg.Add(2) type requestBody struct { Recipient string RecoveryURL string `json:"recovery_url"` @@ -92,6 +92,7 @@ func TestManager(t *testing.T) { var message requestBody require.NoError(t, json.Unmarshal(b, &message)) messages = append(messages, &message) + wg.Done() })) t.Cleanup(srv.Close) requestConfig := fmt.Sprintf(`{"url": "%s"}`, srv.URL) @@ -101,6 +102,12 @@ func TestManager(t *testing.T) { cour, err := reg.Courier(ctx) require.NoError(t, err) + ctx, cancel := context.WithCancel(ctx) + defer t.Cleanup(cancel) + go func() { + require.NoError(t, cour.Work(ctx)) + }() + s, err := reg.RecoveryStrategies(ctx).Strategy("link") require.NoError(t, err) f, err := recovery.NewFlow(conf, time.Hour, "", u, s, flow.TypeBrowser) @@ -109,9 +116,9 @@ func TestManager(t *testing.T) { require.NoError(t, reg.RecoveryFlowPersister().CreateRecoveryFlow(context.Background(), f)) require.NoError(t, reg.LinkSender().SendRecoveryLink(context.Background(), f, "email", "tracked@ory.sh")) - require.ErrorIs(t, reg.LinkSender().SendRecoveryLink(context.Background(), f, "email", "not-tracked@ory.sh"), link.ErrUnknownAddress) + require.EqualError(t, reg.LinkSender().SendRecoveryLink(context.Background(), f, "email", "not-tracked@ory.sh"), link.ErrUnknownAddress.Error()) - require.NoError(t, cour.DispatchQueue(ctx)) + wg.Wait() assert.EqualValues(t, "tracked@ory.sh", messages[0].To) assert.Contains(t, messages[0].Subject, "Recover access to your account") @@ -132,14 +139,11 @@ func TestManager(t *testing.T) { require.NoError(t, reg.VerificationFlowPersister().CreateVerificationFlow(context.Background(), f)) require.NoError(t, reg.LinkSender().SendVerificationLink(context.Background(), f, "email", "tracked@ory.sh")) - require.ErrorIs(t, reg.LinkSender().SendVerificationLink(context.Background(), f, "email", "not-tracked@ory.sh"), link.ErrUnknownAddress) + require.EqualError(t, reg.LinkSender().SendVerificationLink(context.Background(), f, "email", "not-tracked@ory.sh"), link.ErrUnknownAddress.Error()) messages, err := reg.CourierPersister().NextMessages(context.Background(), 12) require.NoError(t, err) require.Len(t, messages, 2) - require.NoError(t, reg.CourierPersister().SetMessageStatus(context.Background(), messages[0].ID, courier.MessageStatusSent)) - require.NoError(t, reg.CourierPersister().SetMessageStatus(context.Background(), messages[1].ID, courier.MessageStatusSent)) - assert.EqualValues(t, "tracked@ory.sh", messages[0].Recipient) assert.Contains(t, messages[0].Subject, "Please verify") assert.Contains(t, messages[0].Body, urlx.AppendPaths(conf.SelfServiceLinkMethodBaseURL(ctx), verification.RouteSubmitFlow).String()+"?") @@ -203,7 +207,7 @@ func TestManager(t *testing.T) { messages, err := reg.CourierPersister().NextMessages(context.Background(), 0) - require.NoError(t, err) + require.ErrorIs(t, err, courier.ErrQueueEmpty) require.Len(t, messages, 0) }) } diff --git a/selfservice/strategy/profile/strategy_test.go b/selfservice/strategy/profile/strategy_test.go index d489e344a6ce..f67407fe799f 100644 --- a/selfservice/strategy/profile/strategy_test.go +++ b/selfservice/strategy/profile/strategy_test.go @@ -17,8 +17,6 @@ import ( "testing" "time" - "github.com/ory/kratos/courier" - "github.com/ory/x/jsonx" kratos "github.com/ory/kratos/internal/httpclient" @@ -533,12 +531,9 @@ func TestStrategyTraits(t *testing.T) { assert.EqualValues(t, flow.StateSuccess, gjson.Get(actual, "state").String(), "%s", actual) assert.Equal(t, newEmail, gjson.Get(actual, "ui.nodes.#(attributes.name==traits.email).attributes.value").Value(), "%s", actual) - ms, err := reg.CourierPersister().NextMessages(ctx, 10) + m, err := reg.CourierPersister().LatestQueuedMessage(context.Background()) require.NoError(t, err) - require.Len(t, ms, 1) - assert.Contains(t, ms[0].Subject, "verify your email address") - - require.NoError(t, reg.CourierPersister().SetMessageStatus(ctx, ms[0].ID, courier.MessageStatusSent)) + assert.Contains(t, m.Subject, "verify your email address") } payload := func(newEmail string) func(v url.Values) { @@ -555,13 +550,13 @@ func TestStrategyTraits(t *testing.T) { }) t.Run("type=spa", func(t *testing.T) { - newEmail := "update-verify-browser-1@mail.com" + newEmail := "update-verify-browser@mail.com" actual := expectSuccess(t, false, true, browserUser1, payload(newEmail)) check(t, actual, newEmail) }) t.Run("type=browser", func(t *testing.T) { - newEmail := "update-verify-browser-2@mail.com" + newEmail := "update-verify-browser@mail.com" actual := expectSuccess(t, false, false, browserUser1, payload(newEmail)) check(t, actual, newEmail) }) From 139a11c99e3a78b6e01f7cf4fdaf560554356656 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Wed, 8 Nov 2023 17:25:06 +0000 Subject: [PATCH 177/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4ffabf6b906..6d63a3555b11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) - [Features](#features) + - [Reverts](#reverts) - [Tests](#tests) - [1.0.0 (2023-07-12)](#100-2023-07-12) - [Bug Fixes](#bug-fixes-1) @@ -44,7 +45,7 @@ - [Code Refactoring](#code-refactoring-1) - [Documentation](#documentation-4) - [Features](#features-5) - - [Reverts](#reverts) + - [Reverts](#reverts-1) - [Tests](#tests-4) - [Unclassified](#unclassified-2) - [0.10.1 (2022-06-01)](#0101-2022-06-01) @@ -113,7 +114,7 @@ - [Code Refactoring](#code-refactoring-5) - [Documentation](#documentation-12) - [Features](#features-11) - - [Reverts](#reverts-1) + - [Reverts](#reverts-2) - [Tests](#tests-10) - [Unclassified](#unclassified-5) - [0.7.6-alpha.1 (2021-09-12)](#076-alpha1-2021-09-12) @@ -504,8 +505,6 @@ https://github.com/ory/kratos/pull/3480 - Properly normalize OIDC verified emails ([#3450](https://github.com/ory/kratos/issues/3450)) ([703b910](https://github.com/ory/kratos/commit/703b910927d879558bfeb0fd2c3339b1d301fac8)) -- Re-add exported symbols ([#3611](https://github.com/ory/kratos/issues/3611)) - ([52639e6](https://github.com/ory/kratos/commit/52639e695e307a7799158b7b79b011af3bfd1ac7)) - Redirect to verification URL even if login_challenge is set ([#3412](https://github.com/ory/kratos/issues/3412)) ([cd9e6a0](https://github.com/ory/kratos/commit/cd9e6a0e1e4cb4957d2a50ae3d288ebb0591e42d)): @@ -905,6 +904,14 @@ https://github.com/ory/kratos/pull/3480 - Webhook analytic events ([9c8a25e](https://github.com/ory/kratos/commit/9c8a25eb0d3e06df182565d3d959d57e5dccfed8)) +### Reverts + +- Revert "chore: simplify courier code (#3603)" + ([7c54c9f](https://github.com/ory/kratos/commit/7c54c9f36c86142c8e071a5359c71cf6213a1a69)), + closes [#3603](https://github.com/ory/kratos/issues/3603): + + This reverts commit 316cd4aacfe31efafa7d737a7c476e2c794e9c9b. + ### Tests - **e2e:** Logout return_to ([#3418](https://github.com/ory/kratos/issues/3418)) From 843a2150c5ae422d687290284f8767bb9824f1d5 Mon Sep 17 00:00:00 2001 From: Anh Nguyen <42261776+anhnmt@users.noreply.github.com> Date: Fri, 10 Nov 2023 16:14:35 +0700 Subject: [PATCH 178/282] chore: fix github.com/bxcodec/faker/v3 is deprecated (#3607) --- corpx/faker.go | 2 +- courier/handler_test.go | 2 +- courier/test/persistence.go | 2 +- go.mod | 2 +- go.sum | 4 ++-- identity/handler_test.go | 2 +- identity/test/pool.go | 2 +- internal/testhelpers/handler_mock.go | 2 +- internal/testhelpers/selfservice.go | 2 +- persistence/sql/persister_registration_code.go | 2 +- selfservice/flow/login/flow_test.go | 2 +- selfservice/flow/login/test/persistence.go | 2 +- selfservice/flow/recovery/test/persistence.go | 2 +- selfservice/flow/registration/flow_test.go | 2 +- selfservice/flow/registration/handler_test.go | 2 +- selfservice/flow/registration/test/persistence.go | 2 +- selfservice/flow/settings/error_test.go | 2 +- selfservice/flow/settings/flow_test.go | 2 +- selfservice/flow/settings/test/persistence.go | 2 +- selfservice/flow/verification/test/persistence.go | 2 +- selfservice/hook/session_destroyer_test.go | 2 +- selfservice/strategy/code/test/persistence.go | 2 +- selfservice/strategy/link/test/persistence.go | 2 +- session/handler_test.go | 2 +- session/test/persistence.go | 2 +- ui/node/node_test.go | 2 +- 26 files changed, 27 insertions(+), 27 deletions(-) diff --git a/corpx/faker.go b/corpx/faker.go index a633f956dd8f..e8fc4b0e388f 100644 --- a/corpx/faker.go +++ b/corpx/faker.go @@ -10,7 +10,7 @@ import ( "sync" "time" - "github.com/bxcodec/faker/v3" + "github.com/go-faker/faker/v4" "github.com/ory/kratos/identity" "github.com/ory/kratos/selfservice/flow" diff --git a/courier/handler_test.go b/courier/handler_test.go index b8920a5bc5f9..28a7ec55d8b2 100644 --- a/courier/handler_test.go +++ b/courier/handler_test.go @@ -13,7 +13,7 @@ import ( "testing" "time" - "github.com/bxcodec/faker/v3" + "github.com/go-faker/faker/v4" "github.com/gofrs/uuid" "github.com/tidwall/gjson" diff --git a/courier/test/persistence.go b/courier/test/persistence.go index fad80efe1742..dddd8adb2cbf 100644 --- a/courier/test/persistence.go +++ b/courier/test/persistence.go @@ -14,7 +14,7 @@ import ( "github.com/gofrs/uuid" "github.com/tidwall/gjson" - "github.com/bxcodec/faker/v3" + "github.com/go-faker/faker/v4" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/go.mod b/go.mod index 1c3c89f958f1..262ebd0103e5 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/avast/retry-go/v3 v3.1.1 github.com/bradleyjkemp/cupaloy/v2 v2.8.0 github.com/bwmarrin/discordgo v0.23.0 - github.com/bxcodec/faker/v3 v3.3.1 + github.com/go-faker/faker/v4 v4.2.0 github.com/cenkalti/backoff v2.2.1+incompatible github.com/coreos/go-oidc v2.2.1+incompatible github.com/cortesi/modd v0.0.0-20210323234521-b35eddab86cc diff --git a/go.sum b/go.sum index d1c3f65c3160..c5d1fc506475 100644 --- a/go.sum +++ b/go.sum @@ -99,8 +99,6 @@ github.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oM github.com/bradleyjkemp/cupaloy/v2 v2.8.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0= github.com/bwmarrin/discordgo v0.23.0 h1://ARp8qUrRZvDGMkfAjtcC20WOvsMtTgi+KrdKnl6eY= github.com/bwmarrin/discordgo v0.23.0/go.mod h1:c1WtWUGN6nREDmzIpyTp/iD3VYt4Fpx+bVyfBG7JE+M= -github.com/bxcodec/faker/v3 v3.3.1 h1:G7uldFk+iO/ES7W4v7JlI/WU9FQ6op9VJ15YZlDEhGQ= -github.com/bxcodec/faker/v3 v3.3.1/go.mod h1:gF31YgnMSMKgkvl+fyEo1xuSMbEuieyqfeslGYFjneM= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= @@ -210,6 +208,8 @@ github.com/go-crypt/x v0.2.1 h1:OGw78Bswme9lffCOX6tyuC280ouU5391glsvThMtM5U= github.com/go-crypt/x v0.2.1/go.mod h1:Q/y9rms7yw4/1CavBlNGn0Itg4HqwNpe1N9FX0TxXrc= github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-faker/faker/v4 v4.2.0 h1:dGebOupKwssrODV51E0zbMrv5e2gO9VWSLNC1WDCpWg= +github.com/go-faker/faker/v4 v4.2.0/go.mod h1:F/bBy8GH9NxOxMInug5Gx4WYeG6fHJZ8Ol/dhcpRub4= 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= diff --git a/identity/handler_test.go b/identity/handler_test.go index 43d432b55eb4..2e38de8db126 100644 --- a/identity/handler_test.go +++ b/identity/handler_test.go @@ -18,7 +18,7 @@ import ( "testing" "time" - "github.com/bxcodec/faker/v3" + "github.com/go-faker/faker/v4" "github.com/gofrs/uuid" "github.com/peterhellberg/link" "github.com/stretchr/testify/assert" diff --git a/identity/test/pool.go b/identity/test/pool.go index f5e96960ac00..371d4a2cf6b1 100644 --- a/identity/test/pool.go +++ b/identity/test/pool.go @@ -15,7 +15,7 @@ import ( "github.com/ory/x/crdbx" - "github.com/bxcodec/faker/v3" + "github.com/go-faker/faker/v4" "github.com/gofrs/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/internal/testhelpers/handler_mock.go b/internal/testhelpers/handler_mock.go index 11031abbcca3..bcc68a1e61c1 100644 --- a/internal/testhelpers/handler_mock.go +++ b/internal/testhelpers/handler_mock.go @@ -11,7 +11,7 @@ import ( "testing" "time" - "github.com/bxcodec/faker/v3" + "github.com/go-faker/faker/v4" "github.com/gofrs/uuid" "github.com/julienschmidt/httprouter" "github.com/pkg/errors" diff --git a/internal/testhelpers/selfservice.go b/internal/testhelpers/selfservice.go index a827aad0a6de..8c7b4c588d78 100644 --- a/internal/testhelpers/selfservice.go +++ b/internal/testhelpers/selfservice.go @@ -11,7 +11,7 @@ import ( "net/url" "testing" - "github.com/bxcodec/faker/v3" + "github.com/go-faker/faker/v4" "github.com/gobuffalo/httptest" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/persistence/sql/persister_registration_code.go b/persistence/sql/persister_registration_code.go index 5c9ac909838c..29d1af549467 100644 --- a/persistence/sql/persister_registration_code.go +++ b/persistence/sql/persister_registration_code.go @@ -7,7 +7,7 @@ import ( "context" "time" - "github.com/bxcodec/faker/v3/support/slice" + "github.com/go-faker/faker/v4/pkg/slice" "github.com/gofrs/uuid" "github.com/pkg/errors" diff --git a/selfservice/flow/login/flow_test.go b/selfservice/flow/login/flow_test.go index c33ac1dc99e3..685d2604c43d 100644 --- a/selfservice/flow/login/flow_test.go +++ b/selfservice/flow/login/flow_test.go @@ -24,7 +24,7 @@ import ( "github.com/ory/kratos/internal" - "github.com/bxcodec/faker/v3" + "github.com/go-faker/faker/v4" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/selfservice/flow/login/test/persistence.go b/selfservice/flow/login/test/persistence.go index 8cfbc3b5a8eb..5dbbed75fc6d 100644 --- a/selfservice/flow/login/test/persistence.go +++ b/selfservice/flow/login/test/persistence.go @@ -11,7 +11,7 @@ import ( "github.com/ory/kratos/internal/testhelpers" - "github.com/bxcodec/faker/v3" + "github.com/go-faker/faker/v4" "github.com/gofrs/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/selfservice/flow/recovery/test/persistence.go b/selfservice/flow/recovery/test/persistence.go index 665dc84b9130..8bc9efad88e0 100644 --- a/selfservice/flow/recovery/test/persistence.go +++ b/selfservice/flow/recovery/test/persistence.go @@ -7,7 +7,7 @@ import ( "context" "testing" - "github.com/bxcodec/faker/v3" + "github.com/go-faker/faker/v4" "github.com/gofrs/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/selfservice/flow/registration/flow_test.go b/selfservice/flow/registration/flow_test.go index aa199becd6b5..d5c13815bb13 100644 --- a/selfservice/flow/registration/flow_test.go +++ b/selfservice/flow/registration/flow_test.go @@ -21,7 +21,7 @@ import ( "github.com/ory/kratos/driver/config" "github.com/ory/kratos/internal" - "github.com/bxcodec/faker/v3" + "github.com/go-faker/faker/v4" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/selfservice/flow/registration/handler_test.go b/selfservice/flow/registration/handler_test.go index 1dac094b91c6..eae66fb720f8 100644 --- a/selfservice/flow/registration/handler_test.go +++ b/selfservice/flow/registration/handler_test.go @@ -16,7 +16,7 @@ import ( "testing" "time" - "github.com/bxcodec/faker/v3" + "github.com/go-faker/faker/v4" "github.com/gofrs/uuid" "github.com/ory/kratos/corpx" diff --git a/selfservice/flow/registration/test/persistence.go b/selfservice/flow/registration/test/persistence.go index a35059c845bc..d382c23a29ba 100644 --- a/selfservice/flow/registration/test/persistence.go +++ b/selfservice/flow/registration/test/persistence.go @@ -18,7 +18,7 @@ import ( "github.com/ory/x/assertx" - "github.com/bxcodec/faker/v3" + "github.com/go-faker/faker/v4" "github.com/gofrs/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/selfservice/flow/settings/error_test.go b/selfservice/flow/settings/error_test.go index 73116ba8a49a..5776cd2b6942 100644 --- a/selfservice/flow/settings/error_test.go +++ b/selfservice/flow/settings/error_test.go @@ -17,7 +17,7 @@ import ( "github.com/ory/kratos/ui/node" - "github.com/bxcodec/faker/v3" + "github.com/go-faker/faker/v4" "github.com/gobuffalo/httptest" "github.com/julienschmidt/httprouter" "github.com/stretchr/testify/assert" diff --git a/selfservice/flow/settings/flow_test.go b/selfservice/flow/settings/flow_test.go index 0a4da77f323d..26a40b71245d 100644 --- a/selfservice/flow/settings/flow_test.go +++ b/selfservice/flow/settings/flow_test.go @@ -22,7 +22,7 @@ import ( "github.com/ory/kratos/internal" - "github.com/bxcodec/faker/v3" + "github.com/go-faker/faker/v4" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/selfservice/flow/settings/test/persistence.go b/selfservice/flow/settings/test/persistence.go index 62bce9c547bf..85c80e49d74e 100644 --- a/selfservice/flow/settings/test/persistence.go +++ b/selfservice/flow/settings/test/persistence.go @@ -22,7 +22,7 @@ import ( "github.com/ory/kratos/ui/node" - "github.com/bxcodec/faker/v3" + "github.com/go-faker/faker/v4" "github.com/gofrs/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/selfservice/flow/verification/test/persistence.go b/selfservice/flow/verification/test/persistence.go index 0358462029f7..57c35cba8d2e 100644 --- a/selfservice/flow/verification/test/persistence.go +++ b/selfservice/flow/verification/test/persistence.go @@ -7,7 +7,7 @@ import ( "context" "testing" - "github.com/bxcodec/faker/v3" + "github.com/go-faker/faker/v4" "github.com/gofrs/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/selfservice/hook/session_destroyer_test.go b/selfservice/hook/session_destroyer_test.go index 653f77111209..e2d0cc21c2e2 100644 --- a/selfservice/hook/session_destroyer_test.go +++ b/selfservice/hook/session_destroyer_test.go @@ -13,7 +13,7 @@ import ( "github.com/ory/kratos/corpx" "github.com/ory/kratos/ui/node" - "github.com/bxcodec/faker/v3" + "github.com/go-faker/faker/v4" "github.com/gobuffalo/httptest" "github.com/gofrs/uuid" "github.com/stretchr/testify/assert" diff --git a/selfservice/strategy/code/test/persistence.go b/selfservice/strategy/code/test/persistence.go index f505bcb9c185..f3c120402ddb 100644 --- a/selfservice/strategy/code/test/persistence.go +++ b/selfservice/strategy/code/test/persistence.go @@ -14,7 +14,7 @@ import ( "github.com/ory/kratos/selfservice/strategy/code" "github.com/ory/x/randx" - "github.com/bxcodec/faker/v3" + "github.com/go-faker/faker/v4" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/selfservice/strategy/link/test/persistence.go b/selfservice/strategy/link/test/persistence.go index 63abe6179f18..af5738eaae31 100644 --- a/selfservice/strategy/link/test/persistence.go +++ b/selfservice/strategy/link/test/persistence.go @@ -14,7 +14,7 @@ import ( "github.com/ory/kratos/selfservice/strategy/link" "github.com/ory/x/sqlcon" - "github.com/bxcodec/faker/v3" + "github.com/go-faker/faker/v4" "github.com/gofrs/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/session/handler_test.go b/session/handler_test.go index b24644880cc7..286943796927 100644 --- a/session/handler_test.go +++ b/session/handler_test.go @@ -17,7 +17,7 @@ import ( "testing" "time" - "github.com/bxcodec/faker/v3" + "github.com/go-faker/faker/v4" "github.com/tidwall/gjson" "github.com/ory/kratos/identity" diff --git a/session/test/persistence.go b/session/test/persistence.go index d2a37837c7e9..fb6a7c469830 100644 --- a/session/test/persistence.go +++ b/session/test/persistence.go @@ -14,7 +14,7 @@ import ( "github.com/ory/kratos/identity" - "github.com/bxcodec/faker/v3" + "github.com/go-faker/faker/v4" "github.com/gofrs/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/ui/node/node_test.go b/ui/node/node_test.go index cfa425632ef2..f8867b98c2a3 100644 --- a/ui/node/node_test.go +++ b/ui/node/node_test.go @@ -17,7 +17,7 @@ import ( "github.com/ory/kratos/ui/container" - "github.com/bxcodec/faker/v3" + "github.com/go-faker/faker/v4" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tidwall/gjson" From 912dccdf04a550604c5bfeb53ccf79c5f1133ef2 Mon Sep 17 00:00:00 2001 From: Krzysztof Bogacki Date: Fri, 10 Nov 2023 10:15:07 +0100 Subject: [PATCH 179/282] fix: omit irrelevant OIDC providers in forced refresh login flows (#3608) Whenever an user is asked to reauthenticate (e.g. because they wish to execute settings flow touching their credentials and their session is no longer privileged) they are asked to provide their credentials again. The forced-refresh login flow generated for such cases already excludes some strategies that are enabled in Kratos but cannot be used to authenticate as current identity, and for example the form presented to the user will not have a password field if the identity does not have a password credential. This, however, does not currently apply to OIDC providers; the user will always see the full set even if some of them can't be used to sign in as current identity. This change causes forced refresh login flows to also omit irrelevant OIDC providers in generated form in order to avoid confunding the user about which strategies/providers are valid and can actually be used to reauthenticate. --- selfservice/strategy/oidc/strategy.go | 34 +++++++++++++++++-- selfservice/strategy/oidc/strategy_login.go | 2 +- .../strategy/oidc/strategy_registration.go | 2 +- .../strategy/oidc/strategy_settings_test.go | 24 +++++++++++-- .../profiles/oidc/settings/success.spec.ts | 13 +++++++ 5 files changed, 69 insertions(+), 6 deletions(-) diff --git a/selfservice/strategy/oidc/strategy.go b/selfservice/strategy/oidc/strategy.go index 2e536c8a35cf..8cf7b5069866 100644 --- a/selfservice/strategy/oidc/strategy.go +++ b/selfservice/strategy/oidc/strategy.go @@ -21,6 +21,7 @@ import ( "golang.org/x/oauth2" "github.com/ory/kratos/cipher" + "github.com/ory/kratos/selfservice/flowhelpers" "github.com/ory/kratos/selfservice/sessiontokenexchange" "github.com/ory/x/jsonnetsecure" "github.com/ory/x/otelx" @@ -484,15 +485,44 @@ func (s *Strategy) ExchangeCode(ctx context.Context, provider Provider, code str return token, err } -func (s *Strategy) populateMethod(r *http.Request, c *container.Container, message func(provider string) *text.Message) error { +func (s *Strategy) populateMethod(r *http.Request, f flow.Flow, message func(provider string) *text.Message) error { conf, err := s.Config(r.Context()) if err != nil { return err } + providers := conf.Providers + + if lf, ok := f.(*login.Flow); ok && lf.IsForced() { + if _, id, c := flowhelpers.GuessForcedLoginIdentifier(r, s.d, lf, s.ID()); id != nil { + if c == nil { + // no OIDC credentials, don't add any providers + providers = nil + } else { + var credentials identity.CredentialsOIDC + if err := json.Unmarshal(c.Config, &credentials); err != nil { + // failed to read OIDC credentials, don't add any providers + providers = nil + } else { + // add only providers that can actually be used to log in as this identity + providers = make([]Configuration, 0, len(conf.Providers)) + for i := range conf.Providers { + for j := range credentials.Providers { + if conf.Providers[i].ID == credentials.Providers[j].Provider { + providers = append(providers, conf.Providers[i]) + break + } + } + } + } + } + } + } + // does not need sorting because there is only one field + c := f.GetUI() c.SetCSRF(s.d.GenerateCSRFToken(r)) - AddProviders(c, conf.Providers, message) + AddProviders(c, providers, message) return nil } diff --git a/selfservice/strategy/oidc/strategy_login.go b/selfservice/strategy/oidc/strategy_login.go index c81537015bc9..a3048df1e15b 100644 --- a/selfservice/strategy/oidc/strategy_login.go +++ b/selfservice/strategy/oidc/strategy_login.go @@ -48,7 +48,7 @@ func (s *Strategy) PopulateLoginMethod(r *http.Request, requestedAAL identity.Au return nil } - return s.populateMethod(r, l.UI, text.NewInfoLoginWith) + return s.populateMethod(r, l, text.NewInfoLoginWith) } // Update Login Flow with OpenID Connect Method diff --git a/selfservice/strategy/oidc/strategy_registration.go b/selfservice/strategy/oidc/strategy_registration.go index d07e6c6fa8ed..d3f3b217f760 100644 --- a/selfservice/strategy/oidc/strategy_registration.go +++ b/selfservice/strategy/oidc/strategy_registration.go @@ -62,7 +62,7 @@ func (s *Strategy) RegisterRegistrationRoutes(r *x.RouterPublic) { } func (s *Strategy) PopulateRegistrationMethod(r *http.Request, f *registration.Flow) error { - return s.populateMethod(r, f.UI, text.NewInfoRegistrationWith) + return s.populateMethod(r, f, text.NewInfoRegistrationWith) } // Update Registration Flow with OpenID Connect Method diff --git a/selfservice/strategy/oidc/strategy_settings_test.go b/selfservice/strategy/oidc/strategy_settings_test.go index 69f2bc03a560..a6b819c94202 100644 --- a/selfservice/strategy/oidc/strategy_settings_test.go +++ b/selfservice/strategy/oidc/strategy_settings_test.go @@ -327,7 +327,17 @@ func TestSettingsStrategy(t *testing.T) { _, res, req := unlink(t, agent, provider) assert.Contains(t, res.Request.URL.String(), uiTS.URL+"/login") - rs, _, err := testhelpers.NewSDKCustomClient(publicTS, agents[agent]).FrontendApi.GetSettingsFlow(context.Background()).Id(req.Id).Execute() + fa := testhelpers.NewSDKCustomClient(publicTS, agents[agent]).FrontendApi + lf, _, err := fa.GetLoginFlow(context.Background()).Id(res.Request.URL.Query()["flow"][0]).Execute() + require.NoError(t, err) + + for _, node := range lf.Ui.Nodes { + if node.Group == "oidc" && node.Attributes.UiNodeInputAttributes.Name == "provider" { + assert.Contains(t, []string{"ory", "github"}, node.Attributes.UiNodeInputAttributes.Value) + } + } + + rs, _, err := fa.GetSettingsFlow(context.Background()).Id(req.Id).Execute() require.NoError(t, err) require.EqualValues(t, flow.StateShowForm, rs.State) @@ -554,7 +564,17 @@ func TestSettingsStrategy(t *testing.T) { _, res, req := link(t, agent, provider) assert.Contains(t, res.Request.URL.String(), uiTS.URL+"/login") - rs, _, err := testhelpers.NewSDKCustomClient(publicTS, agents[agent]).FrontendApi.GetSettingsFlow(context.Background()).Id(req.Id).Execute() + fa := testhelpers.NewSDKCustomClient(publicTS, agents[agent]).FrontendApi + lf, _, err := fa.GetLoginFlow(context.Background()).Id(res.Request.URL.Query()["flow"][0]).Execute() + require.NoError(t, err) + + for _, node := range lf.Ui.Nodes { + if node.Group == "oidc" && node.Attributes.UiNodeInputAttributes.Name == "provider" { + assert.Contains(t, []string{"ory", "github"}, node.Attributes.UiNodeInputAttributes.Value) + } + } + + rs, _, err := fa.GetSettingsFlow(context.Background()).Id(req.Id).Execute() require.NoError(t, err) require.EqualValues(t, flow.StateShowForm, rs.State) diff --git a/test/e2e/cypress/integration/profiles/oidc/settings/success.spec.ts b/test/e2e/cypress/integration/profiles/oidc/settings/success.spec.ts index dadbc06d9453..674e24e0d668 100644 --- a/test/e2e/cypress/integration/profiles/oidc/settings/success.spec.ts +++ b/test/e2e/cypress/integration/profiles/oidc/settings/success.spec.ts @@ -196,6 +196,19 @@ context("Social Sign In Settings Success", () => { hydraReauthFails() }) + it("should show only linked providers during reauth", () => { + cy.shortPrivilegedSessionTime() + + cy.get('input[name="password"]').type(gen.password()) + cy.get('[value="password"]').click() + + cy.location("pathname").should("equal", "/login") + + cy.get('[value="hydra"]').should("exist") + cy.get('[value="google"]').should("not.exist") + cy.get('[value="github"]').should("not.exist") + }) + it("settings screen stays intact when the original sign up method gets removed", () => { const expectSettingsOk = () => { cy.get('[value="google"]', { timeout: 1000 }) From 2474864f4a64fe97925debb218e12a53b48199a7 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Fri, 10 Nov 2023 10:29:13 +0000 Subject: [PATCH 180/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d63a3555b11..9c08af60d491 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-11-08)](#2023-11-08) +- [ (2023-11-10)](#2023-11-10) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -314,7 +314,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-11-08) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-11-10) ## Breaking Changes @@ -490,6 +490,25 @@ https://github.com/ory/kratos/pull/3480 The identity is not always available in the session struct, for example when AAL2 is required. +- Omit irrelevant OIDC providers in forced refresh login flows + ([#3608](https://github.com/ory/kratos/issues/3608)) + ([912dccd](https://github.com/ory/kratos/commit/912dccdf04a550604c5bfeb53ccf79c5f1133ef2)): + + Whenever an user is asked to reauthenticate (e.g. because they wish to execute + settings flow touching their credentials and their session is no longer + privileged) they are asked to provide their credentials again. The + forced-refresh login flow generated for such cases already excludes some + strategies that are enabled in Kratos but cannot be used to authenticate as + current identity, and for example the form presented to the user will not have + a password field if the identity does not have a password credential. + + This, however, does not currently apply to OIDC providers; the user will + always see the full set even if some of them can't be used to sign in as + current identity. This change causes forced refresh login flows to also omit + irrelevant OIDC providers in generated form in order to avoid confunding the + user about which strategies/providers are valid and can actually be used to + reauthenticate. + - On verification required after registration, preserve return_to ([#3589](https://github.com/ory/kratos/issues/3589)) ([6a0a914](https://github.com/ory/kratos/commit/6a0a9149b9828ba994bec9b48a43f9d70245f43f)): From f7c6767dee8158b32ec88650906977288c05ee91 Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Fri, 10 Nov 2023 15:04:08 +0100 Subject: [PATCH 181/282] chore: add missing tracing in manager_cookie.go (#3615) --- continuity/manager_cookie.go | 42 ++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/continuity/manager_cookie.go b/continuity/manager_cookie.go index 314c33da4a68..495800a87736 100644 --- a/continuity/manager_cookie.go +++ b/continuity/manager_cookie.go @@ -13,14 +13,17 @@ import ( "github.com/pkg/errors" "github.com/ory/herodot" + "github.com/ory/x/otelx" "github.com/ory/x/sqlcon" "github.com/ory/kratos/session" "github.com/ory/kratos/x" ) -var _ Manager = new(ManagerCookie) -var ErrNotResumable = *herodot.ErrBadRequest.WithError("no resumable session found").WithReasonf("The browser does not contain the necessary cookie to resume the session. This is a security violation and was blocked. Please clear your browser's cookies and cache and try again!") +var ( + _ Manager = new(ManagerCookie) + ErrNotResumable = *herodot.ErrBadRequest.WithError("no resumable session found").WithReasonf("The browser does not contain the necessary cookie to resume the session. This is a security violation and was blocked. Please clear your browser's cookies and cache and try again!") +) const CookieName = "ory_kratos_continuity" @@ -29,6 +32,7 @@ type ( PersistenceProvider x.CookieProvider session.ManagementProvider + x.TracingProvider } ManagerCookie struct { d managerCookieDependencies @@ -39,7 +43,9 @@ func NewManagerCookie(d managerCookieDependencies) *ManagerCookie { return &ManagerCookie{d: d} } -func (m *ManagerCookie) Pause(ctx context.Context, w http.ResponseWriter, r *http.Request, name string, opts ...ManagerOption) error { +func (m *ManagerCookie) Pause(ctx context.Context, w http.ResponseWriter, r *http.Request, name string, opts ...ManagerOption) (err error) { + ctx, span := m.d.Tracer(ctx).Tracer().Start(ctx, "continuity.ManagerCookie.Pause") + defer otelx.End(span, &err) if len(name) == 0 { return errors.Errorf("continuity container name must be set") } @@ -63,8 +69,11 @@ func (m *ManagerCookie) Pause(ctx context.Context, w http.ResponseWriter, r *htt return nil } -func (m *ManagerCookie) Continue(ctx context.Context, w http.ResponseWriter, r *http.Request, name string, opts ...ManagerOption) (*Container, error) { - container, err := m.container(ctx, w, r, name) +func (m *ManagerCookie) Continue(ctx context.Context, w http.ResponseWriter, r *http.Request, name string, opts ...ManagerOption) (container *Container, err error) { + ctx, span := m.d.Tracer(ctx).Tracer().Start(ctx, "continuity.ManagerCookie.Continue") + defer otelx.End(span, &err) + + container, err = m.container(ctx, w, r, name) if err != nil { return nil, err } @@ -95,21 +104,24 @@ func (m *ManagerCookie) Continue(ctx context.Context, w http.ResponseWriter, r * return container, nil } -func (m *ManagerCookie) sid(ctx context.Context, w http.ResponseWriter, r *http.Request, name string) (uuid.UUID, error) { - var sid uuid.UUID - if s, err := x.SessionGetString(r, m.d.ContinuityCookieManager(ctx), CookieName, name); err != nil { +func (m *ManagerCookie) sessionID(ctx context.Context, w http.ResponseWriter, r *http.Request, name string) (uuid.UUID, error) { + s, err := x.SessionGetString(r, m.d.ContinuityCookieManager(ctx), CookieName, name) + if err != nil { _ = x.SessionUnsetKey(w, r, m.d.ContinuityCookieManager(ctx), CookieName, name) - return sid, errors.WithStack(ErrNotResumable.WithDebugf("%+v", err)) - } else if sid = x.ParseUUID(s); sid == uuid.Nil { + return uuid.Nil, errors.WithStack(ErrNotResumable.WithDebugf("%+v", err)) + } + + sid, err := uuid.FromString(s) + if err != nil { _ = x.SessionUnsetKey(w, r, m.d.ContinuityCookieManager(ctx), CookieName, name) - return sid, errors.WithStack(ErrNotResumable.WithDebug("session id is not a valid uuid")) + return uuid.Nil, errors.WithStack(ErrNotResumable.WithDebug("session id is not a valid uuid")) } return sid, nil } func (m *ManagerCookie) container(ctx context.Context, w http.ResponseWriter, r *http.Request, name string) (*Container, error) { - sid, err := m.sid(ctx, w, r, name) + sid, err := m.sessionID(ctx, w, r, name) if err != nil { return nil, err } @@ -129,8 +141,10 @@ func (m *ManagerCookie) container(ctx context.Context, w http.ResponseWriter, r return container, err } -func (m ManagerCookie) Abort(ctx context.Context, w http.ResponseWriter, r *http.Request, name string) error { - sid, err := m.sid(ctx, w, r, name) +func (m ManagerCookie) Abort(ctx context.Context, w http.ResponseWriter, r *http.Request, name string) (err error) { + ctx, span := m.d.Tracer(ctx).Tracer().Start(ctx, "continuity.ManagerCookie.Abort") + defer otelx.End(span, &err) + sid, err := m.sessionID(ctx, w, r, name) if errors.Is(err, &ErrNotResumable) { // We do not care about an error here return nil From b2b231ee58978c020e9123f194af67713e1f98a8 Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Mon, 13 Nov 2023 11:10:04 +0100 Subject: [PATCH 182/282] chore: improve tracing on recovery and verification (#3586) --- selfservice/strategy/code/strategy_login.go | 2 +- selfservice/strategy/code/strategy_recovery.go | 7 ++++++- selfservice/strategy/code/strategy_verification.go | 6 ++++++ selfservice/strategy/link/strategy.go | 1 + selfservice/strategy/link/strategy_recovery.go | 6 ++++++ selfservice/strategy/link/strategy_verification.go | 7 +++++++ 6 files changed, 27 insertions(+), 2 deletions(-) diff --git a/selfservice/strategy/code/strategy_login.go b/selfservice/strategy/code/strategy_login.go index e837e6f7756d..64a3ab13a325 100644 --- a/selfservice/strategy/code/strategy_login.go +++ b/selfservice/strategy/code/strategy_login.go @@ -101,7 +101,7 @@ func (s *Strategy) PopulateLoginMethod(r *http.Request, requestedAAL identity.Au // the identity through other credentials matching the identifier. // the fallback mechanism is used for migration purposes of old accounts that do not have a code credential. func (s *Strategy) findIdentityByIdentifier(ctx context.Context, identifier string) (_ *identity.Identity, isFallback bool, err error) { - ctx, span := s.deps.Tracer(ctx).Tracer().Start(ctx, "selfservice.strategy.code.strategy.getIdentity") + ctx, span := s.deps.Tracer(ctx).Tracer().Start(ctx, "selfservice.strategy.code.strategy.findIdentityByIdentifier") defer otelx.End(span, &err) id, cred, err := s.deps.PrivilegedIdentityPool().FindByCredentialsIdentifier(ctx, s.ID(), identifier) diff --git a/selfservice/strategy/code/strategy_recovery.go b/selfservice/strategy/code/strategy_recovery.go index 0bdc2d603801..6d75e065e7d1 100644 --- a/selfservice/strategy/code/strategy_recovery.go +++ b/selfservice/strategy/code/strategy_recovery.go @@ -11,9 +11,11 @@ import ( "github.com/gofrs/uuid" "github.com/julienschmidt/httprouter" "github.com/pkg/errors" + "go.opentelemetry.io/otel/attribute" "github.com/ory/herodot" "github.com/ory/x/decoderx" + "github.com/ory/x/otelx" "github.com/ory/x/sqlcon" "github.com/ory/x/sqlxx" "github.com/ory/x/urlx" @@ -285,6 +287,10 @@ func (s Strategy) isCodeFlow(f *recovery.Flow) bool { } func (s *Strategy) Recover(w http.ResponseWriter, r *http.Request, f *recovery.Flow) (err error) { + ctx, span := s.deps.Tracer(r.Context()).Tracer().Start(r.Context(), "selfservice.strategy.code.strategy.Recover") + span.SetAttributes(attribute.String("selfservice_flows_recovery_use", s.deps.Config().SelfServiceFlowRecoveryUse(ctx))) + defer otelx.End(span, &err) + if !s.isCodeFlow(f) { return errors.WithStack(flow.ErrStrategyNotResponsible) } @@ -293,7 +299,6 @@ func (s *Strategy) Recover(w http.ResponseWriter, r *http.Request, f *recovery.F if err != nil { return s.HandleRecoveryError(w, r, nil, body, err) } - ctx := r.Context() if f.DangerousSkipCSRFCheck { s.deps.Logger(). diff --git a/selfservice/strategy/code/strategy_verification.go b/selfservice/strategy/code/strategy_verification.go index c02e89105116..28e21456323e 100644 --- a/selfservice/strategy/code/strategy_verification.go +++ b/selfservice/strategy/code/strategy_verification.go @@ -9,6 +9,7 @@ import ( "time" "github.com/pkg/errors" + "go.opentelemetry.io/otel/attribute" "github.com/ory/kratos/identity" "github.com/ory/kratos/schema" @@ -19,6 +20,7 @@ import ( "github.com/ory/kratos/ui/node" "github.com/ory/kratos/x" "github.com/ory/x/decoderx" + "github.com/ory/x/otelx" "github.com/ory/x/sqlxx" ) @@ -123,6 +125,10 @@ func (body *updateVerificationFlowWithCodeMethod) getMethod() verification.Verif } func (s *Strategy) Verify(w http.ResponseWriter, r *http.Request, f *verification.Flow) (err error) { + ctx, span := s.deps.Tracer(r.Context()).Tracer().Start(r.Context(), "selfservice.strategy.code.strategy.Verify") + span.SetAttributes(attribute.String("selfservice_flows_verification_use", s.deps.Config().SelfServiceFlowVerificationUse(ctx))) + defer otelx.End(span, &err) + body, err := s.decodeVerification(r) if err != nil { return s.handleVerificationError(w, r, nil, body, err) diff --git a/selfservice/strategy/link/strategy.go b/selfservice/strategy/link/strategy.go index f5a0326b9d0b..8188b7e9e873 100644 --- a/selfservice/strategy/link/strategy.go +++ b/selfservice/strategy/link/strategy.go @@ -42,6 +42,7 @@ type ( x.CSRFTokenGeneratorProvider x.WriterProvider x.LoggingProvider + x.TracingProvider config.Provider diff --git a/selfservice/strategy/link/strategy_recovery.go b/selfservice/strategy/link/strategy_recovery.go index da4f40ac9516..326a35c7bfe0 100644 --- a/selfservice/strategy/link/strategy_recovery.go +++ b/selfservice/strategy/link/strategy_recovery.go @@ -11,9 +11,11 @@ import ( "github.com/gofrs/uuid" "github.com/julienschmidt/httprouter" "github.com/pkg/errors" + "go.opentelemetry.io/otel/attribute" "github.com/ory/herodot" "github.com/ory/x/decoderx" + "github.com/ory/x/otelx" "github.com/ory/x/sqlcon" "github.com/ory/x/sqlxx" "github.com/ory/x/urlx" @@ -231,6 +233,10 @@ type updateRecoveryFlowWithLinkMethod struct { } func (s *Strategy) Recover(w http.ResponseWriter, r *http.Request, f *recovery.Flow) (err error) { + ctx, span := s.d.Tracer(r.Context()).Tracer().Start(r.Context(), "selfservice.strategy.link.strategy.Recover") + span.SetAttributes(attribute.String("selfservice_flows_recovery_use", s.d.Config().SelfServiceFlowRecoveryUse(ctx))) + defer otelx.End(span, &err) + body, err := s.decodeRecovery(r) if err != nil { return s.HandleRecoveryError(w, r, nil, body, err) diff --git a/selfservice/strategy/link/strategy_verification.go b/selfservice/strategy/link/strategy_verification.go index 47271cd7191d..0db56233fa3f 100644 --- a/selfservice/strategy/link/strategy_verification.go +++ b/selfservice/strategy/link/strategy_verification.go @@ -10,6 +10,7 @@ import ( "time" "github.com/pkg/errors" + "go.opentelemetry.io/otel/attribute" "github.com/ory/kratos/identity" "github.com/ory/kratos/schema" @@ -20,6 +21,7 @@ import ( "github.com/ory/kratos/ui/node" "github.com/ory/kratos/x" "github.com/ory/x/decoderx" + "github.com/ory/x/otelx" "github.com/ory/x/sqlcon" "github.com/ory/x/sqlxx" "github.com/ory/x/urlx" @@ -116,6 +118,11 @@ type updateVerificationFlowWithLinkMethod struct { } func (s *Strategy) Verify(w http.ResponseWriter, r *http.Request, f *verification.Flow) (err error) { + ctx, span := s.d.Tracer(r.Context()).Tracer().Start(r.Context(), "selfservice.strategy.link.strategy.Verify") + span.SetAttributes(attribute.String("selfservice_flows_verification_use", s.d.Config().SelfServiceFlowVerificationUse(ctx))) + defer otelx.End(span, &err) + r = r.WithContext(ctx) + body, err := s.decodeVerification(r) if err != nil { return s.handleVerificationError(w, r, nil, body, err) From 4364ba0d39b8aaa5b9051117694ba628784b38dd Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Mon, 13 Nov 2023 11:17:01 +0000 Subject: [PATCH 183/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c08af60d491..222a58ef41af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-11-10)](#2023-11-10) +- [ (2023-11-13)](#2023-11-13) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -314,7 +314,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-11-10) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-11-13) ## Breaking Changes From 0fa648d9f7b837a35de9b230a05b5951e95d5874 Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Mon, 13 Nov 2023 12:45:56 +0100 Subject: [PATCH 184/282] feat: allow additional id token audiences (#3616) --- embedx/config.schema.json | 13 ++++-- selfservice/strategy/oidc/provider_apple.go | 17 +++----- .../strategy/oidc/provider_apple_test.go | 22 +++++++--- selfservice/strategy/oidc/provider_config.go | 6 ++- selfservice/strategy/oidc/provider_google.go | 16 ++----- .../strategy/oidc/provider_google_test.go | 23 +++++++--- .../strategy/oidc/strategy_helper_test.go | 4 +- selfservice/strategy/oidc/token_verifier.go | 42 +++++++++++++++++++ 8 files changed, 102 insertions(+), 41 deletions(-) create mode 100644 selfservice/strategy/oidc/token_verifier.go diff --git a/embedx/config.schema.json b/embedx/config.schema.json index 0f1cfd03546d..70ac3a54c9d0 100644 --- a/embedx/config.schema.json +++ b/embedx/config.schema.json @@ -531,6 +531,14 @@ "description": "The ID of the organization that this provider belongs to. Only effective in the Ory Network.", "type": "string", "examples": ["12345678-1234-1234-1234-123456789012"] + }, + "allowed_id_token_audiences": { + "title": "Additional client ids allowed when using ID token submission", + "type": "array", + "items": { + "type": "string", + "examples": ["12345678-1234-1234-1234-123456789012"] + } } }, "additionalProperties": false, @@ -2004,10 +2012,7 @@ "type": "string", "title": "Default Read Consistency Level", "description": "The default consistency level to use when reading from the database. Defaults to `strong` to not break existing API contracts. Only set this to `eventual` if you can accept that other read APIs will suddenly return eventually consistent results. It is only effective in Ory Network.", - "enum": [ - "strong", - "eventual" - ], + "enum": ["strong", "eventual"], "default": "strong" } } diff --git a/selfservice/strategy/oidc/provider_apple.go b/selfservice/strategy/oidc/provider_apple.go index 27dd2b7e6635..d680d0c1faae 100644 --- a/selfservice/strategy/oidc/provider_apple.go +++ b/selfservice/strategy/oidc/provider_apple.go @@ -154,20 +154,13 @@ func (a *ProviderApple) DecodeQuery(query url.Values, claims *Claims) { var _ IDTokenVerifier = new(ProviderApple) +const issuerUrlApple = "https://appleid.apple.com" + func (a *ProviderApple) Verify(ctx context.Context, rawIDToken string) (*Claims, error) { keySet := oidc.NewRemoteKeySet(ctx, a.JWKSUrl) - verifier := oidc.NewVerifier("https://appleid.apple.com", keySet, &oidc.Config{ - ClientID: a.config.ClientID, - }) - token, err := verifier.Verify(oidc.ClientContext(ctx, a.reg.HTTPClient(ctx).HTTPClient), rawIDToken) - if err != nil { - return nil, err - } - claims := &Claims{} - if err := token.Claims(claims); err != nil { - return nil, err - } - return claims, nil + + ctx = oidc.ClientContext(ctx, a.reg.HTTPClient(ctx).HTTPClient) + return verifyToken(ctx, keySet, a.config, rawIDToken, issuerUrlApple) } var _ NonceValidationSkipper = new(ProviderApple) diff --git a/selfservice/strategy/oidc/provider_apple_test.go b/selfservice/strategy/oidc/provider_apple_test.go index 69d5dfd44b69..422ae643708a 100644 --- a/selfservice/strategy/oidc/provider_apple_test.go +++ b/selfservice/strategy/oidc/provider_apple_test.go @@ -48,7 +48,6 @@ func TestDecodeQuery(t *testing.T) { assert.Empty(t, tc.claims.Email) }) } - } func TestAppleVerify(t *testing.T) { @@ -64,7 +63,7 @@ func TestAppleVerify(t *testing.T) { makeClaims := func(aud string) jwt.RegisteredClaims { return jwt.RegisteredClaims{ Issuer: "https://appleid.apple.com", - Subject: "apple@ory.sh", + Subject: "acme@ory.sh", Audience: jwt.ClaimStrings{aud}, ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), } @@ -79,8 +78,8 @@ func TestAppleVerify(t *testing.T) { c, err := apple.Verify(context.Background(), token) require.NoError(t, err) - assert.Equal(t, "apple@ory.sh", c.Email) - assert.Equal(t, "apple@ory.sh", c.Subject) + assert.Equal(t, "acme@ory.sh", c.Email) + assert.Equal(t, "acme@ory.sh", c.Subject) assert.Equal(t, "https://appleid.apple.com", c.Issuer) }) @@ -94,7 +93,7 @@ func TestAppleVerify(t *testing.T) { _, err := apple.Verify(context.Background(), token) require.Error(t, err) - assert.Equal(t, `oidc: expected audience "com.example.app" got ["com.different-example.app"]`, err.Error()) + assert.Equal(t, `token audience didn't match allowed audiences: [com.example.app] oidc: expected audience "com.example.app" got ["com.different-example.app"]`, err.Error()) }) t.Run("case=fails due to jwks mismatch", func(t *testing.T) { @@ -109,4 +108,17 @@ func TestAppleVerify(t *testing.T) { require.Error(t, err) assert.Equal(t, "failed to verify signature: failed to verify id token signature", err.Error()) }) + + t.Run("case=succeedes with additional id token audience", func(t *testing.T) { + _, reg := internal.NewFastRegistryWithMocks(t) + apple := oidc.NewProviderApple(&oidc.Configuration{ + ClientID: "something.else.app", + AdditionalIDTokenAudiences: []string{"com.example.app"}, + }, reg).(*oidc.ProviderApple) + apple.JWKSUrl = ts.URL + token := createIdToken(t, makeClaims("com.example.app")) + + _, err := apple.Verify(context.Background(), token) + require.NoError(t, err) + }) } diff --git a/selfservice/strategy/oidc/provider_config.go b/selfservice/strategy/oidc/provider_config.go index 4c8275c4f709..c6fc84f762de 100644 --- a/selfservice/strategy/oidc/provider_config.go +++ b/selfservice/strategy/oidc/provider_config.go @@ -99,7 +99,7 @@ type Configuration struct { // It can be either a URL (file://, http(s)://, base64://) or an inline JSONNet code snippet. Mapper string `json:"mapper_url"` - // RequestedClaims string encoded json object that specifies claims and optionally their properties which should be + // RequestedClaims is a string encoded json object that specifies claims and optionally their properties that should be // included in the id_token or returned from the UserInfo Endpoint. // // More information: https://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter @@ -108,6 +108,10 @@ type Configuration struct { // An optional organization ID that this provider belongs to. // This parameter is only effective in the Ory Network. OrganizationID string `json:"organization_id"` + + // AdditionalIDTokenAudiences is a list of additional audiences allowed in the ID Token. + // This is only relevant in OIDC flows that submit an IDToken instead of using the callback from the OIDC provider. + AdditionalIDTokenAudiences []string `json:"additional_id_token_audiences"` } func (p Configuration) Redir(public *url.URL) string { diff --git a/selfservice/strategy/oidc/provider_google.go b/selfservice/strategy/oidc/provider_google.go index c1ccdf505383..db7b4fdd14e5 100644 --- a/selfservice/strategy/oidc/provider_google.go +++ b/selfservice/strategy/oidc/provider_google.go @@ -72,20 +72,12 @@ func (g *ProviderGoogle) AuthCodeURLOptions(r ider) []oauth2.AuthCodeOption { var _ IDTokenVerifier = new(ProviderGoogle) +const issuerUrlGoogle = "https://accounts.google.com" + func (p *ProviderGoogle) Verify(ctx context.Context, rawIDToken string) (*Claims, error) { keySet := oidc.NewRemoteKeySet(ctx, p.JWKSUrl) - verifier := oidc.NewVerifier("https://accounts.google.com", keySet, &oidc.Config{ - ClientID: p.config.ClientID, - }) - token, err := verifier.Verify(oidc.ClientContext(ctx, p.reg.HTTPClient(ctx).HTTPClient), rawIDToken) - if err != nil { - return nil, err - } - claims := &Claims{} - if err := token.Claims(claims); err != nil { - return nil, err - } - return claims, nil + ctx = oidc.ClientContext(ctx, p.reg.HTTPClient(ctx).HTTPClient) + return verifyToken(ctx, keySet, p.config, rawIDToken, issuerUrlGoogle) } var _ NonceValidationSkipper = new(ProviderGoogle) diff --git a/selfservice/strategy/oidc/provider_google_test.go b/selfservice/strategy/oidc/provider_google_test.go index 2d849948d391..d900b088d358 100644 --- a/selfservice/strategy/oidc/provider_google_test.go +++ b/selfservice/strategy/oidc/provider_google_test.go @@ -59,7 +59,7 @@ func TestProviderGoogle_AccessType(t *testing.T) { assert.Contains(t, options, oauth2.AccessTypeOffline) } -func TestVerify(t *testing.T) { +func TestGoogleVerify(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(200) w.Write(publicJWKS) @@ -73,7 +73,7 @@ func TestVerify(t *testing.T) { makeClaims := func(aud string) jwt.RegisteredClaims { return jwt.RegisteredClaims{ Issuer: "https://accounts.google.com", - Subject: "apple@ory.sh", + Subject: "acme@ory.sh", Audience: jwt.ClaimStrings{aud}, ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), } @@ -98,8 +98,8 @@ func TestVerify(t *testing.T) { c, err := p.Verify(context.Background(), token) require.NoError(t, err) - assert.Equal(t, "apple@ory.sh", c.Email) - assert.Equal(t, "apple@ory.sh", c.Subject) + assert.Equal(t, "acme@ory.sh", c.Email) + assert.Equal(t, "acme@ory.sh", c.Subject) assert.Equal(t, "https://accounts.google.com", c.Issuer) }) @@ -109,7 +109,7 @@ func TestVerify(t *testing.T) { _, err := p.Verify(context.Background(), token) require.Error(t, err) - assert.Equal(t, `oidc: expected audience "com.example.app" got ["com.different-example.app"]`, err.Error()) + assert.Equal(t, `token audience didn't match allowed audiences: [com.example.app] oidc: expected audience "com.example.app" got ["com.different-example.app"]`, err.Error()) }) t.Run("case=fails due to jwks mismatch", func(t *testing.T) { @@ -120,4 +120,17 @@ func TestVerify(t *testing.T) { require.Error(t, err) assert.Equal(t, "failed to verify signature: failed to verify id token signature", err.Error()) }) + + t.Run("case=succeedes with additional id token audience", func(t *testing.T) { + _, reg := internal.NewFastRegistryWithMocks(t) + google := oidc.NewProviderGoogle(&oidc.Configuration{ + ClientID: "something.else.app", + AdditionalIDTokenAudiences: []string{"com.example.app"}, + }, reg).(*oidc.ProviderGoogle) + google.JWKSUrl = ts.URL + token := createIdToken(t, makeClaims("com.example.app")) + + _, err := google.Verify(context.Background(), token) + require.NoError(t, err) + }) } diff --git a/selfservice/strategy/oidc/strategy_helper_test.go b/selfservice/strategy/oidc/strategy_helper_test.go index 0c92de45d0c7..51df94357bda 100644 --- a/selfservice/strategy/oidc/strategy_helper_test.go +++ b/selfservice/strategy/oidc/strategy_helper_test.go @@ -119,7 +119,7 @@ func newHydraIntegration(t *testing.T, remote *string, subject *string, claims * GrantScope []string `json:"grant_scope,omitempty"` } - var do = func(w http.ResponseWriter, r *http.Request, href string, payload io.Reader) { + do := func(w http.ResponseWriter, r *http.Request, href string, payload io.Reader) { req, err := http.NewRequest("PUT", href, payload) require.NoError(t, err) req.Header.Set("Content-Type", "application/json") @@ -370,7 +370,7 @@ func createIdToken(t *testing.T, cl jwt.RegisteredClaims) string { require.NoError(t, json.Unmarshal(rawKey, key)) token := jwt.NewWithClaims(jwt.SigningMethodRS256, &claims{ RegisteredClaims: &cl, - Email: "apple@ory.sh", + Email: "acme@ory.sh", }) token.Header["kid"] = key.KeyID s, err := token.SignedString(key.Key) diff --git a/selfservice/strategy/oidc/token_verifier.go b/selfservice/strategy/oidc/token_verifier.go new file mode 100644 index 000000000000..e30a529bc6cc --- /dev/null +++ b/selfservice/strategy/oidc/token_verifier.go @@ -0,0 +1,42 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package oidc + +import ( + "context" + "fmt" + "strings" + + "github.com/coreos/go-oidc" +) + +func verifyToken(ctx context.Context, keySet oidc.KeySet, config *Configuration, rawIDToken, issuerURL string) (*Claims, error) { + tokenAudiences := append([]string{config.ClientID}, config.AdditionalIDTokenAudiences...) + var token *oidc.IDToken + err := fmt.Errorf("no audience matched the token's audience") + for _, aud := range tokenAudiences { + verifier := oidc.NewVerifier(issuerURL, keySet, &oidc.Config{ + ClientID: aud, + }) + token, err = verifier.Verify(ctx, rawIDToken) + if err != nil && strings.Contains(err.Error(), "oidc: expected audience") { + // The audience is not the one we expect, try the next one + continue + } else if err != nil { + // Something else went wrong + return nil, err + } + // The token was verified successfully + break + } + if err != nil { + // None of the allowed audiences matched the audience in the token + return nil, fmt.Errorf("token audience didn't match allowed audiences: %+v %w", tokenAudiences, err) + } + claims := &Claims{} + if err := token.Claims(claims); err != nil { + return nil, err + } + return claims, nil +} From 32299d5eb45e735f071d9509354a148f8d353adb Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Mon, 13 Nov 2023 12:50:14 +0000 Subject: [PATCH 185/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 222a58ef41af..b38cbdef2ee2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -740,6 +740,9 @@ https://github.com/ory/kratos/pull/3480 - 4070005 - 5000001 +- Allow additional id token audiences + ([#3616](https://github.com/ory/kratos/issues/3616)) + ([0fa648d](https://github.com/ory/kratos/commit/0fa648d9f7b837a35de9b230a05b5951e95d5874)) - Allow extra migrations in NewPersister ([96c1ff7](https://github.com/ory/kratos/commit/96c1ff7747ea38e23a3892f74b75ee555ed49c88)) - Allow fuzzy-search on credential identifiers From 8ad54f1be53b30fdb24b616be0c52fd66829f201 Mon Sep 17 00:00:00 2001 From: Dawid Danieluk <32909532+nxy7@users.noreply.github.com> Date: Mon, 13 Nov 2023 22:14:43 +0100 Subject: [PATCH 186/282] feat: batch list identities (#3598) This change allows to filter `GET /admin/identities` by ID with the following syntax: ``` /admin/identities?ids=id1&ids=id2&ids=id3 ``` Closes #2448 --- identity/handler.go | 8 ++++++ identity/handler_test.go | 28 +++++++++++++++++++ identity/pool.go | 1 + identity/test/pool.go | 11 ++++++++ .../sql/identity/persister_identity.go | 7 +++++ 5 files changed, 55 insertions(+) diff --git a/identity/handler.go b/identity/handler.go index 2749396632b3..9eb5f11cba99 100644 --- a/identity/handler.go +++ b/identity/handler.go @@ -138,6 +138,13 @@ type listIdentitiesResponse struct { type listIdentitiesParameters struct { migrationpagination.RequestParameters + // IdsFilter is list of ids used to filter identities. + // If this list is empty, then no filter will be applied. + // + // required: false + // in: query + IdsFilter []string `json:"ids_filter"` + // CredentialsIdentifier is the identifier (username, email) of the credentials to look up using exact match. // Only one of CredentialsIdentifier and CredentialsIdentifierSimilar can be used. // @@ -180,6 +187,7 @@ func (h *Handler) list(w http.ResponseWriter, r *http.Request, _ httprouter.Para err error params = ListIdentityParameters{ Expand: ExpandDefault, + IdsFilter: r.URL.Query()["ids"], CredentialsIdentifier: r.URL.Query().Get("credentials_identifier"), CredentialsIdentifierSimilar: r.URL.Query().Get("preview_credentials_identifier_similar"), ConsistencyLevel: crdbx.ConsistencyLevelFromRequest(r), diff --git a/identity/handler_test.go b/identity/handler_test.go index 2e38de8db126..0d5c031cbfad 100644 --- a/identity/handler_test.go +++ b/identity/handler_test.go @@ -339,6 +339,34 @@ func TestHandler(t *testing.T) { } }) + t.Run("suite=create and batch list", func(t *testing.T) { + var ids []uuid.UUID + identitiesAmount := 5 + listAmount := 3 + t.Run("case= create multiple identities", func(t *testing.T) { + for i := 0; i < identitiesAmount; i++ { + res := send(t, adminTS, "POST", "/identities", http.StatusCreated, json.RawMessage(`{"traits": {"bar":"baz"}}`)) + assert.NotEmpty(t, res.Get("id").String(), "%s", res.Raw) + + id := x.ParseUUID(res.Get("id").String()) + ids = append(ids, id) + } + require.Equal(t, len(ids), identitiesAmount) + }) + + t.Run("case= list few identities", func(t *testing.T) { + url := "/identities?ids=" + ids[0].String() + for i := 1; i < listAmount; i++ { + url += "&ids=" + ids[i].String() + } + res := get(t, adminTS, url, 200) + + identities := res.Array() + require.Equal(t, len(identities), listAmount) + }) + + }) + t.Run("suite=create and update", func(t *testing.T) { var i identity.Identity createOidcIdentity := func(t *testing.T, identifier, accessToken, refreshToken, idToken string, encrypt bool) string { diff --git a/identity/pool.go b/identity/pool.go index 46083d3d525b..1da5181b796a 100644 --- a/identity/pool.go +++ b/identity/pool.go @@ -18,6 +18,7 @@ import ( type ( ListIdentityParameters struct { Expand Expandables + IdsFilter []string CredentialsIdentifier string CredentialsIdentifierSimilar string KeySetPagination []keysetpagination.Option diff --git a/identity/test/pool.go b/identity/test/pool.go index 371d4a2cf6b1..8acf9dbfd078 100644 --- a/identity/test/pool.go +++ b/identity/test/pool.go @@ -657,6 +657,17 @@ func TestPool(ctx context.Context, conf *config.Config, p persistence.Persister, assert.Len(t, is, 0) }) + t.Run("list some using ids filter", func(t *testing.T) { + var filterIds []string + for _, id := range createdIDs[:2] { + filterIds = append(filterIds, id.String()) + } + + is, _, err := p.ListIdentities(ctx, identity.ListIdentityParameters{Expand: identity.ExpandDefault, IdsFilter: filterIds}) + require.NoError(t, err) + assert.Len(t, is, len(filterIds)) + }) + t.Run("eventually consistent", func(t *testing.T) { if dbname != "cockroach" { t.Skipf("Test only works with cockroachdb") diff --git a/persistence/sql/identity/persister_identity.go b/persistence/sql/identity/persister_identity.go index 6e3566b7721c..82d7b035e295 100644 --- a/persistence/sql/identity/persister_identity.go +++ b/persistence/sql/identity/persister_identity.go @@ -774,6 +774,13 @@ func (p *IdentityPersister) ListIdentities(ctx context.Context, params identity. args = append(args, nid, nid, identifier, identity.CredentialsTypeWebAuthn, identity.CredentialsTypePassword) } + if params.IdsFilter != nil && len(params.IdsFilter) != 0 { + wheres += ` + AND identities.id in (?) + ` + args = append(args, params.IdsFilter) + } + query := fmt.Sprintf(` SELECT DISTINCT identities.* FROM identities AS identities From ade1a5a544307a873ecba7046bb9f97f2f3311a1 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Mon, 13 Nov 2023 21:16:14 +0000 Subject: [PATCH 187/282] autogen(openapi): regenerate swagger spec and internal client [skip ci] --- internal/client-go/api_identity.go | 16 ++++++++++++++++ internal/httpclient/api_identity.go | 16 ++++++++++++++++ spec/api.json | 11 +++++++++++ spec/swagger.json | 9 +++++++++ 4 files changed, 52 insertions(+) diff --git a/internal/client-go/api_identity.go b/internal/client-go/api_identity.go index ae406e98fae0..a88dba49aab8 100644 --- a/internal/client-go/api_identity.go +++ b/internal/client-go/api_identity.go @@ -2052,6 +2052,7 @@ type IdentityApiApiListIdentitiesRequest struct { pageSize *int64 pageToken *string consistency *string + idsFilter *[]string credentialsIdentifier *string previewCredentialsIdentifierSimilar *string } @@ -2076,6 +2077,10 @@ func (r IdentityApiApiListIdentitiesRequest) Consistency(consistency string) Ide r.consistency = &consistency return r } +func (r IdentityApiApiListIdentitiesRequest) IdsFilter(idsFilter []string) IdentityApiApiListIdentitiesRequest { + r.idsFilter = &idsFilter + return r +} func (r IdentityApiApiListIdentitiesRequest) CredentialsIdentifier(credentialsIdentifier string) IdentityApiApiListIdentitiesRequest { r.credentialsIdentifier = &credentialsIdentifier return r @@ -2142,6 +2147,17 @@ func (a *IdentityApiService) ListIdentitiesExecute(r IdentityApiApiListIdentitie if r.consistency != nil { localVarQueryParams.Add("consistency", parameterToString(*r.consistency, "")) } + if r.idsFilter != nil { + t := *r.idsFilter + if reflect.TypeOf(t).Kind() == reflect.Slice { + s := reflect.ValueOf(t) + for i := 0; i < s.Len(); i++ { + localVarQueryParams.Add("ids_filter", parameterToString(s.Index(i), "multi")) + } + } else { + localVarQueryParams.Add("ids_filter", parameterToString(t, "multi")) + } + } if r.credentialsIdentifier != nil { localVarQueryParams.Add("credentials_identifier", parameterToString(*r.credentialsIdentifier, "")) } diff --git a/internal/httpclient/api_identity.go b/internal/httpclient/api_identity.go index ae406e98fae0..a88dba49aab8 100644 --- a/internal/httpclient/api_identity.go +++ b/internal/httpclient/api_identity.go @@ -2052,6 +2052,7 @@ type IdentityApiApiListIdentitiesRequest struct { pageSize *int64 pageToken *string consistency *string + idsFilter *[]string credentialsIdentifier *string previewCredentialsIdentifierSimilar *string } @@ -2076,6 +2077,10 @@ func (r IdentityApiApiListIdentitiesRequest) Consistency(consistency string) Ide r.consistency = &consistency return r } +func (r IdentityApiApiListIdentitiesRequest) IdsFilter(idsFilter []string) IdentityApiApiListIdentitiesRequest { + r.idsFilter = &idsFilter + return r +} func (r IdentityApiApiListIdentitiesRequest) CredentialsIdentifier(credentialsIdentifier string) IdentityApiApiListIdentitiesRequest { r.credentialsIdentifier = &credentialsIdentifier return r @@ -2142,6 +2147,17 @@ func (a *IdentityApiService) ListIdentitiesExecute(r IdentityApiApiListIdentitie if r.consistency != nil { localVarQueryParams.Add("consistency", parameterToString(*r.consistency, "")) } + if r.idsFilter != nil { + t := *r.idsFilter + if reflect.TypeOf(t).Kind() == reflect.Slice { + s := reflect.ValueOf(t) + for i := 0; i < s.Len(); i++ { + localVarQueryParams.Add("ids_filter", parameterToString(s.Index(i), "multi")) + } + } else { + localVarQueryParams.Add("ids_filter", parameterToString(t, "multi")) + } + } if r.credentialsIdentifier != nil { localVarQueryParams.Add("credentials_identifier", parameterToString(*r.credentialsIdentifier, "")) } diff --git a/spec/api.json b/spec/api.json index e7f7e6360031..880122ea0585 100644 --- a/spec/api.json +++ b/spec/api.json @@ -3489,6 +3489,17 @@ }, "x-go-enum-desc": " ConsistencyLevelUnset ConsistencyLevelUnset is the unset / default consistency level.\nstrong ConsistencyLevelStrong ConsistencyLevelStrong is the strong consistency level.\neventual ConsistencyLevelEventual ConsistencyLevelEventual is the eventual consistency level using follower read timestamps." }, + { + "description": "IdsFilter is list of ids used to filter identities.\nIf this list is empty, then no filter will be applied.", + "in": "query", + "name": "ids_filter", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, { "description": "CredentialsIdentifier is the identifier (username, email) of the credentials to look up using exact match.\nOnly one of CredentialsIdentifier and CredentialsIdentifierSimilar can be used.", "in": "query", diff --git a/spec/swagger.json b/spec/swagger.json index a61ca10e51b4..698a8d55e797 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -232,6 +232,15 @@ "name": "consistency", "in": "query" }, + { + "type": "array", + "items": { + "type": "string" + }, + "description": "IdsFilter is list of ids used to filter identities.\nIf this list is empty, then no filter will be applied.", + "name": "ids_filter", + "in": "query" + }, { "type": "string", "description": "CredentialsIdentifier is the identifier (username, email) of the credentials to look up using exact match.\nOnly one of CredentialsIdentifier and CredentialsIdentifierSimilar can be used.", From 9396bb0b586d1d1e74a85c0ae3bcf9de81214f1b Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Tue, 14 Nov 2023 13:37:58 +0100 Subject: [PATCH 188/282] fix: additional_id_token_audiences key in config schema (#3622) --- embedx/config.schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embedx/config.schema.json b/embedx/config.schema.json index 70ac3a54c9d0..bcac9223263c 100644 --- a/embedx/config.schema.json +++ b/embedx/config.schema.json @@ -532,7 +532,7 @@ "type": "string", "examples": ["12345678-1234-1234-1234-123456789012"] }, - "allowed_id_token_audiences": { + "additional_id_token_audiences": { "title": "Additional client ids allowed when using ID token submission", "type": "array", "items": { From e81e892b00c1a988adc3831518125bb74046f4fb Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Tue, 14 Nov 2023 13:34:09 +0000 Subject: [PATCH 189/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b38cbdef2ee2..c85c509207b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-11-13)](#2023-11-13) +- [ (2023-11-14)](#2023-11-14) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -314,7 +314,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-11-13) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-11-14) ## Breaking Changes @@ -386,6 +386,9 @@ https://github.com/ory/kratos/pull/3480 - chore: generate sdk +- Additional_id_token_audiences key in config schema + ([#3622](https://github.com/ory/kratos/issues/3622)) + ([9396bb0](https://github.com/ory/kratos/commit/9396bb0b586d1d1e74a85c0ae3bcf9de81214f1b)) - Adjust tracing verbosity ([976cd0d](https://github.com/ory/kratos/commit/976cd0dc3dd95c2c1992bfa82394e9fad39f34f2)) - Allow post recovery hooks to interrupt the flow @@ -788,6 +791,17 @@ https://github.com/ory/kratos/pull/3480 This feature allows marking emails provided by social sign in providers as verified. +- Batch list identities ([#3598](https://github.com/ory/kratos/issues/3598)) + ([8ad54f1](https://github.com/ory/kratos/commit/8ad54f1be53b30fdb24b616be0c52fd66829f201)), + closes [#2448](https://github.com/ory/kratos/issues/2448): + + This change allows to filter `GET /admin/identities` by ID with the following + syntax: + + ``` + /admin/identities?ids=id1&ids=id2&ids=id3 + ``` + - Emit error details when we find stray cookies in an API flow ([#3496](https://github.com/ory/kratos/issues/3496)) ([df74339](https://github.com/ory/kratos/commit/df74339802d98a292abb32806eca35fb2554960b)) From e363889732c0a1cb801fd12b2e0e8546006e9714 Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Wed, 15 Nov 2023 11:11:42 +0100 Subject: [PATCH 190/282] feat: add support for recovery on native flows (#3273) --------- Co-authored-by: Henning Perl Co-authored-by: Alano Terblanche <18033717+Benehiko@users.noreply.github.com> Co-authored-by: aeneasr <3372410+aeneasr@users.noreply.github.com> --- .github/workflows/ci.yaml | 8 + .github/workflows/format.yml | 2 +- .schema/openapi/patches/schema.yaml | 4 + .../kratos/email-password/kratos.yml | 2 + driver/config/config.go | 9 +- driver/registry_default_recovery.go | 2 +- embedx/config.schema.json | 6 + internal/client-go/.openapi-generator/FILES | 8 + internal/client-go/README.md | 6 +- internal/client-go/api_frontend.go | 12 +- internal/client-go/model_continue_with.go | 60 + .../model_continue_with_recovery_ui.go | 137 ++ .../model_continue_with_recovery_ui_flow.go | 145 ++ .../model_continue_with_settings_ui.go | 137 ++ .../model_continue_with_settings_ui_flow.go | 108 ++ .../model_recovery_code_for_identity.go | 2 +- internal/client-go/model_recovery_flow.go | 37 + internal/httpclient/.openapi-generator/FILES | 8 + internal/httpclient/README.md | 6 +- internal/httpclient/api_frontend.go | 12 +- internal/httpclient/model_continue_with.go | 60 + .../model_continue_with_recovery_ui.go | 137 ++ .../model_continue_with_recovery_ui_flow.go | 145 ++ .../model_continue_with_settings_ui.go | 137 ++ .../model_continue_with_settings_ui_flow.go | 108 ++ .../model_recovery_code_for_identity.go | 2 +- internal/httpclient/model_recovery_flow.go | 37 + .../testhelpers/selfservice_verification.go | 37 +- selfservice/flow/continue_with.go | 97 ++ selfservice/flow/error.go | 9 + ...=fails_if_active_strategy_is_disabled.json | 4 +- ..._if_recovery_strategy_id_is_not_valid.json | 2 +- ...=fails_if_active_strategy_is_disabled.json | 4 +- ...=fails_if_active_strategy_is_disabled.json | 73 + ..._if_recovery_strategy_id_is_not_valid.json | 6 + ...=fails_if_active_strategy_is_disabled.json | 73 + selfservice/flow/recovery/error.go | 49 +- selfservice/flow/recovery/error_test.go | 270 +++- selfservice/flow/recovery/flow.go | 5 +- selfservice/flow/recovery/flow_test.go | 45 +- selfservice/flow/recovery/handler.go | 20 +- ...he_correct_recovery_payloads-type=api.json | 53 + ...orrect_recovery_payloads-type=browser.json | 53 + ...he_correct_recovery_payloads-type=spa.json | 53 + ...ry_payloads_after_submission-type=api.json | 86 ++ ...ayloads_after_submission-type=browser.json | 86 ++ ...ry_payloads_after_submission-type=spa.json | 86 ++ selfservice/strategy/code/strategy.go | 1 + .../strategy/code/strategy_recovery.go | 331 ++--- .../strategy/code/strategy_recovery_admin.go | 216 +++ .../code/strategy_recovery_admin_test.go | 204 +++ .../strategy/code/strategy_recovery_test.go | 1282 +++++++++++++---- .../code/strategy_verification_test.go | 8 +- spec/api.json | 95 +- spec/swagger.json | 87 +- .../profiles/code/login/error.spec.ts | 15 +- .../profiles/mobile/mfa/totp.spec.ts | 2 +- test/e2e/cypress/support/config.d.ts | 159 +- test/e2e/package-lock.json | 156 +- test/e2e/package.json | 8 +- test/e2e/playwright.config.ts | 13 +- test/e2e/playwright/actions/mail.ts | 24 + test/e2e/playwright/fixtures/index.ts | 64 + test/e2e/playwright/kratos.base-config.json | 2 +- test/e2e/playwright/lib/helper.ts | 20 + test/e2e/playwright/setup/default_config.ts | 3 +- .../e2e/playwright/tests/app_recovery.spec.ts | 140 ++ test/e2e/render-kratos-config.sh | 8 +- 68 files changed, 4614 insertions(+), 672 deletions(-) create mode 100644 internal/client-go/model_continue_with_recovery_ui.go create mode 100644 internal/client-go/model_continue_with_recovery_ui_flow.go create mode 100644 internal/client-go/model_continue_with_settings_ui.go create mode 100644 internal/client-go/model_continue_with_settings_ui_flow.go create mode 100644 internal/httpclient/model_continue_with_recovery_ui.go create mode 100644 internal/httpclient/model_continue_with_recovery_ui_flow.go create mode 100644 internal/httpclient/model_continue_with_settings_ui.go create mode 100644 internal/httpclient/model_continue_with_settings_ui_flow.go create mode 100644 selfservice/flow/recovery/.snapshots/TestHandleError_WithContinueWith-flow=api-case=fails_if_active_strategy_is_disabled.json create mode 100644 selfservice/flow/recovery/.snapshots/TestHandleError_WithContinueWith-flow=browser-case=fails_to_retry_flow_if_recovery_strategy_id_is_not_valid.json create mode 100644 selfservice/flow/recovery/.snapshots/TestHandleError_WithContinueWith-flow=spa-case=fails_if_active_strategy_is_disabled.json create mode 100644 selfservice/strategy/code/.snapshots/TestRecovery_WithContinueWith-description=should_set_all_the_correct_recovery_payloads-type=api.json create mode 100644 selfservice/strategy/code/.snapshots/TestRecovery_WithContinueWith-description=should_set_all_the_correct_recovery_payloads-type=browser.json create mode 100644 selfservice/strategy/code/.snapshots/TestRecovery_WithContinueWith-description=should_set_all_the_correct_recovery_payloads-type=spa.json create mode 100644 selfservice/strategy/code/.snapshots/TestRecovery_WithContinueWith-description=should_set_all_the_correct_recovery_payloads_after_submission-type=api.json create mode 100644 selfservice/strategy/code/.snapshots/TestRecovery_WithContinueWith-description=should_set_all_the_correct_recovery_payloads_after_submission-type=browser.json create mode 100644 selfservice/strategy/code/.snapshots/TestRecovery_WithContinueWith-description=should_set_all_the_correct_recovery_payloads_after_submission-type=spa.json create mode 100644 selfservice/strategy/code/strategy_recovery_admin.go create mode 100644 selfservice/strategy/code/strategy_recovery_admin_test.go create mode 100644 test/e2e/playwright/actions/mail.ts create mode 100644 test/e2e/playwright/fixtures/index.ts create mode 100644 test/e2e/playwright/lib/helper.ts create mode 100644 test/e2e/playwright/tests/app_recovery.spec.ts diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index a99b8f5b2e80..43129b0991ce 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -246,6 +246,7 @@ jobs: TEST_DATABASE_MYSQL: "mysql://root:test@(localhost:3306)/mysql?parseTime=true&multiStatements=true" TEST_DATABASE_COCKROACHDB: "cockroach://root@localhost:26257/defaultdb?sslmode=disable" strategy: + fail-fast: false matrix: database: ["postgres", "cockroach", "sqlite", "mysql"] steps: @@ -323,6 +324,13 @@ jobs: with: name: logs path: test/e2e/*.e2e.log + - if: failure() + uses: actions/upload-artifact@v2 + with: + name: playwright-test-results-${{ github.sha }} + path: | + test/e2e/test-results/ + test/e2e/playwright-report/ docs-cli: runs-on: ubuntu-latest diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index b59c85d31b22..ce6695943cd8 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -2,7 +2,7 @@ name: Format on: pull_request: - push: + merge_group: jobs: format: diff --git a/.schema/openapi/patches/schema.yaml b/.schema/openapi/patches/schema.yaml index bae28a0872db..206aceb2708e 100644 --- a/.schema/openapi/patches/schema.yaml +++ b/.schema/openapi/patches/schema.yaml @@ -41,9 +41,13 @@ mapping: show_verification_ui: "#/components/schemas/continueWithVerificationUi" set_ory_session_token: "#/components/schemas/continueWithSetOrySessionToken" + show_settings_ui: "#/components/schemas/continueWithSettingsUi" + show_recovery_ui: "#/components/schemas/continueWithRecoveryUi" - op: add path: /components/schemas/continueWith/oneOf value: - "$ref": "#/components/schemas/continueWithVerificationUi" - "$ref": "#/components/schemas/continueWithSetOrySessionToken" + - "$ref": "#/components/schemas/continueWithSettingsUi" + - "$ref": "#/components/schemas/continueWithRecoveryUi" diff --git a/contrib/quickstart/kratos/email-password/kratos.yml b/contrib/quickstart/kratos/email-password/kratos.yml index 4ff9fb805917..935727cc2bad 100644 --- a/contrib/quickstart/kratos/email-password/kratos.yml +++ b/contrib/quickstart/kratos/email-password/kratos.yml @@ -14,6 +14,8 @@ selfservice: default_browser_return_url: http://127.0.0.1:4455/ allowed_return_urls: - http://127.0.0.1:4455 + - http://localhost:19006/Callback + - exp://localhost:8081/--/Callback methods: password: diff --git a/driver/config/config.go b/driver/config/config.go index edec657e10ae..a5ff6c7fb3b8 100644 --- a/driver/config/config.go +++ b/driver/config/config.go @@ -113,6 +113,7 @@ const ( ViperKeySessionTokenizerTemplates = "session.whoami.tokenizer.templates" ViperKeySessionWhoAmIAAL = "session.whoami.required_aal" ViperKeySessionWhoAmICaching = "feature_flags.cacheable_sessions" + ViperKeyUseContinueWithTransitions = "feature_flags.use_continue_with_transitions" ViperKeySessionRefreshMinTimeLeft = "session.earliest_possible_extend" ViperKeyCookieSameSite = "cookies.same_site" ViperKeyCookieDomain = "cookies.domain" @@ -594,7 +595,7 @@ func (p *Config) PublicSocketPermission(ctx context.Context) *configx.UnixPermis return &configx.UnixPermission{ Owner: pp.String(ViperKeyPublicSocketOwner), Group: pp.String(ViperKeyPublicSocketGroup), - Mode: os.FileMode(pp.IntF(ViperKeyPublicSocketMode, 0755)), + Mode: os.FileMode(pp.IntF(ViperKeyPublicSocketMode, 0o755)), } } @@ -603,7 +604,7 @@ func (p *Config) AdminSocketPermission(ctx context.Context) *configx.UnixPermiss return &configx.UnixPermission{ Owner: pp.String(ViperKeyAdminSocketOwner), Group: pp.String(ViperKeyAdminSocketGroup), - Mode: os.FileMode(pp.IntF(ViperKeyAdminSocketMode, 0755)), + Mode: os.FileMode(pp.IntF(ViperKeyAdminSocketMode, 0o755)), } } @@ -1309,6 +1310,10 @@ func (p *Config) SessionWhoAmICaching(ctx context.Context) bool { return p.GetProvider(ctx).Bool(ViperKeySessionWhoAmICaching) } +func (p *Config) UseContinueWithTransitions(ctx context.Context) bool { + return p.GetProvider(ctx).Bool(ViperKeyUseContinueWithTransitions) +} + func (p *Config) SessionRefreshMinTimeLeft(ctx context.Context) time.Duration { return p.GetProvider(ctx).DurationF(ViperKeySessionRefreshMinTimeLeft, p.SessionLifespan(ctx)) } diff --git a/driver/registry_default_recovery.go b/driver/registry_default_recovery.go index b16b0b99a412..04cf24857eba 100644 --- a/driver/registry_default_recovery.go +++ b/driver/registry_default_recovery.go @@ -48,7 +48,7 @@ func (m *RegistryDefault) GetActiveRecoveryStrategy(ctx context.Context) (recove s, err := m.RecoveryStrategies(ctx).Strategy(as) if err != nil { return nil, errors.WithStack(herodot.ErrBadRequest. - WithReasonf("The active recovery strategy %s is not enabled. Please enable it in the configuration.", as)) + WithReasonf("You attempted recovery using %s, which is not enabled or does not exist. An administrator needs to enable this recovery method.", as)) } return s, nil } diff --git a/embedx/config.schema.json b/embedx/config.schema.json index bcac9223263c..b8d767ef179a 100644 --- a/embedx/config.schema.json +++ b/embedx/config.schema.json @@ -2647,6 +2647,12 @@ "title": "Enable Ory Sessions caching", "description": "If enabled allows Ory Sessions to be cached. Only effective in the Ory Network.", "default": false + }, + "use_continue_with_transitions": { + "type": "boolean", + "title": "Enable new flow transitions using `continue_with` items", + "description": "If enabled allows new flow transitions using `continue_with` items.", + "default": false } }, "additionalProperties": false diff --git a/internal/client-go/.openapi-generator/FILES b/internal/client-go/.openapi-generator/FILES index 24a832963dac..f2d48ddec66c 100644 --- a/internal/client-go/.openapi-generator/FILES +++ b/internal/client-go/.openapi-generator/FILES @@ -13,7 +13,11 @@ docs/AuthenticatorAssuranceLevel.md docs/BatchPatchIdentitiesResponse.md docs/ConsistencyRequestParameters.md docs/ContinueWith.md +docs/ContinueWithRecoveryUi.md +docs/ContinueWithRecoveryUiFlow.md docs/ContinueWithSetOrySessionToken.md +docs/ContinueWithSettingsUi.md +docs/ContinueWithSettingsUiFlow.md docs/ContinueWithVerificationUi.md docs/ContinueWithVerificationUiFlow.md docs/CourierApi.md @@ -131,7 +135,11 @@ model_authenticator_assurance_level.go model_batch_patch_identities_response.go model_consistency_request_parameters.go model_continue_with.go +model_continue_with_recovery_ui.go +model_continue_with_recovery_ui_flow.go model_continue_with_set_ory_session_token.go +model_continue_with_settings_ui.go +model_continue_with_settings_ui_flow.go model_continue_with_verification_ui.go model_continue_with_verification_ui_flow.go model_courier_message_status.go diff --git a/internal/client-go/README.md b/internal/client-go/README.md index 171764a11a5b..7fedaba9d3e5 100644 --- a/internal/client-go/README.md +++ b/internal/client-go/README.md @@ -107,7 +107,7 @@ Class | Method | HTTP request | Description *FrontendApi* | [**ToSession**](docs/FrontendApi.md#tosession) | **Get** /sessions/whoami | Check Who the Current HTTP Session Belongs To *FrontendApi* | [**UpdateLoginFlow**](docs/FrontendApi.md#updateloginflow) | **Post** /self-service/login | Submit a Login Flow *FrontendApi* | [**UpdateLogoutFlow**](docs/FrontendApi.md#updatelogoutflow) | **Get** /self-service/logout | Update Logout Flow -*FrontendApi* | [**UpdateRecoveryFlow**](docs/FrontendApi.md#updaterecoveryflow) | **Post** /self-service/recovery | Complete Recovery Flow +*FrontendApi* | [**UpdateRecoveryFlow**](docs/FrontendApi.md#updaterecoveryflow) | **Post** /self-service/recovery | Update Recovery Flow *FrontendApi* | [**UpdateRegistrationFlow**](docs/FrontendApi.md#updateregistrationflow) | **Post** /self-service/registration | Update Registration Flow *FrontendApi* | [**UpdateSettingsFlow**](docs/FrontendApi.md#updatesettingsflow) | **Post** /self-service/settings | Complete Settings Flow *FrontendApi* | [**UpdateVerificationFlow**](docs/FrontendApi.md#updateverificationflow) | **Post** /self-service/verification | Complete Verification Flow @@ -140,7 +140,11 @@ Class | Method | HTTP request | Description - [BatchPatchIdentitiesResponse](docs/BatchPatchIdentitiesResponse.md) - [ConsistencyRequestParameters](docs/ConsistencyRequestParameters.md) - [ContinueWith](docs/ContinueWith.md) + - [ContinueWithRecoveryUi](docs/ContinueWithRecoveryUi.md) + - [ContinueWithRecoveryUiFlow](docs/ContinueWithRecoveryUiFlow.md) - [ContinueWithSetOrySessionToken](docs/ContinueWithSetOrySessionToken.md) + - [ContinueWithSettingsUi](docs/ContinueWithSettingsUi.md) + - [ContinueWithSettingsUiFlow](docs/ContinueWithSettingsUiFlow.md) - [ContinueWithVerificationUi](docs/ContinueWithVerificationUi.md) - [ContinueWithVerificationUiFlow](docs/ContinueWithVerificationUiFlow.md) - [CourierMessageStatus](docs/CourierMessageStatus.md) diff --git a/internal/client-go/api_frontend.go b/internal/client-go/api_frontend.go index 0260af5a71b6..ab8c45632935 100644 --- a/internal/client-go/api_frontend.go +++ b/internal/client-go/api_frontend.go @@ -240,7 +240,7 @@ type FrontendApi interface { If a valid provided session cookie or session token is provided, a 400 Bad Request error. - To fetch an existing recovery flow call `/self-service/recovery/flows?flow=`. + On an existing recovery flow, use the `getRecoveryFlow` API endpoint. You MUST NOT use this endpoint in client-side (Single Page Apps, ReactJS, AngularJS) nor server-side (Java Server Pages, NodeJS, PHP, Golang, ...) browser applications. Using this endpoint in these applications will make @@ -775,8 +775,8 @@ type FrontendApi interface { UpdateLogoutFlowExecute(r FrontendApiApiUpdateLogoutFlowRequest) (*http.Response, error) /* - * UpdateRecoveryFlow Complete Recovery Flow - * Use this endpoint to complete a recovery flow. This endpoint + * UpdateRecoveryFlow Update Recovery Flow + * Use this endpoint to update a recovery flow. This endpoint behaves differently for API and browser flows and has several states: `choose_method` expects `flow` (in the URL query) and `email` (in the body) to be sent @@ -2075,7 +2075,7 @@ func (r FrontendApiApiCreateNativeRecoveryFlowRequest) Execute() (*RecoveryFlow, If a valid provided session cookie or session token is provided, a 400 Bad Request error. -To fetch an existing recovery flow call `/self-service/recovery/flows?flow=`. +On an existing recovery flow, use the `getRecoveryFlow` API endpoint. You MUST NOT use this endpoint in client-side (Single Page Apps, ReactJS, AngularJS) nor server-side (Java Server Pages, NodeJS, PHP, Golang, ...) browser applications. Using this endpoint in these applications will make @@ -5076,8 +5076,8 @@ func (r FrontendApiApiUpdateRecoveryFlowRequest) Execute() (*RecoveryFlow, *http } /* - - UpdateRecoveryFlow Complete Recovery Flow - - Use this endpoint to complete a recovery flow. This endpoint + - UpdateRecoveryFlow Update Recovery Flow + - Use this endpoint to update a recovery flow. This endpoint behaves differently for API and browser flows and has several states: diff --git a/internal/client-go/model_continue_with.go b/internal/client-go/model_continue_with.go index 2cd5dd77542c..ee84e74692fb 100644 --- a/internal/client-go/model_continue_with.go +++ b/internal/client-go/model_continue_with.go @@ -18,10 +18,19 @@ import ( // ContinueWith - struct for ContinueWith type ContinueWith struct { + ContinueWithRecoveryUi *ContinueWithRecoveryUi ContinueWithSetOrySessionToken *ContinueWithSetOrySessionToken + ContinueWithSettingsUi *ContinueWithSettingsUi ContinueWithVerificationUi *ContinueWithVerificationUi } +// ContinueWithRecoveryUiAsContinueWith is a convenience function that returns ContinueWithRecoveryUi wrapped in ContinueWith +func ContinueWithRecoveryUiAsContinueWith(v *ContinueWithRecoveryUi) ContinueWith { + return ContinueWith{ + ContinueWithRecoveryUi: v, + } +} + // ContinueWithSetOrySessionTokenAsContinueWith is a convenience function that returns ContinueWithSetOrySessionToken wrapped in ContinueWith func ContinueWithSetOrySessionTokenAsContinueWith(v *ContinueWithSetOrySessionToken) ContinueWith { return ContinueWith{ @@ -29,6 +38,13 @@ func ContinueWithSetOrySessionTokenAsContinueWith(v *ContinueWithSetOrySessionTo } } +// ContinueWithSettingsUiAsContinueWith is a convenience function that returns ContinueWithSettingsUi wrapped in ContinueWith +func ContinueWithSettingsUiAsContinueWith(v *ContinueWithSettingsUi) ContinueWith { + return ContinueWith{ + ContinueWithSettingsUi: v, + } +} + // ContinueWithVerificationUiAsContinueWith is a convenience function that returns ContinueWithVerificationUi wrapped in ContinueWith func ContinueWithVerificationUiAsContinueWith(v *ContinueWithVerificationUi) ContinueWith { return ContinueWith{ @@ -40,6 +56,19 @@ func ContinueWithVerificationUiAsContinueWith(v *ContinueWithVerificationUi) Con func (dst *ContinueWith) UnmarshalJSON(data []byte) error { var err error match := 0 + // try to unmarshal data into ContinueWithRecoveryUi + err = newStrictDecoder(data).Decode(&dst.ContinueWithRecoveryUi) + if err == nil { + jsonContinueWithRecoveryUi, _ := json.Marshal(dst.ContinueWithRecoveryUi) + if string(jsonContinueWithRecoveryUi) == "{}" { // empty struct + dst.ContinueWithRecoveryUi = nil + } else { + match++ + } + } else { + dst.ContinueWithRecoveryUi = nil + } + // try to unmarshal data into ContinueWithSetOrySessionToken err = newStrictDecoder(data).Decode(&dst.ContinueWithSetOrySessionToken) if err == nil { @@ -53,6 +82,19 @@ func (dst *ContinueWith) UnmarshalJSON(data []byte) error { dst.ContinueWithSetOrySessionToken = nil } + // try to unmarshal data into ContinueWithSettingsUi + err = newStrictDecoder(data).Decode(&dst.ContinueWithSettingsUi) + if err == nil { + jsonContinueWithSettingsUi, _ := json.Marshal(dst.ContinueWithSettingsUi) + if string(jsonContinueWithSettingsUi) == "{}" { // empty struct + dst.ContinueWithSettingsUi = nil + } else { + match++ + } + } else { + dst.ContinueWithSettingsUi = nil + } + // try to unmarshal data into ContinueWithVerificationUi err = newStrictDecoder(data).Decode(&dst.ContinueWithVerificationUi) if err == nil { @@ -68,7 +110,9 @@ func (dst *ContinueWith) UnmarshalJSON(data []byte) error { if match > 1 { // more than 1 match // reset to nil + dst.ContinueWithRecoveryUi = nil dst.ContinueWithSetOrySessionToken = nil + dst.ContinueWithSettingsUi = nil dst.ContinueWithVerificationUi = nil return fmt.Errorf("Data matches more than one schema in oneOf(ContinueWith)") @@ -81,10 +125,18 @@ func (dst *ContinueWith) UnmarshalJSON(data []byte) error { // Marshal data from the first non-nil pointers in the struct to JSON func (src ContinueWith) MarshalJSON() ([]byte, error) { + if src.ContinueWithRecoveryUi != nil { + return json.Marshal(&src.ContinueWithRecoveryUi) + } + if src.ContinueWithSetOrySessionToken != nil { return json.Marshal(&src.ContinueWithSetOrySessionToken) } + if src.ContinueWithSettingsUi != nil { + return json.Marshal(&src.ContinueWithSettingsUi) + } + if src.ContinueWithVerificationUi != nil { return json.Marshal(&src.ContinueWithVerificationUi) } @@ -97,10 +149,18 @@ func (obj *ContinueWith) GetActualInstance() interface{} { if obj == nil { return nil } + if obj.ContinueWithRecoveryUi != nil { + return obj.ContinueWithRecoveryUi + } + if obj.ContinueWithSetOrySessionToken != nil { return obj.ContinueWithSetOrySessionToken } + if obj.ContinueWithSettingsUi != nil { + return obj.ContinueWithSettingsUi + } + if obj.ContinueWithVerificationUi != nil { return obj.ContinueWithVerificationUi } diff --git a/internal/client-go/model_continue_with_recovery_ui.go b/internal/client-go/model_continue_with_recovery_ui.go new file mode 100644 index 000000000000..93682bf90beb --- /dev/null +++ b/internal/client-go/model_continue_with_recovery_ui.go @@ -0,0 +1,137 @@ +/* + * Ory Identities API + * + * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. + * + * API version: + * Contact: office@ory.sh + */ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +import ( + "encoding/json" +) + +// ContinueWithRecoveryUi Indicates, that the UI flow could be continued by showing a recovery ui +type ContinueWithRecoveryUi struct { + // Action will always be `show_recovery_ui` show_recovery_ui ContinueWithActionShowRecoveryUIString + Action string `json:"action"` + Flow ContinueWithRecoveryUiFlow `json:"flow"` +} + +// NewContinueWithRecoveryUi instantiates a new ContinueWithRecoveryUi 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 NewContinueWithRecoveryUi(action string, flow ContinueWithRecoveryUiFlow) *ContinueWithRecoveryUi { + this := ContinueWithRecoveryUi{} + this.Action = action + this.Flow = flow + return &this +} + +// NewContinueWithRecoveryUiWithDefaults instantiates a new ContinueWithRecoveryUi 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 NewContinueWithRecoveryUiWithDefaults() *ContinueWithRecoveryUi { + this := ContinueWithRecoveryUi{} + return &this +} + +// GetAction returns the Action field value +func (o *ContinueWithRecoveryUi) GetAction() string { + if o == nil { + var ret string + return ret + } + + return o.Action +} + +// GetActionOk returns a tuple with the Action field value +// and a boolean to check if the value has been set. +func (o *ContinueWithRecoveryUi) GetActionOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Action, true +} + +// SetAction sets field value +func (o *ContinueWithRecoveryUi) SetAction(v string) { + o.Action = v +} + +// GetFlow returns the Flow field value +func (o *ContinueWithRecoveryUi) GetFlow() ContinueWithRecoveryUiFlow { + if o == nil { + var ret ContinueWithRecoveryUiFlow + return ret + } + + return o.Flow +} + +// GetFlowOk returns a tuple with the Flow field value +// and a boolean to check if the value has been set. +func (o *ContinueWithRecoveryUi) GetFlowOk() (*ContinueWithRecoveryUiFlow, bool) { + if o == nil { + return nil, false + } + return &o.Flow, true +} + +// SetFlow sets field value +func (o *ContinueWithRecoveryUi) SetFlow(v ContinueWithRecoveryUiFlow) { + o.Flow = v +} + +func (o ContinueWithRecoveryUi) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if true { + toSerialize["action"] = o.Action + } + if true { + toSerialize["flow"] = o.Flow + } + return json.Marshal(toSerialize) +} + +type NullableContinueWithRecoveryUi struct { + value *ContinueWithRecoveryUi + isSet bool +} + +func (v NullableContinueWithRecoveryUi) Get() *ContinueWithRecoveryUi { + return v.value +} + +func (v *NullableContinueWithRecoveryUi) Set(val *ContinueWithRecoveryUi) { + v.value = val + v.isSet = true +} + +func (v NullableContinueWithRecoveryUi) IsSet() bool { + return v.isSet +} + +func (v *NullableContinueWithRecoveryUi) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableContinueWithRecoveryUi(val *ContinueWithRecoveryUi) *NullableContinueWithRecoveryUi { + return &NullableContinueWithRecoveryUi{value: val, isSet: true} +} + +func (v NullableContinueWithRecoveryUi) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableContinueWithRecoveryUi) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/client-go/model_continue_with_recovery_ui_flow.go b/internal/client-go/model_continue_with_recovery_ui_flow.go new file mode 100644 index 000000000000..3fde7e717ef2 --- /dev/null +++ b/internal/client-go/model_continue_with_recovery_ui_flow.go @@ -0,0 +1,145 @@ +/* + * Ory Identities API + * + * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. + * + * API version: + * Contact: office@ory.sh + */ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +import ( + "encoding/json" +) + +// ContinueWithRecoveryUiFlow struct for ContinueWithRecoveryUiFlow +type ContinueWithRecoveryUiFlow struct { + // The ID of the recovery flow + Id string `json:"id"` + // The URL of the recovery flow + Url *string `json:"url,omitempty"` +} + +// NewContinueWithRecoveryUiFlow instantiates a new ContinueWithRecoveryUiFlow 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 NewContinueWithRecoveryUiFlow(id string) *ContinueWithRecoveryUiFlow { + this := ContinueWithRecoveryUiFlow{} + this.Id = id + return &this +} + +// NewContinueWithRecoveryUiFlowWithDefaults instantiates a new ContinueWithRecoveryUiFlow 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 NewContinueWithRecoveryUiFlowWithDefaults() *ContinueWithRecoveryUiFlow { + this := ContinueWithRecoveryUiFlow{} + return &this +} + +// GetId returns the Id field value +func (o *ContinueWithRecoveryUiFlow) GetId() string { + if o == nil { + var ret string + return ret + } + + return o.Id +} + +// GetIdOk returns a tuple with the Id field value +// and a boolean to check if the value has been set. +func (o *ContinueWithRecoveryUiFlow) GetIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Id, true +} + +// SetId sets field value +func (o *ContinueWithRecoveryUiFlow) SetId(v string) { + o.Id = v +} + +// GetUrl returns the Url field value if set, zero value otherwise. +func (o *ContinueWithRecoveryUiFlow) GetUrl() string { + if o == nil || o.Url == nil { + var ret string + return ret + } + return *o.Url +} + +// GetUrlOk returns a tuple with the Url field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ContinueWithRecoveryUiFlow) GetUrlOk() (*string, bool) { + if o == nil || o.Url == nil { + return nil, false + } + return o.Url, true +} + +// HasUrl returns a boolean if a field has been set. +func (o *ContinueWithRecoveryUiFlow) HasUrl() bool { + if o != nil && o.Url != nil { + return true + } + + return false +} + +// SetUrl gets a reference to the given string and assigns it to the Url field. +func (o *ContinueWithRecoveryUiFlow) SetUrl(v string) { + o.Url = &v +} + +func (o ContinueWithRecoveryUiFlow) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if true { + toSerialize["id"] = o.Id + } + if o.Url != nil { + toSerialize["url"] = o.Url + } + return json.Marshal(toSerialize) +} + +type NullableContinueWithRecoveryUiFlow struct { + value *ContinueWithRecoveryUiFlow + isSet bool +} + +func (v NullableContinueWithRecoveryUiFlow) Get() *ContinueWithRecoveryUiFlow { + return v.value +} + +func (v *NullableContinueWithRecoveryUiFlow) Set(val *ContinueWithRecoveryUiFlow) { + v.value = val + v.isSet = true +} + +func (v NullableContinueWithRecoveryUiFlow) IsSet() bool { + return v.isSet +} + +func (v *NullableContinueWithRecoveryUiFlow) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableContinueWithRecoveryUiFlow(val *ContinueWithRecoveryUiFlow) *NullableContinueWithRecoveryUiFlow { + return &NullableContinueWithRecoveryUiFlow{value: val, isSet: true} +} + +func (v NullableContinueWithRecoveryUiFlow) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableContinueWithRecoveryUiFlow) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/client-go/model_continue_with_settings_ui.go b/internal/client-go/model_continue_with_settings_ui.go new file mode 100644 index 000000000000..eb843d966c16 --- /dev/null +++ b/internal/client-go/model_continue_with_settings_ui.go @@ -0,0 +1,137 @@ +/* + * Ory Identities API + * + * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. + * + * API version: + * Contact: office@ory.sh + */ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +import ( + "encoding/json" +) + +// ContinueWithSettingsUi Indicates, that the UI flow could be continued by showing a settings ui +type ContinueWithSettingsUi struct { + // Action will always be `show_settings_ui` show_settings_ui ContinueWithActionShowSettingsUIString + Action string `json:"action"` + Flow ContinueWithSettingsUiFlow `json:"flow"` +} + +// NewContinueWithSettingsUi instantiates a new ContinueWithSettingsUi 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 NewContinueWithSettingsUi(action string, flow ContinueWithSettingsUiFlow) *ContinueWithSettingsUi { + this := ContinueWithSettingsUi{} + this.Action = action + this.Flow = flow + return &this +} + +// NewContinueWithSettingsUiWithDefaults instantiates a new ContinueWithSettingsUi 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 NewContinueWithSettingsUiWithDefaults() *ContinueWithSettingsUi { + this := ContinueWithSettingsUi{} + return &this +} + +// GetAction returns the Action field value +func (o *ContinueWithSettingsUi) GetAction() string { + if o == nil { + var ret string + return ret + } + + return o.Action +} + +// GetActionOk returns a tuple with the Action field value +// and a boolean to check if the value has been set. +func (o *ContinueWithSettingsUi) GetActionOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Action, true +} + +// SetAction sets field value +func (o *ContinueWithSettingsUi) SetAction(v string) { + o.Action = v +} + +// GetFlow returns the Flow field value +func (o *ContinueWithSettingsUi) GetFlow() ContinueWithSettingsUiFlow { + if o == nil { + var ret ContinueWithSettingsUiFlow + return ret + } + + return o.Flow +} + +// GetFlowOk returns a tuple with the Flow field value +// and a boolean to check if the value has been set. +func (o *ContinueWithSettingsUi) GetFlowOk() (*ContinueWithSettingsUiFlow, bool) { + if o == nil { + return nil, false + } + return &o.Flow, true +} + +// SetFlow sets field value +func (o *ContinueWithSettingsUi) SetFlow(v ContinueWithSettingsUiFlow) { + o.Flow = v +} + +func (o ContinueWithSettingsUi) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if true { + toSerialize["action"] = o.Action + } + if true { + toSerialize["flow"] = o.Flow + } + return json.Marshal(toSerialize) +} + +type NullableContinueWithSettingsUi struct { + value *ContinueWithSettingsUi + isSet bool +} + +func (v NullableContinueWithSettingsUi) Get() *ContinueWithSettingsUi { + return v.value +} + +func (v *NullableContinueWithSettingsUi) Set(val *ContinueWithSettingsUi) { + v.value = val + v.isSet = true +} + +func (v NullableContinueWithSettingsUi) IsSet() bool { + return v.isSet +} + +func (v *NullableContinueWithSettingsUi) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableContinueWithSettingsUi(val *ContinueWithSettingsUi) *NullableContinueWithSettingsUi { + return &NullableContinueWithSettingsUi{value: val, isSet: true} +} + +func (v NullableContinueWithSettingsUi) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableContinueWithSettingsUi) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/client-go/model_continue_with_settings_ui_flow.go b/internal/client-go/model_continue_with_settings_ui_flow.go new file mode 100644 index 000000000000..4ccaf74ef1b8 --- /dev/null +++ b/internal/client-go/model_continue_with_settings_ui_flow.go @@ -0,0 +1,108 @@ +/* + * Ory Identities API + * + * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. + * + * API version: + * Contact: office@ory.sh + */ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +import ( + "encoding/json" +) + +// ContinueWithSettingsUiFlow struct for ContinueWithSettingsUiFlow +type ContinueWithSettingsUiFlow struct { + // The ID of the settings flow + Id string `json:"id"` +} + +// NewContinueWithSettingsUiFlow instantiates a new ContinueWithSettingsUiFlow 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 NewContinueWithSettingsUiFlow(id string) *ContinueWithSettingsUiFlow { + this := ContinueWithSettingsUiFlow{} + this.Id = id + return &this +} + +// NewContinueWithSettingsUiFlowWithDefaults instantiates a new ContinueWithSettingsUiFlow 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 NewContinueWithSettingsUiFlowWithDefaults() *ContinueWithSettingsUiFlow { + this := ContinueWithSettingsUiFlow{} + return &this +} + +// GetId returns the Id field value +func (o *ContinueWithSettingsUiFlow) GetId() string { + if o == nil { + var ret string + return ret + } + + return o.Id +} + +// GetIdOk returns a tuple with the Id field value +// and a boolean to check if the value has been set. +func (o *ContinueWithSettingsUiFlow) GetIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Id, true +} + +// SetId sets field value +func (o *ContinueWithSettingsUiFlow) SetId(v string) { + o.Id = v +} + +func (o ContinueWithSettingsUiFlow) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if true { + toSerialize["id"] = o.Id + } + return json.Marshal(toSerialize) +} + +type NullableContinueWithSettingsUiFlow struct { + value *ContinueWithSettingsUiFlow + isSet bool +} + +func (v NullableContinueWithSettingsUiFlow) Get() *ContinueWithSettingsUiFlow { + return v.value +} + +func (v *NullableContinueWithSettingsUiFlow) Set(val *ContinueWithSettingsUiFlow) { + v.value = val + v.isSet = true +} + +func (v NullableContinueWithSettingsUiFlow) IsSet() bool { + return v.isSet +} + +func (v *NullableContinueWithSettingsUiFlow) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableContinueWithSettingsUiFlow(val *ContinueWithSettingsUiFlow) *NullableContinueWithSettingsUiFlow { + return &NullableContinueWithSettingsUiFlow{value: val, isSet: true} +} + +func (v NullableContinueWithSettingsUiFlow) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableContinueWithSettingsUiFlow) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/client-go/model_recovery_code_for_identity.go b/internal/client-go/model_recovery_code_for_identity.go index 437877b15b94..a5027e7c882e 100644 --- a/internal/client-go/model_recovery_code_for_identity.go +++ b/internal/client-go/model_recovery_code_for_identity.go @@ -18,7 +18,7 @@ import ( // RecoveryCodeForIdentity Used when an administrator creates a recovery code for an identity. type RecoveryCodeForIdentity struct { - // Expires At is the timestamp of when the recovery flow expires The timestamp when the recovery link expires. + // Expires At is the timestamp of when the recovery flow expires The timestamp when the recovery code expires. ExpiresAt *time.Time `json:"expires_at,omitempty"` // RecoveryCode is the code that can be used to recover the account RecoveryCode string `json:"recovery_code"` diff --git a/internal/client-go/model_recovery_flow.go b/internal/client-go/model_recovery_flow.go index acf4ff667df3..e6df63a7c6b2 100644 --- a/internal/client-go/model_recovery_flow.go +++ b/internal/client-go/model_recovery_flow.go @@ -20,6 +20,8 @@ import ( type RecoveryFlow struct { // Active, if set, contains the recovery method that is being used. It is initially not set. Active *string `json:"active,omitempty"` + // Contains possible actions that could follow this flow + ContinueWith []ContinueWith `json:"continue_with,omitempty"` // ExpiresAt is the time (UTC) when the request expires. If the user still wishes to update the setting, a new request has to be initiated. ExpiresAt time.Time `json:"expires_at"` // ID represents the request's unique ID. When performing the recovery flow, this represents the id in the recovery ui's query parameter: http://?request= @@ -93,6 +95,38 @@ func (o *RecoveryFlow) SetActive(v string) { o.Active = &v } +// GetContinueWith returns the ContinueWith field value if set, zero value otherwise. +func (o *RecoveryFlow) GetContinueWith() []ContinueWith { + if o == nil || o.ContinueWith == nil { + var ret []ContinueWith + return ret + } + return o.ContinueWith +} + +// GetContinueWithOk returns a tuple with the ContinueWith field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *RecoveryFlow) GetContinueWithOk() ([]ContinueWith, bool) { + if o == nil || o.ContinueWith == nil { + return nil, false + } + return o.ContinueWith, true +} + +// HasContinueWith returns a boolean if a field has been set. +func (o *RecoveryFlow) HasContinueWith() bool { + if o != nil && o.ContinueWith != nil { + return true + } + + return false +} + +// SetContinueWith gets a reference to the given []ContinueWith and assigns it to the ContinueWith field. +func (o *RecoveryFlow) SetContinueWith(v []ContinueWith) { + o.ContinueWith = v +} + // GetExpiresAt returns the ExpiresAt field value func (o *RecoveryFlow) GetExpiresAt() time.Time { if o == nil { @@ -300,6 +334,9 @@ func (o RecoveryFlow) MarshalJSON() ([]byte, error) { if o.Active != nil { toSerialize["active"] = o.Active } + if o.ContinueWith != nil { + toSerialize["continue_with"] = o.ContinueWith + } if true { toSerialize["expires_at"] = o.ExpiresAt } diff --git a/internal/httpclient/.openapi-generator/FILES b/internal/httpclient/.openapi-generator/FILES index 24a832963dac..f2d48ddec66c 100644 --- a/internal/httpclient/.openapi-generator/FILES +++ b/internal/httpclient/.openapi-generator/FILES @@ -13,7 +13,11 @@ docs/AuthenticatorAssuranceLevel.md docs/BatchPatchIdentitiesResponse.md docs/ConsistencyRequestParameters.md docs/ContinueWith.md +docs/ContinueWithRecoveryUi.md +docs/ContinueWithRecoveryUiFlow.md docs/ContinueWithSetOrySessionToken.md +docs/ContinueWithSettingsUi.md +docs/ContinueWithSettingsUiFlow.md docs/ContinueWithVerificationUi.md docs/ContinueWithVerificationUiFlow.md docs/CourierApi.md @@ -131,7 +135,11 @@ model_authenticator_assurance_level.go model_batch_patch_identities_response.go model_consistency_request_parameters.go model_continue_with.go +model_continue_with_recovery_ui.go +model_continue_with_recovery_ui_flow.go model_continue_with_set_ory_session_token.go +model_continue_with_settings_ui.go +model_continue_with_settings_ui_flow.go model_continue_with_verification_ui.go model_continue_with_verification_ui_flow.go model_courier_message_status.go diff --git a/internal/httpclient/README.md b/internal/httpclient/README.md index 171764a11a5b..7fedaba9d3e5 100644 --- a/internal/httpclient/README.md +++ b/internal/httpclient/README.md @@ -107,7 +107,7 @@ Class | Method | HTTP request | Description *FrontendApi* | [**ToSession**](docs/FrontendApi.md#tosession) | **Get** /sessions/whoami | Check Who the Current HTTP Session Belongs To *FrontendApi* | [**UpdateLoginFlow**](docs/FrontendApi.md#updateloginflow) | **Post** /self-service/login | Submit a Login Flow *FrontendApi* | [**UpdateLogoutFlow**](docs/FrontendApi.md#updatelogoutflow) | **Get** /self-service/logout | Update Logout Flow -*FrontendApi* | [**UpdateRecoveryFlow**](docs/FrontendApi.md#updaterecoveryflow) | **Post** /self-service/recovery | Complete Recovery Flow +*FrontendApi* | [**UpdateRecoveryFlow**](docs/FrontendApi.md#updaterecoveryflow) | **Post** /self-service/recovery | Update Recovery Flow *FrontendApi* | [**UpdateRegistrationFlow**](docs/FrontendApi.md#updateregistrationflow) | **Post** /self-service/registration | Update Registration Flow *FrontendApi* | [**UpdateSettingsFlow**](docs/FrontendApi.md#updatesettingsflow) | **Post** /self-service/settings | Complete Settings Flow *FrontendApi* | [**UpdateVerificationFlow**](docs/FrontendApi.md#updateverificationflow) | **Post** /self-service/verification | Complete Verification Flow @@ -140,7 +140,11 @@ Class | Method | HTTP request | Description - [BatchPatchIdentitiesResponse](docs/BatchPatchIdentitiesResponse.md) - [ConsistencyRequestParameters](docs/ConsistencyRequestParameters.md) - [ContinueWith](docs/ContinueWith.md) + - [ContinueWithRecoveryUi](docs/ContinueWithRecoveryUi.md) + - [ContinueWithRecoveryUiFlow](docs/ContinueWithRecoveryUiFlow.md) - [ContinueWithSetOrySessionToken](docs/ContinueWithSetOrySessionToken.md) + - [ContinueWithSettingsUi](docs/ContinueWithSettingsUi.md) + - [ContinueWithSettingsUiFlow](docs/ContinueWithSettingsUiFlow.md) - [ContinueWithVerificationUi](docs/ContinueWithVerificationUi.md) - [ContinueWithVerificationUiFlow](docs/ContinueWithVerificationUiFlow.md) - [CourierMessageStatus](docs/CourierMessageStatus.md) diff --git a/internal/httpclient/api_frontend.go b/internal/httpclient/api_frontend.go index 0260af5a71b6..ab8c45632935 100644 --- a/internal/httpclient/api_frontend.go +++ b/internal/httpclient/api_frontend.go @@ -240,7 +240,7 @@ type FrontendApi interface { If a valid provided session cookie or session token is provided, a 400 Bad Request error. - To fetch an existing recovery flow call `/self-service/recovery/flows?flow=`. + On an existing recovery flow, use the `getRecoveryFlow` API endpoint. You MUST NOT use this endpoint in client-side (Single Page Apps, ReactJS, AngularJS) nor server-side (Java Server Pages, NodeJS, PHP, Golang, ...) browser applications. Using this endpoint in these applications will make @@ -775,8 +775,8 @@ type FrontendApi interface { UpdateLogoutFlowExecute(r FrontendApiApiUpdateLogoutFlowRequest) (*http.Response, error) /* - * UpdateRecoveryFlow Complete Recovery Flow - * Use this endpoint to complete a recovery flow. This endpoint + * UpdateRecoveryFlow Update Recovery Flow + * Use this endpoint to update a recovery flow. This endpoint behaves differently for API and browser flows and has several states: `choose_method` expects `flow` (in the URL query) and `email` (in the body) to be sent @@ -2075,7 +2075,7 @@ func (r FrontendApiApiCreateNativeRecoveryFlowRequest) Execute() (*RecoveryFlow, If a valid provided session cookie or session token is provided, a 400 Bad Request error. -To fetch an existing recovery flow call `/self-service/recovery/flows?flow=`. +On an existing recovery flow, use the `getRecoveryFlow` API endpoint. You MUST NOT use this endpoint in client-side (Single Page Apps, ReactJS, AngularJS) nor server-side (Java Server Pages, NodeJS, PHP, Golang, ...) browser applications. Using this endpoint in these applications will make @@ -5076,8 +5076,8 @@ func (r FrontendApiApiUpdateRecoveryFlowRequest) Execute() (*RecoveryFlow, *http } /* - - UpdateRecoveryFlow Complete Recovery Flow - - Use this endpoint to complete a recovery flow. This endpoint + - UpdateRecoveryFlow Update Recovery Flow + - Use this endpoint to update a recovery flow. This endpoint behaves differently for API and browser flows and has several states: diff --git a/internal/httpclient/model_continue_with.go b/internal/httpclient/model_continue_with.go index 2cd5dd77542c..ee84e74692fb 100644 --- a/internal/httpclient/model_continue_with.go +++ b/internal/httpclient/model_continue_with.go @@ -18,10 +18,19 @@ import ( // ContinueWith - struct for ContinueWith type ContinueWith struct { + ContinueWithRecoveryUi *ContinueWithRecoveryUi ContinueWithSetOrySessionToken *ContinueWithSetOrySessionToken + ContinueWithSettingsUi *ContinueWithSettingsUi ContinueWithVerificationUi *ContinueWithVerificationUi } +// ContinueWithRecoveryUiAsContinueWith is a convenience function that returns ContinueWithRecoveryUi wrapped in ContinueWith +func ContinueWithRecoveryUiAsContinueWith(v *ContinueWithRecoveryUi) ContinueWith { + return ContinueWith{ + ContinueWithRecoveryUi: v, + } +} + // ContinueWithSetOrySessionTokenAsContinueWith is a convenience function that returns ContinueWithSetOrySessionToken wrapped in ContinueWith func ContinueWithSetOrySessionTokenAsContinueWith(v *ContinueWithSetOrySessionToken) ContinueWith { return ContinueWith{ @@ -29,6 +38,13 @@ func ContinueWithSetOrySessionTokenAsContinueWith(v *ContinueWithSetOrySessionTo } } +// ContinueWithSettingsUiAsContinueWith is a convenience function that returns ContinueWithSettingsUi wrapped in ContinueWith +func ContinueWithSettingsUiAsContinueWith(v *ContinueWithSettingsUi) ContinueWith { + return ContinueWith{ + ContinueWithSettingsUi: v, + } +} + // ContinueWithVerificationUiAsContinueWith is a convenience function that returns ContinueWithVerificationUi wrapped in ContinueWith func ContinueWithVerificationUiAsContinueWith(v *ContinueWithVerificationUi) ContinueWith { return ContinueWith{ @@ -40,6 +56,19 @@ func ContinueWithVerificationUiAsContinueWith(v *ContinueWithVerificationUi) Con func (dst *ContinueWith) UnmarshalJSON(data []byte) error { var err error match := 0 + // try to unmarshal data into ContinueWithRecoveryUi + err = newStrictDecoder(data).Decode(&dst.ContinueWithRecoveryUi) + if err == nil { + jsonContinueWithRecoveryUi, _ := json.Marshal(dst.ContinueWithRecoveryUi) + if string(jsonContinueWithRecoveryUi) == "{}" { // empty struct + dst.ContinueWithRecoveryUi = nil + } else { + match++ + } + } else { + dst.ContinueWithRecoveryUi = nil + } + // try to unmarshal data into ContinueWithSetOrySessionToken err = newStrictDecoder(data).Decode(&dst.ContinueWithSetOrySessionToken) if err == nil { @@ -53,6 +82,19 @@ func (dst *ContinueWith) UnmarshalJSON(data []byte) error { dst.ContinueWithSetOrySessionToken = nil } + // try to unmarshal data into ContinueWithSettingsUi + err = newStrictDecoder(data).Decode(&dst.ContinueWithSettingsUi) + if err == nil { + jsonContinueWithSettingsUi, _ := json.Marshal(dst.ContinueWithSettingsUi) + if string(jsonContinueWithSettingsUi) == "{}" { // empty struct + dst.ContinueWithSettingsUi = nil + } else { + match++ + } + } else { + dst.ContinueWithSettingsUi = nil + } + // try to unmarshal data into ContinueWithVerificationUi err = newStrictDecoder(data).Decode(&dst.ContinueWithVerificationUi) if err == nil { @@ -68,7 +110,9 @@ func (dst *ContinueWith) UnmarshalJSON(data []byte) error { if match > 1 { // more than 1 match // reset to nil + dst.ContinueWithRecoveryUi = nil dst.ContinueWithSetOrySessionToken = nil + dst.ContinueWithSettingsUi = nil dst.ContinueWithVerificationUi = nil return fmt.Errorf("Data matches more than one schema in oneOf(ContinueWith)") @@ -81,10 +125,18 @@ func (dst *ContinueWith) UnmarshalJSON(data []byte) error { // Marshal data from the first non-nil pointers in the struct to JSON func (src ContinueWith) MarshalJSON() ([]byte, error) { + if src.ContinueWithRecoveryUi != nil { + return json.Marshal(&src.ContinueWithRecoveryUi) + } + if src.ContinueWithSetOrySessionToken != nil { return json.Marshal(&src.ContinueWithSetOrySessionToken) } + if src.ContinueWithSettingsUi != nil { + return json.Marshal(&src.ContinueWithSettingsUi) + } + if src.ContinueWithVerificationUi != nil { return json.Marshal(&src.ContinueWithVerificationUi) } @@ -97,10 +149,18 @@ func (obj *ContinueWith) GetActualInstance() interface{} { if obj == nil { return nil } + if obj.ContinueWithRecoveryUi != nil { + return obj.ContinueWithRecoveryUi + } + if obj.ContinueWithSetOrySessionToken != nil { return obj.ContinueWithSetOrySessionToken } + if obj.ContinueWithSettingsUi != nil { + return obj.ContinueWithSettingsUi + } + if obj.ContinueWithVerificationUi != nil { return obj.ContinueWithVerificationUi } diff --git a/internal/httpclient/model_continue_with_recovery_ui.go b/internal/httpclient/model_continue_with_recovery_ui.go new file mode 100644 index 000000000000..93682bf90beb --- /dev/null +++ b/internal/httpclient/model_continue_with_recovery_ui.go @@ -0,0 +1,137 @@ +/* + * Ory Identities API + * + * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. + * + * API version: + * Contact: office@ory.sh + */ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +import ( + "encoding/json" +) + +// ContinueWithRecoveryUi Indicates, that the UI flow could be continued by showing a recovery ui +type ContinueWithRecoveryUi struct { + // Action will always be `show_recovery_ui` show_recovery_ui ContinueWithActionShowRecoveryUIString + Action string `json:"action"` + Flow ContinueWithRecoveryUiFlow `json:"flow"` +} + +// NewContinueWithRecoveryUi instantiates a new ContinueWithRecoveryUi 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 NewContinueWithRecoveryUi(action string, flow ContinueWithRecoveryUiFlow) *ContinueWithRecoveryUi { + this := ContinueWithRecoveryUi{} + this.Action = action + this.Flow = flow + return &this +} + +// NewContinueWithRecoveryUiWithDefaults instantiates a new ContinueWithRecoveryUi 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 NewContinueWithRecoveryUiWithDefaults() *ContinueWithRecoveryUi { + this := ContinueWithRecoveryUi{} + return &this +} + +// GetAction returns the Action field value +func (o *ContinueWithRecoveryUi) GetAction() string { + if o == nil { + var ret string + return ret + } + + return o.Action +} + +// GetActionOk returns a tuple with the Action field value +// and a boolean to check if the value has been set. +func (o *ContinueWithRecoveryUi) GetActionOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Action, true +} + +// SetAction sets field value +func (o *ContinueWithRecoveryUi) SetAction(v string) { + o.Action = v +} + +// GetFlow returns the Flow field value +func (o *ContinueWithRecoveryUi) GetFlow() ContinueWithRecoveryUiFlow { + if o == nil { + var ret ContinueWithRecoveryUiFlow + return ret + } + + return o.Flow +} + +// GetFlowOk returns a tuple with the Flow field value +// and a boolean to check if the value has been set. +func (o *ContinueWithRecoveryUi) GetFlowOk() (*ContinueWithRecoveryUiFlow, bool) { + if o == nil { + return nil, false + } + return &o.Flow, true +} + +// SetFlow sets field value +func (o *ContinueWithRecoveryUi) SetFlow(v ContinueWithRecoveryUiFlow) { + o.Flow = v +} + +func (o ContinueWithRecoveryUi) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if true { + toSerialize["action"] = o.Action + } + if true { + toSerialize["flow"] = o.Flow + } + return json.Marshal(toSerialize) +} + +type NullableContinueWithRecoveryUi struct { + value *ContinueWithRecoveryUi + isSet bool +} + +func (v NullableContinueWithRecoveryUi) Get() *ContinueWithRecoveryUi { + return v.value +} + +func (v *NullableContinueWithRecoveryUi) Set(val *ContinueWithRecoveryUi) { + v.value = val + v.isSet = true +} + +func (v NullableContinueWithRecoveryUi) IsSet() bool { + return v.isSet +} + +func (v *NullableContinueWithRecoveryUi) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableContinueWithRecoveryUi(val *ContinueWithRecoveryUi) *NullableContinueWithRecoveryUi { + return &NullableContinueWithRecoveryUi{value: val, isSet: true} +} + +func (v NullableContinueWithRecoveryUi) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableContinueWithRecoveryUi) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/httpclient/model_continue_with_recovery_ui_flow.go b/internal/httpclient/model_continue_with_recovery_ui_flow.go new file mode 100644 index 000000000000..3fde7e717ef2 --- /dev/null +++ b/internal/httpclient/model_continue_with_recovery_ui_flow.go @@ -0,0 +1,145 @@ +/* + * Ory Identities API + * + * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. + * + * API version: + * Contact: office@ory.sh + */ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +import ( + "encoding/json" +) + +// ContinueWithRecoveryUiFlow struct for ContinueWithRecoveryUiFlow +type ContinueWithRecoveryUiFlow struct { + // The ID of the recovery flow + Id string `json:"id"` + // The URL of the recovery flow + Url *string `json:"url,omitempty"` +} + +// NewContinueWithRecoveryUiFlow instantiates a new ContinueWithRecoveryUiFlow 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 NewContinueWithRecoveryUiFlow(id string) *ContinueWithRecoveryUiFlow { + this := ContinueWithRecoveryUiFlow{} + this.Id = id + return &this +} + +// NewContinueWithRecoveryUiFlowWithDefaults instantiates a new ContinueWithRecoveryUiFlow 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 NewContinueWithRecoveryUiFlowWithDefaults() *ContinueWithRecoveryUiFlow { + this := ContinueWithRecoveryUiFlow{} + return &this +} + +// GetId returns the Id field value +func (o *ContinueWithRecoveryUiFlow) GetId() string { + if o == nil { + var ret string + return ret + } + + return o.Id +} + +// GetIdOk returns a tuple with the Id field value +// and a boolean to check if the value has been set. +func (o *ContinueWithRecoveryUiFlow) GetIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Id, true +} + +// SetId sets field value +func (o *ContinueWithRecoveryUiFlow) SetId(v string) { + o.Id = v +} + +// GetUrl returns the Url field value if set, zero value otherwise. +func (o *ContinueWithRecoveryUiFlow) GetUrl() string { + if o == nil || o.Url == nil { + var ret string + return ret + } + return *o.Url +} + +// GetUrlOk returns a tuple with the Url field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ContinueWithRecoveryUiFlow) GetUrlOk() (*string, bool) { + if o == nil || o.Url == nil { + return nil, false + } + return o.Url, true +} + +// HasUrl returns a boolean if a field has been set. +func (o *ContinueWithRecoveryUiFlow) HasUrl() bool { + if o != nil && o.Url != nil { + return true + } + + return false +} + +// SetUrl gets a reference to the given string and assigns it to the Url field. +func (o *ContinueWithRecoveryUiFlow) SetUrl(v string) { + o.Url = &v +} + +func (o ContinueWithRecoveryUiFlow) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if true { + toSerialize["id"] = o.Id + } + if o.Url != nil { + toSerialize["url"] = o.Url + } + return json.Marshal(toSerialize) +} + +type NullableContinueWithRecoveryUiFlow struct { + value *ContinueWithRecoveryUiFlow + isSet bool +} + +func (v NullableContinueWithRecoveryUiFlow) Get() *ContinueWithRecoveryUiFlow { + return v.value +} + +func (v *NullableContinueWithRecoveryUiFlow) Set(val *ContinueWithRecoveryUiFlow) { + v.value = val + v.isSet = true +} + +func (v NullableContinueWithRecoveryUiFlow) IsSet() bool { + return v.isSet +} + +func (v *NullableContinueWithRecoveryUiFlow) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableContinueWithRecoveryUiFlow(val *ContinueWithRecoveryUiFlow) *NullableContinueWithRecoveryUiFlow { + return &NullableContinueWithRecoveryUiFlow{value: val, isSet: true} +} + +func (v NullableContinueWithRecoveryUiFlow) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableContinueWithRecoveryUiFlow) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/httpclient/model_continue_with_settings_ui.go b/internal/httpclient/model_continue_with_settings_ui.go new file mode 100644 index 000000000000..eb843d966c16 --- /dev/null +++ b/internal/httpclient/model_continue_with_settings_ui.go @@ -0,0 +1,137 @@ +/* + * Ory Identities API + * + * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. + * + * API version: + * Contact: office@ory.sh + */ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +import ( + "encoding/json" +) + +// ContinueWithSettingsUi Indicates, that the UI flow could be continued by showing a settings ui +type ContinueWithSettingsUi struct { + // Action will always be `show_settings_ui` show_settings_ui ContinueWithActionShowSettingsUIString + Action string `json:"action"` + Flow ContinueWithSettingsUiFlow `json:"flow"` +} + +// NewContinueWithSettingsUi instantiates a new ContinueWithSettingsUi 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 NewContinueWithSettingsUi(action string, flow ContinueWithSettingsUiFlow) *ContinueWithSettingsUi { + this := ContinueWithSettingsUi{} + this.Action = action + this.Flow = flow + return &this +} + +// NewContinueWithSettingsUiWithDefaults instantiates a new ContinueWithSettingsUi 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 NewContinueWithSettingsUiWithDefaults() *ContinueWithSettingsUi { + this := ContinueWithSettingsUi{} + return &this +} + +// GetAction returns the Action field value +func (o *ContinueWithSettingsUi) GetAction() string { + if o == nil { + var ret string + return ret + } + + return o.Action +} + +// GetActionOk returns a tuple with the Action field value +// and a boolean to check if the value has been set. +func (o *ContinueWithSettingsUi) GetActionOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Action, true +} + +// SetAction sets field value +func (o *ContinueWithSettingsUi) SetAction(v string) { + o.Action = v +} + +// GetFlow returns the Flow field value +func (o *ContinueWithSettingsUi) GetFlow() ContinueWithSettingsUiFlow { + if o == nil { + var ret ContinueWithSettingsUiFlow + return ret + } + + return o.Flow +} + +// GetFlowOk returns a tuple with the Flow field value +// and a boolean to check if the value has been set. +func (o *ContinueWithSettingsUi) GetFlowOk() (*ContinueWithSettingsUiFlow, bool) { + if o == nil { + return nil, false + } + return &o.Flow, true +} + +// SetFlow sets field value +func (o *ContinueWithSettingsUi) SetFlow(v ContinueWithSettingsUiFlow) { + o.Flow = v +} + +func (o ContinueWithSettingsUi) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if true { + toSerialize["action"] = o.Action + } + if true { + toSerialize["flow"] = o.Flow + } + return json.Marshal(toSerialize) +} + +type NullableContinueWithSettingsUi struct { + value *ContinueWithSettingsUi + isSet bool +} + +func (v NullableContinueWithSettingsUi) Get() *ContinueWithSettingsUi { + return v.value +} + +func (v *NullableContinueWithSettingsUi) Set(val *ContinueWithSettingsUi) { + v.value = val + v.isSet = true +} + +func (v NullableContinueWithSettingsUi) IsSet() bool { + return v.isSet +} + +func (v *NullableContinueWithSettingsUi) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableContinueWithSettingsUi(val *ContinueWithSettingsUi) *NullableContinueWithSettingsUi { + return &NullableContinueWithSettingsUi{value: val, isSet: true} +} + +func (v NullableContinueWithSettingsUi) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableContinueWithSettingsUi) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/httpclient/model_continue_with_settings_ui_flow.go b/internal/httpclient/model_continue_with_settings_ui_flow.go new file mode 100644 index 000000000000..4ccaf74ef1b8 --- /dev/null +++ b/internal/httpclient/model_continue_with_settings_ui_flow.go @@ -0,0 +1,108 @@ +/* + * Ory Identities API + * + * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. + * + * API version: + * Contact: office@ory.sh + */ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package client + +import ( + "encoding/json" +) + +// ContinueWithSettingsUiFlow struct for ContinueWithSettingsUiFlow +type ContinueWithSettingsUiFlow struct { + // The ID of the settings flow + Id string `json:"id"` +} + +// NewContinueWithSettingsUiFlow instantiates a new ContinueWithSettingsUiFlow 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 NewContinueWithSettingsUiFlow(id string) *ContinueWithSettingsUiFlow { + this := ContinueWithSettingsUiFlow{} + this.Id = id + return &this +} + +// NewContinueWithSettingsUiFlowWithDefaults instantiates a new ContinueWithSettingsUiFlow 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 NewContinueWithSettingsUiFlowWithDefaults() *ContinueWithSettingsUiFlow { + this := ContinueWithSettingsUiFlow{} + return &this +} + +// GetId returns the Id field value +func (o *ContinueWithSettingsUiFlow) GetId() string { + if o == nil { + var ret string + return ret + } + + return o.Id +} + +// GetIdOk returns a tuple with the Id field value +// and a boolean to check if the value has been set. +func (o *ContinueWithSettingsUiFlow) GetIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Id, true +} + +// SetId sets field value +func (o *ContinueWithSettingsUiFlow) SetId(v string) { + o.Id = v +} + +func (o ContinueWithSettingsUiFlow) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if true { + toSerialize["id"] = o.Id + } + return json.Marshal(toSerialize) +} + +type NullableContinueWithSettingsUiFlow struct { + value *ContinueWithSettingsUiFlow + isSet bool +} + +func (v NullableContinueWithSettingsUiFlow) Get() *ContinueWithSettingsUiFlow { + return v.value +} + +func (v *NullableContinueWithSettingsUiFlow) Set(val *ContinueWithSettingsUiFlow) { + v.value = val + v.isSet = true +} + +func (v NullableContinueWithSettingsUiFlow) IsSet() bool { + return v.isSet +} + +func (v *NullableContinueWithSettingsUiFlow) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableContinueWithSettingsUiFlow(val *ContinueWithSettingsUiFlow) *NullableContinueWithSettingsUiFlow { + return &NullableContinueWithSettingsUiFlow{value: val, isSet: true} +} + +func (v NullableContinueWithSettingsUiFlow) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableContinueWithSettingsUiFlow) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/httpclient/model_recovery_code_for_identity.go b/internal/httpclient/model_recovery_code_for_identity.go index 437877b15b94..a5027e7c882e 100644 --- a/internal/httpclient/model_recovery_code_for_identity.go +++ b/internal/httpclient/model_recovery_code_for_identity.go @@ -18,7 +18,7 @@ import ( // RecoveryCodeForIdentity Used when an administrator creates a recovery code for an identity. type RecoveryCodeForIdentity struct { - // Expires At is the timestamp of when the recovery flow expires The timestamp when the recovery link expires. + // Expires At is the timestamp of when the recovery flow expires The timestamp when the recovery code expires. ExpiresAt *time.Time `json:"expires_at,omitempty"` // RecoveryCode is the code that can be used to recover the account RecoveryCode string `json:"recovery_code"` diff --git a/internal/httpclient/model_recovery_flow.go b/internal/httpclient/model_recovery_flow.go index acf4ff667df3..e6df63a7c6b2 100644 --- a/internal/httpclient/model_recovery_flow.go +++ b/internal/httpclient/model_recovery_flow.go @@ -20,6 +20,8 @@ import ( type RecoveryFlow struct { // Active, if set, contains the recovery method that is being used. It is initially not set. Active *string `json:"active,omitempty"` + // Contains possible actions that could follow this flow + ContinueWith []ContinueWith `json:"continue_with,omitempty"` // ExpiresAt is the time (UTC) when the request expires. If the user still wishes to update the setting, a new request has to be initiated. ExpiresAt time.Time `json:"expires_at"` // ID represents the request's unique ID. When performing the recovery flow, this represents the id in the recovery ui's query parameter: http://?request= @@ -93,6 +95,38 @@ func (o *RecoveryFlow) SetActive(v string) { o.Active = &v } +// GetContinueWith returns the ContinueWith field value if set, zero value otherwise. +func (o *RecoveryFlow) GetContinueWith() []ContinueWith { + if o == nil || o.ContinueWith == nil { + var ret []ContinueWith + return ret + } + return o.ContinueWith +} + +// GetContinueWithOk returns a tuple with the ContinueWith field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *RecoveryFlow) GetContinueWithOk() ([]ContinueWith, bool) { + if o == nil || o.ContinueWith == nil { + return nil, false + } + return o.ContinueWith, true +} + +// HasContinueWith returns a boolean if a field has been set. +func (o *RecoveryFlow) HasContinueWith() bool { + if o != nil && o.ContinueWith != nil { + return true + } + + return false +} + +// SetContinueWith gets a reference to the given []ContinueWith and assigns it to the ContinueWith field. +func (o *RecoveryFlow) SetContinueWith(v []ContinueWith) { + o.ContinueWith = v +} + // GetExpiresAt returns the ExpiresAt field value func (o *RecoveryFlow) GetExpiresAt() time.Time { if o == nil { @@ -300,6 +334,9 @@ func (o RecoveryFlow) MarshalJSON() ([]byte, error) { if o.Active != nil { toSerialize["active"] = o.Active } + if o.ContinueWith != nil { + toSerialize["continue_with"] = o.ContinueWith + } if true { toSerialize["expires_at"] = o.ExpiresAt } diff --git a/internal/testhelpers/selfservice_verification.go b/internal/testhelpers/selfservice_verification.go index 757f21adb30a..92bc5b191d43 100644 --- a/internal/testhelpers/selfservice_verification.go +++ b/internal/testhelpers/selfservice_verification.go @@ -13,6 +13,8 @@ import ( "testing" "time" + "github.com/tidwall/gjson" + kratos "github.com/ory/kratos/internal/httpclient" "github.com/ory/x/ioutilx" @@ -39,25 +41,48 @@ func NewRecoveryUIFlowEchoServer(t *testing.T, reg driver.Registry) *httptest.Se return ts } -func GetRecoveryFlow(t *testing.T, client *http.Client, ts *httptest.Server) *kratos.RecoveryFlow { +func GetRecoveryFlowForType(t *testing.T, client *http.Client, ts *httptest.Server, ft flow.Type) *kratos.RecoveryFlow { publicClient := NewSDKCustomClient(ts, client) - res, err := client.Get(ts.URL + recovery.RouteInitBrowserFlow) + var url string + switch ft { + case flow.TypeBrowser: + url = ts.URL + recovery.RouteInitBrowserFlow + case flow.TypeAPI: + url = ts.URL + recovery.RouteInitAPIFlow + default: + t.Errorf("unknown type: %s", ft) + t.FailNow() + } + + res, err := client.Get(url) require.NoError(t, err) - require.NoError(t, res.Body.Close()) - flowID := res.Request.URL.Query().Get("flow") - assert.NotEmpty(t, flowID, "expected to receive a flow id, got none") + var flowID string + switch ft { + case flow.TypeBrowser: + flowID = res.Request.URL.Query().Get("flow") + case flow.TypeAPI: + flowID = gjson.GetBytes(ioutilx.MustReadAll(res.Body), "id").String() + default: + t.Errorf("unknown type: %s", ft) + t.FailNow() + } + require.NotEmpty(t, flowID, "expected to receive a flow id, got none. %s", ioutilx.MustReadAll(res.Body)) rs, _, err := publicClient.FrontendApi.GetRecoveryFlow(context.Background()). Id(flowID). Execute() - assert.NotEmpty(t, rs.Active) require.NoError(t, err, "expected no error when fetching recovery flow: %s", err) + assert.NotEmpty(t, rs.Active) return rs } +func GetRecoveryFlow(t *testing.T, client *http.Client, ts *httptest.Server) *kratos.RecoveryFlow { + return GetRecoveryFlowForType(t, client, ts, flow.TypeBrowser) +} + func InitializeRecoveryFlowViaBrowser(t *testing.T, client *http.Client, isSPA bool, ts *httptest.Server, values url.Values) *kratos.RecoveryFlow { publicClient := NewSDKCustomClient(ts, client) diff --git a/selfservice/flow/continue_with.go b/selfservice/flow/continue_with.go index a54af5abef5a..7a5f9ce22410 100644 --- a/selfservice/flow/continue_with.go +++ b/selfservice/flow/continue_with.go @@ -6,6 +6,8 @@ package flow import ( "net/url" + "github.com/ory/herodot" + "github.com/gofrs/uuid" "github.com/ory/x/urlx" @@ -24,6 +26,7 @@ const ( var _ ContinueWith = new(ContinueWithSetOrySessionToken) // Indicates that a session was issued, and the application should use this token for authenticated requests +// // swagger:model continueWithSetOrySessionToken type ContinueWithSetOrySessionToken struct { // Action will always be `set_ory_session_token` @@ -112,3 +115,97 @@ type FlowWithContinueWith interface { AddContinueWith(ContinueWith) ContinueWith() []ContinueWith } + +// swagger:enum ContinueWithActionShowSettingsUI +type ContinueWithActionShowSettingsUI string + +// #nosec G101 -- only a key constant +const ( + ContinueWithActionShowSettingsUIString ContinueWithActionShowSettingsUI = "show_settings_ui" +) + +var _ ContinueWith = new(ContinueWithSettingsUI) + +// Indicates, that the UI flow could be continued by showing a settings ui +// +// swagger:model continueWithSettingsUi +type ContinueWithSettingsUI struct { + // Action will always be `show_settings_ui` + // + // required: true + Action ContinueWithActionShowSettingsUI `json:"action"` + // Flow contains the ID of the verification flow + // + // required: true + Flow ContinueWithSettingsUIFlow `json:"flow"` +} + +// swagger:model continueWithSettingsUiFlow +type ContinueWithSettingsUIFlow struct { + // The ID of the settings flow + // + // required: true + ID uuid.UUID `json:"id"` +} + +func NewContinueWithSettingsUI(f Flow) *ContinueWithSettingsUI { + return &ContinueWithSettingsUI{ + Action: ContinueWithActionShowSettingsUIString, + Flow: ContinueWithSettingsUIFlow{ + ID: f.GetID(), + }, + } +} + +// swagger:enum ContinueWithActionShowRecoveryUI +type ContinueWithActionShowRecoveryUI string + +// #nosec G101 -- only a key constant +const ( + ContinueWithActionShowRecoveryUIString ContinueWithActionShowRecoveryUI = "show_recovery_ui" +) + +// Indicates, that the UI flow could be continued by showing a recovery ui +// +// swagger:model continueWithRecoveryUi +type ContinueWithRecoveryUI struct { + // Action will always be `show_recovery_ui` + // + // required: true + Action ContinueWithActionShowRecoveryUI `json:"action"` + // Flow contains the ID of the recovery flow + // + // required: true + Flow ContinueWithRecoveryUIFlow `json:"flow"` +} + +// swagger:model continueWithRecoveryUiFlow +type ContinueWithRecoveryUIFlow struct { + // The ID of the recovery flow + // + // required: true + ID uuid.UUID `json:"id"` + + // The URL of the recovery flow + // + // required: false + URL string `json:"url,omitempty"` +} + +func NewContinueWithRecoveryUI(f Flow) *ContinueWithRecoveryUI { + return &ContinueWithRecoveryUI{ + Action: ContinueWithActionShowRecoveryUIString, + Flow: ContinueWithRecoveryUIFlow{ + ID: f.GetID(), + }, + } +} + +func ErrorWithContinueWith(err *herodot.DefaultError, continueWith ...ContinueWith) *herodot.DefaultError { + if err.DetailsField == nil { + err.DetailsField = map[string]interface{}{} + } + err.DetailsField["continue_with"] = continueWith + + return err +} diff --git a/selfservice/flow/error.go b/selfservice/flow/error.go index 4e169e3d9d69..d666822fa5c0 100644 --- a/selfservice/flow/error.go +++ b/selfservice/flow/error.go @@ -114,6 +114,15 @@ type ExpiredError struct { flow Flow } +func (e *ExpiredError) Unwrap() error { + return e.DefaultError +} + +func (e *ExpiredError) WithContinueWith(continueWith ...ContinueWith) *ExpiredError { + e.DefaultError = ErrorWithContinueWith(e.DefaultError, continueWith...) + return e +} + func (e *ExpiredError) WithFlow(flow Flow) *ExpiredError { e.FlowID = flow.GetID() e.flow = flow diff --git a/selfservice/flow/recovery/.snapshots/TestHandleError-flow=api-case=fails_if_active_strategy_is_disabled.json b/selfservice/flow/recovery/.snapshots/TestHandleError-flow=api-case=fails_if_active_strategy_is_disabled.json index d6c78d8b8358..f4c0270da2dc 100644 --- a/selfservice/flow/recovery/.snapshots/TestHandleError-flow=api-case=fails_if_active_strategy_is_disabled.json +++ b/selfservice/flow/recovery/.snapshots/TestHandleError-flow=api-case=fails_if_active_strategy_is_disabled.json @@ -60,10 +60,10 @@ "messages": [ { "id": 4000001, - "text": "The active recovery strategy code is not enabled. Please enable it in the configuration.", + "text": "You attempted recovery using code, which is not enabled or does not exist. An administrator needs to enable this recovery method.", "type": "error", "context": { - "reason": "The active recovery strategy code is not enabled. Please enable it in the configuration." + "reason": "You attempted recovery using code, which is not enabled or does not exist. An administrator needs to enable this recovery method." } } ] diff --git a/selfservice/flow/recovery/.snapshots/TestHandleError-flow=browser-case=fails_to_retry_flow_if_recovery_strategy_id_is_not_valid.json b/selfservice/flow/recovery/.snapshots/TestHandleError-flow=browser-case=fails_to_retry_flow_if_recovery_strategy_id_is_not_valid.json index bc2b0b525548..a9d446e87ff3 100644 --- a/selfservice/flow/recovery/.snapshots/TestHandleError-flow=browser-case=fails_to_retry_flow_if_recovery_strategy_id_is_not_valid.json +++ b/selfservice/flow/recovery/.snapshots/TestHandleError-flow=browser-case=fails_to_retry_flow_if_recovery_strategy_id_is_not_valid.json @@ -1,6 +1,6 @@ { "code": 400, "message": "The request was malformed or contained invalid parameters", - "reason": "The active recovery strategy not-valid is not enabled. Please enable it in the configuration.", + "reason": "You attempted recovery using not-valid, which is not enabled or does not exist. An administrator needs to enable this recovery method.", "status": "Bad Request" } diff --git a/selfservice/flow/recovery/.snapshots/TestHandleError-flow=spa-case=fails_if_active_strategy_is_disabled.json b/selfservice/flow/recovery/.snapshots/TestHandleError-flow=spa-case=fails_if_active_strategy_is_disabled.json index 7a17de3f9374..56782eed4571 100644 --- a/selfservice/flow/recovery/.snapshots/TestHandleError-flow=spa-case=fails_if_active_strategy_is_disabled.json +++ b/selfservice/flow/recovery/.snapshots/TestHandleError-flow=spa-case=fails_if_active_strategy_is_disabled.json @@ -60,10 +60,10 @@ "messages": [ { "id": 4000001, - "text": "The active recovery strategy code is not enabled. Please enable it in the configuration.", + "text": "You attempted recovery using code, which is not enabled or does not exist. An administrator needs to enable this recovery method.", "type": "error", "context": { - "reason": "The active recovery strategy code is not enabled. Please enable it in the configuration." + "reason": "You attempted recovery using code, which is not enabled or does not exist. An administrator needs to enable this recovery method." } } ] diff --git a/selfservice/flow/recovery/.snapshots/TestHandleError_WithContinueWith-flow=api-case=fails_if_active_strategy_is_disabled.json b/selfservice/flow/recovery/.snapshots/TestHandleError_WithContinueWith-flow=api-case=fails_if_active_strategy_is_disabled.json new file mode 100644 index 000000000000..f4c0270da2dc --- /dev/null +++ b/selfservice/flow/recovery/.snapshots/TestHandleError_WithContinueWith-flow=api-case=fails_if_active_strategy_is_disabled.json @@ -0,0 +1,73 @@ +{ + "type": "api", + "request_url": "http:///", + "active": "link", + "ui": { + "method": "POST", + "nodes": [ + { + "type": "input", + "group": "default", + "attributes": { + "name": "csrf_token", + "type": "hidden", + "required": true, + "disabled": false, + "node_type": "input" + }, + "messages": [], + "meta": {} + }, + { + "type": "input", + "group": "code", + "attributes": { + "name": "email", + "type": "email", + "required": true, + "disabled": false, + "node_type": "input" + }, + "messages": [], + "meta": { + "label": { + "id": 1070007, + "text": "Email", + "type": "info" + } + } + }, + { + "type": "input", + "group": "code", + "attributes": { + "name": "method", + "type": "submit", + "value": "code", + "disabled": false, + "node_type": "input" + }, + "messages": [], + "meta": { + "label": { + "id": 1070005, + "text": "Submit", + "type": "info" + } + } + } + ], + "messages": [ + { + "id": 4000001, + "text": "You attempted recovery using code, which is not enabled or does not exist. An administrator needs to enable this recovery method.", + "type": "error", + "context": { + "reason": "You attempted recovery using code, which is not enabled or does not exist. An administrator needs to enable this recovery method." + } + } + ] + }, + "state": "choose_method" +} + diff --git a/selfservice/flow/recovery/.snapshots/TestHandleError_WithContinueWith-flow=browser-case=fails_to_retry_flow_if_recovery_strategy_id_is_not_valid.json b/selfservice/flow/recovery/.snapshots/TestHandleError_WithContinueWith-flow=browser-case=fails_to_retry_flow_if_recovery_strategy_id_is_not_valid.json new file mode 100644 index 000000000000..a9d446e87ff3 --- /dev/null +++ b/selfservice/flow/recovery/.snapshots/TestHandleError_WithContinueWith-flow=browser-case=fails_to_retry_flow_if_recovery_strategy_id_is_not_valid.json @@ -0,0 +1,6 @@ +{ + "code": 400, + "message": "The request was malformed or contained invalid parameters", + "reason": "You attempted recovery using not-valid, which is not enabled or does not exist. An administrator needs to enable this recovery method.", + "status": "Bad Request" +} diff --git a/selfservice/flow/recovery/.snapshots/TestHandleError_WithContinueWith-flow=spa-case=fails_if_active_strategy_is_disabled.json b/selfservice/flow/recovery/.snapshots/TestHandleError_WithContinueWith-flow=spa-case=fails_if_active_strategy_is_disabled.json new file mode 100644 index 000000000000..56782eed4571 --- /dev/null +++ b/selfservice/flow/recovery/.snapshots/TestHandleError_WithContinueWith-flow=spa-case=fails_if_active_strategy_is_disabled.json @@ -0,0 +1,73 @@ +{ + "type": "browser", + "request_url": "http:///", + "active": "link", + "ui": { + "method": "POST", + "nodes": [ + { + "type": "input", + "group": "default", + "attributes": { + "name": "csrf_token", + "type": "hidden", + "required": true, + "disabled": false, + "node_type": "input" + }, + "messages": [], + "meta": {} + }, + { + "type": "input", + "group": "code", + "attributes": { + "name": "email", + "type": "email", + "required": true, + "disabled": false, + "node_type": "input" + }, + "messages": [], + "meta": { + "label": { + "id": 1070007, + "text": "Email", + "type": "info" + } + } + }, + { + "type": "input", + "group": "code", + "attributes": { + "name": "method", + "type": "submit", + "value": "code", + "disabled": false, + "node_type": "input" + }, + "messages": [], + "meta": { + "label": { + "id": 1070005, + "text": "Submit", + "type": "info" + } + } + } + ], + "messages": [ + { + "id": 4000001, + "text": "You attempted recovery using code, which is not enabled or does not exist. An administrator needs to enable this recovery method.", + "type": "error", + "context": { + "reason": "You attempted recovery using code, which is not enabled or does not exist. An administrator needs to enable this recovery method." + } + } + ] + }, + "state": "choose_method" +} + diff --git a/selfservice/flow/recovery/error.go b/selfservice/flow/recovery/error.go index defc22719412..9f93af941447 100644 --- a/selfservice/flow/recovery/error.go +++ b/selfservice/flow/recovery/error.go @@ -62,23 +62,23 @@ func (s *ErrorHandler) WriteFlowError( r *http.Request, f *Flow, group node.UiNodeGroup, - err error, + recoveryErr error, ) { s.d.Audit(). - WithError(err). + WithError(recoveryErr). WithRequest(r). WithField("recovery_flow", f). Info("Encountered self-service recovery error.") if f == nil { trace.SpanFromContext(r.Context()).AddEvent(events.NewRecoveryFailed(r.Context(), "", "")) - s.forward(w, r, nil, err) + s.forward(w, r, nil, recoveryErr) return } trace.SpanFromContext(r.Context()).AddEvent(events.NewRecoveryFailed(r.Context(), string(f.Type), f.Active.String())) - if e := new(flow.ExpiredError); errors.As(err, &e) { + if expiredError := new(flow.ExpiredError); errors.As(recoveryErr, &expiredError) { strategy, err := s.d.RecoveryStrategies(r.Context()).Strategy(f.Active.String()) if err != nil { strategy, err = s.d.GetActiveRecoveryStrategy(r.Context()) @@ -89,33 +89,48 @@ func (s *ErrorHandler) WriteFlowError( } } // create new flow because the old one is not valid - a, err := FromOldFlow(s.d.Config(), s.d.Config().SelfServiceFlowRecoveryRequestLifespan(r.Context()), s.d.GenerateCSRFToken(r), r, strategy, *f) + newFlow, err := FromOldFlow(s.d.Config(), s.d.Config().SelfServiceFlowRecoveryRequestLifespan(r.Context()), s.d.GenerateCSRFToken(r), r, strategy, *f) if err != nil { // failed to create a new session and redirect to it, handle that error as a new one s.WriteFlowError(w, r, f, group, err) return } - a.UI.Messages.Add(text.NewErrorValidationRecoveryFlowExpired(e.ExpiredAt)) - if err := s.d.RecoveryFlowPersister().CreateRecoveryFlow(r.Context(), a); err != nil { - s.forward(w, r, a, err) + newFlow.UI.Messages.Add(text.NewErrorValidationRecoveryFlowExpired(expiredError.ExpiredAt)) + if err := s.d.RecoveryFlowPersister().CreateRecoveryFlow(r.Context(), newFlow); err != nil { + s.forward(w, r, newFlow, err) return } - // We need to use the new flow, as that flow will be a browser flow. Bug fix for: - // - // https://github.com/ory/kratos/issues/2049!! - if a.Type == flow.TypeAPI || x.IsJSONRequest(r) { - http.Redirect(w, r, urlx.CopyWithQuery(urlx.AppendPaths(s.d.Config().SelfPublicURL(r.Context()), - RouteGetFlow), url.Values{"id": {a.ID.String()}}).String(), http.StatusSeeOther) + if s.d.Config().UseContinueWithTransitions(r.Context()) { + switch { + case newFlow.Type.IsAPI(): + expiredError.FlowID = newFlow.ID + s.d.Writer().WriteError(w, r, expiredError.WithContinueWith(flow.NewContinueWithRecoveryUI(newFlow))) + case x.IsJSONRequest(r): + http.Redirect(w, r, urlx.CopyWithQuery( + urlx.AppendPaths(s.d.Config().SelfPublicURL(r.Context()), RouteGetFlow), + url.Values{"id": {newFlow.ID.String()}}, + ).String(), http.StatusSeeOther) + default: + http.Redirect(w, r, newFlow.AppendTo(s.d.Config().SelfServiceFlowRecoveryUI(r.Context())).String(), http.StatusSeeOther) + } } else { - http.Redirect(w, r, a.AppendTo(s.d.Config().SelfServiceFlowRecoveryUI(r.Context())).String(), http.StatusSeeOther) + // We need to use the new flow, as that flow will be a browser flow. Bug fix for: + // + // https://github.com/ory/kratos/issues/2049!! + if newFlow.Type == flow.TypeAPI || x.IsJSONRequest(r) { + http.Redirect(w, r, urlx.CopyWithQuery(urlx.AppendPaths(s.d.Config().SelfPublicURL(r.Context()), + RouteGetFlow), url.Values{"id": {newFlow.ID.String()}}).String(), http.StatusSeeOther) + } else { + http.Redirect(w, r, newFlow.AppendTo(s.d.Config().SelfServiceFlowRecoveryUI(r.Context())).String(), http.StatusSeeOther) + } } return } f.UI.ResetMessages() - if err := f.UI.ParseError(group, err); err != nil { + if err := f.UI.ParseError(group, recoveryErr); err != nil { s.forward(w, r, f, err) return } @@ -136,7 +151,7 @@ func (s *ErrorHandler) WriteFlowError( s.forward(w, r, updatedFlow, innerErr) } - s.d.Writer().WriteCode(w, r, x.RecoverStatusCode(err, http.StatusBadRequest), updatedFlow) + s.d.Writer().WriteCode(w, r, x.RecoverStatusCode(recoveryErr, http.StatusBadRequest), updatedFlow) } func (s *ErrorHandler) forward(w http.ResponseWriter, r *http.Request, rr *Flow, err error) { diff --git a/selfservice/flow/recovery/error_test.go b/selfservice/flow/recovery/error_test.go index ec7af27676d5..432d149a04f1 100644 --- a/selfservice/flow/recovery/error_test.go +++ b/selfservice/flow/recovery/error_test.go @@ -12,6 +12,7 @@ import ( "github.com/gofrs/uuid" + "github.com/ory/x/ioutilx" "github.com/ory/x/jsonx" "github.com/ory/x/snapshotx" @@ -133,7 +134,7 @@ func TestHandleError(t *testing.T) { t.Run("case=expired error", func(t *testing.T) { t.Cleanup(reset) - recoveryFlow = newFlow(t, time.Minute, flow.TypeAPI) + recoveryFlow = newFlow(t, time.Minute, tc.t) flowError = flow.NewFlowExpiredError(anHourAgo) methodName = node.UiNodeGroup(recovery.RecoveryStrategyLink) @@ -255,7 +256,6 @@ func TestHandleError(t *testing.T) { }) t.Run("case=new flow uses strategy of old flow", func(t *testing.T) { - t.Cleanup(reset) recoveryFlow = &recovery.Flow{Type: flow.TypeBrowser, Active: "code"} @@ -268,7 +268,6 @@ func TestHandleError(t *testing.T) { }) t.Run("case=new flow uses current strategy if strategy of old flow does not exist", func(t *testing.T) { - t.Cleanup(reset) recoveryFlow = &recovery.Flow{Type: flow.TypeBrowser, Active: "not-valid"} @@ -281,7 +280,272 @@ func TestHandleError(t *testing.T) { }) t.Run("case=fails to retry flow if recovery strategy id is not valid", func(t *testing.T) { + t.Cleanup(func() { + reset() + conf.MustSet(ctx, config.ViperKeySelfServiceRecoveryUse, "code") + }) + + recoveryFlow = newFlow(t, 0, flow.TypeBrowser) + recoveryFlow.Active = "not-valid" + flowError = flow.NewFlowExpiredError(anHourAgo) + + conf.MustSet(ctx, config.ViperKeySelfServiceRecoveryUse, "not-valid") + sse, _ := expectErrorUI(t) + snapshotx.SnapshotT(t, sse) + }) + }) +} + +func TestHandleError_WithContinueWith(t *testing.T) { + ctx := context.Background() + conf, reg := internal.NewFastRegistryWithMocks(t) + conf.MustSet(ctx, config.ViperKeyUseContinueWithTransitions, true) + conf.MustSet(ctx, config.ViperKeySelfServiceRecoveryEnabled, true) + conf.MustSet(ctx, config.ViperKeySelfServiceRecoveryUse, "code") + + public, _ := testhelpers.NewKratosServer(t, reg) + + router := httprouter.New() + ts := httptest.NewServer(router) + t.Cleanup(ts.Close) + + testhelpers.NewRecoveryUIFlowEchoServer(t, reg) + testhelpers.NewErrorTestServer(t, reg) + + h := reg.RecoveryFlowErrorHandler() + sdk := testhelpers.NewSDKClient(public) + + var recoveryFlow *recovery.Flow + var flowError error + var methodName node.UiNodeGroup + router.GET("/error", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + h.WriteFlowError(w, r, recoveryFlow, methodName, flowError) + }) + + reset := func() { + recoveryFlow = nil + flowError = nil + methodName = "" + } + + newFlow := func(t *testing.T, ttl time.Duration, ft flow.Type) *recovery.Flow { + req := &http.Request{URL: urlx.ParseOrPanic("/")} + s, err := reg.GetActiveRecoveryStrategy(context.Background()) + require.NoError(t, err) + f, err := recovery.NewFlow(conf, ttl, x.FakeCSRFToken, req, s, ft) + require.NoError(t, err) + require.NoError(t, reg.RecoveryFlowPersister().CreateRecoveryFlow(context.Background(), f)) + f, err = reg.RecoveryFlowPersister().GetRecoveryFlow(context.Background(), f.ID) + require.NoError(t, err) + return f + } + + expectErrorUI := func(t *testing.T) (map[string]interface{}, *http.Response) { + res, err := ts.Client().Get(ts.URL + "/error") + require.NoError(t, err) + defer res.Body.Close() + require.Contains(t, res.Request.URL.String(), conf.SelfServiceFlowErrorURL(ctx).String()+"?id=") + + sse, _, err := sdk.FrontendApi.GetFlowError(context.Background()).Id(res.Request.URL.Query().Get("id")).Execute() + require.NoError(t, err) + + return sse.Error, nil + } + + anHourAgo := time.Now().Add(-time.Hour) + + t.Run("case=error with nil flow defaults to error ui redirect", func(t *testing.T) { + t.Cleanup(reset) + + flowError = herodot.ErrInternalServerError.WithReason("system error") + methodName = node.UiNodeGroup(recovery.RecoveryStrategyLink) + + sse, _ := expectErrorUI(t) + assertx.EqualAsJSON(t, flowError, sse) + }) + + t.Run("case=error with nil flow detects application/json", func(t *testing.T) { + t.Cleanup(reset) + + flowError = herodot.ErrInternalServerError.WithReason("system error") + methodName = node.UiNodeGroup(recovery.RecoveryStrategyLink) + + res, err := ts.Client().Do(testhelpers.NewHTTPGetJSONRequest(t, ts.URL+"/error")) + require.NoError(t, err) + defer res.Body.Close() + assert.Contains(t, res.Header.Get("Content-Type"), "application/json") + assert.NotContains(t, res.Request.URL.String(), conf.SelfServiceFlowErrorURL(ctx).String()+"?id=") + + body, err := io.ReadAll(res.Body) + require.NoError(t, err) + assert.Contains(t, string(body), "system error") + }) + + for _, tc := range []struct { + n string + t flow.Type + }{ + {"api", flow.TypeAPI}, + {"spa", flow.TypeBrowser}, + } { + t.Run("flow="+tc.n, func(t *testing.T) { + t.Run("case=expired error", func(t *testing.T) { + t.Cleanup(reset) + + recoveryFlow = newFlow(t, time.Minute, tc.t) + flowError = flow.NewFlowExpiredError(anHourAgo) + methodName = node.UiNodeGroup(recovery.RecoveryStrategyLink) + + res, err := ts.Client().Do(testhelpers.NewHTTPGetJSONRequest(t, ts.URL+"/error")) + require.NoError(t, err) + body := ioutilx.MustReadAll(res.Body) + switch tc.t { + case flow.TypeAPI: + require.Equal(t, http.StatusGone, res.StatusCode, "%s", body) + require.Len(t, gjson.GetBytes(body, "error.details.continue_with").Array(), 1, "%s", body) + require.Equal(t, "show_recovery_ui", gjson.GetBytes(body, "error.details.continue_with.0.action").String(), "%s", body) + id := gjson.GetBytes(body, "error.details.continue_with.0.flow.id").String() + res, err = ts.Client().Do(testhelpers.NewHTTPGetJSONRequest(t, public.URL+recovery.RouteGetFlow+"?id="+id)) + require.NoError(t, err) + body = ioutilx.MustReadAll(res.Body) + case flow.TypeBrowser: + require.Contains(t, res.Request.URL.String(), public.URL+recovery.RouteGetFlow, "%s", body) + require.Equal(t, http.StatusOK, res.StatusCode, "%+v", res.Request) + } + assert.Equal(t, int(text.ErrorValidationRecoveryFlowExpired), int(gjson.GetBytes(body, "ui.messages.0.id").Int()), string(body)) + assert.NotEqual(t, recoveryFlow.ID.String(), gjson.GetBytes(body, "id").String()) + }) + + t.Run("case=validation error", func(t *testing.T) { + t.Cleanup(reset) + + recoveryFlow = newFlow(t, time.Minute, tc.t) + flowError = schema.NewInvalidCredentialsError() + methodName = node.UiNodeGroup(recovery.RecoveryStrategyLink) + + res, err := ts.Client().Do(testhelpers.NewHTTPGetJSONRequest(t, ts.URL+"/error")) + require.NoError(t, err) + defer res.Body.Close() + require.Equal(t, http.StatusBadRequest, res.StatusCode) + + body, err := io.ReadAll(res.Body) + require.NoError(t, err) + assert.Equal(t, int(text.ErrorValidationInvalidCredentials), int(gjson.GetBytes(body, "ui.messages.0.id").Int()), "%s", body) + assert.Equal(t, recoveryFlow.ID.String(), gjson.GetBytes(body, "id").String()) + }) + + t.Run("case=generic error", func(t *testing.T) { + t.Cleanup(reset) + + recoveryFlow = newFlow(t, time.Minute, tc.t) + flowError = herodot.ErrInternalServerError.WithReason("system error") + methodName = node.UiNodeGroup(recovery.RecoveryStrategyLink) + + res, err := ts.Client().Do(testhelpers.NewHTTPGetJSONRequest(t, ts.URL+"/error")) + require.NoError(t, err) + defer res.Body.Close() + require.Equal(t, http.StatusInternalServerError, res.StatusCode) + + body, err := io.ReadAll(res.Body) + require.NoError(t, err) + assert.JSONEq(t, x.MustEncodeJSON(t, flowError), gjson.GetBytes(body, "error").Raw) + }) + + t.Run("case=fails if active strategy is disabled", func(t *testing.T) { + c, reg := internal.NewVeryFastRegistryWithoutDB(t) + c.Set(context.Background(), "selfservice.methods.code.enabled", false) + c.Set(context.Background(), config.ViperKeySelfServiceRecoveryUse, "code") + _, err := reg.GetActiveRecoveryStrategy(context.Background()) + recoveryFlow = newFlow(t, time.Minute, tc.t) + flowError = err + methodName = node.UiNodeGroup(recovery.RecoveryStrategyLink) + + res, err := ts.Client().Do(testhelpers.NewHTTPGetJSONRequest(t, ts.URL+"/error")) + require.NoError(t, err) + defer res.Body.Close() + require.Equal(t, http.StatusBadRequest, res.StatusCode) + + body, err := io.ReadAll(res.Body) + require.NoError(t, err) + + snapshotx.SnapshotTJSON(t, body, snapshotx.ExceptPaths("id", "expires_at", "issued_at", "ui.action", "ui.nodes.0.attributes.value")) + }) + }) + } + + t.Run("flow=browser", func(t *testing.T) { + expectRecoveryUI := func(t *testing.T) (*recovery.Flow, *http.Response) { + res, err := ts.Client().Get(ts.URL + "/error") + require.NoError(t, err) + defer res.Body.Close() + assert.Contains(t, res.Request.URL.String(), conf.SelfServiceFlowRecoveryUI(ctx).String()+"?flow=") + + rf, err := reg.RecoveryFlowPersister().GetRecoveryFlow(context.Background(), uuid.FromStringOrNil(res.Request.URL.Query().Get("flow"))) + require.NoError(t, err) + return rf, res + } + + t.Run("case=expired error", func(t *testing.T) { + t.Cleanup(reset) + + recoveryFlow = &recovery.Flow{Type: flow.TypeBrowser} + flowError = flow.NewFlowExpiredError(anHourAgo) + methodName = node.LinkGroup + + lf, _ := expectRecoveryUI(t) + require.Len(t, lf.UI.Messages, 1, "%s", jsonx.TestMarshalJSONString(t, lf)) + assert.Equal(t, int(text.ErrorValidationRecoveryFlowExpired), int(lf.UI.Messages[0].ID)) + }) + + t.Run("case=validation error", func(t *testing.T) { + t.Cleanup(reset) + + recoveryFlow = newFlow(t, time.Minute, flow.TypeBrowser) + flowError = schema.NewInvalidCredentialsError() + methodName = node.LinkGroup + + lf, _ := expectRecoveryUI(t) + require.NotEmpty(t, lf.UI, x.MustEncodeJSON(t, lf)) + require.Len(t, lf.UI.Messages, 1, x.MustEncodeJSON(t, lf)) + assert.Equal(t, int(text.ErrorValidationInvalidCredentials), int(lf.UI.Messages[0].ID), x.MustEncodeJSON(t, lf)) + }) + + t.Run("case=generic error", func(t *testing.T) { + t.Cleanup(reset) + recoveryFlow = newFlow(t, time.Minute, flow.TypeBrowser) + flowError = herodot.ErrInternalServerError.WithReason("system error") + methodName = node.LinkGroup + + sse, _ := expectErrorUI(t) + assertx.EqualAsJSON(t, flowError, sse) + }) + + t.Run("case=new flow uses strategy of old flow", func(t *testing.T) { + t.Cleanup(reset) + + recoveryFlow = &recovery.Flow{Type: flow.TypeBrowser, Active: "code"} + flowError = flow.NewFlowExpiredError(anHourAgo) + + lf, _ := expectRecoveryUI(t) + require.Len(t, lf.UI.Messages, 1, "%s", jsonx.TestMarshalJSONString(t, lf)) + assert.Equal(t, int(text.ErrorValidationRecoveryFlowExpired), int(lf.UI.Messages[0].ID)) + assert.Equal(t, recoveryFlow.Active.String(), lf.Active.String()) + }) + + t.Run("case=new flow uses current strategy if strategy of old flow does not exist", func(t *testing.T) { + t.Cleanup(reset) + + recoveryFlow = &recovery.Flow{Type: flow.TypeBrowser, Active: "not-valid"} + flowError = flow.NewFlowExpiredError(anHourAgo) + + lf, _ := expectRecoveryUI(t) + require.Len(t, lf.UI.Messages, 1, "%s", jsonx.TestMarshalJSONString(t, lf)) + assert.Equal(t, int(text.ErrorValidationRecoveryFlowExpired), int(lf.UI.Messages[0].ID)) + assert.Equal(t, "code", lf.Active.String()) + }) + + t.Run("case=fails to retry flow if recovery strategy id is not valid", func(t *testing.T) { t.Cleanup(func() { reset() conf.MustSet(ctx, config.ViperKeySelfServiceRecoveryUse, "code") diff --git a/selfservice/flow/recovery/flow.go b/selfservice/flow/recovery/flow.go index 3557c8652b8d..d5aed79ae0f3 100644 --- a/selfservice/flow/recovery/flow.go +++ b/selfservice/flow/recovery/flow.go @@ -100,6 +100,9 @@ type Flow struct { // This is needed, because we can not enforce these measures, if the flow has been initialized by someone else than // the user. DangerousSkipCSRFCheck bool `json:"-" faker:"-" db:"skip_csrf_check"` + + // Contains possible actions that could follow this flow + ContinueWith []flow.ContinueWith `json:"continue_with,omitempty" faker:"-" db:"-"` } var _ flow.Flow = new(Flow) @@ -147,7 +150,7 @@ func NewFlow(conf *config.Config, exp time.Duration, csrf string, r *http.Reques func FromOldFlow(conf *config.Config, exp time.Duration, csrf string, r *http.Request, strategy Strategy, of Flow) (*Flow, error) { f := of.Type // Using the same flow in the recovery/verification context can lead to using API flow in a verification/recovery email - if of.Type == flow.TypeAPI { + if of.Type == flow.TypeAPI && of.Active.String() == string(RecoveryStrategyLink) { f = flow.TypeBrowser } nf, err := NewFlow(conf, exp, csrf, r, strategy, f) diff --git a/selfservice/flow/recovery/flow_test.go b/selfservice/flow/recovery/flow_test.go index cab497c1b9a2..2f78a90b2f97 100644 --- a/selfservice/flow/recovery/flow_test.go +++ b/selfservice/flow/recovery/flow_test.go @@ -24,6 +24,8 @@ import ( "github.com/ory/kratos/selfservice/flow" "github.com/ory/kratos/selfservice/flow/recovery" + "github.com/ory/kratos/selfservice/strategy/code" + "github.com/ory/kratos/selfservice/strategy/link" ) func TestFlow(t *testing.T) { @@ -92,20 +94,37 @@ func TestFlowEncodeJSON(t *testing.T) { func TestFromOldFlow(t *testing.T) { ctx := context.Background() - conf := internal.NewConfigurationWithDefaults(t) + conf, reg := internal.NewVeryFastRegistryWithoutDB(t) r := http.Request{URL: &url.URL{Path: "/", RawQuery: "return_to=" + urlx.AppendPaths(conf.SelfPublicURL(ctx), "/self-service/login/browser").String()}, Host: "ory.sh"} - for _, ft := range []flow.Type{ - flow.TypeAPI, - flow.TypeBrowser, - } { - t.Run(fmt.Sprintf("case=original flow is %s", ft), func(t *testing.T) { - f, err := recovery.NewFlow(conf, 0, "csrf", &r, nil, ft) - require.NoError(t, err) - nF, err := recovery.FromOldFlow(conf, time.Duration(time.Hour), f.CSRFToken, &r, nil, *f) - require.NoError(t, err) - require.Equal(t, flow.TypeBrowser, nF.Type) - }) - } + t.Run("strategy=code", func(t *testing.T) { + for _, ft := range []flow.Type{ + flow.TypeAPI, + flow.TypeBrowser, + } { + t.Run(fmt.Sprintf("case=original flow is %s", ft), func(t *testing.T) { + f, err := recovery.NewFlow(conf, 0, "csrf", &r, code.NewStrategy(reg), ft) + require.NoError(t, err) + nF, err := recovery.FromOldFlow(conf, time.Duration(time.Hour), f.CSRFToken, &r, nil, *f) + require.NoError(t, err) + require.Equal(t, ft, nF.Type) + }) + } + }) + + t.Run("strategy=link", func(t *testing.T) { + for _, ft := range []flow.Type{ + flow.TypeAPI, + flow.TypeBrowser, + } { + t.Run(fmt.Sprintf("case=original flow is %s", ft), func(t *testing.T) { + f, err := recovery.NewFlow(conf, 0, "csrf", &r, link.NewStrategy(reg), ft) + require.NoError(t, err) + nF, err := recovery.FromOldFlow(conf, time.Duration(time.Hour), f.CSRFToken, &r, nil, *f) + require.NoError(t, err) + require.Equal(t, flow.TypeBrowser, nF.Type) + }) + } + }) } func TestFlowDontOverrideReturnTo(t *testing.T) { diff --git a/selfservice/flow/recovery/handler.go b/selfservice/flow/recovery/handler.go index 6c4fd21344a4..2a4c7f77dd01 100644 --- a/selfservice/flow/recovery/handler.go +++ b/selfservice/flow/recovery/handler.go @@ -103,7 +103,7 @@ func (h *Handler) RegisterAdminRoutes(admin *x.RouterAdmin) { // // If a valid provided session cookie or session token is provided, a 400 Bad Request error. // -// To fetch an existing recovery flow call `/self-service/recovery/flows?flow=`. +// On an existing recovery flow, use the `getRecoveryFlow` API endpoint. // // You MUST NOT use this endpoint in client-side (Single Page Apps, ReactJS, AngularJS) nor server-side (Java Server // Pages, NodeJS, PHP, Golang, ...) browser applications. Using this endpoint in these applications will make @@ -130,23 +130,23 @@ func (h *Handler) createNativeRecoveryFlow(w http.ResponseWriter, r *http.Reques return } - req, err := NewFlow(h.d.Config(), h.d.Config().SelfServiceFlowRecoveryRequestLifespan(r.Context()), h.d.GenerateCSRFToken(r), r, activeRecoveryStrategy, flow.TypeAPI) + f, err := NewFlow(h.d.Config(), h.d.Config().SelfServiceFlowRecoveryRequestLifespan(r.Context()), h.d.GenerateCSRFToken(r), r, activeRecoveryStrategy, flow.TypeAPI) if err != nil { h.d.Writer().WriteError(w, r, err) return } - if err := h.d.RecoveryExecutor().PreRecoveryHook(w, r, req); err != nil { + if err := h.d.RecoveryExecutor().PreRecoveryHook(w, r, f); err != nil { h.d.Writer().WriteError(w, r, err) return } - if err := h.d.RecoveryFlowPersister().CreateRecoveryFlow(r.Context(), req); err != nil { + if err := h.d.RecoveryFlowPersister().CreateRecoveryFlow(r.Context(), f); err != nil { h.d.Writer().WriteError(w, r, err) return } - h.d.Writer().Write(w, r, req) + h.d.Writer().Write(w, r, f) } // Create Browser Recovery Flow Parameters @@ -305,9 +305,9 @@ func (h *Handler) getRecoveryFlow(w http.ResponseWriter, r *http.Request, _ http WithDetail("return_to", f.ReturnTo))) return } - h.d.Writer().WriteError(w, r, errors.WithStack(x.ErrGone. - WithReason("The recovery flow has expired. Call the recovery flow init API endpoint to initialize a new recovery flow."). - WithDetail("api", urlx.AppendPaths(h.d.Config().SelfPublicURL(r.Context()), RouteInitAPIFlow).String()))) + + h.d.Writer().WriteError(w, r, flow.NewFlowExpiredError(f.ExpiresAt). + WithDetail("api", urlx.AppendPaths(h.d.Config().SelfPublicURL(r.Context()), RouteInitAPIFlow).String())) return } @@ -364,9 +364,9 @@ type updateRecoveryFlowBody struct{} // swagger:route POST /self-service/recovery frontend updateRecoveryFlow // -// # Complete Recovery Flow +// # Update Recovery Flow // -// Use this endpoint to complete a recovery flow. This endpoint +// Use this endpoint to update a recovery flow. This endpoint // behaves differently for API and browser flows and has several states: // // - `choose_method` expects `flow` (in the URL query) and `email` (in the body) to be sent diff --git a/selfservice/strategy/code/.snapshots/TestRecovery_WithContinueWith-description=should_set_all_the_correct_recovery_payloads-type=api.json b/selfservice/strategy/code/.snapshots/TestRecovery_WithContinueWith-description=should_set_all_the_correct_recovery_payloads-type=api.json new file mode 100644 index 000000000000..ec1092ad77a6 --- /dev/null +++ b/selfservice/strategy/code/.snapshots/TestRecovery_WithContinueWith-description=should_set_all_the_correct_recovery_payloads-type=api.json @@ -0,0 +1,53 @@ +[ + { + "attributes": { + "disabled": false, + "name": "csrf_token", + "node_type": "input", + "required": true, + "type": "hidden" + }, + "group": "default", + "messages": [], + "meta": {}, + "type": "input" + }, + { + "attributes": { + "disabled": false, + "name": "email", + "node_type": "input", + "required": true, + "type": "email" + }, + "group": "code", + "messages": [], + "meta": { + "label": { + "id": 1070007, + "text": "Email", + "type": "info" + } + }, + "type": "input" + }, + { + "attributes": { + "disabled": false, + "name": "method", + "node_type": "input", + "type": "submit", + "value": "code" + }, + "group": "code", + "messages": [], + "meta": { + "label": { + "id": 1070005, + "text": "Submit", + "type": "info" + } + }, + "type": "input" + } +] diff --git a/selfservice/strategy/code/.snapshots/TestRecovery_WithContinueWith-description=should_set_all_the_correct_recovery_payloads-type=browser.json b/selfservice/strategy/code/.snapshots/TestRecovery_WithContinueWith-description=should_set_all_the_correct_recovery_payloads-type=browser.json new file mode 100644 index 000000000000..ec1092ad77a6 --- /dev/null +++ b/selfservice/strategy/code/.snapshots/TestRecovery_WithContinueWith-description=should_set_all_the_correct_recovery_payloads-type=browser.json @@ -0,0 +1,53 @@ +[ + { + "attributes": { + "disabled": false, + "name": "csrf_token", + "node_type": "input", + "required": true, + "type": "hidden" + }, + "group": "default", + "messages": [], + "meta": {}, + "type": "input" + }, + { + "attributes": { + "disabled": false, + "name": "email", + "node_type": "input", + "required": true, + "type": "email" + }, + "group": "code", + "messages": [], + "meta": { + "label": { + "id": 1070007, + "text": "Email", + "type": "info" + } + }, + "type": "input" + }, + { + "attributes": { + "disabled": false, + "name": "method", + "node_type": "input", + "type": "submit", + "value": "code" + }, + "group": "code", + "messages": [], + "meta": { + "label": { + "id": 1070005, + "text": "Submit", + "type": "info" + } + }, + "type": "input" + } +] diff --git a/selfservice/strategy/code/.snapshots/TestRecovery_WithContinueWith-description=should_set_all_the_correct_recovery_payloads-type=spa.json b/selfservice/strategy/code/.snapshots/TestRecovery_WithContinueWith-description=should_set_all_the_correct_recovery_payloads-type=spa.json new file mode 100644 index 000000000000..ec1092ad77a6 --- /dev/null +++ b/selfservice/strategy/code/.snapshots/TestRecovery_WithContinueWith-description=should_set_all_the_correct_recovery_payloads-type=spa.json @@ -0,0 +1,53 @@ +[ + { + "attributes": { + "disabled": false, + "name": "csrf_token", + "node_type": "input", + "required": true, + "type": "hidden" + }, + "group": "default", + "messages": [], + "meta": {}, + "type": "input" + }, + { + "attributes": { + "disabled": false, + "name": "email", + "node_type": "input", + "required": true, + "type": "email" + }, + "group": "code", + "messages": [], + "meta": { + "label": { + "id": 1070007, + "text": "Email", + "type": "info" + } + }, + "type": "input" + }, + { + "attributes": { + "disabled": false, + "name": "method", + "node_type": "input", + "type": "submit", + "value": "code" + }, + "group": "code", + "messages": [], + "meta": { + "label": { + "id": 1070005, + "text": "Submit", + "type": "info" + } + }, + "type": "input" + } +] diff --git a/selfservice/strategy/code/.snapshots/TestRecovery_WithContinueWith-description=should_set_all_the_correct_recovery_payloads_after_submission-type=api.json b/selfservice/strategy/code/.snapshots/TestRecovery_WithContinueWith-description=should_set_all_the_correct_recovery_payloads_after_submission-type=api.json new file mode 100644 index 000000000000..dbf1dcd2cbb7 --- /dev/null +++ b/selfservice/strategy/code/.snapshots/TestRecovery_WithContinueWith-description=should_set_all_the_correct_recovery_payloads_after_submission-type=api.json @@ -0,0 +1,86 @@ +[ + { + "type": "input", + "group": "default", + "attributes": { + "name": "csrf_token", + "type": "hidden", + "required": true, + "disabled": false, + "node_type": "input" + }, + "messages": [], + "meta": {} + }, + { + "type": "input", + "group": "code", + "attributes": { + "name": "code", + "type": "text", + "required": true, + "pattern": "[0-9]+", + "disabled": false, + "node_type": "input" + }, + "messages": [], + "meta": { + "label": { + "id": 1070010, + "text": "Recovery code", + "type": "info" + } + } + }, + { + "type": "input", + "group": "code", + "attributes": { + "name": "method", + "type": "hidden", + "value": "code", + "disabled": false, + "node_type": "input" + }, + "messages": [], + "meta": {} + }, + { + "type": "input", + "group": "code", + "attributes": { + "name": "method", + "type": "submit", + "value": "code", + "disabled": false, + "node_type": "input" + }, + "messages": [], + "meta": { + "label": { + "id": 1070005, + "text": "Submit", + "type": "info" + } + } + }, + { + "type": "input", + "group": "code", + "attributes": { + "name": "email", + "type": "submit", + "value": "test@ory.sh", + "disabled": false, + "node_type": "input" + }, + "messages": [], + "meta": { + "label": { + "id": 1070008, + "text": "Resend code", + "type": "info" + } + } + } +] diff --git a/selfservice/strategy/code/.snapshots/TestRecovery_WithContinueWith-description=should_set_all_the_correct_recovery_payloads_after_submission-type=browser.json b/selfservice/strategy/code/.snapshots/TestRecovery_WithContinueWith-description=should_set_all_the_correct_recovery_payloads_after_submission-type=browser.json new file mode 100644 index 000000000000..dbf1dcd2cbb7 --- /dev/null +++ b/selfservice/strategy/code/.snapshots/TestRecovery_WithContinueWith-description=should_set_all_the_correct_recovery_payloads_after_submission-type=browser.json @@ -0,0 +1,86 @@ +[ + { + "type": "input", + "group": "default", + "attributes": { + "name": "csrf_token", + "type": "hidden", + "required": true, + "disabled": false, + "node_type": "input" + }, + "messages": [], + "meta": {} + }, + { + "type": "input", + "group": "code", + "attributes": { + "name": "code", + "type": "text", + "required": true, + "pattern": "[0-9]+", + "disabled": false, + "node_type": "input" + }, + "messages": [], + "meta": { + "label": { + "id": 1070010, + "text": "Recovery code", + "type": "info" + } + } + }, + { + "type": "input", + "group": "code", + "attributes": { + "name": "method", + "type": "hidden", + "value": "code", + "disabled": false, + "node_type": "input" + }, + "messages": [], + "meta": {} + }, + { + "type": "input", + "group": "code", + "attributes": { + "name": "method", + "type": "submit", + "value": "code", + "disabled": false, + "node_type": "input" + }, + "messages": [], + "meta": { + "label": { + "id": 1070005, + "text": "Submit", + "type": "info" + } + } + }, + { + "type": "input", + "group": "code", + "attributes": { + "name": "email", + "type": "submit", + "value": "test@ory.sh", + "disabled": false, + "node_type": "input" + }, + "messages": [], + "meta": { + "label": { + "id": 1070008, + "text": "Resend code", + "type": "info" + } + } + } +] diff --git a/selfservice/strategy/code/.snapshots/TestRecovery_WithContinueWith-description=should_set_all_the_correct_recovery_payloads_after_submission-type=spa.json b/selfservice/strategy/code/.snapshots/TestRecovery_WithContinueWith-description=should_set_all_the_correct_recovery_payloads_after_submission-type=spa.json new file mode 100644 index 000000000000..dbf1dcd2cbb7 --- /dev/null +++ b/selfservice/strategy/code/.snapshots/TestRecovery_WithContinueWith-description=should_set_all_the_correct_recovery_payloads_after_submission-type=spa.json @@ -0,0 +1,86 @@ +[ + { + "type": "input", + "group": "default", + "attributes": { + "name": "csrf_token", + "type": "hidden", + "required": true, + "disabled": false, + "node_type": "input" + }, + "messages": [], + "meta": {} + }, + { + "type": "input", + "group": "code", + "attributes": { + "name": "code", + "type": "text", + "required": true, + "pattern": "[0-9]+", + "disabled": false, + "node_type": "input" + }, + "messages": [], + "meta": { + "label": { + "id": 1070010, + "text": "Recovery code", + "type": "info" + } + } + }, + { + "type": "input", + "group": "code", + "attributes": { + "name": "method", + "type": "hidden", + "value": "code", + "disabled": false, + "node_type": "input" + }, + "messages": [], + "meta": {} + }, + { + "type": "input", + "group": "code", + "attributes": { + "name": "method", + "type": "submit", + "value": "code", + "disabled": false, + "node_type": "input" + }, + "messages": [], + "meta": { + "label": { + "id": 1070005, + "text": "Submit", + "type": "info" + } + } + }, + { + "type": "input", + "group": "code", + "attributes": { + "name": "email", + "type": "submit", + "value": "test@ory.sh", + "disabled": false, + "node_type": "input" + }, + "messages": [], + "meta": { + "label": { + "id": 1070008, + "text": "Resend code", + "type": "info" + } + } + } +] diff --git a/selfservice/strategy/code/strategy.go b/selfservice/strategy/code/strategy.go index 678a2bb5d6a2..8b21a89a69e2 100644 --- a/selfservice/strategy/code/strategy.go +++ b/selfservice/strategy/code/strategy.go @@ -102,6 +102,7 @@ type ( LoginCodePersistenceProvider schema.IdentityTraitsProvider + session.PersistenceProvider sessiontokenexchange.PersistenceProvider diff --git a/selfservice/strategy/code/strategy_recovery.go b/selfservice/strategy/code/strategy_recovery.go index 6d75e065e7d1..1924247179a9 100644 --- a/selfservice/strategy/code/strategy_recovery.go +++ b/selfservice/strategy/code/strategy_recovery.go @@ -9,14 +9,12 @@ import ( "time" "github.com/gofrs/uuid" - "github.com/julienschmidt/httprouter" "github.com/pkg/errors" "go.opentelemetry.io/otel/attribute" "github.com/ory/herodot" "github.com/ory/x/decoderx" "github.com/ory/x/otelx" - "github.com/ory/x/sqlcon" "github.com/ory/x/sqlxx" "github.com/ory/x/urlx" @@ -24,7 +22,6 @@ import ( "github.com/ory/kratos/schema" "github.com/ory/kratos/selfservice/flow" "github.com/ory/kratos/selfservice/flow/recovery" - "github.com/ory/kratos/selfservice/strategy" "github.com/ory/kratos/session" "github.com/ory/kratos/text" "github.com/ory/kratos/ui/container" @@ -32,24 +29,10 @@ import ( "github.com/ory/kratos/x" ) -const ( - RouteAdminCreateRecoveryCode = "/recovery/code" -) - func (s *Strategy) RecoveryStrategyID() string { return string(recovery.RecoveryStrategyCode) } -func (s *Strategy) RegisterPublicRecoveryRoutes(public *x.RouterPublic) { - s.deps.CSRFHandler().IgnorePath(RouteAdminCreateRecoveryCode) - public.POST(RouteAdminCreateRecoveryCode, x.RedirectToAdminRoute(s.deps)) -} - -func (s *Strategy) RegisterAdminRecoveryRoutes(admin *x.RouterAdmin) { - wrappedCreateRecoveryCode := strategy.IsDisabled(s.deps, s.RecoveryStrategyID(), s.createRecoveryCodeForIdentity) - admin.POST(RouteAdminCreateRecoveryCode, wrappedCreateRecoveryCode) -} - func (s *Strategy) PopulateRecoveryMethod(r *http.Request, f *recovery.Flow) error { f.UI.SetCSRF(s.deps.GenerateCSRFToken(r)) f.UI.GetNodes().Upsert( @@ -64,182 +47,6 @@ func (s *Strategy) PopulateRecoveryMethod(r *http.Request, f *recovery.Flow) err return nil } -// Create Recovery Code for Identity Parameters -// -// swagger:parameters createRecoveryCodeForIdentity -// -//nolint:deadcode,unused -//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions -type createRecoveryCodeForIdentity struct { - // in: body - Body createRecoveryCodeForIdentityBody -} - -// Create Recovery Code for Identity Request Body -// -// swagger:model createRecoveryCodeForIdentityBody -type createRecoveryCodeForIdentityBody struct { - // Identity to Recover - // - // The identity's ID you wish to recover. - // - // required: true - IdentityID uuid.UUID `json:"identity_id"` - - // Code Expires In - // - // The recovery code will expire after that amount of time has passed. Defaults to the configuration value of - // `selfservice.methods.code.config.lifespan`. - // - // - // pattern: ^([0-9]+(ns|us|ms|s|m|h))*$ - // example: - // - 1h - // - 1m - // - 1s - ExpiresIn string `json:"expires_in"` -} - -// Recovery Code for Identity -// -// Used when an administrator creates a recovery code for an identity. -// -// swagger:model recoveryCodeForIdentity -// -//nolint:deadcode,unused -//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions -type recoveryCodeForIdentity struct { - // RecoveryLink with flow - // - // This link opens the recovery UI with an empty `code` field. - // - // required: true - // format: uri - RecoveryLink string `json:"recovery_link"` - - // RecoveryCode is the code that can be used to recover the account - // - // required: true - RecoveryCode string `json:"recovery_code"` - - // Expires At is the timestamp of when the recovery flow expires - // - // The timestamp when the recovery link expires. - ExpiresAt time.Time `json:"expires_at"` -} - -// swagger:route POST /admin/recovery/code identity createRecoveryCodeForIdentity -// -// # Create a Recovery Code -// -// This endpoint creates a recovery code which should be given to the user in order for them to recover -// (or activate) their account. -// -// Consumes: -// - application/json -// -// Produces: -// - application/json -// -// Schemes: http, https -// -// Security: -// oryAccessToken: -// -// Responses: -// 201: recoveryCodeForIdentity -// 400: errorGeneric -// 404: errorGeneric -// default: errorGeneric -func (s *Strategy) createRecoveryCodeForIdentity(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { - var p createRecoveryCodeForIdentityBody - if err := s.dx.Decode(r, &p, decoderx.HTTPJSONDecoder()); err != nil { - s.deps.Writer().WriteError(w, r, err) - return - } - - ctx := r.Context() - config := s.deps.Config() - - expiresIn := config.SelfServiceCodeMethodLifespan(ctx) - if len(p.ExpiresIn) > 0 { - // If an expiration of the code was supplied use it instead of the default duration - var err error - expiresIn, err = time.ParseDuration(p.ExpiresIn) - if err != nil { - s.deps.Writer().WriteError(w, r, errors.WithStack(herodot. - ErrBadRequest. - WithReasonf(`Unable to parse "expires_in" whose format should match "[0-9]+(ns|us|ms|s|m|h)" but did not: %s`, p.ExpiresIn))) - return - } - } - - if time.Now().Add(expiresIn).Before(time.Now()) { - s.deps.Writer().WriteError(w, r, errors.WithStack(herodot.ErrBadRequest.WithReasonf(`Value from "expires_in" must result to a future time: %s`, p.ExpiresIn))) - return - } - - recoveryFlow, err := recovery.NewFlow(config, expiresIn, s.deps.GenerateCSRFToken(r), r, s, flow.TypeBrowser) - if err != nil { - s.deps.Writer().WriteError(w, r, err) - return - } - recoveryFlow.DangerousSkipCSRFCheck = true - recoveryFlow.State = flow.StateEmailSent - recoveryFlow.UI.Nodes = node.Nodes{} - recoveryFlow.UI.Nodes.Append(node.NewInputField("code", nil, node.CodeGroup, node.InputAttributeTypeText, node.WithRequiredInputAttribute). - WithMetaLabel(text.NewInfoNodeLabelRecoveryCode()), - ) - - recoveryFlow.UI.Nodes. - Append(node.NewInputField("method", s.RecoveryStrategyID(), node.CodeGroup, node.InputAttributeTypeSubmit). - WithMetaLabel(text.NewInfoNodeLabelSubmit())) - - if err := s.deps.RecoveryFlowPersister().CreateRecoveryFlow(ctx, recoveryFlow); err != nil { - s.deps.Writer().WriteError(w, r, err) - return - } - - id, err := s.deps.IdentityPool().GetIdentity(ctx, p.IdentityID, identity.ExpandDefault) - if notFoundErr := sqlcon.ErrNoRows; errors.As(err, ¬FoundErr) { - s.deps.Writer().WriteError(w, r, notFoundErr.WithReasonf("could not find identity")) - return - } else if err != nil { - s.deps.Writer().WriteError(w, r, err) - return - } - - rawCode := GenerateCode() - - if _, err := s.deps.RecoveryCodePersister().CreateRecoveryCode(ctx, &CreateRecoveryCodeParams{ - RawCode: rawCode, - CodeType: RecoveryCodeTypeAdmin, - ExpiresIn: expiresIn, - FlowID: recoveryFlow.ID, - IdentityID: id.ID, - }); err != nil { - s.deps.Writer().WriteError(w, r, err) - return - } - - s.deps.Audit(). - WithField("identity_id", id.ID). - WithSensitiveField("recovery_code", rawCode). - Info("A recovery code has been created.") - - body := &recoveryCodeForIdentity{ - ExpiresAt: recoveryFlow.ExpiresAt.UTC(), - RecoveryLink: urlx.CopyWithQuery( - s.deps.Config().SelfServiceFlowRecoveryUI(ctx), - url.Values{ - "flow": {recoveryFlow.ID.String()}, - }).String(), - RecoveryCode: rawCode, - } - - s.deps.Writer().WriteCode(w, r, http.StatusCreated, body, herodot.UnescapedHTML) -} - // Update Recovery Flow with Code Method // // swagger:model updateRecoveryFlowWithCodeMethod @@ -307,7 +114,7 @@ func (s *Strategy) Recover(w http.ResponseWriter, r *http.Request, f *recovery.F } else if err := flow.EnsureCSRF(s.deps, r, f.Type, s.deps.Config().DisableAPIFlowEnforcement(ctx), s.deps.GenerateCSRFToken, body.CSRFToken); err != nil { // If a CSRF violation occurs the flow is most likely FUBAR, as the user either lost the CSRF token, or an attack occured. // In this case, we just issue a new flow and "abandon" the old flow. - return s.retryRecoveryFlowWithError(w, r, flow.TypeBrowser, err) + return s.retryRecoveryFlow(w, r, flow.TypeBrowser, RetryWithError(err)) } sID := s.RecoveryStrategyID() @@ -352,9 +159,9 @@ func (s *Strategy) Recover(w http.ResponseWriter, r *http.Request, f *recovery.F return s.recoveryHandleFormSubmission(w, r, recoveryFlow, body) case flow.StatePassedChallenge: // was already handled, do not allow retry - return s.retryRecoveryFlowWithMessage(w, r, recoveryFlow.Type, text.NewErrorValidationRecoveryRetrySuccess()) + return s.retryRecoveryFlow(w, r, recoveryFlow.Type, RetryWithMessage(text.NewErrorValidationRecoveryRetrySuccess())) default: - return s.retryRecoveryFlowWithMessage(w, r, recoveryFlow.Type, text.NewErrorValidationRecoveryStateFailure()) + return s.retryRecoveryFlow(w, r, recoveryFlow.Type, RetryWithMessage(text.NewErrorValidationRecoveryStateFailure())) } } @@ -369,27 +176,34 @@ func (s *Strategy) recoveryIssueSession(w http.ResponseWriter, r *http.Request, Valid: true, } if err := s.deps.RecoveryFlowPersister().UpdateRecoveryFlow(ctx, f); err != nil { - return s.retryRecoveryFlowWithError(w, r, f.Type, err) + return s.retryRecoveryFlow(w, r, f.Type, RetryWithError(err)) } sess, err := session.NewActiveSession(r, id, s.deps.Config(), time.Now().UTC(), identity.CredentialsTypeRecoveryCode, identity.AuthenticatorAssuranceLevel1) if err != nil { - return s.retryRecoveryFlowWithError(w, r, f.Type, err) + return s.retryRecoveryFlow(w, r, f.Type, RetryWithError(err)) } if err := s.deps.RecoveryExecutor().PostRecoveryHook(w, r, f, sess); err != nil { - return s.retryRecoveryFlowWithError(w, r, f.Type, err) + return s.retryRecoveryFlow(w, r, f.Type, RetryWithError(err)) } - // TODO: How does this work with Mobile? - if err := s.deps.SessionManager().UpsertAndIssueCookie(ctx, w, r, sess); err != nil { - return s.retryRecoveryFlowWithError(w, r, f.Type, err) + switch f.Type { + case flow.TypeBrowser: + if err := s.deps.SessionManager().UpsertAndIssueCookie(ctx, w, r, sess); err != nil { + return s.retryRecoveryFlow(w, r, f.Type, RetryWithError(err)) + } + case flow.TypeAPI: + if err := s.deps.SessionPersister().UpsertSession(r.Context(), sess); err != nil { + return s.retryRecoveryFlow(w, r, f.Type, RetryWithError(err)) + } + f.ContinueWith = append(f.ContinueWith, flow.NewContinueWithSetToken(sess.Token)) } sf, err := s.deps.SettingsHandler().NewFlow(w, r, sess.Identity, f.Type) if err != nil { - return s.retryRecoveryFlowWithError(w, r, f.Type, err) + return s.retryRecoveryFlow(w, r, f.Type, RetryWithError(err)) } returnToURL := s.deps.Config().SelfServiceFlowRecoveryReturnTo(r.Context(), nil) @@ -399,20 +213,32 @@ func (s *Strategy) recoveryIssueSession(w http.ResponseWriter, r *http.Request, } sf.RequestURL, err = x.TakeOverReturnToParameter(f.RequestURL, sf.RequestURL, returnTo) if err != nil { - return s.retryRecoveryFlowWithError(w, r, flow.TypeBrowser, err) + return s.retryRecoveryFlow(w, r, f.Type, RetryWithError(err)) } config := s.deps.Config() sf.UI.Messages.Set(text.NewRecoverySuccessful(time.Now().Add(config.SelfServiceFlowSettingsPrivilegedSessionMaxAge(ctx)))) if err := s.deps.SettingsFlowPersister().UpdateSettingsFlow(r.Context(), sf); err != nil { - return s.retryRecoveryFlowWithError(w, r, f.Type, err) - } - - if x.IsJSONRequest(r) { - s.deps.Writer().WriteError(w, r, flow.NewBrowserLocationChangeRequiredError(sf.AppendTo(s.deps.Config().SelfServiceFlowSettingsUI(r.Context())).String())) + return s.retryRecoveryFlow(w, r, f.Type, RetryWithError(err)) + } + + if s.deps.Config().UseContinueWithTransitions(ctx) { + switch { + case f.Type.IsAPI(): + fallthrough + case x.IsJSONRequest(r): + f.ContinueWith = append(f.ContinueWith, flow.NewContinueWithSettingsUI(sf)) + s.deps.Writer().Write(w, r, f) + default: + http.Redirect(w, r, sf.AppendTo(s.deps.Config().SelfServiceFlowSettingsUI(r.Context())).String(), http.StatusSeeOther) + } } else { - http.Redirect(w, r, sf.AppendTo(s.deps.Config().SelfServiceFlowSettingsUI(r.Context())).String(), http.StatusSeeOther) + if x.IsJSONRequest(r) { + s.deps.Writer().WriteError(w, r, flow.NewBrowserLocationChangeRequiredError(sf.AppendTo(s.deps.Config().SelfServiceFlowSettingsUI(r.Context())).String())) + } else { + http.Redirect(w, r, sf.AppendTo(s.deps.Config().SelfServiceFlowSettingsUI(r.Context())).String(), http.StatusSeeOther) + } } return errors.WithStack(flow.ErrCompletedByStrategy) @@ -425,13 +251,13 @@ func (s *Strategy) recoveryUseCode(w http.ResponseWriter, r *http.Request, body f.UI.Messages.Clear() f.UI.Messages.Add(text.NewErrorValidationRecoveryCodeInvalidOrAlreadyUsed()) if err := s.deps.RecoveryFlowPersister().UpdateRecoveryFlow(ctx, f); err != nil { - return s.retryRecoveryFlowWithError(w, r, f.Type, err) + return s.retryRecoveryFlow(w, r, f.Type, RetryWithError(err)) } // No error return nil } else if err != nil { - return s.retryRecoveryFlowWithError(w, r, f.Type, err) + return s.retryRecoveryFlow(w, r, f.Type, RetryWithError(err)) } recovered, err := s.deps.IdentityPool().GetIdentity(ctx, code.IdentityID, identity.ExpandDefault) @@ -449,64 +275,79 @@ func (s *Strategy) recoveryUseCode(w http.ResponseWriter, r *http.Request, body return s.recoveryIssueSession(w, r, f, recovered) } -func (s *Strategy) retryRecoveryFlowWithMessage(w http.ResponseWriter, r *http.Request, ft flow.Type, message *text.Message) error { - s.deps.Logger(). - WithRequest(r). - WithField("message", message). - Debug("A recovery flow is being retried because a validation error occurred.") +type retry struct { + err error + message *text.Message +} - ctx := r.Context() - config := s.deps.Config() +type RetryOption func(*retry) - f, err := recovery.NewFlow(config, config.SelfServiceFlowRecoveryRequestLifespan(ctx), s.deps.CSRFHandler().RegenerateToken(w, r), r, s, ft) - if err != nil { - return err +func RetryWithError(err error) RetryOption { + return func(r *retry) { + r.err = err } +} - f.UI.Messages.Add(message) - if err := s.deps.RecoveryFlowPersister().CreateRecoveryFlow(ctx, f); err != nil { - return err +func RetryWithMessage(msg *text.Message) RetryOption { + return func(r *retry) { + r.message = msg } +} - if x.IsJSONRequest(r) { - http.Redirect(w, r, urlx.CopyWithQuery(urlx.AppendPaths(config.SelfPublicURL(ctx), - recovery.RouteGetFlow), url.Values{"id": {f.ID.String()}}).String(), http.StatusSeeOther) - } else { - http.Redirect(w, r, f.AppendTo(config.SelfServiceFlowRecoveryUI(ctx)).String(), http.StatusSeeOther) - } +func (s *Strategy) retryRecoveryFlow(w http.ResponseWriter, r *http.Request, ft flow.Type, opts ...RetryOption) error { + retryOptions := retry{} - return errors.WithStack(flow.ErrCompletedByStrategy) -} + for _, o := range opts { + o(&retryOptions) + } -func (s *Strategy) retryRecoveryFlowWithError(w http.ResponseWriter, r *http.Request, ft flow.Type, recErr error) error { s.deps.Logger(). WithRequest(r). - WithError(recErr). + WithField("message", retryOptions.message). + WithError(retryOptions.err). Debug("A recovery flow is being retried because a validation error occurred.") ctx := r.Context() config := s.deps.Config() - if expired := new(flow.ExpiredError); errors.As(recErr, &expired) { - return s.retryRecoveryFlowWithMessage(w, r, ft, text.NewErrorValidationRecoveryFlowExpired(expired.ExpiredAt)) - } - f, err := recovery.NewFlow(config, config.SelfServiceFlowRecoveryRequestLifespan(ctx), s.deps.CSRFHandler().RegenerateToken(w, r), r, s, ft) if err != nil { return err } - if err := f.UI.ParseError(node.CodeGroup, recErr); err != nil { - return err + + if retryOptions.message != nil { + f.UI.Messages.Add(retryOptions.message) + } + + if retryOptions.err != nil { + if expired := new(flow.ExpiredError); errors.As(retryOptions.err, &expired) { + f.UI.Messages.Add(text.NewErrorValidationRecoveryFlowExpired(expired.ExpiredAt)) + } else if err := f.UI.ParseError(node.CodeGroup, retryOptions.err); err != nil { + return err + } } if err := s.deps.RecoveryFlowPersister().CreateRecoveryFlow(ctx, f); err != nil { return err } - if x.IsJSONRequest(r) { - http.Redirect(w, r, urlx.CopyWithQuery(urlx.AppendPaths(config.SelfPublicURL(ctx), - recovery.RouteGetFlow), url.Values{"id": {f.ID.String()}}).String(), http.StatusSeeOther) + if s.deps.Config().UseContinueWithTransitions(ctx) { + switch { + case x.IsJSONRequest(r): + rErr := new(herodot.DefaultError) + if !errors.As(retryOptions.err, &rErr) { + rErr = rErr.WithError(retryOptions.err.Error()) + } + s.deps.Writer().WriteError(w, r, flow.ErrorWithContinueWith(rErr, flow.NewContinueWithRecoveryUI(f))) + default: + http.Redirect(w, r, f.AppendTo(config.SelfServiceFlowRecoveryUI(ctx)).String(), http.StatusSeeOther) + } } else { - http.Redirect(w, r, f.AppendTo(config.SelfServiceFlowRecoveryUI(ctx)).String(), http.StatusSeeOther) + if x.IsJSONRequest(r) { + http.Redirect(w, r, urlx.CopyWithQuery(urlx.AppendPaths(config.SelfPublicURL(ctx), + recovery.RouteGetFlow), url.Values{"id": {f.ID.String()}}).String(), http.StatusSeeOther) + } else { + http.Redirect(w, r, f.AppendTo(config.SelfServiceFlowRecoveryUI(ctx)).String(), http.StatusSeeOther) + } } return errors.WithStack(flow.ErrCompletedByStrategy) diff --git a/selfservice/strategy/code/strategy_recovery_admin.go b/selfservice/strategy/code/strategy_recovery_admin.go new file mode 100644 index 000000000000..8964682afe30 --- /dev/null +++ b/selfservice/strategy/code/strategy_recovery_admin.go @@ -0,0 +1,216 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package code + +import ( + "net/http" + "net/url" + "time" + + "github.com/gofrs/uuid" + "github.com/julienschmidt/httprouter" + "github.com/pkg/errors" + + "github.com/ory/herodot" + "github.com/ory/kratos/identity" + "github.com/ory/kratos/selfservice/flow" + "github.com/ory/kratos/selfservice/flow/recovery" + "github.com/ory/kratos/selfservice/strategy" + "github.com/ory/kratos/text" + "github.com/ory/kratos/ui/node" + "github.com/ory/kratos/x" + "github.com/ory/x/decoderx" + "github.com/ory/x/sqlcon" + "github.com/ory/x/urlx" +) + +const ( + RouteAdminCreateRecoveryCode = "/recovery/code" +) + +func (s *Strategy) RegisterPublicRecoveryRoutes(public *x.RouterPublic) { + s.deps.CSRFHandler().IgnorePath(RouteAdminCreateRecoveryCode) + public.POST(RouteAdminCreateRecoveryCode, x.RedirectToAdminRoute(s.deps)) +} + +func (s *Strategy) RegisterAdminRecoveryRoutes(admin *x.RouterAdmin) { + wrappedCreateRecoveryCode := strategy.IsDisabled(s.deps, s.RecoveryStrategyID(), s.createRecoveryCodeForIdentity) + admin.POST(RouteAdminCreateRecoveryCode, wrappedCreateRecoveryCode) +} + +// Create Recovery Code for Identity Parameters +// +// swagger:parameters createRecoveryCodeForIdentity +// +//nolint:deadcode,unused +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions +type createRecoveryCodeForIdentity struct { + // in: body + Body createRecoveryCodeForIdentityBody +} + +// Create Recovery Code for Identity Request Body +// +// swagger:model createRecoveryCodeForIdentityBody +type createRecoveryCodeForIdentityBody struct { + // Identity to Recover + // + // The identity's ID you wish to recover. + // + // required: true + IdentityID uuid.UUID `json:"identity_id"` + + // Code Expires In + // + // The recovery code will expire after that amount of time has passed. Defaults to the configuration value of + // `selfservice.methods.code.config.lifespan`. + // + // + // pattern: ^([0-9]+(ns|us|ms|s|m|h))*$ + // example: + // - 1h + // - 1m + // - 1s + ExpiresIn string `json:"expires_in"` +} + +// Recovery Code for Identity +// +// Used when an administrator creates a recovery code for an identity. +// +// swagger:model recoveryCodeForIdentity +// +//nolint:deadcode,unused +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions +type recoveryCodeForIdentity struct { + // RecoveryLink with flow + // + // This link opens the recovery UI with an empty `code` field. + // + // required: true + // format: uri + RecoveryLink string `json:"recovery_link"` + + // RecoveryCode is the code that can be used to recover the account + // + // required: true + RecoveryCode string `json:"recovery_code"` + + // Expires At is the timestamp of when the recovery flow expires + // + // The timestamp when the recovery code expires. + ExpiresAt time.Time `json:"expires_at"` +} + +// swagger:route POST /admin/recovery/code identity createRecoveryCodeForIdentity +// +// # Create a Recovery Code +// +// This endpoint creates a recovery code which should be given to the user in order for them to recover +// (or activate) their account. +// +// Consumes: +// - application/json +// +// Produces: +// - application/json +// +// Schemes: http, https +// +// Security: +// oryAccessToken: +// +// Responses: +// 201: recoveryCodeForIdentity +// 400: errorGeneric +// 404: errorGeneric +// default: errorGeneric +func (s *Strategy) createRecoveryCodeForIdentity(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + var p createRecoveryCodeForIdentityBody + if err := s.dx.Decode(r, &p, decoderx.HTTPJSONDecoder()); err != nil { + s.deps.Writer().WriteError(w, r, err) + return + } + + ctx := r.Context() + config := s.deps.Config() + + expiresIn := config.SelfServiceCodeMethodLifespan(ctx) + if len(p.ExpiresIn) > 0 { + // If an expiration of the code was supplied use it instead of the default duration + var err error + expiresIn, err = time.ParseDuration(p.ExpiresIn) + if err != nil { + s.deps.Writer().WriteError(w, r, errors.WithStack(herodot. + ErrBadRequest. + WithReasonf(`Unable to parse "expires_in" whose format should match "[0-9]+(ns|us|ms|s|m|h)" but did not: %s`, p.ExpiresIn))) + return + } + } + + if time.Now().Add(expiresIn).Before(time.Now()) { + s.deps.Writer().WriteError(w, r, errors.WithStack(herodot.ErrBadRequest.WithReasonf(`Value from "expires_in" must result to a future time: %s`, p.ExpiresIn))) + return + } + + recoveryFlow, err := recovery.NewFlow(config, expiresIn, s.deps.GenerateCSRFToken(r), r, s, flow.TypeBrowser) + if err != nil { + s.deps.Writer().WriteError(w, r, err) + return + } + recoveryFlow.DangerousSkipCSRFCheck = true + recoveryFlow.State = flow.StateEmailSent + recoveryFlow.UI.Nodes = node.Nodes{} + recoveryFlow.UI.Nodes.Append(node.NewInputField("code", nil, node.CodeGroup, node.InputAttributeTypeText, node.WithRequiredInputAttribute). + WithMetaLabel(text.NewInfoNodeLabelRecoveryCode()), + ) + + recoveryFlow.UI.Nodes. + Append(node.NewInputField("method", s.RecoveryStrategyID(), node.CodeGroup, node.InputAttributeTypeSubmit). + WithMetaLabel(text.NewInfoNodeLabelSubmit())) + + if err := s.deps.RecoveryFlowPersister().CreateRecoveryFlow(ctx, recoveryFlow); err != nil { + s.deps.Writer().WriteError(w, r, err) + return + } + + id, err := s.deps.IdentityPool().GetIdentity(ctx, p.IdentityID, identity.ExpandDefault) + if notFoundErr := sqlcon.ErrNoRows; errors.As(err, ¬FoundErr) { + s.deps.Writer().WriteError(w, r, notFoundErr.WithReasonf("could not find identity")) + return + } else if err != nil { + s.deps.Writer().WriteError(w, r, err) + return + } + + rawCode := GenerateCode() + + if _, err := s.deps.RecoveryCodePersister().CreateRecoveryCode(ctx, &CreateRecoveryCodeParams{ + RawCode: rawCode, + CodeType: RecoveryCodeTypeAdmin, + ExpiresIn: expiresIn, + FlowID: recoveryFlow.ID, + IdentityID: id.ID, + }); err != nil { + s.deps.Writer().WriteError(w, r, err) + return + } + + s.deps.Audit(). + WithField("identity_id", id.ID). + WithSensitiveField("recovery_code", rawCode). + Info("A recovery code has been created.") + + body := &recoveryCodeForIdentity{ + ExpiresAt: recoveryFlow.ExpiresAt.UTC(), + RecoveryLink: urlx.CopyWithQuery( + s.deps.Config().SelfServiceFlowRecoveryUI(ctx), + url.Values{ + "flow": {recoveryFlow.ID.String()}, + }).String(), + RecoveryCode: rawCode, + } + + s.deps.Writer().WriteCode(w, r, http.StatusCreated, body, herodot.UnescapedHTML) +} diff --git a/selfservice/strategy/code/strategy_recovery_admin_test.go b/selfservice/strategy/code/strategy_recovery_admin_test.go new file mode 100644 index 000000000000..aed7bbcbaf43 --- /dev/null +++ b/selfservice/strategy/code/strategy_recovery_admin_test.go @@ -0,0 +1,204 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package code_test + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "net/url" + "testing" + "time" + + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tidwall/gjson" + + "github.com/ory/kratos/identity" + "github.com/ory/kratos/internal" + kratos "github.com/ory/kratos/internal/httpclient" + "github.com/ory/kratos/internal/testhelpers" + "github.com/ory/kratos/selfservice/flow" + "github.com/ory/kratos/selfservice/flow/recovery" + "github.com/ory/kratos/selfservice/strategy/code" + "github.com/ory/kratos/x" + "github.com/ory/x/ioutilx" + "github.com/ory/x/pointerx" + "github.com/ory/x/snapshotx" +) + +func TestAdminStrategy(t *testing.T) { + ctx := context.Background() + conf, reg := internal.NewFastRegistryWithMocks(t) + initViper(t, ctx, conf) + + _ = testhelpers.NewRecoveryUIFlowEchoServer(t, reg) + _ = testhelpers.NewSettingsUIFlowEchoServer(t, reg) + _ = testhelpers.NewLoginUIFlowEchoServer(t, reg) + _ = testhelpers.NewErrorTestServer(t, reg) + + publicTS, adminTS := testhelpers.NewKratosServer(t, reg) + adminSDK := testhelpers.NewSDKClient(adminTS) + + createCode := func(id string, expiresIn *string) (*kratos.RecoveryCodeForIdentity, *http.Response, error) { + return adminSDK.IdentityApi. + CreateRecoveryCodeForIdentity(context.Background()). + CreateRecoveryCodeForIdentityBody( + kratos.CreateRecoveryCodeForIdentityBody{ + IdentityId: id, + ExpiresIn: expiresIn, + }).Execute() + } + + t.Run("no panic on empty body #1384", func(t *testing.T) { + ctx := context.Background() + s, err := reg.RecoveryStrategies(ctx).Strategy("code") + require.NoError(t, err) + w := httptest.NewRecorder() + r := &http.Request{URL: new(url.URL)} + f, err := recovery.NewFlow(reg.Config(), time.Minute, "", r, s, flow.TypeBrowser) + require.NoError(t, err) + require.NotPanics(t, func() { + require.Error(t, s.(*code.Strategy).HandleRecoveryError(w, r, f, nil, errors.New("test"))) + }) + }) + + t.Run("description=should not be able to recover an account that does not exist", func(t *testing.T) { + _, _, err := createCode(x.NewUUID().String(), nil) + + require.IsType(t, err, new(kratos.GenericOpenAPIError), "%T", err) + snapshotx.SnapshotT(t, err.(*kratos.GenericOpenAPIError).Model()) + }) + + t.Run("description=should fail on malformed expiry time", func(t *testing.T) { + _, _, err := createCode(x.NewUUID().String(), pointerx.String("not-a-valid-value")) + require.IsType(t, err, new(kratos.GenericOpenAPIError), "%T", err) + snapshotx.SnapshotT(t, err.(*kratos.GenericOpenAPIError).Model()) + }) + + t.Run("description=should fail on negative expiry time", func(t *testing.T) { + _, _, err := createCode(x.NewUUID().String(), pointerx.String("-1h")) + require.IsType(t, err, new(kratos.GenericOpenAPIError), "%T", err) + snapshotx.SnapshotT(t, err.(*kratos.GenericOpenAPIError).Model()) + }) + + submitRecoveryLink := func(t *testing.T, link string, code string) []byte { + t.Helper() + res, err := publicTS.Client().Get(link) + require.NoError(t, err) + body := ioutilx.MustReadAll(res.Body) + + action := gjson.GetBytes(body, "ui.action").String() + require.NotEmpty(t, action) + + res, err = publicTS.Client().PostForm(action, url.Values{ + "code": {code}, + }) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, res.StatusCode) + + return ioutilx.MustReadAll(res.Body) + } + + t.Run("description=should create code without email", func(t *testing.T) { + id := identity.Identity{Traits: identity.Traits(`{}`)} + + require.NoError(t, reg.IdentityManager().Create(context.Background(), + &id, identity.ManagerAllowWriteProtectedTraits)) + + code, _, err := createCode(id.ID.String(), nil) + require.NoError(t, err) + + require.NotEmpty(t, code.RecoveryLink) + require.Contains(t, code.RecoveryLink, "flow=") + require.NotContains(t, code.RecoveryLink, "code=") + require.NotEmpty(t, code.RecoveryCode) + require.True(t, code.ExpiresAt.Before(time.Now().Add(conf.SelfServiceFlowRecoveryRequestLifespan(ctx)))) + + body := submitRecoveryLink(t, code.RecoveryLink, code.RecoveryCode) + testhelpers.AssertMessage(t, body, "You successfully recovered your account. Please change your password or set up an alternative login method (e.g. social sign in) within the next 60.00 minutes.") + }) + + t.Run("description=should not be able to recover with expired code", func(t *testing.T) { + recoveryEmail := "recover.expired@ory.sh" + id := identity.Identity{Traits: identity.Traits(fmt.Sprintf(`{"email":"%s"}`, recoveryEmail))} + + require.NoError(t, reg.IdentityManager().Create(context.Background(), + &id, identity.ManagerAllowWriteProtectedTraits)) + + code, _, err := createCode(id.ID.String(), pointerx.String("100ms")) + require.NoError(t, err) + + time.Sleep(time.Millisecond * 100) + require.NotEmpty(t, code.RecoveryLink) + require.True(t, code.ExpiresAt.Before(time.Now().Add(conf.SelfServiceFlowRecoveryRequestLifespan(ctx)))) + + body := submitRecoveryLink(t, code.RecoveryLink, code.RecoveryCode) + testhelpers.AssertMessage(t, body, "The recovery flow expired 0.00 minutes ago, please try again.") + + // The recovery address should not be verified if the flow was initiated by the admins + addr, err := reg.IdentityPool().FindVerifiableAddressByValue(context.Background(), identity.VerifiableAddressTypeEmail, recoveryEmail) + assert.NoError(t, err) + assert.False(t, addr.Verified) + assert.Nil(t, addr.VerifiedAt) + assert.Equal(t, identity.VerifiableAddressStatusPending, addr.Status) + }) + + t.Run("description=should create a valid recovery link and set the expiry time as well and recover the account", func(t *testing.T) { + recoveryEmail := "recoverme@ory.sh" + id := identity.Identity{Traits: identity.Traits(fmt.Sprintf(`{"email":"%s"}`, recoveryEmail))} + + require.NoError(t, reg.IdentityManager().Create(context.Background(), + &id, identity.ManagerAllowWriteProtectedTraits)) + + code, _, err := createCode(id.ID.String(), nil) + require.NoError(t, err) + + require.NotEmpty(t, code.RecoveryLink) + require.True(t, code.ExpiresAt.Before(time.Now().Add(conf.SelfServiceFlowRecoveryRequestLifespan(ctx)+time.Second))) + + body := submitRecoveryLink(t, code.RecoveryLink, code.RecoveryCode) + + testhelpers.AssertMessage(t, body, "You successfully recovered your account. Please change your password or set up an alternative login method (e.g. social sign in) within the next 60.00 minutes.") + + addr, err := reg.IdentityPool().FindVerifiableAddressByValue(context.Background(), identity.VerifiableAddressTypeEmail, recoveryEmail) + assert.NoError(t, err) + assert.False(t, addr.Verified) + assert.Nil(t, addr.VerifiedAt) + assert.Equal(t, identity.VerifiableAddressStatusPending, addr.Status) + }) + + t.Run("case=should not be able to use code from different flow", func(t *testing.T) { + email := testhelpers.RandomEmail() + i := createIdentityToRecover(t, reg, email) + + c1, _, err := createCode(i.ID.String(), pointerx.String("1h")) + require.NoError(t, err) + c2, _, err := createCode(i.ID.String(), pointerx.String("1h")) + require.NoError(t, err) + code2 := c2.RecoveryCode + require.NotEmpty(t, code2) + + body := submitRecoveryLink(t, c1.RecoveryLink, c2.RecoveryCode) + + testhelpers.AssertMessage(t, body, "The recovery code is invalid or has already been used. Please try again.") + }) + + t.Run("case=form should not contain email field when creating recovery code", func(t *testing.T) { + email := testhelpers.RandomEmail() + i := createIdentityToRecover(t, reg, email) + + c1, _, err := createCode(i.ID.String(), pointerx.String("1h")) + require.NoError(t, err) + + res, err := http.Get(c1.RecoveryLink) + require.NoError(t, err) + body := ioutilx.MustReadAll(res.Body) + + snapshotx.SnapshotT(t, json.RawMessage(gjson.GetBytes(body, "ui.nodes").String())) + }) +} diff --git a/selfservice/strategy/code/strategy_recovery_test.go b/selfservice/strategy/code/strategy_recovery_test.go index 10d5ae6f5135..91afe5c3e149 100644 --- a/selfservice/strategy/code/strategy_recovery_test.go +++ b/selfservice/strategy/code/strategy_recovery_test.go @@ -17,39 +17,28 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/gofrs/uuid" - errors "github.com/pkg/errors" - - "github.com/ory/kratos/driver" - "github.com/ory/kratos/session" - - "github.com/ory/kratos/ui/node" - - kratos "github.com/ory/kratos/internal/httpclient" - - "github.com/ory/kratos/corpx" - - "github.com/ory/x/ioutilx" - "github.com/ory/x/pointerx" - "github.com/ory/x/snapshotx" - "github.com/ory/x/urlx" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tidwall/gjson" - "github.com/ory/x/sqlxx" - - "github.com/ory/x/assertx" - + "github.com/ory/kratos/corpx" + "github.com/ory/kratos/driver" "github.com/ory/kratos/driver/config" "github.com/ory/kratos/identity" "github.com/ory/kratos/internal" + kratos "github.com/ory/kratos/internal/httpclient" "github.com/ory/kratos/internal/testhelpers" "github.com/ory/kratos/selfservice/flow" "github.com/ory/kratos/selfservice/flow/recovery" "github.com/ory/kratos/selfservice/strategy/code" + "github.com/ory/kratos/session" "github.com/ory/kratos/text" + "github.com/ory/kratos/ui/node" "github.com/ory/kratos/x" + "github.com/ory/x/assertx" + "github.com/ory/x/ioutilx" + "github.com/ory/x/sqlxx" + "github.com/ory/x/urlx" ) func init() { @@ -60,184 +49,18 @@ func extractCsrfToken(body []byte) string { return gjson.GetBytes(body, "ui.nodes.#(attributes.name==csrf_token).attributes.value").String() } -func TestAdminStrategy(t *testing.T) { - ctx := context.Background() - conf, reg := internal.NewFastRegistryWithMocks(t) - initViper(t, ctx, conf) - - _ = testhelpers.NewRecoveryUIFlowEchoServer(t, reg) - _ = testhelpers.NewSettingsUIFlowEchoServer(t, reg) - _ = testhelpers.NewLoginUIFlowEchoServer(t, reg) - _ = testhelpers.NewErrorTestServer(t, reg) - - publicTS, adminTS := testhelpers.NewKratosServer(t, reg) - adminSDK := testhelpers.NewSDKClient(adminTS) - - createCode := func(id string, expiresIn *string) (*kratos.RecoveryCodeForIdentity, *http.Response, error) { - return adminSDK.IdentityApi. - CreateRecoveryCodeForIdentity(context.Background()). - CreateRecoveryCodeForIdentityBody( - kratos.CreateRecoveryCodeForIdentityBody{ - IdentityId: id, - ExpiresIn: expiresIn, - }).Execute() - } - - t.Run("no panic on empty body #1384", func(t *testing.T) { - ctx := context.Background() - s, err := reg.RecoveryStrategies(ctx).Strategy("code") - require.NoError(t, err) - w := httptest.NewRecorder() - r := &http.Request{URL: new(url.URL)} - f, err := recovery.NewFlow(reg.Config(), time.Minute, "", r, s, flow.TypeBrowser) - require.NoError(t, err) - require.NotPanics(t, func() { - require.Error(t, s.(*code.Strategy).HandleRecoveryError(w, r, f, nil, errors.New("test"))) - }) - }) - - t.Run("description=should not be able to recover an account that does not exist", func(t *testing.T) { - _, _, err := createCode(x.NewUUID().String(), nil) - - require.IsType(t, err, new(kratos.GenericOpenAPIError), "%T", err) - snapshotx.SnapshotT(t, err.(*kratos.GenericOpenAPIError).Model()) - }) - - t.Run("description=should fail on malformed expiry time", func(t *testing.T) { - _, _, err := createCode(x.NewUUID().String(), pointerx.String("not-a-valid-value")) - require.IsType(t, err, new(kratos.GenericOpenAPIError), "%T", err) - snapshotx.SnapshotT(t, err.(*kratos.GenericOpenAPIError).Model()) - }) - - t.Run("description=should fail on negative expiry time", func(t *testing.T) { - _, _, err := createCode(x.NewUUID().String(), pointerx.String("-1h")) - require.IsType(t, err, new(kratos.GenericOpenAPIError), "%T", err) - snapshotx.SnapshotT(t, err.(*kratos.GenericOpenAPIError).Model()) - }) - - submitRecoveryLink := func(t *testing.T, link string, code string) []byte { - t.Helper() - res, err := publicTS.Client().Get(link) - require.NoError(t, err) - body := ioutilx.MustReadAll(res.Body) - - action := gjson.GetBytes(body, "ui.action").String() - require.NotEmpty(t, action) - - res, err = publicTS.Client().PostForm(action, url.Values{ - "code": {code}, - }) - require.NoError(t, err) - assert.Equal(t, http.StatusOK, res.StatusCode) - - return ioutilx.MustReadAll(res.Body) - } - - t.Run("description=should create code without email", func(t *testing.T) { - id := identity.Identity{Traits: identity.Traits(`{}`)} - - require.NoError(t, reg.IdentityManager().Create(context.Background(), - &id, identity.ManagerAllowWriteProtectedTraits)) - - code, _, err := createCode(id.ID.String(), nil) - require.NoError(t, err) - - require.NotEmpty(t, code.RecoveryLink) - require.Contains(t, code.RecoveryLink, "flow=") - require.NotContains(t, code.RecoveryLink, "code=") - require.NotEmpty(t, code.RecoveryCode) - require.True(t, code.ExpiresAt.Before(time.Now().Add(conf.SelfServiceFlowRecoveryRequestLifespan(ctx)))) - - body := submitRecoveryLink(t, code.RecoveryLink, code.RecoveryCode) - testhelpers.AssertMessage(t, body, "You successfully recovered your account. Please change your password or set up an alternative login method (e.g. social sign in) within the next 60.00 minutes.") - }) - - t.Run("description=should not be able to recover with expired code", func(t *testing.T) { - recoveryEmail := "recover.expired@ory.sh" - id := identity.Identity{Traits: identity.Traits(fmt.Sprintf(`{"email":"%s"}`, recoveryEmail))} - - require.NoError(t, reg.IdentityManager().Create(context.Background(), - &id, identity.ManagerAllowWriteProtectedTraits)) - - code, _, err := createCode(id.ID.String(), pointerx.String("100ms")) - require.NoError(t, err) - - time.Sleep(time.Millisecond * 100) - require.NotEmpty(t, code.RecoveryLink) - require.True(t, code.ExpiresAt.Before(time.Now().Add(conf.SelfServiceFlowRecoveryRequestLifespan(ctx)))) - - body := submitRecoveryLink(t, code.RecoveryLink, code.RecoveryCode) - testhelpers.AssertMessage(t, body, "The recovery flow expired 0.00 minutes ago, please try again.") - - // The recovery address should not be verified if the flow was initiated by the admins - addr, err := reg.IdentityPool().FindVerifiableAddressByValue(context.Background(), identity.VerifiableAddressTypeEmail, recoveryEmail) - assert.NoError(t, err) - assert.False(t, addr.Verified) - assert.Nil(t, addr.VerifiedAt) - assert.Equal(t, identity.VerifiableAddressStatusPending, addr.Status) - }) - - t.Run("description=should create a valid recovery link and set the expiry time as well and recover the account", func(t *testing.T) { - recoveryEmail := "recoverme@ory.sh" - id := identity.Identity{Traits: identity.Traits(fmt.Sprintf(`{"email":"%s"}`, recoveryEmail))} - - require.NoError(t, reg.IdentityManager().Create(context.Background(), - &id, identity.ManagerAllowWriteProtectedTraits)) - - code, _, err := createCode(id.ID.String(), nil) - require.NoError(t, err) - - require.NotEmpty(t, code.RecoveryLink) - require.True(t, code.ExpiresAt.Before(time.Now().Add(conf.SelfServiceFlowRecoveryRequestLifespan(ctx)+time.Second))) - - body := submitRecoveryLink(t, code.RecoveryLink, code.RecoveryCode) - - testhelpers.AssertMessage(t, body, "You successfully recovered your account. Please change your password or set up an alternative login method (e.g. social sign in) within the next 60.00 minutes.") - - addr, err := reg.IdentityPool().FindVerifiableAddressByValue(context.Background(), identity.VerifiableAddressTypeEmail, recoveryEmail) - assert.NoError(t, err) - assert.False(t, addr.Verified) - assert.Nil(t, addr.VerifiedAt) - assert.Equal(t, identity.VerifiableAddressStatusPending, addr.Status) - }) - - t.Run("case=should not be able to use code from different flow", func(t *testing.T) { - email := testhelpers.RandomEmail() - i := createIdentityToRecover(t, reg, email) - - c1, _, err := createCode(i.ID.String(), pointerx.String("1h")) - require.NoError(t, err) - c2, _, err := createCode(i.ID.String(), pointerx.String("1h")) - require.NoError(t, err) - code2 := c2.RecoveryCode - require.NotEmpty(t, code2) - - body := submitRecoveryLink(t, c1.RecoveryLink, c2.RecoveryCode) - - testhelpers.AssertMessage(t, body, "The recovery code is invalid or has already been used. Please try again.") - }) - - t.Run("case=form should not contain email field when creating recovery code", func(t *testing.T) { - email := testhelpers.RandomEmail() - i := createIdentityToRecover(t, reg, email) - - c1, _, err := createCode(i.ID.String(), pointerx.String("1h")) - require.NoError(t, err) - - res, err := http.Get(c1.RecoveryLink) - require.NoError(t, err) - body := ioutilx.MustReadAll(res.Body) - - snapshotx.SnapshotT(t, json.RawMessage(gjson.GetBytes(body, "ui.nodes").String())) - }) -} +type ClientType string const ( - RecoveryFlowTypeBrowser string = "browser" - RecoveryFlowTypeSPA string = "spa" - RecoveryFlowTypeAPI string = "api" + RecoveryClientTypeBrowser ClientType = "browser" + RecoveryClientTypeSPA ClientType = "spa" + RecoveryClientTypeAPI ClientType = "api" ) +func (c ClientType) String() string { + return string(c) +} + func apiHttpClient(t *testing.T) *http.Client { return &http.Client{} } @@ -250,39 +73,43 @@ func browserHttpClient(t *testing.T) *http.Client { return testhelpers.NewClientWithCookies(t) } -var flowTypes = []string{RecoveryFlowTypeBrowser, RecoveryFlowTypeAPI, RecoveryFlowTypeSPA} +var flowTypes = []ClientType{RecoveryClientTypeBrowser, RecoveryClientTypeAPI, RecoveryClientTypeSPA} var flowTypeCases = []struct { - FlowType string + FlowType flow.Type + ClientType ClientType GetClient func(*testing.T) *http.Client FormContentType string }{ { - FlowType: RecoveryFlowTypeBrowser, + FlowType: flow.TypeBrowser, + ClientType: RecoveryClientTypeBrowser, GetClient: testhelpers.NewClientWithCookies, FormContentType: "application/x-www-form-urlencoded", }, { - FlowType: RecoveryFlowTypeAPI, + FlowType: flow.TypeAPI, + ClientType: RecoveryClientTypeAPI, GetClient: func(_ *testing.T) *http.Client { return &http.Client{} }, FormContentType: "application/json", }, { - FlowType: RecoveryFlowTypeSPA, + FlowType: flow.TypeBrowser, + ClientType: RecoveryClientTypeSPA, GetClient: testhelpers.NewClientWithCookies, FormContentType: "application/json", }, } -func withCSRFToken(t *testing.T, flowType, body string, v url.Values) string { +func withCSRFToken(t *testing.T, clientType ClientType, body string, v url.Values) string { t.Helper() csrfToken := gjson.Get(body, "ui.nodes.#(attributes.name==csrf_token).attributes.value").String() - if csrfToken != "" && flowType != RecoveryFlowTypeAPI { + if csrfToken != "" && clientType != RecoveryClientTypeAPI { v.Set("csrf_token", csrfToken) } - if flowType == RecoveryFlowTypeBrowser { + if clientType == RecoveryClientTypeBrowser { return v.Encode() } return testhelpers.EncodeFormAsJSON(t, true, v) @@ -327,9 +154,9 @@ func TestRecovery(t *testing.T) { public, _, _, _ := testhelpers.NewKratosServerWithCSRFAndRouters(t, reg) - submitRecovery := func(t *testing.T, client *http.Client, flowType string, values func(url.Values), code int) string { - isSPA := flowType == RecoveryFlowTypeSPA - isAPI := flowType == RecoveryFlowTypeAPI + submitRecovery := func(t *testing.T, client *http.Client, flowType ClientType, values func(url.Values), code int) string { + isSPA := flowType == RecoveryClientTypeSPA + isAPI := flowType == RecoveryClientTypeAPI if client == nil { client = testhelpers.NewDebugClient(t) if !isAPI { @@ -342,7 +169,7 @@ func TestRecovery(t *testing.T) { return testhelpers.SubmitRecoveryForm(t, isAPI, isSPA, client, public, values, code, expectedUrl) } - submitRecoveryCode := func(t *testing.T, client *http.Client, flow string, flowType string, recoveryCode string, statusCode int) string { + submitRecoveryCode := func(t *testing.T, client *http.Client, flow string, flowType ClientType, recoveryCode string, statusCode int) string { action := gjson.Get(flow, "ui.action").String() assert.NotEmpty(t, action) @@ -352,7 +179,7 @@ func TestRecovery(t *testing.T) { }) contentType := "application/json" - if flowType == RecoveryFlowTypeBrowser { + if flowType == RecoveryClientTypeBrowser { contentType = "application/x-www-form-urlencoded" } @@ -363,7 +190,7 @@ func TestRecovery(t *testing.T) { return string(ioutilx.MustReadAll(res.Body)) } - resendRecoveryCode := func(t *testing.T, client *http.Client, flow string, flowType string, statusCode int) string { + resendRecoveryCode := func(t *testing.T, client *http.Client, flow string, flowType ClientType, statusCode int) string { action := gjson.Get(flow, "ui.action").String() assert.NotEmpty(t, action) @@ -375,7 +202,7 @@ func TestRecovery(t *testing.T) { }) contentType := "application/json" - if flowType == RecoveryFlowTypeBrowser { + if flowType == RecoveryClientTypeBrowser { contentType = "application/x-www-form-urlencoded" } @@ -386,13 +213,13 @@ func TestRecovery(t *testing.T) { return string(ioutilx.MustReadAll(res.Body)) } - expectValidationError := func(t *testing.T, hc *http.Client, flowType string, values func(url.Values)) string { - code := testhelpers.ExpectStatusCode(flowType == RecoveryFlowTypeAPI || flowType == RecoveryFlowTypeSPA, http.StatusBadRequest, http.StatusOK) + expectValidationError := func(t *testing.T, hc *http.Client, flowType ClientType, values func(url.Values)) string { + code := testhelpers.ExpectStatusCode(flowType == RecoveryClientTypeAPI || flowType == RecoveryClientTypeSPA, http.StatusBadRequest, http.StatusOK) return submitRecovery(t, hc, flowType, values, code) } - expectSuccessfulRecovery := func(t *testing.T, hc *http.Client, flowType string, values func(url.Values)) string { - code := testhelpers.ExpectStatusCode(flowType == RecoveryFlowTypeAPI || flowType == RecoveryFlowTypeSPA, http.StatusUnprocessableEntity, http.StatusOK) + expectSuccessfulRecovery := func(t *testing.T, hc *http.Client, flowType ClientType, values func(url.Values)) string { + code := testhelpers.ExpectStatusCode(flowType == RecoveryClientTypeAPI || flowType == RecoveryClientTypeSPA, http.StatusUnprocessableEntity, http.StatusOK) return submitRecovery(t, hc, flowType, values, code) } @@ -404,7 +231,7 @@ func TestRecovery(t *testing.T) { } t.Run("description=should recover an account", func(t *testing.T) { - checkRecovery := func(t *testing.T, client *http.Client, flowType, recoveryEmail, recoverySubmissionResponse string) string { + checkRecovery := func(t *testing.T, client *http.Client, flowType ClientType, recoveryEmail, recoverySubmissionResponse string) string { ExpectVerfiableAddressStatus(t, recoveryEmail, identity.VerifiableAddressStatusPending) assert.EqualValues(t, node.CodeGroup, gjson.Get(recoverySubmissionResponse, "active").String(), "%s", recoverySubmissionResponse) @@ -418,7 +245,7 @@ func TestRecovery(t *testing.T) { recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) assert.NotEmpty(t, recoveryCode) - statusCode := testhelpers.ExpectStatusCode(flowType == RecoveryFlowTypeAPI || flowType == RecoveryFlowTypeSPA, http.StatusUnprocessableEntity, http.StatusOK) + statusCode := testhelpers.ExpectStatusCode(flowType == RecoveryClientTypeAPI || flowType == RecoveryClientTypeSPA, http.StatusUnprocessableEntity, http.StatusOK) return submitRecoveryCode(t, client, recoverySubmissionResponse, flowType, recoveryCode, statusCode) } @@ -426,10 +253,10 @@ func TestRecovery(t *testing.T) { client := testhelpers.NewClientWithCookies(t) email := "recoverme1@ory.sh" createIdentityToRecover(t, reg, email) - recoverySubmissionResponse := submitRecovery(t, client, RecoveryFlowTypeBrowser, func(v url.Values) { + recoverySubmissionResponse := submitRecovery(t, client, RecoveryClientTypeBrowser, func(v url.Values) { v.Set("email", email) }, http.StatusOK) - body := checkRecovery(t, client, RecoveryFlowTypeBrowser, email, recoverySubmissionResponse) + body := checkRecovery(t, client, RecoveryClientTypeBrowser, email, recoverySubmissionResponse) assert.Equal(t, text.NewRecoverySuccessful(time.Now().Add(time.Hour)).Text, gjson.Get(body, "ui.messages.0.text").String()) @@ -446,10 +273,10 @@ func TestRecovery(t *testing.T) { client := testhelpers.NewClientWithCookies(t) email := "recoverme3@ory.sh" createIdentityToRecover(t, reg, email) - recoverySubmissionResponse := submitRecovery(t, client, RecoveryFlowTypeSPA, func(v url.Values) { + recoverySubmissionResponse := submitRecovery(t, client, RecoveryClientTypeSPA, func(v url.Values) { v.Set("email", email) }, http.StatusOK) - body := checkRecovery(t, client, RecoveryFlowTypeSPA, email, recoverySubmissionResponse) + body := checkRecovery(t, client, RecoveryClientTypeSPA, email, recoverySubmissionResponse) assert.Equal(t, "browser_location_change_required", gjson.Get(body, "error.id").String()) assert.Contains(t, gjson.Get(body, "redirect_browser_to").String(), "settings-ts?") }) @@ -458,10 +285,10 @@ func TestRecovery(t *testing.T) { client := &http.Client{} email := "recoverme4@ory.sh" createIdentityToRecover(t, reg, email) - recoverySubmissionResponse := submitRecovery(t, client, RecoveryFlowTypeAPI, func(v url.Values) { + recoverySubmissionResponse := submitRecovery(t, client, RecoveryClientTypeAPI, func(v url.Values) { v.Set("email", email) }, http.StatusOK) - body := checkRecovery(t, client, RecoveryFlowTypeAPI, email, recoverySubmissionResponse) + body := checkRecovery(t, client, RecoveryClientTypeAPI, email, recoverySubmissionResponse) assert.Equal(t, "browser_location_change_required", gjson.Get(body, "error.id").String()) assert.Contains(t, gjson.Get(body, "redirect_browser_to").String(), "settings-ts?") }) @@ -543,7 +370,7 @@ func TestRecovery(t *testing.T) { expectedURL := testhelpers.ExpectURL(false, public.URL+recovery.RouteSubmitFlow, conf.SelfServiceFlowRecoveryUI(ctx).String()) assert.Contains(t, res.Request.URL.String(), expectedURL, "%+v\n\t%s", res.Request, body) - body = checkRecovery(t, client, RecoveryFlowTypeBrowser, email, body) + body = checkRecovery(t, client, RecoveryClientTypeBrowser, email, body) require.Equal(t, text.NewRecoverySuccessful(time.Now().Add(time.Hour)).Text, gjson.Get(body, "ui.messages.0.text").String()) @@ -584,7 +411,7 @@ func TestRecovery(t *testing.T) { }) t.Run("description=should set all the correct recovery payloads after submission", func(t *testing.T) { - body := expectSuccessfulRecovery(t, nil, RecoveryFlowTypeBrowser, func(v url.Values) { + body := expectSuccessfulRecovery(t, nil, RecoveryClientTypeBrowser, func(v url.Values) { v.Set("email", "test@ory.sh") }) testhelpers.SnapshotTExcept(t, json.RawMessage(gjson.Get(body, "ui.nodes").String()), []string{"0.attributes.value"}) @@ -601,7 +428,7 @@ func TestRecovery(t *testing.T) { t.Run("description=should require an email to be sent", func(t *testing.T) { for _, flowType := range flowTypes { - t.Run("type="+flowType, func(t *testing.T) { + t.Run("type="+string(flowType), func(t *testing.T) { body := expectValidationError(t, nil, flowType, func(v url.Values) { v.Del("email") }) @@ -616,7 +443,7 @@ func TestRecovery(t *testing.T) { t.Run("description=should require a valid email to be sent", func(t *testing.T) { for _, flowType := range flowTypes { for _, email := range []string{"\\", "asdf", "...", "aiacobelli.sec@gmail.com,alejandro.iacobelli@mercadolibre.com"} { - t.Run("type="+flowType, func(t *testing.T) { + t.Run("type="+string(flowType), func(t *testing.T) { responseJSON := expectValidationError(t, nil, flowType, func(v url.Values) { v.Set("email", email) }) @@ -632,7 +459,7 @@ func TestRecovery(t *testing.T) { t.Run("description=should try to submit the form while authenticated", func(t *testing.T) { for _, flowType := range flowTypes { - t.Run("type="+flowType, func(t *testing.T) { + t.Run("type="+string(flowType), func(t *testing.T) { isSPA := flowType == "spa" isAPI := flowType == "api" client := testhelpers.NewDebugClient(t) @@ -688,7 +515,7 @@ func TestRecovery(t *testing.T) { conf.Set(ctx, config.ViperKeySelfServiceRecoveryNotifyUnknownRecipients, false) }) - check := func(t *testing.T, c *http.Client, flowType, email string) { + check := func(t *testing.T, c *http.Client, flowType ClientType, email string) { withValues := func(v url.Values) { v.Set("email", email) } @@ -704,33 +531,33 @@ func TestRecovery(t *testing.T) { t.Run("type=browser", func(t *testing.T) { email := "recover_browser@ory.sh" c := browserHttpClient(t) - check(t, c, RecoveryFlowTypeBrowser, email) + check(t, c, RecoveryClientTypeBrowser, email) }) t.Run("type=spa", func(t *testing.T) { email := "recover_spa@ory.sh" c := spaHttpClient(t) - check(t, c, RecoveryFlowTypeSPA, email) + check(t, c, RecoveryClientTypeSPA, email) }) t.Run("type=api", func(t *testing.T) { email := "recover_api@ory.sh" c := apiHttpClient(t) - check(t, c, RecoveryFlowTypeAPI, email) + check(t, c, RecoveryClientTypeAPI, email) }) }) t.Run("description=should not be able to recover an inactive account", func(t *testing.T) { for _, flowType := range flowTypeCases { - t.Run("type="+flowType.FlowType, func(t *testing.T) { - email := "recoverinactive_" + flowType.FlowType + "@ory.sh" + t.Run("type="+string(flowType.ClientType), func(t *testing.T) { + email := "recoverinactive_" + string(flowType.ClientType) + "@ory.sh" createIdentityToRecover(t, reg, email) values := func(v url.Values) { v.Set("email", email) } cl := testhelpers.NewClientWithCookies(t) - body := submitRecovery(t, cl, flowType.FlowType, values, http.StatusOK) + body := submitRecovery(t, cl, flowType.ClientType, values, http.StatusOK) addr, err := reg.IdentityPool().FindVerifiableAddressByValue(context.Background(), identity.VerifiableAddressTypeEmail, email) assert.NoError(t, err) @@ -740,11 +567,11 @@ func TestRecovery(t *testing.T) { // Deactivate the identity require.NoError(t, reg.Persister().GetConnection(context.Background()).RawQuery("UPDATE identities SET state=? WHERE id = ?", identity.StateInactive, addr.IdentityID).Exec()) - if flowType.FlowType == RecoveryFlowTypeAPI || flowType.FlowType == RecoveryFlowTypeSPA { - body = submitRecoveryCode(t, cl, body, flowType.FlowType, recoveryCode, http.StatusUnauthorized) + if flowType.ClientType == RecoveryClientTypeAPI || flowType.ClientType == RecoveryClientTypeSPA { + body = submitRecoveryCode(t, cl, body, flowType.ClientType, recoveryCode, http.StatusUnauthorized) assertx.EqualAsJSON(t, session.ErrIdentityDisabled.WithDetail("identity_id", addr.IdentityID), json.RawMessage(gjson.Get(body, "error").Raw), "%s", body) } else { - body = submitRecoveryCode(t, cl, body, flowType.FlowType, recoveryCode, http.StatusOK) + body = submitRecoveryCode(t, cl, body, flowType.ClientType, recoveryCode, http.StatusOK) assertx.EqualAsJSON(t, session.ErrIdentityDisabled.WithDetail("identity_id", addr.IdentityID), json.RawMessage(body), "%s", body) } }) @@ -770,7 +597,7 @@ func TestRecovery(t *testing.T) { assert.True(t, actualSession.IsActive()) cl := testhelpers.NewClientWithCookies(t) - actual := expectSuccessfulRecovery(t, cl, RecoveryFlowTypeBrowser, func(v url.Values) { + actual := expectSuccessfulRecovery(t, cl, RecoveryClientTypeBrowser, func(v url.Values) { v.Set("email", email) }) message := testhelpers.CourierExpectMessage(ctx, t, reg, email, "Recover access to your account") @@ -785,7 +612,7 @@ func TestRecovery(t *testing.T) { csrf_token := gjson.Get(actual, "ui.nodes.#(attributes.name==csrf_token).attributes.value").String() require.NotEmpty(t, csrf_token) - submitRecoveryCode(t, cl, actual, RecoveryFlowTypeBrowser, recoveryCode, http.StatusSeeOther) + submitRecoveryCode(t, cl, actual, RecoveryClientTypeBrowser, recoveryCode, http.StatusSeeOther) require.Len(t, cl.Jar.Cookies(urlx.ParseOrPanic(public.URL)), 2) cookies := spew.Sdump(cl.Jar.Cookies(urlx.ParseOrPanic(public.URL))) @@ -800,19 +627,19 @@ func TestRecovery(t *testing.T) { email := testhelpers.RandomEmail() createIdentityToRecover(t, reg, email) c := testhelpers.NewClientWithCookies(t) - body := submitRecovery(t, c, RecoveryFlowTypeBrowser, func(v url.Values) { + body := submitRecovery(t, c, RecoveryClientTypeBrowser, func(v url.Values) { v.Set("email", email) }, http.StatusOK) initialFlowId := gjson.Get(body, "id") for submitTry := 0; submitTry < 5; submitTry++ { - body := submitRecoveryCode(t, c, body, RecoveryFlowTypeBrowser, "12312312", http.StatusOK) + body := submitRecoveryCode(t, c, body, RecoveryClientTypeBrowser, "12312312", http.StatusOK) testhelpers.AssertMessage(t, []byte(body), "The recovery code is invalid or has already been used. Please try again.") } // submit an invalid code for the 6th time - body = submitRecoveryCode(t, c, body, RecoveryFlowTypeBrowser, "12312312", http.StatusOK) + body = submitRecoveryCode(t, c, body, RecoveryClientTypeBrowser, "12312312", http.StatusOK) require.Len(t, gjson.Get(body, "ui.messages").Array(), 1) assert.Equal(t, "The request was submitted too often. Please request another code.", gjson.Get(body, "ui.messages.0.text").String()) @@ -825,19 +652,19 @@ func TestRecovery(t *testing.T) { t.Run("description=should be able to recover after using invalid code", func(t *testing.T) { for _, testCase := range flowTypeCases { - t.Run("type="+testCase.FlowType, func(t *testing.T) { + t.Run("type="+testCase.ClientType.String(), func(t *testing.T) { c := testCase.GetClient(t) recoveryEmail := testhelpers.RandomEmail() _ = createIdentityToRecover(t, reg, recoveryEmail) - actual := submitRecovery(t, c, testCase.FlowType, func(v url.Values) { + actual := submitRecovery(t, c, testCase.ClientType, func(v url.Values) { v.Set("email", recoveryEmail) }, http.StatusOK) message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account") recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) - form := withCSRFToken(t, testCase.FlowType, actual, url.Values{ + form := withCSRFToken(t, testCase.ClientType, actual, url.Values{ "code": {"12312312"}, }) @@ -864,20 +691,20 @@ func TestRecovery(t *testing.T) { require.Len(t, rs.Ui.Messages, 1) assert.Equal(t, "The recovery code is invalid or has already been used. Please try again.", rs.Ui.Messages[0].Text) - form = withCSRFToken(t, testCase.FlowType, actual, url.Values{ + form = withCSRFToken(t, testCase.ClientType, actual, url.Values{ "code": {recoveryCode}, }) // Now submit the correct code res, err = c.Post(action, testCase.FormContentType, bytes.NewBufferString(form)) require.NoError(t, err) - if testCase.FlowType == RecoveryFlowTypeBrowser { + if testCase.ClientType == RecoveryClientTypeBrowser { assert.Equal(t, http.StatusOK, res.StatusCode) json := ioutilx.MustReadAll(res.Body) assert.Len(t, gjson.GetBytes(json, "ui.messages").Array(), 1) assert.Contains(t, gjson.GetBytes(json, "ui.messages.0.text").String(), "You successfully recovered your account.") - } else if testCase.FlowType == RecoveryFlowTypeSPA { + } else if testCase.ClientType == RecoveryClientTypeSPA { assert.Equal(t, http.StatusUnprocessableEntity, res.StatusCode) json := ioutilx.MustReadAll(res.Body) @@ -894,11 +721,11 @@ func TestRecovery(t *testing.T) { createIdentityToRecover(t, reg, email) c := testhelpers.NewClientWithCookies(t) - body := submitRecovery(t, c, RecoveryFlowTypeBrowser, func(v url.Values) { + body := submitRecovery(t, c, RecoveryClientTypeBrowser, func(v url.Values) { v.Set("email", email) }, http.StatusOK) - body = submitRecoveryCode(t, c, body, RecoveryFlowTypeBrowser, "12312312", http.StatusOK) + body = submitRecoveryCode(t, c, body, RecoveryClientTypeBrowser, "12312312", http.StatusOK) testhelpers.AssertMessage(t, []byte(body), "The recovery code is invalid or has already been used. Please try again.") }) @@ -939,7 +766,7 @@ func TestRecovery(t *testing.T) { c := testhelpers.NewClientWithCookies(t) - body := expectSuccessfulRecovery(t, c, RecoveryFlowTypeBrowser, func(v url.Values) { + body := expectSuccessfulRecovery(t, c, RecoveryClientTypeBrowser, func(v url.Values) { v.Set("email", recoveryEmail) }) @@ -952,7 +779,7 @@ func TestRecovery(t *testing.T) { time.Sleep(time.Millisecond * 201) - body = submitRecoveryCode(t, c, body, RecoveryFlowTypeBrowser, recoveryCode, http.StatusOK) + body = submitRecoveryCode(t, c, body, RecoveryClientTypeBrowser, recoveryCode, http.StatusOK) assert.NotEqual(t, gjson.Get(body, "id"), initialFlowId) @@ -970,14 +797,14 @@ func TestRecovery(t *testing.T) { createIdentityToRecover(t, reg, recoveryEmail) c := testhelpers.NewClientWithCookies(t) - body := expectSuccessfulRecovery(t, c, RecoveryFlowTypeBrowser, func(v url.Values) { + body := expectSuccessfulRecovery(t, c, RecoveryClientTypeBrowser, func(v url.Values) { v.Set("email", recoveryEmail) }) action := gjson.Get(body, "ui.action").String() require.NotEmpty(t, action) - body = submitRecoveryCode(t, c, body, RecoveryFlowTypeBrowser, "", http.StatusOK) + body = submitRecoveryCode(t, c, body, RecoveryClientTypeBrowser, "", http.StatusOK) assert.NotContains(t, gjson.Get(body, "ui.nodes").String(), "Property email is missing.") testhelpers.AssertMessage(t, []byte(body), "The recovery code is invalid or has already been used. Please try again.") @@ -988,7 +815,7 @@ func TestRecovery(t *testing.T) { createIdentityToRecover(t, reg, recoveryEmail) c := testhelpers.NewClientWithCookies(t) - body := expectSuccessfulRecovery(t, c, RecoveryFlowTypeBrowser, func(v url.Values) { + body := expectSuccessfulRecovery(t, c, RecoveryClientTypeBrowser, func(v url.Values) { v.Set("email", recoveryEmail) }) @@ -996,14 +823,14 @@ func TestRecovery(t *testing.T) { require.NotEmpty(t, action) assert.Equal(t, recoveryEmail, gjson.Get(body, "ui.nodes.#(attributes.name==email).attributes.value").String()) - body = resendRecoveryCode(t, c, body, RecoveryFlowTypeBrowser, http.StatusOK) + body = resendRecoveryCode(t, c, body, RecoveryClientTypeBrowser, http.StatusOK) assert.True(t, gjson.Get(body, "ui.nodes.#(attributes.name==code)").Exists()) assert.Equal(t, recoveryEmail, gjson.Get(body, "ui.nodes.#(attributes.name==email).attributes.value").String()) message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account") recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) - submitRecoveryCode(t, c, body, RecoveryFlowTypeBrowser, recoveryCode, http.StatusOK) + submitRecoveryCode(t, c, body, RecoveryClientTypeBrowser, recoveryCode, http.StatusOK) }) t.Run("description=should not be able to use first code after re-sending email", func(t *testing.T) { @@ -1011,7 +838,7 @@ func TestRecovery(t *testing.T) { createIdentityToRecover(t, reg, recoveryEmail) c := testhelpers.NewClientWithCookies(t) - body := expectSuccessfulRecovery(t, c, RecoveryFlowTypeBrowser, func(v url.Values) { + body := expectSuccessfulRecovery(t, c, RecoveryClientTypeBrowser, func(v url.Values) { v.Set("email", recoveryEmail) }) @@ -1022,18 +849,18 @@ func TestRecovery(t *testing.T) { message1 := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account") recoveryCode1 := testhelpers.CourierExpectCodeInMessage(t, message1, 1) - body = resendRecoveryCode(t, c, body, RecoveryFlowTypeBrowser, http.StatusOK) + body = resendRecoveryCode(t, c, body, RecoveryClientTypeBrowser, http.StatusOK) assert.True(t, gjson.Get(body, "ui.nodes.#(attributes.name==code)").Exists()) assert.Equal(t, recoveryEmail, gjson.Get(body, "ui.nodes.#(attributes.name==email).attributes.value").String()) message2 := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account") recoveryCode2 := testhelpers.CourierExpectCodeInMessage(t, message2, 1) - body = submitRecoveryCode(t, c, body, RecoveryFlowTypeBrowser, recoveryCode1, http.StatusOK) + body = submitRecoveryCode(t, c, body, RecoveryClientTypeBrowser, recoveryCode1, http.StatusOK) testhelpers.AssertMessage(t, []byte(body), "The recovery code is invalid or has already been used. Please try again.") // For good measure, check that the second code works! - body = submitRecoveryCode(t, c, body, RecoveryFlowTypeBrowser, recoveryCode2, http.StatusOK) + body = submitRecoveryCode(t, c, body, RecoveryClientTypeBrowser, recoveryCode2, http.StatusOK) testhelpers.AssertMessage(t, []byte(body), "You successfully recovered your account. Please change your password or set up an alternative login method (e.g. social sign in) within the next 60.00 minutes.") }) @@ -1042,7 +869,7 @@ func TestRecovery(t *testing.T) { createIdentityToRecover(t, reg, recoveryEmail) c := testhelpers.NewClientWithCookies(t) - body := expectSuccessfulRecovery(t, c, RecoveryFlowTypeBrowser, func(v url.Values) { + body := expectSuccessfulRecovery(t, c, RecoveryClientTypeBrowser, func(v url.Values) { v.Set("email", recoveryEmail) }) @@ -1050,7 +877,7 @@ func TestRecovery(t *testing.T) { require.NotEmpty(t, action) assert.Equal(t, recoveryEmail, gjson.Get(body, "ui.nodes.#(attributes.name==email).attributes.value").String()) - body = submitRecoveryCode(t, c, body, RecoveryFlowTypeBrowser, "12312312", http.StatusOK) // Now send a wrong code that triggers "global" validation error + body = submitRecoveryCode(t, c, body, RecoveryClientTypeBrowser, "12312312", http.StatusOK) // Now send a wrong code that triggers "global" validation error assert.Empty(t, gjson.Get(body, "ui.nodes.#(attributes.name==code).messages").Array()) testhelpers.AssertMessage(t, []byte(body), "The recovery code is invalid or has already been used. Please try again.") @@ -1066,7 +893,7 @@ func TestRecovery(t *testing.T) { createIdentityToRecover(t, reg, recoveryEmail) cl := testhelpers.NewClientWithCookies(t) - body := expectSuccessfulRecovery(t, cl, RecoveryFlowTypeBrowser, func(v url.Values) { + body := expectSuccessfulRecovery(t, cl, RecoveryClientTypeBrowser, func(v url.Values) { v.Set("email", recoveryEmail) }) @@ -1081,7 +908,7 @@ func TestRecovery(t *testing.T) { return http.ErrUseLastResponse } - body = submitRecoveryCode(t, cl, body, RecoveryFlowTypeBrowser, recoveryCode, http.StatusSeeOther) + body = submitRecoveryCode(t, cl, body, RecoveryClientTypeBrowser, recoveryCode, http.StatusSeeOther) require.Len(t, cl.Jar.Cookies(urlx.ParseOrPanic(public.URL)), 2) cookies := spew.Sdump(cl.Jar.Cookies(urlx.ParseOrPanic(public.URL))) @@ -1098,7 +925,7 @@ func TestRecovery(t *testing.T) { createIdentityToRecover(t, reg, recoveryEmail) cl := testhelpers.NewClientWithCookies(t) - body := expectSuccessfulRecovery(t, cl, RecoveryFlowTypeBrowser, func(v url.Values) { + body := expectSuccessfulRecovery(t, cl, RecoveryClientTypeBrowser, func(v url.Values) { v.Set("email", recoveryEmail) }) @@ -1114,7 +941,7 @@ func TestRecovery(t *testing.T) { } initialFlowId := gjson.Get(body, "id") - body = submitRecoveryCode(t, cl, body, RecoveryFlowTypeBrowser, recoveryCode, http.StatusSeeOther) + body = submitRecoveryCode(t, cl, body, RecoveryClientTypeBrowser, recoveryCode, http.StatusSeeOther) assert.NotEqual(t, gjson.Get(body, "id"), initialFlowId) require.Len(t, cl.Jar.Cookies(urlx.ParseOrPanic(public.URL)), 1) @@ -1123,6 +950,929 @@ func TestRecovery(t *testing.T) { }) } +func TestRecovery_WithContinueWith(t *testing.T) { + ctx := context.Background() + conf, reg := internal.NewFastRegistryWithMocks(t) + testhelpers.StrategyEnable(t, conf, string(recovery.RecoveryStrategyCode), true) + testhelpers.StrategyEnable(t, conf, string(recovery.RecoveryStrategyLink), false) + conf.MustSet(ctx, config.ViperKeyUseContinueWithTransitions, true) + + initViper(t, ctx, conf) + + _ = testhelpers.NewRecoveryUIFlowEchoServer(t, reg) + _ = testhelpers.NewLoginUIFlowEchoServer(t, reg) + _ = testhelpers.NewSettingsUIFlowEchoServer(t, reg) + _ = testhelpers.NewErrorTestServer(t, reg) + + public, _, _, _ := testhelpers.NewKratosServerWithCSRFAndRouters(t, reg) + + submitRecoveryForm := func(t *testing.T, client *http.Client, clientType ClientType, values func(url.Values), code int) string { + isSPA := clientType == RecoveryClientTypeSPA + isAPI := clientType == RecoveryClientTypeAPI + if client == nil { + client = testhelpers.NewDebugClient(t) + if !isAPI { + client = testhelpers.NewClientWithCookies(t) + client.Transport = testhelpers.NewTransportWithLogger(http.DefaultTransport, t).RoundTripper + } + } + + expectedUrl := testhelpers.ExpectURL(isAPI || isSPA, public.URL+recovery.RouteSubmitFlow, conf.SelfServiceFlowRecoveryUI(ctx).String()) + return testhelpers.SubmitRecoveryForm(t, isAPI, isSPA, client, public, values, code, expectedUrl) + } + + submitRecoveryCode := func(t *testing.T, client *http.Client, flow string, flowType ClientType, recoveryCode string, statusCode int) string { + t.Helper() + action := gjson.Get(flow, "ui.action").String() + assert.NotEmpty(t, action) + + values := withCSRFToken(t, flowType, flow, url.Values{ + "code": {recoveryCode}, + "method": {"code"}, + }) + + contentType := "application/json" + if flowType == RecoveryClientTypeBrowser { + contentType = "application/x-www-form-urlencoded" + } + + res, err := client.Post(action, contentType, bytes.NewBufferString(values)) + require.NoError(t, err) + assert.Equal(t, statusCode, res.StatusCode) + + return string(ioutilx.MustReadAll(res.Body)) + } + + resendRecoveryCode := func(t *testing.T, client *http.Client, flow string, flowType ClientType, statusCode int) string { + action := gjson.Get(flow, "ui.action").String() + assert.NotEmpty(t, action) + + email := gjson.Get(flow, "ui.nodes.#(attributes.name==email).attributes.value").String() + + values := withCSRFToken(t, flowType, flow, url.Values{ + "method": {"code"}, + "email": {email}, + }) + + contentType := "application/json" + if flowType == RecoveryClientTypeBrowser { + contentType = "application/x-www-form-urlencoded" + } + + res, err := client.Post(action, contentType, bytes.NewBufferString(values)) + require.NoError(t, err) + assert.Equal(t, statusCode, res.StatusCode) + + return string(ioutilx.MustReadAll(res.Body)) + } + + expectValidationError := func(t *testing.T, hc *http.Client, flowType ClientType, values func(url.Values)) string { + code := testhelpers.ExpectStatusCode(flowType == RecoveryClientTypeAPI || flowType == RecoveryClientTypeSPA, http.StatusBadRequest, http.StatusOK) + return submitRecoveryForm(t, hc, flowType, values, code) + } + + expectVerfiableAddressStatus := func(t *testing.T, email string, status identity.VerifiableAddressStatus) { + addr, err := reg.IdentityPool(). + FindVerifiableAddressByValue(context.Background(), identity.VerifiableAddressTypeEmail, email) + assert.NoError(t, err) + assert.Equal(t, status, addr.Status, "verifiable address %s was not %s. instead %", email, status, addr.Status) + } + + submitCodeAndExpectRedirectToSettings := func(t *testing.T, c *http.Client, clientType ClientType, recoveryCode, body string) { + t.Helper() + switch clientType { + case RecoveryClientTypeBrowser: + body = submitRecoveryCode(t, c, body, clientType, recoveryCode, http.StatusOK) + require.Len(t, c.Jar.Cookies(urlx.ParseOrPanic(public.URL)), 2) + cookies := spew.Sdump(c.Jar.Cookies(urlx.ParseOrPanic(public.URL))) + assert.Contains(t, cookies, "ory_kratos_session") + require.Contains(t, body, "You successfully recovered your account. Please change your password or set up an alternative login method (e.g. social sign in) within the next 60.00 minutes.") + case RecoveryClientTypeSPA: + body = submitRecoveryCode(t, c, body, clientType, recoveryCode, http.StatusOK) + // assert.Equal(t, "browser_location_change_required", gjson.Get(body, "error.id").String()) + require.Len(t, c.Jar.Cookies(urlx.ParseOrPanic(public.URL)), 2) + cookies := spew.Sdump(c.Jar.Cookies(urlx.ParseOrPanic(public.URL))) + assert.Contains(t, cookies, "ory_kratos_session") + + require.NotEmpty(t, gjson.Get(body, "continue_with.#(action==show_settings_ui).flow").String(), "%s", body) + case RecoveryClientTypeAPI: + body = submitRecoveryCode(t, c, body, clientType, recoveryCode, http.StatusOK) + require.NotEmpty(t, gjson.Get(body, "continue_with.#(action==show_settings_ui).flow").String(), "%s", body) + require.NotEmpty(t, gjson.Get(body, "continue_with.#(action==set_ory_session_token).ory_session_token").String(), "%s", body) + } + } + + t.Run("description=should recover an account", func(t *testing.T) { + checkRecovery := func(t *testing.T, client *http.Client, flowType ClientType, recoveryEmail, recoverySubmissionResponse string) string { + expectVerfiableAddressStatus(t, recoveryEmail, identity.VerifiableAddressStatusPending) + + assert.EqualValues(t, node.CodeGroup, gjson.Get(recoverySubmissionResponse, "active").String(), "%s", recoverySubmissionResponse) + assert.True(t, gjson.Get(recoverySubmissionResponse, "ui.nodes.#(attributes.name==code)").Exists(), "%s", recoverySubmissionResponse) + assert.Len(t, gjson.Get(recoverySubmissionResponse, "ui.messages").Array(), 1, "%s", recoverySubmissionResponse) + assertx.EqualAsJSON(t, text.NewRecoveryEmailWithCodeSent(), json.RawMessage(gjson.Get(recoverySubmissionResponse, "ui.messages.0").Raw)) + + message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account") + assert.Contains(t, message.Body, "please recover access to your account by entering the following code") + + recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) + assert.NotEmpty(t, recoveryCode) + + // statusCode := testhelpers.ExpectStatusCode(flowType == RecoveryClientTypeSPA, http.StatusUnprocessableEntity, http.StatusOK) + return submitRecoveryCode(t, client, recoverySubmissionResponse, flowType, recoveryCode, http.StatusOK) + } + + t.Run("type=browser", func(t *testing.T) { + client := testhelpers.NewClientWithCookies(t) + email := testhelpers.RandomEmail() + createIdentityToRecover(t, reg, email) + recoverySubmissionResponse := submitRecoveryForm(t, client, RecoveryClientTypeBrowser, func(v url.Values) { + v.Set("email", email) + }, http.StatusOK) + body := checkRecovery(t, client, RecoveryClientTypeBrowser, email, recoverySubmissionResponse) + + assert.Equal(t, text.NewRecoverySuccessful(time.Now().Add(time.Hour)).Text, + gjson.Get(body, "ui.messages.0.text").String()) + + res, err := client.Get(public.URL + session.RouteWhoami) + require.NoError(t, err) + body = string(x.MustReadAll(res.Body)) + require.NoError(t, res.Body.Close()) + assert.Equal(t, "code_recovery", gjson.Get(body, "authentication_methods.0.method").String(), "%s", body) + assert.Equal(t, "aal1", gjson.Get(body, "authenticator_assurance_level").String(), "%s", body) + }) + + t.Run("type=spa", func(t *testing.T) { + client := testhelpers.NewClientWithCookies(t) + email := testhelpers.RandomEmail() + createIdentityToRecover(t, reg, email) + recoverySubmissionResponse := submitRecoveryForm(t, client, RecoveryClientTypeSPA, func(v url.Values) { + v.Set("email", email) + }, http.StatusOK) + body := checkRecovery(t, client, RecoveryClientTypeSPA, email, recoverySubmissionResponse) + assert.Equal(t, "passed_challenge", gjson.Get(body, "state").String()) + assert.Len(t, gjson.Get(body, "continue_with").Array(), 1) + sfId := gjson.Get(body, "continue_with.#(action==show_settings_ui).flow.id").String() + assert.NotEmpty(t, uuid.Must(uuid.FromString(sfId))) + }) + + t.Run("type=api", func(t *testing.T) { + client := &http.Client{} + email := testhelpers.RandomEmail() + createIdentityToRecover(t, reg, email) + recoverySubmissionResponse := submitRecoveryForm(t, client, RecoveryClientTypeAPI, func(v url.Values) { + v.Set("email", email) + }, http.StatusOK) + body := checkRecovery(t, client, RecoveryClientTypeAPI, email, recoverySubmissionResponse) + assert.Equal(t, "passed_challenge", gjson.Get(body, "state").String()) + assert.Len(t, gjson.Get(body, "continue_with").Array(), 2) + assert.NotEmpty(t, gjson.Get(body, "continue_with.#(action==set_ory_session_token).ory_session_token").String()) + sfId := gjson.Get(body, "continue_with.#(action==show_settings_ui).flow.id").String() + assert.NotEmpty(t, uuid.Must(uuid.FromString(sfId))) + }) + + t.Run("description=should return browser to return url", func(t *testing.T) { + returnTo := public.URL + "/return-to" + conf.Set(ctx, config.ViperKeyURLsAllowedReturnToDomains, []string{returnTo}) + for _, tc := range []struct { + desc string + returnTo string + f func(t *testing.T, client *http.Client, identity *identity.Identity) *kratos.RecoveryFlow + expectedAAL string + }{ + { + desc: "should use return_to from recovery flow", + returnTo: returnTo, + f: func(t *testing.T, client *http.Client, identity *identity.Identity) *kratos.RecoveryFlow { + return testhelpers.InitializeRecoveryFlowViaBrowser(t, client, false, public, url.Values{"return_to": []string{returnTo}}) + }, + }, + { + desc: "should use return_to from config", + returnTo: returnTo, + f: func(t *testing.T, client *http.Client, identity *identity.Identity) *kratos.RecoveryFlow { + conf.Set(ctx, config.ViperKeySelfServiceRecoveryBrowserDefaultReturnTo, returnTo) + t.Cleanup(func() { + conf.Set(ctx, config.ViperKeySelfServiceRecoveryBrowserDefaultReturnTo, "") + }) + return testhelpers.InitializeRecoveryFlowViaBrowser(t, client, false, public, nil) + }, + }, + { + desc: "no return to", + returnTo: "", + f: func(t *testing.T, client *http.Client, identity *identity.Identity) *kratos.RecoveryFlow { + return testhelpers.InitializeRecoveryFlowViaBrowser(t, client, false, public, nil) + }, + }, + { + desc: "should use return_to with an account that has 2fa enabled", + returnTo: returnTo, + f: func(t *testing.T, client *http.Client, id *identity.Identity) *kratos.RecoveryFlow { + conf.Set(ctx, config.ViperKeySelfServiceSettingsRequiredAAL, config.HighestAvailableAAL) + conf.Set(ctx, config.ViperKeySessionWhoAmIAAL, config.HighestAvailableAAL) + conf.Set(ctx, config.ViperKeyWebAuthnRPDisplayName, "Kratos") + conf.Set(ctx, config.ViperKeyWebAuthnRPID, "ory.sh") + + t.Cleanup(func() { + conf.MustSet(ctx, config.ViperKeySessionWhoAmIAAL, identity.AuthenticatorAssuranceLevel1) + conf.MustSet(ctx, config.ViperKeySelfServiceSettingsRequiredAAL, identity.AuthenticatorAssuranceLevel1) + }) + testhelpers.StrategyEnable(t, conf, identity.CredentialsTypeWebAuthn.String(), true) + + id.SetCredentials(identity.CredentialsTypeWebAuthn, identity.Credentials{ + Type: identity.CredentialsTypeWebAuthn, + Config: []byte(`{"credentials":[{"is_passwordless":false, "display_name":"test"}]}`), + Identifiers: []string{testhelpers.RandomEmail()}, + }) + + require.NoError(t, reg.IdentityManager().Update(ctx, id, identity.ManagerAllowWriteProtectedTraits)) + return testhelpers.InitializeRecoveryFlowViaBrowser(t, client, false, public, url.Values{"return_to": []string{returnTo}}) + }, + expectedAAL: "aal2", + }, + } { + t.Run(fmt.Sprintf("%s", tc.desc), func(t *testing.T) { + client := testhelpers.NewClientWithCookies(t) + email := testhelpers.RandomEmail() + i := createIdentityToRecover(t, reg, email) + + client.Transport = testhelpers.NewTransportWithLogger(http.DefaultTransport, t).RoundTripper + f := tc.f(t, client, i) + + formPayload := testhelpers.SDKFormFieldsToURLValues(f.Ui.Nodes) + formPayload.Set("email", email) + + body, res := testhelpers.RecoveryMakeRequest(t, false, f, client, formPayload.Encode()) + assert.EqualValues(t, http.StatusOK, res.StatusCode, "%s", body) + expectedURL := testhelpers.ExpectURL(false, public.URL+recovery.RouteSubmitFlow, conf.SelfServiceFlowRecoveryUI(ctx).String()) + assert.Contains(t, res.Request.URL.String(), expectedURL, "%+v\n\t%s", res.Request, body) + + body = checkRecovery(t, client, RecoveryClientTypeBrowser, email, body) + + require.Equal(t, text.NewRecoverySuccessful(time.Now().Add(time.Hour)).Text, + gjson.Get(body, "ui.messages.0.text").String()) + + settingsId := gjson.Get(body, "id").String() + + sf, err := reg.SettingsFlowPersister().GetSettingsFlow(ctx, uuid.Must(uuid.FromString(settingsId))) + require.NoError(t, err) + + u, err := url.Parse(public.URL) + require.NoError(t, err) + require.Len(t, client.Jar.Cookies(u), 2) + found := false + for _, cookie := range client.Jar.Cookies(u) { + if cookie.Name == "ory_kratos_session" { + found = true + } + } + require.True(t, found) + + require.Equal(t, tc.returnTo, sf.ReturnTo) + res, err = client.Get(public.URL + session.RouteWhoami) + require.NoError(t, err) + body = string(x.MustReadAll(res.Body)) + require.NoError(t, res.Body.Close()) + + if tc.expectedAAL == "aal2" { + require.Equal(t, http.StatusForbidden, res.StatusCode) + require.Equalf(t, session.NewErrAALNotSatisfied("").Reason(), gjson.Get(body, "error.reason").String(), "%s", body) + require.Equalf(t, "session_aal2_required", gjson.Get(body, "error.id").String(), "%s", body) + } else { + assert.Equal(t, "code_recovery", gjson.Get(body, "authentication_methods.0.method").String(), "%s", body) + assert.Equal(t, "aal1", gjson.Get(body, "authenticator_assurance_level").String(), "%s", body) + } + }) + } + }) + }) + + t.Run("description=should set all the correct recovery payloads after submission", func(t *testing.T) { + for _, testCase := range flowTypeCases { + t.Run("type="+testCase.ClientType.String(), func(t *testing.T) { + body := submitRecoveryForm(t, testCase.GetClient(t), testCase.ClientType, func(v url.Values) { + v.Set("email", "test@ory.sh") + }, http.StatusOK) + testhelpers.SnapshotTExcept(t, json.RawMessage(gjson.Get(body, "ui.nodes").String()), []string{"0.attributes.value"}) + }) + } + }) + + t.Run("description=should set all the correct recovery payloads", func(t *testing.T) { + for _, testCase := range flowTypeCases { + t.Run("type="+testCase.ClientType.String(), func(t *testing.T) { + c := testCase.GetClient(t) + rs := testhelpers.GetRecoveryFlowForType(t, c, public, testCase.FlowType) + + testhelpers.SnapshotTExcept(t, rs.Ui.Nodes, []string{"0.attributes.value"}) + assert.EqualValues(t, public.URL+recovery.RouteSubmitFlow+"?flow="+rs.Id, rs.Ui.Action) + assert.Empty(t, rs.Ui.Messages) + }) + } + }) + + t.Run("description=should require an email to be sent", func(t *testing.T) { + for _, flowType := range flowTypes { + t.Run("type="+flowType.String(), func(t *testing.T) { + body := expectValidationError(t, nil, flowType, func(v url.Values) { + v.Del("email") + }) + assert.EqualValues(t, node.CodeGroup, gjson.Get(body, "active").String(), "%s", body) + assert.EqualValues(t, "Property email is missing.", + gjson.Get(body, "ui.nodes.#(attributes.name==email).messages.0.text").String(), + "%s", body) + }) + } + }) + + t.Run("description=should require a valid email to be sent", func(t *testing.T) { + for _, flowType := range flowTypes { + t.Run("type="+flowType.String(), func(t *testing.T) { + for _, email := range []string{"\\", "asdf", "...", "aiacobelli.sec@gmail.com,alejandro.iacobelli@mercadolibre.com"} { + responseJSON := expectValidationError(t, nil, flowType, func(v url.Values) { + v.Set("email", email) + }) + activeMethod := gjson.Get(responseJSON, "active").String() + assert.EqualValues(t, node.CodeGroup, activeMethod, "expected method to be %s got %s", node.CodeGroup, activeMethod) + expectedMessage := fmt.Sprintf("%q is not valid \"email\"", email) + actualMessage := gjson.Get(responseJSON, "ui.nodes.#(attributes.name==email).messages.0.text").String() + assert.EqualValues(t, expectedMessage, actualMessage, "%s", responseJSON) + } + }) + } + }) + + t.Run("description=should try to submit the form while authenticated", func(t *testing.T) { + for _, testCase := range flowTypeCases { + t.Run("type="+testCase.ClientType.String(), func(t *testing.T) { + isSPA := testCase.ClientType == "spa" + isAPI := testCase.ClientType == "api" + client := testCase.GetClient(t) + + var f *kratos.RecoveryFlow + if isAPI { + f = testhelpers.InitializeRecoveryFlowViaAPI(t, client, public) + } else { + f = testhelpers.InitializeRecoveryFlowViaBrowser(t, client, isSPA, public, nil) + } + req := httptest.NewRequest("GET", "/sessions/whoami", nil) + + session, err := session.NewActiveSession( + req, + &identity.Identity{ID: x.NewUUID(), State: identity.StateActive}, + testhelpers.NewSessionLifespanProvider(time.Hour), + time.Now(), + identity.CredentialsTypePassword, + identity.AuthenticatorAssuranceLevel1, + ) + + require.NoError(t, err) + + // Add the authentication to the request + client.Transport = testhelpers.NewTransportWithLogger(testhelpers.NewAuthorizedTransport(t, reg, session), t).RoundTripper + + v := testhelpers.SDKFormFieldsToURLValues(f.Ui.Nodes) + v.Set("email", "some-email@example.org") + v.Set("method", "code") + + body, res := testhelpers.RecoveryMakeRequest(t, isAPI || isSPA, f, client, testhelpers.EncodeFormAsJSON(t, isAPI || isSPA, v)) + + if isAPI || isSPA { + assert.EqualValues(t, http.StatusBadRequest, res.StatusCode, "%s", body) + assert.Contains(t, res.Request.URL.String(), recovery.RouteSubmitFlow, "%+v\n\t%s", res.Request, body) + assertx.EqualAsJSONExcept(t, recovery.ErrAlreadyLoggedIn, json.RawMessage(gjson.Get(body, "error").Raw), nil) + } else { + assert.EqualValues(t, http.StatusOK, res.StatusCode, "%s", body) + assert.Contains(t, res.Request.URL.String(), conf.SelfServiceBrowserDefaultReturnTo(ctx).String(), "%+v\n\t%s", res.Request, body) + } + }) + } + }) + + t.Run("description=should not be able to recover account that does not exist", func(t *testing.T) { + conf.Set(ctx, config.ViperKeySelfServiceRecoveryNotifyUnknownRecipients, true) + + t.Cleanup(func() { + conf.Set(ctx, config.ViperKeySelfServiceRecoveryNotifyUnknownRecipients, false) + }) + + for _, testCase := range flowTypeCases { + t.Run("type="+testCase.ClientType.String(), func(t *testing.T) { + email := x.NewUUID().String() + "@ory.sh" + c := testCase.GetClient(t) + withValues := func(v url.Values) { + v.Set("email", email) + } + body := submitRecoveryForm(t, c, testCase.ClientType, withValues, http.StatusOK) + assert.EqualValues(t, node.CodeGroup, gjson.Get(body, "active").String(), "%s", body) + assert.Empty(t, gjson.Get(body, "ui.nodes.#(attributes.name==code).attributes.value").String(), "%s", body) + assertx.EqualAsJSON(t, text.NewRecoveryEmailWithCodeSent(), json.RawMessage(gjson.Get(body, "ui.messages.0").Raw)) + + message := testhelpers.CourierExpectMessage(ctx, t, reg, email, "Account access attempted") + assert.Contains(t, message.Body, "If this was you, check if you signed up using a different address.") + }) + } + }) + + t.Run("description=should not be able to recover an inactive account", func(t *testing.T) { + for _, testCase := range flowTypeCases { + t.Run("type="+testCase.ClientType.String(), func(t *testing.T) { + email := "recoverinactive_" + testCase.ClientType.String() + "@ory.sh" + createIdentityToRecover(t, reg, email) + values := func(v url.Values) { + v.Set("email", email) + } + cl := testhelpers.NewClientWithCookies(t) + + body := submitRecoveryForm(t, cl, testCase.ClientType, values, http.StatusOK) + addr, err := reg.IdentityPool().FindVerifiableAddressByValue(context.Background(), identity.VerifiableAddressTypeEmail, email) + assert.NoError(t, err) + + emailText := testhelpers.CourierExpectMessage(ctx, t, reg, email, "Recover access to your account") + recoveryCode := testhelpers.CourierExpectCodeInMessage(t, emailText, 1) + + // Deactivate the identity + require.NoError(t, reg.Persister().GetConnection(context.Background()).RawQuery("UPDATE identities SET state=? WHERE id = ?", identity.StateInactive, addr.IdentityID).Exec()) + + switch testCase.ClientType { + case RecoveryClientTypeAPI: + fallthrough + case RecoveryClientTypeSPA: + body = submitRecoveryCode(t, cl, body, testCase.ClientType, recoveryCode, http.StatusUnauthorized) + assertx.EqualAsJSON(t, session.ErrIdentityDisabled.WithDetail("identity_id", addr.IdentityID), json.RawMessage(gjson.Get(body, "error").Raw), "%s", body) + default: + body = submitRecoveryCode(t, cl, body, testCase.ClientType, recoveryCode, http.StatusOK) + assertx.EqualAsJSON(t, session.ErrIdentityDisabled.WithDetail("identity_id", addr.IdentityID), json.RawMessage(body), "%s", body) + } + }) + } + }) + + t.Run("description=should recover and invalidate all other sessions if hook is set", func(t *testing.T) { + conf.MustSet(ctx, config.HookStrategyKey(config.ViperKeySelfServiceRecoveryAfter, config.HookGlobal), []config.SelfServiceHook{{Name: "revoke_active_sessions"}}) + t.Cleanup(func() { + conf.MustSet(ctx, config.HookStrategyKey(config.ViperKeySelfServiceRegistrationAfter, identity.CredentialsTypePassword.String()), nil) + }) + + for _, testCase := range flowTypeCases { + t.Run("type="+testCase.ClientType.String(), func(t *testing.T) { + email := testhelpers.RandomEmail() + id := createIdentityToRecover(t, reg, email) + + otherSession, err := session.NewActiveSession(httptest.NewRequest("GET", "/sessions/whoami", nil), id, conf, time.Now(), identity.CredentialsTypePassword, identity.AuthenticatorAssuranceLevel1) + require.NoError(t, err) + require.NoError(t, reg.SessionPersister().UpsertSession(ctx, otherSession)) + + refetchedOtherSession, err := reg.SessionPersister().GetSession(ctx, otherSession.ID, session.ExpandNothing) + require.NoError(t, err) + assert.True(t, refetchedOtherSession.IsActive()) + + cl := testCase.GetClient(t) + actual := submitRecoveryForm(t, cl, testCase.ClientType, func(v url.Values) { + v.Set("email", email) + }, http.StatusOK) + message := testhelpers.CourierExpectMessage(ctx, t, reg, email, "Recover access to your account") + recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) + + submitCodeAndExpectRedirectToSettings(t, cl, testCase.ClientType, recoveryCode, actual) + + refetchedOtherSession, err = reg.SessionPersister().GetSession(ctx, otherSession.ID, session.ExpandNothing) + require.NoError(t, err) + assert.False(t, refetchedOtherSession.IsActive()) + }) + } + }) + + t.Run("description=should not be able to use an invalid code more than 5 times", func(t *testing.T) { + for _, testCase := range flowTypeCases { + t.Run("type="+testCase.ClientType.String(), func(t *testing.T) { + email := testhelpers.RandomEmail() + createIdentityToRecover(t, reg, email) + c := testCase.GetClient(t) + body := submitRecoveryForm(t, c, testCase.ClientType, func(v url.Values) { + v.Set("email", email) + }, http.StatusOK) + + initialFlowId := gjson.Get(body, "id") + + for submitTry := 0; submitTry < 5; submitTry++ { + body := submitRecoveryCode(t, c, body, testCase.ClientType, "12312312", http.StatusOK) + + testhelpers.AssertMessage(t, []byte(body), "The recovery code is invalid or has already been used. Please try again.") + } + + switch testCase.ClientType { + case RecoveryClientTypeBrowser: + // submit an invalid code for the 6th time + body = submitRecoveryCode(t, c, body, testCase.ClientType, "12312312", http.StatusOK) + + require.Len(t, gjson.Get(body, "ui.messages").Array(), 1, "%s", body) + assert.Equal(t, "The request was submitted too often. Please request another code.", gjson.Get(body, "ui.messages.0.text").String()) + + // check that a new flow has been created + assert.NotEqual(t, gjson.Get(body, "id"), initialFlowId) + + assert.True(t, gjson.Get(body, "ui.nodes.#(attributes.name==email)").Exists()) + case RecoveryClientTypeSPA: + fallthrough + case RecoveryClientTypeAPI: + // submit an invalid code for the 6th time + body = submitRecoveryCode(t, c, body, testCase.ClientType, "12312312", http.StatusBadRequest) + + assert.Equal(t, "Bad Request", gjson.Get(body, "error.status").String(), "%s", body) + assert.Equal(t, "The request was submitted too often. Please request another code.", gjson.Get(body, "error.reason").String(), "%s", body) + continueWith := gjson.Get(body, "error.details.continue_with").Array() + assert.Len(t, continueWith, 1, "%s", body) + assert.Equal(t, "show_recovery_ui", continueWith[0].Get("action").String(), "%s", body) + flowId := continueWith[0].Get("flow.id").String() + assert.NotEmpty(t, flowId, "%s", body) + require.NotEqual(t, flowId, initialFlowId, "%s", body) + + flow, err := reg.Persister().GetRecoveryFlow(ctx, uuid.Must(uuid.FromString(flowId))) + require.NoError(t, err) + assert.Len(t, flow.UI.Messages, 1, "%+v", flow) + assert.Equal(t, "The request was submitted too often. Please request another code.", flow.UI.Messages[0].Text) + } + }) + } + }) + + t.Run("description=should be able to recover after using invalid code", func(t *testing.T) { + for _, testCase := range flowTypeCases { + t.Run("type="+testCase.ClientType.String(), func(t *testing.T) { + c := testCase.GetClient(t) + recoveryEmail := testhelpers.RandomEmail() + _ = createIdentityToRecover(t, reg, recoveryEmail) + + actual := submitRecoveryForm(t, c, testCase.ClientType, func(v url.Values) { + v.Set("email", recoveryEmail) + }, http.StatusOK) + + message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account") + recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) + + form := withCSRFToken(t, testCase.ClientType, actual, url.Values{ + "code": {"12312312"}, + }) + + action := gjson.Get(actual, "ui.action").String() + require.NotEmpty(t, action) + + res, err := c.Post(action, testCase.FormContentType, bytes.NewBufferString(form)) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, res.StatusCode) + + flowId := gjson.Get(actual, "id").String() + require.NotEmpty(t, flowId) + + rs, res, err := testhelpers. + NewSDKCustomClient(public, c). + FrontendApi.GetRecoveryFlow(context.Background()). + Id(flowId). + Execute() + + require.NoError(t, err) + body := ioutilx.MustReadAll(res.Body) + require.NotEmpty(t, body) + + require.Len(t, rs.Ui.Messages, 1) + assert.Equal(t, "The recovery code is invalid or has already been used. Please try again.", rs.Ui.Messages[0].Text) + + form = withCSRFToken(t, testCase.ClientType, actual, url.Values{ + "code": {recoveryCode}, + }) + // Now submit the correct code + res, err = c.Post(action, testCase.FormContentType, bytes.NewBufferString(form)) + require.NoError(t, err) + switch testCase.ClientType { + case RecoveryClientTypeBrowser: + assert.Equal(t, http.StatusOK, res.StatusCode) + + json := ioutilx.MustReadAll(res.Body) + + assert.Len(t, gjson.GetBytes(json, "ui.messages").Array(), 1) + assert.Contains(t, gjson.GetBytes(json, "ui.messages.0.text").String(), "You successfully recovered your account.") + case RecoveryClientTypeSPA: + assert.Equal(t, http.StatusOK, res.StatusCode) + + json := ioutilx.MustReadAll(res.Body) + + require.Len(t, c.Jar.Cookies(urlx.ParseOrPanic(public.URL)), 2) + cookies := spew.Sdump(c.Jar.Cookies(urlx.ParseOrPanic(public.URL))) + assert.Contains(t, cookies, "ory_kratos_session") + + require.NotEmpty(t, gjson.GetBytes(json, "continue_with.#(action==show_settings_ui).flow").String(), "%s", json) + case RecoveryClientTypeAPI: + assert.Equal(t, http.StatusOK, res.StatusCode) + + json := ioutilx.MustReadAll(res.Body) + + require.NotEmpty(t, gjson.GetBytes(json, "continue_with.#(action==show_settings_ui).flow").String(), "%s", json) + require.NotEmpty(t, gjson.GetBytes(json, "continue_with.#(action==set_ory_session_token).ory_session_token").String(), "%s", json) + } + }) + } + }) + + t.Run("description=should not be able to use an invalid code", func(t *testing.T) { + for _, testCase := range flowTypeCases { + t.Run("type="+testCase.ClientType.String(), func(t *testing.T) { + email := testhelpers.RandomEmail() + createIdentityToRecover(t, reg, email) + c := testCase.GetClient(t) + + body := submitRecoveryForm(t, c, testCase.ClientType, func(v url.Values) { + v.Set("email", email) + }, http.StatusOK) + + body = submitRecoveryCode(t, c, body, RecoveryClientTypeBrowser, "12312312", http.StatusOK) + + testhelpers.AssertMessage(t, []byte(body), "The recovery code is invalid or has already been used. Please try again.") + }) + } + }) + + t.Run("description=should not be able to submit recover address after flow expired", func(t *testing.T) { + for _, testCase := range flowTypeCases { + t.Run("type="+testCase.ClientType.String(), func(t *testing.T) { + recoveryEmail := testhelpers.RandomEmail() + createIdentityToRecover(t, reg, recoveryEmail) + conf.MustSet(ctx, config.ViperKeySelfServiceRecoveryRequestLifespan, time.Millisecond*10) + t.Cleanup(func() { + conf.MustSet(ctx, config.ViperKeySelfServiceRecoveryRequestLifespan, time.Minute) + }) + + c := testCase.GetClient(t) + var rs *kratos.RecoveryFlow + var res *http.Response + var err error + switch testCase.ClientType { + case RecoveryClientTypeBrowser: + fallthrough + case RecoveryClientTypeSPA: + rs = testhelpers.GetRecoveryFlow(t, c, public) + time.Sleep(time.Millisecond * 11) + res, err = c.PostForm(rs.Ui.Action, url.Values{"email": {recoveryEmail}, "method": {"code"}}) + require.NoError(t, err) + assert.EqualValues(t, http.StatusOK, res.StatusCode) + assert.NotContains(t, res.Request.URL.String(), "flow="+rs.Id) + assert.Contains(t, res.Request.URL.String(), conf.SelfServiceFlowRecoveryUI(ctx).String()) + case RecoveryClientTypeAPI: + rs = testhelpers.InitializeRecoveryFlowViaAPI(t, c, public) + time.Sleep(time.Millisecond * 11) + form := testhelpers.EncodeFormAsJSON(t, true, url.Values{"email": {recoveryEmail}, "method": {"code"}}) + res, err = c.Post(rs.Ui.Action, "application/json", bytes.NewBufferString(form)) + require.NoError(t, err) + body := ioutilx.MustReadAll(res.Body) + assert.Equal(t, http.StatusGone, res.StatusCode, "%s", body) + assert.Equal(t, "self_service_flow_expired", gjson.GetBytes(body, "error.id").String(), "%s", body) + continueWith := gjson.GetBytes(body, "error.details.continue_with").Array() + assert.Len(t, continueWith, 1, "%s", body) + assert.Equal(t, "show_recovery_ui", continueWith[0].Get("action").String(), "%s", continueWith) + flowId := continueWith[0].Get("flow.id").String() + require.NotEmpty(t, flowId, "%s", body) + } + + addr, err := reg.IdentityPool().FindVerifiableAddressByValue(context.Background(), identity.VerifiableAddressTypeEmail, recoveryEmail) + assert.NoError(t, err) + assert.False(t, addr.Verified) + assert.Nil(t, addr.VerifiedAt) + assert.Equal(t, identity.VerifiableAddressStatusPending, addr.Status) + }) + } + }) + + t.Run("description=should not be able to submit code after flow expired", func(t *testing.T) { + conf.MustSet(ctx, config.ViperKeySelfServiceRecoveryRequestLifespan, time.Millisecond*200) + t.Cleanup(func() { + conf.MustSet(ctx, config.ViperKeySelfServiceRecoveryRequestLifespan, time.Minute) + }) + for _, testCase := range flowTypeCases { + t.Run("type="+testCase.ClientType.String(), func(t *testing.T) { + recoveryEmail := testhelpers.RandomEmail() + createIdentityToRecover(t, reg, recoveryEmail) + + c := testhelpers.NewClientWithCookies(t) + + body := submitRecoveryForm(t, c, testCase.ClientType, func(v url.Values) { + v.Set("email", recoveryEmail) + }, http.StatusOK) + + initialFlowId := gjson.Get(body, "id") + + message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account") + assert.Contains(t, message.Body, "please recover access to your account by entering the following code") + + recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) + + time.Sleep(time.Millisecond * 201) + + if testCase.FlowType == "browser" { + body = submitRecoveryCode(t, c, body, testCase.ClientType, recoveryCode, http.StatusOK) + assert.NotEqual(t, gjson.Get(body, "id"), initialFlowId) + + testhelpers.AssertMessage(t, []byte(body), "The recovery flow expired 0.00 minutes ago, please try again.") + } else { + body = submitRecoveryCode(t, c, body, testCase.ClientType, recoveryCode, http.StatusGone) + assert.NotEqual(t, gjson.Get(body, "id"), initialFlowId) + assert.Equal(t, "self_service_flow_expired", gjson.Get(body, "error.id").String()) + } + + addr, err := reg.IdentityPool().FindVerifiableAddressByValue(context.Background(), identity.VerifiableAddressTypeEmail, recoveryEmail) + require.NoError(t, err) + assert.False(t, addr.Verified) + assert.Nil(t, addr.VerifiedAt) + assert.Equal(t, identity.VerifiableAddressStatusPending, addr.Status) + }) + } + }) + + t.Run("description=should not break ui if empty code is submitted", func(t *testing.T) { + for _, testCase := range flowTypeCases { + t.Run("type="+testCase.ClientType.String(), func(t *testing.T) { + recoveryEmail := testhelpers.RandomEmail() + createIdentityToRecover(t, reg, recoveryEmail) + + c := testCase.GetClient(t) + body := submitRecoveryForm(t, c, testCase.ClientType, func(v url.Values) { + v.Set("email", recoveryEmail) + }, http.StatusOK) + + action := gjson.Get(body, "ui.action").String() + require.NotEmpty(t, action) + + body = submitRecoveryCode(t, c, body, testCase.ClientType, "", http.StatusOK) + + assert.NotContains(t, gjson.Get(body, "ui.nodes").String(), "Property email is missing.") + testhelpers.AssertMessage(t, []byte(body), "The recovery code is invalid or has already been used. Please try again.") + }) + } + }) + + t.Run("description=should be able to resend the recovery code", func(t *testing.T) { + for _, testCase := range flowTypeCases { + t.Run("type="+testCase.ClientType.String(), func(t *testing.T) { + recoveryEmail := testhelpers.RandomEmail() + createIdentityToRecover(t, reg, recoveryEmail) + + c := testCase.GetClient(t) + body := submitRecoveryForm(t, c, testCase.ClientType, func(v url.Values) { + v.Set("email", recoveryEmail) + }, http.StatusOK) + + action := gjson.Get(body, "ui.action").String() + require.NotEmpty(t, action) + assert.Equal(t, recoveryEmail, gjson.Get(body, "ui.nodes.#(attributes.name==email).attributes.value").String()) + + body = resendRecoveryCode(t, c, body, testCase.ClientType, http.StatusOK) + assert.True(t, gjson.Get(body, "ui.nodes.#(attributes.name==code)").Exists()) + assert.Equal(t, recoveryEmail, gjson.Get(body, "ui.nodes.#(attributes.name==email).attributes.value").String()) + + message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account") + recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) + + submitCodeAndExpectRedirectToSettings(t, c, testCase.ClientType, recoveryCode, body) + }) + } + }) + + t.Run("description=should not be able to use first code after re-sending email", func(t *testing.T) { + for _, testCase := range flowTypeCases { + t.Run("type="+testCase.ClientType.String(), func(t *testing.T) { + recoveryEmail := testhelpers.RandomEmail() + createIdentityToRecover(t, reg, recoveryEmail) + + c := testCase.GetClient(t) + body := submitRecoveryForm(t, c, testCase.ClientType, func(v url.Values) { + v.Set("email", recoveryEmail) + }, http.StatusOK) + + action := gjson.Get(body, "ui.action").String() + require.NotEmpty(t, action) + assert.Equal(t, recoveryEmail, gjson.Get(body, "ui.nodes.#(attributes.name==email).attributes.value").String()) + + message1 := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account") + recoveryCode1 := testhelpers.CourierExpectCodeInMessage(t, message1, 1) + + body = resendRecoveryCode(t, c, body, testCase.ClientType, http.StatusOK) + assert.True(t, gjson.Get(body, "ui.nodes.#(attributes.name==code)").Exists()) + assert.Equal(t, recoveryEmail, gjson.Get(body, "ui.nodes.#(attributes.name==email).attributes.value").String()) + + message2 := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account") + recoveryCode2 := testhelpers.CourierExpectCodeInMessage(t, message2, 1) + + body = submitRecoveryCode(t, c, body, testCase.ClientType, recoveryCode1, http.StatusOK) + testhelpers.AssertMessage(t, []byte(body), "The recovery code is invalid or has already been used. Please try again.") + + submitCodeAndExpectRedirectToSettings(t, c, testCase.ClientType, recoveryCode2, body) + }) + } + }) + + t.Run("description=should not show outdated validation message if newer message appears #2799", func(t *testing.T) { + for _, testCase := range flowTypeCases { + t.Run("type="+testCase.ClientType.String(), func(t *testing.T) { + recoveryEmail := testhelpers.RandomEmail() + createIdentityToRecover(t, reg, recoveryEmail) + + c := testCase.GetClient(t) + body := submitRecoveryForm(t, c, testCase.ClientType, func(v url.Values) { + v.Set("email", recoveryEmail) + }, http.StatusOK) + + action := gjson.Get(body, "ui.action").String() + require.NotEmpty(t, action) + assert.Equal(t, recoveryEmail, gjson.Get(body, "ui.nodes.#(attributes.name==email).attributes.value").String()) + + body = submitRecoveryCode(t, c, body, testCase.ClientType, "12312312", http.StatusOK) // Now send a wrong code that triggers "global" validation error + + assert.Empty(t, gjson.Get(body, "ui.nodes.#(attributes.name==code).messages").Array()) + testhelpers.AssertMessage(t, []byte(body), "The recovery code is invalid or has already been used. Please try again.") + }) + } + }) + + t.Run("description=should recover if post recovery hook is successful", func(t *testing.T) { + for _, testCase := range flowTypeCases { + t.Run("type="+testCase.ClientType.String(), func(t *testing.T) { + conf.MustSet(ctx, config.HookStrategyKey(config.ViperKeySelfServiceRecoveryAfter, config.HookGlobal), []config.SelfServiceHook{{Name: "err", Config: []byte(`{}`)}}) + t.Cleanup(func() { + conf.MustSet(ctx, config.HookStrategyKey(config.ViperKeySelfServiceRecoveryAfter, config.HookGlobal), nil) + }) + + recoveryEmail := testhelpers.RandomEmail() + createIdentityToRecover(t, reg, recoveryEmail) + + cl := testCase.GetClient(t) + body := submitRecoveryForm(t, cl, testCase.ClientType, func(v url.Values) { + v.Set("email", recoveryEmail) + }, http.StatusOK) + + message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account") + recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) + + action := gjson.Get(body, "ui.action").String() + require.NotEmpty(t, action) + assert.Equal(t, recoveryEmail, gjson.Get(body, "ui.nodes.#(attributes.name==email).attributes.value").String()) + + submitCodeAndExpectRedirectToSettings(t, cl, testCase.ClientType, recoveryCode, body) + }) + } + }) + + t.Run("description=should not be able to recover if post recovery hook fails", func(t *testing.T) { + for _, testCase := range flowTypeCases { + t.Run("type="+testCase.ClientType.String(), func(t *testing.T) { + conf.MustSet(ctx, config.HookStrategyKey(config.ViperKeySelfServiceRecoveryAfter, config.HookGlobal), []config.SelfServiceHook{{Name: "err", Config: []byte(`{"ExecutePostRecoveryHook": "err"}`)}}) + t.Cleanup(func() { + conf.MustSet(ctx, config.HookStrategyKey(config.ViperKeySelfServiceRecoveryAfter, config.HookGlobal), nil) + }) + + recoveryEmail := testhelpers.RandomEmail() + createIdentityToRecover(t, reg, recoveryEmail) + + cl := testhelpers.NewClientWithCookies(t) + body := submitRecoveryForm(t, cl, testCase.ClientType, func(v url.Values) { + v.Set("email", recoveryEmail) + }, http.StatusOK) + + message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account") + recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) + + action := gjson.Get(body, "ui.action").String() + require.NotEmpty(t, action) + assert.Equal(t, recoveryEmail, gjson.Get(body, "ui.nodes.#(attributes.name==email).attributes.value").String()) + + cl.CheckRedirect = func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + } + + initialFlowId := gjson.Get(body, "id") + switch testCase.ClientType { + case RecoveryClientTypeBrowser: + body = submitRecoveryCode(t, cl, body, testCase.ClientType, recoveryCode, http.StatusSeeOther) + assert.NotEqual(t, gjson.Get(body, "id"), initialFlowId) + + require.Len(t, cl.Jar.Cookies(urlx.ParseOrPanic(public.URL)), 1) + cookies := spew.Sdump(cl.Jar.Cookies(urlx.ParseOrPanic(public.URL))) + assert.NotContains(t, cookies, "ory_kratos_session") + case RecoveryClientTypeSPA: + body = submitRecoveryCode(t, cl, body, testCase.ClientType, recoveryCode, http.StatusBadRequest) + assert.NotEqual(t, gjson.Get(body, "id"), initialFlowId) + + require.Len(t, cl.Jar.Cookies(urlx.ParseOrPanic(public.URL)), 1) + cookies := spew.Sdump(cl.Jar.Cookies(urlx.ParseOrPanic(public.URL))) + assert.NotContains(t, cookies, "ory_kratos_session") + case RecoveryClientTypeAPI: + body = submitRecoveryCode(t, cl, body, testCase.ClientType, recoveryCode, http.StatusBadRequest) + assert.NotEqual(t, gjson.Get(body, "id"), initialFlowId) + require.Equal(t, "err", gjson.Get(body, "error.message").String(), "%s", body) + } + }) + } + }) +} + func TestDisabledStrategy(t *testing.T) { ctx := context.Background() conf, reg := internal.NewFastRegistryWithMocks(t) diff --git a/selfservice/strategy/code/strategy_verification_test.go b/selfservice/strategy/code/strategy_verification_test.go index 9be8cd08145d..cdbfedc6069d 100644 --- a/selfservice/strategy/code/strategy_verification_test.go +++ b/selfservice/strategy/code/strategy_verification_test.go @@ -458,7 +458,7 @@ func TestVerification(t *testing.T) { assert.Equal(t, text.ErrIDSelfServiceFlowReplaced, gjson.GetBytes(f2, "error.id").String()) }) - resendVerificationCode := func(t *testing.T, client *http.Client, flow string, flowType string, statusCode int) string { + resendVerificationCode := func(t *testing.T, client *http.Client, flow string, flowType ClientType, statusCode int) string { action := gjson.Get(flow, "ui.action").String() assert.NotEmpty(t, action) @@ -470,7 +470,7 @@ func TestVerification(t *testing.T) { }) contentType := "application/json" - if flowType == RecoveryFlowTypeBrowser { + if flowType == RecoveryClientTypeBrowser { contentType = "application/x-www-form-urlencoded" } @@ -490,7 +490,7 @@ func TestVerification(t *testing.T) { _ = testhelpers.CourierExpectCodeInMessage(t, message, 1) c := testhelpers.NewClientWithCookies(t) - body = resendVerificationCode(t, c, body, RecoveryFlowTypeBrowser, http.StatusOK) + body = resendVerificationCode(t, c, body, RecoveryClientTypeBrowser, http.StatusOK) assert.True(t, gjson.Get(body, "ui.nodes.#(attributes.name==code)").Exists()) assert.Equal(t, verificationEmail, gjson.Get(body, "ui.nodes.#(attributes.name==email).attributes.value").String()) @@ -510,7 +510,7 @@ func TestVerification(t *testing.T) { firstCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) c := testhelpers.NewClientWithCookies(t) - body = resendVerificationCode(t, c, body, RecoveryFlowTypeBrowser, http.StatusOK) + body = resendVerificationCode(t, c, body, RecoveryClientTypeBrowser, http.StatusOK) assert.True(t, gjson.Get(body, "ui.nodes.#(attributes.name==code)").Exists()) assert.Equal(t, verificationEmail, gjson.Get(body, "ui.nodes.#(attributes.name==email).attributes.value").String()) diff --git a/spec/api.json b/spec/api.json index 880122ea0585..ca83970d1da2 100644 --- a/spec/api.json +++ b/spec/api.json @@ -477,6 +477,8 @@ "discriminator": { "mapping": { "set_ory_session_token": "#/components/schemas/continueWithSetOrySessionToken", + "show_recovery_ui": "#/components/schemas/continueWithRecoveryUi", + "show_settings_ui": "#/components/schemas/continueWithSettingsUi", "show_verification_ui": "#/components/schemas/continueWithVerificationUi" }, "propertyName": "action" @@ -487,9 +489,53 @@ }, { "$ref": "#/components/schemas/continueWithSetOrySessionToken" + }, + { + "$ref": "#/components/schemas/continueWithSettingsUi" + }, + { + "$ref": "#/components/schemas/continueWithRecoveryUi" } ] }, + "continueWithRecoveryUi": { + "description": "Indicates, that the UI flow could be continued by showing a recovery ui", + "properties": { + "action": { + "description": "Action will always be `show_recovery_ui`\nshow_recovery_ui ContinueWithActionShowRecoveryUIString", + "enum": [ + "show_recovery_ui" + ], + "type": "string", + "x-go-enum-desc": "show_recovery_ui ContinueWithActionShowRecoveryUIString" + }, + "flow": { + "$ref": "#/components/schemas/continueWithRecoveryUiFlow" + } + }, + "required": [ + "action", + "flow" + ], + "type": "object" + }, + "continueWithRecoveryUiFlow": { + "properties": { + "id": { + "description": "The ID of the recovery flow", + "format": "uuid", + "type": "string" + }, + "url": { + "description": "The URL of the recovery flow", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, "continueWithSetOrySessionToken": { "description": "Indicates that a session was issued, and the application should use this token for authenticated requests", "properties": { @@ -512,6 +558,40 @@ ], "type": "object" }, + "continueWithSettingsUi": { + "description": "Indicates, that the UI flow could be continued by showing a settings ui", + "properties": { + "action": { + "description": "Action will always be `show_settings_ui`\nshow_settings_ui ContinueWithActionShowSettingsUIString", + "enum": [ + "show_settings_ui" + ], + "type": "string", + "x-go-enum-desc": "show_settings_ui ContinueWithActionShowSettingsUIString" + }, + "flow": { + "$ref": "#/components/schemas/continueWithSettingsUiFlow" + } + }, + "required": [ + "action", + "flow" + ], + "type": "object" + }, + "continueWithSettingsUiFlow": { + "properties": { + "id": { + "description": "The ID of the settings flow", + "format": "uuid", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, "continueWithVerificationUi": { "description": "Indicates, that the UI flow could be continued by showing a verification ui", "properties": { @@ -1487,7 +1567,7 @@ "description": "Used when an administrator creates a recovery code for an identity.", "properties": { "expires_at": { - "description": "Expires At is the timestamp of when the recovery flow expires\n\nThe timestamp when the recovery link expires.", + "description": "Expires At is the timestamp of when the recovery flow expires\n\nThe timestamp when the recovery code expires.", "format": "date-time", "type": "string" }, @@ -1514,6 +1594,13 @@ "description": "Active, if set, contains the recovery method that is being used. It is initially\nnot set.", "type": "string" }, + "continue_with": { + "description": "Contains possible actions that could follow this flow", + "items": { + "$ref": "#/components/schemas/continueWith" + }, + "type": "array" + }, "expires_at": { "description": "ExpiresAt is the time (UTC) when the request expires. If the user still wishes to update the setting,\na new request has to be initiated.", "format": "date-time", @@ -5466,7 +5553,7 @@ }, "/self-service/recovery": { "post": { - "description": "Use this endpoint to complete a recovery flow. This endpoint\nbehaves differently for API and browser flows and has several states:\n\n`choose_method` expects `flow` (in the URL query) and `email` (in the body) to be sent\nand works with API- and Browser-initiated flows.\nFor API clients and Browser clients with HTTP Header `Accept: application/json` it either returns a HTTP 200 OK when the form is valid and HTTP 400 OK when the form is invalid.\nand a HTTP 303 See Other redirect with a fresh recovery flow if the flow was otherwise invalid (e.g. expired).\nFor Browser clients without HTTP Header `Accept` or with `Accept: text/*` it returns a HTTP 303 See Other redirect to the Recovery UI URL with the Recovery Flow ID appended.\n`sent_email` is the success state after `choose_method` for the `link` method and allows the user to request another recovery email. It\nworks for both API and Browser-initiated flows and returns the same responses as the flow in `choose_method` state.\n`passed_challenge` expects a `token` to be sent in the URL query and given the nature of the flow (\"sending a recovery link\")\ndoes not have any API capabilities. The server responds with a HTTP 303 See Other redirect either to the Settings UI URL\n(if the link was valid) and instructs the user to update their password, or a redirect to the Recover UI URL with\na new Recovery Flow ID which contains an error message that the recovery link was invalid.\n\nMore information can be found at [Ory Kratos Account Recovery Documentation](../self-service/flows/account-recovery).", + "description": "Use this endpoint to update a recovery flow. This endpoint\nbehaves differently for API and browser flows and has several states:\n\n`choose_method` expects `flow` (in the URL query) and `email` (in the body) to be sent\nand works with API- and Browser-initiated flows.\nFor API clients and Browser clients with HTTP Header `Accept: application/json` it either returns a HTTP 200 OK when the form is valid and HTTP 400 OK when the form is invalid.\nand a HTTP 303 See Other redirect with a fresh recovery flow if the flow was otherwise invalid (e.g. expired).\nFor Browser clients without HTTP Header `Accept` or with `Accept: text/*` it returns a HTTP 303 See Other redirect to the Recovery UI URL with the Recovery Flow ID appended.\n`sent_email` is the success state after `choose_method` for the `link` method and allows the user to request another recovery email. It\nworks for both API and Browser-initiated flows and returns the same responses as the flow in `choose_method` state.\n`passed_challenge` expects a `token` to be sent in the URL query and given the nature of the flow (\"sending a recovery link\")\ndoes not have any API capabilities. The server responds with a HTTP 303 See Other redirect either to the Settings UI URL\n(if the link was valid) and instructs the user to update their password, or a redirect to the Recover UI URL with\na new Recovery Flow ID which contains an error message that the recovery link was invalid.\n\nMore information can be found at [Ory Kratos Account Recovery Documentation](../self-service/flows/account-recovery).", "operationId": "updateRecoveryFlow", "parameters": [ { @@ -5566,7 +5653,7 @@ "description": "errorGeneric" } }, - "summary": "Complete Recovery Flow", + "summary": "Update Recovery Flow", "tags": [ "frontend" ] @@ -5574,7 +5661,7 @@ }, "/self-service/recovery/api": { "get": { - "description": "This endpoint initiates a recovery flow for API clients such as mobile devices, smart TVs, and so on.\n\nIf a valid provided session cookie or session token is provided, a 400 Bad Request error.\n\nTo fetch an existing recovery flow call `/self-service/recovery/flows?flow=\u003cflow_id\u003e`.\n\nYou MUST NOT use this endpoint in client-side (Single Page Apps, ReactJS, AngularJS) nor server-side (Java Server\nPages, NodeJS, PHP, Golang, ...) browser applications. Using this endpoint in these applications will make\nyou vulnerable to a variety of CSRF attacks.\n\nThis endpoint MUST ONLY be used in scenarios such as native mobile apps (React Native, Objective C, Swift, Java, ...).\n\nMore information can be found at [Ory Kratos Account Recovery Documentation](../self-service/flows/account-recovery).", + "description": "This endpoint initiates a recovery flow for API clients such as mobile devices, smart TVs, and so on.\n\nIf a valid provided session cookie or session token is provided, a 400 Bad Request error.\n\nOn an existing recovery flow, use the `getRecoveryFlow` API endpoint.\n\nYou MUST NOT use this endpoint in client-side (Single Page Apps, ReactJS, AngularJS) nor server-side (Java Server\nPages, NodeJS, PHP, Golang, ...) browser applications. Using this endpoint in these applications will make\nyou vulnerable to a variety of CSRF attacks.\n\nThis endpoint MUST ONLY be used in scenarios such as native mobile apps (React Native, Objective C, Swift, Java, ...).\n\nMore information can be found at [Ory Kratos Account Recovery Documentation](../self-service/flows/account-recovery).", "operationId": "createNativeRecoveryFlow", "responses": { "200": { diff --git a/spec/swagger.json b/spec/swagger.json index 698a8d55e797..3b2b0eece6aa 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -1881,7 +1881,7 @@ }, "/self-service/recovery": { "post": { - "description": "Use this endpoint to complete a recovery flow. This endpoint\nbehaves differently for API and browser flows and has several states:\n\n`choose_method` expects `flow` (in the URL query) and `email` (in the body) to be sent\nand works with API- and Browser-initiated flows.\nFor API clients and Browser clients with HTTP Header `Accept: application/json` it either returns a HTTP 200 OK when the form is valid and HTTP 400 OK when the form is invalid.\nand a HTTP 303 See Other redirect with a fresh recovery flow if the flow was otherwise invalid (e.g. expired).\nFor Browser clients without HTTP Header `Accept` or with `Accept: text/*` it returns a HTTP 303 See Other redirect to the Recovery UI URL with the Recovery Flow ID appended.\n`sent_email` is the success state after `choose_method` for the `link` method and allows the user to request another recovery email. It\nworks for both API and Browser-initiated flows and returns the same responses as the flow in `choose_method` state.\n`passed_challenge` expects a `token` to be sent in the URL query and given the nature of the flow (\"sending a recovery link\")\ndoes not have any API capabilities. The server responds with a HTTP 303 See Other redirect either to the Settings UI URL\n(if the link was valid) and instructs the user to update their password, or a redirect to the Recover UI URL with\na new Recovery Flow ID which contains an error message that the recovery link was invalid.\n\nMore information can be found at [Ory Kratos Account Recovery Documentation](../self-service/flows/account-recovery).", + "description": "Use this endpoint to update a recovery flow. This endpoint\nbehaves differently for API and browser flows and has several states:\n\n`choose_method` expects `flow` (in the URL query) and `email` (in the body) to be sent\nand works with API- and Browser-initiated flows.\nFor API clients and Browser clients with HTTP Header `Accept: application/json` it either returns a HTTP 200 OK when the form is valid and HTTP 400 OK when the form is invalid.\nand a HTTP 303 See Other redirect with a fresh recovery flow if the flow was otherwise invalid (e.g. expired).\nFor Browser clients without HTTP Header `Accept` or with `Accept: text/*` it returns a HTTP 303 See Other redirect to the Recovery UI URL with the Recovery Flow ID appended.\n`sent_email` is the success state after `choose_method` for the `link` method and allows the user to request another recovery email. It\nworks for both API and Browser-initiated flows and returns the same responses as the flow in `choose_method` state.\n`passed_challenge` expects a `token` to be sent in the URL query and given the nature of the flow (\"sending a recovery link\")\ndoes not have any API capabilities. The server responds with a HTTP 303 See Other redirect either to the Settings UI URL\n(if the link was valid) and instructs the user to update their password, or a redirect to the Recover UI URL with\na new Recovery Flow ID which contains an error message that the recovery link was invalid.\n\nMore information can be found at [Ory Kratos Account Recovery Documentation](../self-service/flows/account-recovery).", "consumes": [ "application/json", "application/x-www-form-urlencoded" @@ -1896,7 +1896,7 @@ "tags": [ "frontend" ], - "summary": "Complete Recovery Flow", + "summary": "Update Recovery Flow", "operationId": "updateRecoveryFlow", "parameters": [ { @@ -1966,7 +1966,7 @@ }, "/self-service/recovery/api": { "get": { - "description": "This endpoint initiates a recovery flow for API clients such as mobile devices, smart TVs, and so on.\n\nIf a valid provided session cookie or session token is provided, a 400 Bad Request error.\n\nTo fetch an existing recovery flow call `/self-service/recovery/flows?flow=\u003cflow_id\u003e`.\n\nYou MUST NOT use this endpoint in client-side (Single Page Apps, ReactJS, AngularJS) nor server-side (Java Server\nPages, NodeJS, PHP, Golang, ...) browser applications. Using this endpoint in these applications will make\nyou vulnerable to a variety of CSRF attacks.\n\nThis endpoint MUST ONLY be used in scenarios such as native mobile apps (React Native, Objective C, Swift, Java, ...).\n\nMore information can be found at [Ory Kratos Account Recovery Documentation](../self-service/flows/account-recovery).", + "description": "This endpoint initiates a recovery flow for API clients such as mobile devices, smart TVs, and so on.\n\nIf a valid provided session cookie or session token is provided, a 400 Bad Request error.\n\nOn an existing recovery flow, use the `getRecoveryFlow` API endpoint.\n\nYou MUST NOT use this endpoint in client-side (Single Page Apps, ReactJS, AngularJS) nor server-side (Java Server\nPages, NodeJS, PHP, Golang, ...) browser applications. Using this endpoint in these applications will make\nyou vulnerable to a variety of CSRF attacks.\n\nThis endpoint MUST ONLY be used in scenarios such as native mobile apps (React Native, Objective C, Swift, Java, ...).\n\nMore information can be found at [Ory Kratos Account Recovery Documentation](../self-service/flows/account-recovery).", "schemes": [ "http", "https" @@ -3577,6 +3577,44 @@ }, "continueWith": { }, + "continueWithRecoveryUi": { + "description": "Indicates, that the UI flow could be continued by showing a recovery ui", + "type": "object", + "required": [ + "action", + "flow" + ], + "properties": { + "action": { + "description": "Action will always be `show_recovery_ui`\nshow_recovery_ui ContinueWithActionShowRecoveryUIString", + "type": "string", + "enum": [ + "show_recovery_ui" + ], + "x-go-enum-desc": "show_recovery_ui ContinueWithActionShowRecoveryUIString" + }, + "flow": { + "$ref": "#/definitions/continueWithRecoveryUiFlow" + } + } + }, + "continueWithRecoveryUiFlow": { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "description": "The ID of the recovery flow", + "type": "string", + "format": "uuid" + }, + "url": { + "description": "The URL of the recovery flow", + "type": "string" + } + } + }, "continueWithSetOrySessionToken": { "description": "Indicates that a session was issued, and the application should use this token for authenticated requests", "type": "object", @@ -3599,6 +3637,40 @@ } } }, + "continueWithSettingsUi": { + "description": "Indicates, that the UI flow could be continued by showing a settings ui", + "type": "object", + "required": [ + "action", + "flow" + ], + "properties": { + "action": { + "description": "Action will always be `show_settings_ui`\nshow_settings_ui ContinueWithActionShowSettingsUIString", + "type": "string", + "enum": [ + "show_settings_ui" + ], + "x-go-enum-desc": "show_settings_ui ContinueWithActionShowSettingsUIString" + }, + "flow": { + "$ref": "#/definitions/continueWithSettingsUiFlow" + } + } + }, + "continueWithSettingsUiFlow": { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "description": "The ID of the settings flow", + "type": "string", + "format": "uuid" + } + } + }, "continueWithVerificationUi": { "description": "Indicates, that the UI flow could be continued by showing a verification ui", "type": "object", @@ -4550,7 +4622,7 @@ ], "properties": { "expires_at": { - "description": "Expires At is the timestamp of when the recovery flow expires\n\nThe timestamp when the recovery link expires.", + "description": "Expires At is the timestamp of when the recovery flow expires\n\nThe timestamp when the recovery code expires.", "type": "string", "format": "date-time" }, @@ -4582,6 +4654,13 @@ "description": "Active, if set, contains the recovery method that is being used. It is initially\nnot set.", "type": "string" }, + "continue_with": { + "description": "Contains possible actions that could follow this flow", + "type": "array", + "items": { + "$ref": "#/definitions/continueWith" + } + }, "expires_at": { "description": "ExpiresAt is the time (UTC) when the request expires. If the user still wishes to update the setting,\na new request has to be initiated.", "type": "string", diff --git a/test/e2e/cypress/integration/profiles/code/login/error.spec.ts b/test/e2e/cypress/integration/profiles/code/login/error.spec.ts index 95c65c425512..477a149f9b26 100644 --- a/test/e2e/cypress/integration/profiles/code/login/error.spec.ts +++ b/test/e2e/cypress/integration/profiles/code/login/error.spec.ts @@ -1,7 +1,7 @@ // Copyright © 2023 Ory Corp // SPDX-License-Identifier: Apache-2.0 -import { gen, MOBILE_URL } from "../../../../helpers" +import { MOBILE_URL, gen } from "../../../../helpers" import { routes as express } from "../../../../helpers/express" import { routes as react } from "../../../../helpers/react" @@ -40,14 +40,13 @@ context("Login error messages with code method", () => { } before(() => { - cy.useConfigProfile(profile) - cy.deleteMail() if (app !== "mobile") { cy.proxy(app) } }) beforeEach(() => { + cy.useConfigProfile(profile) cy.deleteMail() cy.clearAllCookies() @@ -207,16 +206,6 @@ context("Login error messages with code method", () => { } cy.noSession() - - cy.updateConfigFile((config) => { - config.selfservice.methods.code = { - passwordless_enabled: true, - config: { - lifespan: "1h", - }, - } - return config - }) }) }) }) diff --git a/test/e2e/cypress/integration/profiles/mobile/mfa/totp.spec.ts b/test/e2e/cypress/integration/profiles/mobile/mfa/totp.spec.ts index 0c733c5cdf54..3b86c3890b67 100644 --- a/test/e2e/cypress/integration/profiles/mobile/mfa/totp.spec.ts +++ b/test/e2e/cypress/integration/profiles/mobile/mfa/totp.spec.ts @@ -1,8 +1,8 @@ // Copyright © 2023 Ory Corp // SPDX-License-Identifier: Apache-2.0 -import { APP_URL, gen, MOBILE_URL, website } from "../../../../helpers" import { authenticator } from "otplib" +import { gen, MOBILE_URL, website } from "../../../../helpers" context("Mobile Profile", () => { describe("TOTP 2FA Flow", () => { diff --git a/test/e2e/cypress/support/config.d.ts b/test/e2e/cypress/support/config.d.ts index 790ef1e41ba9..060cb12822bf 100644 --- a/test/e2e/cypress/support/config.d.ts +++ b/test/e2e/cypress/support/config.d.ts @@ -40,11 +40,15 @@ export type WebHookConfiguration = can_interrupt?: false [k: string]: unknown | undefined } -export type SelfServiceHooks = SelfServiceWebHook[] +export type SelfServiceHooks = (SelfServiceWebHook | B2BSSOHook)[] /** * If set to true will enable [User Registration](https://www.ory.sh/kratos/docs/self-service/flows/user-registration/). */ export type EnableUserRegistration = boolean +/** + * When registration fails because an account with the given credentials or addresses previously signed up, provide login hints about available methods to sign in to the user. + */ +export type ProvideLoginHintsOnFailedRegistration = boolean /** * URL where the Registration UI is hosted. Check the [reference implementation](https://github.com/ory/kratos-selfservice-ui-node). */ @@ -106,8 +110,11 @@ export type EnablesLinkMethod = boolean export type OverrideTheBaseURLWhichShouldBeUsedAsTheBaseForRecoveryAndVerificationLinks = string export type HowLongALinkIsValidFor = string -export type EnablesLoginWithCodeMethod = boolean -export type EnablesRegistrationWithCodeMethod = boolean +export type EnablesLoginAndRegistrationWithTheCodeMethod = boolean +/** + * This setting allows the code method to always login a user with code if they have registered with another authentication method such as password or social sign in. + */ +export type PasswordlessLoginFallbackEnabled = boolean export type EnablesCodeMethod = boolean export type HowLongACodeIsValidFor = string export type EnablesUsernameEmailAndPasswordMethod = boolean @@ -146,22 +153,30 @@ export type EnablesTheWebAuthnMethod = boolean * If enabled will have the effect that WebAuthn is used for passwordless flows (as a first factor) and not for multi-factor set ups. With this set to true, users will see an option to sign up with WebAuthn on the registration screen. */ export type UseForPasswordlessFlows = boolean -/** - * An name to help the user identify this RP. - */ -export type RelyingPartyDisplayName = string -/** - * The id must be a subset of the domain currently in the browser. - */ -export type RelyingPartyIdentifier = string -/** - * An explicit RP origin. If left empty, this defaults to `id`. - */ -export type RelyingPartyOrigin = string -/** - * An icon to help the user identify this RP. - */ -export type RelyingPartyIcon = string +export type RelyingPartyRPConfig = + | { + origin?: { + [k: string]: unknown | undefined + } + origins?: { + [k: string]: unknown | undefined + } + [k: string]: unknown | undefined + } + | { + origin: string + origins?: { + [k: string]: unknown | undefined + } + [k: string]: unknown | undefined + } + | { + origin?: { + [k: string]: unknown | undefined + } + origins: string[] + [k: string]: unknown | undefined + } export type EnablesOpenIDConnectMethod = boolean /** * Can be used to modify the base URL for OAuth2 Redirect URLs. If unset, the Public Base URL will be used. @@ -184,6 +199,7 @@ export type SelfServiceOIDCProvider = SelfServiceOIDCProvider1 & { apple_private_key_id?: ApplePrivateKeyIdentifier apple_private_key?: ApplePrivateKey requested_claims?: OpenIDConnectClaims + organization_id?: OrganizationID } export type SelfServiceOIDCProvider1 = { [k: string]: unknown | undefined @@ -239,6 +255,10 @@ export type ApplePrivateKeyIdentifier = string * Sign In with Apple Private Key needed for generating a JWT token for client secret */ export type ApplePrivateKey = string +/** + * The ID of the organization that this provider belongs to. Only effective in the Ory Network. + */ +export type OrganizationID = string /** * A list and configuration of OAuth2 and OpenID Connect providers Ory Kratos should integrate with. */ @@ -323,6 +343,10 @@ export type OAuth20ProviderURL = string * Override the return_to query parameter with the OAuth2 provider request URL when perfoming an OAuth2 login flow. */ export type PersistOAuth2RequestBetweenFlows = boolean +/** + * The default consistency level to use when reading from the database. Defaults to `strong` to not break existing API contracts. Only set this to `eventual` if you can accept that other read APIs will suddenly return eventually consistent results. It is only effective in Ory Network. + */ +export type DefaultReadConsistencyLevel = "strong" | "eventual" /** * Disable request logging for /health/alive and /health/ready endpoints */ @@ -431,6 +455,9 @@ export type HTTPCookiePath = string * Sets the session and CSRF cookie SameSite. */ export type HTTPCookieSameSiteConfiguration = "Strict" | "Lax" | "None" +export type TokenTimeToLive = string +export type JsonNetMapperURL = string +export type JSONWebKeySetURL = string /** * Defines how long a session is active. Once that lifespan has been reached, the user needs to sign in again. */ @@ -479,6 +506,14 @@ export type AddExemptURLsToPrivateIPRanges = string[] * If enabled allows Ory Sessions to be cached. Only effective in the Ory Network. */ export type EnableOrySessionsCaching = boolean +/** + * If enabled allows new flow transitions using `continue_with` items. + */ +export type EnableNewFlowTransitionsUsingContinueWithItems = boolean +/** + * Secifies which organizations are available. Only effective in the Ory Network. + */ +export type Organizations = unknown[] export interface OryKratosConfiguration2 { selfservice: { @@ -500,11 +535,11 @@ export interface OryKratosConfiguration2 { } registration?: { enabled?: EnableUserRegistration + login_hints?: ProvideLoginHintsOnFailedRegistration ui_url?: RegistrationUIURL lifespan?: string before?: SelfServiceBeforeRegistration after?: SelfServiceAfterRegistration - login_hints?: boolean } login?: { ui_url?: LoginUIURL @@ -527,7 +562,8 @@ export interface OryKratosConfiguration2 { config?: LinkConfiguration } code?: { - passwordless_enabled?: boolean + passwordless_enabled?: EnablesLoginAndRegistrationWithTheCodeMethod + passwordless_login_fallback_enabled?: PasswordlessLoginFallbackEnabled enabled?: EnablesCodeMethod config?: CodeConfiguration } @@ -553,6 +589,7 @@ export interface OryKratosConfiguration2 { dsn: DataSourceName courier?: CourierConfiguration oauth2_provider?: OAuth2ProviderConfiguration + preview?: ConfigurePreviewFeatures serve?: { admin?: { request_log?: { @@ -670,14 +707,19 @@ export interface OryKratosConfiguration2 { config?: string[] clients?: GlobalOutgoingNetworkSettings feature_flags?: FeatureFlags + organizations?: Organizations } export interface SelfServiceAfterSettings { default_browser_return_url?: RedirectBrowsersToSetURLPerDefault - password?: SelfServiceAfterSettingsMethod + password?: SelfServiceAfterSettingsAuthMethod + totp?: SelfServiceAfterSettingsAuthMethod + oidc?: SelfServiceAfterSettingsAuthMethod + webauthn?: SelfServiceAfterSettingsAuthMethod + lookup_secret?: SelfServiceAfterSettingsAuthMethod profile?: SelfServiceAfterSettingsMethod hooks?: SelfServiceHooks } -export interface SelfServiceAfterSettingsMethod { +export interface SelfServiceAfterSettingsAuthMethod { default_browser_return_url?: RedirectBrowsersToSetURLPerDefault hooks?: (SelfServiceWebHook | SelfServiceSessionRevokerHook)[] } @@ -685,6 +727,19 @@ export interface SelfServiceWebHook { hook: "web_hook" config: WebHookConfiguration } +export interface SelfServiceSessionRevokerHook { + hook: "revoke_active_sessions" +} +export interface SelfServiceAfterSettingsMethod { + default_browser_return_url?: RedirectBrowsersToSetURLPerDefault + hooks?: SelfServiceWebHook[] +} +export interface B2BSSOHook { + hook: "b2b_sso" + config: { + [k: string]: unknown | undefined + } +} export interface SelfServiceBeforeSettings { hooks?: SelfServiceHooks } @@ -705,6 +760,7 @@ export interface SelfServiceAfterRegistrationMethod { | SelfServiceSessionIssuerHook | SelfServiceWebHook | SelfServiceShowVerificationUIHook + | B2BSSOHook )[] } export interface SelfServiceSessionIssuerHook { @@ -722,10 +778,13 @@ export interface SelfServiceAfterLogin { webauthn?: SelfServiceAfterDefaultLoginMethod oidc?: SelfServiceAfterOIDCLoginMethod code?: SelfServiceAfterDefaultLoginMethod + totp?: SelfServiceAfterDefaultLoginMethod + lookup_secret?: SelfServiceAfterDefaultLoginMethod hooks?: ( | SelfServiceWebHook | SelfServiceSessionRevokerHook | SelfServiceRequireVerifiedAddressHook + | B2BSSOHook )[] } export interface SelfServiceAfterDefaultLoginMethod { @@ -736,9 +795,6 @@ export interface SelfServiceAfterDefaultLoginMethod { | SelfServiceWebHook )[] } -export interface SelfServiceSessionRevokerHook { - hook: "revoke_active_sessions" -} export interface SelfServiceRequireVerifiedAddressHook { hook: "require_verified_address" } @@ -748,6 +804,7 @@ export interface SelfServiceAfterOIDCLoginMethod { | SelfServiceSessionRevokerHook | SelfServiceWebHook | SelfServiceRequireVerifiedAddressHook + | B2BSSOHook )[] } export interface EmailAndPhoneVerificationAndAccountActivationConfiguration { @@ -815,13 +872,6 @@ export interface WebAuthnConfiguration { passwordless?: UseForPasswordlessFlows rp?: RelyingPartyRPConfig } -export interface RelyingPartyRPConfig { - display_name: RelyingPartyDisplayName - id: RelyingPartyIdentifier - origin?: RelyingPartyOrigin - icon?: RelyingPartyIcon - [k: string]: unknown | undefined -} export interface SpecifyOpenIDConnectAndOAuth2Configuration { enabled?: EnablesOpenIDConnectMethod config?: { @@ -893,6 +943,16 @@ export interface CourierConfiguration { recovery_code?: CourierTemplates verification?: CourierTemplates verification_code?: CourierTemplates + registration_code?: { + valid?: { + email: EmailCourierTemplate + } + } + login_code?: { + valid?: { + email: EmailCourierTemplate + } + } } template_override_path?: OverrideMessageTemplates /** @@ -1038,6 +1098,10 @@ export interface OAuth2ProviderConfiguration { export interface HTTPRequestHeaders { [k: string]: string | undefined } +export interface ConfigurePreviewFeatures { + default_read_consistency_level?: DefaultReadConsistencyLevel + [k: string]: unknown | undefined +} /** * Sets the permissions of the unix socket */ @@ -1078,6 +1142,10 @@ export interface OryTracingConfig { * Specifies the service name to use on the tracer. */ service_name?: string + /** + * Specifies the deployment environment to use on the tracer. + */ + deployment_environment?: string providers?: { /** * Configures the jaeger tracing backend. @@ -1141,6 +1209,7 @@ export interface OryTracingConfig { */ sampling_ratio?: number } + authorization_header?: string } } } @@ -1224,6 +1293,29 @@ export interface HTTPCookieConfiguration { */ export interface WhoAmIToSessionSettings { required_aal?: RequiredAuthenticatorAssuranceLevel + tokenizer?: TokenizerConfiguration +} +/** + * Configure the tokenizer, responsible for converting a session into a token format such as JWT. + */ +export interface TokenizerConfiguration { + templates?: TokenizerTemplates + [k: string]: unknown | undefined +} +/** + * A list of different templates that govern how a session is converted to a token format. + */ +export interface TokenizerTemplates { + /** + * This interface was referenced by `TokenizerTemplates`'s JSON-Schema definition + * via the `patternProperty` "[a-zA-Z0-9-_.]+". + */ + [k: string]: { + ttl?: TokenTimeToLive + claims_mapper_url?: JsonNetMapperURL + jwks_url: JSONWebKeySetURL + [k: string]: unknown | undefined + } } /** * Configure how outgoing network calls behave. @@ -1242,4 +1334,5 @@ export interface GlobalHTTPClientConfiguration { } export interface FeatureFlags { cacheable_sessions?: EnableOrySessionsCaching + use_continue_with_transitions?: EnableNewFlowTransitionsUsingContinueWithItems } diff --git a/test/e2e/package-lock.json b/test/e2e/package-lock.json index 08dfd3278dc3..5df47741d1ed 100644 --- a/test/e2e/package-lock.json +++ b/test/e2e/package-lock.json @@ -7,9 +7,15 @@ "": { "name": "@ory/kratos-e2e-suite", "version": "0.0.1", + "dependencies": { + "@faker-js/faker": "7.6.0", + "async-retry": "1.3.3", + "mailhog": "4.16.0" + }, "devDependencies": { "@ory/kratos-client": "0.0.0-next.8d3b018594f7", - "@playwright/test": "1.32.3", + "@playwright/test": "1.34.0", + "@types/async-retry": "1.4.5", "@types/node": "16.9.6", "@types/yamljs": "0.2.31", "chrome-remote-interface": "0.33.0", @@ -91,6 +97,15 @@ "ms": "^2.1.1" } }, + "node_modules/@faker-js/faker": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-7.6.0.tgz", + "integrity": "sha512-XK6BTq1NDMo9Xqw/YkYyGjSsg44fbNwYRx7QK2CuoQgyy+f1rrTDHoExVM5PsyXCtfl2vs2vVJ0MN0yN6LppRw==", + "engines": { + "node": ">=14.0.0", + "npm": ">=6.0.0" + } + }, "node_modules/@hapi/hoek": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", @@ -169,13 +184,13 @@ } }, "node_modules/@playwright/test": { - "version": "1.32.3", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.32.3.tgz", - "integrity": "sha512-BvWNvK0RfBriindxhLVabi8BRe3X0J9EVjKlcmhxjg4giWBD/xleLcg2dz7Tx0agu28rczjNIPQWznwzDwVsZQ==", + "version": "1.34.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.34.0.tgz", + "integrity": "sha512-GIALJVODOIrMflLV54H3Cow635OfrTwOu24ZTDyKC66uchtFX2NcCRq83cLdakMjZKYK78lODNLQSYBj2OgaTw==", "dev": true, "dependencies": { "@types/node": "*", - "playwright-core": "1.32.3" + "playwright-core": "1.34.0" }, "bin": { "playwright": "cli.js" @@ -232,6 +247,15 @@ "node": ">=10" } }, + "node_modules/@types/async-retry": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@types/async-retry/-/async-retry-1.4.5.tgz", + "integrity": "sha512-YrdjSD+yQv7h6d5Ip+PMxh3H6ZxKyQk0Ts+PvaNRInxneG9PFVZjFg77ILAN+N6qYf7g4giSJ1l+ZjQ1zeegvA==", + "dev": true, + "dependencies": { + "@types/retry": "*" + } + }, "node_modules/@types/cacheable-request": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.2.tgz", @@ -308,6 +332,12 @@ "@types/node": "*" } }, + "node_modules/@types/retry": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", + "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", + "dev": true + }, "node_modules/@types/sinonjs__fake-timers": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz", @@ -465,6 +495,14 @@ "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", "dev": true }, + "node_modules/async-retry": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", + "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", + "dependencies": { + "retry": "0.13.1" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -1581,6 +1619,18 @@ "node": ">=8.12.0" } }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -2012,6 +2062,17 @@ "es5-ext": "~0.10.2" } }, + "node_modules/mailhog": { + "version": "4.16.0", + "resolved": "https://registry.npmjs.org/mailhog/-/mailhog-4.16.0.tgz", + "integrity": "sha512-wXrGik+0MaAy4dbYTImxa8niX9a4aRpZTzC/b1GzCvQs09khhs0aKZgHjgScakI4Y18WInDvvF48hhEz9ifN4g==", + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "iconv-lite": "^0.6" + } + }, "node_modules/memoizee": { "version": "0.4.15", "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", @@ -2276,13 +2337,10 @@ } }, "node_modules/playwright-core": { - "version": "1.32.3", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.32.3.tgz", - "integrity": "sha512-SB+cdrnu74ZIn5Ogh/8278ngEh9NEEV0vR4sJFmK04h2iZpybfbqBY0bX6+BLYWVdV12JLLI+JEFtSnYgR+mWg==", + "version": "1.34.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.34.0.tgz", + "integrity": "sha512-fMUY1+iR6kYbJF/EsOOqzBA99ZHXbw9sYPNjwA4X/oV0hVF/1aGlWYBGPVUEqxBkGANDKMziYoOdKGU5DIP5Gg==", "dev": true, - "bin": { - "playwright": "cli.js" - }, "engines": { "node": ">=14" } @@ -2430,6 +2488,14 @@ "node": ">=8" } }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "engines": { + "node": ">= 4" + } + }, "node_modules/rfdc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", @@ -2484,7 +2550,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "devOptional": true }, "node_modules/semver": { "version": "7.5.4", @@ -3024,6 +3090,11 @@ } } }, + "@faker-js/faker": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-7.6.0.tgz", + "integrity": "sha512-XK6BTq1NDMo9Xqw/YkYyGjSsg44fbNwYRx7QK2CuoQgyy+f1rrTDHoExVM5PsyXCtfl2vs2vVJ0MN0yN6LppRw==" + }, "@hapi/hoek": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", @@ -3102,14 +3173,14 @@ } }, "@playwright/test": { - "version": "1.32.3", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.32.3.tgz", - "integrity": "sha512-BvWNvK0RfBriindxhLVabi8BRe3X0J9EVjKlcmhxjg4giWBD/xleLcg2dz7Tx0agu28rczjNIPQWznwzDwVsZQ==", + "version": "1.34.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.34.0.tgz", + "integrity": "sha512-GIALJVODOIrMflLV54H3Cow635OfrTwOu24ZTDyKC66uchtFX2NcCRq83cLdakMjZKYK78lODNLQSYBj2OgaTw==", "dev": true, "requires": { "@types/node": "*", "fsevents": "2.3.2", - "playwright-core": "1.32.3" + "playwright-core": "1.34.0" } }, "@sideway/address": { @@ -3148,6 +3219,15 @@ "defer-to-connect": "^2.0.0" } }, + "@types/async-retry": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@types/async-retry/-/async-retry-1.4.5.tgz", + "integrity": "sha512-YrdjSD+yQv7h6d5Ip+PMxh3H6ZxKyQk0Ts+PvaNRInxneG9PFVZjFg77ILAN+N6qYf7g4giSJ1l+ZjQ1zeegvA==", + "dev": true, + "requires": { + "@types/retry": "*" + } + }, "@types/cacheable-request": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.2.tgz", @@ -3224,6 +3304,12 @@ "@types/node": "*" } }, + "@types/retry": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", + "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", + "dev": true + }, "@types/sinonjs__fake-timers": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz", @@ -3340,6 +3426,14 @@ "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", "dev": true }, + "async-retry": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", + "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", + "requires": { + "retry": "0.13.1" + } + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -4187,6 +4281,15 @@ "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", "dev": true }, + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, "ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -4514,6 +4617,14 @@ "es5-ext": "~0.10.2" } }, + "mailhog": { + "version": "4.16.0", + "resolved": "https://registry.npmjs.org/mailhog/-/mailhog-4.16.0.tgz", + "integrity": "sha512-wXrGik+0MaAy4dbYTImxa8niX9a4aRpZTzC/b1GzCvQs09khhs0aKZgHjgScakI4Y18WInDvvF48hhEz9ifN4g==", + "requires": { + "iconv-lite": "^0.6" + } + }, "memoizee": { "version": "0.4.15", "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", @@ -4715,9 +4826,9 @@ "dev": true }, "playwright-core": { - "version": "1.32.3", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.32.3.tgz", - "integrity": "sha512-SB+cdrnu74ZIn5Ogh/8278ngEh9NEEV0vR4sJFmK04h2iZpybfbqBY0bX6+BLYWVdV12JLLI+JEFtSnYgR+mWg==", + "version": "1.34.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.34.0.tgz", + "integrity": "sha512-fMUY1+iR6kYbJF/EsOOqzBA99ZHXbw9sYPNjwA4X/oV0hVF/1aGlWYBGPVUEqxBkGANDKMziYoOdKGU5DIP5Gg==", "dev": true }, "prettier": { @@ -4827,6 +4938,11 @@ "signal-exit": "^3.0.2" } }, + "retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==" + }, "rfdc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", @@ -4861,7 +4977,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "devOptional": true }, "semver": { "version": "7.5.4", diff --git a/test/e2e/package.json b/test/e2e/package.json index 986fe5cae64a..d4106cbb8aa1 100644 --- a/test/e2e/package.json +++ b/test/e2e/package.json @@ -10,9 +10,15 @@ "text-run": "exit 0", "wait-on": "wait-on" }, + "dependencies": { + "@faker-js/faker": "7.6.0", + "async-retry": "1.3.3", + "mailhog": "4.16.0" + }, "devDependencies": { "@ory/kratos-client": "0.0.0-next.8d3b018594f7", - "@playwright/test": "1.32.3", + "@playwright/test": "1.34.0", + "@types/async-retry": "1.4.5", "@types/node": "16.9.6", "@types/yamljs": "0.2.31", "chrome-remote-interface": "0.33.0", diff --git a/test/e2e/playwright.config.ts b/test/e2e/playwright.config.ts index 677c0a3c2d46..71a67dfd8795 100644 --- a/test/e2e/playwright.config.ts +++ b/test/e2e/playwright.config.ts @@ -43,9 +43,20 @@ export default defineConfig({ cwd: "../..", url: "http://localhost:4433/health/ready", reuseExistingServer: false, - env: { DSN: dbToDsn() }, + env: { + DSN: dbToDsn(), + COURIER_SMTP_CONNECTION_URI: + "smtp://localhost:8026/?disable_starttls=true", + }, timeout: 5 * 60 * 1000, // 5 minutes }, + { + command: + "make .bin/MailHog && .bin/MailHog -smtp-bind-addr=localhost:8026", + cwd: "../..", + reuseExistingServer: false, + url: "http://localhost:8025/", + }, ], }) diff --git a/test/e2e/playwright/actions/mail.ts b/test/e2e/playwright/actions/mail.ts new file mode 100644 index 000000000000..871608bc204d --- /dev/null +++ b/test/e2e/playwright/actions/mail.ts @@ -0,0 +1,24 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +import mailhog from "mailhog" +import retry from "async-retry" + +const mh = mailhog({ + basePath: "http://localhost:8025/api", +}) + +export function search(...props: Parameters) { + return retry( + async () => { + const res = await mh.search(...props) + if (res.total === 0) { + throw new Error("no emails found") + } + return res.items + }, + { + retries: 3, + }, + ) +} diff --git a/test/e2e/playwright/fixtures/index.ts b/test/e2e/playwright/fixtures/index.ts new file mode 100644 index 000000000000..3b1264e84c0a --- /dev/null +++ b/test/e2e/playwright/fixtures/index.ts @@ -0,0 +1,64 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +import { Identity } from "@ory/kratos-client" +import { test as base, expect } from "@playwright/test" +import { OryKratosConfiguration } from "../../cypress/support/config" +import { merge } from "lodash" +import { default_config } from "../setup/default_config" +import { writeFile } from "fs/promises" +import { faker } from "@faker-js/faker" + +// from https://stackoverflow.com/questions/61132262/typescript-deep-partial +type DeepPartial = T extends object + ? { + [P in keyof T]?: DeepPartial + } + : T + +type TestFixtures = { + identity: Identity + configOverride: DeepPartial + config: void +} + +type WorkerFixtures = {} + +export const test = base.extend({ + configOverride: {}, + config: [ + async ({ request, configOverride }, use) => { + const configToWrite = merge(default_config, configOverride) + + const resp = await request.get("http://localhost:4434/health/config") + + const configRevision = await resp.body() + + await writeFile( + "playwright/kratos.config.json", + JSON.stringify(configToWrite), + ) + await expect(async () => { + const resp = await request.get("http://localhost:4434/health/config") + const updatedRevision = await resp.body() + expect(updatedRevision).not.toBe(configRevision) + }).toPass() + + await use() + }, + { auto: true }, + ], + identity: async ({ request }, use) => { + const resp = await request.post("http://localhost:4434/admin/identities", { + data: { + schema_id: "email", + traits: { + email: faker.internet.email(undefined, undefined, "ory.sh"), + website: faker.internet.url(), + }, + }, + }) + expect(resp.status()).toBe(201) + await use(await resp.json()) + }, +}) diff --git a/test/e2e/playwright/kratos.base-config.json b/test/e2e/playwright/kratos.base-config.json index 675f1a94862d..83b24587bd61 100644 --- a/test/e2e/playwright/kratos.base-config.json +++ b/test/e2e/playwright/kratos.base-config.json @@ -110,7 +110,7 @@ }, "courier": { "smtp": { - "connection_uri": "smtps://test:test@localhost:1025/?skip_ssl_verify=true" + "connection_uri": "smtps://test:test@localhost:8026/?skip_ssl_verify=true" } } } diff --git a/test/e2e/playwright/lib/helper.ts b/test/e2e/playwright/lib/helper.ts new file mode 100644 index 000000000000..929b39b74573 --- /dev/null +++ b/test/e2e/playwright/lib/helper.ts @@ -0,0 +1,20 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +import { Message } from "mailhog" + +export const codeRegex = /(\d{6})/ + +/** + * Extracts the recovery or verification code from a mail + * + * @param mail the mail to extract the code from + * @returns the code or null if no code was found + */ +export function extractCode(mail: Message) { + const result = codeRegex.exec(mail.html || mail.text) + if (result != null && result.length > 0) { + return result[0] + } + return null +} diff --git a/test/e2e/playwright/setup/default_config.ts b/test/e2e/playwright/setup/default_config.ts index 6437383f9638..b9249917b039 100644 --- a/test/e2e/playwright/setup/default_config.ts +++ b/test/e2e/playwright/setup/default_config.ts @@ -119,6 +119,7 @@ export const default_config: OryKratosConfiguration = { ui_url: "http://localhost:4455/verify", }, recovery: { + enabled: true, ui_url: "http://localhost:4455/recovery", }, }, @@ -126,7 +127,7 @@ export const default_config: OryKratosConfiguration = { courier: { smtp: { - connection_uri: "smtps://test:test@localhost:1025/?skip_ssl_verify=true", + connection_uri: "smtp://localhost:8026/?disable_starttls=true", }, }, } diff --git a/test/e2e/playwright/tests/app_recovery.spec.ts b/test/e2e/playwright/tests/app_recovery.spec.ts new file mode 100644 index 000000000000..629abd3c05bc --- /dev/null +++ b/test/e2e/playwright/tests/app_recovery.spec.ts @@ -0,0 +1,140 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +import { expect } from "@playwright/test" +import { test } from "../fixtures" +import { search } from "../actions/mail" +import { extractCode } from "../lib/helper" + +const schemaConfig = { + default_schema_id: "email", + schemas: [ + { + id: "email", + url: "file://test/e2e/profiles/email/identity.traits.schema.json", + }, + ], +} + +test.describe("Recovery", () => { + test.use({ + configOverride: { + identity: { + ...schemaConfig, + }, + feature_flags: { + use_continue_with_transitions: true, + }, + }, + }) + + test("succeeds with a valid email address", async ({ page, identity }) => { + await page.goto("/Recovery") + + await page.getByTestId("email").fill(identity.traits.email) + await page.getByTestId("submit-form").click() + await expect(page.getByTestId("ui/message/1060003")).toBeVisible() + + const mails = await search(identity.traits.email, "to") + expect(mails).toHaveLength(1) + + const code = extractCode(mails[0]) + const wrongCode = "0" + code + + await test.step("enter wrong code", async () => { + await page.getByTestId("code").fill(wrongCode) + await page.getByText("Submit").click() + await expect(page.getByTestId("ui/message/4060006")).toBeVisible() + }) + + await test.step("enter correct code", async () => { + await page.getByTestId("code").fill(code) + await page.getByText("Submit").click() + await page.waitForURL(/Settings/) + await expect(page.getByTestId("ui/message/1060001").first()).toBeVisible() + }) + }) + + test("wrong email address does not get sent", async ({ page, identity }) => { + await page.goto("/Recovery") + + const wrongEmailAddress = "wrong-" + identity.traits.email + await page.getByTestId("email").fill(wrongEmailAddress) + await page.getByTestId("submit-form").click() + await expect(page.getByTestId("ui/message/1060003")).toBeVisible() + + try { + await search(identity.traits.email, "to") + expect(false).toBeTruthy() + } catch (e) { + // this is expected + } + }) + + test("fails with an invalid code", async ({ page, identity }) => { + await page.goto("/Recovery") + + await page.getByTestId("email").fill(identity.traits.email) + await page.getByTestId("submit-form").click() + await page.getByTestId("ui/message/1060003").isVisible() + + const mails = await search(identity.traits.email, "to") + expect(mails).toHaveLength(1) + + const code = extractCode(mails[0]) + const wrongCode = "0" + code + + await test.step("enter wrong repeatedly", async () => { + for (let i = 0; i < 10; i++) { + await page.getByTestId("code").fill(wrongCode) + await page.getByText("Submit", { exact: true }).click() + await expect(page.getByTestId("ui/message/4060006")).toBeVisible() + } + }) + + await test.step("enter correct code fails", async () => { + await page.getByTestId("code").fill(code) + await page.getByText("Submit", { exact: true }).click() + await expect(page.getByTestId("ui/message/4060006")).toBeVisible() + }) + }) + + test.describe("with short code expiration", () => { + test.use({ + configOverride: { + identity: { + ...schemaConfig, + }, + selfservice: { + methods: { + code: { + config: { + lifespan: "1ms", + }, + }, + }, + }, + feature_flags: { + use_continue_with_transitions: true, + }, + }, + }) + + test("fails with an expired code", async ({ page, identity }) => { + await page.goto("/Recovery") + + await page.getByTestId("email").fill(identity.traits.email) + await page.getByTestId("submit-form").click() + await page.getByTestId("ui/message/1060003").isVisible() + + const mails = await search(identity.traits.email, "to") + expect(mails).toHaveLength(1) + + const code = extractCode(mails[0]) + + await page.getByTestId("code").fill(code) + await page.getByText("Submit", { exact: true }).click() + await expect(page.getByTestId("email")).toBeVisible() + }) + }) +}) diff --git a/test/e2e/render-kratos-config.sh b/test/e2e/render-kratos-config.sh index 45506efd0380..5867904216e2 100755 --- a/test/e2e/render-kratos-config.sh +++ b/test/e2e/render-kratos-config.sh @@ -8,8 +8,10 @@ dir=$(realpath $(dirname "${BASH_SOURCE[0]}")) ory_x_version="$(cd $dir/../..; go list -f '{{.Version}}' -m github.com/ory/x)" -curl -s https://raw.githubusercontent.com/ory/x/$ory_x_version/otelx/config.schema.json > .tracing-config.schema.json +curl -s https://raw.githubusercontent.com/ory/x/$ory_x_version/otelx/config.schema.json > $dir/.tracing-config.schema.json -sed "s!ory://tracing-config!.tracing-config.schema.json!g;" ../../embedx/config.schema.json | npx json2ts --strictIndexSignatures > cypress/support/config.d.ts +(cd $dir; sed "s!ory://tracing-config!.tracing-config.schema.json!g;" $dir/../../embedx/config.schema.json | npx json2ts --strictIndexSignatures > $dir/cypress/support/config.d.ts) -rm .tracing-config.schema.json +rm $dir/.tracing-config.schema.json + +make format From 492808cae0e804793aef9a02a902fce988f9fc6d Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Wed, 15 Nov 2023 15:11:27 +0100 Subject: [PATCH 191/282] feat(changelog): add support for native recovery (#3624) Adds the ability to complete the recovery flow properly on API flows. This PR also streamlines the behavior for SPA flows to not return 422 errors anymore. To enable this new behavior, set the features.use_continue_with_transitions flag in the config to `true`. See also https://github.com/ory/kratos/pull/3273 --- contrib/quickstart/kratos/email-password/kratos.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contrib/quickstart/kratos/email-password/kratos.yml b/contrib/quickstart/kratos/email-password/kratos.yml index 935727cc2bad..d95e0ef68715 100644 --- a/contrib/quickstart/kratos/email-password/kratos.yml +++ b/contrib/quickstart/kratos/email-password/kratos.yml @@ -97,3 +97,6 @@ identity: courier: smtp: connection_uri: smtps://test:test@mailslurper:1025/?skip_ssl_verify=true + +feature_flags: + use_continue_with_transitions: true From f6fde34c172848c106634c7b91418a147c988599 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Wed, 15 Nov 2023 15:25:01 +0000 Subject: [PATCH 192/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c85c509207b0..2497a277e17f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-11-14)](#2023-11-14) +- [ (2023-11-15)](#2023-11-15) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -314,7 +314,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-11-14) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-11-15) ## Breaking Changes @@ -689,6 +689,9 @@ https://github.com/ory/kratos/pull/3480 - Add OpenTelemetry span for password hash comparison ([#3383](https://github.com/ory/kratos/issues/3383)) ([e3fcf0c](https://github.com/ory/kratos/commit/e3fcf0c31db9742ed61bcf783e37ee119ed19d42)) +- Add support for recovery on native flows + ([#3273](https://github.com/ory/kratos/issues/3273)) + ([e363889](https://github.com/ory/kratos/commit/e363889732c0a1cb801fd12b2e0e8546006e9714)) - Add WebhookSucceeded event ([aa8c936](https://github.com/ory/kratos/commit/aa8c93677a8f682f7693afe69f1baf1887355e0a)) - Added various new text messages @@ -802,6 +805,17 @@ https://github.com/ory/kratos/pull/3480 /admin/identities?ids=id1&ids=id2&ids=id3 ``` +- **changelog:** Add support for native recovery + ([#3624](https://github.com/ory/kratos/issues/3624)) + ([492808c](https://github.com/ory/kratos/commit/492808cae0e804793aef9a02a902fce988f9fc6d)): + + Adds the ability to complete the recovery flow properly on API flows. This PR + also streamlines the behavior for SPA flows to not return 422 errors anymore. + To enable this new behavior, set the features.use_continue_with_transitions + flag in the config to `true`. + + See also https://github.com/ory/kratos/pull/3273 + - Emit error details when we find stray cookies in an API flow ([#3496](https://github.com/ory/kratos/issues/3496)) ([df74339](https://github.com/ory/kratos/commit/df74339802d98a292abb32806eca35fb2554960b)) From 6d08576bbc2c06014192f05e0129b95eb6c9fd80 Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Mon, 20 Nov 2023 16:43:34 +0100 Subject: [PATCH 193/282] fix: improved SSRF protection (#3629) This also improves tracing in the OIDC strategy. --- courier/sms_test.go | 2 +- courier/template/load_template_test.go | 14 +-- go.mod | 44 ++++----- go.sum | 92 ++++++++++--------- identity/validator_test.go | 4 +- selfservice/hook/web_hook_integration_test.go | 6 +- selfservice/strategy/oidc/provider_auth0.go | 8 +- .../strategy/oidc/provider_facebook.go | 4 +- selfservice/strategy/oidc/provider_github.go | 4 +- .../strategy/oidc/provider_github_app.go | 4 +- selfservice/strategy/oidc/provider_gitlab.go | 8 +- selfservice/strategy/oidc/provider_google.go | 5 +- .../strategy/oidc/provider_linkedin.go | 2 +- .../strategy/oidc/provider_microsoft.go | 5 +- selfservice/strategy/oidc/provider_netid.go | 4 +- selfservice/strategy/oidc/provider_patreon.go | 5 +- .../oidc/provider_private_net_test.go | 18 ++-- selfservice/strategy/oidc/provider_spotify.go | 6 +- .../strategy/oidc/provider_userinfo_test.go | 32 +++++-- selfservice/strategy/oidc/provider_vk.go | 4 +- selfservice/strategy/oidc/provider_yandex.go | 4 +- selfservice/strategy/oidc/strategy.go | 2 + selfservice/strategy/oidc/strategy_test.go | 64 ++++++------- .../strategy/password/validator_test.go | 18 ++-- .../profiles/network/errors.spec.ts | 8 +- test/e2e/package-lock.json | 12 +-- 26 files changed, 205 insertions(+), 174 deletions(-) diff --git a/courier/sms_test.go b/courier/sms_test.go index 9dfc6f45116e..5a919788fe04 100644 --- a/courier/sms_test.go +++ b/courier/sms_test.go @@ -146,5 +146,5 @@ func TestDisallowedInternalNetwork(t *testing.T) { err = c.DispatchQueue(ctx) require.Error(t, err) - assert.Contains(t, err.Error(), "127.0.0.1 is not a public IP address") + assert.Contains(t, err.Error(), "is not a permitted destination") } diff --git a/courier/template/load_template_test.go b/courier/template/load_template_test.go index fcc0ba8f35fd..e6b043aa0c54 100644 --- a/courier/template/load_template_test.go +++ b/courier/template/load_template_test.go @@ -29,7 +29,7 @@ import ( ) func TestLoadTextTemplate(t *testing.T) { - var executeTextTemplate = func(t *testing.T, dir, name, pattern string, model map[string]interface{}) string { + executeTextTemplate := func(t *testing.T, dir, name, pattern string, model map[string]interface{}) string { ctx := context.Background() _, reg := internal.NewFastRegistryWithMocks(t) tp, err := template.LoadText(ctx, reg, os.DirFS(dir), name, pattern, model, "") @@ -37,7 +37,7 @@ func TestLoadTextTemplate(t *testing.T) { return tp } - var executeHTMLTemplate = func(t *testing.T, dir, name, pattern string, model map[string]interface{}) string { + executeHTMLTemplate := func(t *testing.T, dir, name, pattern string, model map[string]interface{}) string { ctx := context.Background() _, reg := internal.NewFastRegistryWithMocks(t) tp, err := template.LoadHTML(ctx, reg, os.DirFS(dir), name, pattern, model, "") @@ -91,7 +91,7 @@ func TestLoadTextTemplate(t *testing.T) { name := x.NewUUID().String() + ".body.gotmpl" fp := filepath.Join(dir, name) - require.NoError(t, os.WriteFile(fp, []byte("cached stub body"), 0666)) + require.NoError(t, os.WriteFile(fp, []byte("cached stub body"), 0o666)) assert.Contains(t, executeTextTemplate(t, dir, name, "", nil), "cached stub body") require.NoError(t, os.RemoveAll(fp)) @@ -126,7 +126,6 @@ func TestLoadTextTemplate(t *testing.T) { require.NoError(t, err) assert.Contains(t, tp, "stub email body something") }) - }) t.Run("case=file resource", func(t *testing.T) { @@ -169,7 +168,6 @@ func TestLoadTextTemplate(t *testing.T) { require.NoError(t, err) assert.Contains(t, tp, "stub email body something") }) - }) t.Run("case=unsupported resource", func(t *testing.T) { @@ -191,12 +189,11 @@ func TestLoadTextTemplate(t *testing.T) { _, err := template.LoadHTML(ctx, reg, nil, "", "", map[string]interface{}{}, "http://localhost:8080/1234") require.Error(t, err) - assert.Contains(t, err.Error(), "is not a public IP address") + assert.Contains(t, err.Error(), "is not a permitted destination") _, err = template.LoadText(ctx, reg, nil, "", "", map[string]interface{}{}, "http://localhost:8080/1234") require.Error(t, err) - assert.Contains(t, err.Error(), "is not a public IP address") - + assert.Contains(t, err.Error(), "is not a permitted destination") }) t.Run("method=cache works", func(t *testing.T) { @@ -208,6 +205,5 @@ func TestLoadTextTemplate(t *testing.T) { require.NotEqualf(t, tp1, tp2, "Expected remote template 1 and remote template 2 to not be equal") }) - }) } diff --git a/go.mod b/go.mod index 262ebd0103e5..93496e8b4c93 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,6 @@ require ( github.com/avast/retry-go/v3 v3.1.1 github.com/bradleyjkemp/cupaloy/v2 v2.8.0 github.com/bwmarrin/discordgo v0.23.0 - github.com/go-faker/faker/v4 v4.2.0 github.com/cenkalti/backoff v2.2.1+incompatible github.com/coreos/go-oidc v2.2.1+incompatible github.com/cortesi/modd v0.0.0-20210323234521-b35eddab86cc @@ -30,6 +29,7 @@ require ( github.com/ghodss/yaml v1.0.0 github.com/go-crypt/crypt v0.2.9 github.com/go-errors/errors v1.0.1 + github.com/go-faker/faker/v4 v4.2.0 github.com/go-openapi/strfmt v0.21.7 github.com/go-playground/validator/v10 v10.4.1 github.com/go-swagger/go-swagger v0.30.5 @@ -75,7 +75,7 @@ require ( github.com/ory/jsonschema/v3 v3.0.8 github.com/ory/mail/v3 v3.0.0 github.com/ory/nosurf v1.2.7 - github.com/ory/x v0.0.597 + github.com/ory/x v0.0.604 github.com/peterhellberg/link v1.2.0 github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 github.com/pkg/errors v0.9.1 @@ -92,22 +92,24 @@ require ( github.com/tidwall/gjson v1.14.3 github.com/tidwall/sjson v1.2.5 github.com/urfave/negroni v1.0.0 - github.com/zmb3/spotify/v2 v2.0.0 + github.com/zmb3/spotify/v2 v2.4.0 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 go.opentelemetry.io/otel v1.19.0 go.opentelemetry.io/otel/trace v1.19.0 - golang.org/x/crypto v0.14.0 - golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 - golang.org/x/net v0.17.0 - golang.org/x/oauth2 v0.12.0 - golang.org/x/sync v0.3.0 - golang.org/x/text v0.13.0 + golang.org/x/crypto v0.15.0 + golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa + golang.org/x/net v0.18.0 + golang.org/x/oauth2 v0.14.0 + golang.org/x/sync v0.5.0 + golang.org/x/text v0.14.0 golang.org/x/tools/cmd/cover v0.1.0-deprecated google.golang.org/grpc v1.59.0 ) require go.opentelemetry.io/otel/sdk v1.19.0 +require code.dny.dev/ssrf v0.2.0 // indirect + require ( github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Masterminds/goutils v1.1.1 // indirect @@ -142,12 +144,12 @@ require ( github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/fatih/structs v1.1.0 // indirect github.com/felixge/fgprof v0.9.3 // indirect - github.com/felixge/httpsnoop v1.0.3 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fxamacker/cbor/v2 v2.4.0 // indirect github.com/go-crypt/x v0.2.1 // indirect github.com/go-jose/go-jose/v3 v3.0.0 // indirect - github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/analysis v0.21.4 // indirect github.com/go-openapi/errors v0.20.4 // indirect @@ -192,7 +194,7 @@ require ( github.com/gorilla/securecookie v1.1.1 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-hclog v1.2.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect @@ -307,15 +309,15 @@ require ( go.opentelemetry.io/otel/exporters/zipkin v1.19.0 // indirect; / indirect go.opentelemetry.io/otel/metric v1.19.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect - golang.org/x/mod v0.10.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/term v0.13.0 // indirect - golang.org/x/tools v0.9.3 // indirect - golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect + golang.org/x/mod v0.14.0 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/term v0.14.0 // indirect + golang.org/x/tools v0.15.0 // indirect + golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect diff --git a/go.sum b/go.sum index c5d1fc506475..e22a551b44c4 100644 --- a/go.sum +++ b/go.sum @@ -35,6 +35,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +code.dny.dev/ssrf v0.2.0 h1:wCBP990rQQ1CYfRpW+YK1+8xhwUjv189AQ3WMo1jQaI= +code.dny.dev/ssrf v0.2.0/go.mod h1:B+91l25OnyaLIeCx0WRJN5qfJ/4/ZTZxRXgm0lj/2w8= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= @@ -190,8 +192,8 @@ github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= -github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= @@ -224,8 +226,8 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= @@ -415,8 +417,8 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github/v27 v27.0.1 h1:sSMFSShNn4VnqCqs+qhab6TS3uQc+uVR6TD1bW6MavM= github.com/google/go-github/v27 v27.0.1/go.mod h1:/0Gr8pJ55COkmv+S/yPKCczSkUPIM/LnFyubufRNIS0= github.com/google/go-github/v38 v38.1.0 h1:C6h1FkaITcBFK7gAmq4eFzt6gbhEhk7L5z6R3Uva+po= @@ -474,8 +476,8 @@ github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWm github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 h1:RtRsiaGvWxcwd8y3BiRZxsylPT8hLWZ5SPcfI+3IDNk= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0/go.mod h1:TzP6duP4Py2pHLVPPQp42aoYI92+PCrVotyR5e8Vqlk= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 h1:6UKoz5ujsI55KNpsJH3UwCq3T8kKbZwNZBNPuTTje8U= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1/go.mod h1:YvJ2f6MplWDhfxiUC3KpyTy76kYUZA4W3pTv/wdKQ9Y= github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69 h1:7xsUJsB2NrdcttQPa7JLEaGzvdbk7KvfrjgHZXOQRo0= github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69/go.mod h1:YLEMZOtU+AZ7dhN9T/IpGhXVGly2bvkJQ+zxj3WeVQo= github.com/hashicorp/consul/api v1.20.0 h1:9IHTjNVSZ7MIwjlW3N3a7iGiykCMDpxZu8jsxFJh0yc= @@ -838,8 +840,8 @@ github.com/ory/nosurf v1.2.7 h1:YrHrbSensQyU6r6HT/V5+HPdVEgrOTMJiLoJABSBOp4= github.com/ory/nosurf v1.2.7/go.mod h1:d4L3ZBa7Amv55bqxCBtCs63wSlyaiCkWVl4vKf3OUxA= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2 h1:zm6sDvHy/U9XrGpixwHiuAwpp0Ock6khSVHkrv6lQQU= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/ory/x v0.0.597 h1:msBfbEE5Ps8MXR3VxxIVUvei+f1o7cE/XKoIytuTqVQ= -github.com/ory/x v0.0.597/go.mod h1:ksLBEd6iW6czGpE6eNA0gCIxO1FFeqIxCZgsgwNrzMM= +github.com/ory/x v0.0.604 h1:I02tf+FIEcA98+tPyaspRQYxlX28uIGAB1g7JTh8GUk= +github.com/ory/x v0.0.604/go.mod h1:AFyMDGw6bh14PAGQITzlFuF/1OAvEXOX61PYbxJyeS8= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -1054,8 +1056,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -github.com/zmb3/spotify/v2 v2.0.0 h1:NHW9btztNZTrJ0+3yMNyfY5qcu1ck9s36wwzc7zrCic= -github.com/zmb3/spotify/v2 v2.0.0/go.mod h1:+LVh9CafHu7SedyqYmEf12Rd01dIVlEL845yNhksW0E= +github.com/zmb3/spotify/v2 v2.4.0 h1:ZHdhBx/Qyn7rtVDP+onk/oSvtL5uVyJtb+VBLrNDC7Y= +github.com/zmb3/spotify/v2 v2.4.0/go.mod h1:m6c3mHgZSt1rTF76UfSfdn1Gb2Kx/B/ClCcr+2V1Scw= go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= @@ -1134,8 +1136,8 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= +golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1146,8 +1148,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 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/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM= -golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= 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= @@ -1175,8 +1177,8 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= -golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1219,7 +1221,6 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= @@ -1229,9 +1230,10 @@ golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfS golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= +golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1244,8 +1246,8 @@ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210810183815-faf39c7919d5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= -golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= +golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0= +golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= 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= @@ -1261,8 +1263,8 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1352,8 +1354,8 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20191110171634-ad39bd3f0407/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1365,8 +1367,8 @@ golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= +golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= 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= @@ -1376,17 +1378,18 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= -golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -1453,8 +1456,8 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM= -golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= +golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= +golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= golang.org/x/tools/cmd/cover v0.1.0-deprecated h1:Rwy+mWYz6loAF+LnG1jHG/JWMHRMMC2/1XX3Ejkx9lA= golang.org/x/tools/cmd/cover v0.1.0-deprecated/go.mod h1:hMDiIvlpN1NoVgmjLjUJE9tMHyxHjFX7RuQ+rW12mSA= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1463,8 +1466,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= 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= @@ -1490,8 +1493,9 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= 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= @@ -1528,12 +1532,12 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b h1:+YaDE2r2OG8t/z5qmsh7Y+XXwCbvadxxZ0YY6mTdrVA= -google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI= -google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b h1:CIC2YMXmIhYw6evmhPxBKJ4fmLbOFtXQN/GV3XOZR8k= -google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b h1:ZlWIi1wSK56/8hn4QcBp/j9M7Gt3U/3hZw3mC7vDICo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:swOH3j0KzcDDgGUWr+SNpyTen5YrXjS3eyPzFYKc6lc= +google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ= +google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY= +google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo= +google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= diff --git a/identity/validator_test.go b/identity/validator_test.go index bb5cc81e442e..6b1f00ab7883 100644 --- a/identity/validator_test.go +++ b/identity/validator_test.go @@ -62,8 +62,8 @@ func TestSchemaValidatorDisallowsInternalNetworkRequests(t *testing.T) { } for _, tc := range [][2]string{ - {"localhost", "is not a public IP address"}, - {"privateRef", "is not a public IP address"}, + {"localhost", "is not a permitted destination"}, + {"privateRef", "is not a permitted destination"}, } { t.Run(fmt.Sprintf("case=%s", tc[0]), func(t *testing.T) { assert.Contains(t, do(t, tc[0]), tc[1]) diff --git a/selfservice/hook/web_hook_integration_test.go b/selfservice/hook/web_hook_integration_test.go index 447ddbea4ef8..fbdbb1f79b88 100644 --- a/selfservice/hook/web_hook_integration_test.go +++ b/selfservice/hook/web_hook_integration_test.go @@ -1007,7 +1007,7 @@ func TestDisallowPrivateIPRanges(t *testing.T) { }`)) err := wh.ExecuteLoginPostHook(nil, req, node.DefaultGroup, f, s) require.Error(t, err) - require.Contains(t, err.Error(), "is not a public IP address") + require.Contains(t, err.Error(), "is not a permitted destination") }) t.Run("allowed to call exempt url", func(t *testing.T) { @@ -1019,7 +1019,7 @@ func TestDisallowPrivateIPRanges(t *testing.T) { }`)) err := wh.ExecuteLoginPostHook(nil, req, node.DefaultGroup, f, s) require.Error(t, err, "the target does not exist and we still receive an error") - require.NotContains(t, err.Error(), "is not a public IP address", "but the error is not related to the IP range.") + require.NotContains(t, err.Error(), "is not a permitted destination", "but the error is not related to the IP range.") }) t.Run("not allowed to load from source", func(t *testing.T) { @@ -1040,7 +1040,7 @@ func TestDisallowPrivateIPRanges(t *testing.T) { }`)) err := wh.ExecuteLoginPostHook(nil, req, node.DefaultGroup, f, s) require.Error(t, err) - require.Contains(t, err.Error(), "192.168.178.0 is not a public IP address") + require.Contains(t, err.Error(), "is not a permitted destination") }) } diff --git a/selfservice/strategy/oidc/provider_auth0.go b/selfservice/strategy/oidc/provider_auth0.go index 302c61eaf48e..15f332d5cfa8 100644 --- a/selfservice/strategy/oidc/provider_auth0.go +++ b/selfservice/strategy/oidc/provider_auth0.go @@ -11,14 +11,13 @@ import ( "path" "time" + "github.com/ory/x/httpx" "github.com/ory/x/stringsx" "github.com/tidwall/sjson" "github.com/hashicorp/go-retryablehttp" - "github.com/ory/x/httpx" - "github.com/pkg/errors" "github.com/tidwall/gjson" "golang.org/x/oauth2" @@ -78,13 +77,14 @@ func (g *ProviderAuth0) Claims(ctx context.Context, exchange *oauth2.Token, quer return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("%s", err)) } - client := g.reg.HTTPClient(ctx, httpx.ResilientClientWithClient(o.Client(ctx, exchange))) u, err := url.Parse(g.config.IssuerURL) if err != nil { return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("%s", err)) } u.Path = path.Join(u.Path, "/userinfo") - req, err := retryablehttp.NewRequest("GET", u.String(), nil) + + ctx, client := httpx.SetOAuth2(ctx, g.reg.HTTPClient(ctx), o, exchange) + req, err := retryablehttp.NewRequestWithContext(ctx, "GET", u.String(), nil) if err != nil { return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("%s", err)) } diff --git a/selfservice/strategy/oidc/provider_facebook.go b/selfservice/strategy/oidc/provider_facebook.go index 32bf1f35c0fa..abf9806cce05 100644 --- a/selfservice/strategy/oidc/provider_facebook.go +++ b/selfservice/strategy/oidc/provider_facebook.go @@ -69,13 +69,13 @@ func (g *ProviderFacebook) Claims(ctx context.Context, exchange *oauth2.Token, q } appSecretProof := g.generateAppSecretProof(ctx, exchange) - client := g.reg.HTTPClient(ctx, httpx.ResilientClientWithClient(o.Client(ctx, exchange))) u, err := url.Parse(fmt.Sprintf("https://graph.facebook.com/me?fields=id,name,first_name,last_name,middle_name,email,picture,birthday,gender&appsecret_proof=%s", appSecretProof)) if err != nil { return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("%s", err)) } - req, err := retryablehttp.NewRequest("GET", u.String(), nil) + ctx, client := httpx.SetOAuth2(ctx, g.reg.HTTPClient(ctx), o, exchange) + req, err := retryablehttp.NewRequestWithContext(ctx, "GET", u.String(), nil) if err != nil { return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("%s", err)) } diff --git a/selfservice/strategy/oidc/provider_github.go b/selfservice/strategy/oidc/provider_github.go index c805c593b4e0..fe1d2bc371d1 100644 --- a/selfservice/strategy/oidc/provider_github.go +++ b/selfservice/strategy/oidc/provider_github.go @@ -14,6 +14,7 @@ import ( "golang.org/x/oauth2" "golang.org/x/oauth2/github" + "github.com/ory/x/httpx" "github.com/ory/x/stringslice" "github.com/ory/x/stringsx" @@ -67,7 +68,8 @@ func (g *ProviderGitHub) Claims(ctx context.Context, exchange *oauth2.Token, que } } - gh := ghapi.NewClient(g.oauth2(ctx).Client(ctx, exchange)) + ctx, client := httpx.SetOAuth2(ctx, g.reg.HTTPClient(ctx), g.oauth2(ctx), exchange) + gh := ghapi.NewClient(client.HTTPClient) user, _, err := gh.Users.Get(ctx, "") if err != nil { diff --git a/selfservice/strategy/oidc/provider_github_app.go b/selfservice/strategy/oidc/provider_github_app.go index 703ba494df2c..95801ce59e47 100644 --- a/selfservice/strategy/oidc/provider_github_app.go +++ b/selfservice/strategy/oidc/provider_github_app.go @@ -9,6 +9,7 @@ import ( "net/url" "github.com/ory/kratos/x" + "github.com/ory/x/httpx" "github.com/pkg/errors" "golang.org/x/oauth2" @@ -57,7 +58,8 @@ func (g *ProviderGitHubApp) AuthCodeURLOptions(r ider) []oauth2.AuthCodeOption { } func (g *ProviderGitHubApp) Claims(ctx context.Context, exchange *oauth2.Token, query url.Values) (*Claims, error) { - gh := ghapi.NewClient(g.oauth2(ctx).Client(ctx, exchange)) + ctx, client := httpx.SetOAuth2(ctx, g.reg.HTTPClient(ctx), g.oauth2(ctx), exchange) + gh := ghapi.NewClient(client.HTTPClient) user, _, err := gh.Users.Get(ctx, "") if err != nil { diff --git a/selfservice/strategy/oidc/provider_gitlab.go b/selfservice/strategy/oidc/provider_gitlab.go index f7493367345f..9ef55b4beef7 100644 --- a/selfservice/strategy/oidc/provider_gitlab.go +++ b/selfservice/strategy/oidc/provider_gitlab.go @@ -75,14 +75,14 @@ func (g *ProviderGitLab) Claims(ctx context.Context, exchange *oauth2.Token, que return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("%s", err)) } - client := g.reg.HTTPClient(ctx, httpx.ResilientClientDisallowInternalIPs(), httpx.ResilientClientWithClient(o.Client(ctx, exchange))) - u, err := g.endpoint() if err != nil { return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("%s", err)) } u.Path = path.Join(u.Path, "/oauth/userinfo") - req, err := retryablehttp.NewRequest("GET", u.String(), nil) + + ctx, client := httpx.SetOAuth2(ctx, g.reg.HTTPClient(ctx), o, exchange) + req, err := retryablehttp.NewRequestWithContext(ctx, "GET", u.String(), nil) if err != nil { return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("%s", err)) } @@ -108,7 +108,7 @@ func (g *ProviderGitLab) Claims(ctx context.Context, exchange *oauth2.Token, que } func (g *ProviderGitLab) endpoint() (*url.URL, error) { - var e = defaultEndpoint + e := defaultEndpoint if len(g.config.IssuerURL) > 0 { e = g.config.IssuerURL } diff --git a/selfservice/strategy/oidc/provider_google.go b/selfservice/strategy/oidc/provider_google.go index db7b4fdd14e5..de84a8dc1953 100644 --- a/selfservice/strategy/oidc/provider_google.go +++ b/selfservice/strategy/oidc/provider_google.go @@ -6,7 +6,6 @@ package oidc import ( "context" - "github.com/coreos/go-oidc" gooidc "github.com/coreos/go-oidc" "golang.org/x/oauth2" @@ -75,8 +74,8 @@ var _ IDTokenVerifier = new(ProviderGoogle) const issuerUrlGoogle = "https://accounts.google.com" func (p *ProviderGoogle) Verify(ctx context.Context, rawIDToken string) (*Claims, error) { - keySet := oidc.NewRemoteKeySet(ctx, p.JWKSUrl) - ctx = oidc.ClientContext(ctx, p.reg.HTTPClient(ctx).HTTPClient) + keySet := gooidc.NewRemoteKeySet(ctx, p.JWKSUrl) + ctx = gooidc.ClientContext(ctx, p.reg.HTTPClient(ctx).HTTPClient) return verifyToken(ctx, keySet, p.config, rawIDToken, issuerUrlGoogle) } diff --git a/selfservice/strategy/oidc/provider_linkedin.go b/selfservice/strategy/oidc/provider_linkedin.go index 052542d2b00a..03a3db3e490d 100644 --- a/selfservice/strategy/oidc/provider_linkedin.go +++ b/selfservice/strategy/oidc/provider_linkedin.go @@ -174,7 +174,7 @@ func (l *ProviderLinkedIn) Claims(ctx context.Context, exchange *oauth2.Token, q return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("%s", err)) } - client := l.reg.HTTPClient(ctx, httpx.ResilientClientWithClient(o.Client(ctx, exchange))) + ctx, client := httpx.SetOAuth2(ctx, l.reg.HTTPClient(ctx), o, exchange) profile, err := l.Profile(ctx, client) if err != nil { return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("%s", err)) diff --git a/selfservice/strategy/oidc/provider_microsoft.go b/selfservice/strategy/oidc/provider_microsoft.go index 3e31e505b358..8dd17fbbaae5 100644 --- a/selfservice/strategy/oidc/provider_microsoft.go +++ b/selfservice/strategy/oidc/provider_microsoft.go @@ -70,6 +70,7 @@ func (m *ProviderMicrosoft) Claims(ctx context.Context, exchange *oauth2.Token, } issuer := "https://login.microsoftonline.com/" + unverifiedClaims.TenantID + "/v2.0" + ctx = context.WithValue(ctx, oauth2.HTTPClient, m.reg.HTTPClient(ctx).HTTPClient) p, err := gooidc.NewProvider(ctx, issuer) if err != nil { return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Unable to initialize OpenID Connect Provider: %s", err)) @@ -90,8 +91,8 @@ func (m *ProviderMicrosoft) updateSubject(ctx context.Context, claims *Claims, e return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("%s", err)) } - client := m.reg.HTTPClient(ctx, httpx.ResilientClientWithClient(o.Client(ctx, exchange))) - req, err := retryablehttp.NewRequest("GET", "https://graph.microsoft.com/v1.0/me", nil) + ctx, client := httpx.SetOAuth2(ctx, m.reg.HTTPClient(ctx), o, exchange) + req, err := retryablehttp.NewRequestWithContext(ctx, "GET", "https://graph.microsoft.com/v1.0/me", nil) if err != nil { return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("%s", err)) } diff --git a/selfservice/strategy/oidc/provider_netid.go b/selfservice/strategy/oidc/provider_netid.go index f8f0023878ef..60664b199e7d 100644 --- a/selfservice/strategy/oidc/provider_netid.go +++ b/selfservice/strategy/oidc/provider_netid.go @@ -69,7 +69,6 @@ func (n *ProviderNetID) oAuth2(ctx context.Context) (*oauth2.Config, error) { Scopes: n.config.Scope, RedirectURL: n.config.Redir(n.reg.Config().OIDCRedirectURIBase(ctx)), }, nil - } func (n *ProviderNetID) Claims(ctx context.Context, exchange *oauth2.Token, _ url.Values) (*Claims, error) { @@ -78,13 +77,12 @@ func (n *ProviderNetID) Claims(ctx context.Context, exchange *oauth2.Token, _ ur return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("%s", err)) } + ctx, client := httpx.SetOAuth2(ctx, n.reg.HTTPClient(ctx), o, exchange) req, err := retryablehttp.NewRequestWithContext(ctx, "GET", urlx.AppendPaths(n.brokerURL(), "/userinfo").String(), nil) if err != nil { return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("%s", err)) } - client := n.reg.HTTPClient(ctx, httpx.ResilientClientDisallowInternalIPs(), httpx.ResilientClientWithClient(o.Client(ctx, exchange))) - resp, err := client.Do(req) if err != nil { return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("%s", err)) diff --git a/selfservice/strategy/oidc/provider_patreon.go b/selfservice/strategy/oidc/provider_patreon.go index abe1eeffd805..745dc8fcc199 100644 --- a/selfservice/strategy/oidc/provider_patreon.go +++ b/selfservice/strategy/oidc/provider_patreon.go @@ -83,9 +83,8 @@ func (d *ProviderPatreon) Claims(ctx context.Context, exchange *oauth2.Token, qu identityUrl := "https://www.patreon.com/api/oauth2/v2/identity?fields%5Buser%5D=first_name,last_name,url,full_name,email,image_url" o := d.oauth2(ctx) - client := d.reg.HTTPClient(ctx, httpx.ResilientClientWithClient(o.Client(ctx, exchange))) - - req, err := retryablehttp.NewRequest("GET", identityUrl, nil) + ctx, client := httpx.SetOAuth2(ctx, d.reg.HTTPClient(ctx), o, exchange) + req, err := retryablehttp.NewRequestWithContext(ctx, "GET", identityUrl, nil) if err != nil { return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("%s", err)) } diff --git a/selfservice/strategy/oidc/provider_private_net_test.go b/selfservice/strategy/oidc/provider_private_net_test.go index f017c4addc78..1e1d71458ee9 100644 --- a/selfservice/strategy/oidc/provider_private_net_test.go +++ b/selfservice/strategy/oidc/provider_private_net_test.go @@ -19,10 +19,12 @@ import ( "github.com/ory/kratos/selfservice/strategy/oidc" ) -const wellknownJWKs = "https://raw.githubusercontent.com/aeneasr/private-oidc/master/jwks" -const wellknownToken = "https://raw.githubusercontent.com/aeneasr/private-oidc/master/token" -const fakeJWTJWKS = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjk5OTk5OTk5OTksImF1ZCI6ImFiY2QiLCJpc3MiOiJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vYWVuZWFzci9wcml2YXRlLW9pZGMvbWFzdGVyL2p3a3MifQ.RLR3dSRGGIjbRqyOMGMYFGTzcVHi7hPuFs_IKYywVWJ_XMyzWozTW4M8uuvBUPiVoNDNs7osm-AkRl7cBfw0by1XEcnEKZStCjdEh7Q0IGGb4hgq8rRqm1d3uJwNIGU5h7-s7tMnDED2ZTZhp304U99YWz7Ozl_TA9tqolBLLZEmIfXSY_RR3rMoDwtHZvWhI0OZtPdcBh86vWS9zG6QPHM5qGtRMMIs-ljXrrgS8LulUI5CAVEeHlQLXroBIe9v89IkKi07A7YRrk1SxFxlojcZ2v0z-0iTI3WL8mUoocF-RYy1RgJTK_dPYkSJebaN0R5MmBax5MXLKy4baNHKsg" -const fakeJWTToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjk5OTk5OTk5OTksImF1ZCI6ImFiY2QiLCJpc3MiOiJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vYWVuZWFzci9wcml2YXRlLW9pZGMvbWFzdGVyL3Rva2VuIn0.G9v8pJXJrEOgdJ5ecE6sIIcTH_p-RKkBaImfZY5DDVCl7h5GEis1n3GKKYbL_O3fj8Fu-WzI2mquI8S8BOVCQ6wN0XtrqJv22iX_nzeVHc4V_JWV1q7hg2gPpoFFcnF3KKtxZLvDOA8ujsDbAXmoBu0fEBdwCN56xLOOKQDzULyfijuAa8hrCwespZ9HaqcHzD3iHf_Utd4nHqlTM-6upWpKIMkplS_NGcxrfIRIWusZ0wob6ryy8jECD9QeZpdTGUozq-YM64lZfMOZzuLuqichH_PCMKFyB_tOZb6lDIiiSX4Irz7_YF-DP-LmfxgIW4934RqTCeFGGIP64h4xAA" +const ( + wellknownJWKs = "https://raw.githubusercontent.com/aeneasr/private-oidc/master/jwks" + wellknownToken = "https://raw.githubusercontent.com/aeneasr/private-oidc/master/token" + fakeJWTJWKS = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjk5OTk5OTk5OTksImF1ZCI6ImFiY2QiLCJpc3MiOiJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vYWVuZWFzci9wcml2YXRlLW9pZGMvbWFzdGVyL2p3a3MifQ.RLR3dSRGGIjbRqyOMGMYFGTzcVHi7hPuFs_IKYywVWJ_XMyzWozTW4M8uuvBUPiVoNDNs7osm-AkRl7cBfw0by1XEcnEKZStCjdEh7Q0IGGb4hgq8rRqm1d3uJwNIGU5h7-s7tMnDED2ZTZhp304U99YWz7Ozl_TA9tqolBLLZEmIfXSY_RR3rMoDwtHZvWhI0OZtPdcBh86vWS9zG6QPHM5qGtRMMIs-ljXrrgS8LulUI5CAVEeHlQLXroBIe9v89IkKi07A7YRrk1SxFxlojcZ2v0z-0iTI3WL8mUoocF-RYy1RgJTK_dPYkSJebaN0R5MmBax5MXLKy4baNHKsg" + fakeJWTToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjk5OTk5OTk5OTksImF1ZCI6ImFiY2QiLCJpc3MiOiJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vYWVuZWFzci9wcml2YXRlLW9pZGMvbWFzdGVyL3Rva2VuIn0.G9v8pJXJrEOgdJ5ecE6sIIcTH_p-RKkBaImfZY5DDVCl7h5GEis1n3GKKYbL_O3fj8Fu-WzI2mquI8S8BOVCQ6wN0XtrqJv22iX_nzeVHc4V_JWV1q7hg2gPpoFFcnF3KKtxZLvDOA8ujsDbAXmoBu0fEBdwCN56xLOOKQDzULyfijuAa8hrCwespZ9HaqcHzD3iHf_Utd4nHqlTM-6upWpKIMkplS_NGcxrfIRIWusZ0wob6ryy8jECD9QeZpdTGUozq-YM64lZfMOZzuLuqichH_PCMKFyB_tOZb6lDIiiSX4Irz7_YF-DP-LmfxgIW4934RqTCeFGGIP64h4xAA" +) func TestProviderPrivateIP(t *testing.T) { ctx := context.Background() @@ -50,13 +52,13 @@ func TestProviderPrivateIP(t *testing.T) { }{ // Apple uses a fixed token URL and does not use the issuer. - {p: auth0, c: &oidc.Configuration{IssuerURL: "http://127.0.0.2/"}, e: "127.0.0.2 is not a public IP address"}, + {p: auth0, c: &oidc.Configuration{IssuerURL: "http://127.0.0.2/"}, e: "is not a permitted destination"}, // The TokenURL is fixed in Auth0 to {issuer_url}/token. Since the issuer is called first, any local token fails also. // If the issuer URL is local, we fail - {p: generic, c: &oidc.Configuration{IssuerURL: "http://127.0.0.2/"}, e: "127.0.0.2 is not a public IP address", id: fakeJWTJWKS}, + {p: generic, c: &oidc.Configuration{IssuerURL: "http://127.0.0.2/"}, e: "is not a permitted destination", id: fakeJWTJWKS}, // If the issuer URL has a local JWKs URL, we fail - {p: generic, c: &oidc.Configuration{ClientID: "abcd", IssuerURL: wellknownJWKs}, e: "is not a public IP address", id: fakeJWTJWKS}, + {p: generic, c: &oidc.Configuration{ClientID: "abcd", IssuerURL: wellknownJWKs}, e: "is not a permitted destination", id: fakeJWTJWKS}, // The next call does not fail because the provider uses only the ID JSON Web Token to verify this call and does // not use the TokenURL at all! // {p: generic, c: &oidc.Configuration{ClientID: "abcd", IssuerURL: wellknownToken, TokenURL: "http://127.0.0.3/"}, e: "127.0.0.3 is not a public IP address", id: fakeJWTToken}, @@ -67,7 +69,7 @@ func TestProviderPrivateIP(t *testing.T) { // GitHub App uses a fixed token URL and does not use the issuer. // GitHub App uses a fixed token URL and does not use the issuer. - {p: gitlab, c: &oidc.Configuration{IssuerURL: "http://127.0.0.2/"}, e: "127.0.0.2 is not a public IP address"}, + {p: gitlab, c: &oidc.Configuration{IssuerURL: "http://127.0.0.2/"}, e: "is not a permitted destination"}, // The TokenURL is fixed in GitLab to {issuer_url}/token. Since the issuer is called first, any local token fails also. // Google uses a fixed token URL and does not use the issuer. diff --git a/selfservice/strategy/oidc/provider_spotify.go b/selfservice/strategy/oidc/provider_spotify.go index d68671f9974e..366105c94d0e 100644 --- a/selfservice/strategy/oidc/provider_spotify.go +++ b/selfservice/strategy/oidc/provider_spotify.go @@ -13,6 +13,7 @@ import ( "github.com/pkg/errors" "golang.org/x/oauth2" + "github.com/ory/x/httpx" "github.com/ory/x/stringslice" "github.com/ory/x/stringsx" @@ -71,9 +72,10 @@ func (g *ProviderSpotify) Claims(ctx context.Context, exchange *oauth2.Token, qu spotifyauth.WithRedirectURL(g.config.Redir(g.reg.Config().OIDCRedirectURIBase(ctx))), spotifyauth.WithScopes(spotifyauth.ScopeUserReadPrivate)) - client := spotifyapi.New(auth.Client(ctx, exchange)) + ctx, client := httpx.SetOAuth2(ctx, g.reg.HTTPClient(ctx), auth, exchange) + spotifyClient := spotifyapi.New(client.HTTPClient) - user, err := client.CurrentUser(ctx) + user, err := spotifyClient.CurrentUser(ctx) if err != nil { return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("%s", err)) } diff --git a/selfservice/strategy/oidc/provider_userinfo_test.go b/selfservice/strategy/oidc/provider_userinfo_test.go index 8dc7173d4c77..0b11f2dcae90 100644 --- a/selfservice/strategy/oidc/provider_userinfo_test.go +++ b/selfservice/strategy/oidc/provider_userinfo_test.go @@ -11,23 +11,36 @@ import ( "testing" "time" + "github.com/hashicorp/go-retryablehttp" "github.com/jarcoal/httpmock" "golang.org/x/oauth2" "github.com/ory/herodot" + "github.com/ory/kratos/driver" "github.com/ory/kratos/driver/config" "github.com/ory/kratos/internal" "github.com/ory/kratos/selfservice/strategy/oidc" + "github.com/ory/x/httpx" "github.com/ory/x/otelx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) +type mockRegistry struct { + *driver.RegistryDefault + cl *retryablehttp.Client +} + +func (s *mockRegistry) HTTPClient(ctx context.Context, opts ...httpx.ResilientOptions) *retryablehttp.Client { + return s.cl +} + func TestProviderClaimsRespectsErrorCodes(t *testing.T) { - conf, reg := internal.NewFastRegistryWithMocks(t) + conf, base := internal.NewFastRegistryWithMocks(t) require.NoError(t, conf.Set(context.Background(), config.ViperKeyClientHTTPNoPrivateIPRanges, true)) - reg.SetTracer(otelx.NewNoop(nil, nil)) + base.SetTracer(otelx.NewNoop(nil, nil)) + reg := &mockRegistry{base, retryablehttp.NewClient()} ctx := context.Background() token := &oauth2.Token{AccessToken: "foo", Expiry: time.Now().Add(time.Hour)} @@ -242,7 +255,6 @@ func TestProviderClaimsRespectsErrorCodes(t *testing.T) { resp, err := httpmock.NewJsonResponse(200, json.RawMessage(`{"id":"new-id"}`)) return resp, err - }, userInfoEndpoint: "https://graph.microsoft.com/v1.0/me", provider: oidc.NewProviderMicrosoft(&oidc.Configuration{ @@ -280,8 +292,10 @@ func TestProviderClaimsRespectsErrorCodes(t *testing.T) { }, ) }, - expectedClaims: &oidc.Claims{Issuer: "https://login.microsoftonline.com/a9b86385-f32c-4803-afc8-4b2312fbdf24/v2.0", Subject: "new-id", Name: "John Doe", Email: "john.doe@example.com", - RawClaims: map[string]interface{}{"aud": []interface{}{"foo"}, "exp": 4.071728504e+09, "iat": 1.516239022e+09, "iss": "https://login.microsoftonline.com/a9b86385-f32c-4803-afc8-4b2312fbdf24/v2.0", "email": "john.doe@example.com", "name": "John Doe", "sub": "1234567890", "tid": "a9b86385-f32c-4803-afc8-4b2312fbdf24"}}, + expectedClaims: &oidc.Claims{ + Issuer: "https://login.microsoftonline.com/a9b86385-f32c-4803-afc8-4b2312fbdf24/v2.0", Subject: "new-id", Name: "John Doe", Email: "john.doe@example.com", + RawClaims: map[string]interface{}{"aud": []interface{}{"foo"}, "exp": 4.071728504e+09, "iat": 1.516239022e+09, "iss": "https://login.microsoftonline.com/a9b86385-f32c-4803-afc8-4b2312fbdf24/v2.0", "email": "john.doe@example.com", "name": "John Doe", "sub": "1234567890", "tid": "a9b86385-f32c-4803-afc8-4b2312fbdf24"}, + }, }, { name: "dingtalk", @@ -317,7 +331,7 @@ func TestProviderClaimsRespectsErrorCodes(t *testing.T) { } t.Run("http error is respected", func(t *testing.T) { - httpmock.Activate() + httpmock.ActivateNonDefault(reg.cl.HTTPClient) t.Cleanup(httpmock.DeactivateAndReset) if tc.hook != nil { @@ -325,18 +339,18 @@ func TestProviderClaimsRespectsErrorCodes(t *testing.T) { } httpmock.RegisterResponder("GET", tc.userInfoEndpoint, func(req *http.Request) (*http.Response, error) { - resp, err := httpmock.NewJsonResponse(401, map[string]interface{}{}) + resp, err := httpmock.NewJsonResponse(455, map[string]interface{}{}) return resp, err }) _, err := tc.provider.Claims(ctx, token, url.Values{}) var he *herodot.DefaultError require.ErrorAs(t, err, &he) - assert.Equal(t, "OpenID Connect provider returned a 401 status code but 200 is expected.", he.Reason()) + assert.Equal(t, "OpenID Connect provider returned a 455 status code but 200 is expected.", he.Reason()) }) t.Run("call is successful", func(t *testing.T) { - httpmock.Activate() + httpmock.ActivateNonDefault(reg.cl.HTTPClient) t.Cleanup(httpmock.DeactivateAndReset) if tc.hook != nil { diff --git a/selfservice/strategy/oidc/provider_vk.go b/selfservice/strategy/oidc/provider_vk.go index 995eed6fbe07..2a3513b6e050 100644 --- a/selfservice/strategy/oidc/provider_vk.go +++ b/selfservice/strategy/oidc/provider_vk.go @@ -65,8 +65,8 @@ func (g *ProviderVK) Claims(ctx context.Context, exchange *oauth2.Token, query u return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("%s", err)) } - client := g.reg.HTTPClient(ctx, httpx.ResilientClientWithClient(o.Client(ctx, exchange))) - req, err := retryablehttp.NewRequest("GET", "https://api.vk.com/method/users.get?fields=photo_200,nickname,bdate,sex&access_token="+exchange.AccessToken+"&v=5.103", nil) + ctx, client := httpx.SetOAuth2(ctx, g.reg.HTTPClient(ctx), o, exchange) + req, err := retryablehttp.NewRequestWithContext(ctx, "GET", "https://api.vk.com/method/users.get?fields=photo_200,nickname,bdate,sex&access_token="+exchange.AccessToken+"&v=5.103", nil) if err != nil { return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("%s", err)) } diff --git a/selfservice/strategy/oidc/provider_yandex.go b/selfservice/strategy/oidc/provider_yandex.go index dfb9267f8793..07b30caee52b 100644 --- a/selfservice/strategy/oidc/provider_yandex.go +++ b/selfservice/strategy/oidc/provider_yandex.go @@ -63,8 +63,8 @@ func (g *ProviderYandex) Claims(ctx context.Context, exchange *oauth2.Token, que return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("%s", err)) } - client := g.reg.HTTPClient(ctx, httpx.ResilientClientDisallowInternalIPs(), httpx.ResilientClientWithClient(o.Client(ctx, exchange))) - req, err := retryablehttp.NewRequest("GET", "https://login.yandex.ru/info?format=json&oauth_token="+exchange.AccessToken, nil) + ctx, client := httpx.SetOAuth2(ctx, g.reg.HTTPClient(ctx), o, exchange) + req, err := retryablehttp.NewRequestWithContext(ctx, "GET", "https://login.yandex.ru/info?format=json&oauth_token="+exchange.AccessToken, nil) if err != nil { return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("%s", err)) } diff --git a/selfservice/strategy/oidc/strategy.go b/selfservice/strategy/oidc/strategy.go index 8cf7b5069866..861547874cb5 100644 --- a/selfservice/strategy/oidc/strategy.go +++ b/selfservice/strategy/oidc/strategy.go @@ -481,6 +481,8 @@ func (s *Strategy) ExchangeCode(ctx context.Context, provider Provider, code str } } + client := s.d.HTTPClient(ctx) + ctx = context.WithValue(ctx, oauth2.HTTPClient, client.HTTPClient) token, err = te.Exchange(ctx, code) return token, err } diff --git a/selfservice/strategy/oidc/strategy_test.go b/selfservice/strategy/oidc/strategy_test.go index cdbff20e0477..c5d441bbd766 100644 --- a/selfservice/strategy/oidc/strategy_test.go +++ b/selfservice/strategy/oidc/strategy_test.go @@ -106,7 +106,7 @@ func TestStrategy(t *testing.T) { scope = []string{} // assert form values - var assertFormValues = func(t *testing.T, flowID uuid.UUID, provider string) (action string) { + assertFormValues := func(t *testing.T, flowID uuid.UUID, provider string) (action string) { var config *container.Container if req, err := reg.RegistrationFlowPersister().GetRegistrationFlow(context.Background(), flowID); err == nil { require.EqualValues(t, req.ID, flowID) @@ -135,15 +135,15 @@ func TestStrategy(t *testing.T) { return config.Action } - var registerAction = func(flowID uuid.UUID) string { + registerAction := func(flowID uuid.UUID) string { return ts.URL + registration.RouteSubmitFlow + "?flow=" + flowID.String() } - var loginAction = func(flowID uuid.UUID) string { + loginAction := func(flowID uuid.UUID) string { return ts.URL + login.RouteSubmitFlow + "?flow=" + flowID.String() } - var makeRequestWithCookieJar = func(t *testing.T, provider string, action string, fv url.Values, jar *cookiejar.Jar) (*http.Response, []byte) { + makeRequestWithCookieJar := func(t *testing.T, provider string, action string, fv url.Values, jar *cookiejar.Jar) (*http.Response, []byte) { fv.Set("provider", provider) res, err := testhelpers.NewClientWithCookieJar(t, jar, false).PostForm(action, fv) require.NoError(t, err, action) @@ -157,11 +157,11 @@ func TestStrategy(t *testing.T) { return res, body } - var makeRequest = func(t *testing.T, provider string, action string, fv url.Values) (*http.Response, []byte) { + makeRequest := func(t *testing.T, provider string, action string, fv url.Values) (*http.Response, []byte) { return makeRequestWithCookieJar(t, provider, action, fv, nil) } - var makeJSONRequest = func(t *testing.T, provider string, action string, fv url.Values) (*http.Response, []byte) { + makeJSONRequest := func(t *testing.T, provider string, action string, fv url.Values) (*http.Response, []byte) { fv.Set("provider", provider) client := testhelpers.NewClientWithCookieJar(t, nil, false) req, err := http.NewRequest("POST", action, strings.NewReader(fv.Encode())) @@ -180,7 +180,7 @@ func TestStrategy(t *testing.T) { return res, body } - var makeAPICodeFlowRequest = func(t *testing.T, provider, action string) (returnToCode string) { + makeAPICodeFlowRequest := func(t *testing.T, provider, action string) (returnToCode string) { res, err := testhelpers.NewDebugClient(t).Post(action, "application/json", strings.NewReader(fmt.Sprintf(`{ "method": "oidc", "provider": %q @@ -202,7 +202,7 @@ func TestStrategy(t *testing.T) { return code } - var exchangeCodeForToken = func(t *testing.T, codes sessiontokenexchange.Codes) (codeResponse session.CodeExchangeResponse, err error) { + exchangeCodeForToken := func(t *testing.T, codes sessiontokenexchange.Codes) (codeResponse session.CodeExchangeResponse, err error) { tokenURL := urlx.ParseOrPanic(ts.URL) tokenURL.Path = "/sessions/token-exchange" tokenURL.RawQuery = fmt.Sprintf("init_code=%s&return_to_code=%s", codes.InitCode, codes.ReturnToCode) @@ -218,7 +218,7 @@ func TestStrategy(t *testing.T) { return } - var assertSystemErrorWithReason = func(t *testing.T, res *http.Response, body []byte, code int, reason string) { + assertSystemErrorWithReason := func(t *testing.T, res *http.Response, body []byte, code int, reason string) { require.Contains(t, res.Request.URL.String(), errTS.URL, "%s", body) assert.Equal(t, int64(code), gjson.GetBytes(body, "code").Int(), "%s", prettyJSON(t, body)) @@ -226,7 +226,7 @@ func TestStrategy(t *testing.T) { } // assert system error (redirect to error endpoint) - var assertSystemErrorWithMessage = func(t *testing.T, res *http.Response, body []byte, code int, message string) { + assertSystemErrorWithMessage := func(t *testing.T, res *http.Response, body []byte, code int, message string) { require.Contains(t, res.Request.URL.String(), errTS.URL, "%s", body) assert.Equal(t, int64(code), gjson.GetBytes(body, "code").Int(), "%s", body) @@ -234,20 +234,20 @@ func TestStrategy(t *testing.T) { } // assert ui error (redirect to login/registration ui endpoint) - var assertUIError = func(t *testing.T, res *http.Response, body []byte, reason string) { + assertUIError := func(t *testing.T, res *http.Response, body []byte, reason string) { require.Contains(t, res.Request.URL.String(), uiTS.URL, "status: %d, body: %s", res.StatusCode, body) assert.Contains(t, gjson.GetBytes(body, "ui.messages.0.text").String(), reason, "%s", prettyJSON(t, body)) } // assert identity (success) - var assertIdentity = func(t *testing.T, res *http.Response, body []byte) { + assertIdentity := func(t *testing.T, res *http.Response, body []byte) { assert.Contains(t, res.Request.URL.String(), returnTS.URL, "%s", body) assert.Equal(t, subject, gjson.GetBytes(body, "identity.traits.subject").String(), "%s", prettyJSON(t, body)) assert.Equal(t, claims.traits.website, gjson.GetBytes(body, "identity.traits.website").String(), "%s", prettyJSON(t, body)) assert.Equal(t, claims.metadataPublic.picture, gjson.GetBytes(body, "identity.metadata_public.picture").String(), "%s", prettyJSON(t, body)) } - var newLoginFlow = func(t *testing.T, requestURL string, exp time.Duration, flowType flow.Type) (req *login.Flow) { + newLoginFlow := func(t *testing.T, requestURL string, exp time.Duration, flowType flow.Type) (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(), &http.Request{URL: urlx.ParseOrPanic(requestURL)}, flowType) @@ -264,14 +264,14 @@ func TestStrategy(t *testing.T) { return } - var newBrowserLoginFlow = func(t *testing.T, redirectTo string, exp time.Duration) (req *login.Flow) { + newBrowserLoginFlow := func(t *testing.T, redirectTo string, exp time.Duration) (req *login.Flow) { return newLoginFlow(t, redirectTo, exp, flow.TypeBrowser) } - var newAPILoginFlow = func(t *testing.T, redirectTo string, exp time.Duration) (req *login.Flow) { + newAPILoginFlow := func(t *testing.T, redirectTo string, exp time.Duration) (req *login.Flow) { return newLoginFlow(t, redirectTo, exp, flow.TypeAPI) } - var newRegistrationFlow = func(t *testing.T, redirectTo string, exp time.Duration, flowType flow.Type) *registration.Flow { + newRegistrationFlow := func(t *testing.T, redirectTo string, exp time.Duration, flowType flow.Type) *registration.Flow { // Use NewLoginFlow to instantiate the request but change the things we need to control a copy of it. req, err := reg.RegistrationHandler().NewRegistrationFlow(httptest.NewRecorder(), &http.Request{URL: urlx.ParseOrPanic(redirectTo)}, flowType) @@ -287,10 +287,10 @@ func TestStrategy(t *testing.T) { return req } - var newBrowserRegistrationFlow = func(t *testing.T, redirectTo string, exp time.Duration) *registration.Flow { + newBrowserRegistrationFlow := func(t *testing.T, redirectTo string, exp time.Duration) *registration.Flow { return newRegistrationFlow(t, redirectTo, exp, flow.TypeBrowser) } - var newAPIRegistrationFlow = func(t *testing.T, redirectTo string, exp time.Duration) *registration.Flow { + newAPIRegistrationFlow := func(t *testing.T, redirectTo string, exp time.Duration) *registration.Flow { return newRegistrationFlow(t, redirectTo, exp, flow.TypeAPI) } @@ -331,7 +331,8 @@ func TestStrategy(t *testing.T) { t.Run("case=should fail because the flow is expired", func(t *testing.T) { for k, v := range []uuid.UUID{ newBrowserLoginFlow(t, returnTS.URL, -time.Minute).ID, - newBrowserRegistrationFlow(t, returnTS.URL, -time.Minute).ID} { + newBrowserRegistrationFlow(t, returnTS.URL, -time.Minute).ID, + } { t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { action := assertFormValues(t, v, "valid") res, body := makeRequest(t, "valid", action, url.Values{}) @@ -510,7 +511,7 @@ func TestStrategy(t *testing.T) { t.Run("suite=API with session token exchange code", func(t *testing.T) { scope = []string{"openid"} - var loginOrRegister = func(t *testing.T, id uuid.UUID, code string) { + loginOrRegister := func(t *testing.T, id uuid.UUID, code string) { _, err := exchangeCodeForToken(t, sessiontokenexchange.Codes{InitCode: code}) require.Error(t, err) @@ -525,11 +526,11 @@ func TestStrategy(t *testing.T) { assert.NotEmpty(t, codeResponse.Token) assert.Equal(t, subject, gjson.GetBytes(codeResponse.Session.Identity.Traits, "subject").String()) } - var register = func(t *testing.T) { + register := func(t *testing.T) { f := newAPIRegistrationFlow(t, returnTS.URL+"?return_session_token_exchange_code=true&return_to=/app_code", 1*time.Minute) loginOrRegister(t, f.ID, f.SessionTokenExchangeCode) } - var login = func(t *testing.T) { + login := func(t *testing.T) { f := newAPILoginFlow(t, returnTS.URL+"?return_session_token_exchange_code=true&return_to=/app_code", 1*time.Minute) loginOrRegister(t, f.ID, f.SessionTokenExchangeCode) } @@ -584,7 +585,7 @@ func TestStrategy(t *testing.T) { expect func(t *testing.T, res *http.Response, body []byte) } - var prep = func(tc *testCase) (provider string, token string, nonce string) { + prep := func(tc *testCase) (provider string, token string, nonce string) { provider = tc.provider if provider == "" { provider = "test-provider" @@ -701,13 +702,13 @@ func TestStrategy(t *testing.T) { if tc.v != nil { v = tc.v(provider, token, nonce) } - res, err := cl.PostForm(action, v) + _, err := cl.PostForm(action, v) require.NoError(t, err) lf := newAPILoginFlow(t, returnTS.URL, time.Minute) action = assertFormValues(t, lf.ID, "test-provider") - res, err = cl.PostForm(action, v) + res, err := cl.PostForm(action, v) require.NoError(t, err) body := ioutilx.MustReadAll(res.Body) tc.expect(t, res, body) @@ -726,13 +727,13 @@ func TestStrategy(t *testing.T) { if tc.v != nil { v = tc.v(provider, token, nonce) } - res, err := cl.PostForm(action, v) + _, err := cl.PostForm(action, v) require.NoError(t, err) lf := newAPIRegistrationFlow(t, returnTS.URL, time.Minute) action = assertFormValues(t, lf.ID, "test-provider") - res, err = cl.PostForm(action, v) + res, err := cl.PostForm(action, v) require.NoError(t, err) body := ioutilx.MustReadAll(res.Body) tc.expect(t, res, body) @@ -778,7 +779,6 @@ func TestStrategy(t *testing.T) { }) t.Run("case=login without registered account with return_to", func(t *testing.T) { - t.Run("case=should pass login", func(t *testing.T) { subject = "login-without-register-return-to@ory.sh" scope = []string{"openid"} @@ -1036,7 +1036,7 @@ func TestStrategy(t *testing.T) { testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/registration-verifiable-email.schema.json") - var assertVerifiedEmail = func(t *testing.T, body []byte, verified bool) { + assertVerifiedEmail := func(t *testing.T, body []byte, verified bool) { assert.Len(t, gjson.GetBytes(body, "identity.verifiable_addresses").Array(), 1, "%s", body) assert.Equal(t, "email", gjson.GetBytes(body, "identity.verifiable_addresses.0.via").String(), "%s", body) assert.Equal(t, subject, gjson.GetBytes(body, "identity.verifiable_addresses.0.value").String(), "%s", body) @@ -1153,7 +1153,8 @@ func TestStrategy(t *testing.T) { "csrf_token": {linkingLoginFlow.CSRFToken}, "method": {"password"}, "identifier": {subject2}, - "password": {password}}) + "password": {password}, + }) require.NoError(t, err, linkingLoginFlow.UIAction) body, err := io.ReadAll(res.Body) require.NoError(t, res.Body.Close()) @@ -1170,7 +1171,8 @@ func TestStrategy(t *testing.T) { "csrf_token": {linkingLoginFlow.CSRFToken}, "method": {"password"}, "identifier": {subject}, - "password": {password}}) + "password": {password}, + }) require.NoError(t, err, linkingLoginFlow.UIAction) body, err := io.ReadAll(res.Body) require.NoError(t, res.Body.Close()) diff --git a/selfservice/strategy/password/validator_test.go b/selfservice/strategy/password/validator_test.go index f101cc19b59f..18501317b809 100644 --- a/selfservice/strategy/password/validator_test.go +++ b/selfservice/strategy/password/validator_test.go @@ -87,14 +87,17 @@ func TestDefaultPasswordValidationStrategy(t *testing.T) { } }) } - }) t.Run("failure cases", func(t *testing.T) { conf, reg := internal.NewFastRegistryWithMocks(t) s, _ := password.NewDefaultPasswordValidatorStrategy(reg) fakeClient := NewFakeHTTPClient() - s.Client = httpx.NewResilientClient(httpx.ResilientClientWithClient(&fakeClient.Client), httpx.ResilientClientWithMaxRetry(1), httpx.ResilientClientWithConnectionTimeout(time.Millisecond), httpx.ResilientClientWithMaxRetryWait(time.Millisecond)) + s.Client = httpx.NewResilientClient( + httpx.ResilientClientWithMaxRetry(1), + httpx.ResilientClientWithConnectionTimeout(time.Millisecond), + httpx.ResilientClientWithMaxRetryWait(time.Millisecond)) + s.Client.HTTPClient = &fakeClient.Client t.Run("case=should send request to pwnedpasswords.com", func(t *testing.T) { conf.MustSet(ctx, config.ViperKeyIgnoreNetworkErrors, false) @@ -143,9 +146,10 @@ func TestDefaultPasswordValidationStrategy(t *testing.T) { Request: req, }, nil } - s.Client = httpx.NewResilientClient(httpx.ResilientClientWithClient(&fakeClient.Client), httpx.ResilientClientWithMaxRetry(1), httpx.ResilientClientWithConnectionTimeout(time.Millisecond)) + s.Client = httpx.NewResilientClient(httpx.ResilientClientWithMaxRetry(1), httpx.ResilientClientWithConnectionTimeout(time.Millisecond)) + s.Client.HTTPClient = &fakeClient.Client - var hashPw = func(t *testing.T, pw string) string { + hashPw := func(t *testing.T, pw string) string { //#nosec G401 -- sha1 is used for k-anonymity h := sha1.New() _, err := h.Write([]byte(pw)) @@ -261,7 +265,8 @@ func TestChangeHaveIBeenPwnedValidationHost(t *testing.T) { conf.MustSet(ctx, config.ViperKeyPasswordHaveIBeenPwnedHost, testServerURL.Host) fakeClient := NewFakeHTTPClient() - s.Client = httpx.NewResilientClient(httpx.ResilientClientWithClient(&fakeClient.Client), httpx.ResilientClientWithMaxRetry(1), httpx.ResilientClientWithConnectionTimeout(time.Millisecond)) + s.Client = httpx.NewResilientClient(httpx.ResilientClientWithMaxRetry(1), httpx.ResilientClientWithConnectionTimeout(time.Millisecond)) + s.Client.HTTPClient = &fakeClient.Client testServerExpectedCallURL := fmt.Sprintf("https://%s/range/BCBA9", testServerURL.Host) @@ -279,7 +284,8 @@ func TestDisableHaveIBeenPwnedValidationHost(t *testing.T) { conf.MustSet(ctx, config.ViperKeyPasswordHaveIBeenPwnedEnabled, false) fakeClient := NewFakeHTTPClient() - s.Client = httpx.NewResilientClient(httpx.ResilientClientWithClient(&fakeClient.Client), httpx.ResilientClientWithMaxRetry(1), httpx.ResilientClientWithConnectionTimeout(time.Millisecond)) + s.Client = httpx.NewResilientClient(httpx.ResilientClientWithMaxRetry(1), httpx.ResilientClientWithConnectionTimeout(time.Millisecond)) + s.Client.HTTPClient = &fakeClient.Client t.Run("case=should not send request to test server", func(t *testing.T) { require.NoError(t, s.Validate(context.Background(), "mohutdesub", "damrumukuh")) diff --git a/test/e2e/cypress/integration/profiles/network/errors.spec.ts b/test/e2e/cypress/integration/profiles/network/errors.spec.ts index 9c8dd925fd5e..4207b953b54d 100644 --- a/test/e2e/cypress/integration/profiles/network/errors.spec.ts +++ b/test/e2e/cypress/integration/profiles/network/errors.spec.ts @@ -15,7 +15,7 @@ describe("Registration failures with email profile", () => { cy.visit(express.registration, { failOnStatusCode: false }) cy.get('[data-testid="code-box"]').should( "contain.text", - "is not a public IP address", // could be ::1 or 127.0.0.1 + "is not a permitted destination", // could be ::1 or 127.0.0.1 ) }) @@ -24,7 +24,7 @@ describe("Registration failures with email profile", () => { cy.visit(express.registration, { failOnStatusCode: false }) cy.get('[data-testid="code-box"]').should( "contain.text", - "192.168.178.1 is not a public IP address", + "192.168.178.1 is not a permitted destination", ) }) @@ -33,7 +33,7 @@ describe("Registration failures with email profile", () => { cy.visit(express.login, { failOnStatusCode: false }) cy.get('[data-testid="code-box"]').should( "contain.text", - "192.168.178.2 is not a public IP address", + "192.168.178.2 is not a permitted destination", ) }) @@ -46,7 +46,7 @@ describe("Registration failures with email profile", () => { cy.get('[type="submit"]').click() cy.get('[data-testid="code-box"]').should( "contain.text", - "192.168.178.3 is not a public IP address", + "192.168.178.3 is not a permitted destination", ) }) }) diff --git a/test/e2e/package-lock.json b/test/e2e/package-lock.json index 5df47741d1ed..f7f7bd88539a 100644 --- a/test/e2e/package-lock.json +++ b/test/e2e/package-lock.json @@ -1578,9 +1578,9 @@ } }, "node_modules/http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", "dev": true }, "node_modules/http-signature": { @@ -4249,9 +4249,9 @@ "dev": true }, "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", "dev": true }, "http-signature": { From ee138ec4e1ba55ef077858653220db9e6b0c7254 Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Wed, 22 Nov 2023 16:00:00 +0100 Subject: [PATCH 194/282] fix: incorrect SMTP error handling (#3636) --- courier/smtp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/courier/smtp.go b/courier/smtp.go index 3de84b00384c..3c60b3361594 100644 --- a/courier/smtp.go +++ b/courier/smtp.go @@ -218,7 +218,7 @@ func (c *courier) dispatchEmail(ctx context.Context, msg Message) error { var mailErr *gomail.SendError switch { - case errors.As(err, &mailErr) && mailErr.Index >= 500: + case errors.As(err, &mailErr) && errors.As(mailErr.Cause, &protoErr) && protoErr.Code >= 500: fallthrough case errors.As(err, &protoErr) && protoErr.Code >= 500: // See https://en.wikipedia.org/wiki/List_of_SMTP_server_return_codes From 1a098b728f13bbb43711a5a3ebcfd6496e1632ea Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Wed, 22 Nov 2023 15:43:46 +0000 Subject: [PATCH 195/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2497a277e17f..352c6cd2b726 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-11-15)](#2023-11-15) +- [ (2023-11-22)](#2023-11-22) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -314,7 +314,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-11-15) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-11-22) ## Breaking Changes @@ -465,9 +465,17 @@ https://github.com/ory/kratos/pull/3480 - Ignore more cloudflare cookies ([#3499](https://github.com/ory/kratos/issues/3499)) ([f124ab5](https://github.com/ory/kratos/commit/f124ab5586781cdbfc0a0cfd11b4355bfc8a115c)) +- Improved SSRF protection ([#3629](https://github.com/ory/kratos/issues/3629)) + ([6d08576](https://github.com/ory/kratos/commit/6d08576bbc2c06014192f05e0129b95eb6c9fd80)): + + This also improves tracing in the OIDC strategy. + - Incorrect sdk generator path ([#3488](https://github.com/ory/kratos/issues/3488)) ([ed996c0](https://github.com/ory/kratos/commit/ed996c0d25e68e8a2c7de861c546f0b0e42e9e6e)) +- Incorrect SMTP error handling + ([#3636](https://github.com/ory/kratos/issues/3636)) + ([ee138ec](https://github.com/ory/kratos/commit/ee138ec4e1ba55ef077858653220db9e6b0c7254)) - Increase connection-level timeouts and shutdown timeouts ([#3570](https://github.com/ory/kratos/issues/3570)) ([200b413](https://github.com/ory/kratos/commit/200b4138a429d113ee045d16031bb0a6312c1c01)): From 6c7068cf41df51cde5fe9fc79cca84ec6124d38a Mon Sep 17 00:00:00 2001 From: Henning Perl Date: Wed, 22 Nov 2023 18:30:17 +0100 Subject: [PATCH 196/282] fix: don't list org SSOs in settings (#3637) --- selfservice/strategy/oidc/strategy_settings.go | 4 ++++ selfservice/strategy/oidc/strategy_settings_test.go | 3 +++ 2 files changed, 7 insertions(+) diff --git a/selfservice/strategy/oidc/strategy_settings.go b/selfservice/strategy/oidc/strategy_settings.go index a38e4e0b40d9..24623938fd87 100644 --- a/selfservice/strategy/oidc/strategy_settings.go +++ b/selfservice/strategy/oidc/strategy_settings.go @@ -164,6 +164,10 @@ func (s *Strategy) PopulateSettingsMethod(r *http.Request, id *identity.Identity sr.UI.GetNodes().Remove("unlink", "link") sr.UI.SetCSRF(s.d.GenerateCSRFToken(r)) for _, l := range linkable { + // We do not want to offer to link SSO providers in the settings. + if l.Config().OrganizationID != "" { + continue + } sr.UI.GetNodes().Append(NewLinkNode(l.Config().ID)) } diff --git a/selfservice/strategy/oidc/strategy_settings_test.go b/selfservice/strategy/oidc/strategy_settings_test.go index a6b819c94202..753bae5321b8 100644 --- a/selfservice/strategy/oidc/strategy_settings_test.go +++ b/selfservice/strategy/oidc/strategy_settings_test.go @@ -62,12 +62,15 @@ func TestSettingsStrategy(t *testing.T) { errTS := testhelpers.NewErrorTestServer(t, reg) publicTS, adminTS := testhelpers.NewKratosServers(t) + orgSSO := newOIDCProvider(t, publicTS, remotePublic, remoteAdmin, "org-sso") + orgSSO.OrganizationID = "org-1" viperSetProviderConfig( t, conf, newOIDCProvider(t, publicTS, remotePublic, remoteAdmin, "ory"), newOIDCProvider(t, publicTS, remotePublic, remoteAdmin, "google"), newOIDCProvider(t, publicTS, remotePublic, remoteAdmin, "github"), + orgSSO, ) testhelpers.InitKratosServers(t, reg, publicTS, adminTS) testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/settings.schema.json") From 3735f1cd7b03e128679d91d0ed4e4e6d28309d3c Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Wed, 22 Nov 2023 18:24:24 +0000 Subject: [PATCH 197/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 352c6cd2b726..ead3d791c142 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -439,6 +439,9 @@ https://github.com/ory/kratos/pull/3480 - Do not initialize parts of the registry in parallel ([#3534](https://github.com/ory/kratos/issues/3534)) ([ff177db](https://github.com/ory/kratos/commit/ff177db8a97f27abc3e883e79832685348602334)) +- Don't list org SSOs in settings + ([#3637](https://github.com/ory/kratos/issues/3637)) + ([6c7068c](https://github.com/ory/kratos/commit/6c7068cf41df51cde5fe9fc79cca84ec6124d38a)) - Don't require session for OIDC verification ([#3443](https://github.com/ory/kratos/issues/3443)) ([e08f831](https://github.com/ory/kratos/commit/e08f831c2715e515bf58dc2dbb47fc3576421a5c)) From c25ddffd2270a8d0861e2fc78cd0ba26e63af4eb Mon Sep 17 00:00:00 2001 From: Henning Perl Date: Thu, 23 Nov 2023 12:21:07 +0100 Subject: [PATCH 198/282] fix: panic in recovery (#3639) --- selfservice/strategy/code/strategy_recovery.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/selfservice/strategy/code/strategy_recovery.go b/selfservice/strategy/code/strategy_recovery.go index 1924247179a9..8c5f2c86d980 100644 --- a/selfservice/strategy/code/strategy_recovery.go +++ b/selfservice/strategy/code/strategy_recovery.go @@ -301,11 +301,11 @@ func (s *Strategy) retryRecoveryFlow(w http.ResponseWriter, r *http.Request, ft o(&retryOptions) } - s.deps.Logger(). - WithRequest(r). - WithField("message", retryOptions.message). - WithError(retryOptions.err). - Debug("A recovery flow is being retried because a validation error occurred.") + logger := s.deps.Logger().WithRequest(r).WithError(retryOptions.err) + if retryOptions.message != nil { + logger = logger.WithField("message", retryOptions.message) + } + logger.Debug("A recovery flow is being retried because a validation error occurred.") ctx := r.Context() config := s.deps.Config() From 8cb9e4cae9dffd4c25d52920186f9c5fbe2bd0fe Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Wed, 29 Nov 2023 11:35:44 +0100 Subject: [PATCH 199/282] fix: reject obviously invalid email addresses from courier --- courier/smtp.go | 4 ++++ courier/smtp_test.go | 22 ++++++++++++++-------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/courier/smtp.go b/courier/smtp.go index 3c60b3361594..c7255da045c7 100644 --- a/courier/smtp.go +++ b/courier/smtp.go @@ -8,6 +8,7 @@ import ( "crypto/tls" "encoding/json" "fmt" + "net/mail" "net/textproto" "strconv" "time" @@ -118,6 +119,9 @@ func (c *courier) QueueEmail(ctx context.Context, t EmailTemplate) (uuid.UUID, e if err != nil { return uuid.Nil, err } + if _, err := mail.ParseAddress(recipient); err != nil { + return uuid.Nil, err + } subject, err := t.EmailSubject(ctx) if err != nil { diff --git a/courier/smtp_test.go b/courier/smtp_test.go index c30d865b88ec..108a9a6f1abf 100644 --- a/courier/smtp_test.go +++ b/courier/smtp_test.go @@ -8,6 +8,7 @@ import ( "crypto/rand" "crypto/rsa" "crypto/tls" + "crypto/x509" "crypto/x509/pkix" "encoding/pem" "flag" @@ -19,8 +20,6 @@ import ( "testing" "time" - "crypto/x509" - "github.com/gofrs/uuid" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -55,21 +54,21 @@ func TestNewSMTP(t *testing.T) { t.SkipNow() } - //Should enforce StartTLS => dialer.StartTLSPolicy = gomail.MandatoryStartTLS and dialer.SSL = false + // Should enforce StartTLS => dialer.StartTLSPolicy = gomail.MandatoryStartTLS and dialer.SSL = false smtp := setupCourier("smtp://foo:bar@my-server:1234/") assert.Equal(t, smtp.SmtpDialer().StartTLSPolicy, gomail.MandatoryStartTLS, "StartTLS not enforced") assert.Equal(t, smtp.SmtpDialer().SSL, false, "Implicit TLS should not be enabled") - //Should enforce TLS => dialer.SSL = true + // Should enforce TLS => dialer.SSL = true smtp = setupCourier("smtps://foo:bar@my-server:1234/") assert.Equal(t, smtp.SmtpDialer().SSL, true, "Implicit TLS should be enabled") - //Should allow cleartext => dialer.StartTLSPolicy = gomail.OpportunisticStartTLS and dialer.SSL = false + // Should allow cleartext => dialer.StartTLSPolicy = gomail.OpportunisticStartTLS and dialer.SSL = false smtp = setupCourier("smtp://foo:bar@my-server:1234/?disable_starttls=true") assert.Equal(t, smtp.SmtpDialer().StartTLSPolicy, gomail.OpportunisticStartTLS, "StartTLS is enforced") assert.Equal(t, smtp.SmtpDialer().SSL, false, "Implicit TLS should not be enabled") - //Test cert based SMTP client auth + // Test cert based SMTP client auth clientCert, clientKey, err := generateTestClientCert() require.NoError(t, err) defer os.Remove(clientCert.Name()) @@ -88,8 +87,8 @@ func TestNewSMTP(t *testing.T) { assert.Equal(t, smtpWithCert.SmtpDialer().TLSConfig.ServerName, "my-server", "TLS config server name should match") assert.Contains(t, smtpWithCert.SmtpDialer().TLSConfig.Certificates, clientPEM, "TLS config should contain client pem") - //error case: invalid client key - conf.Set(ctx, config.ViperKeyCourierSMTPClientKeyPath, clientCert.Name()) //mixup client key and client cert + // error case: invalid client key + conf.Set(ctx, config.ViperKeyCourierSMTPClientKeyPath, clientCert.Name()) // mixup client key and client cert smtpWithCert = setupCourier("smtps://subdomain.my-server:1234/?server_name=my-server") assert.Equal(t, len(smtpWithCert.SmtpDialer().TLSConfig.Certificates), 0, "TLS config certificates should be empty") } @@ -117,6 +116,13 @@ func TestQueueEmail(t *testing.T) { ctx, cancel := context.WithCancel(ctx) defer cancel() + _, err = c.QueueEmail(ctx, templates.NewTestStub(reg, &templates.TestStubModel{ + To: "invalid-email", + Subject: "test-subject-1", + Body: "test-body-1", + })) + require.Error(t, err) + id, err := c.QueueEmail(ctx, templates.NewTestStub(reg, &templates.TestStubModel{ To: "test-recipient-1@example.org", Subject: "test-subject-1", From 7c0e02efdc115b5ac9dcf7e6517a27e903c02643 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Wed, 29 Nov 2023 13:05:01 +0000 Subject: [PATCH 200/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ead3d791c142..1e44818aab4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-11-22)](#2023-11-22) +- [ (2023-11-29)](#2023-11-29) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -314,7 +314,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-11-22) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-11-29) ## Breaking Changes @@ -533,6 +533,8 @@ https://github.com/ory/kratos/pull/3480 - chore: refactor +- Panic in recovery ([#3639](https://github.com/ory/kratos/issues/3639)) + ([c25ddff](https://github.com/ory/kratos/commit/c25ddffd2270a8d0861e2fc78cd0ba26e63af4eb)) - Pass context ([#3452](https://github.com/ory/kratos/issues/3452)) ([c492bdc](https://github.com/ory/kratos/commit/c492bdcd0c5dbdf527ae523d879a6c1eeb9c4cdf)) - Properly normalize OIDC verified emails @@ -584,6 +586,8 @@ https://github.com/ory/kratos/pull/3480 - Registration with verification ([#3451](https://github.com/ory/kratos/issues/3451)) ([77c3196](https://github.com/ory/kratos/commit/77c3196fd60c5927b84e9a7f6546f80ac2d78ee5)) +- Reject obviously invalid email addresses from courier + ([8cb9e4c](https://github.com/ory/kratos/commit/8cb9e4cae9dffd4c25d52920186f9c5fbe2bd0fe)) - Remove `earliest_possible_extend` default in schema ([#3464](https://github.com/ory/kratos/issues/3464)) ([7e05b7d](https://github.com/ory/kratos/commit/7e05b7db3c01efc96185ac18042e971e33da37c8)) From 180828eb507ab239a9c6589f747a6816b6e50074 Mon Sep 17 00:00:00 2001 From: Patrik Date: Fri, 1 Dec 2023 12:34:28 +0100 Subject: [PATCH 201/282] feat: extract identifier label for login from default identity schema (#3645) --- identity/validator.go | 4 +- schema/extension.go | 50 ++++-- selfservice/flow/login/error_test.go | 2 + .../flow/login/extension_identifier_label.go | 70 +++++++++ .../login/extension_identifier_label_test.go | 143 ++++++++++++++++++ selfservice/flow/login/handler_test.go | 2 + selfservice/strategy/code/strategy.go | 14 +- selfservice/strategy/code/strategy_login.go | 11 +- selfservice/strategy/password/login.go | 10 +- selfservice/strategy/webauthn/login.go | 11 +- .../profiles/email/login/ui.spec.ts | 2 +- 11 files changed, 294 insertions(+), 25 deletions(-) create mode 100644 selfservice/flow/login/extension_identifier_label.go create mode 100644 selfservice/flow/login/extension_identifier_label_test.go diff --git a/identity/validator.go b/identity/validator.go index 878162e0bd7b..3bd8f9476fa5 100644 --- a/identity/validator.go +++ b/identity/validator.go @@ -35,8 +35,8 @@ func NewValidator(d validatorDependencies) *Validator { return &Validator{v: schema.NewValidator(), d: d} } -func (v *Validator) ValidateWithRunner(ctx context.Context, i *Identity, runners ...schema.Extension) error { - runner, err := schema.NewExtensionRunner(ctx, runners...) +func (v *Validator) ValidateWithRunner(ctx context.Context, i *Identity, runners ...schema.ValidateExtension) error { + runner, err := schema.NewExtensionRunner(ctx, schema.WithValidateRunners(runners...)) if err != nil { return err } diff --git a/schema/extension.go b/schema/extension.go index 5b605cfb91d4..4e15aebf2a0a 100644 --- a/schema/extension.go +++ b/schema/extension.go @@ -41,30 +41,41 @@ type ( Recovery struct { Via string `json:"via"` } `json:"recovery"` - Mappings struct { - Identity struct { - Traits []struct { - Path string `json:"path"` - } `json:"traits"` - } `json:"identity"` - } `json:"mappings"` } - Extension interface { + ValidateExtension interface { Run(ctx jsonschema.ValidationContext, config ExtensionConfig, value interface{}) error Finish() error } + CompileExtension interface { + Run(ctx jsonschema.CompilerContext, config ExtensionConfig, rawSchema map[string]interface{}) error + } ExtensionRunner struct { meta *jsonschema.Schema compile func(ctx jsonschema.CompilerContext, m map[string]interface{}) (interface{}, error) validate func(ctx jsonschema.ValidationContext, s interface{}, v interface{}) error - runners []Extension + validateRunners []ValidateExtension + compileRunners []CompileExtension } + + ExtensionRunnerOption func(*ExtensionRunner) ) -func NewExtensionRunner(ctx context.Context, runners ...Extension) (*ExtensionRunner, error) { +func WithValidateRunners(runners ...ValidateExtension) ExtensionRunnerOption { + return func(r *ExtensionRunner) { + r.validateRunners = append(r.validateRunners, runners...) + } +} + +func WithCompileRunners(runners ...CompileExtension) ExtensionRunnerOption { + return func(r *ExtensionRunner) { + r.compileRunners = append(r.compileRunners, runners...) + } +} + +func NewExtensionRunner(ctx context.Context, opts ...ExtensionRunnerOption) (*ExtensionRunner, error) { var err error r := new(ExtensionRunner) c := jsonschema.NewCompiler() @@ -90,6 +101,12 @@ func NewExtensionRunner(ctx context.Context, runners ...Extension) (*ExtensionRu return nil, errors.WithStack(err) } + for _, runner := range r.compileRunners { + if err := runner.Run(ctx, e, m); err != nil { + return nil, err + } + } + return &e, nil } return nil, nil @@ -101,7 +118,7 @@ func NewExtensionRunner(ctx context.Context, runners ...Extension) (*ExtensionRu return nil } - for _, runner := range r.runners { + for _, runner := range r.validateRunners { if err := runner.Run(ctx, *c, v); err != nil { return err } @@ -109,7 +126,10 @@ func NewExtensionRunner(ctx context.Context, runners ...Extension) (*ExtensionRu return nil } - r.runners = runners + for _, opt := range opts { + opt(r) + } + return r, nil } @@ -126,13 +146,13 @@ func (r *ExtensionRunner) Extension() jsonschema.Extension { } } -func (r *ExtensionRunner) AddRunner(run Extension) *ExtensionRunner { - r.runners = append(r.runners, run) +func (r *ExtensionRunner) AddRunner(run ValidateExtension) *ExtensionRunner { + r.validateRunners = append(r.validateRunners, run) return r } func (r *ExtensionRunner) Finish() error { - for _, runner := range r.runners { + for _, runner := range r.validateRunners { if err := runner.Finish(); err != nil { return err } diff --git a/selfservice/flow/login/error_test.go b/selfservice/flow/login/error_test.go index c6b44b75cf3e..5cc78c35bda1 100644 --- a/selfservice/flow/login/error_test.go +++ b/selfservice/flow/login/error_test.go @@ -43,6 +43,8 @@ func TestHandleError(t *testing.T) { conf, reg := internal.NewFastRegistryWithMocks(t) public, _ := testhelpers.NewKratosServer(t, reg) + testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/password.schema.json") + router := httprouter.New() ts := httptest.NewServer(router) t.Cleanup(ts.Close) diff --git a/selfservice/flow/login/extension_identifier_label.go b/selfservice/flow/login/extension_identifier_label.go new file mode 100644 index 000000000000..8eec2b68d877 --- /dev/null +++ b/selfservice/flow/login/extension_identifier_label.go @@ -0,0 +1,70 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package login + +import ( + "context" + "sort" + + "github.com/ory/kratos/text" + + "github.com/ory/jsonschema/v3" + "github.com/ory/kratos/schema" +) + +type identifierLabelExtension struct { + identifierLabelCandidates []string +} + +var _ schema.CompileExtension = new(identifierLabelExtension) + +func GetIdentifierLabelFromSchema(ctx context.Context, schemaURL string) (*text.Message, error) { + ext := &identifierLabelExtension{} + + runner, err := schema.NewExtensionRunner(ctx, schema.WithCompileRunners(ext)) + if err != nil { + return nil, err + } + c := jsonschema.NewCompiler() + runner.Register(c) + + _, err = c.Compile(ctx, schemaURL) + if err != nil { + return nil, err + } + metaLabel := text.NewInfoNodeLabelID() + if label := ext.getLabel(); label != "" { + metaLabel = text.NewInfoNodeLabelGenerated(label) + } + return metaLabel, nil +} + +func (i *identifierLabelExtension) Run(_ jsonschema.CompilerContext, config schema.ExtensionConfig, rawSchema map[string]interface{}) error { + if config.Credentials.Password.Identifier || + config.Credentials.WebAuthn.Identifier || + config.Credentials.TOTP.AccountName || + config.Credentials.Code.Identifier { + if title, ok := rawSchema["title"]; ok { + // The jsonschema compiler validates the title to be a string, so this should always work. + switch t := title.(type) { + case string: + if t != "" { + i.identifierLabelCandidates = append(i.identifierLabelCandidates, t) + } + } + } + } + return nil +} + +func (i *identifierLabelExtension) getLabel() string { + if len(i.identifierLabelCandidates) == 0 { + // sane default is set elsewhere + return "" + } + // sort the candidates to get a deterministic result + sort.Strings(i.identifierLabelCandidates) + // just take the first, no good way to decide which one is the best + return i.identifierLabelCandidates[0] +} diff --git a/selfservice/flow/login/extension_identifier_label_test.go b/selfservice/flow/login/extension_identifier_label_test.go new file mode 100644 index 000000000000..f504239408e0 --- /dev/null +++ b/selfservice/flow/login/extension_identifier_label_test.go @@ -0,0 +1,143 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package login + +import ( + "context" + "encoding/base64" + "encoding/json" + "fmt" + "testing" + + "github.com/ory/kratos/text" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tidwall/sjson" + + "github.com/ory/kratos/schema" +) + +func constructSchema(t *testing.T, ecModifier, ucModifier func(*schema.ExtensionConfig)) string { + var emailConfig, usernameConfig schema.ExtensionConfig + + if ecModifier != nil { + ecModifier(&emailConfig) + } + if ucModifier != nil { + ucModifier(&usernameConfig) + } + + ec, err := json.Marshal(&emailConfig) + require.NoError(t, err) + uc, err := json.Marshal(&usernameConfig) + require.NoError(t, err) + + ec, err = sjson.DeleteBytes(ec, "verification") + require.NoError(t, err) + ec, err = sjson.DeleteBytes(ec, "recovery") + require.NoError(t, err) + ec, err = sjson.DeleteBytes(ec, "credentials.code.via") + require.NoError(t, err) + uc, err = sjson.DeleteBytes(uc, "verification") + require.NoError(t, err) + uc, err = sjson.DeleteBytes(uc, "recovery") + require.NoError(t, err) + uc, err = sjson.DeleteBytes(uc, "credentials.code.via") + require.NoError(t, err) + + return "base64://" + base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf(` +{ + "properties": { + "traits": { + "properties": { + "email": { + "title": "Email", + "ory.sh/kratos": %s + }, + "username": { + "title": "Username", + "ory.sh/kratos": %s + } + } + } + } +}`, ec, uc))) +} + +func TestGetIdentifierLabelFromSchema(t *testing.T) { + ctx := context.Background() + + for _, tc := range []struct { + name string + emailConfig, usernameConfig func(*schema.ExtensionConfig) + expected *text.Message + }{ + { + name: "email for password", + emailConfig: func(c *schema.ExtensionConfig) { + c.Credentials.Password.Identifier = true + }, + expected: text.NewInfoNodeLabelGenerated("Email"), + }, + { + name: "email for webauthn", + emailConfig: func(c *schema.ExtensionConfig) { + c.Credentials.WebAuthn.Identifier = true + }, + expected: text.NewInfoNodeLabelGenerated("Email"), + }, + { + name: "email for totp", + emailConfig: func(c *schema.ExtensionConfig) { + c.Credentials.TOTP.AccountName = true + }, + expected: text.NewInfoNodeLabelGenerated("Email"), + }, + { + name: "email for code", + emailConfig: func(c *schema.ExtensionConfig) { + c.Credentials.Code.Identifier = true + }, + expected: text.NewInfoNodeLabelGenerated("Email"), + }, + { + name: "email for all", + emailConfig: func(c *schema.ExtensionConfig) { + c.Credentials.Password.Identifier = true + c.Credentials.WebAuthn.Identifier = true + c.Credentials.TOTP.AccountName = true + c.Credentials.Code.Identifier = true + }, + expected: text.NewInfoNodeLabelGenerated("Email"), + }, + { + name: "username works as well", + usernameConfig: func(c *schema.ExtensionConfig) { + c.Credentials.Password.Identifier = true + }, + expected: text.NewInfoNodeLabelGenerated("Username"), + }, + { + name: "multiple identifiers", + emailConfig: func(c *schema.ExtensionConfig) { + c.Credentials.Password.Identifier = true + }, + usernameConfig: func(c *schema.ExtensionConfig) { + c.Credentials.Password.Identifier = true + }, + expected: text.NewInfoNodeLabelGenerated("Email"), + }, + { + name: "no identifiers", + expected: text.NewInfoNodeLabelID(), + }, + } { + t.Run(tc.name, func(t *testing.T) { + label, err := GetIdentifierLabelFromSchema(ctx, constructSchema(t, tc.emailConfig, tc.usernameConfig)) + require.NoError(t, err) + assert.Equal(t, tc.expected, label) + }) + } +} diff --git a/selfservice/flow/login/handler_test.go b/selfservice/flow/login/handler_test.go index 85daee4e65a9..9a82e85ccbc7 100644 --- a/selfservice/flow/login/handler_test.go +++ b/selfservice/flow/login/handler_test.go @@ -797,6 +797,8 @@ func TestGetFlow(t *testing.T) { _ = testhelpers.NewErrorTestServer(t, reg) _ = testhelpers.NewRedirTS(t, "", conf) + testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/password.schema.json") + setupLoginUI := func(t *testing.T, c *http.Client) *httptest.Server { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // It is important that we use a HTTP request to fetch the flow because that will show us if CSRF works or not diff --git a/selfservice/strategy/code/strategy.go b/selfservice/strategy/code/strategy.go index 8b21a89a69e2..a5d0c83703ec 100644 --- a/selfservice/strategy/code/strategy.go +++ b/selfservice/strategy/code/strategy.go @@ -149,9 +149,17 @@ func (s *Strategy) PopulateMethod(r *http.Request, f flow.Flow) error { WithMetaLabel(text.NewInfoNodeInputEmail()), ) } else if f.GetFlowName() == flow.LoginFlow { - // we use the identifier label here since we don't know what - // type of field the identifier is - nodes.Upsert(node.NewInputField("identifier", "", node.DefaultGroup, node.InputAttributeTypeText, node.WithRequiredInputAttribute).WithMetaLabel(text.NewInfoNodeLabelID())) + ds, err := s.deps.Config().DefaultIdentityTraitsSchemaURL(r.Context()) + if err != nil { + return err + } + + identifierLabel, err := login.GetIdentifierLabelFromSchema(r.Context(), ds.String()) + if err != nil { + return err + } + + nodes.Upsert(node.NewInputField("identifier", "", node.DefaultGroup, node.InputAttributeTypeText, node.WithRequiredInputAttribute).WithMetaLabel(identifierLabel)) } else if f.GetFlowName() == flow.RegistrationFlow { ds, err := s.deps.Config().DefaultIdentityTraitsSchemaURL(r.Context()) if err != nil { diff --git a/selfservice/strategy/code/strategy_login.go b/selfservice/strategy/code/strategy_login.go index 64a3ab13a325..1a0170d36648 100644 --- a/selfservice/strategy/code/strategy_login.go +++ b/selfservice/strategy/code/strategy_login.go @@ -22,7 +22,6 @@ import ( "github.com/ory/kratos/selfservice/flow" "github.com/ory/kratos/selfservice/flow/login" "github.com/ory/kratos/session" - "github.com/ory/kratos/text" "github.com/ory/kratos/ui/node" "github.com/ory/kratos/x" "github.com/ory/x/decoderx" @@ -79,10 +78,18 @@ func (s *Strategy) HandleLoginError(r *http.Request, f *login.Flow, body *update email = body.Identifier } + ds, err := s.deps.Config().DefaultIdentityTraitsSchemaURL(r.Context()) + if err != nil { + return err + } + identifierLabel, err := login.GetIdentifierLabelFromSchema(r.Context(), ds.String()) + if err != nil { + return err + } f.UI.SetCSRF(s.deps.GenerateCSRFToken(r)) f.UI.GetNodes().Upsert( node.NewInputField("identifier", email, node.DefaultGroup, node.InputAttributeTypeText, node.WithRequiredInputAttribute). - WithMetaLabel(text.NewInfoNodeLabelID()), + WithMetaLabel(identifierLabel), ) } diff --git a/selfservice/strategy/password/login.go b/selfservice/strategy/password/login.go index 7a56ebaf45d4..5c9ed653872d 100644 --- a/selfservice/strategy/password/login.go +++ b/selfservice/strategy/password/login.go @@ -147,7 +147,15 @@ func (s *Strategy) PopulateLoginMethod(r *http.Request, requestedAAL identity.Au sr.UI.SetCSRF(s.d.GenerateCSRFToken(r)) sr.UI.SetNode(node.NewInputField("identifier", identifier, node.DefaultGroup, node.InputAttributeTypeHidden)) } else { - sr.UI.SetNode(node.NewInputField("identifier", "", node.DefaultGroup, node.InputAttributeTypeText, node.WithRequiredInputAttribute).WithMetaLabel(text.NewInfoNodeLabelID())) + ds, err := s.d.Config().DefaultIdentityTraitsSchemaURL(r.Context()) + if err != nil { + return err + } + identifierLabel, err := login.GetIdentifierLabelFromSchema(r.Context(), ds.String()) + if err != nil { + return err + } + sr.UI.SetNode(node.NewInputField("identifier", "", node.DefaultGroup, node.InputAttributeTypeText, node.WithRequiredInputAttribute).WithMetaLabel(identifierLabel)) } sr.UI.SetCSRF(s.d.GenerateCSRFToken(r)) diff --git a/selfservice/strategy/webauthn/login.go b/selfservice/strategy/webauthn/login.go index 7b968c704151..6b9ee3a154f9 100644 --- a/selfservice/strategy/webauthn/login.go +++ b/selfservice/strategy/webauthn/login.go @@ -90,8 +90,17 @@ func (s *Strategy) populateLoginMethodForPasswordless(r *http.Request, sr *login return nil } + ds, err := s.d.Config().DefaultIdentityTraitsSchemaURL(r.Context()) + if err != nil { + return err + } + identifierLabel, err := login.GetIdentifierLabelFromSchema(r.Context(), ds.String()) + if err != nil { + return err + } + sr.UI.SetCSRF(s.d.GenerateCSRFToken(r)) - sr.UI.SetNode(node.NewInputField("identifier", "", node.DefaultGroup, node.InputAttributeTypeText, node.WithRequiredInputAttribute).WithMetaLabel(text.NewInfoNodeLabelID())) + sr.UI.SetNode(node.NewInputField("identifier", "", node.DefaultGroup, node.InputAttributeTypeText, node.WithRequiredInputAttribute).WithMetaLabel(identifierLabel)) sr.UI.GetNodes().Append(node.NewInputField("method", "webauthn", node.WebAuthnGroup, node.InputAttributeTypeSubmit).WithMetaLabel(text.NewInfoSelfServiceLoginWebAuthn())) return nil } diff --git a/test/e2e/cypress/integration/profiles/email/login/ui.spec.ts b/test/e2e/cypress/integration/profiles/email/login/ui.spec.ts index 8792dd14cb64..ff65ea6ca6b4 100644 --- a/test/e2e/cypress/integration/profiles/email/login/ui.spec.ts +++ b/test/e2e/cypress/integration/profiles/email/login/ui.spec.ts @@ -31,7 +31,7 @@ context("UI tests using the email profile", () => { it("should use the json schema titles", () => { cy.get(`${appPrefix(app)}input[name="identifier"]`) .parent() - .should("contain.text", "ID") + .should("contain.text", "Your E-Mail") cy.get('input[name="password"]') .parentsUntil("label") From bbf874fd7f7c6e5d51b11f39d989a17039a6e955 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Fri, 1 Dec 2023 12:19:30 +0000 Subject: [PATCH 202/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e44818aab4e..0b1a4f811f75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-11-29)](#2023-11-29) +- [ (2023-12-01)](#2023-12-01) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -314,7 +314,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-11-29) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-12-01) ## Breaking Changes @@ -844,6 +844,9 @@ https://github.com/ory/kratos/pull/3480 This feature depends on Cockroach functionality and configuration, and is not possible for MySQL or PostgreSQL. +- Extract identifier label for login from default identity schema + ([#3645](https://github.com/ory/kratos/issues/3645)) + ([180828e](https://github.com/ory/kratos/commit/180828eb507ab239a9c6589f747a6816b6e50074)) - Fine-grained hooks for all available flow methods ([#3519](https://github.com/ory/kratos/issues/3519)) ([a37f6bd](https://github.com/ory/kratos/commit/a37f6bddc48443b2fc464699fa5c2922f64d81f6)): From 309c50694c11162cad070337f9b1d4e0fcdf444b Mon Sep 17 00:00:00 2001 From: Sidartha Rakuram Date: Sun, 26 Nov 2023 18:59:20 +0800 Subject: [PATCH 203/282] fix: ignore CSRF middleware on Apple OIDC callback --- internal/testhelpers/session.go | 10 ++++++++++ selfservice/strategy/oidc/strategy.go | 4 ++-- selfservice/strategy/oidc/strategy_test.go | 6 ++++-- session/handler_test.go | 14 ++------------ 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/internal/testhelpers/session.go b/internal/testhelpers/session.go index 91a2da5abda2..e6e9da316ffd 100644 --- a/internal/testhelpers/session.go +++ b/internal/testhelpers/session.go @@ -251,3 +251,13 @@ func (ct *TransportWithHeader) RoundTrip(req *http.Request) (*http.Response, err } return ct.RoundTripper.RoundTrip(req) } + +func AssertNoCSRFCookieInResponse(t *testing.T, _ *httptest.Server, _ *http.Client, r *http.Response) { + found := false + for _, c := range r.Cookies() { + if strings.HasPrefix(c.Name, "csrf_token") { + found = true + } + } + require.False(t, found) +} diff --git a/selfservice/strategy/oidc/strategy.go b/selfservice/strategy/oidc/strategy.go index 861547874cb5..a2afff3ea425 100644 --- a/selfservice/strategy/oidc/strategy.go +++ b/selfservice/strategy/oidc/strategy.go @@ -210,9 +210,9 @@ func (s *Strategy) setRoutes(r *x.RouterPublic) { // Apple can use the POST request method when calling the callback if handle, _, _ := r.Lookup("POST", RouteCallback); handle == nil { // Hardcoded path to Apple provider, I don't have a better way of doing it right now. - // Also this exempt disables CSRF checks for both GET and POST requests. Unfortunately + // Also this ignore disables CSRF checks for both GET and POST requests. Unfortunately // CSRF handler does not allow to define a rule based on the request method, at least not yet. - s.d.CSRFHandler().ExemptPath(RouteBase + "/callback/apple") + s.d.CSRFHandler().IgnorePath(RouteBase + "/callback/apple") // When handler is called using POST method, the cookies are not attached to the request // by the browser. So here we just redirect the request to the same location rewriting the diff --git a/selfservice/strategy/oidc/strategy_test.go b/selfservice/strategy/oidc/strategy_test.go index c5d441bbd766..0b4ca95c6e9e 100644 --- a/selfservice/strategy/oidc/strategy_test.go +++ b/selfservice/strategy/oidc/strategy_test.go @@ -1417,14 +1417,13 @@ func TestPostEndpointRedirect(t *testing.T) { remoteAdmin, remotePublic, _ := newHydra(t, &subject, &claims, &scope) - publicTS, adminTS := testhelpers.NewKratosServers(t) + publicTS, _, _, _ := testhelpers.NewKratosServerWithCSRFAndRouters(t, reg) viperSetProviderConfig( t, conf, newOIDCProvider(t, publicTS, remotePublic, remoteAdmin, "apple"), ) - testhelpers.InitKratosServers(t, reg, publicTS, adminTS) t.Run("case=should redirect to GET and preserve parameters"+publicTS.URL, func(t *testing.T) { // create a client that does not follow redirects @@ -1441,5 +1440,8 @@ func TestPostEndpointRedirect(t *testing.T) { location, err := res.Location() require.NoError(t, err) assert.Equal(t, publicTS.URL+"/self-service/methods/oidc/callback/apple?state=foo&test=3", location.String()) + + // We don't want to add/override CSRF cookie when redirecting + testhelpers.AssertNoCSRFCookieInResponse(t, publicTS, c, res) }) } diff --git a/session/handler_test.go b/session/handler_test.go index 286943796927..b08fb4d1ecb5 100644 --- a/session/handler_test.go +++ b/session/handler_test.go @@ -51,16 +51,6 @@ func send(code int) httprouter.Handle { } } -func assertNoCSRFCookieInResponse(t *testing.T, _ *httptest.Server, _ *http.Client, r *http.Response) { - found := false - for _, c := range r.Cookies() { - if strings.HasPrefix(c.Name, "csrf_token") { - found = true - } - } - require.False(t, found) -} - func TestSessionWhoAmI(t *testing.T) { conf, reg := internal.NewFastRegistryWithMocks(t) ts, _, r, _ := testhelpers.NewKratosServerWithCSRFAndRouters(t, reg) @@ -156,7 +146,7 @@ func TestSessionWhoAmI(t *testing.T) { // No cookie yet -> 401 res, err := client.Get(ts.URL + RouteWhoami) require.NoError(t, err) - assertNoCSRFCookieInResponse(t, ts, client, res) // Test that no CSRF cookie is ever set here. + testhelpers.AssertNoCSRFCookieInResponse(t, ts, client, res) // Test that no CSRF cookie is ever set here. if cacheEnabled { assert.NotEmpty(t, res.Header.Get("Ory-Session-Cache-For")) @@ -183,7 +173,7 @@ func TestSessionWhoAmI(t *testing.T) { require.NoError(t, err) body, err := io.ReadAll(res.Body) require.NoError(t, err) - assertNoCSRFCookieInResponse(t, ts, client, res) // Test that no CSRF cookie is ever set here. + testhelpers.AssertNoCSRFCookieInResponse(t, ts, client, res) // Test that no CSRF cookie is ever set here. assert.EqualValues(t, http.StatusOK, res.StatusCode) assert.NotEmpty(t, res.Header.Get("X-Kratos-Authenticated-Identity-Id")) From 52c7d3b5dd4c014bdbb06c3104967675d20e87ae Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Tue, 5 Dec 2023 08:01:45 +0000 Subject: [PATCH 204/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b1a4f811f75..d918a481267e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-12-01)](#2023-12-01) +- [ (2023-12-05)](#2023-12-05) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -314,7 +314,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-12-01) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-12-05) ## Breaking Changes @@ -465,6 +465,8 @@ https://github.com/ory/kratos/pull/3480 Adds correct pagination parameters to the SDK methods for listing identities and sessions. +- Ignore CSRF middleware on Apple OIDC callback + ([309c506](https://github.com/ory/kratos/commit/309c50694c11162cad070337f9b1d4e0fcdf444b)) - Ignore more cloudflare cookies ([#3499](https://github.com/ory/kratos/issues/3499)) ([f124ab5](https://github.com/ory/kratos/commit/f124ab5586781cdbfc0a0cfd11b4355bfc8a115c)) From be907dbbd841025fd854344b77d3368b2ff8089f Mon Sep 17 00:00:00 2001 From: Patrik Date: Mon, 11 Dec 2023 12:56:39 +0100 Subject: [PATCH 205/282] fix: use ID label on login with multiple identifiers (#3657) --- selfservice/flow/login/extension_identifier_label.go | 6 +----- selfservice/flow/login/extension_identifier_label_test.go | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/selfservice/flow/login/extension_identifier_label.go b/selfservice/flow/login/extension_identifier_label.go index 8eec2b68d877..02b725f00b7f 100644 --- a/selfservice/flow/login/extension_identifier_label.go +++ b/selfservice/flow/login/extension_identifier_label.go @@ -5,7 +5,6 @@ package login import ( "context" - "sort" "github.com/ory/kratos/text" @@ -59,12 +58,9 @@ func (i *identifierLabelExtension) Run(_ jsonschema.CompilerContext, config sche } func (i *identifierLabelExtension) getLabel() string { - if len(i.identifierLabelCandidates) == 0 { + if len(i.identifierLabelCandidates) != 1 { // sane default is set elsewhere return "" } - // sort the candidates to get a deterministic result - sort.Strings(i.identifierLabelCandidates) - // just take the first, no good way to decide which one is the best return i.identifierLabelCandidates[0] } diff --git a/selfservice/flow/login/extension_identifier_label_test.go b/selfservice/flow/login/extension_identifier_label_test.go index f504239408e0..3b3a21400fb1 100644 --- a/selfservice/flow/login/extension_identifier_label_test.go +++ b/selfservice/flow/login/extension_identifier_label_test.go @@ -127,7 +127,7 @@ func TestGetIdentifierLabelFromSchema(t *testing.T) { usernameConfig: func(c *schema.ExtensionConfig) { c.Credentials.Password.Identifier = true }, - expected: text.NewInfoNodeLabelGenerated("Email"), + expected: text.NewInfoNodeLabelID(), }, { name: "no identifiers", From 8a261367de108d8afd48591f34755095c54fc0fb Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Mon, 11 Dec 2023 12:42:05 +0000 Subject: [PATCH 206/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d918a481267e..61b5a8cbad60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-12-05)](#2023-12-05) +- [ (2023-12-11)](#2023-12-11) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -314,7 +314,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-12-05) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-12-11) ## Breaking Changes @@ -652,6 +652,9 @@ https://github.com/ory/kratos/pull/3480 - test: update snapshot +- Use ID label on login with multiple identifiers + ([#3657](https://github.com/ory/kratos/issues/3657)) + ([be907db](https://github.com/ory/kratos/commit/be907dbbd841025fd854344b77d3368b2ff8089f)) - Use org ID from session if available in login flow ([#3545](https://github.com/ory/kratos/issues/3545)) ([1b3647c](https://github.com/ory/kratos/commit/1b3647c2acdad966f920c2b9e6e657c52aa50c6e)) From b5dede329247d0962688b15872a6caf027cf910f Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Mon, 11 Dec 2023 14:04:58 +0100 Subject: [PATCH 207/282] fix: incorrect login accept challenge (#3658) --- selfservice/flow/recovery/handler.go | 5 +++++ selfservice/flow/verification/handler.go | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/selfservice/flow/recovery/handler.go b/selfservice/flow/recovery/handler.go index 2a4c7f77dd01..6927a733dd8e 100644 --- a/selfservice/flow/recovery/handler.go +++ b/selfservice/flow/recovery/handler.go @@ -443,6 +443,11 @@ func (h *Handler) updateRecoveryFlow(w http.ResponseWriter, r *http.Request, ps return } + // WARNING - just because no error was returned does not mean that the challenge was accepted. Instead, the + // success state is available as: + // + // if f.State == flow.StatePassedChallenge + if f.Type == flow.TypeBrowser && !x.IsJSONRequest(r) { http.Redirect(w, r, f.AppendTo(h.d.Config().SelfServiceFlowRecoveryUI(r.Context())).String(), http.StatusSeeOther) return diff --git a/selfservice/flow/verification/handler.go b/selfservice/flow/verification/handler.go index 6e0852006f22..8b0e832ad8e7 100644 --- a/selfservice/flow/verification/handler.go +++ b/selfservice/flow/verification/handler.go @@ -444,7 +444,7 @@ func (h *Handler) updateVerificationFlow(w http.ResponseWriter, r *http.Request, if x.IsBrowserRequest(r) { // Special case: If we ended up here through a OAuth2 login challenge, we need to accept the login request // and redirect back to the OAuth2 provider. - if f.OAuth2LoginChallenge.String() != "" { + if flow.HasReachedState(flow.StatePassedChallenge, f.State) && f.OAuth2LoginChallenge.String() != "" { if !f.IdentityID.Valid || !f.SessionID.Valid { h.d.VerificationFlowErrorHandler().WriteFlowError(w, r, f, node.DefaultGroup, herodot.ErrBadRequest.WithReasonf("No session was found for this flow. Please retry the authentication.")) @@ -468,6 +468,7 @@ func (h *Handler) updateVerificationFlow(w http.ResponseWriter, r *http.Request, h.d.VerificationFlowErrorHandler().WriteFlowError(w, r, f, node.DefaultGroup, err) return } + err = h.d.SessionManager().IssueCookie(ctx, w, r, sess) if err != nil { h.d.VerificationFlowErrorHandler().WriteFlowError(w, r, f, node.DefaultGroup, err) From af7d1afc9068b8e1e00f03ce423aff118449689c Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Mon, 11 Dec 2023 13:49:31 +0000 Subject: [PATCH 208/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61b5a8cbad60..91d7b00f8f23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -475,6 +475,9 @@ https://github.com/ory/kratos/pull/3480 This also improves tracing in the OIDC strategy. +- Incorrect login accept challenge + ([#3658](https://github.com/ory/kratos/issues/3658)) + ([b5dede3](https://github.com/ory/kratos/commit/b5dede329247d0962688b15872a6caf027cf910f)) - Incorrect sdk generator path ([#3488](https://github.com/ory/kratos/issues/3488)) ([ed996c0](https://github.com/ory/kratos/commit/ed996c0d25e68e8a2c7de861c546f0b0e42e9e6e)) From fe4ac43cd0e2bb11af5aaf5132d1b48b39e5208a Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Tue, 12 Dec 2023 05:17:04 -0500 Subject: [PATCH 209/282] chore: pretty print allowed redirect URLs in error (#3660) --- x/http_secure_redirect.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/x/http_secure_redirect.go b/x/http_secure_redirect.go index cccbba6db2ec..9851abc0f53e 100644 --- a/x/http_secure_redirect.go +++ b/x/http_secure_redirect.go @@ -17,6 +17,8 @@ import ( "github.com/ory/x/stringsx" "github.com/ory/x/urlx" + "github.com/samber/lo" + "github.com/ory/kratos/driver/config" ) @@ -144,7 +146,9 @@ func SecureRedirectTo(r *http.Request, defaultReturnTo *url.URL, opts ...SecureR return nil, errors.WithStack(herodot.ErrBadRequest. WithID(text.ErrIDRedirectURLNotAllowed). WithReasonf("Requested return_to URL %q is not allowed.", returnTo). - WithDebugf("Allowed domains are: %v", o.allowlist)) + WithDebugf("Allowed domains are: %v", strings.Join(lo.Map(o.allowlist, func(u url.URL, _ int) string { + return u.String() + }), ", "))) } func SecureContentNegotiationRedirection( From 3df0d77883e21ed0141db119d95f722270eb39bd Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Tue, 12 Dec 2023 11:02:34 +0000 Subject: [PATCH 210/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 91d7b00f8f23..3503b9c1db9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-12-11)](#2023-12-11) +- [ (2023-12-12)](#2023-12-12) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -314,7 +314,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-12-11) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-12-12) ## Breaking Changes From 6cf7fc5ec9f9892b208e44101b477ff2969f3cc7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Dec 2023 10:59:59 +0100 Subject: [PATCH 211/282] chore(deps): bump github.com/go-jose/go-jose/v3 from 3.0.0 to 3.0.1 (#3634) Bumps [github.com/go-jose/go-jose/v3](https://github.com/go-jose/go-jose) from 3.0.0 to 3.0.1. - [Release notes](https://github.com/go-jose/go-jose/releases) - [Changelog](https://github.com/go-jose/go-jose/blob/v3/CHANGELOG.md) - [Commits](https://github.com/go-jose/go-jose/compare/v3.0.0...v3.0.1) --- updated-dependencies: - dependency-name: github.com/go-jose/go-jose/v3 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 93496e8b4c93..ede7ba2b45ae 100644 --- a/go.mod +++ b/go.mod @@ -148,7 +148,7 @@ require ( github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fxamacker/cbor/v2 v2.4.0 // indirect github.com/go-crypt/x v0.2.1 // indirect - github.com/go-jose/go-jose/v3 v3.0.0 // indirect + github.com/go-jose/go-jose/v3 v3.0.1 // indirect github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/analysis v0.21.4 // indirect diff --git a/go.sum b/go.sum index e22a551b44c4..2b5ffb8afe49 100644 --- a/go.sum +++ b/go.sum @@ -215,8 +215,8 @@ github.com/go-faker/faker/v4 v4.2.0/go.mod h1:F/bBy8GH9NxOxMInug5Gx4WYeG6fHJZ8Ol 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-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo= -github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= +github.com/go-jose/go-jose/v3 v3.0.1 h1:pWmKFVtt+Jl0vBZTIpz/eAKwsm6LkIxDVVbFHKkchhA= +github.com/go-jose/go-jose/v3 v3.0.1/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= From 38607056159a086b0d0dee7291acc4343fd0af6f Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Wed, 13 Dec 2023 10:55:43 +0000 Subject: [PATCH 212/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3503b9c1db9b..dfa157d5e0ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-12-12)](#2023-12-12) +- [ (2023-12-13)](#2023-12-13) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -314,7 +314,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-12-12) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-12-13) ## Breaking Changes From fa5ec93e8ae7d971d07f0e9b3acaa0840b9ac7de Mon Sep 17 00:00:00 2001 From: Henning Perl Date: Wed, 13 Dec 2023 15:16:27 +0100 Subject: [PATCH 213/282] fix: use provider label in link message (#3661) --- selfservice/strategy/oidc/strategy.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/selfservice/strategy/oidc/strategy.go b/selfservice/strategy/oidc/strategy.go index a2afff3ea425..e67a5826b57e 100644 --- a/selfservice/strategy/oidc/strategy.go +++ b/selfservice/strategy/oidc/strategy.go @@ -570,7 +570,7 @@ func (s *Strategy) forwardError(w http.ResponseWriter, r *http.Request, f flow.F } } -func (s *Strategy) handleError(w http.ResponseWriter, r *http.Request, f flow.Flow, provider string, traits []byte, err error) error { +func (s *Strategy) handleError(w http.ResponseWriter, r *http.Request, f flow.Flow, providerID string, traits []byte, err error) error { switch rf := f.(type) { case *login.Flow: return err @@ -590,7 +590,7 @@ func (s *Strategy) handleError(w http.ResponseWriter, r *http.Request, f flow.Fl rf.UI.Messages.Add(text.NewErrorValidationDuplicateCredentialsOnOIDCLink()) } - lf, err := s.registrationToLogin(w, r, rf, provider) + lf, err := s.registrationToLogin(w, r, rf, providerID) if err != nil { return err } @@ -613,7 +613,12 @@ func (s *Strategy) handleError(w http.ResponseWriter, r *http.Request, f flow.Fl } newLoginURL := s.d.Config().SelfServiceFlowLoginUI(r.Context()).String() - lf.UI.Messages.Add(text.NewInfoLoginLinkMessage(dc.DuplicateIdentifier, provider, newLoginURL)) + providerLabel := providerID + provider, _ := s.provider(r.Context(), r, providerID) + if provider != nil && provider.Config() != nil { + providerLabel = provider.Config().Label + } + lf.UI.Messages.Add(text.NewInfoLoginLinkMessage(dc.DuplicateIdentifier, providerLabel, newLoginURL)) err := s.d.LoginFlowPersister().UpdateLoginFlow(r.Context(), lf) if err != nil { @@ -629,7 +634,7 @@ func (s *Strategy) handleError(w http.ResponseWriter, r *http.Request, f flow.Fl // Adds the "Continue" button rf.UI.SetCSRF(s.d.GenerateCSRFToken(r)) - AddProvider(rf.UI, provider, text.NewInfoRegistrationContinue()) + AddProvider(rf.UI, providerID, text.NewInfoRegistrationContinue()) if traits != nil { ds, err := s.d.Config().DefaultIdentityTraitsSchemaURL(r.Context()) From 06c27f46100b89b70df04bf1d8d7b2b917a94e87 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Wed, 13 Dec 2023 15:01:17 +0000 Subject: [PATCH 214/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dfa157d5e0ed..c915a12a38b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -661,6 +661,9 @@ https://github.com/ory/kratos/pull/3480 - Use org ID from session if available in login flow ([#3545](https://github.com/ory/kratos/issues/3545)) ([1b3647c](https://github.com/ory/kratos/commit/1b3647c2acdad966f920c2b9e6e657c52aa50c6e)) +- Use provider label in link message + ([#3661](https://github.com/ory/kratos/issues/3661)) + ([fa5ec93](https://github.com/ory/kratos/commit/fa5ec93e8ae7d971d07f0e9b3acaa0840b9ac7de)) - Use registry client for schema loading ([#3471](https://github.com/ory/kratos/issues/3471)) ([3a57726](https://github.com/ory/kratos/commit/3a577269980213e4415fd5fa713882990e2e7640)) From df8ec2b9b77a53beb32e3f94a8fccb711896d8e7 Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Thu, 14 Dec 2023 09:43:47 +0100 Subject: [PATCH 215/282] fix: don't return nil if code is invalid (#3662) * fix: don't return nil if code is invalid * chore: add test --- .../strategy/code/strategy_recovery.go | 8 ++++-- .../strategy/code/strategy_recovery_test.go | 6 ++-- .../strategy/code/strategy_verification.go | 8 ++++-- .../code/strategy_verification_test.go | 28 +++++++++++++++++++ 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/selfservice/strategy/code/strategy_recovery.go b/selfservice/strategy/code/strategy_recovery.go index 8c5f2c86d980..2a917f0dcecd 100644 --- a/selfservice/strategy/code/strategy_recovery.go +++ b/selfservice/strategy/code/strategy_recovery.go @@ -254,8 +254,12 @@ func (s *Strategy) recoveryUseCode(w http.ResponseWriter, r *http.Request, body return s.retryRecoveryFlow(w, r, f.Type, RetryWithError(err)) } - // No error - return nil + if f.Type == flow.TypeBrowser && !x.IsJSONRequest(r) { + http.Redirect(w, r, f.AppendTo(s.deps.Config().SelfServiceFlowRecoveryUI(r.Context())).String(), http.StatusSeeOther) + } else { + s.deps.Writer().Write(w, r, f) + } + return errors.WithStack(flow.ErrCompletedByStrategy) } else if err != nil { return s.retryRecoveryFlow(w, r, f.Type, RetryWithError(err)) } diff --git a/selfservice/strategy/code/strategy_recovery_test.go b/selfservice/strategy/code/strategy_recovery_test.go index 91afe5c3e149..b481a37c8726 100644 --- a/selfservice/strategy/code/strategy_recovery_test.go +++ b/selfservice/strategy/code/strategy_recovery_test.go @@ -1597,7 +1597,7 @@ func TestRecovery_WithContinueWith(t *testing.T) { t.Run("type="+testCase.ClientType.String(), func(t *testing.T) { recoveryEmail := testhelpers.RandomEmail() createIdentityToRecover(t, reg, recoveryEmail) - conf.MustSet(ctx, config.ViperKeySelfServiceRecoveryRequestLifespan, time.Millisecond*10) + conf.MustSet(ctx, config.ViperKeySelfServiceRecoveryRequestLifespan, time.Millisecond*100) t.Cleanup(func() { conf.MustSet(ctx, config.ViperKeySelfServiceRecoveryRequestLifespan, time.Minute) }) @@ -1611,7 +1611,7 @@ func TestRecovery_WithContinueWith(t *testing.T) { fallthrough case RecoveryClientTypeSPA: rs = testhelpers.GetRecoveryFlow(t, c, public) - time.Sleep(time.Millisecond * 11) + time.Sleep(time.Millisecond * 110) res, err = c.PostForm(rs.Ui.Action, url.Values{"email": {recoveryEmail}, "method": {"code"}}) require.NoError(t, err) assert.EqualValues(t, http.StatusOK, res.StatusCode) @@ -1619,7 +1619,7 @@ func TestRecovery_WithContinueWith(t *testing.T) { assert.Contains(t, res.Request.URL.String(), conf.SelfServiceFlowRecoveryUI(ctx).String()) case RecoveryClientTypeAPI: rs = testhelpers.InitializeRecoveryFlowViaAPI(t, c, public) - time.Sleep(time.Millisecond * 11) + time.Sleep(time.Millisecond * 110) form := testhelpers.EncodeFormAsJSON(t, true, url.Values{"email": {recoveryEmail}, "method": {"code"}}) res, err = c.Post(rs.Ui.Action, "application/json", bytes.NewBufferString(form)) require.NoError(t, err) diff --git a/selfservice/strategy/code/strategy_verification.go b/selfservice/strategy/code/strategy_verification.go index 28e21456323e..e6969fda738d 100644 --- a/selfservice/strategy/code/strategy_verification.go +++ b/selfservice/strategy/code/strategy_verification.go @@ -236,8 +236,12 @@ func (s *Strategy) verificationUseCode(w http.ResponseWriter, r *http.Request, c return s.retryVerificationFlowWithError(w, r, f.Type, err) } - // No error - return nil + if x.IsBrowserRequest(r) { + http.Redirect(w, r, f.AppendTo(s.deps.Config().SelfServiceFlowVerificationUI(r.Context())).String(), http.StatusSeeOther) + } else { + s.deps.Writer().Write(w, r, f) + } + return errors.WithStack(flow.ErrCompletedByStrategy) } else if err != nil { return s.retryVerificationFlowWithError(w, r, f.Type, err) } diff --git a/selfservice/strategy/code/strategy_verification_test.go b/selfservice/strategy/code/strategy_verification_test.go index cdbfedc6069d..0f6a9fe15a10 100644 --- a/selfservice/strategy/code/strategy_verification_test.go +++ b/selfservice/strategy/code/strategy_verification_test.go @@ -16,6 +16,8 @@ import ( "testing" "time" + "github.com/gofrs/uuid" + "github.com/ory/x/urlx" "github.com/ory/kratos/selfservice/strategy/code" @@ -377,6 +379,11 @@ func TestVerification(t *testing.T) { f, err := verification.NewFlow(conf, time.Hour, x.FakeCSRFToken, httptest.NewRequest("GET", requestURL, nil), code.NewStrategy(reg), fType) require.NoError(t, err) f.State = flow.StateEmailSent + u, err := url.Parse(f.RequestURL) + require.NoError(t, err) + f.OAuth2LoginChallenge = sqlxx.NullString(u.Query().Get("login_challenge")) + f.IdentityID = uuid.NullUUID{UUID: x.NewUUID(), Valid: true} + f.SessionID = uuid.NullUUID{UUID: x.NewUUID(), Valid: true} require.NoError(t, reg.VerificationFlowPersister().CreateVerificationFlow(context.Background(), f)) email := identity.NewVerifiableEmailAddress(verificationEmail, identityToVerify.ID) identityToVerify.VerifiableAddresses = append(identityToVerify.VerifiableAddresses, *email) @@ -634,4 +641,25 @@ func TestVerification(t *testing.T) { }) } }) + + t.Run("case=doesn't continue with OAuth2 flow if code is invalid", func(t *testing.T) { + returnToURL := public.URL + "/after-verification" + conf.MustSet(ctx, config.ViperKeyURLsAllowedReturnToDomains, []string{returnToURL}) + + client := testhelpers.NewClientWithCookies(t) + flow, _, _ := newValidFlow(t, flow.TypeBrowser, public.URL+verification.RouteInitBrowserFlow+"?"+url.Values{"return_to": {returnToURL}, "login_challenge": {"any_valid_challenge"}}.Encode()) + + body := fmt.Sprintf( + `{"csrf_token":"%s","code":"%s"}`, flow.CSRFToken, "2475", + ) + + res, err := client.Post(public.URL+verification.RouteSubmitFlow+"?"+url.Values{"flow": {flow.ID.String()}}.Encode(), "application/json", bytes.NewBuffer([]byte(body))) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, res.StatusCode) + responseBody := gjson.ParseBytes(ioutilx.MustReadAll(res.Body)) + + assert.Equal(t, responseBody.Get("state").String(), "sent_email", "%v", responseBody) + assert.Len(t, responseBody.Get("ui.messages").Array(), 1, "%v", responseBody) + assert.Equal(t, "The verification code is invalid or has already been used. Please try again.", responseBody.Get("ui.messages.0.text").String(), "%v", responseBody) + }) } From 0c5ea9bf735a67ef35011ba41d7f98afc6f8e118 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Thu, 14 Dec 2023 09:27:24 +0000 Subject: [PATCH 216/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c915a12a38b1..1a461000c251 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-12-13)](#2023-12-13) +- [ (2023-12-14)](#2023-12-14) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -314,7 +314,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-12-13) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-12-14) ## Breaking Changes @@ -448,6 +448,14 @@ https://github.com/ory/kratos/pull/3480 - Don't return 500 on conflict for POST /admin/identities ([#3437](https://github.com/ory/kratos/issues/3437)) ([1429949](https://github.com/ory/kratos/commit/142994932e449d9948148804502c98ef73daafff)) +- Don't return nil if code is invalid + ([#3662](https://github.com/ory/kratos/issues/3662)) + ([df8ec2b](https://github.com/ory/kratos/commit/df8ec2b9b77a53beb32e3f94a8fccb711896d8e7)): + + - fix: don't return nil if code is invalid + + - chore: add test + - Error handling on identity import ([#3520](https://github.com/ory/kratos/issues/3520)) ([83bfb2d](https://github.com/ory/kratos/commit/83bfb2d2a9c69bf3a3442500b9484c1a69f8c794)): From ec42f2f605829bc46c451d5bc5d3ef1b1588da9c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Dec 2023 14:14:31 +0100 Subject: [PATCH 217/282] chore(deps): bump golang.org/x/crypto from 0.15.0 to 0.17.0 (#3666) Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.15.0 to 0.17.0. - [Commits](https://github.com/golang/crypto/compare/v0.15.0...v0.17.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index ede7ba2b45ae..bb032ea14c19 100644 --- a/go.mod +++ b/go.mod @@ -96,7 +96,7 @@ require ( go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 go.opentelemetry.io/otel v1.19.0 go.opentelemetry.io/otel/trace v1.19.0 - golang.org/x/crypto v0.15.0 + golang.org/x/crypto v0.17.0 golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa golang.org/x/net v0.18.0 golang.org/x/oauth2 v0.14.0 @@ -310,8 +310,8 @@ require ( go.opentelemetry.io/otel/metric v1.19.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect golang.org/x/mod v0.14.0 // indirect - golang.org/x/sys v0.14.0 // indirect - golang.org/x/term v0.14.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/term v0.15.0 // indirect golang.org/x/tools v0.15.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect google.golang.org/appengine v1.6.8 // indirect diff --git a/go.sum b/go.sum index 2b5ffb8afe49..11a27fd38908 100644 --- a/go.sum +++ b/go.sum @@ -1136,8 +1136,8 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= -golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= -golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1354,8 +1354,8 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20191110171634-ad39bd3f0407/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1367,8 +1367,8 @@ golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= -golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= +golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= 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= From d21e167999d60086e2a358f51fa651a5c8f43974 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Thu, 28 Dec 2023 14:11:20 +0000 Subject: [PATCH 218/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a461000c251..deb347222e88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-12-14)](#2023-12-14) +- [ (2023-12-28)](#2023-12-28) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -314,7 +314,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-12-14) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-12-28) ## Breaking Changes From ae8cbdc27ff17824de65927abfd9e32146ffc786 Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Thu, 28 Dec 2023 15:37:08 +0100 Subject: [PATCH 219/282] chore: update opentelemetry (#3672) --- driver/config/config.go | 5 ++- go.mod | 26 ++++++------- go.sum | 44 +++++++++++----------- selfservice/strategy/password/validator.go | 5 ++- 4 files changed, 40 insertions(+), 40 deletions(-) diff --git a/driver/config/config.go b/driver/config/config.go index a5ff6c7fb3b8..f1b839d9093d 100644 --- a/driver/config/config.go +++ b/driver/config/config.go @@ -18,6 +18,8 @@ import ( "testing" "time" + "go.opentelemetry.io/otel/trace/noop" + "github.com/ory/x/crdbx" "github.com/go-webauthn/webauthn/protocol" @@ -27,7 +29,6 @@ import ( "github.com/pkg/errors" "github.com/rs/cors" "github.com/stretchr/testify/require" - "go.opentelemetry.io/otel/trace" "golang.org/x/net/publicsuffix" "github.com/ory/herodot" @@ -426,7 +427,7 @@ func (p *Config) validateIdentitySchemas(ctx context.Context) error { // Tracing still works correctly even though we pass a no-op tracer // here, because the otelhttp package will preferentially use the // tracer from the incoming request context over this one. - httpx.ResilientClientWithTracer(trace.NewNoopTracerProvider().Tracer("github.com/ory/kratos/driver/config")), + httpx.ResilientClientWithTracer(noop.NewTracerProvider().Tracer("github.com/ory/kratos/driver/config")), } if o, ok := ctx.Value(validateIdentitySchemasClientKey).([]httpx.ResilientOptions); ok { diff --git a/go.mod b/go.mod index bb032ea14c19..7232373c704c 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ replace ( ) require ( + code.dny.dev/ssrf v0.2.0 // indirect github.com/Masterminds/sprig/v3 v3.2.3 github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 github.com/avast/retry-go/v3 v3.1.1 @@ -75,7 +76,7 @@ require ( github.com/ory/jsonschema/v3 v3.0.8 github.com/ory/mail/v3 v3.0.0 github.com/ory/nosurf v1.2.7 - github.com/ory/x v0.0.604 + github.com/ory/x v0.0.607 github.com/peterhellberg/link v1.2.0 github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 github.com/pkg/errors v0.9.1 @@ -93,9 +94,10 @@ require ( github.com/tidwall/sjson v1.2.5 github.com/urfave/negroni v1.0.0 github.com/zmb3/spotify/v2 v2.4.0 - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 - go.opentelemetry.io/otel v1.19.0 - go.opentelemetry.io/otel/trace v1.19.0 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 + go.opentelemetry.io/otel v1.21.0 + go.opentelemetry.io/otel/sdk v1.21.0 + go.opentelemetry.io/otel/trace v1.21.0 golang.org/x/crypto v0.17.0 golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa golang.org/x/net v0.18.0 @@ -106,10 +108,6 @@ require ( google.golang.org/grpc v1.59.0 ) -require go.opentelemetry.io/otel/sdk v1.19.0 - -require code.dny.dev/ssrf v0.2.0 // indirect - require ( github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Masterminds/goutils v1.1.1 // indirect @@ -299,15 +297,15 @@ require ( github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect go.mongodb.org/mongo-driver v1.11.3 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.45.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.46.1 // indirect go.opentelemetry.io/contrib/propagators/b3 v1.20.0 // indirect go.opentelemetry.io/contrib/propagators/jaeger v1.20.0 // indirect - go.opentelemetry.io/contrib/samplers/jaegerremote v0.14.0 // indirect + go.opentelemetry.io/contrib/samplers/jaegerremote v0.15.1 // indirect go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect; / indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 // indirect; / indirect - go.opentelemetry.io/otel/exporters/zipkin v1.19.0 // indirect; / indirect - go.opentelemetry.io/otel/metric v1.19.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect; / indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 // indirect; / indirect + go.opentelemetry.io/otel/exporters/zipkin v1.21.0 // indirect; / indirect + go.opentelemetry.io/otel/metric v1.21.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect golang.org/x/mod v0.14.0 // indirect golang.org/x/sys v0.15.0 // indirect diff --git a/go.sum b/go.sum index 11a27fd38908..bc1e37527262 100644 --- a/go.sum +++ b/go.sum @@ -840,8 +840,8 @@ github.com/ory/nosurf v1.2.7 h1:YrHrbSensQyU6r6HT/V5+HPdVEgrOTMJiLoJABSBOp4= github.com/ory/nosurf v1.2.7/go.mod h1:d4L3ZBa7Amv55bqxCBtCs63wSlyaiCkWVl4vKf3OUxA= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2 h1:zm6sDvHy/U9XrGpixwHiuAwpp0Ock6khSVHkrv6lQQU= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/ory/x v0.0.604 h1:I02tf+FIEcA98+tPyaspRQYxlX28uIGAB1g7JTh8GUk= -github.com/ory/x v0.0.604/go.mod h1:AFyMDGw6bh14PAGQITzlFuF/1OAvEXOX61PYbxJyeS8= +github.com/ory/x v0.0.607 h1:qNP1gU6RWVtsEB04rPht+1rV2DqQhvOAN2sF+4eqVWo= +github.com/ory/x v0.0.607/go.mod h1:fCYvVVHo8wYrCwLyU8+9hFY3IRo4EZM3KI30ysDsDYY= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -1069,32 +1069,32 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.45.0 h1:2ea0IkZBsWH+HA2GkD+7+hRw2u97jzdFyRtXuO14a1s= -go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.45.0/go.mod h1:4m3RnBBb+7dB9d21y510oO1pdB1V4J6smNf14WXcBFQ= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.46.1 h1:gbhw/u49SS3gkPWiYweQNJGm/uJN5GkI/FrosxSHT7A= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.46.1/go.mod h1:GnOaBaFQ2we3b9AGWJpsBa7v1S5RlQzlC3O7dRMxZhM= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= go.opentelemetry.io/contrib/propagators/b3 v1.20.0 h1:Yty9Vs4F3D6/liF1o6FNt0PvN85h/BJJ6DQKJ3nrcM0= go.opentelemetry.io/contrib/propagators/b3 v1.20.0/go.mod h1:On4VgbkqYL18kbJlWsa18+cMNe6rYpBnPi1ARI/BrsU= go.opentelemetry.io/contrib/propagators/jaeger v1.20.0 h1:iVhNKkMIpzyZqxk8jkDU2n4DFTD+FbpGacvooxEvyyc= go.opentelemetry.io/contrib/propagators/jaeger v1.20.0/go.mod h1:cpSABr0cm/AH/HhbJjn+AudBVUMgZWdfN3Gb+ZqxSZc= -go.opentelemetry.io/contrib/samplers/jaegerremote v0.14.0 h1:Xg9iU9DF9V9zC6NI8sJthYqHlSWsWAQMTXM8QIErKlc= -go.opentelemetry.io/contrib/samplers/jaegerremote v0.14.0/go.mod h1:ExRuq62/gYluX5fzTTZif5WujyG51ail4APTbBUu+S4= -go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= -go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= +go.opentelemetry.io/contrib/samplers/jaegerremote v0.15.1 h1:Qb+5A+JbIjXwO7l4HkRUhgIn4Bzz0GNS2q+qdmSx+0c= +go.opentelemetry.io/contrib/samplers/jaegerremote v0.15.1/go.mod h1:G4vNCm7fRk0kjZ6pGNLo5SpLxAUvOfSrcaegnT8TPck= +go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= +go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4= go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU= -go.opentelemetry.io/otel/exporters/zipkin v1.19.0 h1:EGY0h5mGliP9o/nIkVuLI0vRiQqmsYOcbwCuotksO1o= -go.opentelemetry.io/otel/exporters/zipkin v1.19.0/go.mod h1:JQgTGJP11yi3o4GHzIWYodhPisxANdqxF1eHwDSnJrI= -go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= -go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= -go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= -go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= -go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= -go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 h1:digkEZCJWobwBqMwC0cwCq8/wkkRy/OowZg5OArWZrM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0/go.mod h1:/OpE/y70qVkndM0TrxT4KBoN3RsFZP0QaofcfYrj76I= +go.opentelemetry.io/otel/exporters/zipkin v1.21.0 h1:D+Gv6lSfrFBWmQYyxKjDd0Zuld9SRXpIrEsKZvE4DO4= +go.opentelemetry.io/otel/exporters/zipkin v1.21.0/go.mod h1:83oMKR6DzmHisFOW3I+yIMGZUTjxiWaiBI8M8+TU5zE= +go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= +go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= +go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= +go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= +go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= +go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= diff --git a/selfservice/strategy/password/validator.go b/selfservice/strategy/password/validator.go index 0875dff6a868..be1aac3c3497 100644 --- a/selfservice/strategy/password/validator.go +++ b/selfservice/strategy/password/validator.go @@ -14,13 +14,14 @@ import ( "strings" "time" + "go.opentelemetry.io/otel/trace/noop" + "github.com/ory/kratos/text" "github.com/arbovm/levenshtein" "github.com/dgraph-io/ristretto" "github.com/hashicorp/go-retryablehttp" "github.com/pkg/errors" - "go.opentelemetry.io/otel/trace" "github.com/ory/herodot" "github.com/ory/kratos/driver/config" @@ -88,7 +89,7 @@ func NewDefaultPasswordValidatorStrategy(reg validatorDependencies) (*DefaultPas // Tracing still works correctly even though we pass a no-op tracer // here, because the otelhttp package will preferentially use the // tracer from the incoming request context over this one. - httpx.ResilientClientWithTracer(trace.NewNoopTracerProvider().Tracer("github.com/ory/kratos/selfservice/strategy/password"))), + httpx.ResilientClientWithTracer(noop.NewTracerProvider().Tracer("github.com/ory/kratos/selfservice/strategy/password"))), reg: reg, hashes: cache, minIdentifierPasswordDist: 5, maxIdentifierPasswordSubstrThreshold: 0.5}, nil From e3a3c4fe0d6697f6864283daf4be8a8f8971c7b4 Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Thu, 28 Dec 2023 16:35:57 +0100 Subject: [PATCH 220/282] feat: add sms verification for phone numbers (#3649) --- .../phone-password/identity.schema.json | 31 ++++ .../kratos/phone-password/kratos.yml | 113 ++++++++++++ courier/channel.go | 13 ++ courier/courier.go | 40 +++-- courier/courier_dispatcher.go | 20 +-- courier/courier_dispatcher_test.go | 28 +++ courier/email_templates_test.go | 93 ---------- courier/http.go | 88 --------- courier/http_channel.go | 124 +++++++++++++ courier/message.go | 21 ++- courier/message_test.go | 2 +- courier/sms.go | 84 +-------- courier/sms_templates.go | 24 +-- courier/sms_templates_test.go | 17 +- courier/sms_test.go | 43 ++--- courier/smtp.go | 145 ++------------- courier/smtp_channel.go | 144 +++++++++++++++ courier/smtp_test.go | 42 ++--- courier/stub/request.config.twilio.jsonnet | 6 +- .../verification_code/valid/sms.body.gotmpl | 1 + courier/template/email/login_code_valid.go | 4 + .../template/email/login_code_valid_test.go | 4 +- .../template/email/recovery_code_invalid.go | 4 + .../email/recovery_code_invalid_test.go | 4 +- courier/template/email/recovery_code_valid.go | 4 + .../email/recovery_code_valid_test.go | 4 +- courier/template/email/recovery_invalid.go | 4 + .../template/email/recovery_invalid_test.go | 4 +- courier/template/email/recovery_valid.go | 4 + courier/template/email/recovery_valid_test.go | 4 +- .../template/email/registration_code_valid.go | 4 + .../email/registration_code_valid_test.go | 4 +- courier/template/email/stub.go | 4 + .../email/verification_code_invalid.go | 4 + .../email/verification_code_invalid_test.go | 4 +- .../template/email/verification_code_valid.go | 4 + .../email/verification_code_valid_test.go | 4 +- .../template/email/verification_invalid.go | 4 + .../email/verification_invalid_test.go | 4 +- courier/template/email/verification_valid.go | 4 + .../template/email/verification_valid_test.go | 4 +- courier/template/sms/otp.go | 41 ----- courier/template/sms/stub.go | 4 + courier/template/sms/verification_code.go | 53 ++++++ ...{otp_test.go => verification_code_test.go} | 2 +- courier/template/template.go | 20 +-- courier/template/testhelpers/testhelpers.go | 27 ++- courier/template/type.go | 23 +++ courier/{email_templates.go => templates.go} | 78 ++------ courier/templates_test.go | 72 ++++++++ driver/config/config.go | 168 ++++++++++-------- driver/config/config_test.go | 78 ++++---- .../config/stub/.kratos.courier.channels.yaml | 14 ++ embedx/config.schema.json | 46 ++++- identity/extension_credentials.go | 6 +- ...on_verify.go => extension_verification.go} | 0 ...test.go => extension_verification_test.go} | 0 internal/client-go/model_message.go | 40 ++++- internal/httpclient/model_message.go | 40 ++++- ...628000000_courier_message_channel.down.sql | 2 + ...94628000000_courier_message_channel.up.sql | 4 + persistence/sql/persister.go | 6 +- selfservice/strategy/code/code_sender.go | 42 ++++- spec/api.json | 8 +- spec/swagger.json | 8 +- 65 files changed, 1160 insertions(+), 785 deletions(-) create mode 100644 contrib/quickstart/kratos/phone-password/identity.schema.json create mode 100644 contrib/quickstart/kratos/phone-password/kratos.yml create mode 100644 courier/channel.go delete mode 100644 courier/email_templates_test.go delete mode 100644 courier/http.go create mode 100644 courier/http_channel.go create mode 100644 courier/smtp_channel.go create mode 100644 courier/template/courier/builtin/templates/verification_code/valid/sms.body.gotmpl delete mode 100644 courier/template/sms/otp.go create mode 100644 courier/template/sms/verification_code.go rename courier/template/sms/{otp_test.go => verification_code_test.go} (86%) create mode 100644 courier/template/type.go rename courier/{email_templates.go => templates.go} (55%) create mode 100644 courier/templates_test.go create mode 100644 driver/config/stub/.kratos.courier.channels.yaml rename identity/{extension_verify.go => extension_verification.go} (100%) rename identity/{extension_verify_test.go => extension_verification_test.go} (100%) create mode 100644 persistence/sql/migrations/sql/20231130094628000000_courier_message_channel.down.sql create mode 100644 persistence/sql/migrations/sql/20231130094628000000_courier_message_channel.up.sql diff --git a/contrib/quickstart/kratos/phone-password/identity.schema.json b/contrib/quickstart/kratos/phone-password/identity.schema.json new file mode 100644 index 000000000000..3d1f190d5521 --- /dev/null +++ b/contrib/quickstart/kratos/phone-password/identity.schema.json @@ -0,0 +1,31 @@ +{ + "$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": { + "phone": { + "type": "string", + "format": "tel", + "title": "Phone number", + "minLength": 3, + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + }, + "verification": { + "via": "phone" + } + } + } + }, + "required": ["phone"], + "additionalProperties": false + } + } +} diff --git a/contrib/quickstart/kratos/phone-password/kratos.yml b/contrib/quickstart/kratos/phone-password/kratos.yml new file mode 100644 index 000000000000..927b61453070 --- /dev/null +++ b/contrib/quickstart/kratos/phone-password/kratos.yml @@ -0,0 +1,113 @@ +version: v0.13.0 + +dsn: memory + +serve: + public: + base_url: http://127.0.0.1:4433/ + cors: + enabled: true + admin: + base_url: http://kratos:4434/ + +selfservice: + default_browser_return_url: http://127.0.0.1:4455/ + allowed_return_urls: + - http://127.0.0.1:4455 + - http://localhost:19006/Callback + - exp://localhost:8081/--/Callback + + methods: + password: + enabled: true + totp: + config: + issuer: Kratos + enabled: true + lookup_secret: + enabled: true + link: + enabled: true + code: + enabled: true + + flows: + error: + ui_url: http://127.0.0.1:4455/error + + settings: + ui_url: http://127.0.0.1:4455/settings + privileged_session_max_age: 15m + required_aal: highest_available + + recovery: + enabled: true + ui_url: http://127.0.0.1:4455/recovery + use: code + + verification: + enabled: true + ui_url: http://127.0.0.1:4455/verification + use: code + after: + default_browser_return_url: http://127.0.0.1:4455/ + + logout: + after: + default_browser_return_url: http://127.0.0.1:4455/login + + login: + ui_url: http://127.0.0.1:4455/login + lifespan: 10m + + registration: + lifespan: 10m + ui_url: http://127.0.0.1:4455/registration + after: + password: + hooks: + - hook: session + - hook: show_verification_ui + +log: + level: debug + format: text + leak_sensitive_values: true + +secrets: + cookie: + - PLEASE-CHANGE-ME-I-AM-VERY-INSECURE + cipher: + - 32-LONG-SECRET-NOT-SECURE-AT-ALL + +ciphers: + algorithm: xchacha20-poly1305 + +hashers: + algorithm: bcrypt + bcrypt: + cost: 8 + +identity: + default_schema_id: default + schemas: + - id: default + url: file:///etc/config/kratos/identity.schema.json + +courier: + channels: + - id: phone + request_config: + url: https://api.twilio.com/2010-04-01/Accounts/AXXXXXXXXXXXXXX/Messages.json + method: POST + body: base64://ZnVuY3Rpb24oY3R4KSB7CkJvZHk6IGN0eC5ib2R5LApUbzogY3R4LnRvLEZyb206IGN0eC5mcm9tCn0= + headers: + Content-Type: application/x-www-form-urlencoded + auth: + type: basic_auth + config: + user: AXXXXXXX + password: XXXX + +feature_flags: + use_continue_with_transitions: true diff --git a/courier/channel.go b/courier/channel.go new file mode 100644 index 000000000000..12697a67de3b --- /dev/null +++ b/courier/channel.go @@ -0,0 +1,13 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package courier + +import ( + "context" +) + +type Channel interface { + ID() string + Dispatch(ctx context.Context, msg Message) error +} diff --git a/courier/courier.go b/courier/courier.go index b42a580fc061..231b4007060f 100644 --- a/courier/courier.go +++ b/courier/courier.go @@ -7,16 +7,15 @@ import ( "context" "time" - "github.com/ory/kratos/courier/template" "github.com/ory/x/jsonnetsecure" "github.com/cenkalti/backoff" "github.com/gofrs/uuid" "github.com/pkg/errors" + "github.com/ory/kratos/courier/template" "github.com/ory/kratos/driver/config" "github.com/ory/kratos/x" - gomail "github.com/ory/mail/v3" ) type ( @@ -33,11 +32,8 @@ type ( Work(ctx context.Context) error QueueEmail(ctx context.Context, t EmailTemplate) (uuid.UUID, error) QueueSMS(ctx context.Context, t SMSTemplate) (uuid.UUID, error) - SmtpDialer() *gomail.Dialer DispatchQueue(ctx context.Context) error DispatchMessage(ctx context.Context, msg Message) error - SetGetEmailTemplateType(f func(t EmailTemplate) (TemplateType, error)) - SetNewEmailTemplateFromMessage(f func(d template.Dependencies, msg Message) (EmailTemplate, error)) UseBackoff(b backoff.BackOff) FailOnDispatchError() } @@ -51,9 +47,7 @@ type ( } courier struct { - smsClient *smsClient - smtpClient *smtpClient - httpClient *httpClient + courierChannels map[string]Channel deps Dependencies failOnDispatchError bool backoff backoff.BackOff @@ -61,16 +55,34 @@ type ( ) func NewCourier(ctx context.Context, deps Dependencies) (Courier, error) { - smtp, err := newSMTP(ctx, deps) + return NewCourierWithCustomTemplates(ctx, deps, NewEmailTemplateFromMessage) +} + +func NewCourierWithCustomTemplates(ctx context.Context, deps Dependencies, newEmailTemplateFromMessage func(d template.Dependencies, msg Message) (EmailTemplate, error)) (Courier, error) { + cs, err := deps.CourierConfig().CourierChannels(ctx) if err != nil { return nil, err } + channels := make(map[string]Channel, len(cs)) + for _, c := range cs { + switch c.Type { + case "smtp": + ch, err := NewSMTPChannelWithCustomTemplates(deps, c.SMTPConfig, newEmailTemplateFromMessage) + if err != nil { + return nil, err + } + channels[ch.ID()] = ch + case "http": + channels[c.ID] = newHttpChannel(c.ID, c.RequestConfig, deps) + default: + return nil, errors.Errorf("unknown courier channel type: %s", c.Type) + } + } + return &courier{ - smsClient: newSMS(ctx, deps), - smtpClient: smtp, - httpClient: newHTTP(ctx, deps), - deps: deps, - backoff: backoff.NewExponentialBackOff(), + deps: deps, + backoff: backoff.NewExponentialBackOff(), + courierChannels: channels, }, nil } diff --git a/courier/courier_dispatcher.go b/courier/courier_dispatcher.go index 8470c024fca4..3d4835636206 100644 --- a/courier/courier_dispatcher.go +++ b/courier/courier_dispatcher.go @@ -19,17 +19,13 @@ func (c *courier) DispatchMessage(ctx context.Context, msg Message) error { return err } - switch msg.Type { - case MessageTypeEmail: - if err := c.dispatchEmail(ctx, msg); err != nil { - return err - } - case MessageTypePhone: - if err := c.dispatchSMS(ctx, msg); err != nil { - return err - } - default: - return errors.Errorf("received unexpected message type: %d", msg.Type) + channel, ok := c.courierChannels[msg.Channel.String()] + if !ok { + return errors.Errorf("message %s has unknown channel %q", msg.ID.String(), msg.Channel) + } + + if err := channel.Dispatch(ctx, msg); err != nil { + return err } if err := c.deps.CourierPersister().SetMessageStatus(ctx, msg.ID, MessageStatusSent); err != nil { @@ -37,6 +33,7 @@ func (c *courier) DispatchMessage(ctx context.Context, msg Message) error { WithError(err). WithField("message_id", msg.ID). WithField("message_nid", msg.NID). + WithField("channel", channel.ID()). Error(`Unable to set the message status to "sent".`) return err } @@ -47,6 +44,7 @@ func (c *courier) DispatchMessage(ctx context.Context, msg Message) error { WithField("message_type", msg.Type). WithField("message_template_type", msg.TemplateType). WithField("message_subject", msg.Subject). + WithField("channel", channel.ID()). Debug("Courier sent out message.") return nil diff --git a/courier/courier_dispatcher_test.go b/courier/courier_dispatcher_test.go index 528badf2de02..1f8c94ddf3e2 100644 --- a/courier/courier_dispatcher_test.go +++ b/courier/courier_dispatcher_test.go @@ -16,6 +16,7 @@ import ( templates "github.com/ory/kratos/courier/template/email" "github.com/ory/kratos/driver/config" "github.com/ory/kratos/internal" + "github.com/ory/kratos/internal/testhelpers" ) func queueNewMessage(t *testing.T, ctx context.Context, c courier.Courier, d template.Dependencies) uuid.UUID { @@ -58,6 +59,33 @@ func TestDispatchMessageWithInvalidSMTP(t *testing.T) { }) } +func TestDispatchMessage(t *testing.T) { + ctx := context.Background() + + conf, reg := internal.NewRegistryDefaultWithDSN(t, "") + conf.MustSet(ctx, config.ViperKeyCourierMessageRetries, 5) + conf.MustSet(ctx, config.ViperKeyCourierSMTPURL, "http://foo.url") + + ctx, cancel := context.WithCancel(ctx) + t.Cleanup(cancel) + + c, err := reg.Courier(ctx) + require.NoError(t, err) + t.Run("case=invalid channel", func(t *testing.T) { + message := courier.Message{ + Channel: "invalid-channel", + Status: courier.MessageStatusQueued, + Type: courier.MessageTypeEmail, + Recipient: testhelpers.RandomEmail(), + Subject: "test-subject-1", + Body: "test-body-1", + TemplateType: "stub", + } + require.NoError(t, reg.CourierPersister().AddMessage(ctx, &message)) + require.Error(t, c.DispatchMessage(ctx, message)) + }) +} + func TestDispatchQueue(t *testing.T) { ctx := context.Background() diff --git a/courier/email_templates_test.go b/courier/email_templates_test.go deleted file mode 100644 index 40afb5dc6863..000000000000 --- a/courier/email_templates_test.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright © 2023 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -package courier_test - -import ( - "context" - "encoding/json" - "fmt" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/ory/kratos/courier" - "github.com/ory/kratos/courier/template/email" - "github.com/ory/kratos/internal" -) - -func TestGetTemplateType(t *testing.T) { - for expectedType, tmpl := range map[courier.TemplateType]courier.EmailTemplate{ - courier.TypeRecoveryInvalid: &email.RecoveryInvalid{}, - courier.TypeRecoveryValid: &email.RecoveryValid{}, - courier.TypeRecoveryCodeInvalid: &email.RecoveryCodeInvalid{}, - courier.TypeRecoveryCodeValid: &email.RecoveryCodeValid{}, - courier.TypeVerificationInvalid: &email.VerificationInvalid{}, - courier.TypeVerificationValid: &email.VerificationValid{}, - courier.TypeVerificationCodeInvalid: &email.VerificationCodeInvalid{}, - courier.TypeVerificationCodeValid: &email.VerificationCodeValid{}, - courier.TypeTestStub: &email.TestStub{}, - courier.TypeLoginCodeValid: &email.LoginCodeValid{}, - courier.TypeRegistrationCodeValid: &email.RegistrationCodeValid{}, - } { - t.Run(fmt.Sprintf("case=%s", expectedType), func(t *testing.T) { - actualType, err := courier.GetEmailTemplateType(tmpl) - require.NoError(t, err) - require.Equal(t, expectedType, actualType) - }) - } -} - -func TestNewEmailTemplateFromMessage(t *testing.T) { - _, reg := internal.NewFastRegistryWithMocks(t) - ctx := context.Background() - - for tmplType, expectedTmpl := range map[courier.TemplateType]courier.EmailTemplate{ - courier.TypeRecoveryInvalid: email.NewRecoveryInvalid(reg, &email.RecoveryInvalidModel{To: "foo"}), - courier.TypeRecoveryValid: email.NewRecoveryValid(reg, &email.RecoveryValidModel{To: "bar", RecoveryURL: "http://foo.bar"}), - courier.TypeRecoveryCodeValid: email.NewRecoveryCodeValid(reg, &email.RecoveryCodeValidModel{To: "bar", RecoveryCode: "12345678"}), - courier.TypeRecoveryCodeInvalid: email.NewRecoveryCodeInvalid(reg, &email.RecoveryCodeInvalidModel{To: "bar"}), - courier.TypeVerificationInvalid: email.NewVerificationInvalid(reg, &email.VerificationInvalidModel{To: "baz"}), - courier.TypeVerificationValid: email.NewVerificationValid(reg, &email.VerificationValidModel{To: "faz", VerificationURL: "http://bar.foo"}), - courier.TypeVerificationCodeInvalid: email.NewVerificationCodeInvalid(reg, &email.VerificationCodeInvalidModel{To: "baz"}), - courier.TypeVerificationCodeValid: email.NewVerificationCodeValid(reg, &email.VerificationCodeValidModel{To: "faz", VerificationURL: "http://bar.foo", VerificationCode: "123456678"}), - courier.TypeTestStub: email.NewTestStub(reg, &email.TestStubModel{To: "far", Subject: "test subject", Body: "test body"}), - courier.TypeLoginCodeValid: email.NewLoginCodeValid(reg, &email.LoginCodeValidModel{To: "far", LoginCode: "123456"}), - courier.TypeRegistrationCodeValid: email.NewRegistrationCodeValid(reg, &email.RegistrationCodeValidModel{To: "far", RegistrationCode: "123456"}), - } { - t.Run(fmt.Sprintf("case=%s", tmplType), func(t *testing.T) { - tmplData, err := json.Marshal(expectedTmpl) - require.NoError(t, err) - - m := courier.Message{TemplateType: tmplType, TemplateData: tmplData} - actualTmpl, err := courier.NewEmailTemplateFromMessage(reg, m) - require.NoError(t, err) - - require.IsType(t, expectedTmpl, actualTmpl) - - expectedRecipient, err := expectedTmpl.EmailRecipient() - require.NoError(t, err) - actualRecipient, err := actualTmpl.EmailRecipient() - require.NoError(t, err) - require.Equal(t, expectedRecipient, actualRecipient) - - expectedSubject, err := expectedTmpl.EmailSubject(ctx) - require.NoError(t, err) - actualSubject, err := actualTmpl.EmailSubject(ctx) - require.NoError(t, err) - require.Equal(t, expectedSubject, actualSubject) - - expectedBody, err := expectedTmpl.EmailBody(ctx) - require.NoError(t, err) - actualBody, err := actualTmpl.EmailBody(ctx) - require.NoError(t, err) - require.Equal(t, expectedBody, actualBody) - - expectedBodyPlaintext, err := expectedTmpl.EmailBodyPlaintext(ctx) - require.NoError(t, err) - actualBodyPlaintext, err := actualTmpl.EmailBodyPlaintext(ctx) - require.NoError(t, err) - require.Equal(t, expectedBodyPlaintext, actualBodyPlaintext) - }) - } -} diff --git a/courier/http.go b/courier/http.go deleted file mode 100644 index 6542d26964af..000000000000 --- a/courier/http.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright © 2023 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -package courier - -import ( - "context" - "encoding/json" - "fmt" - - "github.com/ory/kratos/request" - "github.com/ory/x/otelx" -) - -type httpDataModel struct { - Recipient string - Subject string - Body string - TemplateType TemplateType - TemplateData EmailTemplate -} - -type httpClient struct { - RequestConfig json.RawMessage -} - -func newHTTP(ctx context.Context, deps Dependencies) *httpClient { - return &httpClient{ - RequestConfig: deps.CourierConfig().CourierEmailRequestConfig(ctx), - } -} -func (c *courier) dispatchMailerEmail(ctx context.Context, msg Message) (err error) { - ctx, span := c.deps.Tracer(ctx).Tracer().Start(ctx, "courier.http.dispatchMailerEmail") - defer otelx.End(span, &err) - - builder, err := request.NewBuilder(ctx, c.httpClient.RequestConfig, c.deps) - if err != nil { - return err - } - - tmpl, err := c.smtpClient.NewTemplateFromMessage(c.deps, msg) - if err != nil { - return err - } - - td := httpDataModel{ - Recipient: msg.Recipient, - Subject: msg.Subject, - Body: msg.Body, - TemplateType: msg.TemplateType, - TemplateData: tmpl, - } - - req, err := builder.BuildRequest(ctx, td) - if err != nil { - return err - } - - res, err := c.deps.HTTPClient(ctx).Do(req) - if err != nil { - return err - } - - defer res.Body.Close() - - if res.StatusCode >= 200 && res.StatusCode < 300 { - c.deps.Logger(). - WithField("message_id", msg.ID). - WithField("message_type", msg.Type). - WithField("message_template_type", msg.TemplateType). - WithField("message_subject", msg.Subject). - Debug("Courier sent out mailer.") - return nil - } - - err = fmt.Errorf( - "unable to dispatch mail delivery because upstream server replied with status code %d", - res.StatusCode, - ) - c.deps.Logger(). - WithField("message_id", msg.ID). - WithField("message_type", msg.Type). - WithField("message_template_type", msg.TemplateType). - WithField("message_subject", msg.Subject). - WithError(err). - Error("sending mail via HTTP failed.") - return err -} diff --git a/courier/http_channel.go b/courier/http_channel.go new file mode 100644 index 000000000000..67b917dd8841 --- /dev/null +++ b/courier/http_channel.go @@ -0,0 +1,124 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package courier + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/pkg/errors" + + "github.com/ory/kratos/courier/template" + "github.com/ory/kratos/request" + "github.com/ory/kratos/x" + "github.com/ory/x/jsonnetsecure" + "github.com/ory/x/otelx" +) + +type ( + httpChannel struct { + id string + requestConfig json.RawMessage + d channelDependencies + } + channelDependencies interface { + x.TracingProvider + x.LoggingProvider + x.HTTPClientProvider + jsonnetsecure.VMProvider + ConfigProvider + } +) + +var _ Channel = new(httpChannel) + +func newHttpChannel(id string, requestConfig json.RawMessage, d channelDependencies) *httpChannel { + return &httpChannel{ + id: id, + requestConfig: requestConfig, + d: d, + } +} + +func (c *httpChannel) ID() string { + return c.id +} + +type httpDataModel struct { + Recipient string + Subject string + Body string + TemplateType template.TemplateType + TemplateData Template + MessageType string +} + +func (c *httpChannel) Dispatch(ctx context.Context, msg Message) (err error) { + ctx, span := c.d.Tracer(ctx).Tracer().Start(ctx, "courier.httpChannel.Dispatch") + defer otelx.End(span, &err) + + builder, err := request.NewBuilder(ctx, c.requestConfig, c.d) + if err != nil { + return err + } + + tmpl, err := newTemplate(c.d, msg) + if err != nil { + return err + } + + td := httpDataModel{ + Recipient: msg.Recipient, + Subject: msg.Subject, + Body: msg.Body, + TemplateType: msg.TemplateType, + TemplateData: tmpl, + MessageType: msg.Type.String(), + } + + req, err := builder.BuildRequest(ctx, td) + if err != nil { + return err + } + + res, err := c.d.HTTPClient(ctx).Do(req) + if err != nil { + return err + } + + if res.StatusCode >= 200 && res.StatusCode < 300 { + c.d.Logger(). + WithField("message_id", msg.ID). + WithField("message_type", msg.Type). + WithField("message_template_type", msg.TemplateType). + WithField("message_subject", msg.Subject). + Debug("Courier sent out mailer.") + return nil + } + + err = errors.Errorf( + "unable to dispatch mail delivery because upstream server replied with status code %d", + res.StatusCode, + ) + c.d.Logger(). + WithField("message_id", msg.ID). + WithField("message_type", msg.Type). + WithField("message_template_type", msg.TemplateType). + WithField("message_subject", msg.Subject). + WithError(err). + Error("sending mail via HTTP failed.") + return err +} + +func newTemplate(d template.Dependencies, msg Message) (Template, error) { + switch msg.Type { + case MessageTypeEmail: + return NewEmailTemplateFromMessage(d, msg) + case MessageTypeSMS: + return NewSMSTemplateFromMessage(d, msg) + default: + return nil, fmt.Errorf("received unexpected message type: %s", msg.Type) + } +} diff --git a/courier/message.go b/courier/message.go index 9ba9cf9cdb6c..ef39514aee93 100644 --- a/courier/message.go +++ b/courier/message.go @@ -12,7 +12,9 @@ import ( "github.com/pkg/errors" "github.com/ory/herodot" + "github.com/ory/kratos/courier/template" "github.com/ory/x/pagination/keysetpagination" + "github.com/ory/x/sqlxx" "github.com/ory/x/stringsx" ) @@ -88,7 +90,6 @@ func (ms *MessageStatus) UnmarshalJSON(data []byte) error { } s, err := ToMessageStatus(str) - if err != nil { return err } @@ -106,12 +107,12 @@ type MessageType int const ( MessageTypeEmail MessageType = iota + 1 - MessageTypePhone + MessageTypeSMS ) const ( messageTypeEmailText = "email" - messageTypePhoneText = "phone" + messageTypeSMSText = "sms" ) // The format we need to use in the Page tokens, as it's the only format that is understood by all DBs @@ -121,8 +122,8 @@ func ToMessageType(str string) (MessageType, error) { switch s := stringsx.SwitchExact(str); { case s.AddCase(messageTypeEmailText): return MessageTypeEmail, nil - case s.AddCase(messageTypePhoneText): - return MessageTypePhone, nil + case s.AddCase(messageTypeSMSText): + return MessageTypeSMS, nil default: return 0, errors.WithStack(herodot.ErrBadRequest.WithWrap(s.ToUnknownCaseErr()).WithReason("Message type is not valid")) } @@ -132,8 +133,8 @@ func (mt MessageType) String() string { switch mt { case MessageTypeEmail: return messageTypeEmailText - case MessageTypePhone: - return messageTypePhoneText + case MessageTypeSMS: + return messageTypeSMSText default: return "" } @@ -141,7 +142,7 @@ func (mt MessageType) String() string { func (mt MessageType) IsValid() error { switch mt { - case MessageTypeEmail, MessageTypePhone: + case MessageTypeEmail, MessageTypeSMS: return nil default: return errors.WithStack(herodot.ErrBadRequest.WithReason("Message type is not valid")) @@ -187,7 +188,9 @@ type Message struct { // required: true Subject string `json:"subject" db:"subject"` // required: true - TemplateType TemplateType `json:"template_type" db:"template_type"` + TemplateType template.TemplateType `json:"template_type" db:"template_type"` + + Channel sqlxx.NullString `json:"channel" db:"channel"` TemplateData []byte `json:"-" db:"template_data"` // required: true diff --git a/courier/message_test.go b/courier/message_test.go index e8db6713bcf5..c359f19e67a8 100644 --- a/courier/message_test.go +++ b/courier/message_test.go @@ -46,7 +46,7 @@ func TestToMessageType(t *testing.T) { t.Run("case=should return corresponding MessageType for given str", func(t *testing.T) { for str, exp := range map[string]courier.MessageType{ "email": courier.MessageTypeEmail, - "phone": courier.MessageTypePhone, + "sms": courier.MessageTypeSMS, } { result, err := courier.ToMessageType(str) require.NoError(t, err) diff --git a/courier/sms.go b/courier/sms.go index e6b7a1925a9b..122f8a5f1ed1 100644 --- a/courier/sms.go +++ b/courier/sms.go @@ -6,60 +6,34 @@ package courier import ( "context" "encoding/json" - "net/http" - - "github.com/pkg/errors" - - "github.com/ory/herodot" "github.com/gofrs/uuid" - - "github.com/ory/kratos/request" ) -type sendSMSRequestBody struct { - From string `json:"from"` - To string `json:"to"` - Body string `json:"body"` -} - -type smsClient struct { - RequestConfig json.RawMessage - - GetTemplateType func(t SMSTemplate) (TemplateType, error) - NewTemplateFromMessage func(d Dependencies, msg Message) (SMSTemplate, error) -} - -func newSMS(ctx context.Context, deps Dependencies) *smsClient { - return &smsClient{ - RequestConfig: deps.CourierConfig().CourierSMSRequestConfig(ctx), - GetTemplateType: SMSTemplateType, - NewTemplateFromMessage: NewSMSTemplateFromMessage, - } -} - func (c *courier) QueueSMS(ctx context.Context, t SMSTemplate) (uuid.UUID, error) { recipient, err := t.PhoneNumber() if err != nil { return uuid.Nil, err } - templateType, err := c.smsClient.GetTemplateType(t) + templateData, err := json.Marshal(t) if err != nil { return uuid.Nil, err } - templateData, err := json.Marshal(t) + body, err := t.SMSBody(ctx) if err != nil { return uuid.Nil, err } message := &Message{ Status: MessageStatusQueued, - Type: MessageTypePhone, + Type: MessageTypeSMS, + Channel: "sms", Recipient: recipient, - TemplateType: templateType, + TemplateType: t.TemplateType(), TemplateData: templateData, + Body: body, } if err := c.deps.CourierPersister().AddMessage(ctx, message); err != nil { return uuid.Nil, err @@ -67,49 +41,3 @@ func (c *courier) QueueSMS(ctx context.Context, t SMSTemplate) (uuid.UUID, error return message.ID, nil } - -func (c *courier) dispatchSMS(ctx context.Context, msg Message) error { - if !c.deps.CourierConfig().CourierSMSEnabled(ctx) { - return errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Courier tried to deliver an sms but courier.sms.enabled is set to false!")) - } - - tmpl, err := c.smsClient.NewTemplateFromMessage(c.deps, msg) - if err != nil { - return err - } - - body, err := tmpl.SMSBody(ctx) - if err != nil { - return err - } - - builder, err := request.NewBuilder(ctx, c.smsClient.RequestConfig, c.deps) - if err != nil { - return err - } - - req, err := builder.BuildRequest(ctx, &sendSMSRequestBody{ - To: msg.Recipient, - From: c.deps.CourierConfig().CourierSMSFrom(ctx), - Body: body, - }) - if err != nil { - return err - } - - res, err := c.deps.HTTPClient(ctx).Do(req) - if err != nil { - return err - } - - defer res.Body.Close() - - switch res.StatusCode { - case http.StatusOK: - case http.StatusCreated: - default: - return errors.New(http.StatusText(res.StatusCode)) - } - - return nil -} diff --git a/courier/sms_templates.go b/courier/sms_templates.go index 0b1c58e3a635..683ba7d98ca3 100644 --- a/courier/sms_templates.go +++ b/courier/sms_templates.go @@ -9,6 +9,7 @@ import ( "github.com/pkg/errors" + "github.com/ory/kratos/courier/template" "github.com/ory/kratos/courier/template/sms" ) @@ -16,33 +17,24 @@ type SMSTemplate interface { json.Marshaler SMSBody(context.Context) (string, error) PhoneNumber() (string, error) + TemplateType() template.TemplateType } -func SMSTemplateType(t SMSTemplate) (TemplateType, error) { - switch t.(type) { - case *sms.OTPMessage: - return TypeOTP, nil - case *sms.TestStub: - return TypeTestStub, nil - default: - return "", errors.Errorf("unexpected template type") - } -} - -func NewSMSTemplateFromMessage(d Dependencies, m Message) (SMSTemplate, error) { +func NewSMSTemplateFromMessage(d template.Dependencies, m Message) (SMSTemplate, error) { switch m.TemplateType { - case TypeOTP: - var t sms.OTPMessageModel + case template.TypeVerificationCodeValid: + var t sms.VerificationCodeValidModel if err := json.Unmarshal(m.TemplateData, &t); err != nil { return nil, err } - return sms.NewOTPMessage(d, &t), nil - case TypeTestStub: + return sms.NewVerificationCodeValid(d, &t), nil + case template.TypeTestStub: var t sms.TestStubModel if err := json.Unmarshal(m.TemplateData, &t); err != nil { return nil, err } return sms.NewTestStub(d, &t), nil + default: return nil, errors.Errorf("received unexpected message template type: %s", m.TemplateType) } diff --git a/courier/sms_templates_test.go b/courier/sms_templates_test.go index 8d87e11f8956..2577b38eaad9 100644 --- a/courier/sms_templates_test.go +++ b/courier/sms_templates_test.go @@ -12,19 +12,18 @@ import ( "github.com/stretchr/testify/require" "github.com/ory/kratos/courier" + "github.com/ory/kratos/courier/template" "github.com/ory/kratos/courier/template/sms" "github.com/ory/kratos/internal" ) func TestSMSTemplateType(t *testing.T) { - for expectedType, tmpl := range map[courier.TemplateType]courier.SMSTemplate{ - courier.TypeOTP: &sms.OTPMessage{}, - courier.TypeTestStub: &sms.TestStub{}, + for expectedType, tmpl := range map[template.TemplateType]courier.SMSTemplate{ + template.TypeVerificationCodeValid: &sms.VerificationCodeValid{}, + template.TypeTestStub: &sms.TestStub{}, } { t.Run(fmt.Sprintf("case=%s", expectedType), func(t *testing.T) { - actualType, err := courier.SMSTemplateType(tmpl) - require.NoError(t, err) - require.Equal(t, expectedType, actualType) + require.Equal(t, expectedType, tmpl.TemplateType()) }) } } @@ -33,9 +32,9 @@ func TestNewSMSTemplateFromMessage(t *testing.T) { _, reg := internal.NewFastRegistryWithMocks(t) ctx := context.Background() - for tmplType, expectedTmpl := range map[courier.TemplateType]courier.SMSTemplate{ - courier.TypeOTP: sms.NewOTPMessage(reg, &sms.OTPMessageModel{To: "+12345678901"}), - courier.TypeTestStub: sms.NewTestStub(reg, &sms.TestStubModel{To: "+12345678901", Body: "test body"}), + for tmplType, expectedTmpl := range map[template.TemplateType]courier.SMSTemplate{ + template.TypeVerificationCodeValid: sms.NewVerificationCodeValid(reg, &sms.VerificationCodeValidModel{To: "+12345678901"}), + template.TypeTestStub: sms.NewTestStub(reg, &sms.TestStubModel{To: "+12345678901", Body: "test body"}), } { t.Run(fmt.Sprintf("case=%s", tmplType), func(t *testing.T) { tmplData, err := json.Marshal(expectedTmpl) diff --git a/courier/sms_test.go b/courier/sms_test.go index 5a919788fe04..a93a7974bf71 100644 --- a/courier/sms_test.go +++ b/courier/sms_test.go @@ -14,7 +14,6 @@ import ( "time" "github.com/gofrs/uuid" - "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -22,7 +21,6 @@ import ( "github.com/ory/kratos/courier/template/sms" "github.com/ory/kratos/driver/config" "github.com/ory/kratos/internal" - "github.com/ory/x/resilience" ) func TestQueueSMS(t *testing.T) { @@ -80,9 +78,13 @@ func TestQueueSMS(t *testing.T) { }`, srv.URL) conf, reg := internal.NewFastRegistryWithMocks(t) - conf.MustSet(ctx, config.ViperKeyCourierSMSRequestConfig, requestConfig) - conf.MustSet(ctx, config.ViperKeyCourierSMSFrom, expectedSender) - conf.MustSet(ctx, config.ViperKeyCourierSMSEnabled, true) + conf.MustSet(ctx, config.ViperKeyCourierChannels, fmt.Sprintf(`[ + { + "id": "sms", + "type": "http", + "request_config": %s + } + ]`, requestConfig)) conf.MustSet(ctx, config.ViperKeyCourierSMTPURL, "http://foo.url") reg.Logger().Level = logrus.TraceLevel @@ -98,16 +100,11 @@ func TestQueueSMS(t *testing.T) { require.NotEqual(t, uuid.Nil, id) } - go func() { - require.NoError(t, c.Work(ctx)) - }() + require.NoError(t, c.DispatchQueue(ctx)) - require.NoError(t, resilience.Retry(reg.Logger(), time.Millisecond*250, time.Second*10, func() error { - if len(actual) == len(expectedSMS) { - return nil - } - return errors.New("capacity not reached") - })) + require.Eventually(t, func() bool { + return len(actual) == len(expectedSMS) + }, 10*time.Second, 250*time.Millisecond) for i, message := range actual { expected := expectedSMS[i] @@ -123,15 +120,19 @@ func TestDisallowedInternalNetwork(t *testing.T) { ctx := context.Background() conf, reg := internal.NewFastRegistryWithMocks(t) - conf.MustSet(ctx, config.ViperKeyCourierSMSRequestConfig, `{ - "url": "http://127.0.0.1/", - "method": "GET", - "body": "file://./stub/request.config.twilio.jsonnet" - }`) - conf.MustSet(ctx, config.ViperKeyCourierSMSEnabled, true) + conf.MustSet(ctx, config.ViperKeyCourierChannels, `[ + { + "id": "sms", + "type": "http", + "request_config": { + "url": "http://127.0.0.1/", + "method": "GET", + "body": "file://./stub/request.config.twilio.jsonnet" + } + } + ]`) conf.MustSet(ctx, config.ViperKeyCourierSMTPURL, "http://foo.url") conf.MustSet(ctx, config.ViperKeyClientHTTPNoPrivateIPRanges, true) - reg.Logger().Level = logrus.TraceLevel c, err := reg.Courier(ctx) require.NoError(t, err) diff --git a/courier/smtp.go b/courier/smtp.go index c7255da045c7..8c7ef91fbe33 100644 --- a/courier/smtp.go +++ b/courier/smtp.go @@ -7,42 +7,33 @@ import ( "context" "crypto/tls" "encoding/json" - "fmt" "net/mail" - "net/textproto" + "net/url" "strconv" "time" - "github.com/ory/kratos/courier/template" - + "github.com/ory/herodot" "github.com/ory/kratos/driver/config" "github.com/gofrs/uuid" - "github.com/pkg/errors" - "github.com/ory/herodot" gomail "github.com/ory/mail/v3" ) -type smtpClient struct { +type SMTPClient struct { *gomail.Dialer - - GetTemplateType func(t EmailTemplate) (TemplateType, error) - NewTemplateFromMessage func(d template.Dependencies, msg Message) (EmailTemplate, error) } -func newSMTP(ctx context.Context, deps Dependencies) (*smtpClient, error) { - uri, err := deps.CourierConfig().CourierSMTPURL(ctx) +func NewSMTPClient(deps Dependencies, cfg *config.SMTPConfig) (*SMTPClient, error) { + uri, err := url.Parse(cfg.ConnectionURI) if err != nil { - return nil, err + return nil, herodot.ErrInternalServerError.WithError(err.Error()) } var tlsCertificates []tls.Certificate - clientCertPath := deps.CourierConfig().CourierSMTPClientCertPath(ctx) - clientKeyPath := deps.CourierConfig().CourierSMTPClientKeyPath(ctx) - if clientCertPath != "" && clientKeyPath != "" { - clientCert, err := tls.LoadX509KeyPair(clientCertPath, clientKeyPath) + if cfg.ClientCertPath != "" && cfg.ClientKeyPath != "" { + clientCert, err := tls.LoadX509KeyPair(cfg.ClientCertPath, cfg.ClientKeyPath) if err == nil { tlsCertificates = append(tlsCertificates, clientCert) } else { @@ -52,7 +43,6 @@ func newSMTP(ctx context.Context, deps Dependencies) (*smtpClient, error) { } } - localName := deps.CourierConfig().CourierSMTPLocalName(ctx) password, _ := uri.User.Password() port, _ := strconv.ParseInt(uri.Port(), 10, 0) @@ -61,7 +51,7 @@ func newSMTP(ctx context.Context, deps Dependencies) (*smtpClient, error) { Port: int(port), Username: uri.User.Username(), Password: password, - LocalName: localName, + LocalName: cfg.LocalName, Timeout: time.Second * 10, RetryFailure: true, @@ -94,26 +84,11 @@ func newSMTP(ctx context.Context, deps Dependencies) (*smtpClient, error) { dialer.SSL = true } - return &smtpClient{ + return &SMTPClient{ Dialer: dialer, - - GetTemplateType: GetEmailTemplateType, - NewTemplateFromMessage: NewEmailTemplateFromMessage, }, nil } -func (c *courier) SetGetEmailTemplateType(f func(t EmailTemplate) (TemplateType, error)) { - c.smtpClient.GetTemplateType = f -} - -func (c *courier) SetNewEmailTemplateFromMessage(f func(d template.Dependencies, msg Message) (EmailTemplate, error)) { - c.smtpClient.NewTemplateFromMessage = f -} - -func (c *courier) SmtpDialer() *gomail.Dialer { - return c.smtpClient.Dialer -} - func (c *courier) QueueEmail(ctx context.Context, t EmailTemplate) (uuid.UUID, error) { recipient, err := t.EmailRecipient() if err != nil { @@ -133,11 +108,6 @@ func (c *courier) QueueEmail(ctx context.Context, t EmailTemplate) (uuid.UUID, e return uuid.Nil, err } - templateType, err := c.smtpClient.GetTemplateType(t) - if err != nil { - return uuid.Nil, err - } - templateData, err := json.Marshal(t) if err != nil { return uuid.Nil, err @@ -146,10 +116,11 @@ func (c *courier) QueueEmail(ctx context.Context, t EmailTemplate) (uuid.UUID, e message := &Message{ Status: MessageStatusQueued, Type: MessageTypeEmail, + Channel: "email", Recipient: recipient, Body: bodyPlaintext, Subject: subject, - TemplateType: templateType, + TemplateType: t.TemplateType(), TemplateData: templateData, } @@ -159,95 +130,3 @@ func (c *courier) QueueEmail(ctx context.Context, t EmailTemplate) (uuid.UUID, e return message.ID, nil } - -func (c *courier) dispatchEmail(ctx context.Context, msg Message) error { - if c.deps.CourierConfig().CourierEmailStrategy(ctx) == "http" { - return c.dispatchMailerEmail(ctx, msg) - } - if c.smtpClient.Host == "" { - return errors.WithStack(herodot.ErrInternalServerError.WithErrorf("Courier tried to deliver an email but %s is not set!", config.ViperKeyCourierSMTPURL)) - } - - from := c.deps.CourierConfig().CourierSMTPFrom(ctx) - fromName := c.deps.CourierConfig().CourierSMTPFromName(ctx) - - gm := gomail.NewMessage() - if fromName == "" { - gm.SetHeader("From", from) - } else { - gm.SetAddressHeader("From", from, fromName) - } - - gm.SetHeader("To", msg.Recipient) - gm.SetHeader("Subject", msg.Subject) - - headers := c.deps.CourierConfig().CourierSMTPHeaders(ctx) - for k, v := range headers { - gm.SetHeader(k, v) - } - - gm.SetBody("text/plain", msg.Body) - - tmpl, err := c.smtpClient.NewTemplateFromMessage(c.deps, msg) - if err != nil { - c.deps.Logger(). - WithError(err). - WithField("message_id", msg.ID). - WithField("message_nid", msg.NID). - Error(`Unable to get email template from message.`) - } else { - htmlBody, err := tmpl.EmailBody(ctx) - if err != nil { - c.deps.Logger(). - WithError(err). - WithField("message_id", msg.ID). - WithField("message_nid", msg.NID). - Error(`Unable to get email body from template.`) - } else { - gm.AddAlternative("text/html", htmlBody) - } - } - - if err := c.smtpClient.DialAndSend(ctx, gm); err != nil { - c.deps.Logger(). - WithError(err). - WithField("smtp_server", fmt.Sprintf("%s:%d", c.smtpClient.Host, c.smtpClient.Port)). - WithField("smtp_ssl_enabled", c.smtpClient.SSL). - WithField("message_from", from). - WithField("message_id", msg.ID). - WithField("message_nid", msg.NID). - Error("Unable to send email using SMTP connection.") - - var protoErr *textproto.Error - var mailErr *gomail.SendError - - switch { - case errors.As(err, &mailErr) && errors.As(mailErr.Cause, &protoErr) && protoErr.Code >= 500: - fallthrough - case errors.As(err, &protoErr) && protoErr.Code >= 500: - // See https://en.wikipedia.org/wiki/List_of_SMTP_server_return_codes - // If the SMTP server responds with 5xx, sending the message should not be retried (without changing something about the request) - if err := c.deps.CourierPersister().SetMessageStatus(ctx, msg.ID, MessageStatusAbandoned); err != nil { - c.deps.Logger(). - WithError(err). - WithField("message_id", msg.ID). - WithField("message_nid", msg.NID). - Error(`Unable to reset the retried message's status to "abandoned".`) - return err - } - } - - return errors.WithStack(herodot.ErrInternalServerError. - WithError(err.Error()).WithReason("failed to send email via smtp")) - } - - c.deps.Logger(). - WithField("message_id", msg.ID). - WithField("message_nid", msg.NID). - WithField("message_type", msg.Type). - WithField("message_template_type", msg.TemplateType). - WithField("message_subject", msg.Subject). - Debug("Courier sent out message.") - - return nil -} diff --git a/courier/smtp_channel.go b/courier/smtp_channel.go new file mode 100644 index 000000000000..a44719a351d6 --- /dev/null +++ b/courier/smtp_channel.go @@ -0,0 +1,144 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package courier + +import ( + "context" + "fmt" + "net/textproto" + + "github.com/pkg/errors" + + "github.com/ory/herodot" + "github.com/ory/kratos/courier/template" + "github.com/ory/kratos/driver/config" + "github.com/ory/mail/v3" +) + +type ( + SMTPChannel struct { + smtpClient *SMTPClient + d Dependencies + + newEmailTemplateFromMessage func(d template.Dependencies, msg Message) (EmailTemplate, error) + } +) + +var _ Channel = new(SMTPChannel) + +func NewSMTPChannel(deps Dependencies, cfg *config.SMTPConfig) (*SMTPChannel, error) { + return NewSMTPChannelWithCustomTemplates(deps, cfg, NewEmailTemplateFromMessage) +} + +func NewSMTPChannelWithCustomTemplates(deps Dependencies, cfg *config.SMTPConfig, newEmailTemplateFromMessage func(d template.Dependencies, msg Message) (EmailTemplate, error)) (*SMTPChannel, error) { + smtpClient, err := NewSMTPClient(deps, cfg) + if err != nil { + return nil, err + } + return &SMTPChannel{ + smtpClient: smtpClient, + d: deps, + newEmailTemplateFromMessage: newEmailTemplateFromMessage, + }, nil +} + +func (c *SMTPChannel) ID() string { + return "email" +} + +func (c *SMTPChannel) Dispatch(ctx context.Context, msg Message) error { + if c.smtpClient.Host == "" { + return errors.WithStack(herodot.ErrInternalServerError.WithErrorf("Courier tried to deliver an email but %s is not set!", config.ViperKeyCourierSMTPURL)) + } + + channels, err := c.d.CourierConfig().CourierChannels(ctx) + if err != nil { + return err + } + + var cfg *config.SMTPConfig + for _, channel := range channels { + if channel.ID == "email" && channel.SMTPConfig != nil { + cfg = channel.SMTPConfig + break + } + } + + gm := mail.NewMessage() + if cfg.FromName == "" { + gm.SetHeader("From", cfg.FromAddress) + } else { + gm.SetAddressHeader("From", cfg.FromAddress, cfg.FromName) + } + + gm.SetHeader("To", msg.Recipient) + gm.SetHeader("Subject", msg.Subject) + + headers := cfg.Headers + for k, v := range headers { + gm.SetHeader(k, v) + } + + gm.SetBody("text/plain", msg.Body) + + tmpl, err := c.newEmailTemplateFromMessage(c.d, msg) + if err != nil { + c.d.Logger(). + WithError(err). + WithField("message_id", msg.ID). + WithField("message_nid", msg.NID). + Error(`Unable to get email template from message.`) + } else if htmlBody, err := tmpl.EmailBody(ctx); err != nil { + c.d.Logger(). + WithError(err). + WithField("message_id", msg.ID). + WithField("message_nid", msg.NID). + Error(`Unable to get email body from template.`) + } else { + gm.AddAlternative("text/html", htmlBody) + } + + if err := c.smtpClient.DialAndSend(ctx, gm); err != nil { + c.d.Logger(). + WithError(err). + WithField("smtp_server", fmt.Sprintf("%s:%d", c.smtpClient.Host, c.smtpClient.Port)). + WithField("smtp_ssl_enabled", c.smtpClient.SSL). + WithField("message_from", cfg.FromAddress). + WithField("message_id", msg.ID). + WithField("message_nid", msg.NID). + Error("Unable to send email using SMTP connection.") + + var protoErr *textproto.Error + var mailErr *mail.SendError + + switch { + case errors.As(err, &mailErr) && errors.As(mailErr.Cause, &protoErr) && protoErr.Code >= 500: + fallthrough + case errors.As(err, &protoErr) && protoErr.Code >= 500: + // See https://en.wikipedia.org/wiki/List_of_SMTP_server_return_codes + // If the SMTP server responds with 5xx, sending the message should not be retried (without changing something about the request) + if err := c.d.CourierPersister().SetMessageStatus(ctx, msg.ID, MessageStatusAbandoned); err != nil { + c.d.Logger(). + WithError(err). + WithField("message_id", msg.ID). + WithField("message_nid", msg.NID). + Error(`Unable to reset the retried message's status to "abandoned".`) + return err + } + } + + return errors.WithStack(herodot.ErrInternalServerError. + WithError(err.Error()).WithReason("failed to send email via smtp")) + } + + c.d.Logger(). + WithField("message_id", msg.ID). + WithField("message_nid", msg.NID). + WithField("message_type", msg.Type). + WithField("message_template_type", msg.TemplateType). + WithField("message_subject", msg.Subject). + Debug("Courier sent out message.") + + return nil +} diff --git a/courier/smtp_test.go b/courier/smtp_test.go index 108a9a6f1abf..107ab2803447 100644 --- a/courier/smtp_test.go +++ b/courier/smtp_test.go @@ -39,13 +39,13 @@ func TestNewSMTP(t *testing.T) { ctx := context.Background() conf, reg := internal.NewFastRegistryWithMocks(t) - setupCourier := func(stringURL string) courier.Courier { + setupSMTPClient := func(stringURL string) *courier.SMTPClient { conf.MustSet(ctx, config.ViperKeyCourierSMTPURL, stringURL) - u, err := conf.CourierSMTPURL(ctx) - require.NoError(t, err) - t.Logf("SMTP URL: %s", u.String()) - c, err := courier.NewCourier(ctx, reg) + channels, err := conf.CourierChannels(ctx) + require.NoError(t, err) + require.Len(t, channels, 1) + c, err := courier.NewSMTPClient(reg, channels[0].SMTPConfig) require.NoError(t, err) return c } @@ -55,18 +55,18 @@ func TestNewSMTP(t *testing.T) { } // Should enforce StartTLS => dialer.StartTLSPolicy = gomail.MandatoryStartTLS and dialer.SSL = false - smtp := setupCourier("smtp://foo:bar@my-server:1234/") - assert.Equal(t, smtp.SmtpDialer().StartTLSPolicy, gomail.MandatoryStartTLS, "StartTLS not enforced") - assert.Equal(t, smtp.SmtpDialer().SSL, false, "Implicit TLS should not be enabled") + smtp := setupSMTPClient("smtp://foo:bar@my-server:1234/") + assert.Equal(t, smtp.StartTLSPolicy, gomail.MandatoryStartTLS, "StartTLS not enforced") + assert.Equal(t, smtp.SSL, false, "Implicit TLS should not be enabled") // Should enforce TLS => dialer.SSL = true - smtp = setupCourier("smtps://foo:bar@my-server:1234/") - assert.Equal(t, smtp.SmtpDialer().SSL, true, "Implicit TLS should be enabled") + smtp = setupSMTPClient("smtps://foo:bar@my-server:1234/") + assert.Equal(t, smtp.SSL, true, "Implicit TLS should be enabled") // Should allow cleartext => dialer.StartTLSPolicy = gomail.OpportunisticStartTLS and dialer.SSL = false - smtp = setupCourier("smtp://foo:bar@my-server:1234/?disable_starttls=true") - assert.Equal(t, smtp.SmtpDialer().StartTLSPolicy, gomail.OpportunisticStartTLS, "StartTLS is enforced") - assert.Equal(t, smtp.SmtpDialer().SSL, false, "Implicit TLS should not be enabled") + smtp = setupSMTPClient("smtp://foo:bar@my-server:1234/?disable_starttls=true") + assert.Equal(t, smtp.StartTLSPolicy, gomail.OpportunisticStartTLS, "StartTLS is enforced") + assert.Equal(t, smtp.SSL, false, "Implicit TLS should not be enabled") // Test cert based SMTP client auth clientCert, clientKey, err := generateTestClientCert() @@ -80,17 +80,17 @@ func TestNewSMTP(t *testing.T) { clientPEM, err := tls.LoadX509KeyPair(clientCert.Name(), clientKey.Name()) require.NoError(t, err) - smtpWithCert := setupCourier("smtps://subdomain.my-server:1234/?server_name=my-server") - assert.Equal(t, smtpWithCert.SmtpDialer().SSL, true, "Implicit TLS should be enabled") - assert.Equal(t, smtpWithCert.SmtpDialer().Host, "subdomain.my-server", "SMTP Dialer host should match") - assert.Equal(t, smtpWithCert.SmtpDialer().TLSConfig.ServerName, "my-server", "TLS config server name should match") - assert.Equal(t, smtpWithCert.SmtpDialer().TLSConfig.ServerName, "my-server", "TLS config server name should match") - assert.Contains(t, smtpWithCert.SmtpDialer().TLSConfig.Certificates, clientPEM, "TLS config should contain client pem") + smtpWithCert := setupSMTPClient("smtps://subdomain.my-server:1234/?server_name=my-server") + assert.Equal(t, smtpWithCert.SSL, true, "Implicit TLS should be enabled") + assert.Equal(t, smtpWithCert.Host, "subdomain.my-server", "SMTP Dialer host should match") + assert.Equal(t, smtpWithCert.TLSConfig.ServerName, "my-server", "TLS config server name should match") + assert.Equal(t, smtpWithCert.TLSConfig.ServerName, "my-server", "TLS config server name should match") + assert.Contains(t, smtpWithCert.TLSConfig.Certificates, clientPEM, "TLS config should contain client pem") // error case: invalid client key conf.Set(ctx, config.ViperKeyCourierSMTPClientKeyPath, clientCert.Name()) // mixup client key and client cert - smtpWithCert = setupCourier("smtps://subdomain.my-server:1234/?server_name=my-server") - assert.Equal(t, len(smtpWithCert.SmtpDialer().TLSConfig.Certificates), 0, "TLS config certificates should be empty") + smtpWithCert = setupSMTPClient("smtps://subdomain.my-server:1234/?server_name=my-server") + assert.Equal(t, len(smtpWithCert.TLSConfig.Certificates), 0, "TLS config certificates should be empty") } func TestQueueEmail(t *testing.T) { diff --git a/courier/stub/request.config.twilio.jsonnet b/courier/stub/request.config.twilio.jsonnet index da0736b06df0..f3a99db694e5 100644 --- a/courier/stub/request.config.twilio.jsonnet +++ b/courier/stub/request.config.twilio.jsonnet @@ -1,5 +1,5 @@ function(ctx) { - from: ctx.from, - to: ctx.to, - body: ctx.body + from: "Kratos Test", + to: ctx.Recipient, + body: ctx.Body } diff --git a/courier/template/courier/builtin/templates/verification_code/valid/sms.body.gotmpl b/courier/template/courier/builtin/templates/verification_code/valid/sms.body.gotmpl new file mode 100644 index 000000000000..0469598d2d58 --- /dev/null +++ b/courier/template/courier/builtin/templates/verification_code/valid/sms.body.gotmpl @@ -0,0 +1 @@ +Your verification code is: {{ .VerificationCode }} diff --git a/courier/template/email/login_code_valid.go b/courier/template/email/login_code_valid.go index 2debc3a0cb7c..1b3b55d4807c 100644 --- a/courier/template/email/login_code_valid.go +++ b/courier/template/email/login_code_valid.go @@ -49,3 +49,7 @@ func (t *LoginCodeValid) EmailBodyPlaintext(ctx context.Context) (string, error) func (t *LoginCodeValid) MarshalJSON() ([]byte, error) { return json.Marshal(t.model) } + +func (t *LoginCodeValid) TemplateType() template.TemplateType { + return template.TypeLoginCodeValid +} diff --git a/courier/template/email/login_code_valid_test.go b/courier/template/email/login_code_valid_test.go index dca97defe08c..eb6a95be0686 100644 --- a/courier/template/email/login_code_valid_test.go +++ b/courier/template/email/login_code_valid_test.go @@ -7,7 +7,7 @@ import ( "context" "testing" - "github.com/ory/kratos/courier" + "github.com/ory/kratos/courier/template" "github.com/ory/kratos/courier/template/email" "github.com/ory/kratos/courier/template/testhelpers" "github.com/ory/kratos/internal" @@ -25,6 +25,6 @@ func TestLoginCodeValid(t *testing.T) { }) t.Run("test=with remote resources", func(t *testing.T) { - testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/login_code/valid", courier.TypeLoginCodeValid) + testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/login_code/valid", template.TypeLoginCodeValid) }) } diff --git a/courier/template/email/recovery_code_invalid.go b/courier/template/email/recovery_code_invalid.go index 01dad94cb0a9..4914b75c7024 100644 --- a/courier/template/email/recovery_code_invalid.go +++ b/courier/template/email/recovery_code_invalid.go @@ -50,3 +50,7 @@ func (t *RecoveryCodeInvalid) EmailBodyPlaintext(ctx context.Context) (string, e func (t *RecoveryCodeInvalid) MarshalJSON() ([]byte, error) { return json.Marshal(t.model) } + +func (t *RecoveryCodeInvalid) TemplateType() template.TemplateType { + return template.TypeRecoveryCodeInvalid +} diff --git a/courier/template/email/recovery_code_invalid_test.go b/courier/template/email/recovery_code_invalid_test.go index dc6e3d28cae6..b043ecbbfe38 100644 --- a/courier/template/email/recovery_code_invalid_test.go +++ b/courier/template/email/recovery_code_invalid_test.go @@ -7,7 +7,7 @@ import ( "context" "testing" - "github.com/ory/kratos/courier" + "github.com/ory/kratos/courier/template" "github.com/ory/kratos/courier/template/email" "github.com/ory/kratos/courier/template/testhelpers" "github.com/ory/kratos/internal" @@ -25,6 +25,6 @@ func TestRecoveryCodeInvalid(t *testing.T) { }) t.Run("case=test remote resources", func(t *testing.T) { - testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/recovery_code/invalid", courier.TypeRecoveryCodeInvalid) + testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/recovery_code/invalid", template.TypeRecoveryCodeInvalid) }) } diff --git a/courier/template/email/recovery_code_valid.go b/courier/template/email/recovery_code_valid.go index 5468ac70206b..dce31b72e2fa 100644 --- a/courier/template/email/recovery_code_valid.go +++ b/courier/template/email/recovery_code_valid.go @@ -49,3 +49,7 @@ func (t *RecoveryCodeValid) EmailBodyPlaintext(ctx context.Context) (string, err func (t *RecoveryCodeValid) MarshalJSON() ([]byte, error) { return json.Marshal(t.model) } + +func (t *RecoveryCodeValid) TemplateType() template.TemplateType { + return template.TypeRecoveryCodeValid +} diff --git a/courier/template/email/recovery_code_valid_test.go b/courier/template/email/recovery_code_valid_test.go index 346e4180a93a..dd133c38c850 100644 --- a/courier/template/email/recovery_code_valid_test.go +++ b/courier/template/email/recovery_code_valid_test.go @@ -7,7 +7,7 @@ import ( "context" "testing" - "github.com/ory/kratos/courier" + "github.com/ory/kratos/courier/template" "github.com/ory/kratos/courier/template/email" "github.com/ory/kratos/courier/template/testhelpers" "github.com/ory/kratos/internal" @@ -25,6 +25,6 @@ func TestRecoveryCodeValid(t *testing.T) { }) t.Run("test=with remote resources", func(t *testing.T) { - testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/recovery_code/valid", courier.TypeRecoveryCodeValid) + testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/recovery_code/valid", template.TypeRecoveryCodeValid) }) } diff --git a/courier/template/email/recovery_invalid.go b/courier/template/email/recovery_invalid.go index fec6edb7e20c..dbc8992d5593 100644 --- a/courier/template/email/recovery_invalid.go +++ b/courier/template/email/recovery_invalid.go @@ -47,3 +47,7 @@ func (t *RecoveryInvalid) EmailBodyPlaintext(ctx context.Context) (string, error func (t *RecoveryInvalid) MarshalJSON() ([]byte, error) { return json.Marshal(t.m) } + +func (t *RecoveryInvalid) TemplateType() template.TemplateType { + return template.TypeRecoveryInvalid +} diff --git a/courier/template/email/recovery_invalid_test.go b/courier/template/email/recovery_invalid_test.go index cae880a24e97..b39a3839ef89 100644 --- a/courier/template/email/recovery_invalid_test.go +++ b/courier/template/email/recovery_invalid_test.go @@ -7,7 +7,7 @@ import ( "context" "testing" - "github.com/ory/kratos/courier" + "github.com/ory/kratos/courier/template" "github.com/ory/kratos/courier/template/email" "github.com/ory/kratos/courier/template/testhelpers" "github.com/ory/kratos/internal" @@ -25,6 +25,6 @@ func TestRecoverInvalid(t *testing.T) { }) t.Run("case=test remote resources", func(t *testing.T) { - testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/recovery/invalid", courier.TypeRecoveryInvalid) + testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/recovery/invalid", template.TypeRecoveryInvalid) }) } diff --git a/courier/template/email/recovery_valid.go b/courier/template/email/recovery_valid.go index 419cd26dd0c6..532d8d1bc4e6 100644 --- a/courier/template/email/recovery_valid.go +++ b/courier/template/email/recovery_valid.go @@ -49,3 +49,7 @@ func (t *RecoveryValid) EmailBodyPlaintext(ctx context.Context) (string, error) func (t *RecoveryValid) MarshalJSON() ([]byte, error) { return json.Marshal(t.m) } + +func (t *RecoveryValid) TemplateType() template.TemplateType { + return template.TypeRecoveryValid +} diff --git a/courier/template/email/recovery_valid_test.go b/courier/template/email/recovery_valid_test.go index eaaf85c27039..83027c787182 100644 --- a/courier/template/email/recovery_valid_test.go +++ b/courier/template/email/recovery_valid_test.go @@ -7,7 +7,7 @@ import ( "context" "testing" - "github.com/ory/kratos/courier" + "github.com/ory/kratos/courier/template" "github.com/ory/kratos/courier/template/email" "github.com/ory/kratos/courier/template/testhelpers" "github.com/ory/kratos/internal" @@ -25,6 +25,6 @@ func TestRecoverValid(t *testing.T) { }) t.Run("test=with remote resources", func(t *testing.T) { - testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/recovery/valid", courier.TypeRecoveryValid) + testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/recovery/valid", template.TypeRecoveryValid) }) } diff --git a/courier/template/email/registration_code_valid.go b/courier/template/email/registration_code_valid.go index f7e39e334976..f984ffaeb6c6 100644 --- a/courier/template/email/registration_code_valid.go +++ b/courier/template/email/registration_code_valid.go @@ -49,3 +49,7 @@ func (t *RegistrationCodeValid) EmailBodyPlaintext(ctx context.Context) (string, func (t *RegistrationCodeValid) MarshalJSON() ([]byte, error) { return json.Marshal(t.model) } + +func (t *RegistrationCodeValid) TemplateType() template.TemplateType { + return template.TypeRegistrationCodeValid +} diff --git a/courier/template/email/registration_code_valid_test.go b/courier/template/email/registration_code_valid_test.go index be4cfe8059ea..c0a877698aa8 100644 --- a/courier/template/email/registration_code_valid_test.go +++ b/courier/template/email/registration_code_valid_test.go @@ -7,7 +7,7 @@ import ( "context" "testing" - "github.com/ory/kratos/courier" + "github.com/ory/kratos/courier/template" "github.com/ory/kratos/courier/template/email" "github.com/ory/kratos/courier/template/testhelpers" "github.com/ory/kratos/internal" @@ -25,6 +25,6 @@ func TestRegistrationCodeValid(t *testing.T) { }) t.Run("test=with remote resources", func(t *testing.T) { - testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/registration_code/valid", courier.TypeRegistrationCodeValid) + testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/registration_code/valid", template.TypeRegistrationCodeValid) }) } diff --git a/courier/template/email/stub.go b/courier/template/email/stub.go index b96e1c195e22..57b66e06e4aa 100644 --- a/courier/template/email/stub.go +++ b/courier/template/email/stub.go @@ -49,3 +49,7 @@ func (t *TestStub) EmailBodyPlaintext(ctx context.Context) (string, error) { func (t *TestStub) MarshalJSON() ([]byte, error) { return json.Marshal(t.m) } + +func (t *TestStub) TemplateType() template.TemplateType { + return template.TypeTestStub +} diff --git a/courier/template/email/verification_code_invalid.go b/courier/template/email/verification_code_invalid.go index ea69695ce801..fa76441b3434 100644 --- a/courier/template/email/verification_code_invalid.go +++ b/courier/template/email/verification_code_invalid.go @@ -71,3 +71,7 @@ func (t *VerificationCodeInvalid) EmailBodyPlaintext(ctx context.Context) (strin func (t *VerificationCodeInvalid) MarshalJSON() ([]byte, error) { return json.Marshal(t.m) } + +func (t *VerificationCodeInvalid) TemplateType() template.TemplateType { + return template.TypeVerificationCodeInvalid +} diff --git a/courier/template/email/verification_code_invalid_test.go b/courier/template/email/verification_code_invalid_test.go index af36f87f5ce5..3764e64cf1bf 100644 --- a/courier/template/email/verification_code_invalid_test.go +++ b/courier/template/email/verification_code_invalid_test.go @@ -7,7 +7,7 @@ import ( "context" "testing" - "github.com/ory/kratos/courier" + "github.com/ory/kratos/courier/template" "github.com/ory/kratos/courier/template/email" "github.com/ory/kratos/courier/template/testhelpers" "github.com/ory/kratos/internal" @@ -25,6 +25,6 @@ func TestVerifyCodeInvalid(t *testing.T) { }) t.Run("test=with remote resources", func(t *testing.T) { - testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/verification_code/invalid", courier.TypeVerificationCodeInvalid) + testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/verification_code/invalid", template.TypeVerificationCodeInvalid) }) } diff --git a/courier/template/email/verification_code_valid.go b/courier/template/email/verification_code_valid.go index fdb752c791ba..e23f48f70b5a 100644 --- a/courier/template/email/verification_code_valid.go +++ b/courier/template/email/verification_code_valid.go @@ -72,3 +72,7 @@ func (t *VerificationCodeValid) EmailBodyPlaintext(ctx context.Context) (string, func (t *VerificationCodeValid) MarshalJSON() ([]byte, error) { return json.Marshal(t.m) } + +func (t *VerificationCodeValid) TemplateType() template.TemplateType { + return template.TypeVerificationCodeValid +} diff --git a/courier/template/email/verification_code_valid_test.go b/courier/template/email/verification_code_valid_test.go index 7b2883927074..6ec0857ea2bb 100644 --- a/courier/template/email/verification_code_valid_test.go +++ b/courier/template/email/verification_code_valid_test.go @@ -7,7 +7,7 @@ import ( "context" "testing" - "github.com/ory/kratos/courier" + "github.com/ory/kratos/courier/template" "github.com/ory/kratos/courier/template/email" "github.com/ory/kratos/courier/template/testhelpers" "github.com/ory/kratos/internal" @@ -25,6 +25,6 @@ func TestVerifyCodeValid(t *testing.T) { }) t.Run("test=with remote resources", func(t *testing.T) { - testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/verification_code/valid", courier.TypeVerificationCodeValid) + testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/verification_code/valid", template.TypeVerificationCodeValid) }) } diff --git a/courier/template/email/verification_invalid.go b/courier/template/email/verification_invalid.go index c62ec0523c3f..5f6623f04352 100644 --- a/courier/template/email/verification_invalid.go +++ b/courier/template/email/verification_invalid.go @@ -47,3 +47,7 @@ func (t *VerificationInvalid) EmailBodyPlaintext(ctx context.Context) (string, e func (t *VerificationInvalid) MarshalJSON() ([]byte, error) { return json.Marshal(t.m) } + +func (t *VerificationInvalid) TemplateType() template.TemplateType { + return template.TypeVerificationInvalid +} diff --git a/courier/template/email/verification_invalid_test.go b/courier/template/email/verification_invalid_test.go index 226dc39aede0..1950b3d0806c 100644 --- a/courier/template/email/verification_invalid_test.go +++ b/courier/template/email/verification_invalid_test.go @@ -7,7 +7,7 @@ import ( "context" "testing" - "github.com/ory/kratos/courier" + "github.com/ory/kratos/courier/template" "github.com/ory/kratos/courier/template/email" "github.com/ory/kratos/courier/template/testhelpers" "github.com/ory/kratos/internal" @@ -26,7 +26,7 @@ func TestVerifyInvalid(t *testing.T) { t.Run("test=with remote resources", func(t *testing.T) { t.Run("test=with remote resources", func(t *testing.T) { - testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/verification/invalid", courier.TypeVerificationInvalid) + testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/verification/invalid", template.TypeVerificationInvalid) }) }) } diff --git a/courier/template/email/verification_valid.go b/courier/template/email/verification_valid.go index d58710da86cb..723ea618e071 100644 --- a/courier/template/email/verification_valid.go +++ b/courier/template/email/verification_valid.go @@ -49,3 +49,7 @@ func (t *VerificationValid) EmailBodyPlaintext(ctx context.Context) (string, err func (t *VerificationValid) MarshalJSON() ([]byte, error) { return json.Marshal(t.m) } + +func (t *VerificationValid) TemplateType() template.TemplateType { + return template.TypeVerificationValid +} diff --git a/courier/template/email/verification_valid_test.go b/courier/template/email/verification_valid_test.go index 6c086fbdb6a7..334ac07d1ab8 100644 --- a/courier/template/email/verification_valid_test.go +++ b/courier/template/email/verification_valid_test.go @@ -7,7 +7,7 @@ import ( "context" "testing" - "github.com/ory/kratos/courier" + "github.com/ory/kratos/courier/template" "github.com/ory/kratos/courier/template/email" "github.com/ory/kratos/courier/template/testhelpers" "github.com/ory/kratos/internal" @@ -25,6 +25,6 @@ func TestVerifyValid(t *testing.T) { }) t.Run("test=with remote resources", func(t *testing.T) { - testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/verification/valid", courier.TypeVerificationValid) + testhelpers.TestRemoteTemplates(t, "../courier/builtin/templates/verification/valid", template.TypeVerificationValid) }) } diff --git a/courier/template/sms/otp.go b/courier/template/sms/otp.go deleted file mode 100644 index 7dda3f4fb2c8..000000000000 --- a/courier/template/sms/otp.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright © 2023 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -package sms - -import ( - "context" - "encoding/json" - "os" - - "github.com/ory/kratos/courier/template" -) - -type ( - OTPMessage struct { - d template.Dependencies - m *OTPMessageModel - } - - OTPMessageModel struct { - To string - Code string - Identity map[string]interface{} - } -) - -func NewOTPMessage(d template.Dependencies, m *OTPMessageModel) *OTPMessage { - return &OTPMessage{d: d, m: m} -} - -func (t *OTPMessage) PhoneNumber() (string, error) { - return t.m.To, nil -} - -func (t *OTPMessage) SMSBody(ctx context.Context) (string, error) { - return template.LoadText(ctx, t.d, os.DirFS(t.d.CourierConfig().CourierTemplatesRoot(ctx)), "otp/sms.body.gotmpl", "otp/sms.body*", t.m, "") -} - -func (t *OTPMessage) MarshalJSON() ([]byte, error) { - return json.Marshal(t.m) -} diff --git a/courier/template/sms/stub.go b/courier/template/sms/stub.go index b42d76c11319..0d68db1b209b 100644 --- a/courier/template/sms/stub.go +++ b/courier/template/sms/stub.go @@ -39,3 +39,7 @@ func (t *TestStub) SMSBody(ctx context.Context) (string, error) { func (t *TestStub) MarshalJSON() ([]byte, error) { return json.Marshal(t.m) } + +func (t *TestStub) TemplateType() template.TemplateType { + return template.TypeTestStub +} diff --git a/courier/template/sms/verification_code.go b/courier/template/sms/verification_code.go new file mode 100644 index 000000000000..f4ab6fc23359 --- /dev/null +++ b/courier/template/sms/verification_code.go @@ -0,0 +1,53 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package sms + +import ( + "context" + "encoding/json" + "os" + + "github.com/ory/kratos/courier/template" +) + +type ( + VerificationCodeValid struct { + deps template.Dependencies + model *VerificationCodeValidModel + } + + VerificationCodeValidModel struct { + To string + VerificationCode string + Identity map[string]interface{} + } +) + +func NewVerificationCodeValid(d template.Dependencies, m *VerificationCodeValidModel) *VerificationCodeValid { + return &VerificationCodeValid{deps: d, model: m} +} + +func (t *VerificationCodeValid) PhoneNumber() (string, error) { + return t.model.To, nil +} + +func (t *VerificationCodeValid) SMSBody(ctx context.Context) (string, error) { + return template.LoadText( + ctx, + t.deps, + os.DirFS(t.deps.CourierConfig().CourierTemplatesRoot(ctx)), + "verification_code/valid/sms.body.gotmpl", + "verification_code/valid/sms.body*", + t.model, + t.deps.CourierConfig().CourierSMSTemplatesVerificationCodeValid(ctx).Body.PlainText, + ) +} + +func (t *VerificationCodeValid) MarshalJSON() ([]byte, error) { + return json.Marshal(t.model) +} + +func (t *VerificationCodeValid) TemplateType() template.TemplateType { + return template.TypeVerificationCodeValid +} diff --git a/courier/template/sms/otp_test.go b/courier/template/sms/verification_code_test.go similarity index 86% rename from courier/template/sms/otp_test.go rename to courier/template/sms/verification_code_test.go index 9853c10fac34..fc2bb892e6b2 100644 --- a/courier/template/sms/otp_test.go +++ b/courier/template/sms/verification_code_test.go @@ -23,7 +23,7 @@ func TestNewOTPMessage(t *testing.T) { otp = "012345" ) - tpl := sms.NewOTPMessage(reg, &sms.OTPMessageModel{To: expectedPhone, Code: otp}) + tpl := sms.NewVerificationCodeValid(reg, &sms.VerificationCodeValidModel{To: expectedPhone, VerificationCode: otp}) expectedBody := fmt.Sprintf("Your verification code is: %s\n", otp) diff --git a/courier/template/template.go b/courier/template/template.go index 483c40bd2f5e..bf7074990253 100644 --- a/courier/template/template.go +++ b/courier/template/template.go @@ -12,19 +12,7 @@ import ( "github.com/ory/x/httpx" ) -type ( - Config interface { - CourierTemplatesRoot() string - CourierTemplatesVerificationInvalid() *config.CourierEmailTemplate - CourierTemplatesVerificationValid() *config.CourierEmailTemplate - CourierTemplatesRecoveryInvalid() *config.CourierEmailTemplate - CourierTemplatesRecoveryValid() *config.CourierEmailTemplate - CourierTemplatesLoginValid() *config.CourierEmailTemplate - CourierTemplatesRegistrationValid() *config.CourierEmailTemplate - } - - Dependencies interface { - CourierConfig() config.CourierConfigs - HTTPClient(ctx context.Context, opts ...httpx.ResilientOptions) *retryablehttp.Client - } -) +type Dependencies interface { + CourierConfig() config.CourierConfigs + HTTPClient(ctx context.Context, opts ...httpx.ResilientOptions) *retryablehttp.Client +} diff --git a/courier/template/testhelpers/testhelpers.go b/courier/template/testhelpers/testhelpers.go index 6c2923dbe416..66d2f15f6f4b 100644 --- a/courier/template/testhelpers/testhelpers.go +++ b/courier/template/testhelpers/testhelpers.go @@ -18,7 +18,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/ory/kratos/courier" "github.com/ory/kratos/courier/template" "github.com/ory/kratos/driver" "github.com/ory/kratos/driver/config" @@ -51,7 +50,7 @@ func TestRendered(t *testing.T, ctx context.Context, tpl interface { assert.NotEmpty(t, rendered) } -func TestRemoteTemplates(t *testing.T, basePath string, tmplType courier.TemplateType) { +func TestRemoteTemplates(t *testing.T, basePath string, tmplType template.TemplateType) { ctx, cancel := context.WithCancel(context.Background()) t.Cleanup(cancel) @@ -61,32 +60,32 @@ func TestRemoteTemplates(t *testing.T, basePath string, tmplType courier.Templat return base64.StdEncoding.EncodeToString(f) } - getTemplate := func(tmpl courier.TemplateType, d template.Dependencies) interface { + getTemplate := func(tmpl template.TemplateType, d template.Dependencies) interface { EmailBody(context.Context) (string, error) EmailSubject(context.Context) (string, error) } { switch tmpl { - case courier.TypeRecoveryInvalid: + case template.TypeRecoveryInvalid: return email.NewRecoveryInvalid(d, &email.RecoveryInvalidModel{}) - case courier.TypeRecoveryValid: + case template.TypeRecoveryValid: return email.NewRecoveryValid(d, &email.RecoveryValidModel{}) - case courier.TypeRecoveryCodeValid: + case template.TypeRecoveryCodeValid: return email.NewRecoveryCodeValid(d, &email.RecoveryCodeValidModel{}) - case courier.TypeRecoveryCodeInvalid: + case template.TypeRecoveryCodeInvalid: return email.NewRecoveryCodeInvalid(d, &email.RecoveryCodeInvalidModel{}) - case courier.TypeTestStub: + case template.TypeTestStub: return email.NewTestStub(d, &email.TestStubModel{}) - case courier.TypeVerificationInvalid: + case template.TypeVerificationInvalid: return email.NewVerificationInvalid(d, &email.VerificationInvalidModel{}) - case courier.TypeVerificationValid: + case template.TypeVerificationValid: return email.NewVerificationValid(d, &email.VerificationValidModel{}) - case courier.TypeVerificationCodeInvalid: + case template.TypeVerificationCodeInvalid: return email.NewVerificationCodeInvalid(d, &email.VerificationCodeInvalidModel{}) - case courier.TypeVerificationCodeValid: + case template.TypeVerificationCodeValid: return email.NewVerificationCodeValid(d, &email.VerificationCodeValidModel{}) - case courier.TypeLoginCodeValid: + case template.TypeLoginCodeValid: return email.NewLoginCodeValid(d, &email.LoginCodeValidModel{}) - case courier.TypeRegistrationCodeValid: + case template.TypeRegistrationCodeValid: return email.NewRegistrationCodeValid(d, &email.RegistrationCodeValidModel{}) default: return nil diff --git a/courier/template/type.go b/courier/template/type.go new file mode 100644 index 000000000000..4fc0b9bccca2 --- /dev/null +++ b/courier/template/type.go @@ -0,0 +1,23 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package template + +// A Template's type +// +// swagger:enum TemplateType +type TemplateType string + +const ( + TypeRecoveryInvalid TemplateType = "recovery_invalid" + TypeRecoveryValid TemplateType = "recovery_valid" + TypeRecoveryCodeInvalid TemplateType = "recovery_code_invalid" + TypeRecoveryCodeValid TemplateType = "recovery_code_valid" + TypeVerificationInvalid TemplateType = "verification_invalid" + TypeVerificationValid TemplateType = "verification_valid" + TypeVerificationCodeInvalid TemplateType = "verification_code_invalid" + TypeVerificationCodeValid TemplateType = "verification_code_valid" + TypeTestStub TemplateType = "stub" + TypeLoginCodeValid TemplateType = "login_code_valid" + TypeRegistrationCodeValid TemplateType = "registration_code_valid" +) diff --git a/courier/email_templates.go b/courier/templates.go similarity index 55% rename from courier/email_templates.go rename to courier/templates.go index d2bae0a197e4..4ffb2c3f766a 100644 --- a/courier/email_templates.go +++ b/courier/templates.go @@ -15,8 +15,13 @@ import ( ) type ( - EmailTemplate interface { + Template interface { json.Marshaler + TemplateType() template.TemplateType + } + + EmailTemplate interface { + Template EmailSubject(context.Context) (string, error) EmailBody(context.Context) (string, error) EmailBodyPlaintext(context.Context) (string, error) @@ -24,118 +29,69 @@ type ( } ) -// A Template's type -// -// swagger:enum TemplateType -type TemplateType string - -const ( - TypeRecoveryInvalid TemplateType = "recovery_invalid" - TypeRecoveryValid TemplateType = "recovery_valid" - TypeRecoveryCodeInvalid TemplateType = "recovery_code_invalid" - TypeRecoveryCodeValid TemplateType = "recovery_code_valid" - TypeVerificationInvalid TemplateType = "verification_invalid" - TypeVerificationValid TemplateType = "verification_valid" - TypeVerificationCodeInvalid TemplateType = "verification_code_invalid" - TypeVerificationCodeValid TemplateType = "verification_code_valid" - TypeOTP TemplateType = "otp" - TypeTestStub TemplateType = "stub" - TypeLoginCodeValid TemplateType = "login_code_valid" - TypeRegistrationCodeValid TemplateType = "registration_code_valid" -) - -func GetEmailTemplateType(t EmailTemplate) (TemplateType, error) { - switch t.(type) { - case *email.RecoveryInvalid: - return TypeRecoveryInvalid, nil - case *email.RecoveryValid: - return TypeRecoveryValid, nil - case *email.RecoveryCodeInvalid: - return TypeRecoveryCodeInvalid, nil - case *email.RecoveryCodeValid: - return TypeRecoveryCodeValid, nil - case *email.VerificationInvalid: - return TypeVerificationInvalid, nil - case *email.VerificationValid: - return TypeVerificationValid, nil - case *email.VerificationCodeInvalid: - return TypeVerificationCodeInvalid, nil - case *email.VerificationCodeValid: - return TypeVerificationCodeValid, nil - case *email.LoginCodeValid: - return TypeLoginCodeValid, nil - case *email.RegistrationCodeValid: - return TypeRegistrationCodeValid, nil - case *email.TestStub: - return TypeTestStub, nil - default: - return "", errors.Errorf("unexpected template type") - } -} - func NewEmailTemplateFromMessage(d template.Dependencies, msg Message) (EmailTemplate, error) { switch msg.TemplateType { - case TypeRecoveryInvalid: + case template.TypeRecoveryInvalid: var t email.RecoveryInvalidModel if err := json.Unmarshal(msg.TemplateData, &t); err != nil { return nil, err } return email.NewRecoveryInvalid(d, &t), nil - case TypeRecoveryValid: + case template.TypeRecoveryValid: var t email.RecoveryValidModel if err := json.Unmarshal(msg.TemplateData, &t); err != nil { return nil, err } return email.NewRecoveryValid(d, &t), nil - case TypeRecoveryCodeInvalid: + case template.TypeRecoveryCodeInvalid: var t email.RecoveryCodeInvalidModel if err := json.Unmarshal(msg.TemplateData, &t); err != nil { return nil, err } return email.NewRecoveryCodeInvalid(d, &t), nil - case TypeRecoveryCodeValid: + case template.TypeRecoveryCodeValid: var t email.RecoveryCodeValidModel if err := json.Unmarshal(msg.TemplateData, &t); err != nil { return nil, err } return email.NewRecoveryCodeValid(d, &t), nil - case TypeVerificationInvalid: + case template.TypeVerificationInvalid: var t email.VerificationInvalidModel if err := json.Unmarshal(msg.TemplateData, &t); err != nil { return nil, err } return email.NewVerificationInvalid(d, &t), nil - case TypeVerificationValid: + case template.TypeVerificationValid: var t email.VerificationValidModel if err := json.Unmarshal(msg.TemplateData, &t); err != nil { return nil, err } return email.NewVerificationValid(d, &t), nil - case TypeVerificationCodeInvalid: + case template.TypeVerificationCodeInvalid: var t email.VerificationCodeInvalidModel if err := json.Unmarshal(msg.TemplateData, &t); err != nil { return nil, err } return email.NewVerificationCodeInvalid(d, &t), nil - case TypeVerificationCodeValid: + case template.TypeVerificationCodeValid: var t email.VerificationCodeValidModel if err := json.Unmarshal(msg.TemplateData, &t); err != nil { return nil, err } return email.NewVerificationCodeValid(d, &t), nil - case TypeTestStub: + case template.TypeTestStub: var t email.TestStubModel if err := json.Unmarshal(msg.TemplateData, &t); err != nil { return nil, err } return email.NewTestStub(d, &t), nil - case TypeLoginCodeValid: + case template.TypeLoginCodeValid: var t email.LoginCodeValidModel if err := json.Unmarshal(msg.TemplateData, &t); err != nil { return nil, err } return email.NewLoginCodeValid(d, &t), nil - case TypeRegistrationCodeValid: + case template.TypeRegistrationCodeValid: var t email.RegistrationCodeValidModel if err := json.Unmarshal(msg.TemplateData, &t); err != nil { return nil, err diff --git a/courier/templates_test.go b/courier/templates_test.go new file mode 100644 index 000000000000..f6b9fa3f8b7b --- /dev/null +++ b/courier/templates_test.go @@ -0,0 +1,72 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package courier_test + +import ( + "context" + "encoding/json" + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/ory/kratos/courier" + "github.com/ory/kratos/courier/template" + "github.com/ory/kratos/courier/template/email" + "github.com/ory/kratos/internal" +) + +func TestNewEmailTemplateFromMessage(t *testing.T) { + _, reg := internal.NewFastRegistryWithMocks(t) + ctx := context.Background() + + for tmplType, expectedTmpl := range map[template.TemplateType]courier.EmailTemplate{ + template.TypeRecoveryInvalid: email.NewRecoveryInvalid(reg, &email.RecoveryInvalidModel{To: "foo"}), + template.TypeRecoveryValid: email.NewRecoveryValid(reg, &email.RecoveryValidModel{To: "bar", RecoveryURL: "http://foo.bar"}), + template.TypeRecoveryCodeValid: email.NewRecoveryCodeValid(reg, &email.RecoveryCodeValidModel{To: "bar", RecoveryCode: "12345678"}), + template.TypeRecoveryCodeInvalid: email.NewRecoveryCodeInvalid(reg, &email.RecoveryCodeInvalidModel{To: "bar"}), + template.TypeVerificationInvalid: email.NewVerificationInvalid(reg, &email.VerificationInvalidModel{To: "baz"}), + template.TypeVerificationValid: email.NewVerificationValid(reg, &email.VerificationValidModel{To: "faz", VerificationURL: "http://bar.foo"}), + template.TypeVerificationCodeInvalid: email.NewVerificationCodeInvalid(reg, &email.VerificationCodeInvalidModel{To: "baz"}), + template.TypeVerificationCodeValid: email.NewVerificationCodeValid(reg, &email.VerificationCodeValidModel{To: "faz", VerificationURL: "http://bar.foo", VerificationCode: "123456678"}), + template.TypeTestStub: email.NewTestStub(reg, &email.TestStubModel{To: "far", Subject: "test subject", Body: "test body"}), + template.TypeLoginCodeValid: email.NewLoginCodeValid(reg, &email.LoginCodeValidModel{To: "far", LoginCode: "123456"}), + template.TypeRegistrationCodeValid: email.NewRegistrationCodeValid(reg, &email.RegistrationCodeValidModel{To: "far", RegistrationCode: "123456"}), + } { + t.Run(fmt.Sprintf("case=%s", tmplType), func(t *testing.T) { + tmplData, err := json.Marshal(expectedTmpl) + require.NoError(t, err) + + m := courier.Message{TemplateType: tmplType, TemplateData: tmplData} + actualTmpl, err := courier.NewEmailTemplateFromMessage(reg, m) + require.NoError(t, err) + + require.IsType(t, expectedTmpl, actualTmpl) + + expectedRecipient, err := expectedTmpl.EmailRecipient() + require.NoError(t, err) + actualRecipient, err := actualTmpl.EmailRecipient() + require.NoError(t, err) + require.Equal(t, expectedRecipient, actualRecipient) + + expectedSubject, err := expectedTmpl.EmailSubject(ctx) + require.NoError(t, err) + actualSubject, err := actualTmpl.EmailSubject(ctx) + require.NoError(t, err) + require.Equal(t, expectedSubject, actualSubject) + + expectedBody, err := expectedTmpl.EmailBody(ctx) + require.NoError(t, err) + actualBody, err := actualTmpl.EmailBody(ctx) + require.NoError(t, err) + require.Equal(t, expectedBody, actualBody) + + expectedBodyPlaintext, err := expectedTmpl.EmailBodyPlaintext(ctx) + require.NoError(t, err) + actualBodyPlaintext, err := actualTmpl.EmailBodyPlaintext(ctx) + require.NoError(t, err) + require.Equal(t, expectedBodyPlaintext, actualBodyPlaintext) + }) + } +} diff --git a/driver/config/config.go b/driver/config/config.go index f1b839d9093d..8162ea39bc37 100644 --- a/driver/config/config.go +++ b/driver/config/config.go @@ -66,20 +66,20 @@ const ( ViperKeyCourierTemplatesVerificationValidEmail = "courier.templates.verification.valid.email" ViperKeyCourierTemplatesVerificationCodeInvalidEmail = "courier.templates.verification_code.invalid.email" ViperKeyCourierTemplatesVerificationCodeValidEmail = "courier.templates.verification_code.valid.email" + ViperKeyCourierTemplatesVerificationCodeValidSMS = "courier.templates.verification_code.valid.sms" ViperKeyCourierDeliveryStrategy = "courier.delivery_strategy" ViperKeyCourierHTTPRequestConfig = "courier.http.request_config" ViperKeyCourierTemplatesLoginCodeValidEmail = "courier.templates.login_code.valid.email" ViperKeyCourierTemplatesRegistrationCodeValidEmail = "courier.templates.registration_code.valid.email" + ViperKeyCourierSMTP = "courier.smtp" ViperKeyCourierSMTPFrom = "courier.smtp.from_address" ViperKeyCourierSMTPFromName = "courier.smtp.from_name" ViperKeyCourierSMTPHeaders = "courier.smtp.headers" ViperKeyCourierSMTPLocalName = "courier.smtp.local_name" - ViperKeyCourierSMSRequestConfig = "courier.sms.request_config" - ViperKeyCourierSMSEnabled = "courier.sms.enabled" - ViperKeyCourierSMSFrom = "courier.sms.from" ViperKeyCourierMessageRetries = "courier.message_retries" ViperKeyCourierWorkerPullCount = "courier.worker.pull_count" ViperKeyCourierWorkerPullWait = "courier.worker.pull_wait" + ViperKeyCourierChannels = "courier.channels" ViperKeySecretsDefault = "secrets.default" ViperKeySecretsCookie = "secrets.cookie" ViperKeySecretsCipher = "secrets.cipher" @@ -258,6 +258,28 @@ type ( Body *CourierEmailBodyTemplate `json:"body"` Subject string `json:"subject"` } + CourierSMSTemplate struct { + Body *CourierSMSTemplateBody `json:"body"` + } + CourierSMSTemplateBody struct { + PlainText string `json:"plaintext"` + } + CourierChannel struct { + ID string `json:"id" koanf:"id"` + Type string `json:"type" koanf:"type"` + SMTPConfig *SMTPConfig `json:"smtp_config" koanf:"smtp_config"` + RequestConfig json.RawMessage `json:"request_config" koanf:"-"` + RequestConfigRaw map[string]any `json:"-" koanf:"request_config"` + } + SMTPConfig struct { + ConnectionURI string `json:"connection_uri" koanf:"connection_uri"` + ClientCertPath string `json:"client_cert_path" koanf:"client_cert_path"` + ClientKeyPath string `json:"client_key_path" koanf:"client_key_path"` + FromAddress string `json:"from_address" koanf:"from_address"` + FromName string `json:"from_name" koanf:"from_name"` + Headers map[string]string `json:"headers" koanf:"headers"` + LocalName string `json:"local_name" koanf:"local_name"` + } Config struct { l *logrusx.Logger p *configx.Provider @@ -269,18 +291,6 @@ type ( Config() *Config } CourierConfigs interface { - CourierEmailStrategy(ctx context.Context) string - CourierEmailRequestConfig(ctx context.Context) json.RawMessage - CourierSMTPURL(ctx context.Context) (*url.URL, error) - CourierSMTPClientCertPath(ctx context.Context) string - CourierSMTPClientKeyPath(ctx context.Context) string - CourierSMTPFrom(ctx context.Context) string - CourierSMTPFromName(ctx context.Context) string - CourierSMTPHeaders(ctx context.Context) map[string]string - CourierSMTPLocalName(ctx context.Context) string - CourierSMSEnabled(ctx context.Context) bool - CourierSMSFrom(ctx context.Context) string - CourierSMSRequestConfig(ctx context.Context) json.RawMessage CourierTemplatesRoot(ctx context.Context) string CourierTemplatesVerificationInvalid(ctx context.Context) *CourierEmailTemplate CourierTemplatesVerificationValid(ctx context.Context) *CourierEmailTemplate @@ -292,9 +302,11 @@ type ( CourierTemplatesVerificationCodeValid(ctx context.Context) *CourierEmailTemplate CourierTemplatesLoginCodeValid(ctx context.Context) *CourierEmailTemplate CourierTemplatesRegistrationCodeValid(ctx context.Context) *CourierEmailTemplate + CourierSMSTemplatesVerificationCodeValid(ctx context.Context) *CourierSMSTemplate CourierMessageRetries(ctx context.Context) int CourierWorkerPullCount(ctx context.Context) int CourierWorkerPullWait(ctx context.Context) time.Duration + CourierChannels(context.Context) ([]*CourierChannel, error) } ) @@ -884,15 +896,6 @@ func (p *Config) SelfAdminURL(ctx context.Context) *url.URL { return p.baseURL(ctx, ViperKeyAdminBaseURL, ViperKeyAdminHost, ViperKeyAdminPort, 4434) } -func (p *Config) CourierSMTPURL(ctx context.Context) (*url.URL, error) { - source := p.GetProvider(ctx).String(ViperKeyCourierSMTPURL) - parsed, err := url.Parse(source) - if err != nil { - return nil, errors.WithStack(herodot.ErrInternalServerError.WithReason("Unable to parse the project's SMTP URL. Please ensure that it is properly escaped: https://www.ory.sh/dr/3").WithDebugf("%s", err)) - } - return parsed, nil -} - func (p *Config) OAuth2ProviderHeader(ctx context.Context) http.Header { hh := map[string]string{} if err := p.GetProvider(ctx).Unmarshal(ViperKeyOAuth2ProviderHeader, &hh); err != nil { @@ -1022,31 +1025,11 @@ func (p *Config) CourierEmailRequestConfig(ctx context.Context) json.RawMessage return config } -func (p *Config) CourierSMTPClientCertPath(ctx context.Context) string { - return p.GetProvider(ctx).StringF(ViperKeyCourierSMTPClientCertPath, "") -} - -func (p *Config) CourierSMTPClientKeyPath(ctx context.Context) string { - return p.GetProvider(ctx).StringF(ViperKeyCourierSMTPClientKeyPath, "") -} - -func (p *Config) CourierSMTPFrom(ctx context.Context) string { - return p.GetProvider(ctx).StringF(ViperKeyCourierSMTPFrom, "noreply@kratos.ory.sh") -} - -func (p *Config) CourierSMTPFromName(ctx context.Context) string { - return p.GetProvider(ctx).StringF(ViperKeyCourierSMTPFromName, "") -} - -func (p *Config) CourierSMTPLocalName(ctx context.Context) string { - return p.GetProvider(ctx).StringF(ViperKeyCourierSMTPLocalName, "localhost") -} - func (p *Config) CourierTemplatesRoot(ctx context.Context) string { return p.GetProvider(ctx).StringF(ViperKeyCourierTemplatesPath, "courier/builtin/templates") } -func (p *Config) CourierTemplatesHelper(ctx context.Context, key string) *CourierEmailTemplate { +func (p *Config) CourierEmailTemplatesHelper(ctx context.Context, key string) *CourierEmailTemplate { courierTemplate := &CourierEmailTemplate{ Body: &CourierEmailBodyTemplate{ PlainText: "", @@ -1072,44 +1055,72 @@ func (p *Config) CourierTemplatesHelper(ctx context.Context, key string) *Courie return courierTemplate } +func (p *Config) CourierSMSTemplatesHelper(ctx context.Context, key string) *CourierSMSTemplate { + courierTemplate := &CourierSMSTemplate{ + Body: &CourierSMSTemplateBody{ + PlainText: "", + }, + } + + if !p.GetProvider(ctx).Exists(key) { + return courierTemplate + } + + config, err := json.Marshal(p.GetProvider(ctx).Get(key)) + if err != nil { + p.l.WithError(err).Fatalf("Unable to decode values from %s.", key) + return courierTemplate + } + + if err := json.Unmarshal(config, courierTemplate); err != nil { + p.l.WithError(err).Fatalf("Unable to encode values from %s.", key) + return courierTemplate + } + return courierTemplate +} + func (p *Config) CourierTemplatesVerificationInvalid(ctx context.Context) *CourierEmailTemplate { - return p.CourierTemplatesHelper(ctx, ViperKeyCourierTemplatesVerificationInvalidEmail) + return p.CourierEmailTemplatesHelper(ctx, ViperKeyCourierTemplatesVerificationInvalidEmail) } func (p *Config) CourierTemplatesVerificationValid(ctx context.Context) *CourierEmailTemplate { - return p.CourierTemplatesHelper(ctx, ViperKeyCourierTemplatesVerificationValidEmail) + return p.CourierEmailTemplatesHelper(ctx, ViperKeyCourierTemplatesVerificationValidEmail) } func (p *Config) CourierTemplatesRecoveryInvalid(ctx context.Context) *CourierEmailTemplate { - return p.CourierTemplatesHelper(ctx, ViperKeyCourierTemplatesRecoveryInvalidEmail) + return p.CourierEmailTemplatesHelper(ctx, ViperKeyCourierTemplatesRecoveryInvalidEmail) } func (p *Config) CourierTemplatesRecoveryValid(ctx context.Context) *CourierEmailTemplate { - return p.CourierTemplatesHelper(ctx, ViperKeyCourierTemplatesRecoveryValidEmail) + return p.CourierEmailTemplatesHelper(ctx, ViperKeyCourierTemplatesRecoveryValidEmail) } func (p *Config) CourierTemplatesRecoveryCodeInvalid(ctx context.Context) *CourierEmailTemplate { - return p.CourierTemplatesHelper(ctx, ViperKeyCourierTemplatesRecoveryCodeInvalidEmail) + return p.CourierEmailTemplatesHelper(ctx, ViperKeyCourierTemplatesRecoveryCodeInvalidEmail) } func (p *Config) CourierTemplatesRecoveryCodeValid(ctx context.Context) *CourierEmailTemplate { - return p.CourierTemplatesHelper(ctx, ViperKeyCourierTemplatesRecoveryCodeValidEmail) + return p.CourierEmailTemplatesHelper(ctx, ViperKeyCourierTemplatesRecoveryCodeValidEmail) } func (p *Config) CourierTemplatesVerificationCodeInvalid(ctx context.Context) *CourierEmailTemplate { - return p.CourierTemplatesHelper(ctx, ViperKeyCourierTemplatesVerificationCodeInvalidEmail) + return p.CourierEmailTemplatesHelper(ctx, ViperKeyCourierTemplatesVerificationCodeInvalidEmail) } func (p *Config) CourierTemplatesVerificationCodeValid(ctx context.Context) *CourierEmailTemplate { - return p.CourierTemplatesHelper(ctx, ViperKeyCourierTemplatesVerificationCodeValidEmail) + return p.CourierEmailTemplatesHelper(ctx, ViperKeyCourierTemplatesVerificationCodeValidEmail) +} + +func (p *Config) CourierSMSTemplatesVerificationCodeValid(ctx context.Context) *CourierSMSTemplate { + return p.CourierSMSTemplatesHelper(ctx, ViperKeyCourierTemplatesVerificationCodeValidEmail) } func (p *Config) CourierTemplatesLoginCodeValid(ctx context.Context) *CourierEmailTemplate { - return p.CourierTemplatesHelper(ctx, ViperKeyCourierTemplatesLoginCodeValidEmail) + return p.CourierEmailTemplatesHelper(ctx, ViperKeyCourierTemplatesLoginCodeValidEmail) } func (p *Config) CourierTemplatesRegistrationCodeValid(ctx context.Context) *CourierEmailTemplate { - return p.CourierTemplatesHelper(ctx, ViperKeyCourierTemplatesRegistrationCodeValidEmail) + return p.CourierEmailTemplatesHelper(ctx, ViperKeyCourierTemplatesRegistrationCodeValidEmail) } func (p *Config) CourierMessageRetries(ctx context.Context) int { @@ -1128,25 +1139,40 @@ func (p *Config) CourierSMTPHeaders(ctx context.Context) map[string]string { return p.GetProvider(ctx).StringMap(ViperKeyCourierSMTPHeaders) } -func (p *Config) CourierSMSRequestConfig(ctx context.Context) json.RawMessage { - if !p.GetProvider(ctx).Bool(ViperKeyCourierSMSEnabled) { - return nil +func (p *Config) CourierChannels(ctx context.Context) (ccs []*CourierChannel, _ error) { + if err := p.GetProvider(ctx).Koanf.Unmarshal(ViperKeyCourierChannels, &ccs); err != nil { + return nil, errors.WithStack(err) } - - config, err := json.Marshal(p.GetProvider(ctx).Get(ViperKeyCourierSMSRequestConfig)) - if err != nil { - p.l.WithError(err).Warn("Unable to marshal SMS request configuration.") - return json.RawMessage("{}") + if len(ccs) != 0 { + for _, c := range ccs { + if c.RequestConfigRaw != nil { + var err error + c.RequestConfig, err = json.Marshal(c.RequestConfigRaw) + if err != nil { + return nil, errors.WithStack(err) + } + } + } + return ccs, nil } - return config -} -func (p *Config) CourierSMSFrom(ctx context.Context) string { - return p.GetProvider(ctx).StringF(ViperKeyCourierSMSFrom, "Ory Kratos") -} - -func (p *Config) CourierSMSEnabled(ctx context.Context) bool { - return p.GetProvider(ctx).Bool(ViperKeyCourierSMSEnabled) + // load legacy configs + channel := CourierChannel{ + ID: "email", + Type: p.CourierEmailStrategy(ctx), + } + if channel.Type == "smtp" { + if err := p.GetProvider(ctx).Koanf.Unmarshal(ViperKeyCourierSMTP, &channel.SMTPConfig); err != nil { + return nil, errors.WithStack(err) + } + } else { + var err error + channel.RequestConfig, err = json.Marshal(p.GetProvider(ctx).Get(ViperKeyCourierHTTPRequestConfig)) + if err != nil { + return nil, errors.WithStack(err) + } + } + return []*CourierChannel{&channel}, nil } func splitUrlAndFragment(s string) (string, string) { diff --git a/driver/config/config_test.go b/driver/config/config_test.go index 602a4971a74e..38e3a01fd055 100644 --- a/driver/config/config_test.go +++ b/driver/config/config_test.go @@ -1149,53 +1149,47 @@ func TestCourierEmailHTTP(t *testing.T) { }) } -func TestCourierSMS(t *testing.T) { +func TestCourierChannels(t *testing.T) { t.Parallel() ctx := context.Background() - t.Run("case=configs set", func(t *testing.T) { - conf, _ := config.New(ctx, logrusx.New("", ""), os.Stderr, - configx.WithConfigFiles("stub/.kratos.courier.sms.yaml"), configx.SkipValidation()) - assert.True(t, conf.CourierSMSEnabled(ctx)) - snapshotx.SnapshotTExcept(t, conf.CourierSMSRequestConfig(ctx), nil) - assert.Equal(t, "+49123456789", conf.CourierSMSFrom(ctx)) + conf, _ := config.New(ctx, logrusx.New("", ""), os.Stderr, configx.WithConfigFiles("stub/.kratos.courier.channels.yaml"), configx.SkipValidation()) + + channelConfig, err := conf.CourierChannels(ctx) + require.NoError(t, err) + require.Len(t, channelConfig, 1) + assert.Equal(t, channelConfig[0].ID, "phone") + assert.NotEmpty(t, channelConfig[0].RequestConfig) }) t.Run("case=defaults", func(t *testing.T) { conf, _ := config.New(ctx, logrusx.New("", ""), os.Stderr, configx.SkipValidation()) - assert.False(t, conf.CourierSMSEnabled(ctx)) - snapshotx.SnapshotTExcept(t, conf.CourierSMSRequestConfig(ctx), nil) - assert.Equal(t, "Ory Kratos", conf.CourierSMSFrom(ctx)) + channelConfig, err := conf.CourierChannels(ctx) + require.NoError(t, err) + assert.Len(t, channelConfig, 1) + assert.Equal(t, channelConfig[0].ID, "email") + assert.Equal(t, channelConfig[0].Type, "smtp") }) -} - -func TestCourierSMTPUrl(t *testing.T) { - t.Parallel() - ctx := context.Background() - for _, tc := range []string{ - "smtp://a:basdasdasda%2Fc@email-smtp.eu-west-3.amazonaws.com:587/", - "smtp://a:b$c@email-smtp.eu-west-3.amazonaws.com:587/", - "smtp://a/a:bc@email-smtp.eu-west-3.amazonaws.com:587", - "smtp://aa:b+c@email-smtp.eu-west-3.amazonaws.com:587/", - "smtp://user?name:password@email-smtp.eu-west-3.amazonaws.com:587/", - "smtp://username:pass%2Fword@email-smtp.eu-west-3.amazonaws.com:587/", - } { - t.Run("case="+tc, func(t *testing.T) { - conf, err := config.New(ctx, logrusx.New("", ""), os.Stderr, configx.WithValue(config.ViperKeyCourierSMTPURL, tc), configx.SkipValidation()) - require.NoError(t, err) - parsed, err := conf.CourierSMTPURL(ctx) - require.NoError(t, err) - assert.Equal(t, tc, parsed.String()) - }) - } - - t.Run("invalid", func(t *testing.T) { - conf, err := config.New(ctx, logrusx.New("", ""), os.Stderr, configx.WithValue(config.ViperKeyCourierSMTPURL, "smtp://a:b/c@email-smtp.eu-west-3.amazonaws.com:587/"), configx.SkipValidation()) - require.NoError(t, err) - _, err = conf.CourierSMTPURL(ctx) - require.Error(t, err) + t.Run("smtp urls", func(t *testing.T) { + for _, tc := range []string{ + "smtp://a:basdasdasda%2Fc@email-smtp.eu-west-3.amazonaws.com:587/", + "smtp://a:b$c@email-smtp.eu-west-3.amazonaws.com:587/", + "smtp://a/a:bc@email-smtp.eu-west-3.amazonaws.com:587", + "smtp://aa:b+c@email-smtp.eu-west-3.amazonaws.com:587/", + "smtp://user?name:password@email-smtp.eu-west-3.amazonaws.com:587/", + "smtp://username:pass%2Fword@email-smtp.eu-west-3.amazonaws.com:587/", + } { + t.Run("case="+tc, func(t *testing.T) { + conf, err := config.New(ctx, logrusx.New("", ""), os.Stderr, configx.WithValue(config.ViperKeyCourierSMTPURL, tc), configx.SkipValidation()) + require.NoError(t, err) + cs, err := conf.CourierChannels(ctx) + require.NoError(t, err) + require.Len(t, cs, 1) + assert.Equal(t, tc, cs[0].SMTPConfig.ConnectionURI) + }) + } }) } @@ -1311,10 +1305,10 @@ func TestCourierTemplatesConfig(t *testing.T) { Subject: "", } - assert.Equal(t, courierTemplateConfig, c.CourierTemplatesHelper(ctx, config.ViperKeyCourierTemplatesVerificationInvalidEmail)) - assert.Equal(t, courierTemplateConfig, c.CourierTemplatesHelper(ctx, config.ViperKeyCourierTemplatesVerificationValidEmail)) + assert.Equal(t, courierTemplateConfig, c.CourierEmailTemplatesHelper(ctx, config.ViperKeyCourierTemplatesVerificationInvalidEmail)) + assert.Equal(t, courierTemplateConfig, c.CourierEmailTemplatesHelper(ctx, config.ViperKeyCourierTemplatesVerificationValidEmail)) // this should return an empty courierEmailTemplate as the key does not exist - assert.Equal(t, courierTemplateConfig, c.CourierTemplatesHelper(ctx, "a_random_key")) + assert.Equal(t, courierTemplateConfig, c.CourierEmailTemplatesHelper(ctx, "a_random_key")) courierTemplateConfig = &config.CourierEmailTemplate{ Body: &config.CourierEmailBodyTemplate{ @@ -1323,7 +1317,7 @@ func TestCourierTemplatesConfig(t *testing.T) { }, Subject: "base64://QWNjb3VudCBBY2Nlc3MgQXR0ZW1wdGVk", } - assert.Equal(t, courierTemplateConfig, c.CourierTemplatesHelper(ctx, config.ViperKeyCourierTemplatesRecoveryInvalidEmail)) + assert.Equal(t, courierTemplateConfig, c.CourierEmailTemplatesHelper(ctx, config.ViperKeyCourierTemplatesRecoveryInvalidEmail)) courierTemplateConfig = &config.CourierEmailTemplate{ Body: &config.CourierEmailBodyTemplate{ @@ -1332,7 +1326,7 @@ func TestCourierTemplatesConfig(t *testing.T) { }, Subject: "base64://UmVjb3ZlciBhY2Nlc3MgdG8geW91ciBhY2NvdW50", } - assert.Equal(t, courierTemplateConfig, c.CourierTemplatesHelper(ctx, config.ViperKeyCourierTemplatesRecoveryValidEmail)) + assert.Equal(t, courierTemplateConfig, c.CourierEmailTemplatesHelper(ctx, config.ViperKeyCourierTemplatesRecoveryValidEmail)) }) } diff --git a/driver/config/stub/.kratos.courier.channels.yaml b/driver/config/stub/.kratos.courier.channels.yaml new file mode 100644 index 000000000000..9f4cdcd6de94 --- /dev/null +++ b/driver/config/stub/.kratos.courier.channels.yaml @@ -0,0 +1,14 @@ +courier: + channels: + - id: phone + request_config: + url: https://ory.sh + method: GET + body: base64://ZnVuY3Rpb24oY3R4KSB7CkJvZHk6IGN0eC5ib2R5LApUbzogY3R4LnRvLEZyb206IGN0eC5mcm9tCn0= + headers: + Content-Type: application/x-www-form-urlencoded + auth: + type: basic_auth + config: + user: ABC + password: DEF diff --git a/embedx/config.schema.json b/embedx/config.schema.json index b8d767ef179a..41a7ff4d24bf 100644 --- a/embedx/config.schema.json +++ b/embedx/config.schema.json @@ -1034,12 +1034,36 @@ "properties": { "email": { "$ref": "#/definitions/emailCourierTemplate" + }, + "sms": { + "$ref": "#/definitions/smsCourierTemplate" } }, "required": ["email"] } } }, + "smsCourierTemplate": { + "additionalProperties": false, + "type": "object", + "properties": { + "body": { + "additionalProperties": false, + "type": "object", + "properties": { + "plaintext": { + "type": "string", + "description": "A template send to the SMS provider.", + "format": "uri", + "examples": [ + "file://path/to/body.plaintext.gotmpl", + "https://foo.bar.com/path/to/body.plaintext.gotmpl" + ] + } + } + } + } + }, "emailCourierTemplate": { "additionalProperties": false, "type": "object", @@ -1963,9 +1987,29 @@ } }, "additionalProperties": false + }, + "channels": { + "type": "array", + "items": { + "title": "Courier channel configuration", + "type": "object", + "properties": { + "id": { + "type": "string", + "title": "Channel id", + "description": "The channel id. Corresponds to the .via property of the identity schema for recovery, verification, etc. Currently only phone is supported.", + "maxLength": 32, + "enum": ["phone"] + }, + "request_config": { + "$ref": "#/definitions/httpRequestConfig" + } + }, + "required": ["id", "request_config"], + "additionalProperties": false + } } }, - "required": ["smtp"], "additionalProperties": false }, "oauth2_provider": { diff --git a/identity/extension_credentials.go b/identity/extension_credentials.go index 69fb53810fbc..88823ee8a226 100644 --- a/identity/extension_credentials.go +++ b/identity/extension_credentials.go @@ -63,13 +63,13 @@ func (r *SchemaExtensionCredentials) Run(ctx jsonschema.ValidationContext, s sch return ctx.Error("format", "%q is not a valid %q", value, s.Credentials.Code.Via) } - r.setIdentifier(CredentialsTypeCodeAuth, value, AddressTypeEmail) + r.setIdentifier(CredentialsTypeCodeAuth, value, CredentialsIdentifierAddressTypeEmail) // case f.AddCase(AddressTypePhone): // if !jsonschema.Formats["tel"](value) { // return ctx.Error("format", "%q is not a valid %q", value, s.Credentials.Code.Via) // } - // - // r.setIdentifier(CredentialsTypeCodeAuth, value, CredentialsIdentifierAddressType(AddressTypePhone)) + + // r.setIdentifier(CredentialsTypeCodeAuth, value, CredentialsIdentifierAddressTypePhone) default: return ctx.Error("", "credentials.code.via has unknown value %q", s.Credentials.Code.Via) } diff --git a/identity/extension_verify.go b/identity/extension_verification.go similarity index 100% rename from identity/extension_verify.go rename to identity/extension_verification.go diff --git a/identity/extension_verify_test.go b/identity/extension_verification_test.go similarity index 100% rename from identity/extension_verify_test.go rename to identity/extension_verification_test.go diff --git a/internal/client-go/model_message.go b/internal/client-go/model_message.go index f0452185f169..405575779c78 100644 --- a/internal/client-go/model_message.go +++ b/internal/client-go/model_message.go @@ -18,7 +18,8 @@ import ( // Message struct for Message type Message struct { - Body string `json:"body"` + Body string `json:"body"` + Channel *string `json:"channel,omitempty"` // CreatedAt is a helper struct field for gobuffalo.pop. CreatedAt time.Time `json:"created_at"` // Dispatches store information about the attempts of delivering a message May contain an error if any happened, or just the `success` state. @@ -28,7 +29,7 @@ type Message struct { SendCount int64 `json:"send_count"` Status CourierMessageStatus `json:"status"` Subject string `json:"subject"` - // recovery_invalid TypeRecoveryInvalid recovery_valid TypeRecoveryValid recovery_code_invalid TypeRecoveryCodeInvalid recovery_code_valid TypeRecoveryCodeValid verification_invalid TypeVerificationInvalid verification_valid TypeVerificationValid verification_code_invalid TypeVerificationCodeInvalid verification_code_valid TypeVerificationCodeValid otp TypeOTP stub TypeTestStub login_code_valid TypeLoginCodeValid registration_code_valid TypeRegistrationCodeValid + // recovery_invalid TypeRecoveryInvalid recovery_valid TypeRecoveryValid recovery_code_invalid TypeRecoveryCodeInvalid recovery_code_valid TypeRecoveryCodeValid verification_invalid TypeVerificationInvalid verification_valid TypeVerificationValid verification_code_invalid TypeVerificationCodeInvalid verification_code_valid TypeVerificationCodeValid stub TypeTestStub login_code_valid TypeLoginCodeValid registration_code_valid TypeRegistrationCodeValid TemplateType string `json:"template_type"` Type CourierMessageType `json:"type"` // UpdatedAt is a helper struct field for gobuffalo.pop. @@ -86,6 +87,38 @@ func (o *Message) SetBody(v string) { o.Body = v } +// GetChannel returns the Channel field value if set, zero value otherwise. +func (o *Message) GetChannel() string { + if o == nil || o.Channel == nil { + var ret string + return ret + } + return *o.Channel +} + +// GetChannelOk returns a tuple with the Channel field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *Message) GetChannelOk() (*string, bool) { + if o == nil || o.Channel == nil { + return nil, false + } + return o.Channel, true +} + +// HasChannel returns a boolean if a field has been set. +func (o *Message) HasChannel() bool { + if o != nil && o.Channel != nil { + return true + } + + return false +} + +// SetChannel gets a reference to the given string and assigns it to the Channel field. +func (o *Message) SetChannel(v string) { + o.Channel = &v +} + // GetCreatedAt returns the CreatedAt field value func (o *Message) GetCreatedAt() time.Time { if o == nil { @@ -339,6 +372,9 @@ func (o Message) MarshalJSON() ([]byte, error) { if true { toSerialize["body"] = o.Body } + if o.Channel != nil { + toSerialize["channel"] = o.Channel + } if true { toSerialize["created_at"] = o.CreatedAt } diff --git a/internal/httpclient/model_message.go b/internal/httpclient/model_message.go index f0452185f169..405575779c78 100644 --- a/internal/httpclient/model_message.go +++ b/internal/httpclient/model_message.go @@ -18,7 +18,8 @@ import ( // Message struct for Message type Message struct { - Body string `json:"body"` + Body string `json:"body"` + Channel *string `json:"channel,omitempty"` // CreatedAt is a helper struct field for gobuffalo.pop. CreatedAt time.Time `json:"created_at"` // Dispatches store information about the attempts of delivering a message May contain an error if any happened, or just the `success` state. @@ -28,7 +29,7 @@ type Message struct { SendCount int64 `json:"send_count"` Status CourierMessageStatus `json:"status"` Subject string `json:"subject"` - // recovery_invalid TypeRecoveryInvalid recovery_valid TypeRecoveryValid recovery_code_invalid TypeRecoveryCodeInvalid recovery_code_valid TypeRecoveryCodeValid verification_invalid TypeVerificationInvalid verification_valid TypeVerificationValid verification_code_invalid TypeVerificationCodeInvalid verification_code_valid TypeVerificationCodeValid otp TypeOTP stub TypeTestStub login_code_valid TypeLoginCodeValid registration_code_valid TypeRegistrationCodeValid + // recovery_invalid TypeRecoveryInvalid recovery_valid TypeRecoveryValid recovery_code_invalid TypeRecoveryCodeInvalid recovery_code_valid TypeRecoveryCodeValid verification_invalid TypeVerificationInvalid verification_valid TypeVerificationValid verification_code_invalid TypeVerificationCodeInvalid verification_code_valid TypeVerificationCodeValid stub TypeTestStub login_code_valid TypeLoginCodeValid registration_code_valid TypeRegistrationCodeValid TemplateType string `json:"template_type"` Type CourierMessageType `json:"type"` // UpdatedAt is a helper struct field for gobuffalo.pop. @@ -86,6 +87,38 @@ func (o *Message) SetBody(v string) { o.Body = v } +// GetChannel returns the Channel field value if set, zero value otherwise. +func (o *Message) GetChannel() string { + if o == nil || o.Channel == nil { + var ret string + return ret + } + return *o.Channel +} + +// GetChannelOk returns a tuple with the Channel field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *Message) GetChannelOk() (*string, bool) { + if o == nil || o.Channel == nil { + return nil, false + } + return o.Channel, true +} + +// HasChannel returns a boolean if a field has been set. +func (o *Message) HasChannel() bool { + if o != nil && o.Channel != nil { + return true + } + + return false +} + +// SetChannel gets a reference to the given string and assigns it to the Channel field. +func (o *Message) SetChannel(v string) { + o.Channel = &v +} + // GetCreatedAt returns the CreatedAt field value func (o *Message) GetCreatedAt() time.Time { if o == nil { @@ -339,6 +372,9 @@ func (o Message) MarshalJSON() ([]byte, error) { if true { toSerialize["body"] = o.Body } + if o.Channel != nil { + toSerialize["channel"] = o.Channel + } if true { toSerialize["created_at"] = o.CreatedAt } diff --git a/persistence/sql/migrations/sql/20231130094628000000_courier_message_channel.down.sql b/persistence/sql/migrations/sql/20231130094628000000_courier_message_channel.down.sql new file mode 100644 index 000000000000..a43df5063cec --- /dev/null +++ b/persistence/sql/migrations/sql/20231130094628000000_courier_message_channel.down.sql @@ -0,0 +1,2 @@ +ALTER TABLE + courier_messages DROP column channel; diff --git a/persistence/sql/migrations/sql/20231130094628000000_courier_message_channel.up.sql b/persistence/sql/migrations/sql/20231130094628000000_courier_message_channel.up.sql new file mode 100644 index 000000000000..a4075c0eecba --- /dev/null +++ b/persistence/sql/migrations/sql/20231130094628000000_courier_message_channel.up.sql @@ -0,0 +1,4 @@ +ALTER TABLE + courier_messages +ADD + column channel VARCHAR(32) NULL; \ No newline at end of file diff --git a/persistence/sql/persister.go b/persistence/sql/persister.go index 82df92a72314..fa553cd559f5 100644 --- a/persistence/sql/persister.go +++ b/persistence/sql/persister.go @@ -13,7 +13,7 @@ import ( "github.com/gofrs/uuid" "github.com/laher/mergefs" "github.com/pkg/errors" - "github.com/sirupsen/logrus/hooks/test" + "github.com/sirupsen/logrus" "github.com/ory/kratos/driver/config" "github.com/ory/kratos/identity" @@ -24,7 +24,6 @@ import ( "github.com/ory/kratos/session" "github.com/ory/kratos/x" "github.com/ory/x/contextx" - "github.com/ory/x/logrusx" "github.com/ory/x/networkx" "github.com/ory/x/popx" ) @@ -82,8 +81,7 @@ func NewPersister(ctx context.Context, r persisterDependencies, c *pop.Connectio } logger := r.Logger() if o.disableLogging { - inner, _ := test.NewNullLogger() - logger = logrusx.New("kratos", "", logrusx.UseLogger(inner)) + logger.Logrus().SetLevel(logrus.WarnLevel) } m, err := popx.NewMigrationBox( mergefs.Merge( diff --git a/selfservice/strategy/code/code_sender.go b/selfservice/strategy/code/code_sender.go index 3317fafdb2e4..9f98f183b589 100644 --- a/selfservice/strategy/code/code_sender.go +++ b/selfservice/strategy/code/code_sender.go @@ -13,6 +13,7 @@ import ( "github.com/ory/herodot" "github.com/ory/kratos/courier/template/email" + "github.com/ory/kratos/courier/template/sms" "github.com/ory/x/httpx" "github.com/ory/x/sqlcon" @@ -312,20 +313,35 @@ func (s *Sender) SendVerificationCodeTo(ctx context.Context, f *verification.Flo return err } - if err := s.send(ctx, string(code.VerifiableAddress.Via), email.NewVerificationCodeValid(s.deps, - &email.VerificationCodeValidModel{ + var t courier.Template + + // TODO: this can likely be abstracted by making templates not specific to the channel they're using + switch code.VerifiableAddress.Via { + case identity.AddressTypeEmail: + t = email.NewVerificationCodeValid(s.deps, &email.VerificationCodeValidModel{ To: code.VerifiableAddress.Value, VerificationURL: s.constructVerificationLink(ctx, f.ID, codeString), Identity: model, VerificationCode: codeString, - })); err != nil { + }) + case identity.AddressTypePhone: + t = sms.NewVerificationCodeValid(s.deps, &sms.VerificationCodeValidModel{ + To: code.VerifiableAddress.Value, + VerificationCode: codeString, + Identity: model, + }) + default: + return errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Expected email or phone but got %s", code.VerifiableAddress.Via)) + } + + if err := s.send(ctx, string(code.VerifiableAddress.Via), t); err != nil { return err } code.VerifiableAddress.Status = identity.VerifiableAddressStatusSent return s.deps.PrivilegedIdentityPool().UpdateVerifiableAddress(ctx, code.VerifiableAddress) } -func (s *Sender) send(ctx context.Context, via string, t courier.EmailTemplate) error { +func (s *Sender) send(ctx context.Context, via string, t courier.Template) error { switch f := stringsx.SwitchExact(via); { case f.AddCase(identity.AddressTypeEmail): c, err := s.deps.Courier(ctx) @@ -333,8 +349,26 @@ func (s *Sender) send(ctx context.Context, via string, t courier.EmailTemplate) return err } + t, ok := t.(courier.EmailTemplate) + if !ok { + return errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Expected email template but got %T", t)) + } + _, err = c.QueueEmail(ctx, t) return err + case f.AddCase(identity.AddressTypePhone): + c, err := s.deps.Courier(ctx) + if err != nil { + return err + } + + t, ok := t.(courier.SMSTemplate) + if !ok { + return errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Expected sms template but got %T", t)) + } + + _, err = c.QueueSMS(ctx, t) + return err default: return f.ToUnknownCaseErr() } diff --git a/spec/api.json b/spec/api.json index ca83970d1da2..e17cb5dbd4d2 100644 --- a/spec/api.json +++ b/spec/api.json @@ -1387,6 +1387,9 @@ "body": { "type": "string" }, + "channel": { + "type": "string" + }, "created_at": { "description": "CreatedAt is a helper struct field for gobuffalo.pop.", "format": "date-time", @@ -1417,7 +1420,7 @@ "type": "string" }, "template_type": { - "description": "\nrecovery_invalid TypeRecoveryInvalid\nrecovery_valid TypeRecoveryValid\nrecovery_code_invalid TypeRecoveryCodeInvalid\nrecovery_code_valid TypeRecoveryCodeValid\nverification_invalid TypeVerificationInvalid\nverification_valid TypeVerificationValid\nverification_code_invalid TypeVerificationCodeInvalid\nverification_code_valid TypeVerificationCodeValid\notp TypeOTP\nstub TypeTestStub\nlogin_code_valid TypeLoginCodeValid\nregistration_code_valid TypeRegistrationCodeValid", + "description": "\nrecovery_invalid TypeRecoveryInvalid\nrecovery_valid TypeRecoveryValid\nrecovery_code_invalid TypeRecoveryCodeInvalid\nrecovery_code_valid TypeRecoveryCodeValid\nverification_invalid TypeVerificationInvalid\nverification_valid TypeVerificationValid\nverification_code_invalid TypeVerificationCodeInvalid\nverification_code_valid TypeVerificationCodeValid\nstub TypeTestStub\nlogin_code_valid TypeLoginCodeValid\nregistration_code_valid TypeRegistrationCodeValid", "enum": [ "recovery_invalid", "recovery_valid", @@ -1427,13 +1430,12 @@ "verification_valid", "verification_code_invalid", "verification_code_valid", - "otp", "stub", "login_code_valid", "registration_code_valid" ], "type": "string", - "x-go-enum-desc": "recovery_invalid TypeRecoveryInvalid\nrecovery_valid TypeRecoveryValid\nrecovery_code_invalid TypeRecoveryCodeInvalid\nrecovery_code_valid TypeRecoveryCodeValid\nverification_invalid TypeVerificationInvalid\nverification_valid TypeVerificationValid\nverification_code_invalid TypeVerificationCodeInvalid\nverification_code_valid TypeVerificationCodeValid\notp TypeOTP\nstub TypeTestStub\nlogin_code_valid TypeLoginCodeValid\nregistration_code_valid TypeRegistrationCodeValid" + "x-go-enum-desc": "recovery_invalid TypeRecoveryInvalid\nrecovery_valid TypeRecoveryValid\nrecovery_code_invalid TypeRecoveryCodeInvalid\nrecovery_code_valid TypeRecoveryCodeValid\nverification_invalid TypeVerificationInvalid\nverification_valid TypeVerificationValid\nverification_code_invalid TypeVerificationCodeInvalid\nverification_code_valid TypeVerificationCodeValid\nstub TypeTestStub\nlogin_code_valid TypeLoginCodeValid\nregistration_code_valid TypeRegistrationCodeValid" }, "type": { "$ref": "#/components/schemas/courierMessageType" diff --git a/spec/swagger.json b/spec/swagger.json index 3b2b0eece6aa..67217a74c9f7 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -4458,6 +4458,9 @@ "body": { "type": "string" }, + "channel": { + "type": "string" + }, "created_at": { "description": "CreatedAt is a helper struct field for gobuffalo.pop.", "type": "string", @@ -4488,7 +4491,7 @@ "type": "string" }, "template_type": { - "description": "\nrecovery_invalid TypeRecoveryInvalid\nrecovery_valid TypeRecoveryValid\nrecovery_code_invalid TypeRecoveryCodeInvalid\nrecovery_code_valid TypeRecoveryCodeValid\nverification_invalid TypeVerificationInvalid\nverification_valid TypeVerificationValid\nverification_code_invalid TypeVerificationCodeInvalid\nverification_code_valid TypeVerificationCodeValid\notp TypeOTP\nstub TypeTestStub\nlogin_code_valid TypeLoginCodeValid\nregistration_code_valid TypeRegistrationCodeValid", + "description": "\nrecovery_invalid TypeRecoveryInvalid\nrecovery_valid TypeRecoveryValid\nrecovery_code_invalid TypeRecoveryCodeInvalid\nrecovery_code_valid TypeRecoveryCodeValid\nverification_invalid TypeVerificationInvalid\nverification_valid TypeVerificationValid\nverification_code_invalid TypeVerificationCodeInvalid\nverification_code_valid TypeVerificationCodeValid\nstub TypeTestStub\nlogin_code_valid TypeLoginCodeValid\nregistration_code_valid TypeRegistrationCodeValid", "type": "string", "enum": [ "recovery_invalid", @@ -4499,12 +4502,11 @@ "verification_valid", "verification_code_invalid", "verification_code_valid", - "otp", "stub", "login_code_valid", "registration_code_valid" ], - "x-go-enum-desc": "recovery_invalid TypeRecoveryInvalid\nrecovery_valid TypeRecoveryValid\nrecovery_code_invalid TypeRecoveryCodeInvalid\nrecovery_code_valid TypeRecoveryCodeValid\nverification_invalid TypeVerificationInvalid\nverification_valid TypeVerificationValid\nverification_code_invalid TypeVerificationCodeInvalid\nverification_code_valid TypeVerificationCodeValid\notp TypeOTP\nstub TypeTestStub\nlogin_code_valid TypeLoginCodeValid\nregistration_code_valid TypeRegistrationCodeValid" + "x-go-enum-desc": "recovery_invalid TypeRecoveryInvalid\nrecovery_valid TypeRecoveryValid\nrecovery_code_invalid TypeRecoveryCodeInvalid\nrecovery_code_valid TypeRecoveryCodeValid\nverification_invalid TypeVerificationInvalid\nverification_valid TypeVerificationValid\nverification_code_invalid TypeVerificationCodeInvalid\nverification_code_valid TypeVerificationCodeValid\nstub TypeTestStub\nlogin_code_valid TypeLoginCodeValid\nregistration_code_valid TypeRegistrationCodeValid" }, "type": { "$ref": "#/definitions/courierMessageType" From 699e5d59a0198846f45b4e951cf07a862cbc1e25 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Thu, 28 Dec 2023 16:19:33 +0000 Subject: [PATCH 221/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index deb347222e88..489f8d969076 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -723,6 +723,9 @@ https://github.com/ory/kratos/pull/3480 - Add OpenTelemetry span for password hash comparison ([#3383](https://github.com/ory/kratos/issues/3383)) ([e3fcf0c](https://github.com/ory/kratos/commit/e3fcf0c31db9742ed61bcf783e37ee119ed19d42)) +- Add sms verification for phone numbers + ([#3649](https://github.com/ory/kratos/issues/3649)) + ([e3a3c4f](https://github.com/ory/kratos/commit/e3a3c4fe0d6697f6864283daf4be8a8f8971c7b4)) - Add support for recovery on native flows ([#3273](https://github.com/ory/kratos/issues/3273)) ([e363889](https://github.com/ory/kratos/commit/e363889732c0a1cb801fd12b2e0e8546006e9714)) From eb8d1b9abd6d2b3eb86ab11d48d9ebd059586b67 Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Fri, 5 Jan 2024 14:07:33 +0100 Subject: [PATCH 222/282] fix: rename "phone" courier channel to "sms" (#3680) Co-authored-by: zepatrik --- .../phone-password/identity.schema.json | 2 +- .../kratos/phone-password/kratos.yml | 5 +- courier/http_channel.go | 10 +-- driver/config/config.go | 2 +- embedx/config.schema.json | 8 +- embedx/embedx_test.go | 39 +++++++++- embedx/identity_extension.schema.json | 2 +- embedx/identity_meta.schema.json | 34 +++++++-- ...dentity_meta.no_traits.invalid.schema.json | 1 + .../identity_meta.simple.valid.schema.json | 23 ++++++ ...ta.verification_format.invalid.schema.json | 23 ++++++ identity/address.go | 1 - identity/credentials.go | 9 --- identity/credentials_code.go | 1 - identity/extension_credentials.go | 8 +- identity/extension_verification.go | 71 +++++++++++------ identity/extension_verification_test.go | 76 ++++++++++++++----- identity/identity_verification.go | 31 ++------ identity/pool.go | 2 +- .../legacy-email-missing-format.schema.json | 13 ++++ .../verify/missing-format.schema.json | 13 ++++ .../extension/verify/no-validate.schema.json | 14 ++++ .../stub/extension/verify/phone.schema.json | 6 +- .../model_verifiable_identity_address.go | 2 +- .../model_verifiable_identity_address.go | 2 +- .../sql/identity/persister_identity.go | 2 +- request/builder.go | 8 +- schema/extension.go | 4 +- selfservice/strategy/code/code_sender.go | 12 +-- spec/api.json | 12 +-- spec/swagger.json | 12 +-- 31 files changed, 321 insertions(+), 127 deletions(-) create mode 100644 embedx/testdata/identity_meta.no_traits.invalid.schema.json create mode 100644 embedx/testdata/identity_meta.simple.valid.schema.json create mode 100644 embedx/testdata/identity_meta.verification_format.invalid.schema.json create mode 100644 identity/stub/extension/verify/legacy-email-missing-format.schema.json create mode 100644 identity/stub/extension/verify/missing-format.schema.json create mode 100644 identity/stub/extension/verify/no-validate.schema.json diff --git a/contrib/quickstart/kratos/phone-password/identity.schema.json b/contrib/quickstart/kratos/phone-password/identity.schema.json index 3d1f190d5521..0d986aeb672e 100644 --- a/contrib/quickstart/kratos/phone-password/identity.schema.json +++ b/contrib/quickstart/kratos/phone-password/identity.schema.json @@ -19,7 +19,7 @@ } }, "verification": { - "via": "phone" + "via": "sms" } } } diff --git a/contrib/quickstart/kratos/phone-password/kratos.yml b/contrib/quickstart/kratos/phone-password/kratos.yml index 927b61453070..88ee01bc84e6 100644 --- a/contrib/quickstart/kratos/phone-password/kratos.yml +++ b/contrib/quickstart/kratos/phone-password/kratos.yml @@ -96,11 +96,12 @@ identity: courier: channels: - - id: phone + - id: sms + type: http request_config: url: https://api.twilio.com/2010-04-01/Accounts/AXXXXXXXXXXXXXX/Messages.json method: POST - body: base64://ZnVuY3Rpb24oY3R4KSB7CkJvZHk6IGN0eC5ib2R5LApUbzogY3R4LnRvLEZyb206IGN0eC5mcm9tCn0= + body: base64://ZnVuY3Rpb24oY3R4KSB7ClRvOiBjdHguUmVjaXBpZW50LApCb2R5OiBjdHguQm9keSwKfQ== headers: Content-Type: application/x-www-form-urlencoded auth: diff --git a/courier/http_channel.go b/courier/http_channel.go index 67b917dd8841..41315f33e067 100644 --- a/courier/http_channel.go +++ b/courier/http_channel.go @@ -61,12 +61,12 @@ func (c *httpChannel) Dispatch(ctx context.Context, msg Message) (err error) { builder, err := request.NewBuilder(ctx, c.requestConfig, c.d) if err != nil { - return err + return errors.WithStack(err) } tmpl, err := newTemplate(c.d, msg) if err != nil { - return err + return errors.WithStack(err) } td := httpDataModel{ @@ -80,12 +80,12 @@ func (c *httpChannel) Dispatch(ctx context.Context, msg Message) (err error) { req, err := builder.BuildRequest(ctx, td) if err != nil { - return err + return errors.WithStack(err) } res, err := c.d.HTTPClient(ctx).Do(req) if err != nil { - return err + return errors.WithStack(err) } if res.StatusCode >= 200 && res.StatusCode < 300 { @@ -109,7 +109,7 @@ func (c *httpChannel) Dispatch(ctx context.Context, msg Message) (err error) { WithField("message_subject", msg.Subject). WithError(err). Error("sending mail via HTTP failed.") - return err + return errors.WithStack(err) } func newTemplate(d template.Dependencies, msg Message) (Template, error) { diff --git a/driver/config/config.go b/driver/config/config.go index 8162ea39bc37..35d33ee8316a 100644 --- a/driver/config/config.go +++ b/driver/config/config.go @@ -1112,7 +1112,7 @@ func (p *Config) CourierTemplatesVerificationCodeValid(ctx context.Context) *Cou } func (p *Config) CourierSMSTemplatesVerificationCodeValid(ctx context.Context) *CourierSMSTemplate { - return p.CourierSMSTemplatesHelper(ctx, ViperKeyCourierTemplatesVerificationCodeValidEmail) + return p.CourierSMSTemplatesHelper(ctx, ViperKeyCourierTemplatesVerificationCodeValidSMS) } func (p *Config) CourierTemplatesLoginCodeValid(ctx context.Context) *CourierEmailTemplate { diff --git a/embedx/config.schema.json b/embedx/config.schema.json index 41a7ff4d24bf..a42568389fe7 100644 --- a/embedx/config.schema.json +++ b/embedx/config.schema.json @@ -1999,7 +1999,13 @@ "title": "Channel id", "description": "The channel id. Corresponds to the .via property of the identity schema for recovery, verification, etc. Currently only phone is supported.", "maxLength": 32, - "enum": ["phone"] + "enum": ["sms"] + }, + "type": { + "type": "string", + "title": "Channel type", + "description": "The channel type. Currently only http is supported.", + "enum": ["http"] }, "request_config": { "$ref": "#/definitions/httpRequestConfig" diff --git a/embedx/embedx_test.go b/embedx/embedx_test.go index 27bf4a103a28..c06410f64873 100644 --- a/embedx/embedx_test.go +++ b/embedx/embedx_test.go @@ -5,15 +5,19 @@ package embedx import ( "context" + "embed" + "io/fs" + "strings" "testing" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/assert" "github.com/ory/jsonschema/v3" ) func TestAddSchemaResources(t *testing.T) { - for _, tc := range []struct { description string dependencies []SchemaType @@ -65,7 +69,38 @@ func TestAddSchemaResources(t *testing.T) { assert.NoError(t, err) } } - }) } } + +//go:embed testdata/identity_meta.* +var identityMetaTestCases embed.FS + +func TestIdentityMetaSchema(t *testing.T) { + c := jsonschema.NewCompiler() + err := AddSchemaResources(c, IdentityMeta, IdentityExtension) + require.NoError(t, err) + + schema, err := c.Compile(context.Background(), IdentityMeta.GetSchemaID()) + require.NoError(t, err) + + require.NoError(t, fs.WalkDir(identityMetaTestCases, ".", func(path string, d fs.DirEntry, err error) error { + if d.IsDir() { + return nil + } + + t.Run("case="+path, func(t *testing.T) { + f, err := identityMetaTestCases.Open(path) + require.NoError(t, err) + + err = schema.Validate(f) + if strings.HasSuffix(path, "invalid.schema.json") { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + + return nil + })) +} diff --git a/embedx/identity_extension.schema.json b/embedx/identity_extension.schema.json index 9af2e97f07ce..c105cbe42f95 100644 --- a/embedx/identity_extension.schema.json +++ b/embedx/identity_extension.schema.json @@ -60,7 +60,7 @@ "properties": { "via": { "type": "string", - "enum": ["email", "phone"] + "enum": ["email", "sms"] } } }, diff --git a/embedx/identity_meta.schema.json b/embedx/identity_meta.schema.json index e1213d4893f1..27c2c8eefc2d 100644 --- a/embedx/identity_meta.schema.json +++ b/embedx/identity_meta.schema.json @@ -10,9 +10,7 @@ "properties": { "properties": { "type": "object", - "required": [ - "traits" - ], + "required": ["traits"], "properties": { "traits": { "type": "object", @@ -27,6 +25,32 @@ "patternProperties": { ".*": { "type": "object", + "if": { + "properties": { + "ory.sh/kratos": { + "type": "object", + "properties": { + "verification": {} + }, + "required": ["verification"] + } + }, + "required": ["ory.sh/kratos"] + }, + "then": { + "properties": { + "format": { + "enum": [ + "email", + "tel", + "date", + "time", + "date-time", + "no-validate" + ] + } + } + }, "allOf": [ { "$ref": "ory://identity-extension" @@ -40,9 +64,7 @@ } } }, - "required": [ - "properties" - ] + "required": ["properties"] } ] } diff --git a/embedx/testdata/identity_meta.no_traits.invalid.schema.json b/embedx/testdata/identity_meta.no_traits.invalid.schema.json new file mode 100644 index 000000000000..0967ef424bce --- /dev/null +++ b/embedx/testdata/identity_meta.no_traits.invalid.schema.json @@ -0,0 +1 @@ +{} diff --git a/embedx/testdata/identity_meta.simple.valid.schema.json b/embedx/testdata/identity_meta.simple.valid.schema.json new file mode 100644 index 000000000000..6f090b383a55 --- /dev/null +++ b/embedx/testdata/identity_meta.simple.valid.schema.json @@ -0,0 +1,23 @@ +{ + "properties": { + "traits": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + }, + "verification": { + "via": "email" + } + } + } + } + } + } +} diff --git a/embedx/testdata/identity_meta.verification_format.invalid.schema.json b/embedx/testdata/identity_meta.verification_format.invalid.schema.json new file mode 100644 index 000000000000..1dc46bdcfdc3 --- /dev/null +++ b/embedx/testdata/identity_meta.verification_format.invalid.schema.json @@ -0,0 +1,23 @@ +{ + "properties": { + "traits": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "unknown", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + }, + "verification": { + "via": "email" + } + } + } + } + } + } +} diff --git a/identity/address.go b/identity/address.go index 4c4145114083..2e9175642e84 100644 --- a/identity/address.go +++ b/identity/address.go @@ -5,5 +5,4 @@ package identity const ( AddressTypeEmail = "email" - AddressTypePhone = "phone" ) diff --git a/identity/credentials.go b/identity/credentials.go index c323f7dcc790..4f2dbd522874 100644 --- a/identity/credentials.go +++ b/identity/credentials.go @@ -146,15 +146,6 @@ func ParseCredentialsType(in string) (CredentialsType, bool) { return "", false } -// swagger:ignore -type CredentialsIdentifierAddressType string - -const ( - CredentialsIdentifierAddressTypeEmail CredentialsIdentifierAddressType = AddressTypeEmail - CredentialsIdentifierAddressTypePhone CredentialsIdentifierAddressType = AddressTypePhone - CredentialsIdentifierAddressTypeNone CredentialsIdentifierAddressType = "none" -) - // Credentials represents a specific credential type // // swagger:model identityCredentials diff --git a/identity/credentials_code.go b/identity/credentials_code.go index 184479ae1700..abc9decbbf46 100644 --- a/identity/credentials_code.go +++ b/identity/credentials_code.go @@ -11,7 +11,6 @@ type CodeAddressType string const ( CodeAddressTypeEmail CodeAddressType = AddressTypeEmail - CodeAddressTypePhone CodeAddressType = AddressTypePhone ) // CredentialsCode represents a one time login/registration code diff --git a/identity/extension_credentials.go b/identity/extension_credentials.go index 88823ee8a226..3baa826b2e9c 100644 --- a/identity/extension_credentials.go +++ b/identity/extension_credentials.go @@ -26,7 +26,7 @@ func NewSchemaExtensionCredentials(i *Identity) *SchemaExtensionCredentials { return &SchemaExtensionCredentials{i: i} } -func (r *SchemaExtensionCredentials) setIdentifier(ct CredentialsType, value interface{}, addressType CredentialsIdentifierAddressType) { +func (r *SchemaExtensionCredentials) setIdentifier(ct CredentialsType, value interface{}) { cred, ok := r.i.GetCredentials(ct) if !ok { cred = &Credentials{ @@ -49,11 +49,11 @@ func (r *SchemaExtensionCredentials) Run(ctx jsonschema.ValidationContext, s sch defer r.l.Unlock() if s.Credentials.Password.Identifier { - r.setIdentifier(CredentialsTypePassword, value, CredentialsIdentifierAddressTypeNone) + r.setIdentifier(CredentialsTypePassword, value) } if s.Credentials.WebAuthn.Identifier { - r.setIdentifier(CredentialsTypeWebAuthn, value, CredentialsIdentifierAddressTypeNone) + r.setIdentifier(CredentialsTypeWebAuthn, value) } if s.Credentials.Code.Identifier { @@ -63,7 +63,7 @@ func (r *SchemaExtensionCredentials) Run(ctx jsonschema.ValidationContext, s sch return ctx.Error("format", "%q is not a valid %q", value, s.Credentials.Code.Via) } - r.setIdentifier(CredentialsTypeCodeAuth, value, CredentialsIdentifierAddressTypeEmail) + r.setIdentifier(CredentialsTypeCodeAuth, value) // case f.AddCase(AddressTypePhone): // if !jsonschema.Formats["tel"](value) { // return ctx.Error("format", "%q is not a valid %q", value, s.Credentials.Code.Via) diff --git a/identity/extension_verification.go b/identity/extension_verification.go index 8fa86c0754a7..3b3f92581c37 100644 --- a/identity/extension_verification.go +++ b/identity/extension_verification.go @@ -9,10 +9,18 @@ import ( "sync" "time" + "golang.org/x/exp/maps" + "github.com/ory/jsonschema/v3" "github.com/ory/kratos/schema" ) +func init() { + jsonschema.Formats["no-validate"] = func(v interface{}) bool { + return true + } +} + type SchemaExtensionVerification struct { lifespan time.Duration l sync.Mutex @@ -24,40 +32,57 @@ func NewSchemaExtensionVerification(i *Identity, lifespan time.Duration) *Schema return &SchemaExtensionVerification{i: i, lifespan: lifespan} } +const ( + ChannelTypeEmail = "email" + ChannelTypeSMS = "sms" +) + func (r *SchemaExtensionVerification) Run(ctx jsonschema.ValidationContext, s schema.ExtensionConfig, value interface{}) error { r.l.Lock() defer r.l.Unlock() - switch s.Verification.Via { - case AddressTypeEmail: - if !jsonschema.Formats["email"](value) { - return ctx.Error("format", "%q is not valid %q", value, "email") - } - - address := NewVerifiableEmailAddress( - strings.ToLower(strings.TrimSpace( - fmt.Sprintf("%s", value))), r.i.ID) - - r.appendAddress(address) + if s.Verification.Via == "" { + return nil + } + format, ok := s.RawSchema["format"] + if !ok { + format = "" + } + formatString, ok := format.(string) + if !ok { return nil + } - case AddressTypePhone: - if !jsonschema.Formats["tel"](value) { - return ctx.Error("format", "%q is not valid %q", value, "phone") + if formatString == "" { + switch s.Verification.Via { + case ChannelTypeEmail: + formatString = "email" + formatter, ok := jsonschema.Formats[formatString] + if !ok { + supportedKeys := maps.Keys(jsonschema.Formats) + return ctx.Error("format", "format %q is not supported. Supported formats are [%s]", formatString, strings.Join(supportedKeys, ", ")) + } + + if !formatter(value) { + return ctx.Error("format", "%q is not valid %q", value, formatString) + } + default: + return ctx.Error("format", "no format specified. A format is required if verification is enabled. If this was intentional, please set \"format\" to \"no-validate\"") } + } - address := NewVerifiablePhoneAddress(fmt.Sprintf("%s", value), r.i.ID) - - r.appendAddress(address) - - return nil - - case "": - return nil + var normalized string + switch formatString { + case "email": + normalized = strings.ToLower(strings.TrimSpace(fmt.Sprintf("%s", value))) + default: + normalized = strings.TrimSpace(fmt.Sprintf("%s", value)) } - return ctx.Error("", "verification.via has unknown value %q", s.Verification.Via) + address := NewVerifiableAddress(normalized, r.i.ID, s.Verification.Via) + r.appendAddress(address) + return nil } func (r *SchemaExtensionVerification) Finish() error { diff --git a/identity/extension_verification_test.go b/identity/extension_verification_test.go index 9085f2e03ea5..ebf2c09f207e 100644 --- a/identity/extension_verification_test.go +++ b/identity/extension_verification_test.go @@ -6,12 +6,13 @@ package identity import ( "bytes" "context" - "errors" "fmt" + "net" "reflect" "testing" "time" + "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -22,13 +23,17 @@ import ( ) const ( - emailSchemaPath = "file://./stub/extension/verify/email.schema.json" - phoneSchemaPath = "file://./stub/extension/verify/phone.schema.json" + emailSchemaPath = "file://./stub/extension/verify/email.schema.json" + phoneSchemaPath = "file://./stub/extension/verify/phone.schema.json" + missingFormatSchemaPath = "file://./stub/extension/verify/missing-format.schema.json" + legacyEmailMissingFormatSchemaPath = "file://./stub/extension/verify/legacy-email-missing-format.schema.json" + noValidateSchemaPath = "file://./stub/extension/verify/no-validate.schema.json" ) var ctx = context.Background() func TestSchemaExtensionVerification(t *testing.T) { + net.IP{}.IsPrivate() t.Run("address verification", func(t *testing.T) { iid := x.NewUUID() @@ -194,7 +199,7 @@ func TestSchemaExtensionVerification(t *testing.T) { Value: "+18004444444", Verified: false, Status: VerifiableAddressStatusPending, - Via: VerifiableAddressTypePhone, + Via: ChannelTypeSMS, IdentityID: iid, }, }, @@ -208,7 +213,7 @@ func TestSchemaExtensionVerification(t *testing.T) { Value: "+442087599036", Verified: false, Status: VerifiableAddressStatusPending, - Via: VerifiableAddressTypePhone, + Via: ChannelTypeSMS, IdentityID: iid, }, }, @@ -217,7 +222,7 @@ func TestSchemaExtensionVerification(t *testing.T) { Value: "+18004444444", Verified: false, Status: VerifiableAddressStatusPending, - Via: VerifiableAddressTypePhone, + Via: ChannelTypeSMS, IdentityID: iid, }, }, @@ -231,14 +236,14 @@ func TestSchemaExtensionVerification(t *testing.T) { Value: "+442087599036", Verified: true, Status: VerifiableAddressStatusCompleted, - Via: VerifiableAddressTypePhone, + Via: ChannelTypeSMS, IdentityID: iid, }, { Value: "+380634872774", Verified: true, Status: VerifiableAddressStatusCompleted, - Via: VerifiableAddressTypePhone, + Via: ChannelTypeSMS, IdentityID: iid, }, }, @@ -247,14 +252,14 @@ func TestSchemaExtensionVerification(t *testing.T) { Value: "+442087599036", Verified: true, Status: VerifiableAddressStatusCompleted, - Via: VerifiableAddressTypePhone, + Via: ChannelTypeSMS, IdentityID: iid, }, { Value: "+18004444444", Verified: false, Status: VerifiableAddressStatusPending, - Via: VerifiableAddressTypePhone, + Via: ChannelTypeSMS, IdentityID: iid, }, }, @@ -268,14 +273,14 @@ func TestSchemaExtensionVerification(t *testing.T) { Value: "+18004444444", Verified: false, Status: VerifiableAddressStatusPending, - Via: VerifiableAddressTypePhone, + Via: ChannelTypeSMS, IdentityID: iid, }, { Value: "+380634872774", Verified: true, Status: VerifiableAddressStatusCompleted, - Via: VerifiableAddressTypePhone, + Via: ChannelTypeSMS, IdentityID: iid, }, }, @@ -284,14 +289,14 @@ func TestSchemaExtensionVerification(t *testing.T) { Value: "+18004444444", Verified: false, Status: VerifiableAddressStatusPending, - Via: VerifiableAddressTypePhone, + Via: ChannelTypeSMS, IdentityID: iid, }, { Value: "+442087599036", Verified: false, Status: VerifiableAddressStatusPending, - Via: VerifiableAddressTypePhone, + Via: ChannelTypeSMS, IdentityID: iid, }, }, @@ -305,21 +310,21 @@ func TestSchemaExtensionVerification(t *testing.T) { Value: "+18004444444", Verified: false, Status: VerifiableAddressStatusPending, - Via: VerifiableAddressTypePhone, + Via: ChannelTypeSMS, IdentityID: iid, }, { Value: "+442087599036", Verified: false, Status: VerifiableAddressStatusPending, - Via: VerifiableAddressTypePhone, + Via: ChannelTypeSMS, IdentityID: iid, }, { Value: "+380634872774", Verified: false, Status: VerifiableAddressStatusPending, - Via: VerifiableAddressTypePhone, + Via: ChannelTypeSMS, IdentityID: iid, }, }, @@ -328,7 +333,41 @@ func TestSchemaExtensionVerification(t *testing.T) { name: "phone:must return error for malformed input", schema: phoneSchemaPath, doc: `{"phones":["+18004444444","+18004444444","12112112"], "username": "+380634872774"}`, - expectErr: errors.New("I[#/phones/2] S[#/properties/phones/items/format] \"12112112\" is not valid \"phone\""), + expectErr: errors.New("I[#/phones/2] S[#/properties/phones/items/format] \"12112112\" is not valid \"tel\""), + }, + { + name: "missing format returns an error", + schema: missingFormatSchemaPath, + doc: `{"phone": "+380634872774"}`, + expectErr: errors.New("I[#/phone] S[#/properties/phone/format] no format specified. A format is required if verification is enabled. If this was intentional, please set \"format\" to \"no-validate\""), + }, + { + name: "missing format works for email if format is missing", + schema: legacyEmailMissingFormatSchemaPath, + doc: `{"email": "user@ory.sh"}`, + expect: []VerifiableAddress{ + { + Value: "user@ory.sh", + Verified: false, + Status: VerifiableAddressStatusPending, + Via: ChannelTypeEmail, + IdentityID: iid, + }, + }, + }, + { + name: "format: no-validate works", + schema: noValidateSchemaPath, + doc: `{"phone": "not a phone number"}`, + expect: []VerifiableAddress{ + { + Value: "not a phone number", + Verified: false, + Status: VerifiableAddressStatusPending, + Via: ChannelTypeSMS, + IdentityID: iid, + }, + }, }, } { t.Run(fmt.Sprintf("case=%v", tc.name), func(t *testing.T) { @@ -357,7 +396,6 @@ func TestSchemaExtensionVerification(t *testing.T) { }) } }) - } func mustContainAddress(t *testing.T, expected, actual []VerifiableAddress) { diff --git a/identity/identity_verification.go b/identity/identity_verification.go index 697af0594b4f..54ac435ec9fd 100644 --- a/identity/identity_verification.go +++ b/identity/identity_verification.go @@ -15,7 +15,6 @@ import ( const ( VerifiableAddressTypeEmail VerifiableAddressType = AddressTypeEmail - VerifiableAddressTypePhone VerifiableAddressType = AddressTypePhone VerifiableAddressStatusPending VerifiableAddressStatus = "pending" VerifiableAddressStatusSent VerifiableAddressStatus = "sent" @@ -25,7 +24,7 @@ const ( // VerifiableAddressType must not exceed 16 characters as that is the limitation in the SQL Schema // // swagger:model identityVerifiableAddressType -type VerifiableAddressType string +type VerifiableAddressType = string // VerifiableAddressStatus must not exceed 16 characters as that is the limitation in the SQL Schema // @@ -54,14 +53,14 @@ type VerifiableAddress struct { // The delivery method // - // enum: ["email"] + // enum: email,sms // example: email // required: true - Via VerifiableAddressType `json:"via" db:"via"` + Via string `json:"via" db:"via"` // The verified address status // - // enum: ["pending","sent","completed"] + // enum: pending,sent,completed // example: sent // required: true Status VerifiableAddressStatus `json:"status" db:"status"` @@ -87,36 +86,20 @@ type VerifiableAddress struct { NID uuid.UUID `json:"-" faker:"-" db:"nid"` } -func (v VerifiableAddressType) HTMLFormInputType() string { - switch v { - case VerifiableAddressTypeEmail: - return "email" - case VerifiableAddressTypePhone: - return "phone" - } - return "" -} - func (a VerifiableAddress) TableName(ctx context.Context) string { return "identity_verifiable_addresses" } func NewVerifiableEmailAddress(value string, identity uuid.UUID) *VerifiableAddress { - return &VerifiableAddress{ - Value: value, - Verified: false, - Status: VerifiableAddressStatusPending, - Via: VerifiableAddressTypeEmail, - IdentityID: identity, - } + return NewVerifiableAddress(value, identity, VerifiableAddressTypeEmail) } -func NewVerifiablePhoneAddress(value string, identity uuid.UUID) *VerifiableAddress { +func NewVerifiableAddress(value string, identity uuid.UUID, channel string) *VerifiableAddress { return &VerifiableAddress{ Value: value, Verified: false, Status: VerifiableAddressStatusPending, - Via: VerifiableAddressTypePhone, + Via: channel, IdentityID: identity, } } diff --git a/identity/pool.go b/identity/pool.go index 1da5181b796a..5316f8a53ff9 100644 --- a/identity/pool.go +++ b/identity/pool.go @@ -39,7 +39,7 @@ type ( GetIdentity(context.Context, uuid.UUID, sqlxx.Expandables) (*Identity, error) // FindVerifiableAddressByValue returns a matching address or sql.ErrNoRows if no address could be found. - FindVerifiableAddressByValue(ctx context.Context, via VerifiableAddressType, address string) (*VerifiableAddress, error) + FindVerifiableAddressByValue(ctx context.Context, via string, address string) (*VerifiableAddress, error) // FindRecoveryAddressByValue returns a matching address or sql.ErrNoRows if no address could be found. FindRecoveryAddressByValue(ctx context.Context, via RecoveryAddressType, address string) (*RecoveryAddress, error) diff --git a/identity/stub/extension/verify/legacy-email-missing-format.schema.json b/identity/stub/extension/verify/legacy-email-missing-format.schema.json new file mode 100644 index 000000000000..50d7c5f7b548 --- /dev/null +++ b/identity/stub/extension/verify/legacy-email-missing-format.schema.json @@ -0,0 +1,13 @@ +{ + "type": "object", + "properties": { + "email": { + "type": "string", + "ory.sh/kratos": { + "verification": { + "via": "email" + } + } + } + } +} diff --git a/identity/stub/extension/verify/missing-format.schema.json b/identity/stub/extension/verify/missing-format.schema.json new file mode 100644 index 000000000000..b3716126bb0d --- /dev/null +++ b/identity/stub/extension/verify/missing-format.schema.json @@ -0,0 +1,13 @@ +{ + "type": "object", + "properties": { + "phone": { + "type": "string", + "ory.sh/kratos": { + "verification": { + "via": "sms" + } + } + } + } +} diff --git a/identity/stub/extension/verify/no-validate.schema.json b/identity/stub/extension/verify/no-validate.schema.json new file mode 100644 index 000000000000..d92bb04ef4c4 --- /dev/null +++ b/identity/stub/extension/verify/no-validate.schema.json @@ -0,0 +1,14 @@ +{ + "type": "object", + "properties": { + "phone": { + "type": "string", + "format": "noformat", + "ory.sh/kratos": { + "verification": { + "via": "sms" + } + } + } + } +} diff --git a/identity/stub/extension/verify/phone.schema.json b/identity/stub/extension/verify/phone.schema.json index 2bd7d6f4fa35..6b273dccf880 100644 --- a/identity/stub/extension/verify/phone.schema.json +++ b/identity/stub/extension/verify/phone.schema.json @@ -5,18 +5,20 @@ "type": "array", "items": { "type": "string", + "format": "tel", "ory.sh/kratos": { "verification": { - "via": "phone" + "via": "sms" } } } }, "username": { "type": "string", + "format": "tel", "ory.sh/kratos": { "verification": { - "via": "phone" + "via": "sms" } } } diff --git a/internal/client-go/model_verifiable_identity_address.go b/internal/client-go/model_verifiable_identity_address.go index 516a8107e40a..820881b2d3a2 100644 --- a/internal/client-go/model_verifiable_identity_address.go +++ b/internal/client-go/model_verifiable_identity_address.go @@ -31,7 +31,7 @@ type VerifiableIdentityAddress struct { // Indicates if the address has already been verified Verified bool `json:"verified"` VerifiedAt *time.Time `json:"verified_at,omitempty"` - // VerifiableAddressType must not exceed 16 characters as that is the limitation in the SQL Schema + // The delivery method Via string `json:"via"` } diff --git a/internal/httpclient/model_verifiable_identity_address.go b/internal/httpclient/model_verifiable_identity_address.go index 516a8107e40a..820881b2d3a2 100644 --- a/internal/httpclient/model_verifiable_identity_address.go +++ b/internal/httpclient/model_verifiable_identity_address.go @@ -31,7 +31,7 @@ type VerifiableIdentityAddress struct { // Indicates if the address has already been verified Verified bool `json:"verified"` VerifiedAt *time.Time `json:"verified_at,omitempty"` - // VerifiableAddressType must not exceed 16 characters as that is the limitation in the SQL Schema + // The delivery method Via string `json:"via"` } diff --git a/persistence/sql/identity/persister_identity.go b/persistence/sql/identity/persister_identity.go index 82d7b035e295..1bfbf107ee0a 100644 --- a/persistence/sql/identity/persister_identity.go +++ b/persistence/sql/identity/persister_identity.go @@ -957,7 +957,7 @@ func (p *IdentityPersister) GetIdentityConfidential(ctx context.Context, id uuid return p.GetIdentity(ctx, id, identity.ExpandEverything) } -func (p *IdentityPersister) FindVerifiableAddressByValue(ctx context.Context, via identity.VerifiableAddressType, value string) (_ *identity.VerifiableAddress, err error) { +func (p *IdentityPersister) FindVerifiableAddressByValue(ctx context.Context, via string, value string) (_ *identity.VerifiableAddress, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.FindVerifiableAddressByValue") otelx.End(span, &err) diff --git a/request/builder.go b/request/builder.go index 48d43856edf1..f930bc089aae 100644 --- a/request/builder.go +++ b/request/builder.go @@ -163,23 +163,23 @@ func (b *Builder) addURLEncodedBody(ctx context.Context, template *bytes.Buffer, enc.SetIndent("", "") if err := enc.Encode(body); err != nil { - return err + return errors.WithStack(err) } vm, err := b.deps.JsonnetVM(ctx) if err != nil { - return err + return errors.WithStack(err) } vm.TLACode("ctx", buf.String()) res, err := vm.EvaluateAnonymousSnippet(b.Config.TemplateURI, template.String()) if err != nil { - return err + return errors.WithStack(err) } values := map[string]string{} if err := json.Unmarshal([]byte(res), &values); err != nil { - return err + return errors.WithStack(err) } u := url.Values{} diff --git a/schema/extension.go b/schema/extension.go index 4e15aebf2a0a..c217f409c8c3 100644 --- a/schema/extension.go +++ b/schema/extension.go @@ -41,6 +41,7 @@ type ( Recovery struct { Via string `json:"via"` } `json:"recovery"` + RawSchema map[string]interface{} `json:"-"` } ValidateExtension interface { @@ -53,7 +54,7 @@ type ( ExtensionRunner struct { meta *jsonschema.Schema - compile func(ctx jsonschema.CompilerContext, m map[string]interface{}) (interface{}, error) + compile func(ctx jsonschema.CompilerContext, rawSchema map[string]interface{}) (interface{}, error) validate func(ctx jsonschema.ValidationContext, s interface{}, v interface{}) error validateRunners []ValidateExtension @@ -106,6 +107,7 @@ func NewExtensionRunner(ctx context.Context, opts ...ExtensionRunnerOption) (*Ex return nil, err } } + e.RawSchema = m return &e, nil } diff --git a/selfservice/strategy/code/code_sender.go b/selfservice/strategy/code/code_sender.go index 9f98f183b589..d41beef463ed 100644 --- a/selfservice/strategy/code/code_sender.go +++ b/selfservice/strategy/code/code_sender.go @@ -241,7 +241,7 @@ func (s *Sender) SendRecoveryCodeTo(ctx context.Context, i *identity.Identity, c // If the address does not exist in the store and dispatching invalid emails is enabled (CourierEnableInvalidDispatch is // true), an email is still being sent to prevent account enumeration attacks. In that case, this function returns the // ErrUnknownAddress error. -func (s *Sender) SendVerificationCode(ctx context.Context, f *verification.Flow, via identity.VerifiableAddressType, to string) error { +func (s *Sender) SendVerificationCode(ctx context.Context, f *verification.Flow, via string, to string) error { s.deps.Logger(). WithField("via", via). WithSensitiveField("address", to). @@ -317,21 +317,21 @@ func (s *Sender) SendVerificationCodeTo(ctx context.Context, f *verification.Flo // TODO: this can likely be abstracted by making templates not specific to the channel they're using switch code.VerifiableAddress.Via { - case identity.AddressTypeEmail: + case identity.ChannelTypeEmail: t = email.NewVerificationCodeValid(s.deps, &email.VerificationCodeValidModel{ To: code.VerifiableAddress.Value, VerificationURL: s.constructVerificationLink(ctx, f.ID, codeString), Identity: model, VerificationCode: codeString, }) - case identity.AddressTypePhone: + case identity.ChannelTypeSMS: t = sms.NewVerificationCodeValid(s.deps, &sms.VerificationCodeValidModel{ To: code.VerifiableAddress.Value, VerificationCode: codeString, Identity: model, }) default: - return errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Expected email or phone but got %s", code.VerifiableAddress.Via)) + return errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Expected email or sms but got %s", code.VerifiableAddress.Via)) } if err := s.send(ctx, string(code.VerifiableAddress.Via), t); err != nil { @@ -343,7 +343,7 @@ func (s *Sender) SendVerificationCodeTo(ctx context.Context, f *verification.Flo func (s *Sender) send(ctx context.Context, via string, t courier.Template) error { switch f := stringsx.SwitchExact(via); { - case f.AddCase(identity.AddressTypeEmail): + case f.AddCase(identity.ChannelTypeEmail): c, err := s.deps.Courier(ctx) if err != nil { return err @@ -356,7 +356,7 @@ func (s *Sender) send(ctx context.Context, via string, t courier.Template) error _, err = c.QueueEmail(ctx, t) return err - case f.AddCase(identity.AddressTypePhone): + case f.AddCase(identity.ChannelTypeSMS): c, err := s.deps.Courier(ctx) if err != nil { return err diff --git a/spec/api.json b/spec/api.json index e17cb5dbd4d2..22bd0751a8f7 100644 --- a/spec/api.json +++ b/spec/api.json @@ -1156,10 +1156,6 @@ "description": "VerifiableAddressStatus must not exceed 16 characters as that is the limitation in the SQL Schema", "type": "string" }, - "identityVerifiableAddressType": { - "description": "VerifiableAddressType must not exceed 16 characters as that is the limitation in the SQL Schema", - "type": "string" - }, "identityWithCredentials": { "description": "Create Identity and Import Credentials", "properties": { @@ -3255,7 +3251,13 @@ "$ref": "#/components/schemas/nullTime" }, "via": { - "$ref": "#/components/schemas/identityVerifiableAddressType" + "description": "The delivery method", + "enum": [ + "email", + "sms" + ], + "example": "email", + "type": "string" } }, "required": [ diff --git a/spec/swagger.json b/spec/swagger.json index 67217a74c9f7..804bf09363a7 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -4219,10 +4219,6 @@ "description": "VerifiableAddressStatus must not exceed 16 characters as that is the limitation in the SQL Schema", "type": "string" }, - "identityVerifiableAddressType": { - "description": "VerifiableAddressType must not exceed 16 characters as that is the limitation in the SQL Schema", - "type": "string" - }, "identityWithCredentials": { "description": "Create Identity and Import Credentials", "type": "object", @@ -6147,7 +6143,13 @@ "$ref": "#/definitions/nullTime" }, "via": { - "$ref": "#/definitions/identityVerifiableAddressType" + "description": "The delivery method", + "type": "string", + "enum": [ + "email", + "sms" + ], + "example": "email" } } }, From a2f79c31f3208b88024897fc8bf1307ccac6f895 Mon Sep 17 00:00:00 2001 From: Kedas Date: Mon, 8 Jan 2024 02:49:49 -0800 Subject: [PATCH 223/282] fix: check whoami aal before accepting hydra login request (#3669) --- selfservice/flow/login/hook.go | 20 ++++++++++---------- selfservice/flow/login/hook_test.go | 29 ++++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/selfservice/flow/login/hook.go b/selfservice/flow/login/hook.go index 2af0c3daf1fc..620559f57b06 100644 --- a/selfservice/flow/login/hook.go +++ b/selfservice/flow/login/hook.go @@ -257,6 +257,16 @@ func (e *HookExecutor) PostLoginHook( // Browser flows rely on cookies. Adding tokens in the mix will confuse consumers. s.Token = "" + // If we detect that whoami would require a higher AAL, we redirect! + if _, err := e.requiresAAL2(r, s, a); err != nil { + if aalErr := new(session.ErrAALNotSatisfied); errors.As(err, &aalErr) { + span.SetAttributes(attribute.String("return_to", aalErr.RedirectTo), attribute.String("redirect_reason", "requires aal2")) + e.d.Writer().WriteError(w, r, flow.NewBrowserLocationChangeRequiredError(aalErr.RedirectTo)) + return nil + } + return err + } + // If Kratos is used as a Hydra login provider, we need to redirect back to Hydra by returning a 422 status // with the post login challenge URL as the body. if a.OAuth2LoginChallenge != "" { @@ -275,16 +285,6 @@ func (e *HookExecutor) PostLoginHook( return nil } - // If we detect that whoami would require a higher AAL, we redirect! - if _, err := e.requiresAAL2(r, s, a); err != nil { - if aalErr := new(session.ErrAALNotSatisfied); errors.As(err, &aalErr) { - span.SetAttributes(attribute.String("return_to", aalErr.RedirectTo), attribute.String("redirect_reason", "requires aal2")) - e.d.Writer().WriteError(w, r, flow.NewBrowserLocationChangeRequiredError(aalErr.RedirectTo)) - return nil - } - return err - } - response := &APIFlowResponse{Session: s} e.d.Writer().Write(w, r, response) return nil diff --git a/selfservice/flow/login/hook_test.go b/selfservice/flow/login/hook_test.go index 052973317ca2..46f957c1ca76 100644 --- a/selfservice/flow/login/hook_test.go +++ b/selfservice/flow/login/hook_test.go @@ -231,6 +231,8 @@ func TestLoginExecutor(t *testing.T) { }) t.Cleanup(testhelpers.SelfServiceHookConfigReset(t, conf)) + conf.MustSet(ctx, config.ViperKeyOAuth2ProviderURL, "https://hydra") + useIdentity := &identity.Identity{Credentials: map[identity.CredentialsType]identity.Credentials{ identity.CredentialsTypePassword: {Type: identity.CredentialsTypePassword, Config: []byte(`{"hashed_password": "$argon2id$v=19$m=32,t=2,p=4$cm94YnRVOW5jZzFzcVE4bQ$MNzk5BtR2vUhrp6qQEjRNw"}`), Identifiers: []string{testhelpers.RandomEmail()}}, identity.CredentialsTypeWebAuthn: {Type: identity.CredentialsTypeWebAuthn, Config: []byte(`{"credentials":[{"is_passwordless":false}]}`), Identifiers: []string{testhelpers.RandomEmail()}}, @@ -243,6 +245,17 @@ func TestLoginExecutor(t *testing.T) { assert.Contains(t, res.Request.URL.String(), "/self-service/login/browser?aal=aal2") }) + t.Run("browser client with login challenge", func(t *testing.T) { + res, _ := makeRequestPost(t, newServer(t, flow.TypeBrowser, useIdentity), false, url.Values{ + "login_challenge": []string{hydra.FakeValidLoginChallenge}, + }) + assert.EqualValues(t, http.StatusNotFound, res.StatusCode) + + assert.Equal(t, res.Request.URL.Path, "/self-service/login/browser") + assert.Equal(t, res.Request.URL.Query().Get("aal"), "aal2") + assert.Equal(t, res.Request.URL.Query().Get("login_challenge"), hydra.FakeValidLoginChallenge) + }) + t.Run("api client returns the token and the session without the identity", func(t *testing.T) { res, body := makeRequestPost(t, newServer(t, flow.TypeAPI, useIdentity), true, url.Values{}) assert.EqualValues(t, http.StatusOK, res.StatusCode) @@ -256,8 +269,22 @@ func TestLoginExecutor(t *testing.T) { assert.NotEmpty(t, gjson.Get(body, "redirect_browser_to").String()) assert.Contains(t, gjson.Get(body, "redirect_browser_to").String(), "/self-service/login/browser?aal=aal2", "%s", body) }) - }) + t.Run("browser JSON client with login challenge", func(t *testing.T) { + res, body := makeRequestPost(t, newServer(t, flow.TypeBrowser, useIdentity), true, url.Values{ + "login_challenge": []string{hydra.FakeValidLoginChallenge}, + }) + assert.EqualValues(t, http.StatusUnprocessableEntity, res.StatusCode) + assert.NotEmpty(t, gjson.Get(body, "redirect_browser_to").String()) + + redirectBrowserTo, err := url.Parse(gjson.Get(body, "redirect_browser_to").String()) + require.NoError(t, err) + + assert.Equal(t, redirectBrowserTo.Path, "/self-service/login/browser") + assert.Equal(t, redirectBrowserTo.Query().Get("aal"), "aal2") + assert.Equal(t, redirectBrowserTo.Query().Get("login_challenge"), hydra.FakeValidLoginChallenge) + }) + }) }) t.Run("case=maybe links credential", func(t *testing.T) { t.Cleanup(testhelpers.SelfServiceHookConfigReset(t, conf)) From c251cb257743c86d0bc960915c3aae445d0896ff Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Mon, 8 Jan 2024 11:33:44 +0000 Subject: [PATCH 224/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 489f8d969076..85d8e31296c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2023-12-28)](#2023-12-28) +- [ (2024-01-08)](#2024-01-08) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -314,7 +314,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2023-12-28) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2024-01-08) ## Breaking Changes @@ -420,6 +420,9 @@ https://github.com/ory/kratos/pull/3480 Signed-off-by: nxy7 +- Check whoami aal before accepting hydra login request + ([#3669](https://github.com/ory/kratos/issues/3669)) + ([a2f79c3](https://github.com/ory/kratos/commit/a2f79c31f3208b88024897fc8bf1307ccac6f895)) - Code method on registration and 2fa ([#3481](https://github.com/ory/kratos/issues/3481)) ([7aa2e29](https://github.com/ory/kratos/commit/7aa2e293175d0f4b6c13552cc3781f54f8caf3a0)) @@ -613,6 +616,9 @@ https://github.com/ory/kratos/pull/3480 - Remove slow queries from update identities ([#3553](https://github.com/ory/kratos/issues/3553)) ([d138abb](https://github.com/ory/kratos/commit/d138abb6278ebb232e120bee0fb956a0f2816b8d)) +- Rename "phone" courier channel to "sms" + ([#3680](https://github.com/ory/kratos/issues/3680)) + ([eb8d1b9](https://github.com/ory/kratos/commit/eb8d1b9abd6d2b3eb86ab11d48d9ebd059586b67)) - Respect gomail.SendError in mail queue ([#3600](https://github.com/ory/kratos/issues/3600)) ([9c608b9](https://github.com/ory/kratos/commit/9c608b991874d839782d9219f2fc27d0d4a398af)) From 2c1470ab3556e639f06a01ac1646a6b90c7ecac7 Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Mon, 8 Jan 2024 13:08:30 +0100 Subject: [PATCH 225/282] fix: incorrect swagger spec for filter parameter (#3684) Closes #3676 #3675 --- identity/handler.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/identity/handler.go b/identity/handler.go index 9eb5f11cba99..de50cb73eb2f 100644 --- a/identity/handler.go +++ b/identity/handler.go @@ -138,12 +138,12 @@ type listIdentitiesResponse struct { type listIdentitiesParameters struct { migrationpagination.RequestParameters - // IdsFilter is list of ids used to filter identities. + // List of ids used to filter identities. // If this list is empty, then no filter will be applied. // // required: false // in: query - IdsFilter []string `json:"ids_filter"` + IdsFilter []string `json:"ids"` // CredentialsIdentifier is the identifier (username, email) of the credentials to look up using exact match. // Only one of CredentialsIdentifier and CredentialsIdentifierSimilar can be used. From ee0af6c16d79f0e8f75f4fe8826b646ed209dad6 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Mon, 8 Jan 2024 12:10:16 +0000 Subject: [PATCH 226/282] autogen(openapi): regenerate swagger spec and internal client [skip ci] --- internal/client-go/api_identity.go | 14 +++++++------- internal/httpclient/api_identity.go | 14 +++++++------- spec/api.json | 4 ++-- spec/swagger.json | 4 ++-- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/internal/client-go/api_identity.go b/internal/client-go/api_identity.go index a88dba49aab8..ca2b697f8cf5 100644 --- a/internal/client-go/api_identity.go +++ b/internal/client-go/api_identity.go @@ -2052,7 +2052,7 @@ type IdentityApiApiListIdentitiesRequest struct { pageSize *int64 pageToken *string consistency *string - idsFilter *[]string + ids *[]string credentialsIdentifier *string previewCredentialsIdentifierSimilar *string } @@ -2077,8 +2077,8 @@ func (r IdentityApiApiListIdentitiesRequest) Consistency(consistency string) Ide r.consistency = &consistency return r } -func (r IdentityApiApiListIdentitiesRequest) IdsFilter(idsFilter []string) IdentityApiApiListIdentitiesRequest { - r.idsFilter = &idsFilter +func (r IdentityApiApiListIdentitiesRequest) Ids(ids []string) IdentityApiApiListIdentitiesRequest { + r.ids = &ids return r } func (r IdentityApiApiListIdentitiesRequest) CredentialsIdentifier(credentialsIdentifier string) IdentityApiApiListIdentitiesRequest { @@ -2147,15 +2147,15 @@ func (a *IdentityApiService) ListIdentitiesExecute(r IdentityApiApiListIdentitie if r.consistency != nil { localVarQueryParams.Add("consistency", parameterToString(*r.consistency, "")) } - if r.idsFilter != nil { - t := *r.idsFilter + if r.ids != nil { + t := *r.ids if reflect.TypeOf(t).Kind() == reflect.Slice { s := reflect.ValueOf(t) for i := 0; i < s.Len(); i++ { - localVarQueryParams.Add("ids_filter", parameterToString(s.Index(i), "multi")) + localVarQueryParams.Add("ids", parameterToString(s.Index(i), "multi")) } } else { - localVarQueryParams.Add("ids_filter", parameterToString(t, "multi")) + localVarQueryParams.Add("ids", parameterToString(t, "multi")) } } if r.credentialsIdentifier != nil { diff --git a/internal/httpclient/api_identity.go b/internal/httpclient/api_identity.go index a88dba49aab8..ca2b697f8cf5 100644 --- a/internal/httpclient/api_identity.go +++ b/internal/httpclient/api_identity.go @@ -2052,7 +2052,7 @@ type IdentityApiApiListIdentitiesRequest struct { pageSize *int64 pageToken *string consistency *string - idsFilter *[]string + ids *[]string credentialsIdentifier *string previewCredentialsIdentifierSimilar *string } @@ -2077,8 +2077,8 @@ func (r IdentityApiApiListIdentitiesRequest) Consistency(consistency string) Ide r.consistency = &consistency return r } -func (r IdentityApiApiListIdentitiesRequest) IdsFilter(idsFilter []string) IdentityApiApiListIdentitiesRequest { - r.idsFilter = &idsFilter +func (r IdentityApiApiListIdentitiesRequest) Ids(ids []string) IdentityApiApiListIdentitiesRequest { + r.ids = &ids return r } func (r IdentityApiApiListIdentitiesRequest) CredentialsIdentifier(credentialsIdentifier string) IdentityApiApiListIdentitiesRequest { @@ -2147,15 +2147,15 @@ func (a *IdentityApiService) ListIdentitiesExecute(r IdentityApiApiListIdentitie if r.consistency != nil { localVarQueryParams.Add("consistency", parameterToString(*r.consistency, "")) } - if r.idsFilter != nil { - t := *r.idsFilter + if r.ids != nil { + t := *r.ids if reflect.TypeOf(t).Kind() == reflect.Slice { s := reflect.ValueOf(t) for i := 0; i < s.Len(); i++ { - localVarQueryParams.Add("ids_filter", parameterToString(s.Index(i), "multi")) + localVarQueryParams.Add("ids", parameterToString(s.Index(i), "multi")) } } else { - localVarQueryParams.Add("ids_filter", parameterToString(t, "multi")) + localVarQueryParams.Add("ids", parameterToString(t, "multi")) } } if r.credentialsIdentifier != nil { diff --git a/spec/api.json b/spec/api.json index 22bd0751a8f7..8ba46ef3790d 100644 --- a/spec/api.json +++ b/spec/api.json @@ -3581,9 +3581,9 @@ "x-go-enum-desc": " ConsistencyLevelUnset ConsistencyLevelUnset is the unset / default consistency level.\nstrong ConsistencyLevelStrong ConsistencyLevelStrong is the strong consistency level.\neventual ConsistencyLevelEventual ConsistencyLevelEventual is the eventual consistency level using follower read timestamps." }, { - "description": "IdsFilter is list of ids used to filter identities.\nIf this list is empty, then no filter will be applied.", + "description": "List of ids used to filter identities.\nIf this list is empty, then no filter will be applied.", "in": "query", - "name": "ids_filter", + "name": "ids", "schema": { "items": { "type": "string" diff --git a/spec/swagger.json b/spec/swagger.json index 804bf09363a7..0efbf7716e9c 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -237,8 +237,8 @@ "items": { "type": "string" }, - "description": "IdsFilter is list of ids used to filter identities.\nIf this list is empty, then no filter will be applied.", - "name": "ids_filter", + "description": "List of ids used to filter identities.\nIf this list is empty, then no filter will be applied.", + "name": "ids", "in": "query" }, { From 4ce179a8c4cc431d3539ea1dc96c806b9f5d3beb Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Mon, 8 Jan 2024 12:53:25 +0000 Subject: [PATCH 227/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85d8e31296c7..7d2c0f47a526 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -495,6 +495,11 @@ https://github.com/ory/kratos/pull/3480 - Incorrect SMTP error handling ([#3636](https://github.com/ory/kratos/issues/3636)) ([ee138ec](https://github.com/ory/kratos/commit/ee138ec4e1ba55ef077858653220db9e6b0c7254)) +- Incorrect swagger spec for filter parameter + ([#3684](https://github.com/ory/kratos/issues/3684)) + ([2c1470a](https://github.com/ory/kratos/commit/2c1470ab3556e639f06a01ac1646a6b90c7ecac7)), + closes [#3676](https://github.com/ory/kratos/issues/3676) + [#3675](https://github.com/ory/kratos/issues/3675) - Increase connection-level timeouts and shutdown timeouts ([#3570](https://github.com/ory/kratos/issues/3570)) ([200b413](https://github.com/ory/kratos/commit/200b4138a429d113ee045d16031bb0a6312c1c01)): From 21ab03149e2b87c49cc5367a026a3514e02947e0 Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Tue, 9 Jan 2024 13:58:36 +0100 Subject: [PATCH 228/282] chore: bump openapi-generator (#3686) --- Makefile | 2 + internal/client-go/.openapi-generator/VERSION | 2 +- internal/client-go/go.sum | 2 - .../httpclient/.openapi-generator/VERSION | 2 +- openapitools.json | 2 +- package-lock.json | 278 ++++++------------ package.json | 2 +- 7 files changed, 90 insertions(+), 200 deletions(-) diff --git a/Makefile b/Makefile index 59fd30158bdb..fd023e75bf13 100644 --- a/Makefile +++ b/Makefile @@ -125,6 +125,7 @@ sdk: .bin/swagger .bin/ory node_modules --git-user-id ory \ --git-repo-id client-go \ --git-host github.com \ + --api-name-suffix "Api" \ -t .schema/openapi/templates/go \ -c .schema/openapi/gen.go.yml @@ -138,6 +139,7 @@ sdk: .bin/swagger .bin/ory node_modules --git-user-id ory \ --git-repo-id client-go \ --git-host github.com \ + --api-name-suffix "Api" \ -t .schema/openapi/templates/go \ -c .schema/openapi/gen.go.yml diff --git a/internal/client-go/.openapi-generator/VERSION b/internal/client-go/.openapi-generator/VERSION index 0df17dd0f6a3..4b49d9bb63ee 100644 --- a/internal/client-go/.openapi-generator/VERSION +++ b/internal/client-go/.openapi-generator/VERSION @@ -1 +1 @@ -6.2.1 \ No newline at end of file +7.2.0 \ No newline at end of file diff --git a/internal/client-go/go.sum b/internal/client-go/go.sum index 734252e68153..c966c8ddfd0d 100644 --- a/internal/client-go/go.sum +++ b/internal/client-go/go.sum @@ -4,8 +4,6 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/internal/httpclient/.openapi-generator/VERSION b/internal/httpclient/.openapi-generator/VERSION index 0df17dd0f6a3..4b49d9bb63ee 100644 --- a/internal/httpclient/.openapi-generator/VERSION +++ b/internal/httpclient/.openapi-generator/VERSION @@ -1 +1 @@ -6.2.1 \ No newline at end of file +7.2.0 \ No newline at end of file diff --git a/openapitools.json b/openapitools.json index f5f966a1030d..64f2cbb54164 100644 --- a/openapitools.json +++ b/openapitools.json @@ -2,6 +2,6 @@ "$schema": "node_modules/@openapitools/openapi-generator-cli/config.schema.json", "spaces": 2, "generator-cli": { - "version": "6.2.1" + "version": "7.2.0" } } diff --git a/package-lock.json b/package-lock.json index e2e32697e06a..8f860f034e72 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,8 +4,9 @@ "requires": true, "packages": { "": { + "name": "kratos", "dependencies": { - "@openapitools/openapi-generator-cli": "2.6.0", + "@openapitools/openapi-generator-cli": "2.7.0", "yamljs": "0.3.0" }, "devDependencies": { @@ -41,35 +42,33 @@ } }, "node_modules/@nestjs/axios": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-0.0.8.tgz", - "integrity": "sha512-oJyfR9/h9tVk776il0829xyj3b2e81yTu6HjPraxynwNtMNGqZBHHmAQL24yMB3tVbBM0RvG3eUXH8+pRCGwlg==", + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-0.1.0.tgz", + "integrity": "sha512-b2TT2X6BFbnNoeteiaxCIiHaFcSbVW+S5yygYqiIq5i6H77yIU3IVuLdpQkHq8/EqOWFwMopLN8jdkUT71Am9w==", "dependencies": { "axios": "0.27.2" }, "peerDependencies": { - "@nestjs/common": "^7.0.0 || ^8.0.0", + "@nestjs/common": "^7.0.0 || ^8.0.0 || ^9.0.0", "reflect-metadata": "^0.1.12", "rxjs": "^6.0.0 || ^7.0.0" } }, "node_modules/@nestjs/common": { - "version": "8.4.7", - "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-8.4.7.tgz", - "integrity": "sha512-m/YsbcBal+gA5CFrDpqXqsSfylo+DIQrkFY3qhVIltsYRfu8ct8J9pqsTO6OPf3mvqdOpFGrV5sBjoyAzOBvsw==", - "peer": true, + "version": "9.3.11", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-9.3.11.tgz", + "integrity": "sha512-IFZ2G/5UKWC2Uo7tJ4SxGed2+aiA+sJyWeWsGTogKVDhq90oxVBToh+uCDeI31HNUpqYGoWmkletfty42zUd8A==", "dependencies": { - "axios": "0.27.2", "iterare": "1.2.1", - "tslib": "2.4.0", - "uuid": "8.3.2" + "tslib": "2.5.0", + "uid": "2.0.1" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/nest" }, "peerDependencies": { - "cache-manager": "*", + "cache-manager": "<=5", "class-transformer": "*", "class-validator": "*", "reflect-metadata": "^0.1.12", @@ -88,10 +87,9 @@ } }, "node_modules/@nestjs/common/node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", - "peer": true + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", @@ -146,12 +144,12 @@ } }, "node_modules/@openapitools/openapi-generator-cli": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@openapitools/openapi-generator-cli/-/openapi-generator-cli-2.6.0.tgz", - "integrity": "sha512-M/aOpR7G+Y1nMf+ofuar8pGszajgfhs1aSPSijkcr2tHTxKAI3sA3YYcOGbszxaNRKFyvOcDq+KP9pcJvKoCHg==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@openapitools/openapi-generator-cli/-/openapi-generator-cli-2.7.0.tgz", + "integrity": "sha512-ieEpHTA/KsDz7ANw03lLPYyjdedDEXYEyYoGBRWdduqXWSX65CJtttjqa8ZaB1mNmIjMtchUHwAYQmTLVQ8HYg==", "hasInstallScript": true, "dependencies": { - "@nestjs/axios": "0.0.8", + "@nestjs/axios": "0.1.0", "@nestjs/common": "9.3.11", "@nestjs/core": "9.3.11", "@nuxtjs/opencollective": "0.3.2", @@ -179,43 +177,6 @@ "url": "https://opencollective.com/openapi_generator" } }, - "node_modules/@openapitools/openapi-generator-cli/node_modules/@nestjs/common": { - "version": "9.3.11", - "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-9.3.11.tgz", - "integrity": "sha512-IFZ2G/5UKWC2Uo7tJ4SxGed2+aiA+sJyWeWsGTogKVDhq90oxVBToh+uCDeI31HNUpqYGoWmkletfty42zUd8A==", - "dependencies": { - "iterare": "1.2.1", - "tslib": "2.5.0", - "uid": "2.0.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nest" - }, - "peerDependencies": { - "cache-manager": "<=5", - "class-transformer": "*", - "class-validator": "*", - "reflect-metadata": "^0.1.12", - "rxjs": "^7.1.0" - }, - "peerDependenciesMeta": { - "cache-manager": { - "optional": true - }, - "class-transformer": { - "optional": true - }, - "class-validator": { - "optional": true - } - } - }, - "node_modules/@openapitools/openapi-generator-cli/node_modules/@nestjs/common/node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - }, "node_modules/@openapitools/openapi-generator-cli/node_modules/@nestjs/core": { "version": "9.3.11", "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-9.3.11.tgz", @@ -268,9 +229,9 @@ } }, "node_modules/@sideway/formula": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", - "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", "dev": true }, "node_modules/@sideway/pinpoint": { @@ -389,19 +350,6 @@ "form-data": "^4.0.0" } }, - "node_modules/axios/node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -847,9 +795,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", - "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", + "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", "funding": [ { "type": "individual", @@ -865,6 +813,19 @@ } } }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", @@ -1261,15 +1222,6 @@ "node": ">=4" } }, - "node_modules/license-checker/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, "node_modules/license-checker/node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -1435,15 +1387,6 @@ "validate-npm-package-license": "^3.0.1" } }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, "node_modules/npm-normalize-package-bin": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", @@ -1640,15 +1583,6 @@ "graceful-fs": "^4.1.2" } }, - "node_modules/read-installed/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, "node_modules/read-package-json": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.2.tgz", @@ -1806,6 +1740,15 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -2062,15 +2005,6 @@ "integrity": "sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA==", "dev": true }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "peer": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -2239,30 +2173,27 @@ "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==" }, "@nestjs/axios": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-0.0.8.tgz", - "integrity": "sha512-oJyfR9/h9tVk776il0829xyj3b2e81yTu6HjPraxynwNtMNGqZBHHmAQL24yMB3tVbBM0RvG3eUXH8+pRCGwlg==", + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-0.1.0.tgz", + "integrity": "sha512-b2TT2X6BFbnNoeteiaxCIiHaFcSbVW+S5yygYqiIq5i6H77yIU3IVuLdpQkHq8/EqOWFwMopLN8jdkUT71Am9w==", "requires": { "axios": "0.27.2" } }, "@nestjs/common": { - "version": "8.4.7", - "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-8.4.7.tgz", - "integrity": "sha512-m/YsbcBal+gA5CFrDpqXqsSfylo+DIQrkFY3qhVIltsYRfu8ct8J9pqsTO6OPf3mvqdOpFGrV5sBjoyAzOBvsw==", - "peer": true, + "version": "9.3.11", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-9.3.11.tgz", + "integrity": "sha512-IFZ2G/5UKWC2Uo7tJ4SxGed2+aiA+sJyWeWsGTogKVDhq90oxVBToh+uCDeI31HNUpqYGoWmkletfty42zUd8A==", "requires": { - "axios": "0.27.2", "iterare": "1.2.1", - "tslib": "2.4.0", - "uuid": "8.3.2" + "tslib": "2.5.0", + "uid": "2.0.1" }, "dependencies": { "tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", - "peer": true + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" } } }, @@ -2303,11 +2234,11 @@ } }, "@openapitools/openapi-generator-cli": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@openapitools/openapi-generator-cli/-/openapi-generator-cli-2.6.0.tgz", - "integrity": "sha512-M/aOpR7G+Y1nMf+ofuar8pGszajgfhs1aSPSijkcr2tHTxKAI3sA3YYcOGbszxaNRKFyvOcDq+KP9pcJvKoCHg==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@openapitools/openapi-generator-cli/-/openapi-generator-cli-2.7.0.tgz", + "integrity": "sha512-ieEpHTA/KsDz7ANw03lLPYyjdedDEXYEyYoGBRWdduqXWSX65CJtttjqa8ZaB1mNmIjMtchUHwAYQmTLVQ8HYg==", "requires": { - "@nestjs/axios": "0.0.8", + "@nestjs/axios": "0.1.0", "@nestjs/common": "9.3.11", "@nestjs/core": "9.3.11", "@nuxtjs/opencollective": "0.3.2", @@ -2325,23 +2256,6 @@ "tslib": "2.0.3" }, "dependencies": { - "@nestjs/common": { - "version": "9.3.11", - "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-9.3.11.tgz", - "integrity": "sha512-IFZ2G/5UKWC2Uo7tJ4SxGed2+aiA+sJyWeWsGTogKVDhq90oxVBToh+uCDeI31HNUpqYGoWmkletfty42zUd8A==", - "requires": { - "iterare": "1.2.1", - "tslib": "2.5.0", - "uid": "2.0.1" - }, - "dependencies": { - "tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - } - } - }, "@nestjs/core": { "version": "9.3.11", "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-9.3.11.tgz", @@ -2374,9 +2288,9 @@ } }, "@sideway/formula": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", - "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", "dev": true }, "@sideway/pinpoint": { @@ -2472,18 +2386,6 @@ "requires": { "follow-redirects": "^1.14.9", "form-data": "^4.0.0" - }, - "dependencies": { - "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - } } }, "balanced-match": { @@ -2810,9 +2712,19 @@ } }, "follow-redirects": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", - "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==" + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", + "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==" + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } }, "fs-extra": { "version": "10.1.0", @@ -3116,12 +3028,6 @@ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -3243,14 +3149,6 @@ "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } } }, "npm-normalize-package-bin": { @@ -3386,14 +3284,6 @@ "semver": "2 || 3 || 4 || 5", "slide": "~1.1.3", "util-extend": "^1.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } } }, "read-package-json": { @@ -3505,6 +3395,12 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + }, "signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -3716,12 +3612,6 @@ "integrity": "sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA==", "dev": true }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "peer": true - }, "validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", diff --git a/package.json b/package.json index 6c2735e4db2d..944faa190bf8 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ }, "prettier": "ory-prettier-styles", "dependencies": { - "@openapitools/openapi-generator-cli": "2.6.0", + "@openapitools/openapi-generator-cli": "2.7.0", "yamljs": "0.3.0" }, "devDependencies": { From 1da818072154baa5c0921134919afde595031e94 Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Thu, 18 Jan 2024 13:39:36 +0100 Subject: [PATCH 229/282] fix: add caching to Jsonnet snippet during session JWT tokenization (#3699) --- go.mod | 3 +-- go.sum | 21 ++------------- persistence/sql/persister_test.go | 43 ++++++++++++++++++------------- session/tokenizer.go | 34 ++++++++++++++++++------ 4 files changed, 54 insertions(+), 47 deletions(-) diff --git a/go.mod b/go.mod index 7232373c704c..6e64290855d1 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,6 @@ require ( github.com/fatih/color v1.13.0 github.com/ghodss/yaml v1.0.0 github.com/go-crypt/crypt v0.2.9 - github.com/go-errors/errors v1.0.1 github.com/go-faker/faker/v4 v4.2.0 github.com/go-openapi/strfmt v0.21.7 github.com/go-playground/validator/v10 v10.4.1 @@ -127,7 +126,7 @@ require ( github.com/boombuler/barcode v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/cockroachdb/cockroach-go/v2 v2.2.16 // indirect + github.com/cockroachdb/cockroach-go/v2 v2.3.5 github.com/containerd/continuity v0.3.0 // indirect github.com/cortesi/moddwatch v0.0.0-20210222043437-a6aaad86a36e // indirect github.com/cortesi/termlog v0.0.0-20210222042314-a1eec763abec // indirect diff --git a/go.sum b/go.sum index bc1e37527262..bc6051c55224 100644 --- a/go.sum +++ b/go.sum @@ -123,8 +123,8 @@ github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnht github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/cockroachdb/cockroach-go/v2 v2.2.16 h1:t9dmZuC9J2W8IDQDSIGXmP+fBuEJSsrGXxWQz4cYqBY= -github.com/cockroachdb/cockroach-go/v2 v2.2.16/go.mod h1:xZ2VHjUEb/cySv0scXBx7YsBnHtLHkR1+w/w73b5i3M= +github.com/cockroachdb/cockroach-go/v2 v2.3.5 h1:Khtm8K6fTTz/ZCWPzU9Ne3aOW9VyAnj4qIPCJgKtwK0= +github.com/cockroachdb/cockroach-go/v2 v2.3.5/go.mod h1:1wNJ45eSXW9AnOc3skntW9ZUZz6gxrQK3cOj3rK+BC8= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= @@ -208,8 +208,6 @@ github.com/go-crypt/crypt v0.2.9 h1:5gWWTId2Qyqs9ROIsegt5pnqo9wUSRLbhpkR6JSftjg= github.com/go-crypt/crypt v0.2.9/go.mod h1:JjzdTYE2mArb6nBoIvvpF7o46/rK/1pfmlArCRMTFUk= github.com/go-crypt/x v0.2.1 h1:OGw78Bswme9lffCOX6tyuC280ouU5391glsvThMtM5U= github.com/go-crypt/x v0.2.1/go.mod h1:Q/y9rms7yw4/1CavBlNGn0Itg4HqwNpe1N9FX0TxXrc= -github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= -github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-faker/faker/v4 v4.2.0 h1:dGebOupKwssrODV51E0zbMrv5e2gO9VWSLNC1WDCpWg= github.com/go-faker/faker/v4 v4.2.0/go.mod h1:F/bBy8GH9NxOxMInug5Gx4WYeG6fHJZ8Ol/dhcpRub4= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -563,8 +561,6 @@ github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsU github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.12.0/go.mod h1:ZkhRC59Llhrq3oSfrikvwQ5NaxYExr6twkdkMLaKono= -github.com/jackc/pgconn v1.12.1/go.mod h1:ZkhRC59Llhrq3oSfrikvwQ5NaxYExr6twkdkMLaKono= github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys= github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= @@ -582,7 +578,6 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvW github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y= github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= @@ -591,21 +586,17 @@ github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01C 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.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.11.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w= github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= 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.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.16.0/go.mod h1:N0A9sFdWzkw/Jy1lwoiB64F2+ugFZi987zRxcPez/wI= -github.com/jackc/pgx/v4 v4.16.1/go.mod h1:SIhx0D5hoADaiXZVyv+3gSm3LCIIINTVO0PficsvWGQ= github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E= github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw= 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.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jandelgado/gcov2lcov v1.0.5 h1:rkBt40h0CVK4oCb8Dps950gvfd1rYvQ8+cWa346lVU0= github.com/jandelgado/gcov2lcov v1.0.5/go.mod h1:NnSxK6TMlg1oGDBfGelGbjgorT5/L3cchlbtgFYZSss= @@ -616,8 +607,6 @@ github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LF github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg= github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= -github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= @@ -697,7 +686,6 @@ 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.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/luna-duclos/instrumentedsql v1.1.3 h1:t7mvC0z1jUt5A0UQ6I/0H31ryymuQRnJcWCiqV3lSAA= @@ -1131,7 +1119,6 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220517005047-85d78b3ac167/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= @@ -1341,7 +1328,6 @@ golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1617,9 +1603,6 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/postgres v1.3.5/go.mod h1:EGCWefLFQSVFrHGy4J8EtiHCWX5Q8t0yz2Jt9aKkGzU= -gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= -gorm.io/gorm v1.23.5/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.2.0 h1:I0DwBVMGAx26dttAj1BtJLAkVGncrkkUXfJLC4Flt/I= gotest.tools/v3 v3.2.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A= diff --git a/persistence/sql/persister_test.go b/persistence/sql/persister_test.go index 088c7cb13e19..f88d7380a5c7 100644 --- a/persistence/sql/persister_test.go +++ b/persistence/sql/persister_test.go @@ -11,35 +11,26 @@ import ( "testing" "time" - "golang.org/x/sync/errgroup" - - "github.com/ory/x/sqlxx" - "github.com/ory/x/urlx" - - "github.com/ory/kratos/driver/config" - "github.com/ory/kratos/schema" - - "github.com/ory/kratos/x/xsql" - - "github.com/go-errors/errors" + "github.com/cockroachdb/cockroach-go/v2/testserver" "github.com/gobuffalo/pop/v6" "github.com/gobuffalo/pop/v6/logging" + "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - - "github.com/ory/x/sqlcon" - "github.com/ory/x/sqlcon/dockertest" + "golang.org/x/sync/errgroup" continuity "github.com/ory/kratos/continuity/test" "github.com/ory/kratos/corpx" courier "github.com/ory/kratos/courier/test" "github.com/ory/kratos/driver" + "github.com/ory/kratos/driver/config" ri "github.com/ory/kratos/identity" identity "github.com/ory/kratos/identity/test" "github.com/ory/kratos/internal" "github.com/ory/kratos/internal/testhelpers" "github.com/ory/kratos/persistence/sql" sqltesthelpers "github.com/ory/kratos/persistence/sql/testhelpers" + "github.com/ory/kratos/schema" errorx "github.com/ory/kratos/selfservice/errorx/test" lf "github.com/ory/kratos/selfservice/flow/login" login "github.com/ory/kratos/selfservice/flow/login/test" @@ -52,6 +43,11 @@ import ( link "github.com/ory/kratos/selfservice/strategy/link/test" session "github.com/ory/kratos/session/test" "github.com/ory/kratos/x" + "github.com/ory/kratos/x/xsql" + "github.com/ory/x/sqlcon" + "github.com/ory/x/sqlcon/dockertest" + "github.com/ory/x/sqlxx" + "github.com/ory/x/urlx" ) func init() { @@ -59,7 +55,7 @@ func init() { pop.SetNowFunc(func() time.Time { return time.Now().UTC().Round(time.Second) }) - //pop.Debug = true + // pop.Debug = true } func TestMain(m *testing.M) { @@ -104,9 +100,9 @@ func createCleanDatabases(t testing.TB) map[string]*driver.RegistryDefault { var l sync.Mutex if !testing.Short() { funcs := map[string]func(t testing.TB) string{ - //"postgres": dockertest.RunTestPostgreSQL, - //"mysql": dockertest.RunTestMySQL, - "cockroach": dockertest.NewLocalTestCRDBServer, + "postgres": dockertest.RunTestPostgreSQL, + "mysql": dockertest.RunTestMySQL, + "cockroach": newLocalTestCRDBServer, } var wg sync.WaitGroup @@ -386,3 +382,14 @@ func Benchmark_BatchCreateIdentities(b *testing.B) { }) } } + +func newLocalTestCRDBServer(t testing.TB) string { + ts, err := testserver.NewTestServer(testserver.CustomVersionOpt("23.1.13")) + require.NoError(t, err) + t.Cleanup(ts.Stop) + + require.NoError(t, ts.WaitForInit()) + + ts.PGURL().Scheme = "cockroach" + return ts.PGURL().String() +} diff --git a/session/tokenizer.go b/session/tokenizer.go index f4317f067ac1..2d1decb352e5 100644 --- a/session/tokenizer.go +++ b/session/tokenizer.go @@ -5,21 +5,21 @@ package session import ( "context" + "crypto/sha256" "encoding/json" "time" - "go.opentelemetry.io/otel/trace" - - "github.com/ory/kratos/x/events" - + "github.com/dgraph-io/ristretto" "github.com/gofrs/uuid" "github.com/golang-jwt/jwt/v5" "github.com/pkg/errors" "github.com/tidwall/gjson" + "go.opentelemetry.io/otel/trace" "github.com/ory/herodot" "github.com/ory/kratos/driver/config" "github.com/ory/kratos/x" + "github.com/ory/kratos/x/events" "github.com/ory/x/fetcher" "github.com/ory/x/jsonnetsecure" "github.com/ory/x/jwksx" @@ -51,6 +51,16 @@ func (s *Tokenizer) SetNowFunc(t func() time.Time) { s.nowFunc = t } +var cache, _ = ristretto.NewCache(&ristretto.Config{ + NumCounters: 100000000, + MaxCost: 10000000, + BufferItems: 64, + IgnoreInternalCost: true, + Cost: func(value interface{}) int64 { + return 1 + }, +}) + func (s *Tokenizer) TokenizeSession(ctx context.Context, template string, session *Session) (err error) { ctx, span := s.r.Tracer(ctx).Tracer().Start(ctx, "sessions.ManagerHTTP.TokenizeSession") defer otelx.End(span, &err) @@ -100,9 +110,17 @@ func (s *Tokenizer) TokenizeSession(ctx context.Context, template string, sessio } if mapper := tpl.ClaimsMapperURL; len(mapper) > 0 { - jn, err := fetch.FetchContext(ctx, mapper) - if err != nil { - return err + var jsonnet string + cacheKey := sha256.Sum256([]byte(mapper)) + if result, found := cache.Get(cacheKey[:]); found { + jsonnet = result.(string) + } else { + jn, err := fetch.FetchContext(ctx, mapper) + if err != nil { + return err + } + jsonnet = jn.String() + cache.SetWithTTL(cacheKey[:], jsonnet, 1, time.Hour) } sessionRaw, err := json.Marshal(session) @@ -118,7 +136,7 @@ func (s *Tokenizer) TokenizeSession(ctx context.Context, template string, sessio vm.ExtCode("session", string(sessionRaw)) vm.ExtCode("claims", string(claimsRaw)) - evaluated, err := vm.EvaluateAnonymousSnippet(tpl.ClaimsMapperURL, jn.String()) + evaluated, err := vm.EvaluateAnonymousSnippet(tpl.ClaimsMapperURL, jsonnet) if err != nil { return errors.WithStack(herodot.ErrBadRequest.WithWrap(err).WithDebug(err.Error()).WithReasonf("Unable to execute tokenizer JsonNet.")) } From 55560a1eedc7741f3a732c3d61f4eb4bb8af88c1 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Thu, 18 Jan 2024 13:24:28 +0000 Subject: [PATCH 230/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d2c0f47a526..dfceab4c189b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2024-01-08)](#2024-01-08) +- [ (2024-01-18)](#2024-01-18) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -314,7 +314,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2024-01-08) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2024-01-18) ## Breaking Changes @@ -372,6 +372,9 @@ https://github.com/ory/kratos/pull/3480 Part of https://github.com/ory/network/issues/320 +- Add caching to Jsonnet snippet during session JWT tokenization + ([#3699](https://github.com/ory/kratos/issues/3699)) + ([1da8180](https://github.com/ory/kratos/commit/1da818072154baa5c0921134919afde595031e94)) - Add max-age to default cors headers ([#3584](https://github.com/ory/kratos/issues/3584)) ([c5b4aaa](https://github.com/ory/kratos/commit/c5b4aaa2df5d010b62a99ccf45850583daad3a66)) From d93570d330155c27a9315d1f530a0002a459910a Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Fri, 19 Jan 2024 11:38:21 +0100 Subject: [PATCH 231/282] fix: do not generate CSRF token for api flows (#3704) --- .../strategy/code/strategy_recovery.go | 3 +- .../strategy/code/strategy_recovery_test.go | 37 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/selfservice/strategy/code/strategy_recovery.go b/selfservice/strategy/code/strategy_recovery.go index 2a917f0dcecd..894166a236a2 100644 --- a/selfservice/strategy/code/strategy_recovery.go +++ b/selfservice/strategy/code/strategy_recovery.go @@ -170,7 +170,6 @@ func (s *Strategy) recoveryIssueSession(w http.ResponseWriter, r *http.Request, f.UI.Messages.Clear() f.State = flow.StatePassedChallenge - f.SetCSRFToken(s.deps.CSRFHandler().RegenerateToken(w, r)) f.RecoveredIdentityID = uuid.NullUUID{ UUID: id.ID, Valid: true, @@ -191,6 +190,8 @@ func (s *Strategy) recoveryIssueSession(w http.ResponseWriter, r *http.Request, switch f.Type { case flow.TypeBrowser: + f.SetCSRFToken(s.deps.CSRFHandler().RegenerateToken(w, r)) + if err := s.deps.SessionManager().UpsertAndIssueCookie(ctx, w, r, sess); err != nil { return s.retryRecoveryFlow(w, r, f.Type, RetryWithError(err)) } diff --git a/selfservice/strategy/code/strategy_recovery_test.go b/selfservice/strategy/code/strategy_recovery_test.go index b481a37c8726..29a054c28550 100644 --- a/selfservice/strategy/code/strategy_recovery_test.go +++ b/selfservice/strategy/code/strategy_recovery_test.go @@ -1574,6 +1574,43 @@ func TestRecovery_WithContinueWith(t *testing.T) { } }) + t.Run("description=does not issue csrf cookie when submitting API flow", func(t *testing.T) { + t.Run("type="+RecoveryClientTypeAPI.String(), func(t *testing.T) { + c := new(http.Client) + recoveryEmail := testhelpers.RandomEmail() + _ = createIdentityToRecover(t, reg, recoveryEmail) + + actual := submitRecoveryForm(t, c, RecoveryClientTypeAPI, func(v url.Values) { + v.Set("email", recoveryEmail) + }, http.StatusOK) + + message := testhelpers.CourierExpectMessage(ctx, t, reg, recoveryEmail, "Recover access to your account") + recoveryCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) + + action := gjson.Get(actual, "ui.action").String() + require.NotEmpty(t, action) + + flowId := gjson.Get(actual, "id").String() + require.NotEmpty(t, flowId) + + form := withCSRFToken(t, RecoveryClientTypeAPI, actual, url.Values{ + "code": {recoveryCode}, + }) + + // Now submit the correct code + res, err := c.Post(action, "application/json", bytes.NewBufferString(form)) + require.NoError(t, err) + + assert.Equal(t, http.StatusOK, res.StatusCode) + + assert.Empty(t, res.Header.Get("Set-Cookie")) + + json := ioutilx.MustReadAll(res.Body) + require.NotEmpty(t, gjson.GetBytes(json, "continue_with.#(action==show_settings_ui).flow").String(), "%s", json) + require.NotEmpty(t, gjson.GetBytes(json, "continue_with.#(action==set_ory_session_token).ory_session_token").String(), "%s", json) + }) + }) + t.Run("description=should not be able to use an invalid code", func(t *testing.T) { for _, testCase := range flowTypeCases { t.Run("type="+testCase.ClientType.String(), func(t *testing.T) { From 5a192f2631ae2844c8c6b77a6c5f047f0fd3d322 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Fri, 19 Jan 2024 11:20:01 +0000 Subject: [PATCH 232/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dfceab4c189b..4dbff6be101a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2024-01-18)](#2024-01-18) +- [ (2024-01-19)](#2024-01-19) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -314,7 +314,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2024-01-18) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2024-01-19) ## Breaking Changes @@ -442,6 +442,9 @@ https://github.com/ory/kratos/pull/3480 - Do not encode full config in multiple places ([#3500](https://github.com/ory/kratos/issues/3500)) ([57a3273](https://github.com/ory/kratos/commit/57a3273055c6e8627dd0b736e881dba3fb0fe75d)) +- Do not generate CSRF token for api flows + ([#3704](https://github.com/ory/kratos/issues/3704)) + ([d93570d](https://github.com/ory/kratos/commit/d93570d330155c27a9315d1f530a0002a459910a)) - Do not initialize parts of the registry in parallel ([#3534](https://github.com/ory/kratos/issues/3534)) ([ff177db](https://github.com/ory/kratos/commit/ff177db8a97f27abc3e883e79832685348602334)) From 1d26e097b273aeda36f73637765da5bdb2aa4a66 Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Fri, 19 Jan 2024 12:28:12 +0100 Subject: [PATCH 233/282] feat: jsonnet caching for OIDC claims mapper, webhooks, JWT session tokenizer (#3701) --- courier/http_channel.go | 3 +- courier/template/load_template.go | 9 +--- driver/registry_default.go | 2 +- go.mod | 6 +-- go.sum | 12 ++--- request/builder.go | 25 ++++++----- request/builder_test.go | 4 +- selfservice/hook/web_hook.go | 9 +++- .../strategy/oidc/strategy_registration.go | 43 +++++++++--------- session/tokenizer.go | 45 +++++++------------ x/fetcher.go | 4 +- 11 files changed, 74 insertions(+), 88 deletions(-) diff --git a/courier/http_channel.go b/courier/http_channel.go index 41315f33e067..e9015dca13fd 100644 --- a/courier/http_channel.go +++ b/courier/http_channel.go @@ -59,7 +59,7 @@ func (c *httpChannel) Dispatch(ctx context.Context, msg Message) (err error) { ctx, span := c.d.Tracer(ctx).Tracer().Start(ctx, "courier.httpChannel.Dispatch") defer otelx.End(span, &err) - builder, err := request.NewBuilder(ctx, c.requestConfig, c.d) + builder, err := request.NewBuilder(ctx, c.requestConfig, c.d, nil) if err != nil { return errors.WithStack(err) } @@ -82,6 +82,7 @@ func (c *httpChannel) Dispatch(ctx context.Context, msg Message) (err error) { if err != nil { return errors.WithStack(err) } + req = req.WithContext(ctx) res, err := c.d.HTTPClient(ctx).Do(req) if err != nil { diff --git a/courier/template/load_template.go b/courier/template/load_template.go index 58b46f898b9d..47341b8f35af 100644 --- a/courier/template/load_template.go +++ b/courier/template/load_template.go @@ -78,24 +78,19 @@ func loadBuiltInTemplate(filesystem fs.FS, name string, html bool) (Template, er return tpl, nil } -func loadRemoteTemplate(ctx context.Context, d templateDependencies, url string, html bool) (Template, error) { +func loadRemoteTemplate(ctx context.Context, d templateDependencies, url string, html bool) (t Template, err error) { var b []byte - var err error - - // instead of creating a new request always we always cache the bytes.Buffer using the url as the key if t, found := Cache.Get(url); found { b = t.([]byte) } else { f := fetcher.NewFetcher(fetcher.WithClient(d.HTTPClient(ctx))) - bb, err := f.FetchContext(ctx, url) + b, err = f.FetchContext(ctx, url) if err != nil { return nil, errors.WithStack(err) } - b = bb.Bytes() _ = Cache.Add(url, b) } - var t Template if html { t, err = htemplate.New(url).Funcs(sprig.HermeticHtmlFuncMap()).Parse(string(b)) if err != nil { diff --git a/driver/registry_default.go b/driver/registry_default.go index f9c47bb30739..a267d9cb637d 100644 --- a/driver/registry_default.go +++ b/driver/registry_default.go @@ -875,7 +875,7 @@ func (m *RegistryDefault) Contextualizer() contextx.Contextualizer { return m.ctxer } -func (m *RegistryDefault) Fetcher() *jwksx.FetcherNext { +func (m *RegistryDefault) JWKSFetcher() *jwksx.FetcherNext { if m.jwkFetcher == nil { maxItems := int64(10000000) cache, _ := ristretto.NewCache(&ristretto.Config{ diff --git a/go.mod b/go.mod index 6e64290855d1..42b2bad25942 100644 --- a/go.mod +++ b/go.mod @@ -75,7 +75,7 @@ require ( github.com/ory/jsonschema/v3 v3.0.8 github.com/ory/mail/v3 v3.0.0 github.com/ory/nosurf v1.2.7 - github.com/ory/x v0.0.607 + github.com/ory/x v0.0.610 github.com/peterhellberg/link v1.2.0 github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 github.com/pkg/errors v0.9.1 @@ -297,8 +297,8 @@ require ( github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect go.mongodb.org/mongo-driver v1.11.3 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.46.1 // indirect - go.opentelemetry.io/contrib/propagators/b3 v1.20.0 // indirect - go.opentelemetry.io/contrib/propagators/jaeger v1.20.0 // indirect + go.opentelemetry.io/contrib/propagators/b3 v1.21.0 // indirect + go.opentelemetry.io/contrib/propagators/jaeger v1.21.1 // indirect go.opentelemetry.io/contrib/samplers/jaegerremote v0.15.1 // indirect go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect; / indirect diff --git a/go.sum b/go.sum index bc6051c55224..b3b463884b74 100644 --- a/go.sum +++ b/go.sum @@ -828,8 +828,8 @@ github.com/ory/nosurf v1.2.7 h1:YrHrbSensQyU6r6HT/V5+HPdVEgrOTMJiLoJABSBOp4= github.com/ory/nosurf v1.2.7/go.mod h1:d4L3ZBa7Amv55bqxCBtCs63wSlyaiCkWVl4vKf3OUxA= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2 h1:zm6sDvHy/U9XrGpixwHiuAwpp0Ock6khSVHkrv6lQQU= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/ory/x v0.0.607 h1:qNP1gU6RWVtsEB04rPht+1rV2DqQhvOAN2sF+4eqVWo= -github.com/ory/x v0.0.607/go.mod h1:fCYvVVHo8wYrCwLyU8+9hFY3IRo4EZM3KI30ysDsDYY= +github.com/ory/x v0.0.610 h1:SY1X5jfJVq45zeZEIc1XWqlE+lna+rMjeLxMoRdx0bY= +github.com/ory/x v0.0.610/go.mod h1:FkkwV9h7U9VqDe6Xkdl7KKLCfDC1sQcO+q2iCBAA0Ho= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -1061,10 +1061,10 @@ go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0. go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.46.1/go.mod h1:GnOaBaFQ2we3b9AGWJpsBa7v1S5RlQzlC3O7dRMxZhM= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= -go.opentelemetry.io/contrib/propagators/b3 v1.20.0 h1:Yty9Vs4F3D6/liF1o6FNt0PvN85h/BJJ6DQKJ3nrcM0= -go.opentelemetry.io/contrib/propagators/b3 v1.20.0/go.mod h1:On4VgbkqYL18kbJlWsa18+cMNe6rYpBnPi1ARI/BrsU= -go.opentelemetry.io/contrib/propagators/jaeger v1.20.0 h1:iVhNKkMIpzyZqxk8jkDU2n4DFTD+FbpGacvooxEvyyc= -go.opentelemetry.io/contrib/propagators/jaeger v1.20.0/go.mod h1:cpSABr0cm/AH/HhbJjn+AudBVUMgZWdfN3Gb+ZqxSZc= +go.opentelemetry.io/contrib/propagators/b3 v1.21.0 h1:uGdgDPNzwQWRwCXJgw/7h29JaRqcq9B87Iv4hJDKAZw= +go.opentelemetry.io/contrib/propagators/b3 v1.21.0/go.mod h1:D9GQXvVGT2pzyTfp1QBOnD1rzKEWzKjjwu5q2mslCUI= +go.opentelemetry.io/contrib/propagators/jaeger v1.21.1 h1:f4beMGDKiVzg9IcX7/VuWVy+oGdjx3dNJ72YehmtY5k= +go.opentelemetry.io/contrib/propagators/jaeger v1.21.1/go.mod h1:U9jhkEl8d1LL+QXY7q3kneJWJugiN3kZJV2OWz3hkBY= go.opentelemetry.io/contrib/samplers/jaegerremote v0.15.1 h1:Qb+5A+JbIjXwO7l4HkRUhgIn4Bzz0GNS2q+qdmSx+0c= go.opentelemetry.io/contrib/samplers/jaegerremote v0.15.1/go.mod h1:G4vNCm7fRk0kjZ6pGNLo5SpLxAUvOfSrcaegnT8TPck= go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= diff --git a/request/builder.go b/request/builder.go index f930bc089aae..f407c8c5c763 100644 --- a/request/builder.go +++ b/request/builder.go @@ -12,18 +12,18 @@ import ( "net/url" "reflect" "strings" + "time" - "go.opentelemetry.io/otel/attribute" - - "github.com/ory/x/otelx" - + "github.com/dgraph-io/ristretto" "github.com/google/go-jsonnet" "github.com/hashicorp/go-retryablehttp" "github.com/pkg/errors" + "go.opentelemetry.io/otel/attribute" "github.com/ory/kratos/x" "github.com/ory/x/fetcher" "github.com/ory/x/jsonnetsecure" + "github.com/ory/x/otelx" ) var ErrCancel = errors.New("request cancel by JsonNet") @@ -44,10 +44,11 @@ type ( r *retryablehttp.Request Config *Config deps Dependencies + cache *ristretto.Cache } ) -func NewBuilder(ctx context.Context, config json.RawMessage, deps Dependencies) (_ *Builder, err error) { +func NewBuilder(ctx context.Context, config json.RawMessage, deps Dependencies, jsonnetCache *ristretto.Cache) (_ *Builder, err error) { _, span := deps.Tracer(ctx).Tracer().Start(ctx, "request.NewBuilder") defer otelx.End(span, &err) @@ -67,6 +68,7 @@ func NewBuilder(ctx context.Context, config json.RawMessage, deps Dependencies) r: r, Config: c, deps: deps, + cache: jsonnetCache, }, nil } @@ -118,7 +120,7 @@ func (b *Builder) addBody(ctx context.Context, body interface{}) error { return nil } -func (b *Builder) addJSONBody(ctx context.Context, template *bytes.Buffer, body interface{}) error { +func (b *Builder) addJSONBody(ctx context.Context, jsonnetSnippet []byte, body interface{}) error { buf := new(bytes.Buffer) enc := json.NewEncoder(buf) enc.SetEscapeHTML(false) @@ -136,7 +138,7 @@ func (b *Builder) addJSONBody(ctx context.Context, template *bytes.Buffer, body res, err := vm.EvaluateAnonymousSnippet( b.Config.TemplateURI, - template.String(), + string(jsonnetSnippet), ) if err != nil { // Unfortunately we can not use errors.As / errors.Is, see: @@ -156,7 +158,7 @@ func (b *Builder) addJSONBody(ctx context.Context, template *bytes.Buffer, body return nil } -func (b *Builder) addURLEncodedBody(ctx context.Context, template *bytes.Buffer, body interface{}) error { +func (b *Builder) addURLEncodedBody(ctx context.Context, jsonnetSnippet []byte, body interface{}) error { buf := new(bytes.Buffer) enc := json.NewEncoder(buf) enc.SetEscapeHTML(false) @@ -172,7 +174,7 @@ func (b *Builder) addURLEncodedBody(ctx context.Context, template *bytes.Buffer, } vm.TLACode("ctx", buf.String()) - res, err := vm.EvaluateAnonymousSnippet(b.Config.TemplateURI, template.String()) + res, err := vm.EvaluateAnonymousSnippet(b.Config.TemplateURI, string(jsonnetSnippet)) if err != nil { return errors.WithStack(err) } @@ -213,15 +215,14 @@ func (b *Builder) BuildRequest(ctx context.Context, body interface{}) (*retryabl return b.r, nil } -func (b *Builder) readTemplate(ctx context.Context) (*bytes.Buffer, error) { +func (b *Builder) readTemplate(ctx context.Context) ([]byte, error) { templateURI := b.Config.TemplateURI if templateURI == "" { return nil, nil } - f := fetcher.NewFetcher(fetcher.WithClient(b.deps.HTTPClient(ctx))) - + f := fetcher.NewFetcher(fetcher.WithClient(b.deps.HTTPClient(ctx)), fetcher.WithCache(b.cache, 60*time.Minute)) tpl, err := f.FetchContext(ctx, templateURI) if errors.Is(err, fetcher.ErrUnknownScheme) { // legacy filepath diff --git a/request/builder_test.go b/request/builder_test.go index cffa032cc2f9..8269b5133346 100644 --- a/request/builder_test.go +++ b/request/builder_test.go @@ -245,7 +245,7 @@ func TestBuildRequest(t *testing.T) { } { t.Run( "request-type="+tc.name, func(t *testing.T) { - rb, err := NewBuilder(context.Background(), json.RawMessage(tc.rawConfig), newTestDependencyProvider(t)) + rb, err := NewBuilder(context.Background(), json.RawMessage(tc.rawConfig), newTestDependencyProvider(t), nil) require.NoError(t, err) assert.Equal(t, tc.bodyTemplateURI, rb.Config.TemplateURI) @@ -279,7 +279,7 @@ func TestBuildRequest(t *testing.T) { "method": "POST", "body": "file://./stub/cancel_body.jsonnet" }`, - ), newTestDependencyProvider(t)) + ), newTestDependencyProvider(t), nil) require.NoError(t, err) _, err = rb.BuildRequest(context.Background(), json.RawMessage(`{}`)) diff --git a/selfservice/hook/web_hook.go b/selfservice/hook/web_hook.go index c06d47a216ba..5c9aa31e92fa 100644 --- a/selfservice/hook/web_hook.go +++ b/selfservice/hook/web_hook.go @@ -12,6 +12,7 @@ import ( "net/http/httputil" "time" + "github.com/dgraph-io/ristretto" "github.com/gofrs/uuid" "github.com/hashicorp/go-retryablehttp" "github.com/pkg/errors" @@ -60,6 +61,12 @@ var _ interface { settings.PostHookPostPersistExecutor } = (*WebHook)(nil) +var jsonnetCache, _ = ristretto.NewCache(&ristretto.Config{ + MaxCost: 100 << 20, // 100MB, + NumCounters: 1_000_000, // 1kB per snippet -> 100k snippets -> 1M counters + BufferItems: 64, +}) + type ( webHookDependencies interface { x.LoggingProvider @@ -334,7 +341,7 @@ func (e *WebHook) execute(ctx context.Context, data *templateContext) error { } }(time.Now()) - builder, err := request.NewBuilder(ctx, e.conf, e.deps) + builder, err := request.NewBuilder(ctx, e.conf, e.deps, jsonnetCache) if err != nil { return err } diff --git a/selfservice/strategy/oidc/strategy_registration.go b/selfservice/strategy/oidc/strategy_registration.go index d3f3b217f760..27b4a74eb9f5 100644 --- a/selfservice/strategy/oidc/strategy_registration.go +++ b/selfservice/strategy/oidc/strategy_registration.go @@ -10,39 +10,36 @@ import ( "strings" "time" + "github.com/dgraph-io/ristretto" "github.com/gofrs/uuid" "github.com/julienschmidt/httprouter" - - "github.com/ory/x/otelx" - "github.com/ory/x/sqlxx" - - "github.com/ory/herodot" - - "github.com/ory/x/fetcher" - + "github.com/pkg/errors" "github.com/tidwall/gjson" "github.com/tidwall/sjson" - - "github.com/ory/x/decoderx" - "golang.org/x/oauth2" - "github.com/ory/kratos/selfservice/flow/login" - - "github.com/ory/kratos/text" - - "github.com/pkg/errors" - + "github.com/ory/herodot" "github.com/ory/kratos/continuity" - "github.com/ory/kratos/identity" "github.com/ory/kratos/selfservice/flow" + "github.com/ory/kratos/selfservice/flow/login" "github.com/ory/kratos/selfservice/flow/registration" + "github.com/ory/kratos/text" "github.com/ory/kratos/x" + "github.com/ory/x/decoderx" + "github.com/ory/x/fetcher" + "github.com/ory/x/otelx" + "github.com/ory/x/sqlxx" ) var _ registration.Strategy = new(Strategy) +var jsonnetCache, _ = ristretto.NewCache(&ristretto.Config{ + MaxCost: 100 << 20, // 100MB, + NumCounters: 1_000_000, // 1kB per snippet -> 100k snippets -> 1M counters + BufferItems: 64, +}) + type MetadataType string type VerifiedAddress struct { @@ -308,13 +305,13 @@ func (s *Strategy) processRegistration(w http.ResponseWriter, r *http.Request, r return nil, nil } - fetch := fetcher.NewFetcher(fetcher.WithClient(s.d.HTTPClient(r.Context()))) - jn, err := fetch.FetchContext(r.Context(), provider.Config().Mapper) + fetch := fetcher.NewFetcher(fetcher.WithClient(s.d.HTTPClient(r.Context())), fetcher.WithCache(jsonnetCache, 60*time.Minute)) + jsonnetMapperSnippet, err := fetch.FetchContext(r.Context(), provider.Config().Mapper) if err != nil { return nil, s.handleError(w, r, rf, provider.Config().ID, nil, err) } - i, va, err := s.createIdentity(w, r, rf, claims, provider, container, jn) + i, va, err := s.createIdentity(w, r, rf, claims, provider, container, jsonnetMapperSnippet) if err != nil { return nil, s.handleError(w, r, rf, provider.Config().ID, nil, err) } @@ -369,7 +366,7 @@ func (s *Strategy) processRegistration(w http.ResponseWriter, r *http.Request, r return nil, nil } -func (s *Strategy) createIdentity(w http.ResponseWriter, r *http.Request, a *registration.Flow, claims *Claims, provider Provider, container *AuthCodeContainer, jn *bytes.Buffer) (*identity.Identity, []VerifiedAddress, error) { +func (s *Strategy) createIdentity(w http.ResponseWriter, r *http.Request, a *registration.Flow, claims *Claims, provider Provider, container *AuthCodeContainer, jsonnetSnippet []byte) (*identity.Identity, []VerifiedAddress, error) { var jsonClaims bytes.Buffer if err := json.NewEncoder(&jsonClaims).Encode(claims); err != nil { return nil, nil, s.handleError(w, r, a, provider.Config().ID, nil, err) @@ -381,7 +378,7 @@ func (s *Strategy) createIdentity(w http.ResponseWriter, r *http.Request, a *reg } vm.ExtCode("claims", jsonClaims.String()) - evaluated, err := vm.EvaluateAnonymousSnippet(provider.Config().Mapper, jn.String()) + evaluated, err := vm.EvaluateAnonymousSnippet(provider.Config().Mapper, string(jsonnetSnippet)) if err != nil { return nil, nil, s.handleError(w, r, a, provider.Config().ID, nil, err) } diff --git a/session/tokenizer.go b/session/tokenizer.go index 2d1decb352e5..f3c47ef22e0e 100644 --- a/session/tokenizer.go +++ b/session/tokenizer.go @@ -5,7 +5,6 @@ package session import ( "context" - "crypto/sha256" "encoding/json" "time" @@ -32,11 +31,12 @@ type ( x.TracingProvider x.HTTPClientProvider config.Provider - x.JWKFetchProvider + x.JWKSFetchProvider } Tokenizer struct { r tokenizerDependencies nowFunc func() time.Time + cache *ristretto.Cache } TokenizerProvider interface { SessionTokenizer() *Tokenizer @@ -44,23 +44,18 @@ type ( ) func NewTokenizer(r tokenizerDependencies) *Tokenizer { - return &Tokenizer{r: r, nowFunc: time.Now} + cache, _ := ristretto.NewCache(&ristretto.Config{ + MaxCost: 50 << 20, // 50MB, + NumCounters: 500_000, // 1kB per snippet -> 50k snippets -> 500k counters + BufferItems: 64, + }) + return &Tokenizer{r: r, nowFunc: time.Now, cache: cache} } func (s *Tokenizer) SetNowFunc(t func() time.Time) { s.nowFunc = t } -var cache, _ = ristretto.NewCache(&ristretto.Config{ - NumCounters: 100000000, - MaxCost: 10000000, - BufferItems: 64, - IgnoreInternalCost: true, - Cost: func(value interface{}) int64 { - return 1 - }, -}) - func (s *Tokenizer) TokenizeSession(ctx context.Context, template string, session *Session) (err error) { ctx, span := s.r.Tracer(ctx).Tracer().Start(ctx, "sessions.ManagerHTTP.TokenizeSession") defer otelx.End(span, &err) @@ -71,7 +66,7 @@ func (s *Tokenizer) TokenizeSession(ctx context.Context, template string, sessio } httpClient := s.r.HTTPClient(ctx) - key, err := s.r.Fetcher().ResolveKey( + key, err := s.r.JWKSFetcher().ResolveKey( ctx, tpl.JWKSURL, jwksx.WithCacheEnabled(), @@ -94,8 +89,6 @@ func (s *Tokenizer) TokenizeSession(ctx context.Context, template string, sessio return err } - fetch := fetcher.NewFetcher(fetcher.WithClient(httpClient)) - now := s.nowFunc() token := jwt.New(alg) token.Header["kid"] = key.KeyID() @@ -110,19 +103,6 @@ func (s *Tokenizer) TokenizeSession(ctx context.Context, template string, sessio } if mapper := tpl.ClaimsMapperURL; len(mapper) > 0 { - var jsonnet string - cacheKey := sha256.Sum256([]byte(mapper)) - if result, found := cache.Get(cacheKey[:]); found { - jsonnet = result.(string) - } else { - jn, err := fetch.FetchContext(ctx, mapper) - if err != nil { - return err - } - jsonnet = jn.String() - cache.SetWithTTL(cacheKey[:], jsonnet, 1, time.Hour) - } - sessionRaw, err := json.Marshal(session) if err != nil { return errors.WithStack(herodot.ErrInternalServerError.WithWrap(err).WithReasonf("Unable to encode session to JSON.")) @@ -136,7 +116,12 @@ func (s *Tokenizer) TokenizeSession(ctx context.Context, template string, sessio vm.ExtCode("session", string(sessionRaw)) vm.ExtCode("claims", string(claimsRaw)) - evaluated, err := vm.EvaluateAnonymousSnippet(tpl.ClaimsMapperURL, jsonnet) + fetcher := fetcher.NewFetcher(fetcher.WithClient(httpClient), fetcher.WithCache(s.cache, 60*time.Minute)) + jsonnet, err := fetcher.FetchContext(ctx, mapper) + if err != nil { + return err + } + evaluated, err := vm.EvaluateAnonymousSnippet(tpl.ClaimsMapperURL, string(jsonnet)) if err != nil { return errors.WithStack(herodot.ErrBadRequest.WithWrap(err).WithDebug(err.Error()).WithReasonf("Unable to execute tokenizer JsonNet.")) } diff --git a/x/fetcher.go b/x/fetcher.go index 77f3dbf31099..bb6aeaeaa3fb 100644 --- a/x/fetcher.go +++ b/x/fetcher.go @@ -5,6 +5,6 @@ package x import "github.com/ory/x/jwksx" -type JWKFetchProvider interface { - Fetcher() *jwksx.FetcherNext +type JWKSFetchProvider interface { + JWKSFetcher() *jwksx.FetcherNext } From 03d3f478c046a35b18abd4bfaf17b4763bbc4be4 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Fri, 19 Jan 2024 12:13:58 +0000 Subject: [PATCH 234/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dbff6be101a..6061758d69df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -915,6 +915,9 @@ https://github.com/ory/kratos/pull/3480 - Improve performance by computing password hashes while validating ([#3508](https://github.com/ory/kratos/issues/3508)) ([a9786c5](https://github.com/ory/kratos/commit/a9786c599d09f61e2e07df5066ce94feb2d99bac)) +- Jsonnet caching for OIDC claims mapper, webhooks, JWT session tokenizer + ([#3701](https://github.com/ory/kratos/issues/3701)) + ([1d26e09](https://github.com/ory/kratos/commit/1d26e097b273aeda36f73637765da5bdb2aa4a66)) - Link oidc credentials when login ([#3563](https://github.com/ory/kratos/issues/3563)) ([b784949](https://github.com/ory/kratos/commit/b784949d03b849d9d1d594977f75f5843b7b5da8)), From 688111c9a6bf9872657cf6aada77f55fa2520e00 Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Fri, 19 Jan 2024 13:34:07 +0100 Subject: [PATCH 235/282] feat: order sessions by created_at (#3696) --- courier/message.go | 8 ++--- ...8000000_sessions_created_at_index.down.sql | 1 + ...0_sessions_created_at_index.mysql.down.sql | 1 + ...628000000_sessions_created_at_index.up.sql | 1 + persistence/sql/persister_session.go | 11 ++++--- session/handler.go | 2 +- session/handler_test.go | 21 ++++++++++++-- session/session.go | 12 ++++++-- session/test/persistence.go | 29 ++++++++++++++----- x/pagination.go | 3 ++ 10 files changed, 67 insertions(+), 22 deletions(-) create mode 100644 persistence/sql/migrations/sql/20240119094628000000_sessions_created_at_index.down.sql create mode 100644 persistence/sql/migrations/sql/20240119094628000000_sessions_created_at_index.mysql.down.sql create mode 100644 persistence/sql/migrations/sql/20240119094628000000_sessions_created_at_index.up.sql diff --git a/courier/message.go b/courier/message.go index ef39514aee93..2cc8ec5a1e32 100644 --- a/courier/message.go +++ b/courier/message.go @@ -13,6 +13,7 @@ import ( "github.com/ory/herodot" "github.com/ory/kratos/courier/template" + "github.com/ory/kratos/x" "github.com/ory/x/pagination/keysetpagination" "github.com/ory/x/sqlxx" "github.com/ory/x/stringsx" @@ -115,9 +116,6 @@ const ( messageTypeSMSText = "sms" ) -// The format we need to use in the Page tokens, as it's the only format that is understood by all DBs -const dbFormat = "2006-01-02 15:04:05.99999" - func ToMessageType(str string) (MessageType, error) { switch s := stringsx.SwitchExact(str); { case s.AddCase(messageTypeEmailText): @@ -211,14 +209,14 @@ type Message struct { func (m Message) PageToken() keysetpagination.PageToken { return keysetpagination.MapPageToken{ "id": m.ID.String(), - "created_at": m.CreatedAt.Format(dbFormat), + "created_at": m.CreatedAt.Format(x.MapPaginationDateFormat), } } func (m Message) DefaultPageToken() keysetpagination.PageToken { return keysetpagination.MapPageToken{ "id": uuid.Nil.String(), - "created_at": time.Date(2200, 12, 31, 23, 59, 59, 0, time.UTC).Format(dbFormat), + "created_at": time.Date(2200, 12, 31, 23, 59, 59, 0, time.UTC).Format(x.MapPaginationDateFormat), } } diff --git a/persistence/sql/migrations/sql/20240119094628000000_sessions_created_at_index.down.sql b/persistence/sql/migrations/sql/20240119094628000000_sessions_created_at_index.down.sql new file mode 100644 index 000000000000..5f937e301376 --- /dev/null +++ b/persistence/sql/migrations/sql/20240119094628000000_sessions_created_at_index.down.sql @@ -0,0 +1 @@ +DROP INDEX sessions_nid_created_at_id_idx; \ No newline at end of file diff --git a/persistence/sql/migrations/sql/20240119094628000000_sessions_created_at_index.mysql.down.sql b/persistence/sql/migrations/sql/20240119094628000000_sessions_created_at_index.mysql.down.sql new file mode 100644 index 000000000000..50d8926a5f31 --- /dev/null +++ b/persistence/sql/migrations/sql/20240119094628000000_sessions_created_at_index.mysql.down.sql @@ -0,0 +1 @@ +DROP INDEX sessions_nid_created_at_id_idx ON sessions; \ No newline at end of file diff --git a/persistence/sql/migrations/sql/20240119094628000000_sessions_created_at_index.up.sql b/persistence/sql/migrations/sql/20240119094628000000_sessions_created_at_index.up.sql new file mode 100644 index 000000000000..c2b2f9e080bf --- /dev/null +++ b/persistence/sql/migrations/sql/20240119094628000000_sessions_created_at_index.up.sql @@ -0,0 +1 @@ +CREATE INDEX sessions_nid_created_at_id_idx ON sessions (nid, created_at DESC, id ASC); \ No newline at end of file diff --git a/persistence/sql/persister_session.go b/persistence/sql/persister_session.go index f8f6b13e8a9e..7cbd968f50a2 100644 --- a/persistence/sql/persister_session.go +++ b/persistence/sql/persister_session.go @@ -25,10 +25,12 @@ import ( var _ session.Persister = new(Persister) -const SessionDeviceUserAgentMaxLength = 512 -const SessionDeviceLocationMaxLength = 512 -const paginationMaxItemsSize = 1000 -const paginationDefaultItemsSize = 250 +const ( + SessionDeviceUserAgentMaxLength = 512 + SessionDeviceLocationMaxLength = 512 + paginationMaxItemsSize = 1000 + paginationDefaultItemsSize = 250 +) func (p *Persister) GetSession(ctx context.Context, sid uuid.UUID, expandables session.Expandables) (_ *session.Session, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetSession") @@ -73,6 +75,7 @@ func (p *Persister) ListSessions(ctx context.Context, active *bool, paginatorOpt paginatorOpts = append(paginatorOpts, keysetpagination.WithDefaultSize(paginationDefaultItemsSize)) paginatorOpts = append(paginatorOpts, keysetpagination.WithMaxSize(paginationMaxItemsSize)) paginatorOpts = append(paginatorOpts, keysetpagination.WithDefaultToken(new(session.Session).DefaultPageToken())) + paginatorOpts = append(paginatorOpts, keysetpagination.WithColumn("created_at", "DESC")) paginator := keysetpagination.GetPaginator(paginatorOpts...) if err := p.Transaction(ctx, func(ctx context.Context, c *pop.Connection) error { diff --git a/session/handler.go b/session/handler.go index fd3b8ac1deea..4f23881c652c 100644 --- a/session/handler.go +++ b/session/handler.go @@ -383,7 +383,7 @@ func (h *Handler) adminListSessions(w http.ResponseWriter, r *http.Request, ps h } // Parse request pagination parameters - opts, err := keysetpagination.Parse(r.URL.Query(), keysetpagination.NewStringPageToken) + opts, err := keysetpagination.Parse(r.URL.Query(), keysetpagination.NewMapPageToken) if err != nil { h.r.Writer().WriteError(w, r, herodot.ErrBadRequest.WithError("could not parse parameter page_size")) return diff --git a/session/handler_test.go b/session/handler_test.go index b08fb4d1ecb5..dce2f7b05116 100644 --- a/session/handler_test.go +++ b/session/handler_test.go @@ -11,6 +11,7 @@ import ( "io" "net/http" "net/http/httptest" + "net/url" "sort" "strconv" "strings" @@ -18,6 +19,7 @@ import ( "time" "github.com/go-faker/faker/v4" + "github.com/peterhellberg/link" "github.com/tidwall/gjson" "github.com/ory/kratos/identity" @@ -26,6 +28,7 @@ import ( "github.com/pkg/errors" "github.com/ory/kratos/corpx" + "github.com/ory/x/pagination/keysetpagination" "github.com/ory/x/sqlcon" "github.com/julienschmidt/httprouter" @@ -557,13 +560,27 @@ func TestHandlerAdminSessionManagement(t *testing.T) { require.Equal(t, ts.URL+"/sessions/whoami", res.Header.Get("Location")) }) + assertPageToken := func(t *testing.T, id, linkHeader string) { + t.Helper() + + g := link.Parse(linkHeader) + require.Len(t, g, 1) + u, err := url.Parse(g["first"].URI) + require.NoError(t, err) + pt, err := keysetpagination.NewMapPageToken(u.Query().Get("page_token")) + require.NoError(t, err) + mpt := pt.(keysetpagination.MapPageToken) + assert.Equal(t, id, mpt["id"]) + } + t.Run("list sessions", func(t *testing.T) { req, _ := http.NewRequest("GET", ts.URL+"/admin/sessions/", nil) res, err := client.Do(req) require.NoError(t, err) assert.Equal(t, http.StatusOK, res.StatusCode) assert.Equal(t, "1", res.Header.Get("X-Total-Count")) - assert.Equal(t, "; rel=\"first\"", res.Header.Get("Link")) + + assertPageToken(t, uuid.Nil.String(), res.Header.Get("Link")) var sessions []Session require.NoError(t, json.NewDecoder(res.Body).Decode(&sessions)) @@ -611,7 +628,7 @@ func TestHandlerAdminSessionManagement(t *testing.T) { require.NoError(t, err) assert.Equal(t, http.StatusOK, res.StatusCode) assert.Equal(t, "1", res.Header.Get("X-Total-Count")) - assert.Equal(t, "; rel=\"first\"", res.Header.Get("Link")) + assertPageToken(t, uuid.Nil.String(), res.Header.Get("Link")) body := ioutilx.MustReadAll(res.Body) assert.Equal(t, s.ID.String(), gjson.GetBytes(body, "0.id").String()) diff --git a/session/session.go b/session/session.go index d11a05e3bf05..84f64ceec0d6 100644 --- a/session/session.go +++ b/session/session.go @@ -153,11 +153,17 @@ type Session struct { } func (s Session) PageToken() keysetpagination.PageToken { - return keysetpagination.StringPageToken(s.ID.String()) + return keysetpagination.MapPageToken{ + "id": s.ID.String(), + "created_at": s.CreatedAt.Format(x.MapPaginationDateFormat), + } } -func (s Session) DefaultPageToken() keysetpagination.PageToken { - return keysetpagination.StringPageToken(uuid.Nil.String()) +func (m Session) DefaultPageToken() keysetpagination.PageToken { + return keysetpagination.MapPageToken{ + "id": uuid.Nil.String(), + "created_at": time.Date(2200, 12, 31, 23, 59, 59, 0, time.UTC).Format(x.MapPaginationDateFormat), + } } func (s Session) TableName(ctx context.Context) string { diff --git a/session/test/persistence.go b/session/test/persistence.go index fb6a7c469830..727cc744bdce 100644 --- a/session/test/persistence.go +++ b/session/test/persistence.go @@ -8,6 +8,8 @@ import ( "testing" "time" + "github.com/gobuffalo/pop/v6" + "github.com/ory/x/pagination/keysetpagination" "github.com/ory/x/pointerx" @@ -30,7 +32,8 @@ import ( func TestPersister(ctx context.Context, conf *config.Config, p interface { persistence.Persister -}) func(t *testing.T) { +}, +) func(t *testing.T) { return func(t *testing.T) { _, p := testhelpers.NewNetworkUnlessExisting(t, ctx, p) @@ -149,6 +152,7 @@ func TestPersister(ctx context.Context, conf *config.Config, p interface { seedSessionIDs := make([]uuid.UUID, 5) seedSessionsList := make([]session.Session, 5) + start := time.Now() for j := range seedSessionsList { require.NoError(t, faker.FakeData(&seedSessionsList[j])) seedSessionsList[j].Identity = &identity1 @@ -165,9 +169,13 @@ func TestPersister(ctx context.Context, conf *config.Config, p interface { seedSessionsList[j].Devices = []session.Device{ device, } + pop.SetNowFunc(func() time.Time { + return start.Add(time.Duration(j) * time.Minute) + }) require.NoError(t, l.UpsertSession(ctx, &seedSessionsList[j])) seedSessionIDs[j] = seedSessionsList[j].ID } + pop.SetNowFunc(time.Now) identity2Session.Identity = &identity2 identity2Session.Active = true @@ -288,7 +296,10 @@ func TestPersister(ctx context.Context, conf *config.Config, p interface { require.Equal(t, len(tc.expected), len(actual)) require.Equal(t, int64(len(tc.expected)), total) assert.Equal(t, true, nextPage.IsLast()) - assert.Equal(t, uuid.Nil.String(), nextPage.Token().Encode()) + + mapPageToken := nextPage.Token().Parse("") + assert.Equal(t, uuid.Nil.String(), mapPageToken["id"]) + assert.Equal(t, 250, nextPage.Size()) for _, es := range tc.expected { found := false @@ -312,7 +323,8 @@ func TestPersister(ctx context.Context, conf *config.Config, p interface { require.Equal(t, 6, len(actual)) require.Equal(t, int64(6), total) assert.Equal(t, true, page.IsLast()) - assert.Equal(t, uuid.Nil.String(), page.Token().Encode()) + mapPageToken := page.Token().Parse("") + assert.Equal(t, uuid.Nil.String(), mapPageToken["id"]) assert.Equal(t, 250, page.Size()) }) @@ -325,21 +337,24 @@ func TestPersister(ctx context.Context, conf *config.Config, p interface { assert.Len(t, firstPageItems, 3) assert.Equal(t, false, page1.IsLast()) - assert.Equal(t, firstPageItems[len(firstPageItems)-1].ID.String(), page1.Token().Encode()) + mapPageToken := page1.Token().Parse("") + assert.Equal(t, firstPageItems[len(firstPageItems)-1].ID.String(), mapPageToken["id"]) assert.Equal(t, 3, page1.Size()) // Validate secondPageItems page secondPageItems, total, page2, err := l.ListSessions(ctx, nil, page1.ToOptions(), session.ExpandEverything) require.NoError(t, err) + require.Equal(t, int64(6), total) + assert.Len(t, secondPageItems, 3) acutalIDs := make([]uuid.UUID, 0) for _, s := range append(firstPageItems, secondPageItems...) { acutalIDs = append(acutalIDs, s.ID) } - assert.ElementsMatch(t, append(seedSessionIDs, identity2Session.ID), acutalIDs) + expect := append(seedSessionIDs, identity2Session.ID) + require.Len(t, acutalIDs, len(expect)) + assert.ElementsMatch(t, expect, acutalIDs) - require.Equal(t, int64(6), total) - assert.Len(t, secondPageItems, 3) assert.True(t, page2.IsLast()) assert.Equal(t, 3, page2.Size()) }) diff --git a/x/pagination.go b/x/pagination.go index 7e31cd8f7d2e..5d633f19dc58 100644 --- a/x/pagination.go +++ b/x/pagination.go @@ -13,6 +13,9 @@ import ( "github.com/ory/x/pagination/pagepagination" ) +// The format we need to use in the Page tokens, as it's the only format that is understood by all DBs +const MapPaginationDateFormat = "2006-01-02 15:04:05.99999" + // ParsePagination parses limit and page from *http.Request with given limits and defaults. func ParsePagination(r *http.Request) (page, itemsPerPage int) { return migrationpagination.NewDefaultPaginator().ParsePagination(r) From f633959db3f0f70a0410cd2d99e7170a9f48d967 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Fri, 19 Jan 2024 13:18:06 +0000 Subject: [PATCH 236/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6061758d69df..5c60a002b036 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -942,6 +942,9 @@ https://github.com/ory/kratos/pull/3480 - One-time code native flows ([#3516](https://github.com/ory/kratos/issues/3516)) ([9b0fee3](https://github.com/ory/kratos/commit/9b0fee30f980d860fd548e7589fa6a06e593537a)) +- Order sessions by created_at + ([#3696](https://github.com/ory/kratos/issues/3696)) + ([688111c](https://github.com/ory/kratos/commit/688111c9a6bf9872657cf6aada77f55fa2520e00)) - Parametrize courier worker ([#3601](https://github.com/ory/kratos/issues/3601)) ([0e4be57](https://github.com/ory/kratos/commit/0e4be57e41e1152f4be22f490541c2c099cfe3fe)): From e4908dbe4a42fad5a80c4d46004e1e3710cabeb7 Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Fri, 19 Jan 2024 19:09:36 +0100 Subject: [PATCH 237/282] fix: csrf token regenerate on browser flows (#3706) Closes #3705 --- internal/client-go/go.sum | 1 + selfservice/strategy/code/strategy_recovery.go | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/internal/client-go/go.sum b/internal/client-go/go.sum index c966c8ddfd0d..6cc3f5911d11 100644 --- a/internal/client-go/go.sum +++ b/internal/client-go/go.sum @@ -4,6 +4,7 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/selfservice/strategy/code/strategy_recovery.go b/selfservice/strategy/code/strategy_recovery.go index 894166a236a2..6a64f82e876a 100644 --- a/selfservice/strategy/code/strategy_recovery.go +++ b/selfservice/strategy/code/strategy_recovery.go @@ -174,6 +174,11 @@ func (s *Strategy) recoveryIssueSession(w http.ResponseWriter, r *http.Request, UUID: id.ID, Valid: true, } + + if f.Type == flow.TypeBrowser { + f.SetCSRFToken(s.deps.CSRFHandler().RegenerateToken(w, r)) + } + if err := s.deps.RecoveryFlowPersister().UpdateRecoveryFlow(ctx, f); err != nil { return s.retryRecoveryFlow(w, r, f.Type, RetryWithError(err)) } @@ -190,8 +195,6 @@ func (s *Strategy) recoveryIssueSession(w http.ResponseWriter, r *http.Request, switch f.Type { case flow.TypeBrowser: - f.SetCSRFToken(s.deps.CSRFHandler().RegenerateToken(w, r)) - if err := s.deps.SessionManager().UpsertAndIssueCookie(ctx, w, r, sess); err != nil { return s.retryRecoveryFlow(w, r, f.Type, RetryWithError(err)) } From 793a368cd9663276006f5f9d639669b5e833bad9 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Fri, 19 Jan 2024 18:11:06 +0000 Subject: [PATCH 238/282] autogen(openapi): regenerate swagger spec and internal client [skip ci] --- internal/client-go/go.sum | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/client-go/go.sum b/internal/client-go/go.sum index 6cc3f5911d11..c966c8ddfd0d 100644 --- a/internal/client-go/go.sum +++ b/internal/client-go/go.sum @@ -4,7 +4,6 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= From 1792dc6abb96e47c5a4256655151f50d2c50af94 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Fri, 19 Jan 2024 18:53:45 +0000 Subject: [PATCH 239/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c60a002b036..5b4993de0267 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -437,6 +437,10 @@ https://github.com/ory/kratos/pull/3480 JSON objects: new login flow with actual error message as the first one and a very confusing '500, aborted registration hook execution' as the second one. +- Csrf token regenerate on browser flows + ([#3706](https://github.com/ory/kratos/issues/3706)) + ([e4908db](https://github.com/ory/kratos/commit/e4908dbe4a42fad5a80c4d46004e1e3710cabeb7)), + closes [#3705](https://github.com/ory/kratos/issues/3705) - Data race in test ([ab6dc31](https://github.com/ory/kratos/commit/ab6dc3121535d27668fed58804a218b17b17ae43)) - Do not encode full config in multiple places From 4a7bcc9322be37e6fd141e411bd65e3977eeb692 Mon Sep 17 00:00:00 2001 From: Mustafa Ucuncu <40738345+mustaf115@users.noreply.github.com> Date: Tue, 23 Jan 2024 11:26:11 -0700 Subject: [PATCH 240/282] feat: extend Microsoft Graph API capabilities (#3609) This change queries for all user information available with the `User.Read` scope during OIDC, and populates the `RawClaims` field. --- selfservice/strategy/oidc/provider_microsoft.go | 17 ++++++++++++----- .../strategy/oidc/provider_userinfo_test.go | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/selfservice/strategy/oidc/provider_microsoft.go b/selfservice/strategy/oidc/provider_microsoft.go index 8dd17fbbaae5..61fba182c045 100644 --- a/selfservice/strategy/oidc/provider_microsoft.go +++ b/selfservice/strategy/oidc/provider_microsoft.go @@ -92,7 +92,10 @@ func (m *ProviderMicrosoft) updateSubject(ctx context.Context, claims *Claims, e } ctx, client := httpx.SetOAuth2(ctx, m.reg.HTTPClient(ctx), o, exchange) - req, err := retryablehttp.NewRequestWithContext(ctx, "GET", "https://graph.microsoft.com/v1.0/me", nil) + // params to request all user fields from the graph api (User.Read scope) - https://learn.microsoft.com/en-us/previous-versions/azure/ad/graph/api/entity-and-complex-type-reference#user-entity + graphFields := "accountEnabled,assignedLicenses,assignedPlans,city,country,creationType,deletionTimestamp,department,dirSyncEnabled,displayName,employeeId,facsimileTelephoneNumber,givenName,immutableId,jobTitle,lastDirSyncTime,mail,mailNickname,mobile,objectId,objectType,onPremisesSecurityIdentifier,otherMails,passwordPolicies,passwordProfile,physicalDeliveryOfficeName,postalCode,preferredLanguage,provisionedPlans,provisioningErrors,proxyAddresses,refreshTokensValidFromDateTime,showInAddressList,signInNames,sipProxyAddress,state,streetAddress,surname,telephoneNumber,thumbnailPhoto,usageLocation,userIdentities,userPrincipalName,userType" + req, err := retryablehttp.NewRequestWithContext(ctx, "GET", "https://graph.microsoft.com/v1.0/me?$select="+graphFields, nil) + if err != nil { return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("%s", err)) } @@ -107,14 +110,18 @@ func (m *ProviderMicrosoft) updateSubject(ctx context.Context, claims *Claims, e return nil, err } - var user struct { - ID string `json:"id"` - } + var user map[string]interface{} if err := json.NewDecoder(resp.Body).Decode(&user); err != nil { return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Unable to decode JSON from `https://graph.microsoft.com/v1.0/me`: %s", err)) } - claims.Subject = user.ID + ok := false + claims.Subject, ok = user["id"].(string) + if !ok { + return nil, errors.WithStack(herodot.ErrInternalServerError.WithReason("Unable to retrieve subject from response")) + } + + claims.RawClaims["user"] = user } return claims, nil diff --git a/selfservice/strategy/oidc/provider_userinfo_test.go b/selfservice/strategy/oidc/provider_userinfo_test.go index 0b11f2dcae90..f29ef925bbe5 100644 --- a/selfservice/strategy/oidc/provider_userinfo_test.go +++ b/selfservice/strategy/oidc/provider_userinfo_test.go @@ -294,7 +294,7 @@ func TestProviderClaimsRespectsErrorCodes(t *testing.T) { }, expectedClaims: &oidc.Claims{ Issuer: "https://login.microsoftonline.com/a9b86385-f32c-4803-afc8-4b2312fbdf24/v2.0", Subject: "new-id", Name: "John Doe", Email: "john.doe@example.com", - RawClaims: map[string]interface{}{"aud": []interface{}{"foo"}, "exp": 4.071728504e+09, "iat": 1.516239022e+09, "iss": "https://login.microsoftonline.com/a9b86385-f32c-4803-afc8-4b2312fbdf24/v2.0", "email": "john.doe@example.com", "name": "John Doe", "sub": "1234567890", "tid": "a9b86385-f32c-4803-afc8-4b2312fbdf24"}, + RawClaims: map[string]interface{}{"aud": []interface{}{"foo"}, "exp": 4.071728504e+09, "iat": 1.516239022e+09, "iss": "https://login.microsoftonline.com/a9b86385-f32c-4803-afc8-4b2312fbdf24/v2.0", "email": "john.doe@example.com", "name": "John Doe", "sub": "1234567890", "tid": "a9b86385-f32c-4803-afc8-4b2312fbdf24", "user": map[string]interface{}{"id": "new-id"}}, }, }, { From 96dba50d01e57c1a40136fe457c4614acccebe86 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Tue, 23 Jan 2024 19:11:06 +0000 Subject: [PATCH 241/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b4993de0267..f92a5c751c3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2024-01-19)](#2024-01-19) +- [ (2024-01-23)](#2024-01-23) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -314,7 +314,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2024-01-19) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2024-01-23) ## Breaking Changes @@ -887,6 +887,13 @@ https://github.com/ory/kratos/pull/3480 This feature depends on Cockroach functionality and configuration, and is not possible for MySQL or PostgreSQL. +- Extend Microsoft Graph API capabilities + ([#3609](https://github.com/ory/kratos/issues/3609)) + ([4a7bcc9](https://github.com/ory/kratos/commit/4a7bcc9322be37e6fd141e411bd65e3977eeb692)): + + This change queries for all user information available with the `User.Read` + scope during OIDC, and populates the `RawClaims` field. + - Extract identifier label for login from default identity schema ([#3645](https://github.com/ory/kratos/issues/3645)) ([180828e](https://github.com/ory/kratos/commit/180828eb507ab239a9c6589f747a6816b6e50074)) From e8740c3498446dcaeab2990604a317e61dc170df Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Wed, 24 Jan 2024 12:56:51 +0100 Subject: [PATCH 242/282] fix: lint --- hash/hash_comparator.go | 5 +--- .../strategy/code/strategy_recovery_test.go | 4 +-- .../strategy/link/strategy_recovery_test.go | 2 +- .../strategy/password/op_helpers_test.go | 26 +++++++++---------- .../strategy/password/op_login_test.go | 6 ++--- .../strategy/password/op_registration_test.go | 14 ++++------ 6 files changed, 24 insertions(+), 33 deletions(-) diff --git a/hash/hash_comparator.go b/hash/hash_comparator.go index e68c1e663286..524eb9bfba14 100644 --- a/hash/hash_comparator.go +++ b/hash/hash_comparator.go @@ -28,7 +28,7 @@ import ( "golang.org/x/crypto/bcrypt" //nolint:staticcheck - //lint:ignore SA1019 + //lint:ignore SA1019 compatibility for imported passwords "golang.org/x/crypto/md4" //#nosec G501 -- compatibility for imported passwords "golang.org/x/crypto/pbkdf2" "golang.org/x/crypto/scrypt" @@ -211,7 +211,6 @@ func CompareScrypt(_ context.Context, password []byte, hash []byte) error { func CompareSSHA(_ context.Context, password []byte, hash []byte) error { hasher, salt, hash, err := decodeSSHAHash(string(hash)) - if err != nil { return err } @@ -222,7 +221,6 @@ func CompareSSHA(_ context.Context, password []byte, hash []byte) error { } func CompareSHA(_ context.Context, password []byte, hash []byte) error { - hasher, pf, salt, hash, err := decodeSHAHash(string(hash)) if err != nil { return err @@ -485,7 +483,6 @@ func decodeSHAHash(encodedHash string) (hasher string, pf, salt, hash []byte, er // used for CompareSHA and CompareSSHA func compareSHAHelper(hasher string, raw []byte, hash []byte) error { - var sha []byte switch hasher { diff --git a/selfservice/strategy/code/strategy_recovery_test.go b/selfservice/strategy/code/strategy_recovery_test.go index 29a054c28550..a5b4cef8bca5 100644 --- a/selfservice/strategy/code/strategy_recovery_test.go +++ b/selfservice/strategy/code/strategy_recovery_test.go @@ -354,7 +354,7 @@ func TestRecovery(t *testing.T) { expectedAAL: "aal2", }, } { - t.Run(fmt.Sprintf("%s", tc.desc), func(t *testing.T) { + t.Run(tc.desc, func(t *testing.T) { client := testhelpers.NewClientWithCookies(t) email := testhelpers.RandomEmail() i := createIdentityToRecover(t, reg, email) @@ -1191,7 +1191,7 @@ func TestRecovery_WithContinueWith(t *testing.T) { expectedAAL: "aal2", }, } { - t.Run(fmt.Sprintf("%s", tc.desc), func(t *testing.T) { + t.Run(tc.desc, func(t *testing.T) { client := testhelpers.NewClientWithCookies(t) email := testhelpers.RandomEmail() i := createIdentityToRecover(t, reg, email) diff --git a/selfservice/strategy/link/strategy_recovery_test.go b/selfservice/strategy/link/strategy_recovery_test.go index d470d8af6ce3..67e1cd388671 100644 --- a/selfservice/strategy/link/strategy_recovery_test.go +++ b/selfservice/strategy/link/strategy_recovery_test.go @@ -593,7 +593,7 @@ func TestRecovery(t *testing.T) { }, }, } { - t.Run(fmt.Sprintf("%s", tc.desc), func(t *testing.T) { + t.Run(tc.desc, func(t *testing.T) { email := testhelpers.RandomEmail() createIdentityToRecover(t, reg, email) diff --git a/selfservice/strategy/password/op_helpers_test.go b/selfservice/strategy/password/op_helpers_test.go index 824de913be69..17422063207b 100644 --- a/selfservice/strategy/password/op_helpers_test.go +++ b/selfservice/strategy/password/op_helpers_test.go @@ -43,25 +43,25 @@ type callTrace string const ( RegistrationUI callTrace = "registration-ui" - RegistrationWithOAuth2LoginChallenge = "registration-with-oauth2-login-challenge" - RegistrationWithFlowID = "registration-with-flow-id" - LoginUI = "login-ui" - LoginWithOAuth2LoginChallenge = "login-with-oauth2-login-challenge" - LoginWithFlowID = "login-with-flow-id" - Consent = "consent" - ConsentWithChallenge = "consent-with-challenge" - ConsentAccept = "consent-accept" - ConsentSkip = "consent-skip" - ConsentClientSkip = "consent-client-skip" - CodeExchange = "code-exchange" - CodeExchangeWithToken = "code-exchange-with-token" + RegistrationWithOAuth2LoginChallenge callTrace = "registration-with-oauth2-login-challenge" + RegistrationWithFlowID callTrace = "registration-with-flow-id" + LoginUI callTrace = "login-ui" + LoginWithOAuth2LoginChallenge callTrace = "login-with-oauth2-login-challenge" + LoginWithFlowID callTrace = "login-with-flow-id" + Consent callTrace = "consent" + ConsentWithChallenge callTrace = "consent-with-challenge" + ConsentAccept callTrace = "consent-accept" + ConsentSkip callTrace = "consent-skip" + ConsentClientSkip callTrace = "consent-client-skip" + CodeExchange callTrace = "code-exchange" + CodeExchangeWithToken callTrace = "code-exchange-with-token" ) type testContextKey string const ( TestUIConfig testContextKey = "test-ui-config" - TestOAuthClientState = "test-oauth-client-state" + TestOAuthClientState testContextKey = "test-oauth-client-state" ) type testConfig struct { diff --git a/selfservice/strategy/password/op_login_test.go b/selfservice/strategy/password/op_login_test.go index 64232072d736..6d8492a2ff3e 100644 --- a/selfservice/strategy/password/op_login_test.go +++ b/selfservice/strategy/password/op_login_test.go @@ -147,10 +147,8 @@ func TestOAuth2Provider(t *testing.T) { require.NoError(t, err) assert.Equal(t, http.StatusOK, resp.StatusCode) - if completedAcceptRequest != nil { - *c.callTrace = append(*c.callTrace, ConsentAccept) - } - assert.NotNil(t, completedAcceptRequest) + require.NotNil(t, completedAcceptRequest) + *c.callTrace = append(*c.callTrace, ConsentAccept) t.Logf("[consentTS] navigating to %s", completedAcceptRequest.RedirectTo) resp, err = c.browserClient.Get(completedAcceptRequest.RedirectTo) diff --git a/selfservice/strategy/password/op_registration_test.go b/selfservice/strategy/password/op_registration_test.go index 55e9907aba07..77f91cfb1ee3 100644 --- a/selfservice/strategy/password/op_registration_test.go +++ b/selfservice/strategy/password/op_registration_test.go @@ -43,9 +43,10 @@ func TestOAuth2ProviderRegistration(t *testing.T) { router := x.NewRouterPublic() + type contextKey string const ( - TestUIConfig = "test-ui-config" - TestOAuthClientState = "test-oauth-client-state" + TestUIConfig contextKey = "test-ui-config" + TestOAuthClientState contextKey = "test-oauth-client-state" ) router.GET("/login-ts", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { @@ -176,10 +177,8 @@ func TestOAuth2ProviderRegistration(t *testing.T) { require.NoError(t, err) assert.Equal(t, http.StatusOK, resp.StatusCode) - if completedAcceptRequest != nil { - *c.callTrace = append(*c.callTrace, ConsentAccept) - } - assert.NotNil(t, completedAcceptRequest) + require.NotNil(t, completedAcceptRequest) + *c.callTrace = append(*c.callTrace, ConsentAccept) t.Logf("[consentTS] navigating to %s", completedAcceptRequest.RedirectTo) resp, err = c.browserClient.Get(completedAcceptRequest.RedirectTo) @@ -244,9 +243,6 @@ func TestOAuth2ProviderRegistration(t *testing.T) { conf.MustSet(ctx, config.HookStrategyKey(config.ViperKeySelfServiceRegistrationAfter, identity.CredentialsTypePassword.String()), []config.SelfServiceHook{{Name: "session"}}) testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/registration.schema.json") - type state struct { - cas clientAppState - } doOAuthFlow := func(t *testing.T, ctx context.Context, oauthClient *oauth2.Config, browserClient *http.Client) { t.Helper() From 1254bf5a38dbe2c0e2798e07dd0ee5e4b2f63d6e Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Tue, 23 Jan 2024 13:27:54 +0100 Subject: [PATCH 243/282] fix: tracing context passing in /sessions/whoami --- session/handler.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/session/handler.go b/session/handler.go index 4f23881c652c..f69e9c655c67 100644 --- a/session/handler.go +++ b/session/handler.go @@ -212,11 +212,11 @@ func (h *Handler) whoami(w http.ResponseWriter, r *http.Request, _ httprouter.Pa ctx, span := h.r.Tracer(r.Context()).Tracer().Start(r.Context(), "sessions.Handler.whoami") defer span.End() - s, err := h.r.SessionManager().FetchFromRequest(r.Context(), r) + s, err := h.r.SessionManager().FetchFromRequest(ctx, r) c := h.r.Config() if err != nil { // We cache errors (and set cache header only when configured) where no session was found. - if noSess := new(ErrNoActiveSessionFound); c.SessionWhoAmICaching(r.Context()) && errors.As(err, &noSess) && noSess.credentialsMissing { + if noSess := new(ErrNoActiveSessionFound); c.SessionWhoAmICaching(ctx) && errors.As(err, &noSess) && noSess.credentialsMissing { w.Header().Set("Ory-Session-Cache-For", fmt.Sprintf("%d", int64(time.Minute.Seconds()))) } @@ -226,7 +226,7 @@ func (h *Handler) whoami(w http.ResponseWriter, r *http.Request, _ httprouter.Pa } var aalErr *ErrAALNotSatisfied - if err := h.r.SessionManager().DoesSessionSatisfy(r, s, c.SessionWhoAmIAAL(r.Context()), + if err := h.r.SessionManager().DoesSessionSatisfy(r, s, c.SessionWhoAmIAAL(ctx), // For the time being we want to update the AAL in the database if it is unset. UpsertAAL, ); errors.As(err, &aalErr) { @@ -254,11 +254,11 @@ func (h *Handler) whoami(w http.ResponseWriter, r *http.Request, _ httprouter.Pa w.Header().Set("X-Kratos-Authenticated-Identity-Id", s.Identity.ID.String()) // Set Cache header only when configured, and when no tokenization is requested. - if c.SessionWhoAmICaching(r.Context()) && len(tokenizeTemplate) == 0 { + if c.SessionWhoAmICaching(ctx) && len(tokenizeTemplate) == 0 { w.Header().Set("Ory-Session-Cache-For", fmt.Sprintf("%d", int64(time.Until(s.ExpiresAt).Seconds()))) } - if err := h.r.SessionManager().RefreshCookie(r.Context(), w, r, s); err != nil { + if err := h.r.SessionManager().RefreshCookie(ctx, w, r, s); err != nil { h.r.Audit().WithRequest(r).WithError(err).Info("Could not re-issue cookie.") h.r.Writer().WriteError(w, r, err) return From 9a52ddfbe7c24c41b6aa3ddc3c79c6fcbfb8db02 Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Wed, 24 Jan 2024 12:38:30 +0100 Subject: [PATCH 244/282] feat: pooled process-isolated Jsonnet VM --- .github/workflows/ci.yaml | 2 +- Makefile | 2 +- cmd/root.go | 40 ++++++++------ driver/registry.go | 7 +++ driver/registry_default.go | 87 +++++++++++++----------------- go.mod | 9 +++- go.sum | 17 +++--- internal/driver.go | 5 +- internal/testhelpers/e2e_server.go | 7 ++- main.go | 11 +--- 10 files changed, 97 insertions(+), 90 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 43129b0991ce..c39b51455b2b 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -91,7 +91,7 @@ jobs: GOGC: 100 with: args: --timeout 10m0s - version: v1.54.2 + version: v1.55.2 skip-go-installation: true skip-pkg-cache: true - name: Build Kratos diff --git a/Makefile b/Makefile index fd023e75bf13..cbee2a75fc93 100644 --- a/Makefile +++ b/Makefile @@ -49,7 +49,7 @@ docs/swagger: npx @redocly/openapi-cli preview-docs spec/swagger.json .bin/golangci-lint: Makefile - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -d -b .bin v1.54.2 + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -d -b .bin v1.55.2 .bin/hydra: Makefile bash <(curl https://raw.githubusercontent.com/ory/meta/master/install.sh) -d -b .bin hydra v2.2.0-rc.3 diff --git a/cmd/root.go b/cmd/root.go index 9364ebd3bbc3..8f85896312b2 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -6,33 +6,33 @@ package cmd import ( "errors" "fmt" - "os" + "runtime" - "github.com/ory/kratos/cmd/cleanup" - "github.com/ory/kratos/driver/config" - "github.com/ory/x/jsonnetsecure" + "github.com/spf13/cobra" + "github.com/ory/kratos/cmd/cleanup" "github.com/ory/kratos/cmd/courier" "github.com/ory/kratos/cmd/hashers" - - "github.com/ory/kratos/cmd/remote" - "github.com/ory/kratos/cmd/identities" "github.com/ory/kratos/cmd/jsonnet" "github.com/ory/kratos/cmd/migrate" + "github.com/ory/kratos/cmd/remote" "github.com/ory/kratos/cmd/serve" + "github.com/ory/kratos/driver" + "github.com/ory/kratos/driver/config" "github.com/ory/x/cmdx" - - "github.com/spf13/cobra" + "github.com/ory/x/dbal" + "github.com/ory/x/jsonnetsecure" + "github.com/ory/x/profilex" ) -func NewRootCmd() (cmd *cobra.Command) { +func NewRootCmd(driverOpts ...driver.RegistryOption) (cmd *cobra.Command) { cmd = &cobra.Command{ Use: "kratos", } cmdx.EnableUsageTemplating(cmd) - courier.RegisterCommandRecursive(cmd, nil, nil) + courier.RegisterCommandRecursive(cmd, nil, driverOpts) cmd.AddCommand(identities.NewGetCmd()) cmd.AddCommand(identities.NewDeleteCmd()) cmd.AddCommand(jsonnet.NewFormatCmd()) @@ -41,7 +41,7 @@ func NewRootCmd() (cmd *cobra.Command) { cmd.AddCommand(jsonnet.NewLintCmd()) cmd.AddCommand(identities.NewListCmd()) migrate.RegisterCommandRecursive(cmd) - serve.RegisterCommandRecursive(cmd, nil, nil) + serve.RegisterCommandRecursive(cmd, nil, driverOpts) cleanup.RegisterCommandRecursive(cmd) remote.RegisterCommandRecursive(cmd) cmd.AddCommand(identities.NewValidateCmd()) @@ -55,13 +55,23 @@ func NewRootCmd() (cmd *cobra.Command) { // Execute adds all child commands to the root command and sets flags appropriately. // This is called by main.main(). It only needs to happen once to the RootCmd. -func Execute() { - c := NewRootCmd() +func Execute() int { + defer profilex.Profile().Stop() + + dbal.RegisterDriver(func() dbal.Driver { + return driver.NewRegistryDefault() + }) + + jsonnetPool := jsonnetsecure.NewProcessPool(runtime.GOMAXPROCS(0)) + defer jsonnetPool.Close() + + c := NewRootCmd(driver.WithJsonnetPool(jsonnetPool)) if err := c.Execute(); err != nil { if !errors.Is(err, cmdx.ErrNoPrintButFail) { _, _ = fmt.Fprintln(c.ErrOrStderr(), err) } - os.Exit(1) + return 1 } + return 0 } diff --git a/driver/registry.go b/driver/registry.go index 31a3f650a62a..e87fdd076078 100644 --- a/driver/registry.go +++ b/driver/registry.go @@ -188,6 +188,7 @@ type options struct { replacementStrategies []NewStrategy extraHooks map[string]func(config.SelfServiceHook) any disableMigrationLogging bool + jsonnetPool jsonnetsecure.Pool } type RegistryOption func(*options) @@ -196,6 +197,12 @@ func SkipNetworkInit(o *options) { o.skipNetworkInit = true } +func WithJsonnetPool(pool jsonnetsecure.Pool) RegistryOption { + return func(o *options) { + o.jsonnetPool = pool + } +} + func WithConfig(config *config.Config) RegistryOption { return func(o *options) { o.config = config diff --git a/driver/registry_default.go b/driver/registry_default.go index a267d9cb637d..5349c7359d39 100644 --- a/driver/registry_default.go +++ b/driver/registry_default.go @@ -12,74 +12,56 @@ import ( "testing" "time" + "github.com/cenkalti/backoff" "github.com/dgraph-io/ristretto" - - "github.com/ory/x/jwksx" - - "github.com/ory/x/contextx" - "github.com/ory/x/jsonnetsecure" - - "github.com/ory/x/popx" - - "github.com/hashicorp/go-retryablehttp" - - "github.com/ory/x/httpx" - "github.com/ory/x/otelx" - otelsql "github.com/ory/x/otelx/sql" - "github.com/gobuffalo/pop/v6" - - "github.com/ory/nosurf" - - "github.com/ory/kratos/hydra" - "github.com/ory/kratos/selfservice/strategy/code" - "github.com/ory/kratos/selfservice/strategy/webauthn" - - "github.com/ory/kratos/selfservice/strategy/lookup" - - "github.com/ory/kratos/selfservice/strategy/totp" - + "github.com/gorilla/sessions" + "github.com/hashicorp/go-retryablehttp" "github.com/luna-duclos/instrumentedsql" + "github.com/pkg/errors" - prometheus "github.com/ory/x/prometheusx" - + "github.com/ory/herodot" "github.com/ory/kratos/cipher" "github.com/ory/kratos/continuity" + "github.com/ory/kratos/courier" + "github.com/ory/kratos/driver/config" "github.com/ory/kratos/hash" + "github.com/ory/kratos/hydra" + "github.com/ory/kratos/identity" + "github.com/ory/kratos/persistence" + "github.com/ory/kratos/persistence/sql" "github.com/ory/kratos/schema" + "github.com/ory/kratos/selfservice/errorx" + "github.com/ory/kratos/selfservice/flow/login" + "github.com/ory/kratos/selfservice/flow/logout" "github.com/ory/kratos/selfservice/flow/recovery" + "github.com/ory/kratos/selfservice/flow/registration" "github.com/ory/kratos/selfservice/flow/settings" "github.com/ory/kratos/selfservice/flow/verification" "github.com/ory/kratos/selfservice/hook" + "github.com/ory/kratos/selfservice/strategy/code" "github.com/ory/kratos/selfservice/strategy/link" + "github.com/ory/kratos/selfservice/strategy/lookup" + "github.com/ory/kratos/selfservice/strategy/oidc" + "github.com/ory/kratos/selfservice/strategy/password" "github.com/ory/kratos/selfservice/strategy/profile" + "github.com/ory/kratos/selfservice/strategy/totp" + "github.com/ory/kratos/selfservice/strategy/webauthn" + "github.com/ory/kratos/session" "github.com/ory/kratos/x" - - "github.com/cenkalti/backoff" - "github.com/gorilla/sessions" - "github.com/pkg/errors" - + "github.com/ory/nosurf" + "github.com/ory/x/contextx" "github.com/ory/x/dbal" "github.com/ory/x/healthx" - "github.com/ory/x/sqlcon" - + "github.com/ory/x/httpx" + "github.com/ory/x/jsonnetsecure" + "github.com/ory/x/jwksx" "github.com/ory/x/logrusx" - - "github.com/ory/kratos/courier" - "github.com/ory/kratos/persistence" - "github.com/ory/kratos/persistence/sql" - "github.com/ory/kratos/selfservice/flow/login" - "github.com/ory/kratos/selfservice/flow/logout" - "github.com/ory/kratos/selfservice/flow/registration" - "github.com/ory/kratos/selfservice/strategy/oidc" - - "github.com/ory/herodot" - - "github.com/ory/kratos/driver/config" - "github.com/ory/kratos/identity" - "github.com/ory/kratos/selfservice/errorx" - "github.com/ory/kratos/selfservice/strategy/password" - "github.com/ory/kratos/session" + "github.com/ory/x/otelx" + otelsql "github.com/ory/x/otelx/sql" + "github.com/ory/x/popx" + prometheus "github.com/ory/x/prometheusx" + "github.com/ory/x/sqlcon" ) type RegistryDefault struct { @@ -169,12 +151,13 @@ type RegistryDefault struct { csrfTokenGenerator x.CSRFToken jsonnetVMProvider jsonnetsecure.VMProvider + jsonnetPool jsonnetsecure.Pool jwkFetcher *jwksx.FetcherNext } func (m *RegistryDefault) JsonnetVM(ctx context.Context) (jsonnetsecure.VM, error) { if m.jsonnetVMProvider == nil { - m.jsonnetVMProvider = &jsonnetsecure.DefaultProvider{Subcommand: "jsonnet"} + m.jsonnetVMProvider = &jsonnetsecure.DefaultProvider{Subcommand: "jsonnet", Pool: m.jsonnetPool} } return m.jsonnetVMProvider.JsonnetVM(ctx) } @@ -631,6 +614,8 @@ func (m *RegistryDefault) Init(ctx context.Context, ctxer contextx.Contextualize o := newOptions(opts) + m.jsonnetPool = o.jsonnetPool + var instrumentedDriverOpts []instrumentedsql.Opt if m.Tracer(ctx).IsLoaded() { instrumentedDriverOpts = []instrumentedsql.Opt{ diff --git a/go.mod b/go.mod index 42b2bad25942..96fad3946f5b 100644 --- a/go.mod +++ b/go.mod @@ -44,7 +44,7 @@ require ( github.com/golang/mock v1.6.0 github.com/google/go-github/v27 v27.0.1 github.com/google/go-github/v38 v38.1.0 - github.com/google/go-jsonnet v0.19.0 + github.com/google/go-jsonnet v0.20.0 github.com/gorilla/sessions v1.2.1 github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69 github.com/hashicorp/consul/api v1.20.0 @@ -75,7 +75,7 @@ require ( github.com/ory/jsonschema/v3 v3.0.8 github.com/ory/mail/v3 v3.0.0 github.com/ory/nosurf v1.2.7 - github.com/ory/x v0.0.610 + github.com/ory/x v0.0.611 github.com/peterhellberg/link v1.2.0 github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 github.com/pkg/errors v0.9.1 @@ -327,3 +327,8 @@ require ( mvdan.cc/sh/v3 v3.3.0-0.dev.0.20210224101809-fb5052e7a010 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) + +require ( + github.com/jackc/puddle/v2 v2.1.2 // indirect + go.uber.org/atomic v1.10.0 // indirect +) diff --git a/go.sum b/go.sum index b3b463884b74..42b770741175 100644 --- a/go.sum +++ b/go.sum @@ -184,7 +184,6 @@ github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2Vvl github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= @@ -421,8 +420,8 @@ github.com/google/go-github/v27 v27.0.1 h1:sSMFSShNn4VnqCqs+qhab6TS3uQc+uVR6TD1b github.com/google/go-github/v27 v27.0.1/go.mod h1:/0Gr8pJ55COkmv+S/yPKCczSkUPIM/LnFyubufRNIS0= github.com/google/go-github/v38 v38.1.0 h1:C6h1FkaITcBFK7gAmq4eFzt6gbhEhk7L5z6R3Uva+po= github.com/google/go-github/v38 v38.1.0/go.mod h1:cStvrz/7nFr0FoENgG6GLbp53WaelXucT+BBz/3VKx4= -github.com/google/go-jsonnet v0.19.0 h1:G7uJZhi8t1eg5NZ+PZJ3bU0GZ4suYGGy79BCtEswlbM= -github.com/google/go-jsonnet v0.19.0/go.mod h1:5JVT33JVCoehdTj5Z2KJq1eIdt3Nb8PCmZ+W5D8U350= +github.com/google/go-jsonnet v0.20.0 h1:WG4TTSARuV7bSm4PMB4ohjxe33IHT5WVTrJSU33uT4g= +github.com/google/go-jsonnet v0.20.0/go.mod h1:VbgWF9JX7ztlv770x/TolZNGGFfiHEVx9G6ca2eUmeA= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk= @@ -598,6 +597,8 @@ github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0f github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle/v2 v2.1.2 h1:0f7vaaXINONKTsxYDn4otOAiJanX/BMeAtY//BXqzlg= +github.com/jackc/puddle/v2 v2.1.2/go.mod h1:2lpufsF5mRHO6SuZkm0fNYxM6SWHfvyFj62KwNzgels= github.com/jandelgado/gcov2lcov v1.0.5 h1:rkBt40h0CVK4oCb8Dps950gvfd1rYvQ8+cWa346lVU0= github.com/jandelgado/gcov2lcov v1.0.5/go.mod h1:NnSxK6TMlg1oGDBfGelGbjgorT5/L3cchlbtgFYZSss= github.com/jarcoal/httpmock v1.0.5 h1:cHtVEcTxRSX4J0je7mWPfc9BpDpqzXSJ5HbymZmyHck= @@ -828,8 +829,8 @@ github.com/ory/nosurf v1.2.7 h1:YrHrbSensQyU6r6HT/V5+HPdVEgrOTMJiLoJABSBOp4= github.com/ory/nosurf v1.2.7/go.mod h1:d4L3ZBa7Amv55bqxCBtCs63wSlyaiCkWVl4vKf3OUxA= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2 h1:zm6sDvHy/U9XrGpixwHiuAwpp0Ock6khSVHkrv6lQQU= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/ory/x v0.0.610 h1:SY1X5jfJVq45zeZEIc1XWqlE+lna+rMjeLxMoRdx0bY= -github.com/ory/x v0.0.610/go.mod h1:FkkwV9h7U9VqDe6Xkdl7KKLCfDC1sQcO+q2iCBAA0Ho= +github.com/ory/x v0.0.611 h1:mB23kkg8EYebmKo25JYubXQZmu1l4qLFJnkwr3DnpzA= +github.com/ory/x v0.0.611/go.mod h1:uH065puz8neija0neqwIN3PmXXfDsB9VbZTZ20Znoos= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -927,7 +928,6 @@ github.com/segmentio/conf v1.2.0/go.mod h1:Y3B9O/PqqWqjyxyWWseyj/quPEtMu1zDp/kVb 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/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/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= @@ -1089,6 +1089,8 @@ 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.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= @@ -1335,7 +1337,6 @@ golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1591,7 +1592,6 @@ 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.5/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/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= @@ -1619,6 +1619,5 @@ mvdan.cc/sh/v3 v3.3.0-0.dev.0.20210224101809-fb5052e7a010/go.mod h1:fPQmabBpREM/ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/internal/driver.go b/internal/driver.go index d17f2b0ca62b..a6f1f13d7954 100644 --- a/internal/driver.go +++ b/internal/driver.go @@ -6,6 +6,7 @@ package internal import ( "context" "os" + "runtime" "testing" "github.com/sirupsen/logrus" @@ -82,7 +83,9 @@ func NewRegistryDefaultWithDSN(t testing.TB, dsn string) (*config.Config, *drive reg, err := driver.NewRegistryFromDSN(ctx, c, logrusx.New("", "", logrusx.ForceLevel(logrus.ErrorLevel))) require.NoError(t, err) reg.Config().MustSet(ctx, "dev", true) - require.NoError(t, reg.Init(context.Background(), &contextx.Default{}, driver.SkipNetworkInit, driver.WithDisabledMigrationLogging())) + pool := jsonnetsecure.NewProcessPool(runtime.GOMAXPROCS(0)) + t.Cleanup(pool.Close) + require.NoError(t, reg.Init(context.Background(), &contextx.Default{}, driver.SkipNetworkInit, driver.WithDisabledMigrationLogging(), driver.WithJsonnetPool(pool))) require.NoError(t, reg.Persister().MigrateUp(context.Background())) // always migrate up actual, err := reg.Persister().DetermineNetwork(context.Background()) diff --git a/internal/testhelpers/e2e_server.go b/internal/testhelpers/e2e_server.go index 0eebca91f726..4c97303707b0 100644 --- a/internal/testhelpers/e2e_server.go +++ b/internal/testhelpers/e2e_server.go @@ -18,12 +18,14 @@ import ( "net/http" "os" "path/filepath" + "runtime" "strings" "testing" "time" "github.com/ory/kratos/driver" "github.com/ory/x/dbal" + "github.com/ory/x/jsonnetsecure" "golang.org/x/sync/errgroup" @@ -84,13 +86,16 @@ func startE2EServerOnly(t *testing.T, configFile string, isTLS bool, configOptio configx.WithValues(configOptions), ) + jsonnetPool := jsonnetsecure.NewProcessPool(runtime.GOMAXPROCS(0)) + t.Cleanup(jsonnetPool.Close) + //nolint:staticcheck //lint:ignore SA1029 we really want this ctx = context.WithValue(ctx, "dsn", dsn) ctx, cancel := context.WithCancel(ctx) executor := &cmdx.CommandExecuter{ New: func() *cobra.Command { - return cmd.NewRootCmd() + return cmd.NewRootCmd(driver.WithJsonnetPool(jsonnetPool)) }, Ctx: ctx, } diff --git a/main.go b/main.go index 3eaff9925369..680a5f780afa 100644 --- a/main.go +++ b/main.go @@ -5,18 +5,11 @@ package main import ( - "github.com/ory/kratos/driver" - "github.com/ory/x/dbal" - "github.com/ory/x/profilex" + "os" "github.com/ory/kratos/cmd" ) func main() { - defer profilex.Profile().Stop() - dbal.RegisterDriver(func() dbal.Driver { - return driver.NewRegistryDefault() - }) - - cmd.Execute() + os.Exit(cmd.Execute()) } From ce6b11abeb1ada7d763e767f7973510552d79f80 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Wed, 24 Jan 2024 13:36:26 +0000 Subject: [PATCH 245/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f92a5c751c3b..87cfdec84114 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2024-01-23)](#2024-01-23) +- [ (2024-01-24)](#2024-01-24) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -314,7 +314,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2024-01-23) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2024-01-24) ## Breaking Changes @@ -520,6 +520,8 @@ https://github.com/ory/kratos/pull/3480 - Issue session after verification after registration with OIDC SSO ([#3467](https://github.com/ory/kratos/issues/3467)) ([a28b523](https://github.com/ory/kratos/commit/a28b523238743f3873b51479eea3b86d684092f9)) +- Lint + ([e8740c3](https://github.com/ory/kratos/commit/e8740c3498446dcaeab2990604a317e61dc170df)) - Lower-case recovery & verification emails on import ([#3571](https://github.com/ory/kratos/issues/3571)) ([e2ac9ff](https://github.com/ory/kratos/commit/e2ac9ff4e2101788f1fca1b8c83f8791cce446e2)): @@ -668,6 +670,8 @@ https://github.com/ory/kratos/pull/3480 ([bee0341](https://github.com/ory/kratos/commit/bee0341c5bf5708a2210146fc59f050a1b9df663)) - Specify correct minimum versions in migratest ([18b89ea](https://github.com/ory/kratos/commit/18b89ea588d129fa88379f7b0d7f4fd00ec6023d)) +- Tracing context passing in /sessions/whoami + ([1254bf5](https://github.com/ory/kratos/commit/1254bf5a38dbe2c0e2798e07dd0ee5e4b2f63d6e)) - Tracing improvements ([c804cb2](https://github.com/ory/kratos/commit/c804cb2bebbefc97073cf3b8fa250c3eefc58894)) - Type-assert all interfaces that WebHook implements @@ -975,6 +979,8 @@ https://github.com/ory/kratos/pull/3480 This feature is currently only working for browser facing APIs. +- Pooled process-isolated Jsonnet VM + ([9a52ddf](https://github.com/ory/kratos/commit/9a52ddfbe7c24c41b6aa3ddc3c79c6fcbfb8db02)) - Provide login hints when registration fails due to duplicate credentials/addresses ([#3430](https://github.com/ory/kratos/issues/3430)) ([8b28469](https://github.com/ory/kratos/commit/8b284697e4a26fb01ad57d2e9ebd8f714be49f33)): From 757a5e43257e9ff28a16bfe76f8e737b656d3696 Mon Sep 17 00:00:00 2001 From: Patrik Date: Thu, 25 Jan 2024 09:40:22 +0100 Subject: [PATCH 246/282] fix: add return_to parameter to API spec of createRecoveryLinkForIdentity (#3711) --- internal/client-go/api_identity.go | 8 ++++++++ internal/httpclient/api_identity.go | 8 ++++++++ selfservice/strategy/link/strategy_recovery.go | 4 +++- spec/api.json | 9 +++++++++ spec/swagger.json | 5 +++++ 5 files changed, 33 insertions(+), 1 deletion(-) diff --git a/internal/client-go/api_identity.go b/internal/client-go/api_identity.go index ca2b697f8cf5..7ebc9fc7ca44 100644 --- a/internal/client-go/api_identity.go +++ b/internal/client-go/api_identity.go @@ -774,9 +774,14 @@ func (a *IdentityApiService) CreateRecoveryCodeForIdentityExecute(r IdentityApiA type IdentityApiApiCreateRecoveryLinkForIdentityRequest struct { ctx context.Context ApiService IdentityApi + returnTo *string createRecoveryLinkForIdentityBody *CreateRecoveryLinkForIdentityBody } +func (r IdentityApiApiCreateRecoveryLinkForIdentityRequest) ReturnTo(returnTo string) IdentityApiApiCreateRecoveryLinkForIdentityRequest { + r.returnTo = &returnTo + return r +} func (r IdentityApiApiCreateRecoveryLinkForIdentityRequest) CreateRecoveryLinkForIdentityBody(createRecoveryLinkForIdentityBody CreateRecoveryLinkForIdentityBody) IdentityApiApiCreateRecoveryLinkForIdentityRequest { r.createRecoveryLinkForIdentityBody = &createRecoveryLinkForIdentityBody return r @@ -826,6 +831,9 @@ func (a *IdentityApiService) CreateRecoveryLinkForIdentityExecute(r IdentityApiA localVarQueryParams := url.Values{} localVarFormParams := url.Values{} + if r.returnTo != nil { + localVarQueryParams.Add("return_to", parameterToString(*r.returnTo, "")) + } // to determine the Content-Type header localVarHTTPContentTypes := []string{"application/json"} diff --git a/internal/httpclient/api_identity.go b/internal/httpclient/api_identity.go index ca2b697f8cf5..7ebc9fc7ca44 100644 --- a/internal/httpclient/api_identity.go +++ b/internal/httpclient/api_identity.go @@ -774,9 +774,14 @@ func (a *IdentityApiService) CreateRecoveryCodeForIdentityExecute(r IdentityApiA type IdentityApiApiCreateRecoveryLinkForIdentityRequest struct { ctx context.Context ApiService IdentityApi + returnTo *string createRecoveryLinkForIdentityBody *CreateRecoveryLinkForIdentityBody } +func (r IdentityApiApiCreateRecoveryLinkForIdentityRequest) ReturnTo(returnTo string) IdentityApiApiCreateRecoveryLinkForIdentityRequest { + r.returnTo = &returnTo + return r +} func (r IdentityApiApiCreateRecoveryLinkForIdentityRequest) CreateRecoveryLinkForIdentityBody(createRecoveryLinkForIdentityBody CreateRecoveryLinkForIdentityBody) IdentityApiApiCreateRecoveryLinkForIdentityRequest { r.createRecoveryLinkForIdentityBody = &createRecoveryLinkForIdentityBody return r @@ -826,6 +831,9 @@ func (a *IdentityApiService) CreateRecoveryLinkForIdentityExecute(r IdentityApiA localVarQueryParams := url.Values{} localVarFormParams := url.Values{} + if r.returnTo != nil { + localVarQueryParams.Add("return_to", parameterToString(*r.returnTo, "")) + } // to determine the Content-Type header localVarHTTPContentTypes := []string{"application/json"} diff --git a/selfservice/strategy/link/strategy_recovery.go b/selfservice/strategy/link/strategy_recovery.go index 326a35c7bfe0..6297e780b646 100644 --- a/selfservice/strategy/link/strategy_recovery.go +++ b/selfservice/strategy/link/strategy_recovery.go @@ -69,6 +69,8 @@ func (s *Strategy) PopulateRecoveryMethod(r *http.Request, f *recovery.Flow) err type createRecoveryLinkForIdentity struct { // in: body Body createRecoveryLinkForIdentityBody + // in: query + ReturnTo string `json:"return_to"` } // Create Recovery Link for Identity Request Body @@ -156,7 +158,7 @@ func (s *Strategy) createRecoveryLinkForIdentity(w http.ResponseWriter, r *http. } } - if time.Now().Add(expiresIn).Before(time.Now()) { + if expiresIn <= 0 { s.d.Writer().WriteError(w, r, errors.WithStack(herodot.ErrBadRequest.WithReasonf(`Value from "expires_in" must be result to a future time: %s`, p.ExpiresIn))) return } diff --git a/spec/api.json b/spec/api.json index 8ba46ef3790d..fcb22f35419e 100644 --- a/spec/api.json +++ b/spec/api.json @@ -4379,6 +4379,15 @@ "post": { "description": "This endpoint creates a recovery link which should be given to the user in order for them to recover\n(or activate) their account.", "operationId": "createRecoveryLinkForIdentity", + "parameters": [ + { + "in": "query", + "name": "return_to", + "schema": { + "type": "string" + } + } + ], "requestBody": { "content": { "application/json": { diff --git a/spec/swagger.json b/spec/swagger.json index 0efbf7716e9c..557a69043a5a 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -934,6 +934,11 @@ "schema": { "$ref": "#/definitions/createRecoveryLinkForIdentityBody" } + }, + { + "type": "string", + "name": "return_to", + "in": "query" } ], "responses": { From f1493c8c0d4272dfb927cf59c639f855d48bd15d Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Thu, 25 Jan 2024 09:22:43 +0000 Subject: [PATCH 247/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87cfdec84114..47290095bce5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2024-01-24)](#2024-01-24) +- [ (2024-01-25)](#2024-01-25) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -314,7 +314,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2024-01-24) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2024-01-25) ## Breaking Changes @@ -381,6 +381,9 @@ https://github.com/ory/kratos/pull/3480 - Add missing tracing & attributes in oidc strategy ([#3429](https://github.com/ory/kratos/issues/3429)) ([09bcb71](https://github.com/ory/kratos/commit/09bcb71f1f0b3238e2d0f4376a1a2290d062c6c1)) +- Add return_to parameter to API spec of createRecoveryLinkForIdentity + ([#3711](https://github.com/ory/kratos/issues/3711)) + ([757a5e4](https://github.com/ory/kratos/commit/757a5e43257e9ff28a16bfe76f8e737b656d3696)) - Add value code to authentication method enum ([#3546](https://github.com/ory/kratos/issues/3546)) ([95dc7a2](https://github.com/ory/kratos/commit/95dc7a20f49aa682f324b70e507ec56c20159ebb)): From 1516cf64e346819dccace1cc25aaccac38b9e47c Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Fri, 26 Jan 2024 17:01:11 +0100 Subject: [PATCH 248/282] feat: support MFA via SMS (#3682) --------- Co-authored-by: zepatrik --- Makefile | 8 +- cmd/clidoc/main.go | 7 +- .../phone-password/identity.schema.json | 24 +- courier/sms_templates.go | 6 + .../login_code/valid/sms.body.gotmpl | 1 + courier/template/sms/login_code_valid.go | 52 +++ courier/template/sms/login_code_valid_test.go | 37 ++ driver/config/config.go | 18 +- driver/registry_default.go | 14 +- driver/registry_default_test.go | 37 +- embedx/config.schema.json | 31 +- embedx/identity_extension.schema.json | 2 +- identity/credentials_code.go | 2 +- internal/client-go/api_frontend.go | 8 + .../model_identity_credentials_code.go | 1 + internal/httpclient/api_frontend.go | 8 + .../model_identity_credentials_code.go | 1 + internal/registrationhelpers/helpers.go | 16 +- internal/testhelpers/courier.go | 2 +- internal/testhelpers/selfservice_login.go | 25 +- internal/testhelpers/server.go | 5 +- internal/testhelpers/session.go | 14 + schema/errors.go | 11 + .../flow/login/extension_identifier_label.go | 31 +- selfservice/flow/login/handler.go | 25 +- selfservice/flow/login/hook.go | 2 +- selfservice/flow/login/strategy.go | 5 +- selfservice/flow/registration/handler_test.go | 3 +- selfservice/flow/request.go | 15 +- selfservice/flow/request_test.go | 71 ---- ...suite=mfa-case=verify_initial_payload.json | 84 +++++ ...suite=mfa-case=verify_initial_payload.json | 70 ++++ ...suite=mfa-case=verify_initial_payload.json | 84 +++++ selfservice/strategy/code/code_sender.go | 28 +- selfservice/strategy/code/strategy.go | 347 +++++++++++------- selfservice/strategy/code/strategy_login.go | 68 +++- .../strategy/code/strategy_login_test.go | 191 ++++++++-- .../code/strategy_registration_test.go | 5 +- selfservice/strategy/code/strategy_test.go | 36 ++ selfservice/strategy/lookup/login.go | 9 +- selfservice/strategy/lookup/strategy.go | 8 +- selfservice/strategy/oidc/strategy.go | 2 +- selfservice/strategy/oidc/strategy_login.go | 4 +- selfservice/strategy/password/login.go | 3 +- selfservice/strategy/password/strategy.go | 2 +- selfservice/strategy/totp/login.go | 6 +- selfservice/strategy/totp/strategy.go | 10 +- selfservice/strategy/webauthn/login.go | 5 +- selfservice/strategy/webauthn/strategy.go | 10 +- .../strategy/webauthn/strategy_test.go | 4 +- spec/api.json | 14 +- spec/swagger.json | 12 +- .../code/registration/success.spec.ts | 20 +- .../integration/profiles/mfa/code.spec.ts | 104 ++++++ .../profiles/oidc-provider/login.spec.ts | 4 +- .../profiles/recovery/code/errors.spec.ts | 18 +- .../profiles/recovery/link/errors.spec.ts | 25 +- .../verification/registration/errors.spec.ts | 5 +- .../verification/settings/error.spec.ts | 5 +- .../verification/verify/errors.spec.ts | 19 +- .../verification/verify/success.spec.ts | 5 +- test/e2e/cypress/support/commands.ts | 190 ++++++---- test/e2e/cypress/support/config.d.ts | 45 ++- test/e2e/cypress/support/configHelpers.ts | 9 + test/e2e/cypress/support/index.d.ts | 18 +- text/id.go | 3 + text/message_login.go | 28 +- 67 files changed, 1473 insertions(+), 509 deletions(-) create mode 100644 courier/template/courier/builtin/templates/login_code/valid/sms.body.gotmpl create mode 100644 courier/template/sms/login_code_valid.go create mode 100644 courier/template/sms/login_code_valid_test.go create mode 100644 selfservice/strategy/code/.snapshots/TestLoginCodeStrategy-test=Browser_client-suite=mfa-case=verify_initial_payload.json create mode 100644 selfservice/strategy/code/.snapshots/TestLoginCodeStrategy-test=Native_client-suite=mfa-case=verify_initial_payload.json create mode 100644 selfservice/strategy/code/.snapshots/TestLoginCodeStrategy-test=SPA_client-suite=mfa-case=verify_initial_payload.json create mode 100644 test/e2e/cypress/integration/profiles/mfa/code.spec.ts diff --git a/Makefile b/Makefile index cbee2a75fc93..1775d09b25ea 100644 --- a/Makefile +++ b/Makefile @@ -175,7 +175,7 @@ docker: DOCKER_BUILDKIT=1 DOCKER_CONTENT_TRUST=1 docker build -f .docker/Dockerfile-build --build-arg=COMMIT=$(VCS_REF) --build-arg=BUILD_DATE=$(BUILD_DATE) -t oryd/kratos:${IMAGE_TAG} . .PHONY: test-e2e -test-e2e: node_modules test-resetdb +test-e2e: node_modules test-resetdb kratos-config-e2e source script/test-envs.sh test/e2e/run.sh sqlite test/e2e/run.sh postgres @@ -183,7 +183,7 @@ test-e2e: node_modules test-resetdb test/e2e/run.sh mysql .PHONY: test-e2e-playwright -test-e2e-playwright: node_modules test-resetdb +test-e2e-playwright: node_modules test-resetdb kratos-config-e2e source script/test-envs.sh test/e2e/run.sh --only-setup (cd test/e2e; DB=memory npm run playwright) @@ -212,3 +212,7 @@ licenses: .bin/licenses node_modules # checks open-source licenses node_modules: package-lock.json npm ci touch node_modules + +.PHONY: kratos-config-e2e +kratos-config-e2e: + sh ./test/e2e/render-kratos-config.sh diff --git a/cmd/clidoc/main.go b/cmd/clidoc/main.go index 6a9ff0610017..ef3027a936a3 100644 --- a/cmd/clidoc/main.go +++ b/cmd/clidoc/main.go @@ -168,6 +168,9 @@ func init() { "NewErrorValidationRegistrationRetrySuccessful": text.NewErrorValidationRegistrationRetrySuccessful(), "NewInfoSelfServiceRegistrationRegisterCode": text.NewInfoSelfServiceRegistrationRegisterCode(), "NewErrorValidationLoginLinkedCredentialsDoNotMatch": text.NewErrorValidationLoginLinkedCredentialsDoNotMatch(), + "NewErrorValidationAddressUnknown": text.NewErrorValidationAddressUnknown(), + "NewInfoSelfServiceLoginCodeMFA": text.NewInfoSelfServiceLoginCodeMFA(), + "NewInfoSelfServiceLoginCodeMFAHint": text.NewInfoSelfServiceLoginCodeMFAHint("{maskedIdentifier}"), } } @@ -247,7 +250,7 @@ func writeMessages(path string, sortedMessages []*text.Message) error { r := regexp.MustCompile(`(?s)(.*?)`) result := r.ReplaceAllString(string(content), "\n"+w.String()+"\n") - f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755) + f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o755) if err != nil { return err } @@ -266,7 +269,7 @@ func writeMessages(path string, sortedMessages []*text.Message) error { func writeMessagesJson(path string, sortedMessages []*text.Message) error { result := codeEncode(sortedMessages) - f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755) + f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o755) if err != nil { return err } diff --git a/contrib/quickstart/kratos/phone-password/identity.schema.json b/contrib/quickstart/kratos/phone-password/identity.schema.json index 0d986aeb672e..e3a013ffc282 100644 --- a/contrib/quickstart/kratos/phone-password/identity.schema.json +++ b/contrib/quickstart/kratos/phone-password/identity.schema.json @@ -1,5 +1,5 @@ { - "$id": "https://schemas.ory.sh/presets/kratos/quickstart/email-password/identity.schema.json", + "$id": "https://schemas.ory.sh/presets/kratos/quickstart/phone-password/identity.schema.json", "$schema": "http://json-schema.org/draft-07/schema#", "title": "Person", "type": "object", @@ -7,6 +7,26 @@ "traits": { "type": "object", "properties": { + "email": { + "type": "string", + "format": "email", + "title": "E-mail", + "minLength": 3, + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + }, + "code": { + "identifier": true, + "via": "email" + } + }, + "verification": { + "via": "email" + } + } + }, "phone": { "type": "string", "format": "tel", @@ -24,7 +44,7 @@ } } }, - "required": ["phone"], + "required": ["email", "phone"], "additionalProperties": false } } diff --git a/courier/sms_templates.go b/courier/sms_templates.go index 683ba7d98ca3..b560542d53c9 100644 --- a/courier/sms_templates.go +++ b/courier/sms_templates.go @@ -34,6 +34,12 @@ func NewSMSTemplateFromMessage(d template.Dependencies, m Message) (SMSTemplate, return nil, err } return sms.NewTestStub(d, &t), nil + case template.TypeLoginCodeValid: + var t sms.LoginCodeValidModel + if err := json.Unmarshal(m.TemplateData, &t); err != nil { + return nil, err + } + return sms.NewLoginCodeValid(d, &t), nil default: return nil, errors.Errorf("received unexpected message template type: %s", m.TemplateType) diff --git a/courier/template/courier/builtin/templates/login_code/valid/sms.body.gotmpl b/courier/template/courier/builtin/templates/login_code/valid/sms.body.gotmpl new file mode 100644 index 000000000000..5b88dde9a382 --- /dev/null +++ b/courier/template/courier/builtin/templates/login_code/valid/sms.body.gotmpl @@ -0,0 +1 @@ +Your login code is: {{ .LoginCode }} diff --git a/courier/template/sms/login_code_valid.go b/courier/template/sms/login_code_valid.go new file mode 100644 index 000000000000..194e113e6c6b --- /dev/null +++ b/courier/template/sms/login_code_valid.go @@ -0,0 +1,52 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package sms + +import ( + "context" + "encoding/json" + "os" + + "github.com/ory/kratos/courier/template" +) + +type ( + LoginCodeValid struct { + deps template.Dependencies + model *LoginCodeValidModel + } + LoginCodeValidModel struct { + To string + LoginCode string + Identity map[string]interface{} + } +) + +func NewLoginCodeValid(d template.Dependencies, m *LoginCodeValidModel) *LoginCodeValid { + return &LoginCodeValid{deps: d, model: m} +} + +func (t *LoginCodeValid) PhoneNumber() (string, error) { + return t.model.To, nil +} + +func (t *LoginCodeValid) SMSBody(ctx context.Context) (string, error) { + return template.LoadText( + ctx, + t.deps, + os.DirFS(t.deps.CourierConfig().CourierTemplatesRoot(ctx)), + "login_code/valid/sms.body.gotmpl", + "login_code/valid/sms.body*", + t.model, + t.deps.CourierConfig().CourierSMSTemplatesLoginCodeValid(ctx).Body.PlainText, + ) +} + +func (t *LoginCodeValid) MarshalJSON() ([]byte, error) { + return json.Marshal(t.model) +} + +func (t *LoginCodeValid) TemplateType() template.TemplateType { + return template.TypeLoginCodeValid +} diff --git a/courier/template/sms/login_code_valid_test.go b/courier/template/sms/login_code_valid_test.go new file mode 100644 index 000000000000..a2915c750c89 --- /dev/null +++ b/courier/template/sms/login_code_valid_test.go @@ -0,0 +1,37 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package sms_test + +import ( + "context" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/ory/kratos/courier/template/sms" + "github.com/ory/kratos/internal" +) + +func TestNewLoginCodeValid(t *testing.T) { + _, reg := internal.NewFastRegistryWithMocks(t) + + const ( + expectedPhone = "+12345678901" + otp = "012345" + ) + + tpl := sms.NewLoginCodeValid(reg, &sms.LoginCodeValidModel{To: expectedPhone, LoginCode: otp}) + + expectedBody := fmt.Sprintf("Your login code is: %s\n", otp) + + actualBody, err := tpl.SMSBody(context.Background()) + require.NoError(t, err) + assert.Equal(t, expectedBody, actualBody) + + actualPhone, err := tpl.PhoneNumber() + require.NoError(t, err) + assert.Equal(t, expectedPhone, actualPhone) +} diff --git a/driver/config/config.go b/driver/config/config.go index 35d33ee8316a..6af7e7c17c5c 100644 --- a/driver/config/config.go +++ b/driver/config/config.go @@ -67,6 +67,7 @@ const ( ViperKeyCourierTemplatesVerificationCodeInvalidEmail = "courier.templates.verification_code.invalid.email" ViperKeyCourierTemplatesVerificationCodeValidEmail = "courier.templates.verification_code.valid.email" ViperKeyCourierTemplatesVerificationCodeValidSMS = "courier.templates.verification_code.valid.sms" + ViperKeyCourierTemplatesLoginCodeValidSMS = "courier.templates.login_code.valid.sms" ViperKeyCourierDeliveryStrategy = "courier.delivery_strategy" ViperKeyCourierHTTPRequestConfig = "courier.http.request_config" ViperKeyCourierTemplatesLoginCodeValidEmail = "courier.templates.login_code.valid.email" @@ -236,6 +237,7 @@ type ( SelfServiceStrategyCode struct { *SelfServiceStrategy PasswordlessEnabled bool `json:"passwordless_enabled"` + MFAEnabled bool `json:"mfa_enabled"` } Schema struct { ID string `json:"id" koanf:"id"` @@ -303,6 +305,7 @@ type ( CourierTemplatesLoginCodeValid(ctx context.Context) *CourierEmailTemplate CourierTemplatesRegistrationCodeValid(ctx context.Context) *CourierEmailTemplate CourierSMSTemplatesVerificationCodeValid(ctx context.Context) *CourierSMSTemplate + CourierSMSTemplatesLoginCodeValid(ctx context.Context) *CourierSMSTemplate CourierMessageRetries(ctx context.Context) int CourierWorkerPullCount(ctx context.Context) int CourierWorkerPullWait(ctx context.Context) time.Duration @@ -758,8 +761,16 @@ func (p *Config) SelfServiceStrategy(ctx context.Context, strategy string) *Self case "code", "password", "profile": defaultEnabled = true } + + // Backwards compatibility for the old "passwordless_enabled" key + // This force-enables the code strategy, if passwordless is enabled, because in earlier versions it was possible to + // disable the code strategy, but enable passwordless + enabled := pp.BoolF(basePath+".enabled", defaultEnabled) + if strategy == "code" { + enabled = enabled || pp.Bool(basePath+".passwordless_enabled") + } return &SelfServiceStrategy{ - Enabled: pp.BoolF(basePath+".enabled", defaultEnabled), + Enabled: enabled, Config: config, } } @@ -782,6 +793,7 @@ func (p *Config) SelfServiceCodeStrategy(ctx context.Context) *SelfServiceStrate Config: config, }, PasswordlessEnabled: pp.BoolF(basePath+".passwordless_enabled", false), + MFAEnabled: pp.BoolF(basePath+".mfa_enabled", false), } } @@ -1115,6 +1127,10 @@ func (p *Config) CourierSMSTemplatesVerificationCodeValid(ctx context.Context) * return p.CourierSMSTemplatesHelper(ctx, ViperKeyCourierTemplatesVerificationCodeValidSMS) } +func (p *Config) CourierSMSTemplatesLoginCodeValid(ctx context.Context) *CourierSMSTemplate { + return p.CourierSMSTemplatesHelper(ctx, ViperKeyCourierTemplatesLoginCodeValidSMS) +} + func (p *Config) CourierTemplatesLoginCodeValid(ctx context.Context) *CourierEmailTemplate { return p.CourierEmailTemplatesHelper(ctx, ViperKeyCourierTemplatesLoginCodeValidEmail) } diff --git a/driver/registry_default.go b/driver/registry_default.go index 5349c7359d39..890fb7d2f5eb 100644 --- a/driver/registry_default.go +++ b/driver/registry_default.go @@ -327,21 +327,11 @@ func (m *RegistryDefault) selfServiceStrategies() []any { } func (m *RegistryDefault) strategyRegistrationEnabled(ctx context.Context, id string) bool { - switch id { - case identity.CredentialsTypeCodeAuth.String(): - return m.Config().SelfServiceCodeStrategy(ctx).PasswordlessEnabled - default: - return m.Config().SelfServiceStrategy(ctx, id).Enabled - } + return m.Config().SelfServiceStrategy(ctx, id).Enabled } func (m *RegistryDefault) strategyLoginEnabled(ctx context.Context, id string) bool { - switch id { - case identity.CredentialsTypeCodeAuth.String(): - return m.Config().SelfServiceCodeStrategy(ctx).PasswordlessEnabled - default: - return m.Config().SelfServiceStrategy(ctx, id).Enabled - } + return m.Config().SelfServiceStrategy(ctx, id).Enabled } func (m *RegistryDefault) RegistrationStrategies(ctx context.Context, filters ...registration.StrategyFilter) (registrationStrategies registration.Strategies) { diff --git a/driver/registry_default_test.go b/driver/registry_default_test.go index 533cdd621a9a..0dd43e2efc70 100644 --- a/driver/registry_default_test.go +++ b/driver/registry_default_test.go @@ -621,39 +621,49 @@ func TestDriverDefault_Strategies(t *testing.T) { t.Run("case=registration", func(t *testing.T) { t.Parallel() for k, tc := range []struct { + name string prep func(conf *config.Config) expect []string }{ { + name: "no strategies", prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".password.enabled", false) + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.enabled", false) }, }, { + name: "only password", prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".password.enabled", true) + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.enabled", false) }, expect: []string{"password"}, }, { + name: "oidc and password", prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".oidc.enabled", true) conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".password.enabled", true) + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.enabled", false) }, expect: []string{"password", "oidc"}, }, { + name: "oidc, password and totp", prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".oidc.enabled", true) conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".password.enabled", true) conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".totp.enabled", true) + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.enabled", false) }, expect: []string{"password", "oidc"}, }, { + name: "password and code", prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".password.enabled", true) - conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.passwordless_enabled", true) + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.enabled", true) }, expect: []string{"password", "code"}, }, @@ -673,45 +683,64 @@ func TestDriverDefault_Strategies(t *testing.T) { t.Run("case=login", func(t *testing.T) { t.Parallel() - for k, tc := range []struct { + for _, tc := range []struct { + name string prep func(conf *config.Config) expect []string }{ { + name: "no strategies", prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".password.enabled", false) + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.enabled", false) }, }, { + name: "only password", prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".password.enabled", true) + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.enabled", false) }, expect: []string{"password"}, }, { + name: "oidc and password", prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".oidc.enabled", true) conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".password.enabled", true) + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.enabled", false) }, expect: []string{"password", "oidc"}, }, { + name: "oidc, password and totp", prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".oidc.enabled", true) conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".password.enabled", true) conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".totp.enabled", true) + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.enabled", false) }, expect: []string{"password", "oidc", "totp"}, }, { + name: "password and code", prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".password.enabled", true) - conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.passwordless_enabled", true) + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.enabled", true) }, expect: []string{"password", "code"}, }, + { + name: "code is enabled if passwordless_enabled is true", + prep: func(conf *config.Config) { + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".password.enabled", false) + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.enabled", false) + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.passwordless_enabled", true) + }, + expect: []string{"code"}, + }, } { - t.Run(fmt.Sprintf("run=%d", k), func(t *testing.T) { + t.Run(fmt.Sprintf("run=%s", tc.name), func(t *testing.T) { conf, reg := internal.NewVeryFastRegistryWithoutDB(t) tc.prep(conf) diff --git a/embedx/config.schema.json b/embedx/config.schema.json index a42568389fe7..e223b4cc1c79 100644 --- a/embedx/config.schema.json +++ b/embedx/config.schema.json @@ -1410,10 +1410,36 @@ "code": { "type": "object", "additionalProperties": false, + "anyOf": [ + { + "properties": { + "passwordless_enabled": { "const": true }, + "mfa_enabled": { "const": false } + } + }, + { + "properties": { + "mfa_enabled": { "const": true }, + "passwordless_enabled": { "const": false } + } + }, + { + "properties": { + "mfa_enabled": { "const": false }, + "passwordless_enabled": { "const": false } + } + } + ], "properties": { "passwordless_enabled": { "type": "boolean", - "title": "Enables Login and Registration with the Code Method", + "title": "Enables login and registration with the code method.", + "description": "If set to true, code.enabled will be set to true as well.", + "default": false + }, + "mfa_enabled": { + "type": "boolean", + "title": "Enables login flows code method to fulfil MFA requests", "default": false }, "passwordless_login_fallback_enabled": { @@ -1793,6 +1819,9 @@ "properties": { "email": { "$ref": "#/definitions/emailCourierTemplate" + }, + "sms": { + "$ref": "#/definitions/smsCourierTemplate" } }, "required": ["email"] diff --git a/embedx/identity_extension.schema.json b/embedx/identity_extension.schema.json index c105cbe42f95..6ad7765ef839 100644 --- a/embedx/identity_extension.schema.json +++ b/embedx/identity_extension.schema.json @@ -48,7 +48,7 @@ }, "via": { "type": "string", - "enum": ["email"] + "enum": ["email", "sms"] } } } diff --git a/identity/credentials_code.go b/identity/credentials_code.go index abc9decbbf46..b7f828ae09a1 100644 --- a/identity/credentials_code.go +++ b/identity/credentials_code.go @@ -7,7 +7,7 @@ import ( "database/sql" ) -type CodeAddressType string +type CodeAddressType = string const ( CodeAddressTypeEmail CodeAddressType = AddressTypeEmail diff --git a/internal/client-go/api_frontend.go b/internal/client-go/api_frontend.go index ab8c45632935..94c0d05a6dba 100644 --- a/internal/client-go/api_frontend.go +++ b/internal/client-go/api_frontend.go @@ -1890,6 +1890,7 @@ type FrontendApiApiCreateNativeLoginFlowRequest struct { xSessionToken *string returnSessionTokenExchangeCode *bool returnTo *string + via *string } func (r FrontendApiApiCreateNativeLoginFlowRequest) Refresh(refresh bool) FrontendApiApiCreateNativeLoginFlowRequest { @@ -1912,6 +1913,10 @@ func (r FrontendApiApiCreateNativeLoginFlowRequest) ReturnTo(returnTo string) Fr r.returnTo = &returnTo return r } +func (r FrontendApiApiCreateNativeLoginFlowRequest) Via(via string) FrontendApiApiCreateNativeLoginFlowRequest { + r.via = &via + return r +} func (r FrontendApiApiCreateNativeLoginFlowRequest) Execute() (*LoginFlow, *http.Response, error) { return r.ApiService.CreateNativeLoginFlowExecute(r) @@ -1986,6 +1991,9 @@ func (a *FrontendApiService) CreateNativeLoginFlowExecute(r FrontendApiApiCreate if r.returnTo != nil { localVarQueryParams.Add("return_to", parameterToString(*r.returnTo, "")) } + if r.via != nil { + localVarQueryParams.Add("via", parameterToString(*r.via, "")) + } // to determine the Content-Type header localVarHTTPContentTypes := []string{} diff --git a/internal/client-go/model_identity_credentials_code.go b/internal/client-go/model_identity_credentials_code.go index f542b359639a..75857f31c272 100644 --- a/internal/client-go/model_identity_credentials_code.go +++ b/internal/client-go/model_identity_credentials_code.go @@ -18,6 +18,7 @@ import ( // IdentityCredentialsCode CredentialsCode represents a one time login/registration code type IdentityCredentialsCode struct { + // The type of the address for this code AddressType *string `json:"address_type,omitempty"` UsedAt NullableTime `json:"used_at,omitempty"` } diff --git a/internal/httpclient/api_frontend.go b/internal/httpclient/api_frontend.go index ab8c45632935..94c0d05a6dba 100644 --- a/internal/httpclient/api_frontend.go +++ b/internal/httpclient/api_frontend.go @@ -1890,6 +1890,7 @@ type FrontendApiApiCreateNativeLoginFlowRequest struct { xSessionToken *string returnSessionTokenExchangeCode *bool returnTo *string + via *string } func (r FrontendApiApiCreateNativeLoginFlowRequest) Refresh(refresh bool) FrontendApiApiCreateNativeLoginFlowRequest { @@ -1912,6 +1913,10 @@ func (r FrontendApiApiCreateNativeLoginFlowRequest) ReturnTo(returnTo string) Fr r.returnTo = &returnTo return r } +func (r FrontendApiApiCreateNativeLoginFlowRequest) Via(via string) FrontendApiApiCreateNativeLoginFlowRequest { + r.via = &via + return r +} func (r FrontendApiApiCreateNativeLoginFlowRequest) Execute() (*LoginFlow, *http.Response, error) { return r.ApiService.CreateNativeLoginFlowExecute(r) @@ -1986,6 +1991,9 @@ func (a *FrontendApiService) CreateNativeLoginFlowExecute(r FrontendApiApiCreate if r.returnTo != nil { localVarQueryParams.Add("return_to", parameterToString(*r.returnTo, "")) } + if r.via != nil { + localVarQueryParams.Add("via", parameterToString(*r.via, "")) + } // to determine the Content-Type header localVarHTTPContentTypes := []string{} diff --git a/internal/httpclient/model_identity_credentials_code.go b/internal/httpclient/model_identity_credentials_code.go index f542b359639a..75857f31c272 100644 --- a/internal/httpclient/model_identity_credentials_code.go +++ b/internal/httpclient/model_identity_credentials_code.go @@ -18,6 +18,7 @@ import ( // IdentityCredentialsCode CredentialsCode represents a one time login/registration code type IdentityCredentialsCode struct { + // The type of the address for this code AddressType *string `json:"address_type,omitempty"` UsedAt NullableTime `json:"used_at,omitempty"` } diff --git a/internal/registrationhelpers/helpers.go b/internal/registrationhelpers/helpers.go index e9dbe7598797..67a636b567fb 100644 --- a/internal/registrationhelpers/helpers.go +++ b/internal/registrationhelpers/helpers.go @@ -106,7 +106,7 @@ func AssertSchemDoesNotExist(t *testing.T, reg *driver.RegistryDefault, flows [] reset() t.Run("case=should fail because schema does not exist", func(t *testing.T) { - var check = func(t *testing.T, actual string) { + check := func(t *testing.T, actual string) { assert.Equal(t, int64(http.StatusInternalServerError), gjson.Get(actual, "code").Int(), "%s", actual) assert.Equal(t, "Internal Server Error", gjson.Get(actual, "status").String(), "%s", actual) assert.Contains(t, gjson.Get(actual, "reason").String(), "no such file or directory", "%s", actual) @@ -164,7 +164,7 @@ func AssertCSRFFailures(t *testing.T, reg *driver.RegistryDefault, flows []strin apiClient := testhelpers.NewDebugClient(t) _ = testhelpers.NewErrorTestServer(t, reg) - var values = url.Values{ + values := url.Values{ "csrf_token": {"invalid_token"}, "traits.username": {testhelpers.RandomEmail()}, "traits.foobar": {"bar"}, @@ -253,7 +253,7 @@ func AssertRegistrationRespectsValidation(t *testing.T, reg *driver.RegistryDefa t.Run("case=should return an error because not passing validation", func(t *testing.T) { email := testhelpers.RandomEmail() - var check = func(t *testing.T, actual string) { + check := func(t *testing.T, actual string) { assert.NotEmpty(t, gjson.Get(actual, "id").String(), "%s", actual) assert.Contains(t, gjson.Get(actual, "ui.action").String(), publicTS.URL+registration.RouteSubmitFlow, "%s", actual) CheckFormContent(t, []byte(actual), "password", "csrf_token", "traits.username", "traits.foobar") @@ -261,7 +261,7 @@ func AssertRegistrationRespectsValidation(t *testing.T, reg *driver.RegistryDefa assert.Equal(t, email, gjson.Get(actual, "ui.nodes.#(attributes.name==traits.username).attributes.value").String(), "%s", actual) } - var values = func(v url.Values) { + values := func(v url.Values) { v.Set("traits.username", email) v.Del("traits.foobar") payload(v) @@ -411,7 +411,7 @@ func AssertCommonErrorCases(t *testing.T, flows []string) { }) t.Run("case=should show the error ui because the request id is missing", func(t *testing.T) { - var check = func(t *testing.T, actual string) { + check := func(t *testing.T, actual string) { assert.Equal(t, int64(http.StatusNotFound), gjson.Get(actual, "code").Int(), "%s", actual) assert.Equal(t, "Not Found", gjson.Get(actual, "status").String(), "%s", actual) assert.Contains(t, gjson.Get(actual, "message").String(), "Unable to locate the resource", "%s", actual) @@ -481,14 +481,14 @@ func AssertCommonErrorCases(t *testing.T, flows []string) { }) }) - t.Run("case=should fail because the return_to url is not allowed", func(t *testing.T) { + t.Run("case=should fail because the password was used in databreaches", func(t *testing.T) { testhelpers.SetDefaultIdentitySchemaFromRaw(conf, multifieldSchema) t.Cleanup(func() { testhelpers.SetDefaultIdentitySchemaFromRaw(conf, basicSchema) }) email := testhelpers.RandomEmail() - var check = func(t *testing.T, actual string) { + check := func(t *testing.T, actual string) { assert.NotEmpty(t, gjson.Get(actual, "id").String(), "%s", actual) assert.Contains(t, gjson.Get(actual, "ui.action").String(), publicTS.URL+registration.RouteSubmitFlow, "%s", actual) CheckFormContent(t, []byte(actual), "password", "csrf_token", "traits.username", "traits.foobar") @@ -498,7 +498,7 @@ func AssertCommonErrorCases(t *testing.T, flows []string) { assert.Equal(t, "password", gjson.Get(actual, "ui.nodes.#(attributes.name==method).attributes.value").String(), "%s", actual) } - var values = func(v url.Values) { + values := func(v url.Values) { v.Set("traits.username", email) v.Set("password", "password") v.Set("traits.foobar", "bar") diff --git a/internal/testhelpers/courier.go b/internal/testhelpers/courier.go index fd9aa63f45d2..796dac29989d 100644 --- a/internal/testhelpers/courier.go +++ b/internal/testhelpers/courier.go @@ -36,7 +36,7 @@ func CourierExpectMessage(ctx context.Context, t *testing.T, reg interface { } } - require.Failf(t, "could not find courier messages with recipient %s and subject %s", recipient, subject) + require.Failf(t, "could not find courier messages", "could not find courier messages with recipient %s and subject %s", recipient, subject) return nil } diff --git a/internal/testhelpers/selfservice_login.go b/internal/testhelpers/selfservice_login.go index bedba03fee16..2bd20f81dfd4 100644 --- a/internal/testhelpers/selfservice_login.go +++ b/internal/testhelpers/selfservice_login.go @@ -58,6 +58,7 @@ type initFlowOptions struct { returnTo string refresh bool oauth2LoginChallenge string + via string } func (o *initFlowOptions) apply(opts []InitFlowWithOption) *initFlowOptions { @@ -86,6 +87,9 @@ func getURLFromInitOptions(ts *httptest.Server, path string, forced bool, opts . if o.oauth2LoginChallenge != "" { q.Set("login_challenge", o.oauth2LoginChallenge) } + if o.via != "" { + q.Set("via", o.via) + } u := urlx.ParseOrPanic(ts.URL + path) u.RawQuery = q.Encode() @@ -118,6 +122,13 @@ func InitFlowWithOAuth2LoginChallenge(hlc string) InitFlowWithOption { } } +// InitFlowWithVia sets the `via` query parameter which is used by the code MFA flows to determine the trait to use to send the code to the user +func InitFlowWithVia(via string) InitFlowWithOption { + return func(o *initFlowOptions) { + o.via = via + } +} + func InitializeLoginFlowViaBrowser(t *testing.T, client *http.Client, ts *httptest.Server, forced bool, isSPA bool, expectInitError bool, expectGetError bool, opts ...InitFlowWithOption) *kratos.LoginFlow { publicClient := NewSDKCustomClient(ts, client) @@ -132,8 +143,8 @@ 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()) + require.Equal(t, 200, res.StatusCode, "%s", body) if expectInitError { - require.Equal(t, 200, res.StatusCode) require.NotNil(t, res.Request.URL) require.Contains(t, res.Request.URL.String(), "error-ts") } @@ -142,13 +153,14 @@ func InitializeLoginFlowViaBrowser(t *testing.T, client *http.Client, ts *httpte if isSPA { flowID = gjson.GetBytes(body, "id").String() } + require.NotEmpty(t, flowID) - rs, _, err := publicClient.FrontendApi.GetLoginFlow(context.Background()).Id(flowID).Execute() + rs, r, err := publicClient.FrontendApi.GetLoginFlow(context.Background()).Id(flowID).Execute() if expectGetError { require.Error(t, err) require.Nil(t, rs) } else { - require.NoError(t, err) + require.NoError(t, err, "%s", ioutilx.MustReadAll(r.Body)) assert.Empty(t, rs.Active) } @@ -163,9 +175,12 @@ func InitializeLoginFlowViaAPI(t *testing.T, client *http.Client, ts *httptest.S if o.aal != "" { req = req.Aal(string(o.aal)) } + if o.via != "" { + req = req.Via(o.via) + } - rs, _, err := req.Execute() - require.NoError(t, err) + rs, res, err := req.Execute() + require.NoError(t, err, "%s", ioutilx.MustReadAll(res.Body)) assert.Empty(t, rs.Active) return rs diff --git a/internal/testhelpers/server.go b/internal/testhelpers/server.go index c3dffb9ab9d8..2608b04f2d1f 100644 --- a/internal/testhelpers/server.go +++ b/internal/testhelpers/server.go @@ -33,7 +33,10 @@ func NewKratosServerWithCSRFAndRouters(t *testing.T, reg driver.Registry) (publi ran := negroni.New() ran.UseFunc(x.RedirectAdminMiddleware) ran.UseHandler(ra) - public = httptest.NewServer(x.NewTestCSRFHandler(rp, reg)) + rpn := negroni.New() + rpn.UseFunc(x.HTTPLoaderContextMiddleware(reg)) + rpn.UseHandler(rp) + public = httptest.NewServer(x.NewTestCSRFHandler(rpn, reg)) admin = httptest.NewServer(ran) ctx := context.Background() diff --git a/internal/testhelpers/session.go b/internal/testhelpers/session.go index e6e9da316ffd..adbc4f81a392 100644 --- a/internal/testhelpers/session.go +++ b/internal/testhelpers/session.go @@ -196,6 +196,20 @@ func NewHTTPClientWithIdentitySessionCookie(t *testing.T, reg *driver.RegistryDe return NewHTTPClientWithSessionCookie(t, reg, s) } +func NewHTTPClientWithIdentitySessionCookieLocalhost(t *testing.T, reg *driver.RegistryDefault, id *identity.Identity) *http.Client { + req := NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) + s, err := session.NewActiveSession(req, + id, + NewSessionLifespanProvider(time.Hour), + time.Now(), + identity.CredentialsTypePassword, + identity.AuthenticatorAssuranceLevel1, + ) + require.NoError(t, err, "Could not initialize session from identity.") + + return NewHTTPClientWithSessionCookieLocalhost(t, reg, s) +} + func NewHTTPClientWithIdentitySessionToken(t *testing.T, reg *driver.RegistryDefault, id *identity.Identity) *http.Client { req := NewTestHTTPRequest(t, "GET", "/sessions/whoami", nil) s, err := session.NewActiveSession(req, diff --git a/schema/errors.go b/schema/errors.go index d72e02af7d11..30c1f72976f3 100644 --- a/schema/errors.go +++ b/schema/errors.go @@ -359,3 +359,14 @@ func NewLinkedCredentialsDoNotMatch() error { Messages: new(text.Messages).Add(text.NewErrorValidationLoginLinkedCredentialsDoNotMatch()), }) } + +func NewUnknownAddressError() error { + return errors.WithStack(&ValidationError{ + ValidationError: &jsonschema.ValidationError{ + Message: `the supplied address does not match any known addresses.`, + InstancePtr: "#/", + }, + Messages: new(text.Messages).Add(text.NewErrorValidationAddressUnknown()), + }, + ) +} diff --git a/selfservice/flow/login/extension_identifier_label.go b/selfservice/flow/login/extension_identifier_label.go index 02b725f00b7f..9d28dd8ecf9f 100644 --- a/selfservice/flow/login/extension_identifier_label.go +++ b/selfservice/flow/login/extension_identifier_label.go @@ -6,6 +6,10 @@ package login import ( "context" + "github.com/pkg/errors" + "github.com/samber/lo" + + "github.com/ory/herodot" "github.com/ory/kratos/text" "github.com/ory/jsonschema/v3" @@ -13,25 +17,46 @@ import ( ) type identifierLabelExtension struct { + field string identifierLabelCandidates []string } -var _ schema.CompileExtension = new(identifierLabelExtension) +var ( + _ schema.CompileExtension = new(identifierLabelExtension) + ErrUnknownTrait = herodot.ErrInternalServerError.WithReasonf("Trait does not exist in identity schema") +) func GetIdentifierLabelFromSchema(ctx context.Context, schemaURL string) (*text.Message, error) { - ext := &identifierLabelExtension{} + return GetIdentifierLabelFromSchemaWithField(ctx, schemaURL, "") +} + +func GetIdentifierLabelFromSchemaWithField(ctx context.Context, schemaURL string, trait string) (*text.Message, error) { + ext := &identifierLabelExtension{ + field: trait, + } runner, err := schema.NewExtensionRunner(ctx, schema.WithCompileRunners(ext)) if err != nil { return nil, err } c := jsonschema.NewCompiler() + c.ExtractAnnotations = true runner.Register(c) - _, err = c.Compile(ctx, schemaURL) + s, err := c.Compile(ctx, schemaURL) if err != nil { return nil, err } + + if trait != "" { + f, ok := s.Properties["traits"].Properties[trait] + if !ok { + knownTraits := lo.Keys(s.Properties["traits"].Properties) + return nil, errors.WithStack(ErrUnknownTrait.WithDetail("trait", trait).WithDetail("known_traits", knownTraits)) + } + return text.NewInfoNodeLabelGenerated(f.Title), nil + } + metaLabel := text.NewInfoNodeLabelID() if label := ext.getLabel(); label != "" { metaLabel = text.NewInfoNodeLabelGenerated(label) diff --git a/selfservice/flow/login/handler.go b/selfservice/flow/login/handler.go index 096a657c0869..ab7fe85245e2 100644 --- a/selfservice/flow/login/handler.go +++ b/selfservice/flow/login/handler.go @@ -186,14 +186,6 @@ func (h *Handler) NewLoginFlow(w http.ResponseWriter, r *http.Request, ft flow.T } preLoginHook: - if f.Refresh { - f.UI.Messages.Set(text.NewInfoLoginReAuth()) - } - - if sess != nil && f.RequestedAAL > sess.AuthenticatorAssuranceLevel && f.RequestedAAL > identity.AuthenticatorAssuranceLevel1 { - f.UI.Messages.Add(text.NewInfoLoginMFA()) - } - var strategyFilters []StrategyFilter orgID := uuid.NullUUID{ Valid: false, @@ -222,6 +214,14 @@ preLoginHook: } } + if f.Refresh { + f.UI.Messages.Set(text.NewInfoLoginReAuth()) + } + + if sess != nil && f.RequestedAAL > sess.AuthenticatorAssuranceLevel && f.RequestedAAL > identity.AuthenticatorAssuranceLevel1 { + f.UI.Messages.Add(text.NewInfoLoginMFA()) + } + if err := sortNodes(r.Context(), f.UI.Nodes); err != nil { return nil, nil, err } @@ -293,6 +293,11 @@ type createNativeLoginFlow struct { // // in: query ReturnTo string `json:"return_to"` + + // Via should contain the identity's credential the code should be sent to. Only relevant in aal2 flows. + // + // in: query + Via string `json:"via"` } // swagger:route GET /self-service/login/api frontend createNativeLoginFlow @@ -781,7 +786,7 @@ continueLogin: var i *identity.Identity var group node.UiNodeGroup for _, ss := range h.d.AllLoginStrategies() { - interim, err := ss.Login(w, r, f, sess.IdentityID) + interim, err := ss.Login(w, r, f, sess) group = ss.NodeGroup() if errors.Is(err, flow.ErrStrategyNotResponsible) { continue @@ -798,7 +803,7 @@ continueLogin: sess = session.NewInactiveSession() } - method := ss.CompletedAuthenticationMethod(r.Context()) + method := ss.CompletedAuthenticationMethod(r.Context(), sess.AMR) sess.CompletedLoginForMethod(method) i = interim break diff --git a/selfservice/flow/login/hook.go b/selfservice/flow/login/hook.go index 620559f57b06..418e9237df5c 100644 --- a/selfservice/flow/login/hook.go +++ b/selfservice/flow/login/hook.go @@ -356,7 +356,7 @@ func (e *HookExecutor) maybeLinkCredentials(ctx context.Context, sess *session.S return err } - method := strategy.CompletedAuthenticationMethod(ctx) + method := strategy.CompletedAuthenticationMethod(ctx, sess.AMR) sess.CompletedLoginForMethod(method) return nil diff --git a/selfservice/flow/login/strategy.go b/selfservice/flow/login/strategy.go index c8ad84986a55..c70ad9cc8684 100644 --- a/selfservice/flow/login/strategy.go +++ b/selfservice/flow/login/strategy.go @@ -7,7 +7,6 @@ import ( "context" "net/http" - "github.com/gofrs/uuid" "github.com/pkg/errors" "github.com/ory/kratos/identity" @@ -22,8 +21,8 @@ type Strategy interface { NodeGroup() node.UiNodeGroup RegisterLoginRoutes(*x.RouterPublic) PopulateLoginMethod(r *http.Request, requestedAAL identity.AuthenticatorAssuranceLevel, sr *Flow) error - Login(w http.ResponseWriter, r *http.Request, f *Flow, identityID uuid.UUID) (i *identity.Identity, err error) - CompletedAuthenticationMethod(ctx context.Context) session.AuthenticationMethod + Login(w http.ResponseWriter, r *http.Request, f *Flow, sess *session.Session) (i *identity.Identity, err error) + CompletedAuthenticationMethod(ctx context.Context, methods session.AuthenticationMethods) session.AuthenticationMethod } type Strategies []Strategy diff --git a/selfservice/flow/registration/handler_test.go b/selfservice/flow/registration/handler_test.go index eae66fb720f8..a9e7b842718c 100644 --- a/selfservice/flow/registration/handler_test.go +++ b/selfservice/flow/registration/handler_test.go @@ -21,6 +21,7 @@ import ( "github.com/ory/kratos/corpx" "github.com/ory/kratos/hydra" + "github.com/ory/x/ioutilx" "github.com/ory/x/urlx" "github.com/stretchr/testify/assert" @@ -479,7 +480,7 @@ func TestOIDCStrategyOrder(t *testing.T) { resp, err := client.Do(req) require.NoError(t, err) - require.Equal(t, http.StatusOK, resp.StatusCode) + require.Equal(t, http.StatusOK, resp.StatusCode, "%s", ioutilx.MustReadAll(resp.Body)) verifiableAddress, err := reg.PrivilegedIdentityPool().FindVerifiableAddressByValue(ctx, identity.VerifiableAddressTypeEmail, email) require.NoError(t, err) diff --git a/selfservice/flow/request.go b/selfservice/flow/request.go index 6db872f43199..bb140eae24a2 100644 --- a/selfservice/flow/request.go +++ b/selfservice/flow/request.go @@ -10,7 +10,6 @@ import ( "strings" "github.com/ory/kratos/driver/config" - "github.com/ory/kratos/identity" "github.com/ory/kratos/selfservice/strategy" "github.com/ory/x/decoderx" @@ -106,19 +105,7 @@ func MethodEnabledAndAllowed(ctx context.Context, flowName FlowName, expected, a return errors.WithStack(ErrStrategyNotResponsible) } - var ok bool - if strings.EqualFold(actual, identity.CredentialsTypeCodeAuth.String()) { - switch flowName { - case RegistrationFlow, LoginFlow: - ok = d.Config().SelfServiceCodeStrategy(ctx).PasswordlessEnabled - case VerificationFlow, RecoveryFlow: - ok = d.Config().SelfServiceCodeStrategy(ctx).Enabled - } - } else { - ok = d.Config().SelfServiceStrategy(ctx, expected).Enabled - } - - if !ok { + if !d.Config().SelfServiceStrategy(ctx, expected).Enabled { return errors.WithStack(herodot.ErrNotFound.WithReason(strategy.EndpointDisabledMessage)) } diff --git a/selfservice/flow/request_test.go b/selfservice/flow/request_test.go index adc47f6149c9..3728748f8044 100644 --- a/selfservice/flow/request_test.go +++ b/selfservice/flow/request_test.go @@ -101,74 +101,3 @@ func TestMethodEnabledAndAllowed(t *testing.T) { assert.Contains(t, string(body), "The requested resource could not be found") }) } - -func TestMethodCodeEnabledAndAllowed(t *testing.T) { - ctx := context.Background() - conf, d := internal.NewFastRegistryWithMocks(t) - - currentFlow := make(chan flow.FlowName, 1) - - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - f := <-currentFlow - if err := flow.MethodEnabledAndAllowedFromRequest(r, f, "code", d); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - w.WriteHeader(http.StatusNoContent) - })) - - t.Run("login code allowed", func(t *testing.T) { - conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.passwordless_enabled", true) - currentFlow <- flow.LoginFlow - res, err := ts.Client().PostForm(ts.URL, url.Values{"method": {"code"}}) - require.NoError(t, err) - require.NoError(t, res.Body.Close()) - assert.Equal(t, http.StatusNoContent, res.StatusCode) - }) - - t.Run("login code not allowed", func(t *testing.T) { - conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.passwordless_enabled", false) - currentFlow <- flow.LoginFlow - res, err := ts.Client().PostForm(ts.URL, url.Values{"method": {"code"}}) - require.NoError(t, err) - body, err := io.ReadAll(res.Body) - require.NoError(t, err) - require.NoError(t, res.Body.Close()) - assert.Equal(t, http.StatusInternalServerError, res.StatusCode) - assert.Contains(t, string(body), "The requested resource could not be found") - }) - - t.Run("registration code allowed", func(t *testing.T) { - conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.passwordless_enabled", true) - currentFlow <- flow.RegistrationFlow - res, err := ts.Client().PostForm(ts.URL, url.Values{"method": {"code"}}) - require.NoError(t, err) - require.NoError(t, res.Body.Close()) - assert.Equal(t, http.StatusNoContent, res.StatusCode) - }) - - t.Run("registration code not allowed", func(t *testing.T) { - conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.passwordless_enabled", false) - currentFlow <- flow.RegistrationFlow - res, err := ts.Client().PostForm(ts.URL, url.Values{"method": {"code"}}) - require.NoError(t, err) - body, err := io.ReadAll(res.Body) - require.NoError(t, err) - require.NoError(t, res.Body.Close()) - assert.Equal(t, http.StatusInternalServerError, res.StatusCode) - assert.Contains(t, string(body), "The requested resource could not be found") - }) - - t.Run("recovery and verification should still be allowed if registration and login is disabled", func(t *testing.T) { - conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.passwordless_enabled", false) - conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.enabled", true) - - for _, f := range []flow.FlowName{flow.RecoveryFlow, flow.VerificationFlow} { - currentFlow <- f - res, err := ts.Client().PostForm(ts.URL, url.Values{"method": {"code"}}) - require.NoError(t, err) - require.NoError(t, res.Body.Close()) - assert.Equal(t, http.StatusNoContent, res.StatusCode) - } - }) -} diff --git a/selfservice/strategy/code/.snapshots/TestLoginCodeStrategy-test=Browser_client-suite=mfa-case=verify_initial_payload.json b/selfservice/strategy/code/.snapshots/TestLoginCodeStrategy-test=Browser_client-suite=mfa-case=verify_initial_payload.json new file mode 100644 index 000000000000..14efb22f25a3 --- /dev/null +++ b/selfservice/strategy/code/.snapshots/TestLoginCodeStrategy-test=Browser_client-suite=mfa-case=verify_initial_payload.json @@ -0,0 +1,84 @@ +{ + "organization_id": null, + "refresh": false, + "requested_aal": "aal2", + "state": "choose_method", + "type": "browser", + "ui": { + "messages": [ + { + "id": 1010004, + "text": "Please complete the second authentication challenge.", + "type": "info" + } + ], + "method": "POST", + "nodes": [ + { + "attributes": { + "disabled": false, + "name": "csrf_token", + "node_type": "input", + "required": true, + "type": "hidden" + }, + "group": "default", + "messages": [], + "meta": {}, + "type": "input" + }, + { + "attributes": { + "disabled": false, + "name": "identifier", + "node_type": "input", + "required": true, + "type": "text", + "value": "" + }, + "group": "default", + "messages": [ + { + "context": { + "masked_to": "fi****@ory.sh" + }, + "id": 1010020, + "text": "We will send a code to fi****@ory.sh. To verify that this is your address please enter it here.", + "type": "info" + } + ], + "meta": { + "label": { + "context": { + "title": "Email" + }, + "id": 1070002, + "text": "Email", + "type": "info" + } + }, + "type": "input" + }, + { + "attributes": { + "disabled": false, + "name": "method", + "node_type": "input", + "type": "submit", + "value": "code" + }, + "group": "code", + "messages": [], + "meta": { + "label": { + "id": 1010019, + "text": "Continue with code", + "type": "info" + } + }, + "type": "input" + } + ] + } +} + diff --git a/selfservice/strategy/code/.snapshots/TestLoginCodeStrategy-test=Native_client-suite=mfa-case=verify_initial_payload.json b/selfservice/strategy/code/.snapshots/TestLoginCodeStrategy-test=Native_client-suite=mfa-case=verify_initial_payload.json new file mode 100644 index 000000000000..49f7d3a37cc1 --- /dev/null +++ b/selfservice/strategy/code/.snapshots/TestLoginCodeStrategy-test=Native_client-suite=mfa-case=verify_initial_payload.json @@ -0,0 +1,70 @@ +{ + "organization_id": null, + "refresh": false, + "requested_aal": "aal2", + "state": "choose_method", + "type": "api", + "ui": { + "messages": [ + { + "id": 1010004, + "text": "Please complete the second authentication challenge.", + "type": "info" + } + ], + "method": "POST", + "nodes": [ + { + "attributes": { + "disabled": false, + "name": "identifier", + "node_type": "input", + "required": true, + "type": "text" + }, + "group": "default", + "messages": [ + { + "context": { + "masked_to": "fi****@ory.sh" + }, + "id": 1010020, + "text": "We will send a code to fi****@ory.sh. To verify that this is your address please enter it here.", + "type": "info" + } + ], + "meta": { + "label": { + "context": { + "title": "Email" + }, + "id": 1070002, + "text": "Email", + "type": "info" + } + }, + "type": "input" + }, + { + "attributes": { + "disabled": false, + "name": "method", + "node_type": "input", + "type": "submit", + "value": "code" + }, + "group": "code", + "messages": [], + "meta": { + "label": { + "id": 1010019, + "text": "Continue with code", + "type": "info" + } + }, + "type": "input" + } + ] + } +} + diff --git a/selfservice/strategy/code/.snapshots/TestLoginCodeStrategy-test=SPA_client-suite=mfa-case=verify_initial_payload.json b/selfservice/strategy/code/.snapshots/TestLoginCodeStrategy-test=SPA_client-suite=mfa-case=verify_initial_payload.json new file mode 100644 index 000000000000..14efb22f25a3 --- /dev/null +++ b/selfservice/strategy/code/.snapshots/TestLoginCodeStrategy-test=SPA_client-suite=mfa-case=verify_initial_payload.json @@ -0,0 +1,84 @@ +{ + "organization_id": null, + "refresh": false, + "requested_aal": "aal2", + "state": "choose_method", + "type": "browser", + "ui": { + "messages": [ + { + "id": 1010004, + "text": "Please complete the second authentication challenge.", + "type": "info" + } + ], + "method": "POST", + "nodes": [ + { + "attributes": { + "disabled": false, + "name": "csrf_token", + "node_type": "input", + "required": true, + "type": "hidden" + }, + "group": "default", + "messages": [], + "meta": {}, + "type": "input" + }, + { + "attributes": { + "disabled": false, + "name": "identifier", + "node_type": "input", + "required": true, + "type": "text", + "value": "" + }, + "group": "default", + "messages": [ + { + "context": { + "masked_to": "fi****@ory.sh" + }, + "id": 1010020, + "text": "We will send a code to fi****@ory.sh. To verify that this is your address please enter it here.", + "type": "info" + } + ], + "meta": { + "label": { + "context": { + "title": "Email" + }, + "id": 1070002, + "text": "Email", + "type": "info" + } + }, + "type": "input" + }, + { + "attributes": { + "disabled": false, + "name": "method", + "node_type": "input", + "type": "submit", + "value": "code" + }, + "group": "code", + "messages": [], + "meta": { + "label": { + "id": 1010019, + "text": "Continue with code", + "type": "info" + } + }, + "type": "input" + } + ] + } +} + diff --git a/selfservice/strategy/code/code_sender.go b/selfservice/strategy/code/code_sender.go index d41beef463ed..ccc3330f9ba8 100644 --- a/selfservice/strategy/code/code_sender.go +++ b/selfservice/strategy/code/code_sender.go @@ -84,7 +84,7 @@ func (s *Sender) SendCode(ctx context.Context, f flow.Flow, id *identity.Identit code, err := s.deps. RegistrationCodePersister(). CreateRegistrationCode(ctx, &CreateRegistrationCodeParams{ - AddressType: address.Via, + AddressType: identity.CodeAddressType(address.Via), RawCode: rawCode, ExpiresIn: s.deps.Config().SelfServiceCodeMethodLifespan(ctx), FlowID: f.GetID(), @@ -118,7 +118,7 @@ func (s *Sender) SendCode(ctx context.Context, f flow.Flow, id *identity.Identit code, err := s.deps. LoginCodePersister(). CreateLoginCode(ctx, &CreateLoginCodeParams{ - AddressType: address.Via, + AddressType: identity.CodeAddressType(address.Via), Address: address.To, RawCode: rawCode, ExpiresIn: s.deps.Config().SelfServiceCodeMethodLifespan(ctx), @@ -133,19 +133,29 @@ func (s *Sender) SendCode(ctx context.Context, f flow.Flow, id *identity.Identit if err != nil { return err } - - emailModel := email.LoginCodeValidModel{ - To: address.To, - LoginCode: rawCode, - Identity: model, - } s.deps.Audit(). WithField("login_flow_id", code.FlowID). WithField("login_code_id", code.ID). WithSensitiveField("login_code", rawCode). Info("Sending out login email with code.") - if err := s.send(ctx, string(address.Via), email.NewLoginCodeValid(s.deps, &emailModel)); err != nil { + var t courier.Template + switch address.Via { + case identity.ChannelTypeEmail: + t = email.NewLoginCodeValid(s.deps, &email.LoginCodeValidModel{ + To: address.To, + LoginCode: rawCode, + Identity: model, + }) + case identity.ChannelTypeSMS: + t = sms.NewLoginCodeValid(s.deps, &sms.LoginCodeValidModel{ + To: address.To, + LoginCode: rawCode, + Identity: model, + }) + } + + if err := s.send(ctx, string(address.Via), t); err != nil { return errors.WithStack(err) } diff --git a/selfservice/strategy/code/strategy.go b/selfservice/strategy/code/strategy.go index a5d0c83703ec..a4b52e980754 100644 --- a/selfservice/strategy/code/strategy.go +++ b/selfservice/strategy/code/strategy.go @@ -4,10 +4,12 @@ package code import ( + "context" "net/http" "strings" "github.com/pkg/errors" + "github.com/tidwall/gjson" "github.com/ory/herodot" "github.com/ory/kratos/continuity" @@ -132,190 +134,243 @@ func (s *Strategy) NodeGroup() node.UiNodeGroup { } func (s *Strategy) PopulateMethod(r *http.Request, f flow.Flow) error { + codeConfig := s.deps.Config().SelfServiceCodeStrategy(r.Context()) + switch f := f.(type) { + case *login.Flow: + if f.RequestedAAL == identity.AuthenticatorAssuranceLevel2 { + if !codeConfig.MFAEnabled { + // if the flow is requesting AAL2 but MFA is not enabled for the code strategy, we return nil so that + // other strategies can fulfil the request + return nil + } + } else if !codeConfig.PasswordlessEnabled { + // if the flow is a normal login flow but passwordless is not enabled for the code strategy, + // we return nil so that other strategies can fulfil the request + return nil + } + case *registration.Flow: + // for registration flows, we don't have AAL requirements, so we just check that passwordless is enabled. + if !codeConfig.PasswordlessEnabled { + return nil + } + } + if string(f.GetState()) == "" { f.SetState(flow.StateChooseMethod) } f.GetUI().ResetMessages() - nodes := f.GetUI().Nodes - switch f.GetState() { case flow.StateChooseMethod: + if err := s.populateChooseMethodFlow(r, f); err != nil { + return err + } + case flow.StateEmailSent: + if err := s.populateEmailSentFlow(r.Context(), f); err != nil { + return err + } + case flow.StatePassedChallenge: + fallthrough + default: + return errors.WithStack(herodot.ErrBadRequest.WithReason("received an unexpected flow state")) + } - if f.GetFlowName() == flow.VerificationFlow || f.GetFlowName() == flow.RecoveryFlow { - nodes.Append( - node.NewInputField("email", nil, node.CodeGroup, node.InputAttributeTypeEmail, node.WithRequiredInputAttribute). - WithMetaLabel(text.NewInfoNodeInputEmail()), - ) - } else if f.GetFlowName() == flow.LoginFlow { - ds, err := s.deps.Config().DefaultIdentityTraitsSchemaURL(r.Context()) + // no matter the flow type or state we need to set the CSRF token + if f.GetType() == flow.TypeBrowser { + f.GetUI().SetCSRF(s.deps.GenerateCSRFToken(r)) + } + return nil +} + +func (s *Strategy) populateChooseMethodFlow(r *http.Request, f flow.Flow) error { + ctx := r.Context() + var codeMetaLabel *text.Message + switch f := f.(type) { + case *recovery.Flow, *verification.Flow: + f.GetUI().Nodes.Append( + node.NewInputField("email", nil, node.CodeGroup, node.InputAttributeTypeEmail, node.WithRequiredInputAttribute). + WithMetaLabel(text.NewInfoNodeInputEmail()), + ) + codeMetaLabel = text.NewInfoNodeLabelSubmit() + case *login.Flow: + ds, err := s.deps.Config().DefaultIdentityTraitsSchemaURL(ctx) + if err != nil { + return err + } + if f.RequestedAAL == identity.AuthenticatorAssuranceLevel2 { + via := r.URL.Query().Get("via") + if via == "" { + return errors.WithStack(herodot.ErrBadRequest.WithReason("AAL2 login via code requires the `via` query parameter")) + } + + sess, err := s.deps.SessionManager().FetchFromRequest(r.Context(), r) if err != nil { return err } - identifierLabel, err := login.GetIdentifierLabelFromSchema(r.Context(), ds.String()) + allSchemas, err := s.deps.IdentityTraitsSchemas(ctx) if err != nil { return err } - - nodes.Upsert(node.NewInputField("identifier", "", node.DefaultGroup, node.InputAttributeTypeText, node.WithRequiredInputAttribute).WithMetaLabel(identifierLabel)) - } else if f.GetFlowName() == flow.RegistrationFlow { - ds, err := s.deps.Config().DefaultIdentityTraitsSchemaURL(r.Context()) + iSchema, err := allSchemas.GetByID(sess.Identity.SchemaID) if err != nil { return err } - - // set the traits on the default group so that the ui can render them - // this prevents having multiple of the same ui fields on the same ui form - traitNodes, err := container.NodesFromJSONSchema(r.Context(), node.DefaultGroup, ds.String(), "", nil) + identifierLabel, err := login.GetIdentifierLabelFromSchemaWithField(ctx, iSchema.RawURL, via) if err != nil { return err } - for _, n := range traitNodes { - nodes.Upsert(n) + value := gjson.GetBytes(sess.Identity.Traits, via).String() + if value == "" { + return errors.WithStack(herodot.ErrBadRequest.WithReasonf("No value found for trait %s in the current identity", via)) + } + + codeMetaLabel = text.NewInfoSelfServiceLoginCodeMFA() + idNode := node.NewInputField("identifier", "", node.DefaultGroup, node.InputAttributeTypeText, node.WithRequiredInputAttribute).WithMetaLabel(identifierLabel) + idNode.Messages.Add(text.NewInfoSelfServiceLoginCodeMFAHint(MaskAddress(value))) + f.GetUI().Nodes.Upsert(idNode) + } else { + codeMetaLabel = text.NewInfoSelfServiceLoginCode() + identifierLabel, err := login.GetIdentifierLabelFromSchema(ctx, ds.String()) + if err != nil { + return err } + + f.GetUI().Nodes.Upsert(node.NewInputField("identifier", "", node.DefaultGroup, node.InputAttributeTypeText, node.WithRequiredInputAttribute).WithMetaLabel(identifierLabel)) + } + case *registration.Flow: + codeMetaLabel = text.NewInfoSelfServiceRegistrationRegisterCode() + ds, err := s.deps.Config().DefaultIdentityTraitsSchemaURL(ctx) + if err != nil { + return err } - var codeMetaLabel *text.Message + // set the traits on the default group so that the ui can render them + // this prevents having multiple of the same ui fields on the same ui form + traitNodes, err := container.NodesFromJSONSchema(ctx, node.DefaultGroup, ds.String(), "", nil) + if err != nil { + return err + } - switch f.GetFlowName() { - case flow.VerificationFlow, flow.RecoveryFlow: - codeMetaLabel = text.NewInfoNodeLabelSubmit() - case flow.LoginFlow: - codeMetaLabel = text.NewInfoSelfServiceLoginCode() - case flow.RegistrationFlow: - codeMetaLabel = text.NewInfoSelfServiceRegistrationRegisterCode() + for _, n := range traitNodes { + f.GetUI().Nodes.Upsert(n) } + } - methodButton := node.NewInputField("method", s.ID(), node.CodeGroup, node.InputAttributeTypeSubmit). - WithMetaLabel(codeMetaLabel) + methodButton := node.NewInputField("method", s.ID(), node.CodeGroup, node.InputAttributeTypeSubmit). + WithMetaLabel(codeMetaLabel) - nodes.Append(methodButton) + f.GetUI().Nodes.Append(methodButton) - f.GetUI().Nodes = nodes + return nil +} - case flow.StateEmailSent: - // fresh ui node group - freshNodes := node.Nodes{} - var route string - var codeMetaLabel *text.Message - var message *text.Message - - var resendNode *node.Node - - switch f.GetFlowName() { - case flow.RecoveryFlow: - route = recovery.RouteSubmitFlow - codeMetaLabel = text.NewInfoNodeLabelRecoveryCode() - message = text.NewRecoveryEmailWithCodeSent() - - resendNode = node.NewInputField("email", nil, node.CodeGroup, node.InputAttributeTypeEmail, node.WithRequiredInputAttribute). - WithMetaLabel(text.NewInfoNodeResendOTP()) - case flow.VerificationFlow: - route = verification.RouteSubmitFlow - codeMetaLabel = text.NewInfoNodeLabelVerificationCode() - message = text.NewVerificationEmailWithCodeSent() - - case flow.LoginFlow: - route = login.RouteSubmitFlow - codeMetaLabel = text.NewInfoNodeLabelLoginCode() - message = text.NewLoginEmailWithCodeSent() - - // preserve the login identifier that were submitted - // so we can retry the code flow with the same data - for _, n := range f.GetUI().Nodes { - if n.Group == node.DefaultGroup { - // we don't need the user to change the values here - // for better UX let's make them disabled - // when there are errors we won't hide the fields - if len(n.Messages) == 0 { - if input, ok := n.Attributes.(*node.InputAttributes); ok { - input.Type = "hidden" - n.Attributes = input - } +func (s *Strategy) populateEmailSentFlow(ctx context.Context, f flow.Flow) error { + // fresh ui node group + freshNodes := node.Nodes{} + var route string + var codeMetaLabel *text.Message + var message *text.Message + + var resendNode *node.Node + + switch f.GetFlowName() { + case flow.RecoveryFlow: + route = recovery.RouteSubmitFlow + codeMetaLabel = text.NewInfoNodeLabelRecoveryCode() + message = text.NewRecoveryEmailWithCodeSent() + + resendNode = node.NewInputField("email", nil, node.CodeGroup, node.InputAttributeTypeEmail, node.WithRequiredInputAttribute). + WithMetaLabel(text.NewInfoNodeResendOTP()) + case flow.VerificationFlow: + route = verification.RouteSubmitFlow + codeMetaLabel = text.NewInfoNodeLabelVerificationCode() + message = text.NewVerificationEmailWithCodeSent() + + case flow.LoginFlow: + route = login.RouteSubmitFlow + codeMetaLabel = text.NewInfoNodeLabelLoginCode() + message = text.NewLoginEmailWithCodeSent() + + // preserve the login identifier that was submitted + // so we can retry the code flow with the same data + for _, n := range f.GetUI().Nodes { + if n.Group == node.DefaultGroup { + // we don't need the user to change the values here + // for better UX let's make them disabled + // when there are errors we won't hide the fields + if len(n.Messages) == 0 { + if input, ok := n.Attributes.(*node.InputAttributes); ok { + input.Type = "hidden" + n.Attributes = input } - freshNodes = append(freshNodes, n) } + freshNodes = append(freshNodes, n) } + } - resendNode = node.NewInputField("resend", "code", node.CodeGroup, node.InputAttributeTypeSubmit). - WithMetaLabel(text.NewInfoNodeResendOTP()) + resendNode = node.NewInputField("resend", "code", node.CodeGroup, node.InputAttributeTypeSubmit). + WithMetaLabel(text.NewInfoNodeResendOTP()) - case flow.RegistrationFlow: - route = registration.RouteSubmitFlow - codeMetaLabel = text.NewInfoNodeLabelRegistrationCode() - message = text.NewRegistrationEmailWithCodeSent() + case flow.RegistrationFlow: + route = registration.RouteSubmitFlow + codeMetaLabel = text.NewInfoNodeLabelRegistrationCode() + message = text.NewRegistrationEmailWithCodeSent() - // in the registration flow we need to preserve the trait fields that were submitted - // so we can retry the code flow with the same data - for _, n := range f.GetUI().Nodes { - if t, ok := n.Attributes.(*node.InputAttributes); ok && t.Type == node.InputAttributeTypeSubmit { - continue - } + // in the registration flow we need to preserve the trait fields that were submitted + // so we can retry the code flow with the same data + for _, n := range f.GetUI().Nodes { + if t, ok := n.Attributes.(*node.InputAttributes); ok && t.Type == node.InputAttributeTypeSubmit { + continue + } - if n.Group == node.DefaultGroup { - // we don't need the user to change the values here - // for better UX let's make them disabled - // when there are errors we won't hide the fields - if len(n.Messages) == 0 { - if input, ok := n.Attributes.(*node.InputAttributes); ok { - input.Type = "hidden" - n.Attributes = input - } + if n.Group == node.DefaultGroup { + // we don't need the user to change the values here + // for better UX let's make them disabled + // when there are errors we won't hide the fields + if len(n.Messages) == 0 { + if input, ok := n.Attributes.(*node.InputAttributes); ok { + input.Type = "hidden" + n.Attributes = input } - freshNodes = append(freshNodes, n) } + freshNodes = append(freshNodes, n) } - - resendNode = node.NewInputField("resend", "code", node.CodeGroup, node.InputAttributeTypeSubmit). - WithMetaLabel(text.NewInfoNodeResendOTP()) - default: - return errors.WithStack(herodot.ErrBadRequest.WithReason("received an unexpected flow type")) } - // Hidden field Required for the re-send code button - // !!important!!: this field must be appended before the code submit button since upsert will replace the first node with the same name - freshNodes.Upsert( - node.NewInputField("method", s.NodeGroup(), node.CodeGroup, node.InputAttributeTypeHidden), - ) - - // code input field - freshNodes.Upsert(node.NewInputField("code", nil, node.CodeGroup, node.InputAttributeTypeText, node.WithRequiredInputAttribute). - WithMetaLabel(codeMetaLabel)) - - // code submit button - freshNodes. - Append(node.NewInputField("method", s.ID(), node.CodeGroup, node.InputAttributeTypeSubmit). - WithMetaLabel(text.NewInfoNodeLabelSubmit())) + resendNode = node.NewInputField("resend", "code", node.CodeGroup, node.InputAttributeTypeSubmit). + WithMetaLabel(text.NewInfoNodeResendOTP()) + default: + return errors.WithStack(herodot.ErrBadRequest.WithReason("received an unexpected flow type")) + } - if resendNode != nil { - freshNodes.Append(resendNode) - } + // Hidden field Required for the re-send code button + // !!important!!: this field must be appended before the code submit button since upsert will replace the first node with the same name + freshNodes.Upsert( + node.NewInputField("method", s.NodeGroup(), node.CodeGroup, node.InputAttributeTypeHidden), + ) - f.GetUI().Nodes = freshNodes + // code input field + freshNodes.Upsert(node.NewInputField("code", nil, node.CodeGroup, node.InputAttributeTypeText, node.WithRequiredInputAttribute). + WithMetaLabel(codeMetaLabel)) - f.GetUI().Method = "POST" - f.GetUI().Action = flow.AppendFlowTo(urlx.AppendPaths(s.deps.Config().SelfPublicURL(r.Context()), route), f.GetID()).String() + // code submit button + freshNodes. + Append(node.NewInputField("method", s.ID(), node.CodeGroup, node.InputAttributeTypeSubmit). + WithMetaLabel(text.NewInfoNodeLabelSubmit())) - // Set the request's CSRF token - if f.GetType() == flow.TypeBrowser { - f.GetUI().SetCSRF(s.deps.GenerateCSRFToken(r)) - } + if resendNode != nil { + freshNodes.Append(resendNode) + } - f.GetUI().Messages.Set(message) + f.GetUI().Nodes = freshNodes - case flow.StatePassedChallenge: - fallthrough - default: - return errors.WithStack(herodot.ErrBadRequest.WithReason("received an unexpected flow state")) - } + f.GetUI().Method = "POST" + f.GetUI().Action = flow.AppendFlowTo(urlx.AppendPaths(s.deps.Config().SelfPublicURL(ctx), route), f.GetID()).String() - // no matter the flow type or state we need to set the CSRF token - if f.GetType() == flow.TypeBrowser { - f.GetUI().SetCSRF(s.deps.GenerateCSRFToken(r)) - } + f.GetUI().Messages.Set(message) return nil } @@ -361,3 +416,29 @@ const CodeLength = 6 func GenerateCode() string { return randx.MustString(CodeLength, randx.Numeric) } + +// MaskAddress masks an address by replacing the middle part with asterisks. +// +// If the address contains an @, the part before the @ is masked by taking the first 2 characters and adding 4 * +// (if the part before the @ is less than 2 characters the full value is used). +// Otherwise, the first 3 characters and last two characters are taken and 4 * are added in between. +// +// Examples: +// - foo@bar -> fo****@bar +// - foobar -> fo****ar +// - f@bar -> f@bar +// - fo@bar -> fo****@bar +// - +12345678910 -> +12****10 +func MaskAddress(input string) string { + if strings.Contains(input, "@") { + pre, post, found := strings.Cut(input, "@") + if !found || len(pre) < 2 { + return input + } + return pre[:2] + strings.Repeat("*", 4) + "@" + post + } + if len(input) < 6 { + return input + } + return input[:3] + strings.Repeat("*", 4) + input[len(input)-2:] +} diff --git a/selfservice/strategy/code/strategy_login.go b/selfservice/strategy/code/strategy_login.go index 1a0170d36648..5f7d04e395da 100644 --- a/selfservice/strategy/code/strategy_login.go +++ b/selfservice/strategy/code/strategy_login.go @@ -11,12 +11,13 @@ import ( "github.com/ory/x/sqlcon" - "github.com/gofrs/uuid" "github.com/pkg/errors" "github.com/ory/herodot" "github.com/ory/x/otelx" + "github.com/samber/lo" + "github.com/ory/kratos/identity" "github.com/ory/kratos/schema" "github.com/ory/kratos/selfservice/flow" @@ -60,7 +61,16 @@ type updateLoginFlowWithCodeMethod struct { func (s *Strategy) RegisterLoginRoutes(*x.RouterPublic) {} -func (s *Strategy) CompletedAuthenticationMethod(ctx context.Context) session.AuthenticationMethod { +func (s *Strategy) CompletedAuthenticationMethod(ctx context.Context, amr session.AuthenticationMethods) session.AuthenticationMethod { + aal1Satisfied := lo.ContainsBy(amr, func(am session.AuthenticationMethod) bool { + return am.Method != identity.CredentialsTypeCodeAuth && am.AAL == identity.AuthenticatorAssuranceLevel1 + }) + if aal1Satisfied { + return session.AuthenticationMethod{ + Method: identity.CredentialsTypeCodeAuth, + AAL: identity.AuthenticatorAssuranceLevel2, + } + } return session.AuthenticationMethod{ Method: identity.CredentialsTypeCodeAuth, AAL: identity.AuthenticatorAssuranceLevel1, @@ -97,9 +107,6 @@ func (s *Strategy) HandleLoginError(r *http.Request, f *login.Flow, body *update } func (s *Strategy) PopulateLoginMethod(r *http.Request, requestedAAL identity.AuthenticatorAssuranceLevel, lf *login.Flow) error { - if requestedAAL > identity.AuthenticatorAssuranceLevel1 { - return nil - } return s.PopulateMethod(r, lf) } @@ -136,7 +143,7 @@ func (s *Strategy) findIdentityByIdentifier(ctx context.Context, identifier stri return id, false, nil } -func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, _ uuid.UUID) (_ *identity.Identity, err error) { +func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, sess *session.Session) (_ *identity.Identity, err error) { ctx, span := s.deps.Tracer(r.Context()).Tracer().Start(r.Context(), "selfservice.strategy.code.strategy.Login") defer otelx.End(span, &err) @@ -144,7 +151,15 @@ func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, return nil, err } - if err := login.CheckAAL(f, identity.AuthenticatorAssuranceLevel1); err != nil { + var aal identity.AuthenticatorAssuranceLevel + + if s.deps.Config().SelfServiceCodeStrategy(ctx).PasswordlessEnabled { + aal = identity.AuthenticatorAssuranceLevel1 + } else if s.deps.Config().SelfServiceCodeStrategy(ctx).MFAEnabled { + aal = identity.AuthenticatorAssuranceLevel2 + } + + if err := login.CheckAAL(f, aal); err != nil { return nil, err } @@ -167,7 +182,7 @@ func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, switch f.GetState() { case flow.StateChooseMethod: - if err := s.loginSendEmail(ctx, w, r, f, &p); err != nil { + if err := s.loginSendCode(ctx, w, r, f, &p, sess); err != nil { return nil, s.HandleLoginError(r, f, &p, err) } return nil, nil @@ -184,8 +199,8 @@ func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, return nil, s.HandleLoginError(r, f, &p, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Unexpected flow state: %s", f.GetState()))) } -func (s *Strategy) loginSendEmail(ctx context.Context, w http.ResponseWriter, r *http.Request, f *login.Flow, p *updateLoginFlowWithCodeMethod) (err error) { - ctx, span := s.deps.Tracer(ctx).Tracer().Start(ctx, "selfservice.strategy.code.strategy.loginSendEmail") +func (s *Strategy) loginSendCode(ctx context.Context, w http.ResponseWriter, r *http.Request, f *login.Flow, p *updateLoginFlowWithCodeMethod, sess *session.Session) (err error) { + ctx, span := s.deps.Tracer(ctx).Tracer().Start(ctx, "selfservice.strategy.code.strategy.loginSendCode") defer otelx.End(span, &err) if len(p.Identifier) == 0 { @@ -194,10 +209,30 @@ func (s *Strategy) loginSendEmail(ctx context.Context, w http.ResponseWriter, r p.Identifier = maybeNormalizeEmail(p.Identifier) - // Step 1: Get the identity - i, _, err := s.findIdentityByIdentifier(ctx, p.Identifier) - if err != nil { - return err + var addresses []Address + var i *identity.Identity + if f.RequestedAAL > identity.AuthenticatorAssuranceLevel1 { + address, found := lo.Find(sess.Identity.VerifiableAddresses, func(va identity.VerifiableAddress) bool { + return va.Value == p.Identifier + }) + if !found { + return errors.WithStack(schema.NewUnknownAddressError()) + } + i = sess.Identity + addresses = []Address{{ + To: address.Value, + Via: address.Via, + }} + } else { + // Step 1: Get the identity + i, _, err = s.findIdentityByIdentifier(ctx, p.Identifier) + if err != nil { + return err + } + addresses = []Address{{ + To: p.Identifier, + Via: identity.CodeAddressType(identity.AddressTypeEmail), + }} } // Step 2: Delete any previous login codes for this flow ID @@ -205,11 +240,6 @@ func (s *Strategy) loginSendEmail(ctx context.Context, w http.ResponseWriter, r return errors.WithStack(err) } - addresses := []Address{{ - To: p.Identifier, - Via: identity.CodeAddressType(identity.AddressTypeEmail), - }} - // kratos only supports `email` identifiers at the moment with the code method // this is validated in the identity validation step above if err := s.deps.CodeSender().SendCode(ctx, f, i, addresses...); err != nil { diff --git a/selfservice/strategy/code/strategy_login_test.go b/selfservice/strategy/code/strategy_login_test.go index cda8ef3c05a9..06d811362978 100644 --- a/selfservice/strategy/code/strategy_login_test.go +++ b/selfservice/strategy/code/strategy_login_test.go @@ -12,6 +12,8 @@ import ( "net/url" "testing" + "github.com/ory/x/ioutilx" + "github.com/ory/x/snapshotx" "github.com/ory/x/sqlcon" "github.com/ory/x/stringsx" @@ -25,6 +27,7 @@ import ( oryClient "github.com/ory/kratos/internal/httpclient" "github.com/ory/kratos/internal/testhelpers" "github.com/ory/kratos/session" + "github.com/ory/kratos/text" "github.com/ory/kratos/x" "github.com/ory/x/sqlxx" ) @@ -33,7 +36,7 @@ func TestLoginCodeStrategy(t *testing.T) { ctx := context.Background() conf, reg := internal.NewFastRegistryWithMocks(t) testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/code.identity.schema.json") - conf.MustSet(ctx, fmt.Sprintf("%s.%s.enabled", config.ViperKeySelfServiceStrategyConfig, identity.CredentialsTypeCodeAuth.String()), false) + conf.MustSet(ctx, fmt.Sprintf("%s.%s.enabled", config.ViperKeySelfServiceStrategyConfig, identity.CredentialsTypeCodeAuth.String()), true) conf.MustSet(ctx, fmt.Sprintf("%s.%s.passwordless_enabled", config.ViperKeySelfServiceStrategyConfig, identity.CredentialsTypeCodeAuth.String()), true) conf.MustSet(ctx, config.ViperKeySelfServiceBrowserDefaultReturnTo, "https://www.ory.sh") conf.MustSet(ctx, config.ViperKeyURLsAllowedReturnToDomains, []string{"https://www.ory.sh"}) @@ -85,6 +88,7 @@ func TestLoginCodeStrategy(t *testing.T) { loginCode string identityEmail string testServer *httptest.Server + body string } type ApiType string @@ -161,6 +165,7 @@ func TestLoginCodeStrategy(t *testing.T) { submitAssertion(t, s, body, resp) return s } + s.body = body if mustHaveSession { req, err := http.NewRequest("GET", s.testServer.URL+session.RouteWhoami, nil) @@ -173,13 +178,14 @@ func TestLoginCodeStrategy(t *testing.T) { resp, err = s.client.Do(req) require.NoError(t, err) require.EqualValues(t, http.StatusOK, resp.StatusCode) + body = string(ioutilx.MustReadAll(resp.Body)) } else { // SPAs need to be informed that the login has not yet completed using status 400. // Browser clients will redirect back to the login URL. if apiType == ApiTypeBrowser { - require.EqualValues(t, http.StatusOK, resp.StatusCode) + require.EqualValues(t, http.StatusOK, resp.StatusCode, "%s", body) } else { - require.EqualValues(t, http.StatusBadRequest, resp.StatusCode) + require.EqualValues(t, http.StatusBadRequest, resp.StatusCode, "%s", body) } } @@ -570,50 +576,167 @@ func TestLoginCodeStrategy(t *testing.T) { require.True(t, va.Verified) }) - t.Run("case=should not populate on 2FA request", func(t *testing.T) { - if tc.apiType == ApiTypeNative { - t.Skip("skipping test since it is not applicable to native clients") - } - + t.Run("suite=mfa", func(t *testing.T) { ctx := context.Background() + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.passwordless_enabled", false) + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.mfa_enabled", true) + t.Cleanup(func() { + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.passwordless_enabled", true) + conf.MustSet(ctx, config.ViperKeySelfServiceStrategyConfig+".code.mfa_enabled", false) + }) - // enable webauthn 2FA method - conf.MustSet(ctx, fmt.Sprintf("%s.%s.enabled", config.ViperKeySelfServiceStrategyConfig, "webauthn"), true) - conf.MustSet(ctx, config.ViperKeySessionWhoAmIAAL, config.HighestAvailableAAL) + t.Run("case=should be able to get AAL2 session", func(t *testing.T) { + identity := createIdentity(ctx, t, false) + var cl *http.Client + var f *oryClient.LoginFlow + if tc.apiType == ApiTypeNative { + cl = testhelpers.NewHTTPClientWithIdentitySessionToken(t, reg, identity) + f = testhelpers.InitializeLoginFlowViaAPI(t, cl, public, false, testhelpers.InitFlowWithAAL("aal2"), testhelpers.InitFlowWithVia("email")) + } else { + cl = testhelpers.NewHTTPClientWithIdentitySessionCookieLocalhost(t, reg, identity) + f = testhelpers.InitializeLoginFlowViaBrowser(t, cl, public, false, tc.apiType == ApiTypeSPA, false, false, testhelpers.InitFlowWithAAL("aal2"), testhelpers.InitFlowWithVia("email")) + } - t.Cleanup(func() { - conf.MustSet(ctx, fmt.Sprintf("%s.%s.enabled", config.ViperKeySelfServiceStrategyConfig, "webauthn"), false) - conf.MustSet(ctx, config.ViperKeySessionWhoAmIAAL, "aal1") + body, err := json.Marshal(f) + require.NoError(t, err) + require.Len(t, gjson.GetBytes(body, "ui.nodes.#(group==code)").Array(), 1) + require.Len(t, gjson.GetBytes(body, "ui.messages").Array(), 1, "%s", body) + require.EqualValues(t, gjson.GetBytes(body, "ui.messages.0.id").Int(), text.InfoSelfServiceLoginMFA, "%s", body) + + s := &state{ + flowID: f.GetId(), + identity: identity, + client: cl, + testServer: public, + identityEmail: gjson.Get(identity.Traits.String(), "email").String(), + } + s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { + v.Set("identifier", s.identityEmail) + }, true, nil) + + message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Login to your account") + assert.Contains(t, message.Body, "please login to your account by entering the following code") + loginCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) + assert.NotEmpty(t, loginCode) + + s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { + v.Set("code", loginCode) + }, true, nil) + + testhelpers.EnsureAAL(t, cl, public, "aal2", "code") }) + t.Run("case=cannot use different identifier", func(t *testing.T) { + identity := createIdentity(ctx, t, false) + var cl *http.Client + var f *oryClient.LoginFlow + if tc.apiType == ApiTypeNative { + cl = testhelpers.NewHTTPClientWithIdentitySessionToken(t, reg, identity) + f = testhelpers.InitializeLoginFlowViaAPI(t, cl, public, false, testhelpers.InitFlowWithAAL("aal2"), testhelpers.InitFlowWithVia("email")) + } else { + cl = testhelpers.NewHTTPClientWithIdentitySessionCookieLocalhost(t, reg, identity) + f = testhelpers.InitializeLoginFlowViaBrowser(t, cl, public, false, tc.apiType == ApiTypeSPA, false, false, testhelpers.InitFlowWithAAL("aal2"), testhelpers.InitFlowWithVia("email")) + } - s := createLoginFlow(ctx, t, public, tc.apiType, false) + body, err := json.Marshal(f) + require.NoError(t, err) + require.Len(t, gjson.GetBytes(body, "ui.nodes.#(group==code)").Array(), 1) + require.Len(t, gjson.GetBytes(body, "ui.messages").Array(), 1, "%s", body) + require.EqualValues(t, gjson.GetBytes(body, "ui.messages.0.id").Int(), text.InfoSelfServiceLoginMFA, "%s", body) + + s := &state{ + flowID: f.GetId(), + identity: identity, + client: cl, + testServer: public, + identityEmail: gjson.Get(identity.Traits.String(), "email").String(), + } + email := testhelpers.RandomEmail() + s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { + v.Set("identifier", email) + }, true, nil) - // submit email - s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { - v.Set("identifier", s.identityEmail) - }, false, nil) + require.Equal(t, "The address you entered does not match any known addresses in the current account.", gjson.Get(s.body, "ui.messages.0.text").String(), "%s", body) + }) - message := testhelpers.CourierExpectMessage(ctx, t, reg, s.identityEmail, "Login to your account") - assert.Contains(t, message.Body, "please login to your account by entering the following code") + t.Run("case=verify initial payload", func(t *testing.T) { + fixedEmail := fmt.Sprintf("fixed_mfa_test_%s@ory.sh", tc.apiType) + identity := createIdentity(ctx, t, false, fixedEmail) + var cl *http.Client + var f *oryClient.LoginFlow + if tc.apiType == ApiTypeNative { + cl = testhelpers.NewHTTPClientWithIdentitySessionToken(t, reg, identity) + f = testhelpers.InitializeLoginFlowViaAPI(t, cl, public, false, testhelpers.InitFlowWithAAL("aal2"), testhelpers.InitFlowWithVia("email_1")) + } else { + cl = testhelpers.NewHTTPClientWithIdentitySessionCookieLocalhost(t, reg, identity) + f = testhelpers.InitializeLoginFlowViaBrowser(t, cl, public, false, tc.apiType == ApiTypeSPA, false, false, testhelpers.InitFlowWithAAL("aal2"), testhelpers.InitFlowWithVia("email_1")) + } - loginCode := testhelpers.CourierExpectCodeInMessage(t, message, 1) - assert.NotEmpty(t, loginCode) + body, err := json.Marshal(f) + require.NoError(t, err) + snapshotx.SnapshotTJSON(t, body, snapshotx.ExceptPaths("ui.nodes.0.attributes.value", "id", "created_at", "expires_at", "updated_at", "issued_at", "request_url", "ui.action")) + }) - // 3. Submit OTP - s = submitLogin(ctx, t, s, tc.apiType, func(v *url.Values) { - v.Set("code", loginCode) - }, false, func(t *testing.T, s *state, body string, res *http.Response) { - if tc.apiType == ApiTypeSPA { - require.EqualValues(t, http.StatusOK, res.StatusCode) + t.Run("case=using a non existing identity trait results in an error", func(t *testing.T) { + identity := createIdentity(ctx, t, false) + var cl *http.Client + var res *http.Response + var err error + if tc.apiType == ApiTypeNative { + cl = testhelpers.NewHTTPClientWithIdentitySessionToken(t, reg, identity) + res, err = cl.Get(public.URL + "/self-service/login/api?aal=aal2&via=doesnt_exist") } else { - require.EqualValues(t, http.StatusOK, res.StatusCode) + cl = testhelpers.NewHTTPClientWithIdentitySessionCookieLocalhost(t, reg, identity) + res, err = cl.Get(public.URL + "/self-service/login/browser?aal=aal2&via=doesnt_exist") } + require.NoError(t, err) + + body := ioutilx.MustReadAll(res.Body) + if tc.apiType == ApiTypeNative { + body = []byte(gjson.GetBytes(body, "error").Raw) + } + require.Equal(t, "Trait does not exist in identity schema", gjson.GetBytes(body, "reason").String(), "%s", body) }) - clientInit := testhelpers.InitializeLoginFlowViaBrowser(t, s.client, public, false, tc.apiType == ApiTypeSPA, false, false, testhelpers.InitFlowWithAAL("aal2")) - body, err := json.Marshal(clientInit) - require.NoError(t, err) - require.Len(t, gjson.GetBytes(body, "ui.nodes.#(group==code)").Array(), 0, "should not populate code field on 2fa request") + t.Run("case=missing via parameter results results in an error", func(t *testing.T) { + identity := createIdentity(ctx, t, false) + var cl *http.Client + var res *http.Response + var err error + if tc.apiType == ApiTypeNative { + cl = testhelpers.NewHTTPClientWithIdentitySessionToken(t, reg, identity) + res, err = cl.Get(public.URL + "/self-service/login/api?aal=aal2") + } else { + cl = testhelpers.NewHTTPClientWithIdentitySessionCookieLocalhost(t, reg, identity) + res, err = cl.Get(public.URL + "/self-service/login/browser?aal=aal2") + } + require.NoError(t, err) + + body := ioutilx.MustReadAll(res.Body) + if tc.apiType == ApiTypeNative { + body = []byte(gjson.GetBytes(body, "error").Raw) + } + require.Equal(t, "AAL2 login via code requires the `via` query parameter", gjson.GetBytes(body, "reason").String(), "%s", body) + }) + t.Run("case=unset trait in identity should lead to an error", func(t *testing.T) { + identity := createIdentity(ctx, t, false) + var cl *http.Client + var res *http.Response + var err error + if tc.apiType == ApiTypeNative { + cl = testhelpers.NewHTTPClientWithIdentitySessionToken(t, reg, identity) + res, err = cl.Get(public.URL + "/self-service/login/api?aal=aal2&via=email_1") + } else { + cl = testhelpers.NewHTTPClientWithIdentitySessionCookieLocalhost(t, reg, identity) + res, err = cl.Get(public.URL + "/self-service/login/browser?aal=aal2&via=email_1") + } + require.NoError(t, err) + + body := ioutilx.MustReadAll(res.Body) + if tc.apiType == ApiTypeNative { + body = []byte(gjson.GetBytes(body, "error").Raw) + } + require.Equal(t, "No value found for trait email_1 in the current identity", gjson.GetBytes(body, "reason").String(), "%s", body) + }) }) }) } diff --git a/selfservice/strategy/code/strategy_registration_test.go b/selfservice/strategy/code/strategy_registration_test.go index e591e627f5ef..1ca150b5f0ba 100644 --- a/selfservice/strategy/code/strategy_registration_test.go +++ b/selfservice/strategy/code/strategy_registration_test.go @@ -96,7 +96,7 @@ func TestRegistrationCodeStrategy(t *testing.T) { conf, reg := internal.NewFastRegistryWithMocks(t) testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/code.identity.schema.json") conf.MustSet(ctx, fmt.Sprintf("%s.%s.enabled", config.ViperKeySelfServiceStrategyConfig, identity.CredentialsTypePassword.String()), false) - conf.MustSet(ctx, fmt.Sprintf("%s.%s.enabled", config.ViperKeySelfServiceStrategyConfig, identity.CredentialsTypeCodeAuth.String()), false) + conf.MustSet(ctx, fmt.Sprintf("%s.%s.enabled", config.ViperKeySelfServiceStrategyConfig, identity.CredentialsTypeCodeAuth.String()), true) conf.MustSet(ctx, fmt.Sprintf("%s.%s.passwordless_enabled", config.ViperKeySelfServiceStrategyConfig, identity.CredentialsTypeCodeAuth), true) conf.MustSet(ctx, config.ViperKeySelfServiceBrowserDefaultReturnTo, "https://www.ory.sh") conf.MustSet(ctx, config.ViperKeyURLsAllowedReturnToDomains, []string{"https://www.ory.sh"}) @@ -176,6 +176,7 @@ func TestRegistrationCodeStrategy(t *testing.T) { submitAssertion(ctx, t, s, body, resp) return s } + t.Logf("%v", body) if apiType == ApiTypeBrowser { require.EqualValues(t, http.StatusOK, resp.StatusCode) @@ -532,7 +533,7 @@ func TestRegistrationCodeStrategy(t *testing.T) { require.Contains(t, gjson.GetBytes(body, "ui.messages").String(), "Could not find any login identifiers") } else { - require.Equal(t, http.StatusBadRequest, resp.StatusCode) + require.Equal(t, http.StatusBadRequest, resp.StatusCode, "%v", body) require.Contains(t, gjson.Get(body, "ui.messages").String(), "Could not find any login identifiers") } }) diff --git a/selfservice/strategy/code/strategy_test.go b/selfservice/strategy/code/strategy_test.go index 634605cba3f3..4561a280fb96 100644 --- a/selfservice/strategy/code/strategy_test.go +++ b/selfservice/strategy/code/strategy_test.go @@ -38,3 +38,39 @@ func TestGenerateCode(t *testing.T) { assert.Len(t, stringslice.Unique(codes), len(codes)) } + +func TestMaskAddress(t *testing.T) { + for _, tc := range []struct { + address string + expected string + }{ + { + address: "a", + expected: "a", + }, + { + address: "ab@cd", + expected: "ab****@cd", + }, + { + address: "fixed@ory.sh", + expected: "fi****@ory.sh", + }, + { + address: "f@ory.sh", + expected: "f@ory.sh", + }, + { + address: "+12345678910", + expected: "+12****10", + }, + { + address: "+123456", + expected: "+12****56", + }, + } { + t.Run("case="+tc.address, func(t *testing.T) { + assert.Equal(t, tc.expected, code.MaskAddress(tc.address)) + }) + } +} diff --git a/selfservice/strategy/lookup/login.go b/selfservice/strategy/lookup/login.go index 75edc2181059..2eda9b5796c8 100644 --- a/selfservice/strategy/lookup/login.go +++ b/selfservice/strategy/lookup/login.go @@ -8,8 +8,6 @@ import ( "net/http" "time" - "github.com/gofrs/uuid" - "github.com/ory/x/sqlcon" "github.com/ory/x/sqlxx" @@ -21,6 +19,7 @@ import ( "github.com/ory/kratos/schema" "github.com/ory/kratos/selfservice/flow" "github.com/ory/kratos/selfservice/flow/login" + "github.com/ory/kratos/session" "github.com/ory/kratos/text" "github.com/ory/kratos/ui/node" "github.com/ory/kratos/x" @@ -89,7 +88,7 @@ type updateLoginFlowWithLookupSecretMethod struct { Code string `json:"lookup_secret"` } -func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, identityID uuid.UUID) (i *identity.Identity, err error) { +func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, sess *session.Session) (i *identity.Identity, err error) { if err := login.CheckAAL(f, identity.AuthenticatorAssuranceLevel2); err != nil { return nil, err } @@ -110,7 +109,7 @@ func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, return nil, s.handleLoginError(r, f, err) } - i, c, err := s.d.PrivilegedIdentityPool().FindByCredentialsIdentifier(r.Context(), s.ID(), identityID.String()) + i, c, err := s.d.PrivilegedIdentityPool().FindByCredentialsIdentifier(r.Context(), s.ID(), sess.IdentityID.String()) if errors.Is(err, sqlcon.ErrNoRows) { return nil, s.handleLoginError(r, f, errors.WithStack(schema.NewNoLookupDefined())) } else if err != nil { @@ -138,7 +137,7 @@ func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, return nil, s.handleLoginError(r, f, errors.WithStack(schema.NewErrorValidationLookupInvalid())) } - toUpdate, err := s.d.PrivilegedIdentityPool().GetIdentityConfidential(r.Context(), identityID) + toUpdate, err := s.d.PrivilegedIdentityPool().GetIdentityConfidential(r.Context(), sess.IdentityID) if err != nil { return nil, err } diff --git a/selfservice/strategy/lookup/strategy.go b/selfservice/strategy/lookup/strategy.go index 13c233913f18..e8f12cac9948 100644 --- a/selfservice/strategy/lookup/strategy.go +++ b/selfservice/strategy/lookup/strategy.go @@ -24,8 +24,10 @@ import ( ) // var _ login.Strategy = new(Strategy) -var _ settings.Strategy = new(Strategy) -var _ identity.ActiveCredentialsCounter = new(Strategy) +var ( + _ settings.Strategy = new(Strategy) + _ identity.ActiveCredentialsCounter = new(Strategy) +) type lookupStrategyDependencies interface { x.LoggingProvider @@ -104,7 +106,7 @@ func (s *Strategy) NodeGroup() node.UiNodeGroup { return node.LookupGroup } -func (s *Strategy) CompletedAuthenticationMethod(ctx context.Context) session.AuthenticationMethod { +func (s *Strategy) CompletedAuthenticationMethod(ctx context.Context, _ session.AuthenticationMethods) session.AuthenticationMethod { return session.AuthenticationMethod{ Method: s.ID(), AAL: identity.AuthenticatorAssuranceLevel2, diff --git a/selfservice/strategy/oidc/strategy.go b/selfservice/strategy/oidc/strategy.go index e67a5826b57e..4f5848e8a431 100644 --- a/selfservice/strategy/oidc/strategy.go +++ b/selfservice/strategy/oidc/strategy.go @@ -663,7 +663,7 @@ func (s *Strategy) NodeGroup() node.UiNodeGroup { return node.OpenIDConnectGroup } -func (s *Strategy) CompletedAuthenticationMethod(ctx context.Context) session.AuthenticationMethod { +func (s *Strategy) CompletedAuthenticationMethod(ctx context.Context, _ session.AuthenticationMethods) session.AuthenticationMethod { return session.AuthenticationMethod{ Method: s.ID(), AAL: identity.AuthenticatorAssuranceLevel1, diff --git a/selfservice/strategy/oidc/strategy_login.go b/selfservice/strategy/oidc/strategy_login.go index a3048df1e15b..641b3d42b977 100644 --- a/selfservice/strategy/oidc/strategy_login.go +++ b/selfservice/strategy/oidc/strategy_login.go @@ -13,8 +13,6 @@ import ( "github.com/julienschmidt/httprouter" "golang.org/x/oauth2" - "github.com/gofrs/uuid" - "github.com/ory/kratos/session" "github.com/ory/kratos/ui/node" @@ -181,7 +179,7 @@ func (s *Strategy) processLogin(w http.ResponseWriter, r *http.Request, loginFlo return nil, s.handleError(w, r, loginFlow, provider.Config().ID, nil, errors.WithStack(herodot.ErrInternalServerError.WithReason("Unable to find matching OpenID Connect Credentials.").WithDebugf(`Unable to find credentials that match the given provider "%s" and subject "%s".`, provider.Config().ID, claims.Subject))) } -func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, _ uuid.UUID) (i *identity.Identity, err error) { +func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, _ *session.Session) (i *identity.Identity, err error) { ctx, span := s.d.Tracer(r.Context()).Tracer().Start(r.Context(), "selfservice.strategy.oidc.strategy.Login") defer span.End() diff --git a/selfservice/strategy/password/login.go b/selfservice/strategy/password/login.go index 5c9ed653872d..706a4fcab0f0 100644 --- a/selfservice/strategy/password/login.go +++ b/selfservice/strategy/password/login.go @@ -11,6 +11,7 @@ import ( "time" "github.com/ory/kratos/selfservice/flowhelpers" + "github.com/ory/kratos/session" "github.com/ory/x/stringsx" @@ -46,7 +47,7 @@ func (s *Strategy) handleLoginError(w http.ResponseWriter, r *http.Request, f *l return err } -func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, identityID uuid.UUID) (i *identity.Identity, err error) { +func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, _ *session.Session) (i *identity.Identity, err error) { if err := login.CheckAAL(f, identity.AuthenticatorAssuranceLevel1); err != nil { return nil, err } diff --git a/selfservice/strategy/password/strategy.go b/selfservice/strategy/password/strategy.go index bb750bc9ef80..911ad619cd15 100644 --- a/selfservice/strategy/password/strategy.go +++ b/selfservice/strategy/password/strategy.go @@ -109,7 +109,7 @@ func (s *Strategy) ID() identity.CredentialsType { return identity.CredentialsTypePassword } -func (s *Strategy) CompletedAuthenticationMethod(ctx context.Context) session.AuthenticationMethod { +func (s *Strategy) CompletedAuthenticationMethod(ctx context.Context, _ session.AuthenticationMethods) session.AuthenticationMethod { return session.AuthenticationMethod{ Method: s.ID(), AAL: identity.AuthenticatorAssuranceLevel1, diff --git a/selfservice/strategy/totp/login.go b/selfservice/strategy/totp/login.go index bc9816d265f3..1eaa5aeedac7 100644 --- a/selfservice/strategy/totp/login.go +++ b/selfservice/strategy/totp/login.go @@ -7,7 +7,6 @@ import ( "encoding/json" "net/http" - "github.com/gofrs/uuid" "github.com/pkg/errors" "github.com/pquerna/otp" "github.com/pquerna/otp/totp" @@ -17,6 +16,7 @@ import ( "github.com/ory/kratos/schema" "github.com/ory/kratos/selfservice/flow" "github.com/ory/kratos/selfservice/flow/login" + "github.com/ory/kratos/session" "github.com/ory/kratos/text" "github.com/ory/kratos/ui/node" "github.com/ory/kratos/x" @@ -85,7 +85,7 @@ type updateLoginFlowWithTotpMethod struct { TOTPCode string `json:"totp_code"` } -func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, identityID uuid.UUID) (i *identity.Identity, err error) { +func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, sess *session.Session) (i *identity.Identity, err error) { if err := login.CheckAAL(f, identity.AuthenticatorAssuranceLevel2); err != nil { return nil, err } @@ -106,7 +106,7 @@ func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, return nil, s.handleLoginError(r, f, err) } - i, c, err := s.d.PrivilegedIdentityPool().FindByCredentialsIdentifier(r.Context(), s.ID(), identityID.String()) + i, c, err := s.d.PrivilegedIdentityPool().FindByCredentialsIdentifier(r.Context(), s.ID(), sess.IdentityID.String()) if err != nil { return nil, s.handleLoginError(r, f, errors.WithStack(schema.NewNoTOTPDeviceRegistered())) } diff --git a/selfservice/strategy/totp/strategy.go b/selfservice/strategy/totp/strategy.go index bcaf09069053..6c3205abd9ac 100644 --- a/selfservice/strategy/totp/strategy.go +++ b/selfservice/strategy/totp/strategy.go @@ -24,9 +24,11 @@ import ( "github.com/ory/x/decoderx" ) -var _ login.Strategy = new(Strategy) -var _ settings.Strategy = new(Strategy) -var _ identity.ActiveCredentialsCounter = new(Strategy) +var ( + _ login.Strategy = new(Strategy) + _ settings.Strategy = new(Strategy) + _ identity.ActiveCredentialsCounter = new(Strategy) +) type totpStrategyDependencies interface { x.LoggingProvider @@ -107,7 +109,7 @@ func (s *Strategy) NodeGroup() node.UiNodeGroup { return node.TOTPGroup } -func (s *Strategy) CompletedAuthenticationMethod(ctx context.Context) session.AuthenticationMethod { +func (s *Strategy) CompletedAuthenticationMethod(ctx context.Context, _ session.AuthenticationMethods) session.AuthenticationMethod { return session.AuthenticationMethod{ Method: s.ID(), AAL: identity.AuthenticatorAssuranceLevel2, diff --git a/selfservice/strategy/webauthn/login.go b/selfservice/strategy/webauthn/login.go index 6b9ee3a154f9..38cdf283b9f1 100644 --- a/selfservice/strategy/webauthn/login.go +++ b/selfservice/strategy/webauthn/login.go @@ -10,6 +10,7 @@ import ( "time" "github.com/ory/kratos/selfservice/flowhelpers" + "github.com/ory/kratos/session" "github.com/gofrs/uuid" @@ -200,7 +201,7 @@ type updateLoginFlowWithWebAuthnMethod struct { Login string `json:"webauthn_login"` } -func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, identityID uuid.UUID) (i *identity.Identity, err error) { +func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, sess *session.Session) (i *identity.Identity, err error) { if f.Type != flow.TypeBrowser { return nil, flow.ErrStrategyNotResponsible } @@ -232,7 +233,7 @@ func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, return s.loginPasswordless(w, r, f, &p) } - return s.loginMultiFactor(w, r, f, identityID, &p) + return s.loginMultiFactor(w, r, f, sess.IdentityID, &p) } func (s *Strategy) loginPasswordless(w http.ResponseWriter, r *http.Request, f *login.Flow, p *updateLoginFlowWithWebAuthnMethod) (i *identity.Identity, err error) { diff --git a/selfservice/strategy/webauthn/strategy.go b/selfservice/strategy/webauthn/strategy.go index aa4529cda620..998490055996 100644 --- a/selfservice/strategy/webauthn/strategy.go +++ b/selfservice/strategy/webauthn/strategy.go @@ -23,9 +23,11 @@ import ( "github.com/ory/x/decoderx" ) -var _ login.Strategy = new(Strategy) -var _ settings.Strategy = new(Strategy) -var _ identity.ActiveCredentialsCounter = new(Strategy) +var ( + _ login.Strategy = new(Strategy) + _ settings.Strategy = new(Strategy) + _ identity.ActiveCredentialsCounter = new(Strategy) +) type webauthnStrategyDependencies interface { x.LoggingProvider @@ -112,7 +114,7 @@ func (s *Strategy) NodeGroup() node.UiNodeGroup { return node.WebAuthnGroup } -func (s *Strategy) CompletedAuthenticationMethod(ctx context.Context) session.AuthenticationMethod { +func (s *Strategy) CompletedAuthenticationMethod(ctx context.Context, _ session.AuthenticationMethods) session.AuthenticationMethod { aal := identity.AuthenticatorAssuranceLevel1 if !s.d.Config().WebAuthnForPasswordless(ctx) { aal = identity.AuthenticatorAssuranceLevel2 diff --git a/selfservice/strategy/webauthn/strategy_test.go b/selfservice/strategy/webauthn/strategy_test.go index 699a36ab6cbb..cc5f6fafb475 100644 --- a/selfservice/strategy/webauthn/strategy_test.go +++ b/selfservice/strategy/webauthn/strategy_test.go @@ -26,13 +26,13 @@ func TestCompletedAuthenticationMethod(t *testing.T) { assert.Equal(t, session.AuthenticationMethod{ Method: strategy.ID(), AAL: identity.AuthenticatorAssuranceLevel2, - }, strategy.CompletedAuthenticationMethod(context.Background())) + }, strategy.CompletedAuthenticationMethod(context.Background(), session.AuthenticationMethods{})) conf.MustSet(ctx, config.ViperKeyWebAuthnPasswordless, true) assert.Equal(t, session.AuthenticationMethod{ Method: strategy.ID(), AAL: identity.AuthenticatorAssuranceLevel1, - }, strategy.CompletedAuthenticationMethod(context.Background())) + }, strategy.CompletedAuthenticationMethod(context.Background(), session.AuthenticationMethods{})) } func TestCountActiveFirstFactorCredentials(t *testing.T) { diff --git a/spec/api.json b/spec/api.json index fcb22f35419e..0ea8c9ef5ba6 100644 --- a/spec/api.json +++ b/spec/api.json @@ -81,9 +81,6 @@ } }, "schemas": { - "CodeAddressType": { - "type": "string" - }, "DefaultError": {}, "Duration": { "description": "A Duration represents the elapsed time between two instants\nas an int64 nanosecond count. The representation limits the\nlargest representable duration to approximately 290 years.", @@ -1010,7 +1007,8 @@ "description": "CredentialsCode represents a one time login/registration code", "properties": { "address_type": { - "$ref": "#/components/schemas/CodeAddressType" + "description": "The type of the address for this code", + "type": "string" }, "used_at": { "$ref": "#/components/schemas/NullTime" @@ -5178,6 +5176,14 @@ "schema": { "type": "string" } + }, + { + "description": "Via should contain the identity's credential the code should be sent to. Only relevant in aal2 flows.", + "in": "query", + "name": "via", + "schema": { + "type": "string" + } } ], "responses": { diff --git a/spec/swagger.json b/spec/swagger.json index 557a69043a5a..ea6f219adb35 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -1563,6 +1563,12 @@ "description": "The URL to return the browser to after the flow was completed.", "name": "return_to", "in": "query" + }, + { + "type": "string", + "description": "Via should contain the identity's credential the code should be sent to. Only relevant in aal2 flows.", + "name": "via", + "in": "query" } ], "responses": { @@ -3195,9 +3201,6 @@ } }, "definitions": { - "CodeAddressType": { - "type": "string" - }, "DefaultError": {}, "Duration": { "description": "A Duration represents the elapsed time between two instants\nas an int64 nanosecond count. The representation limits the\nlargest representable duration to approximately 290 years.", @@ -4090,7 +4093,8 @@ "type": "object", "properties": { "address_type": { - "$ref": "#/definitions/CodeAddressType" + "description": "The type of the address for this code", + "type": "string" }, "used_at": { "$ref": "#/definitions/NullTime" diff --git a/test/e2e/cypress/integration/profiles/code/registration/success.spec.ts b/test/e2e/cypress/integration/profiles/code/registration/success.spec.ts index cdc5e8019219..53fd71ac0f66 100644 --- a/test/e2e/cypress/integration/profiles/code/registration/success.spec.ts +++ b/test/e2e/cypress/integration/profiles/code/registration/success.spec.ts @@ -289,23 +289,9 @@ context("Registration success with code method", () => { cy.get(Selectors[app]["submitRecovery"]).click() - if (app === "mobile") { - cy.get('[data-testid="session-token"]').then((token) => { - cy.getSession({ - expectAal: "aal1", - token: token.text(), - }).then((session) => { - cy.wrap(session).as("session") - }) - }) - - cy.get('[data-testid="session-content"]').should("contain", email) - cy.get('[data-testid="session-token"]').should("not.be.empty") - } else { - cy.getSession({ expectAal: "aal1" }).then((session) => { - cy.wrap(session).as("session") - }) - } + cy.getSession({ expectAal: "aal1" }).then((session) => { + cy.wrap(session).as("session") + }) cy.get("@session").then(({ identity }) => { expect(identity.id).to.not.be.empty diff --git a/test/e2e/cypress/integration/profiles/mfa/code.spec.ts b/test/e2e/cypress/integration/profiles/mfa/code.spec.ts new file mode 100644 index 000000000000..7961aa850de9 --- /dev/null +++ b/test/e2e/cypress/integration/profiles/mfa/code.spec.ts @@ -0,0 +1,104 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +import { gen, website } from "../../../helpers" +import { routes as express } from "../../../helpers/express" +import { routes as react } from "../../../helpers/react" + +context("2FA code", () => { + ;[ + // { + // login: react.login, + // settings: react.settings, + // base: react.base, + // app: "react" as "react", + // profile: "spa", + // }, + { + login: express.login, + settings: express.settings, + base: express.base, + app: "express" as "express", + profile: "mfa", + }, + ].forEach(({ settings, login, profile, app }) => { + describe(`for app ${app}`, () => { + before(() => { + cy.useConfigProfile(profile) + cy.proxy(app) + }) + + let email: string + let password: string + + beforeEach(() => { + email = gen.email() + password = gen.password() + cy.useConfig((builder) => + builder + .longPrivilegedSessionTime() + .useLaxAal() + .enableCode() + .enableCodeMFA(), + ) + + cy.register({ + email, + password, + fields: { "traits.website": website }, + }) + cy.deleteMail() + cy.visit(login + "?aal=aal2&via=email") + }) + + it("should be asked to sign in with 2fa if set up", () => { + cy.get("input[name='identifier']").type(email) + cy.contains("Continue with code").click() + + cy.get("input[name='code']").should("be.visible") + cy.getLoginCodeFromEmail(email).then((code) => { + cy.get("input[name='code']").type(code) + cy.contains("Submit").click() + }) + + cy.getSession({ + expectAal: "aal2", + expectMethods: ["password", "code"], + }) + }) + + it("can't use different email in 2fa request", () => { + cy.get("input[name='identifier']").type(gen.email()) + cy.contains("Continue with code").click() + + cy.get("*[data-testid='ui/message/4010010']").should("be.visible") + cy.get("input[name='code']").should("not.exist") + cy.get("input[name='identifier']").should("be.visible") + + // The current session should be unchanged + cy.getSession({ + expectAal: "aal1", + expectMethods: ["password"], + }) + }) + + it("entering wrong code should not invalidate correct codes", () => { + cy.get("input[name='identifier']").type(email) + cy.contains("Continue with code").click() + + cy.get("input[name='code']").should("be.visible") + cy.get("input[name='code']").type("123456") + cy.contains("Submit").click() + cy.getLoginCodeFromEmail(email).then((code) => { + cy.get("input[name='code']").type(code) + cy.contains("Submit").click() + }) + + cy.getSession({ + expectAal: "aal2", + expectMethods: ["password", "code"], + }) + }) + }) + }) +}) diff --git a/test/e2e/cypress/integration/profiles/oidc-provider/login.spec.ts b/test/e2e/cypress/integration/profiles/oidc-provider/login.spec.ts index 8264047a8f44..861cfd0d2a79 100644 --- a/test/e2e/cypress/integration/profiles/oidc-provider/login.spec.ts +++ b/test/e2e/cypress/integration/profiles/oidc-provider/login.spec.ts @@ -273,7 +273,9 @@ context("OpenID Provider - change between flows", () => { cy.notifyUnknownRecipients("recovery", false) cy.longPrivilegedSessionTime() - const fakeOidcFlow = (identity: identityWithWebsite) => { + const fakeOidcFlow = ( + identity: ReturnType, + ) => { cy.get("input[name='username']").type(identity.email) cy.get("button[name='action'][value='accept']").click() // consent screen for the 'fake' oidc provider diff --git a/test/e2e/cypress/integration/profiles/recovery/code/errors.spec.ts b/test/e2e/cypress/integration/profiles/recovery/code/errors.spec.ts index f0e28989aed2..23d877049e6c 100644 --- a/test/e2e/cypress/integration/profiles/recovery/code/errors.spec.ts +++ b/test/e2e/cypress/integration/profiles/recovery/code/errors.spec.ts @@ -114,7 +114,10 @@ context("Account Recovery Errors", () => { ) cy.get('input[name="code"]').should("be.visible") - cy.getMail().should((message) => { + cy.getMail({ + subject: "Account access attempted", + email, + }).should((message) => { expect(message.subject).to.equal("Account access attempted") expect(message.fromAddress.trim()).to.equal("no-reply@ory.kratos.sh") expect(message.toAddresses).to.have.length(1) @@ -182,7 +185,10 @@ context("Account Recovery Errors", () => { "An email containing a recovery code has been sent to the email address you provided. If you have not received an email, check the spelling of the address and make sure to use the address you registered with.", ) - cy.getMail().then((mail) => { + cy.getMail({ + subject: "recovery_code_valid REMOTE TEMPLATE SUBJECT", + email: identity.email, + }).then((mail) => { expect(mail.body).to.include("recovery_code_valid REMOTE TEMPLATE") }) }) @@ -191,14 +197,18 @@ context("Account Recovery Errors", () => { cy.notifyUnknownRecipients("recovery") cy.remoteCourierRecoveryCodeTemplates() cy.visit(recovery) - cy.get(appPrefix(app) + "input[name='email']").type(email()) + const email = gen.email() + cy.get(appPrefix(app) + "input[name='email']").type(email) cy.get("button[value='code']").click() cy.get('[data-testid="ui/message/1060003"]').should( "have.text", "An email containing a recovery code has been sent to the email address you provided. If you have not received an email, check the spelling of the address and make sure to use the address you registered with.", ) - cy.getMail().then((mail) => { + cy.getMail({ + subject: "recovery_code_invalid REMOTE TEMPLATE SUBJECT", + email: email, + }).then((mail) => { expect(mail.body).to.include("recovery_code_invalid REMOTE TEMPLATE") }) }) diff --git a/test/e2e/cypress/integration/profiles/recovery/link/errors.spec.ts b/test/e2e/cypress/integration/profiles/recovery/link/errors.spec.ts index 97d72d3221de..4b01db22a70c 100644 --- a/test/e2e/cypress/integration/profiles/recovery/link/errors.spec.ts +++ b/test/e2e/cypress/integration/profiles/recovery/link/errors.spec.ts @@ -72,7 +72,10 @@ context("Account Recovery Errors", () => { cy.recoverApi({ email: identity.email }) cy.wait(1000) - cy.getMail().should((message) => { + cy.getMail({ + subject: "Recover access to your account", + email: identity.email, + }).should((message) => { expect(message.subject).to.equal("Recover access to your account") expect(message.toAddresses[0].trim()).to.equal(identity.email) @@ -104,7 +107,10 @@ context("Account Recovery Errors", () => { ) cy.get('input[name="email"]').should("have.value", email) - cy.getMail().should((message) => { + cy.getMail({ + subject: "Account access attempted", + email, + }).should((message) => { expect(message.subject).to.equal("Account access attempted") expect(message.fromAddress.trim()).to.equal("no-reply@ory.kratos.sh") expect(message.toAddresses).to.have.length(1) @@ -172,7 +178,10 @@ context("Account Recovery Errors", () => { cy.registerApi(identity) cy.recoverApi({ email: identity.email }) - cy.getMail().then((mail) => { + cy.getMail({ + subject: "Recover access to your account", + email: identity.email, + }).then((mail) => { console.log(mail) const link = parseHtml(mail.body).querySelector("a") cy.visit(link.href + "-not") // add random stuff to the confirm challenge @@ -189,7 +198,10 @@ context("Account Recovery Errors", () => { cy.registerApi(identity) cy.recoverApi({ email: identity.email }) - cy.getMail().then((mail) => { + cy.getMail({ + subject: "Recover access to your account", + email: identity.email, + }).then((mail) => { const link = parseHtml(mail.body).querySelector("a") // Workaround for cypress cy.visit limitation. @@ -215,7 +227,10 @@ context("Account Recovery Errors", () => { const identity = gen.identityWithWebsite() cy.recoverApi({ email: identity.email }) - cy.getMail().then((mail) => { + cy.getMail({ + subject: "Account Access Attempted", + email: identity.email, + }).then((mail) => { expect(mail.body).to.include( "this is a remote invalid recovery template", ) diff --git a/test/e2e/cypress/integration/profiles/verification/registration/errors.spec.ts b/test/e2e/cypress/integration/profiles/verification/registration/errors.spec.ts index 74b0ad72231c..06a68f4af237 100644 --- a/test/e2e/cypress/integration/profiles/verification/registration/errors.spec.ts +++ b/test/e2e/cypress/integration/profiles/verification/registration/errors.spec.ts @@ -65,7 +65,10 @@ context("Account Verification Registration Errors", () => { }) it("is unable to verify the email address if the code is incorrect", () => { - cy.getMail().then((mail) => { + cy.getMail({ + subject: "Please verify your email address", + email: identity.email, + }).then((mail) => { const link = parseHtml(mail.body).querySelector("a") expect(verifyHrefPattern.test(link.href)).to.be.true diff --git a/test/e2e/cypress/integration/profiles/verification/settings/error.spec.ts b/test/e2e/cypress/integration/profiles/verification/settings/error.spec.ts index 128234a2d570..287f63a931e0 100644 --- a/test/e2e/cypress/integration/profiles/verification/settings/error.spec.ts +++ b/test/e2e/cypress/integration/profiles/verification/settings/error.spec.ts @@ -71,7 +71,10 @@ context("Account Verification Settings Error", () => { cy.get('input[name="traits.email"]').clear().type(email) cy.get('button[value="profile"]').click() - cy.getMail().then((mail) => { + cy.getMail({ + subject: "Please verify your email address", + email, + }).then((mail) => { const link = parseHtml(mail.body).querySelector("a") expect(verifyHrefPattern.test(link.href)).to.be.true diff --git a/test/e2e/cypress/integration/profiles/verification/verify/errors.spec.ts b/test/e2e/cypress/integration/profiles/verification/verify/errors.spec.ts index 0b47b0838f92..97fd908a2e22 100644 --- a/test/e2e/cypress/integration/profiles/verification/verify/errors.spec.ts +++ b/test/e2e/cypress/integration/profiles/verification/verify/errors.spec.ts @@ -68,7 +68,11 @@ context("Account Verification Error", () => { cy.wait(1000) cy.shortVerificationLifespan() - cy.getMail().then((message) => { + cy.getMail({ + removeMail: true, + subject: "Please verify your email address", + email: identity.email, + }).then((message) => { expect(message.subject).to.equal( "Please verify your email address", ) @@ -101,6 +105,8 @@ context("Account Verification Error", () => { strategy: s, }) + cy.wait(1000) + cy.verifyEmailButExpired({ expect: { email: identity.email }, strategy: s, @@ -128,7 +134,10 @@ context("Account Verification Error", () => { cy.contains("An email containing a verification") - cy.getMail().then((mail) => { + cy.getMail({ + email: identity.email, + subject: "Please verify your email address", + }).then((mail) => { const link = parseHtml(mail.body).querySelector("a") expect(verifyHrefPattern.test(link.href)).to.be.true @@ -148,7 +157,11 @@ context("Account Verification Error", () => { const email = gen.identity().email cy.get('input[name="email"]').type(email) cy.get(`button[value="${s}"]`).click() - cy.getMail().then((mail) => { + cy.getMail({ + subject: "Someone tried to verify this email address", + email, + removeMail: true, + }).then((mail) => { expect(mail.toAddresses).includes(email) expect(mail.subject).eq( "Someone tried to verify this email address", diff --git a/test/e2e/cypress/integration/profiles/verification/verify/success.spec.ts b/test/e2e/cypress/integration/profiles/verification/verify/success.spec.ts index ae39cdbc0d83..0938e80f186d 100644 --- a/test/e2e/cypress/integration/profiles/verification/verify/success.spec.ts +++ b/test/e2e/cypress/integration/profiles/verification/verify/success.spec.ts @@ -61,7 +61,10 @@ context("Account Verification Settings Success", () => { cy.contains("An email containing a verification") - cy.getMail().should((message) => { + cy.getMail({ + subject: "Someone tried to verify this email address", + email, + }).should((message) => { expect(message.subject.trim()).to.equal( "Someone tried to verify this email address", ) diff --git a/test/e2e/cypress/support/commands.ts b/test/e2e/cypress/support/commands.ts index f8f2b7ad0615..7ef6260f4b78 100644 --- a/test/e2e/cypress/support/commands.ts +++ b/test/e2e/cypress/support/commands.ts @@ -16,9 +16,9 @@ import { import dayjs from "dayjs" import YAML from "yamljs" -import { Strategy } from "." +import { MailMessage, Strategy } from "." import { OryKratosConfiguration } from "./config" -import { UiNode, UiNodeAttributes } from "@ory/kratos-client" +import { UiNode } from "@ory/kratos-client" import { ConfigBuilder } from "./configHelpers" const configFile = "kratos.generated.yml" @@ -1023,7 +1023,13 @@ Cypress.Commands.add("deleteMail", ({ atLeast = 0 } = {}) => { return Promise.resolve() }) - return req() + try { + return req() + } catch (e) { + cy.log(e) + // just retry, since retry logic is already implemented in req() and will abort after enough tries + return req() + } }) Cypress.Commands.add( @@ -1103,7 +1109,10 @@ Cypress.Commands.add("noSession", () => Cypress.Commands.add( "performEmailVerification", ({ expect: { email, redirectTo }, strategy = "code" }) => { - cy.getMail().then((message) => { + cy.getMail({ + email, + subject: "Please verify your email address", + }).then((message) => { expect(message.subject).to.equal("Please verify your email address") expect(message.fromAddress.trim()).to.equal("no-reply@ory.kratos.sh") expect(message.toAddresses).to.have.length(1) @@ -1147,10 +1156,11 @@ Cypress.Commands.add( // Uses the verification email but waits so that it expires Cypress.Commands.add("recoverEmailButExpired", ({ expect: { email } }) => { - cy.getMail().should((message) => { - expect(message.subject).to.equal("Recover access to your account") - expect(message.toAddresses[0].trim()).to.equal(email) - + cy.getMail({ + removeMail: true, + email, + subject: "Recover access to your account", + }).should((message) => { const link = parseHtml(message.body).querySelector("a") expect(link).to.not.be.null expect(link.href).to.contain(APP_URL) @@ -1162,10 +1172,11 @@ Cypress.Commands.add("recoverEmailButExpired", ({ expect: { email } }) => { Cypress.Commands.add( "recoveryEmailWithCode", ({ expect: { email, enterCode = true } }) => { - cy.getMail({ removeMail: true }).should((message) => { - expect(message.subject).to.equal("Recover access to your account") - expect(message.toAddresses[0].trim()).to.equal(email) - + cy.getMail({ + removeMail: true, + email, + subject: "Recover access to your account", + }).should((message) => { const code = extractRecoveryCode(message.body) expect(code).to.not.be.undefined expect(code.length).to.equal(6) @@ -1180,30 +1191,37 @@ Cypress.Commands.add( Cypress.Commands.add( "recoverEmail", ({ expect: { email }, shouldVisit = true }) => - cy.getMail().should((message) => { - expect(message.subject).to.equal("Recover access to your account") - expect(message.fromAddress.trim()).to.equal("no-reply@ory.kratos.sh") - expect(message.toAddresses).to.have.length(1) - expect(message.toAddresses[0].trim()).to.equal(email) + cy + .getMail({ + removeMail: true, + email, + subject: "Recover access to your account", + }) + .should((message) => { + expect(message.fromAddress.trim()).to.equal("no-reply@ory.kratos.sh") + expect(message.toAddresses).to.have.length(1) + expect(message.toAddresses[0].trim()).to.equal(email) - const link = parseHtml(message.body).querySelector("a") - expect(link).to.not.be.null - expect(link.href).to.contain(APP_URL) + const link = parseHtml(message.body).querySelector("a") + expect(link).to.not.be.null + expect(link.href).to.contain(APP_URL) - if (shouldVisit) { - cy.visit(link.href) - } - return link.href - }), + if (shouldVisit) { + cy.visit(link.href) + } + return link.href + }), ) // Uses the verification email but waits so that it expires Cypress.Commands.add( "verifyEmailButExpired", ({ expect: { email }, strategy = "code" }) => { - cy.getMail().should((message) => { - expect(message.subject).to.equal("Please verify your email address") - + cy.getMail({ + removeMail: true, + email, + subject: "Please verify your email address", + }).should((message) => { expect(message.fromAddress.trim()).to.equal("no-reply@ory.kratos.sh") expect(message.toAddresses).to.have.length(1) expect(message.toAddresses[0].trim()).to.equal(email) @@ -1236,13 +1254,6 @@ Cypress.Commands.add( }, ) -Cypress.Commands.add("useVerificationStrategy", (strategy: Strategy) => { - cy.updateConfigFile((config) => { - config.selfservice.flows.verification.use = strategy - return config - }) -}) - Cypress.Commands.add("useLookupSecrets", (value: boolean) => { cy.updateConfigFile((config) => { config.selfservice.methods = { @@ -1269,45 +1280,60 @@ Cypress.Commands.add("expectSettingsSaved", () => { Cypress.Commands.add( "getMail", - ({ removeMail = true, expectedCount = 1, email = undefined } = {}) => { + ({ + removeMail = true, + expectedCount = 1, + email = undefined, + subject = undefined, + }) => { let tries = 0 const req = () => - cy.request(`${MAIL_API}/mail`).then((response) => { - expect(response.body).to.have.property("mailItems") - let count = response.body.mailItems.length - if (count === 0 && tries < 100) { - tries++ - cy.wait(pollInterval) - return req() - } - - let mailItem: any - if (email) { - const filtered = response.body.mailItems.filter((m: any) => - m.toAddresses.includes(email), - ) - - if (filtered.length === 0) { + cy + .request(`${MAIL_API}/mail`) + .then((response: Cypress.Response<{ mailItems: MailMessage[] }>) => { + expect(response.body).to.have.property("mailItems") + let count = response.body.mailItems.length + if (count === 0 && tries < 100) { tries++ cy.wait(pollInterval) return req() } - expect(filtered.length).to.equal(expectedCount) - mailItem = filtered[0] - } else { - expect(count).to.equal(expectedCount) - mailItem = response.body.mailItems[0] - } + let mailItem: MailMessage - if (removeMail) { - return cy.deleteMail({ atLeast: count }).then(() => { - return Promise.resolve(mailItem) - }) - } + if (!subject && !email) { + expect(count).to.equal(expectedCount) + mailItem = response.body.mailItems[0] + } else { + const filters: ((m: MailMessage) => boolean)[] = [] + if (email) { + filters.push((m: MailMessage) => m.toAddresses.includes(email)) + } + if (subject) { + filters.push((m: MailMessage) => m.subject.includes(subject)) + } + const filtered = response.body.mailItems.filter((m) => { + return filters.every((f) => f(m)) + }) + + if (filtered.length === 0) { + tries++ + cy.wait(pollInterval) + return req() + } + + expect(filtered.length).to.equal(expectedCount) + mailItem = filtered[0] + + if (removeMail) { + return cy.deleteMail({ atLeast: count }).then(() => { + return Promise.resolve(mailItem) + }) + } + } - return Promise.resolve(mailItem) - }) + return Promise.resolve(mailItem) + }) return req() }, @@ -1378,8 +1404,8 @@ Cypress.Commands.add( Cypress.Commands.add( "shouldHaveCsrfError", ({ app }: { app: "express" | "react" }) => { - let initial - let pathname + let initial: string + let pathname: string cy.location().should((location) => { initial = location.search pathname = location.pathname @@ -1490,9 +1516,12 @@ Cypress.Commands.add( Cypress.Commands.add("getVerificationCodeFromEmail", (email) => { return cy - .getMail({ removeMail: true }) + .getMail({ + removeMail: true, + email, + subject: "Please verify your email address", + }) .should((message) => { - expect(message.subject).to.equal("Please verify your email address") expect(message.toAddresses[0].trim()).to.equal(email) }) .then((message) => { @@ -1503,18 +1532,15 @@ Cypress.Commands.add("getVerificationCodeFromEmail", (email) => { }) }) -Cypress.Commands.add("enableRegistrationViaCode", (enable: boolean = true) => { - cy.updateConfigFile((config) => { - config.selfservice.methods.code.passwordless_enabled = enable - return config - }) -}) - Cypress.Commands.add("getRegistrationCodeFromEmail", (email, opts) => { return cy - .getMail({ removeMail: true, email, ...opts }) + .getMail({ + removeMail: true, + email, + subject: "Complete your account registration", + ...opts, + }) .should((message) => { - expect(message.subject).to.equal("Complete your account registration") expect(message.toAddresses[0].trim()).to.equal(email) }) .then((message) => { @@ -1527,9 +1553,13 @@ Cypress.Commands.add("getRegistrationCodeFromEmail", (email, opts) => { Cypress.Commands.add("getLoginCodeFromEmail", (email, opts) => { return cy - .getMail({ removeMail: true, email, ...opts }) + .getMail({ + removeMail: true, + email, + subject: "Login to your account", + ...opts, + }) .should((message) => { - expect(message.subject).to.equal("Login to your account") expect(message.toAddresses[0].trim()).to.equal(email) }) .then((message) => { diff --git a/test/e2e/cypress/support/config.d.ts b/test/e2e/cypress/support/config.d.ts index 060cb12822bf..c7e9742aed39 100644 --- a/test/e2e/cypress/support/config.d.ts +++ b/test/e2e/cypress/support/config.d.ts @@ -1,4 +1,4 @@ -// Copyright © 2023 Ory Corp +// Copyright © 2024 Ory Corp // SPDX-License-Identifier: Apache-2.0 /* eslint-disable */ @@ -111,6 +111,7 @@ export type OverrideTheBaseURLWhichShouldBeUsedAsTheBaseForRecoveryAndVerificati string export type HowLongALinkIsValidFor = string export type EnablesLoginAndRegistrationWithTheCodeMethod = boolean +export type EnablesLoginFlowsCodeMethodToFulfilMFARequests = boolean /** * This setting allows the code method to always login a user with code if they have registered with another authentication method such as password or social sign in. */ @@ -200,6 +201,7 @@ export type SelfServiceOIDCProvider = SelfServiceOIDCProvider1 & { apple_private_key?: ApplePrivateKey requested_claims?: OpenIDConnectClaims organization_id?: OrganizationID + additional_id_token_audiences?: AdditionalClientIdsAllowedWhenUsingIDTokenSubmission } export type SelfServiceOIDCProvider1 = { [k: string]: unknown | undefined @@ -259,6 +261,7 @@ export type ApplePrivateKey = string * The ID of the organization that this provider belongs to. Only effective in the Ory Network. */ export type OrganizationID = string +export type AdditionalClientIdsAllowedWhenUsingIDTokenSubmission = string[] /** * A list and configuration of OAuth2 and OpenID Connect providers Ory Kratos should integrate with. */ @@ -335,6 +338,14 @@ export type HTTPAddressOfAPIEndpoint1 = string export type AuthMechanisms1 = | WebHookAuthApiKeyProperties | WebHookAuthBasicAuthProperties +/** + * The channel id. Corresponds to the .via property of the identity schema for recovery, verification, etc. Currently only phone is supported. + */ +export type ChannelId = "sms" +/** + * The channel type. Currently only http is supported. + */ +export type ChannelType = "http" /** * 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. */ @@ -563,6 +574,7 @@ export interface OryKratosConfiguration2 { } code?: { passwordless_enabled?: EnablesLoginAndRegistrationWithTheCodeMethod + mfa_enabled?: EnablesLoginFlowsCodeMethodToFulfilMFARequests passwordless_login_fallback_enabled?: PasswordlessLoginFallbackEnabled enabled?: EnablesCodeMethod config?: CodeConfiguration @@ -959,10 +971,25 @@ export interface CourierConfiguration { * Defines the maximum number of times the sending of a message is retried after it failed before it is marked as abandoned */ message_retries?: number + /** + * Configures the dispatch worker. + */ + worker?: { + /** + * Defines how many messages are pulled from the queue at once. + */ + pull_count?: number + /** + * Defines how long the worker waits before pulling messages from the queue again. + */ + pull_wait?: string + [k: string]: unknown | undefined + } delivery_strategy?: DeliveryStrategy http?: HTTPConfiguration - smtp: SMTPConfiguration + smtp?: SMTPConfiguration sms?: SMSSenderConfiguration + channels?: CourierChannelConfiguration[] } export interface CourierTemplates { invalid?: { @@ -970,6 +997,7 @@ export interface CourierTemplates { } valid?: { email: EmailCourierTemplate + sms?: SmsCourierTemplate } } export interface EmailCourierTemplate { @@ -985,6 +1013,14 @@ export interface EmailCourierTemplate { } subject?: string } +export interface SmsCourierTemplate { + body?: { + /** + * A template send to the SMS provider. + */ + plaintext?: string + } +} /** * Configures outgoing emails using HTTP. */ @@ -1087,6 +1123,11 @@ export interface SMSSenderConfiguration { additionalProperties?: false } } +export interface CourierChannelConfiguration { + id: ChannelId + type?: ChannelType + request_config: HttpRequestConfig +} export interface OAuth2ProviderConfiguration { url?: OAuth20ProviderURL headers?: HTTPRequestHeaders diff --git a/test/e2e/cypress/support/configHelpers.ts b/test/e2e/cypress/support/configHelpers.ts index 545bff2449c3..c8ccf05b70d2 100644 --- a/test/e2e/cypress/support/configHelpers.ts +++ b/test/e2e/cypress/support/configHelpers.ts @@ -132,4 +132,13 @@ export class ConfigBuilder { this.config.session.whoami.required_aal = "aal1" return this } + public enableCode() { + this.config.selfservice.methods.code.enabled = true + return this + } + + public enableCodeMFA() { + this.config.selfservice.methods.code.mfa_enabled = true + return this + } } diff --git a/test/e2e/cypress/support/index.d.ts b/test/e2e/cypress/support/index.d.ts index 1792db4a51cc..3fef679ec098 100644 --- a/test/e2e/cypress/support/index.d.ts +++ b/test/e2e/cypress/support/index.d.ts @@ -104,10 +104,11 @@ declare global { * * @param opts */ - getMail(opts?: { - removeMail: boolean + getMail(opts: { + removeMail?: boolean expectedCount?: number email?: string + subject?: string }): Chainable performEmailVerification(opts?: { @@ -560,13 +561,6 @@ declare global { strategy?: Strategy }): Chainable - /** - * Sets the strategy to use for verification - * - * @param strategy the Strategy - */ - useVerificationStrategy(strategy: Strategy): Chainable - /** * Disables verification */ @@ -723,12 +717,6 @@ declare global { */ getVerificationCodeFromEmail(email: string): Chainable - /** - * Enables the registration code method - * @param enable - */ - enableRegistrationViaCode(enable: boolean): Chainable - /** * Extracts a registration code from the received email */ diff --git a/text/id.go b/text/id.go index fa8184f0ffaf..562a179740ef 100644 --- a/text/id.go +++ b/text/id.go @@ -28,6 +28,8 @@ const ( InfoSelfServiceLoginLink // 1010016 InfoSelfServiceLoginAndLink // 1010017 InfoSelfServiceLoginWithAndLink // 1010018 + InfoSelfServiceLoginCodeMFA // 1010019 + InfoSelfServiceLoginCodeMFAHint // 1010020 ) const ( @@ -153,6 +155,7 @@ const ( ErrorValidationLoginRetrySuccess // 4010007 ErrorValidationLoginCodeInvalidOrAlreadyUsed // 4010008 ErrorValidationLoginLinkedCredentialsDoNotMatch // 4010009 + ErrorValidationLoginAddressUnknown // 4010010 ) const ( diff --git a/text/message_login.go b/text/message_login.go index 4918cb893701..c94db4538704 100644 --- a/text/message_login.go +++ b/text/message_login.go @@ -117,7 +117,6 @@ func NewInfoLoginWith(provider string) *Message { } func NewInfoLoginWithAndLink(provider string) *Message { - return &Message{ ID: InfoSelfServiceLoginWithAndLink, Text: fmt.Sprintf("Sign in with %s and link credential", provider), @@ -243,3 +242,30 @@ func NewErrorValidationLoginLinkedCredentialsDoNotMatch() *Message { Type: Error, } } + +func NewErrorValidationAddressUnknown() *Message { + return &Message{ + ID: ErrorValidationLoginAddressUnknown, + Text: "The address you entered does not match any known addresses in the current account.", + Type: Error, + } +} + +func NewInfoSelfServiceLoginCodeMFA() *Message { + return &Message{ + ID: InfoSelfServiceLoginCodeMFA, + Type: Info, + Text: "Continue with code", + } +} + +func NewInfoSelfServiceLoginCodeMFAHint(maskedTo string) *Message { + return &Message{ + ID: InfoSelfServiceLoginCodeMFAHint, + Type: Info, + Text: fmt.Sprintf("We will send a code to %s. To verify that this is your address please enter it here.", maskedTo), + Context: context(map[string]any{ + "masked_to": maskedTo, + }), + } +} From 0e45e87632b1982f51200b6ef167870646051488 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Fri, 26 Jan 2024 16:44:24 +0000 Subject: [PATCH 249/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47290095bce5..518d3b6c7add 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2024-01-25)](#2024-01-25) +- [ (2024-01-26)](#2024-01-26) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -314,7 +314,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2024-01-25) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2024-01-26) ## Breaking Changes @@ -1015,6 +1015,8 @@ https://github.com/ory/kratos/pull/3480 - Support for B2B SSO ([#3489](https://github.com/ory/kratos/issues/3489)) ([0ec037a](https://github.com/ory/kratos/commit/0ec037ab298ed28fb0ac84db6a4d2b14b81e57df)) +- Support MFA via SMS ([#3682](https://github.com/ory/kratos/issues/3682)) + ([1516cf6](https://github.com/ory/kratos/commit/1516cf64e346819dccace1cc25aaccac38b9e47c)) - Support multiple origins for WebAuthN ([#3380](https://github.com/ory/kratos/issues/3380)) ([013f335](https://github.com/ory/kratos/commit/013f335881831bbf90ac31b219b57118fc089fe6)): From 549308db1f7dca42004631ed6156cae5f827b8fe Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Mon, 29 Jan 2024 12:18:54 +0100 Subject: [PATCH 250/282] Revert "feat: extend Microsoft Graph API capabilities (#3609)" (#3717) This reverts commit 4a7bcc9322be37e6fd141e411bd65e3977eeb692. Co-authored-by: Arne Luenser --- selfservice/strategy/oidc/provider_microsoft.go | 17 +++++------------ .../strategy/oidc/provider_userinfo_test.go | 2 +- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/selfservice/strategy/oidc/provider_microsoft.go b/selfservice/strategy/oidc/provider_microsoft.go index 61fba182c045..8dd17fbbaae5 100644 --- a/selfservice/strategy/oidc/provider_microsoft.go +++ b/selfservice/strategy/oidc/provider_microsoft.go @@ -92,10 +92,7 @@ func (m *ProviderMicrosoft) updateSubject(ctx context.Context, claims *Claims, e } ctx, client := httpx.SetOAuth2(ctx, m.reg.HTTPClient(ctx), o, exchange) - // params to request all user fields from the graph api (User.Read scope) - https://learn.microsoft.com/en-us/previous-versions/azure/ad/graph/api/entity-and-complex-type-reference#user-entity - graphFields := "accountEnabled,assignedLicenses,assignedPlans,city,country,creationType,deletionTimestamp,department,dirSyncEnabled,displayName,employeeId,facsimileTelephoneNumber,givenName,immutableId,jobTitle,lastDirSyncTime,mail,mailNickname,mobile,objectId,objectType,onPremisesSecurityIdentifier,otherMails,passwordPolicies,passwordProfile,physicalDeliveryOfficeName,postalCode,preferredLanguage,provisionedPlans,provisioningErrors,proxyAddresses,refreshTokensValidFromDateTime,showInAddressList,signInNames,sipProxyAddress,state,streetAddress,surname,telephoneNumber,thumbnailPhoto,usageLocation,userIdentities,userPrincipalName,userType" - req, err := retryablehttp.NewRequestWithContext(ctx, "GET", "https://graph.microsoft.com/v1.0/me?$select="+graphFields, nil) - + req, err := retryablehttp.NewRequestWithContext(ctx, "GET", "https://graph.microsoft.com/v1.0/me", nil) if err != nil { return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("%s", err)) } @@ -110,18 +107,14 @@ func (m *ProviderMicrosoft) updateSubject(ctx context.Context, claims *Claims, e return nil, err } - var user map[string]interface{} + var user struct { + ID string `json:"id"` + } if err := json.NewDecoder(resp.Body).Decode(&user); err != nil { return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Unable to decode JSON from `https://graph.microsoft.com/v1.0/me`: %s", err)) } - ok := false - claims.Subject, ok = user["id"].(string) - if !ok { - return nil, errors.WithStack(herodot.ErrInternalServerError.WithReason("Unable to retrieve subject from response")) - } - - claims.RawClaims["user"] = user + claims.Subject = user.ID } return claims, nil diff --git a/selfservice/strategy/oidc/provider_userinfo_test.go b/selfservice/strategy/oidc/provider_userinfo_test.go index f29ef925bbe5..0b11f2dcae90 100644 --- a/selfservice/strategy/oidc/provider_userinfo_test.go +++ b/selfservice/strategy/oidc/provider_userinfo_test.go @@ -294,7 +294,7 @@ func TestProviderClaimsRespectsErrorCodes(t *testing.T) { }, expectedClaims: &oidc.Claims{ Issuer: "https://login.microsoftonline.com/a9b86385-f32c-4803-afc8-4b2312fbdf24/v2.0", Subject: "new-id", Name: "John Doe", Email: "john.doe@example.com", - RawClaims: map[string]interface{}{"aud": []interface{}{"foo"}, "exp": 4.071728504e+09, "iat": 1.516239022e+09, "iss": "https://login.microsoftonline.com/a9b86385-f32c-4803-afc8-4b2312fbdf24/v2.0", "email": "john.doe@example.com", "name": "John Doe", "sub": "1234567890", "tid": "a9b86385-f32c-4803-afc8-4b2312fbdf24", "user": map[string]interface{}{"id": "new-id"}}, + RawClaims: map[string]interface{}{"aud": []interface{}{"foo"}, "exp": 4.071728504e+09, "iat": 1.516239022e+09, "iss": "https://login.microsoftonline.com/a9b86385-f32c-4803-afc8-4b2312fbdf24/v2.0", "email": "john.doe@example.com", "name": "John Doe", "sub": "1234567890", "tid": "a9b86385-f32c-4803-afc8-4b2312fbdf24"}, }, }, { From 4b881cae4359bfa068261d2d0765ce3daadcbcf2 Mon Sep 17 00:00:00 2001 From: Patrik Date: Tue, 30 Jan 2024 16:18:17 +0100 Subject: [PATCH 251/282] docs: improve enum handling and completeness (#3714) --- .schema/openapi/patches/identity.yaml | 23 ---- identity/credentials.go | 22 ++-- identity/handler.go | 16 +-- identity/identity.go | 2 +- internal/client-go/.openapi-generator/FILES | 4 - internal/client-go/README.md | 2 - internal/client-go/api_identity.go | 4 +- .../client-go/model_create_identity_body.go | 15 +-- internal/client-go/model_identity.go | 17 +-- .../client-go/model_identity_credentials.go | 15 +-- .../model_identity_credentials_type.go | 88 -------------- internal/client-go/model_identity_state.go | 84 ------------- internal/client-go/model_login_flow.go | 13 ++- internal/client-go/model_registration_flow.go | 13 ++- .../client-go/model_update_identity_body.go | 15 +-- internal/httpclient/.openapi-generator/FILES | 4 - internal/httpclient/README.md | 2 - internal/httpclient/api_identity.go | 4 +- .../httpclient/model_create_identity_body.go | 15 +-- internal/httpclient/model_identity.go | 17 +-- .../httpclient/model_identity_credentials.go | 15 +-- .../model_identity_credentials_type.go | 88 -------------- internal/httpclient/model_identity_state.go | 84 ------------- internal/httpclient/model_login_flow.go | 13 ++- .../httpclient/model_registration_flow.go | 13 ++- .../httpclient/model_update_identity_body.go | 15 +-- spec/api.json | 108 +++++++++++------ spec/swagger.json | 110 +++++++++++++++--- 28 files changed, 280 insertions(+), 541 deletions(-) delete mode 100644 internal/client-go/model_identity_credentials_type.go delete mode 100644 internal/client-go/model_identity_state.go delete mode 100644 internal/httpclient/model_identity_credentials_type.go delete mode 100644 internal/httpclient/model_identity_state.go diff --git a/.schema/openapi/patches/identity.yaml b/.schema/openapi/patches/identity.yaml index c5f5ede63c58..1132912747e4 100644 --- a/.schema/openapi/patches/identity.yaml +++ b/.schema/openapi/patches/identity.yaml @@ -1,26 +1,3 @@ -- op: add - path: /components/schemas/identityState/enum - value: - - active - - inactive -- op: add - path: /components/schemas/identityCredentialsType/enum - value: - - password - - totp - - oidc - - webauthn - - lookup_secret - - code -- op: add - path: /paths/~1admin~1identities~1{id}/get/parameters/1/schema/items/enum - value: - - password - - totp - - oidc - - webauthn - - lookup_secret - - code - op: remove path: /components/schemas/updateIdentityBody/properties/metadata_admin/type - op: remove diff --git a/identity/credentials.go b/identity/credentials.go index 4f2dbd522874..c18b9df97f5d 100644 --- a/identity/credentials.go +++ b/identity/credentials.go @@ -75,9 +75,19 @@ func (n NullableAuthenticatorAssuranceLevel) ToAAL() (AuthenticatorAssuranceLeve // CredentialsType represents several different credential types, like password credentials, passwordless credentials, // and so on. // -// swagger:model identityCredentialsType +// swagger:enum CredentialsType type CredentialsType string +// Please make sure to add all of these values to the test that ensures they are created during migration +const ( + CredentialsTypePassword CredentialsType = "password" + CredentialsTypeOIDC CredentialsType = "oidc" + CredentialsTypeTOTP CredentialsType = "totp" + CredentialsTypeLookup CredentialsType = "lookup_secret" + CredentialsTypeWebAuthn CredentialsType = "webauthn" + CredentialsTypeCodeAuth CredentialsType = "code" +) + func (c CredentialsType) String() string { return string(c) } @@ -101,16 +111,6 @@ func (c CredentialsType) ToUiNodeGroup() node.UiNodeGroup { } } -// Please make sure to add all of these values to the test that ensures they are created during migration -const ( - CredentialsTypePassword CredentialsType = "password" - CredentialsTypeOIDC CredentialsType = "oidc" - CredentialsTypeTOTP CredentialsType = "totp" - CredentialsTypeLookup CredentialsType = "lookup_secret" - CredentialsTypeWebAuthn CredentialsType = "webauthn" - CredentialsTypeCodeAuth CredentialsType = "code" -) - var AllCredentialTypes = []CredentialsType{ CredentialsTypePassword, CredentialsTypeOIDC, diff --git a/identity/handler.go b/identity/handler.go index de50cb73eb2f..c821a13de844 100644 --- a/identity/handler.go +++ b/identity/handler.go @@ -257,7 +257,7 @@ type getIdentity struct { // // required: false // in: query - DeclassifyCredentials []string `json:"include_credential"` + DeclassifyCredentials []CredentialsType `json:"include_credential"` } // swagger:route GET /admin/identities/{id} identity getIdentity @@ -932,13 +932,11 @@ type deleteIdentityCredentials struct { // in: path ID string `json:"id"` - // Type is the credential's Type. - // One of totp, webauthn, lookup + // Type is the type of credentials to be deleted. // - // enum: totp,webauthn,lookup // required: true // in: path - Type string `json:"type"` + Type CredentialsType `json:"type"` } // swagger:route DELETE /admin/identities/{id}/credentials/{type} identity deleteIdentityCredentials @@ -977,9 +975,7 @@ func (h *Handler) deleteIdentityCredentials(w http.ResponseWriter, r *http.Reque } switch cred.Type { - case CredentialsTypeLookup: - fallthrough - case CredentialsTypeTOTP: + case CredentialsTypeLookup, CredentialsTypeTOTP: identity.DeleteCredentialsType(cred.Type) case CredentialsTypeWebAuthn: identity, err = deletCredentialWebAuthFromIdentity(identity) @@ -987,9 +983,7 @@ func (h *Handler) deleteIdentityCredentials(w http.ResponseWriter, r *http.Reque h.r.Writer().WriteError(w, r, err) return } - case CredentialsTypeOIDC: - fallthrough - case CredentialsTypePassword: + case CredentialsTypeOIDC, CredentialsTypePassword, CredentialsTypeCodeAuth: h.r.Writer().WriteError(w, r, errors.WithStack(herodot.ErrBadRequest.WithReasonf("You can't remove first factor credentials."))) return default: diff --git a/identity/identity.go b/identity/identity.go index 85030bd41e92..d763e688a8e3 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -33,7 +33,7 @@ import ( // // The state can either be `active` or `inactive`. // -// swagger:model identityState +// swagger:enum State type State string const ( diff --git a/internal/client-go/.openapi-generator/FILES b/internal/client-go/.openapi-generator/FILES index f2d48ddec66c..0f14f1ccb470 100644 --- a/internal/client-go/.openapi-generator/FILES +++ b/internal/client-go/.openapi-generator/FILES @@ -44,11 +44,9 @@ docs/IdentityCredentialsCode.md docs/IdentityCredentialsOidc.md docs/IdentityCredentialsOidcProvider.md docs/IdentityCredentialsPassword.md -docs/IdentityCredentialsType.md docs/IdentityPatch.md docs/IdentityPatchResponse.md docs/IdentitySchemaContainer.md -docs/IdentityState.md docs/IdentityWithCredentials.md docs/IdentityWithCredentialsOidc.md docs/IdentityWithCredentialsOidcConfig.md @@ -163,11 +161,9 @@ model_identity_credentials_code.go model_identity_credentials_oidc.go model_identity_credentials_oidc_provider.go model_identity_credentials_password.go -model_identity_credentials_type.go model_identity_patch.go model_identity_patch_response.go model_identity_schema_container.go -model_identity_state.go model_identity_with_credentials.go model_identity_with_credentials_oidc.go model_identity_with_credentials_oidc_config.go diff --git a/internal/client-go/README.md b/internal/client-go/README.md index 7fedaba9d3e5..7f5de7166ef1 100644 --- a/internal/client-go/README.md +++ b/internal/client-go/README.md @@ -168,11 +168,9 @@ Class | Method | HTTP request | Description - [IdentityCredentialsOidc](docs/IdentityCredentialsOidc.md) - [IdentityCredentialsOidcProvider](docs/IdentityCredentialsOidcProvider.md) - [IdentityCredentialsPassword](docs/IdentityCredentialsPassword.md) - - [IdentityCredentialsType](docs/IdentityCredentialsType.md) - [IdentityPatch](docs/IdentityPatch.md) - [IdentityPatchResponse](docs/IdentityPatchResponse.md) - [IdentitySchemaContainer](docs/IdentitySchemaContainer.md) - - [IdentityState](docs/IdentityState.md) - [IdentityWithCredentials](docs/IdentityWithCredentials.md) - [IdentityWithCredentialsOidc](docs/IdentityWithCredentialsOidc.md) - [IdentityWithCredentialsOidcConfig](docs/IdentityWithCredentialsOidcConfig.md) diff --git a/internal/client-go/api_identity.go b/internal/client-go/api_identity.go index 7ebc9fc7ca44..bc1b675876fb 100644 --- a/internal/client-go/api_identity.go +++ b/internal/client-go/api_identity.go @@ -114,7 +114,7 @@ type IdentityApi interface { You can only delete second factor (aal2) credentials. * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). * @param id ID is the identity's ID. - * @param type_ Type is the credential's Type. One of totp, webauthn, lookup + * @param type_ Type is the type of credentials to be deleted. password CredentialsTypePassword oidc CredentialsTypeOIDC totp CredentialsTypeTOTP lookup_secret CredentialsTypeLookup webauthn CredentialsTypeWebAuthn code CredentialsTypeCodeAuth link_recovery CredentialsTypeRecoveryLink CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). It is not used within the credentials object itself. code_recovery CredentialsTypeRecoveryCode * @return IdentityApiApiDeleteIdentityCredentialsRequest */ DeleteIdentityCredentials(ctx context.Context, id string, type_ string) IdentityApiApiDeleteIdentityCredentialsRequest @@ -1077,7 +1077,7 @@ func (r IdentityApiApiDeleteIdentityCredentialsRequest) Execute() (*http.Respons You can only delete second factor (aal2) credentials. - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @param id ID is the identity's ID. - - @param type_ Type is the credential's Type. One of totp, webauthn, lookup + - @param type_ Type is the type of credentials to be deleted. password CredentialsTypePassword oidc CredentialsTypeOIDC totp CredentialsTypeTOTP lookup_secret CredentialsTypeLookup webauthn CredentialsTypeWebAuthn code CredentialsTypeCodeAuth link_recovery CredentialsTypeRecoveryLink CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). It is not used within the credentials object itself. code_recovery CredentialsTypeRecoveryCode - @return IdentityApiApiDeleteIdentityCredentialsRequest */ func (a *IdentityApiService) DeleteIdentityCredentials(ctx context.Context, id string, type_ string) IdentityApiApiDeleteIdentityCredentialsRequest { diff --git a/internal/client-go/model_create_identity_body.go b/internal/client-go/model_create_identity_body.go index 8a7c7d3c369f..177317c62d2e 100644 --- a/internal/client-go/model_create_identity_body.go +++ b/internal/client-go/model_create_identity_body.go @@ -25,8 +25,9 @@ type CreateIdentityBody struct { // RecoveryAddresses contains all the addresses that can be used to recover an identity. Use this structure to import recovery addresses for an identity. Please keep in mind that the address needs to be represented in the Identity Schema or this field will be overwritten on the next identity update. RecoveryAddresses []RecoveryIdentityAddress `json:"recovery_addresses,omitempty"` // SchemaID is the ID of the JSON Schema to be used for validating the identity's traits. - SchemaId string `json:"schema_id"` - State *IdentityState `json:"state,omitempty"` + SchemaId string `json:"schema_id"` + // State is the identity's state. active StateActive inactive StateInactive + State *string `json:"state,omitempty"` // Traits represent an identity's traits. The identity is able to create, modify, and delete traits in a self-service manner. The input will always be validated against the JSON Schema defined in `schema_url`. Traits map[string]interface{} `json:"traits"` // VerifiableAddresses contains all the addresses that can be verified by the user. Use this structure to import verified addresses for an identity. Please keep in mind that the address needs to be represented in the Identity Schema or this field will be overwritten on the next identity update. @@ -207,9 +208,9 @@ func (o *CreateIdentityBody) SetSchemaId(v string) { } // GetState returns the State field value if set, zero value otherwise. -func (o *CreateIdentityBody) GetState() IdentityState { +func (o *CreateIdentityBody) GetState() string { if o == nil || o.State == nil { - var ret IdentityState + var ret string return ret } return *o.State @@ -217,7 +218,7 @@ func (o *CreateIdentityBody) GetState() IdentityState { // GetStateOk returns a tuple with the State field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *CreateIdentityBody) GetStateOk() (*IdentityState, bool) { +func (o *CreateIdentityBody) GetStateOk() (*string, bool) { if o == nil || o.State == nil { return nil, false } @@ -233,8 +234,8 @@ func (o *CreateIdentityBody) HasState() bool { return false } -// SetState gets a reference to the given IdentityState and assigns it to the State field. -func (o *CreateIdentityBody) SetState(v IdentityState) { +// SetState gets a reference to the given string and assigns it to the State field. +func (o *CreateIdentityBody) SetState(v string) { o.State = &v } diff --git a/internal/client-go/model_identity.go b/internal/client-go/model_identity.go index 282821f468ed..cd939965877d 100644 --- a/internal/client-go/model_identity.go +++ b/internal/client-go/model_identity.go @@ -34,9 +34,10 @@ type Identity struct { // SchemaID is the ID of the JSON Schema to be used for validating the identity's traits. SchemaId string `json:"schema_id"` // SchemaURL is the URL of the endpoint where the identity's traits schema can be fetched from. format: url - SchemaUrl string `json:"schema_url"` - State *IdentityState `json:"state,omitempty"` - StateChangedAt *time.Time `json:"state_changed_at,omitempty"` + SchemaUrl string `json:"schema_url"` + // State is the identity's state. This value has currently no effect. active StateActive inactive StateInactive + State *string `json:"state,omitempty"` + StateChangedAt *time.Time `json:"state_changed_at,omitempty"` // Traits represent an identity's traits. The identity is able to create, modify, and delete traits in a self-service manner. The input will always be validated against the JSON Schema defined in `schema_url`. Traits interface{} `json:"traits"` // UpdatedAt is a helper struct field for gobuffalo.pop. @@ -344,9 +345,9 @@ func (o *Identity) SetSchemaUrl(v string) { } // GetState returns the State field value if set, zero value otherwise. -func (o *Identity) GetState() IdentityState { +func (o *Identity) GetState() string { if o == nil || o.State == nil { - var ret IdentityState + var ret string return ret } return *o.State @@ -354,7 +355,7 @@ func (o *Identity) GetState() IdentityState { // GetStateOk returns a tuple with the State field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *Identity) GetStateOk() (*IdentityState, bool) { +func (o *Identity) GetStateOk() (*string, bool) { if o == nil || o.State == nil { return nil, false } @@ -370,8 +371,8 @@ func (o *Identity) HasState() bool { return false } -// SetState gets a reference to the given IdentityState and assigns it to the State field. -func (o *Identity) SetState(v IdentityState) { +// SetState gets a reference to the given string and assigns it to the State field. +func (o *Identity) SetState(v string) { o.State = &v } diff --git a/internal/client-go/model_identity_credentials.go b/internal/client-go/model_identity_credentials.go index 16d0a90a6330..5b454383d520 100644 --- a/internal/client-go/model_identity_credentials.go +++ b/internal/client-go/model_identity_credentials.go @@ -22,8 +22,9 @@ type IdentityCredentials struct { // CreatedAt is a helper struct field for gobuffalo.pop. CreatedAt *time.Time `json:"created_at,omitempty"` // Identifiers represents a list of unique identifiers this credential type matches. - Identifiers []string `json:"identifiers,omitempty"` - Type *IdentityCredentialsType `json:"type,omitempty"` + Identifiers []string `json:"identifiers,omitempty"` + // Type discriminates between different types of credentials. password CredentialsTypePassword oidc CredentialsTypeOIDC totp CredentialsTypeTOTP lookup_secret CredentialsTypeLookup webauthn CredentialsTypeWebAuthn code CredentialsTypeCodeAuth link_recovery CredentialsTypeRecoveryLink CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). It is not used within the credentials object itself. code_recovery CredentialsTypeRecoveryCode + Type *string `json:"type,omitempty"` // UpdatedAt is a helper struct field for gobuffalo.pop. UpdatedAt *time.Time `json:"updated_at,omitempty"` // Version refers to the version of the credential. Useful when changing the config schema. @@ -144,9 +145,9 @@ func (o *IdentityCredentials) SetIdentifiers(v []string) { } // GetType returns the Type field value if set, zero value otherwise. -func (o *IdentityCredentials) GetType() IdentityCredentialsType { +func (o *IdentityCredentials) GetType() string { if o == nil || o.Type == nil { - var ret IdentityCredentialsType + var ret string return ret } return *o.Type @@ -154,7 +155,7 @@ func (o *IdentityCredentials) GetType() IdentityCredentialsType { // GetTypeOk returns a tuple with the Type field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *IdentityCredentials) GetTypeOk() (*IdentityCredentialsType, bool) { +func (o *IdentityCredentials) GetTypeOk() (*string, bool) { if o == nil || o.Type == nil { return nil, false } @@ -170,8 +171,8 @@ func (o *IdentityCredentials) HasType() bool { return false } -// SetType gets a reference to the given IdentityCredentialsType and assigns it to the Type field. -func (o *IdentityCredentials) SetType(v IdentityCredentialsType) { +// SetType gets a reference to the given string and assigns it to the Type field. +func (o *IdentityCredentials) SetType(v string) { o.Type = &v } diff --git a/internal/client-go/model_identity_credentials_type.go b/internal/client-go/model_identity_credentials_type.go deleted file mode 100644 index a9d01c54e796..000000000000 --- a/internal/client-go/model_identity_credentials_type.go +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Ory Identities API - * - * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. - * - * API version: - * Contact: office@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" - "fmt" -) - -// IdentityCredentialsType and so on. -type IdentityCredentialsType string - -// List of identityCredentialsType -const ( - IDENTITYCREDENTIALSTYPE_PASSWORD IdentityCredentialsType = "password" - IDENTITYCREDENTIALSTYPE_TOTP IdentityCredentialsType = "totp" - IDENTITYCREDENTIALSTYPE_OIDC IdentityCredentialsType = "oidc" - IDENTITYCREDENTIALSTYPE_WEBAUTHN IdentityCredentialsType = "webauthn" - IDENTITYCREDENTIALSTYPE_LOOKUP_SECRET IdentityCredentialsType = "lookup_secret" - IDENTITYCREDENTIALSTYPE_CODE IdentityCredentialsType = "code" -) - -func (v *IdentityCredentialsType) UnmarshalJSON(src []byte) error { - var value string - err := json.Unmarshal(src, &value) - if err != nil { - return err - } - enumTypeValue := IdentityCredentialsType(value) - for _, existing := range []IdentityCredentialsType{"password", "totp", "oidc", "webauthn", "lookup_secret", "code"} { - if existing == enumTypeValue { - *v = enumTypeValue - return nil - } - } - - return fmt.Errorf("%+v is not a valid IdentityCredentialsType", value) -} - -// Ptr returns reference to identityCredentialsType value -func (v IdentityCredentialsType) Ptr() *IdentityCredentialsType { - return &v -} - -type NullableIdentityCredentialsType struct { - value *IdentityCredentialsType - isSet bool -} - -func (v NullableIdentityCredentialsType) Get() *IdentityCredentialsType { - return v.value -} - -func (v *NullableIdentityCredentialsType) Set(val *IdentityCredentialsType) { - v.value = val - v.isSet = true -} - -func (v NullableIdentityCredentialsType) IsSet() bool { - return v.isSet -} - -func (v *NullableIdentityCredentialsType) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableIdentityCredentialsType(val *IdentityCredentialsType) *NullableIdentityCredentialsType { - return &NullableIdentityCredentialsType{value: val, isSet: true} -} - -func (v NullableIdentityCredentialsType) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableIdentityCredentialsType) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_identity_state.go b/internal/client-go/model_identity_state.go deleted file mode 100644 index 239a49c65fe5..000000000000 --- a/internal/client-go/model_identity_state.go +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Ory Identities API - * - * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. - * - * API version: - * Contact: office@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" - "fmt" -) - -// IdentityState The state can either be `active` or `inactive`. -type IdentityState string - -// List of identityState -const ( - IDENTITYSTATE_ACTIVE IdentityState = "active" - IDENTITYSTATE_INACTIVE IdentityState = "inactive" -) - -func (v *IdentityState) UnmarshalJSON(src []byte) error { - var value string - err := json.Unmarshal(src, &value) - if err != nil { - return err - } - enumTypeValue := IdentityState(value) - for _, existing := range []IdentityState{"active", "inactive"} { - if existing == enumTypeValue { - *v = enumTypeValue - return nil - } - } - - return fmt.Errorf("%+v is not a valid IdentityState", value) -} - -// Ptr returns reference to identityState value -func (v IdentityState) Ptr() *IdentityState { - return &v -} - -type NullableIdentityState struct { - value *IdentityState - isSet bool -} - -func (v NullableIdentityState) Get() *IdentityState { - return v.value -} - -func (v *NullableIdentityState) Set(val *IdentityState) { - v.value = val - v.isSet = true -} - -func (v NullableIdentityState) IsSet() bool { - return v.isSet -} - -func (v *NullableIdentityState) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableIdentityState(val *IdentityState) *NullableIdentityState { - return &NullableIdentityState{value: val, isSet: true} -} - -func (v NullableIdentityState) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableIdentityState) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/client-go/model_login_flow.go b/internal/client-go/model_login_flow.go index 161377f6b680..b36abc379568 100644 --- a/internal/client-go/model_login_flow.go +++ b/internal/client-go/model_login_flow.go @@ -18,7 +18,8 @@ import ( // LoginFlow This object represents a login flow. A login flow is initiated at the \"Initiate Login API / Browser Flow\" endpoint by a client. Once a login flow is completed successfully, a session cookie or session token will be issued. type LoginFlow struct { - Active *IdentityCredentialsType `json:"active,omitempty"` + // The active login method If set contains the login method used. If the flow is new, it is unset. password CredentialsTypePassword oidc CredentialsTypeOIDC totp CredentialsTypeTOTP lookup_secret CredentialsTypeLookup webauthn CredentialsTypeWebAuthn code CredentialsTypeCodeAuth link_recovery CredentialsTypeRecoveryLink CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). It is not used within the credentials object itself. code_recovery CredentialsTypeRecoveryCode + Active *string `json:"active,omitempty"` // CreatedAt is a helper struct field for gobuffalo.pop. CreatedAt *time.Time `json:"created_at,omitempty"` // ExpiresAt is the time (UTC) when the flow expires. If the user still wishes to log in, a new flow has to be initiated. @@ -74,9 +75,9 @@ func NewLoginFlowWithDefaults() *LoginFlow { } // GetActive returns the Active field value if set, zero value otherwise. -func (o *LoginFlow) GetActive() IdentityCredentialsType { +func (o *LoginFlow) GetActive() string { if o == nil || o.Active == nil { - var ret IdentityCredentialsType + var ret string return ret } return *o.Active @@ -84,7 +85,7 @@ func (o *LoginFlow) GetActive() IdentityCredentialsType { // GetActiveOk returns a tuple with the Active field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *LoginFlow) GetActiveOk() (*IdentityCredentialsType, bool) { +func (o *LoginFlow) GetActiveOk() (*string, bool) { if o == nil || o.Active == nil { return nil, false } @@ -100,8 +101,8 @@ func (o *LoginFlow) HasActive() bool { return false } -// SetActive gets a reference to the given IdentityCredentialsType and assigns it to the Active field. -func (o *LoginFlow) SetActive(v IdentityCredentialsType) { +// SetActive gets a reference to the given string and assigns it to the Active field. +func (o *LoginFlow) SetActive(v string) { o.Active = &v } diff --git a/internal/client-go/model_registration_flow.go b/internal/client-go/model_registration_flow.go index 85d0365ddcb1..71ab2c03ebe2 100644 --- a/internal/client-go/model_registration_flow.go +++ b/internal/client-go/model_registration_flow.go @@ -18,7 +18,8 @@ import ( // RegistrationFlow struct for RegistrationFlow type RegistrationFlow struct { - Active *IdentityCredentialsType `json:"active,omitempty"` + // Active, if set, contains the registration method that is being used. It is initially not set. password CredentialsTypePassword oidc CredentialsTypeOIDC totp CredentialsTypeTOTP lookup_secret CredentialsTypeLookup webauthn CredentialsTypeWebAuthn code CredentialsTypeCodeAuth link_recovery CredentialsTypeRecoveryLink CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). It is not used within the credentials object itself. code_recovery CredentialsTypeRecoveryCode + Active *string `json:"active,omitempty"` // ExpiresAt is the time (UTC) when the flow expires. If the user still wishes to log in, a new flow has to be initiated. ExpiresAt time.Time `json:"expires_at"` // 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= @@ -69,9 +70,9 @@ func NewRegistrationFlowWithDefaults() *RegistrationFlow { } // GetActive returns the Active field value if set, zero value otherwise. -func (o *RegistrationFlow) GetActive() IdentityCredentialsType { +func (o *RegistrationFlow) GetActive() string { if o == nil || o.Active == nil { - var ret IdentityCredentialsType + var ret string return ret } return *o.Active @@ -79,7 +80,7 @@ func (o *RegistrationFlow) GetActive() IdentityCredentialsType { // GetActiveOk returns a tuple with the Active field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *RegistrationFlow) GetActiveOk() (*IdentityCredentialsType, bool) { +func (o *RegistrationFlow) GetActiveOk() (*string, bool) { if o == nil || o.Active == nil { return nil, false } @@ -95,8 +96,8 @@ func (o *RegistrationFlow) HasActive() bool { return false } -// SetActive gets a reference to the given IdentityCredentialsType and assigns it to the Active field. -func (o *RegistrationFlow) SetActive(v IdentityCredentialsType) { +// SetActive gets a reference to the given string and assigns it to the Active field. +func (o *RegistrationFlow) SetActive(v string) { o.Active = &v } diff --git a/internal/client-go/model_update_identity_body.go b/internal/client-go/model_update_identity_body.go index 3f4ac7903207..9009e2a88b30 100644 --- a/internal/client-go/model_update_identity_body.go +++ b/internal/client-go/model_update_identity_body.go @@ -23,8 +23,9 @@ type UpdateIdentityBody struct { // Store metadata about the identity which the identity itself can see when calling for example the session endpoint. Do not store sensitive information (e.g. credit score) about the identity in this field. MetadataPublic interface{} `json:"metadata_public,omitempty"` // SchemaID is the ID of the JSON Schema to be used for validating the identity's traits. If set will update the Identity's SchemaID. - SchemaId string `json:"schema_id"` - State IdentityState `json:"state"` + SchemaId string `json:"schema_id"` + // State is the identity's state. active StateActive inactive StateInactive + State string `json:"state"` // Traits represent an identity's traits. The identity is able to create, modify, and delete traits in a self-service manner. The input will always be validated against the JSON Schema defined in `schema_id`. Traits map[string]interface{} `json:"traits"` } @@ -33,7 +34,7 @@ type UpdateIdentityBody struct { // 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 NewUpdateIdentityBody(schemaId string, state IdentityState, traits map[string]interface{}) *UpdateIdentityBody { +func NewUpdateIdentityBody(schemaId string, state string, traits map[string]interface{}) *UpdateIdentityBody { this := UpdateIdentityBody{} this.SchemaId = schemaId this.State = state @@ -172,9 +173,9 @@ func (o *UpdateIdentityBody) SetSchemaId(v string) { } // GetState returns the State field value -func (o *UpdateIdentityBody) GetState() IdentityState { +func (o *UpdateIdentityBody) GetState() string { if o == nil { - var ret IdentityState + var ret string return ret } @@ -183,7 +184,7 @@ func (o *UpdateIdentityBody) GetState() IdentityState { // GetStateOk returns a tuple with the State field value // and a boolean to check if the value has been set. -func (o *UpdateIdentityBody) GetStateOk() (*IdentityState, bool) { +func (o *UpdateIdentityBody) GetStateOk() (*string, bool) { if o == nil { return nil, false } @@ -191,7 +192,7 @@ func (o *UpdateIdentityBody) GetStateOk() (*IdentityState, bool) { } // SetState sets field value -func (o *UpdateIdentityBody) SetState(v IdentityState) { +func (o *UpdateIdentityBody) SetState(v string) { o.State = v } diff --git a/internal/httpclient/.openapi-generator/FILES b/internal/httpclient/.openapi-generator/FILES index f2d48ddec66c..0f14f1ccb470 100644 --- a/internal/httpclient/.openapi-generator/FILES +++ b/internal/httpclient/.openapi-generator/FILES @@ -44,11 +44,9 @@ docs/IdentityCredentialsCode.md docs/IdentityCredentialsOidc.md docs/IdentityCredentialsOidcProvider.md docs/IdentityCredentialsPassword.md -docs/IdentityCredentialsType.md docs/IdentityPatch.md docs/IdentityPatchResponse.md docs/IdentitySchemaContainer.md -docs/IdentityState.md docs/IdentityWithCredentials.md docs/IdentityWithCredentialsOidc.md docs/IdentityWithCredentialsOidcConfig.md @@ -163,11 +161,9 @@ model_identity_credentials_code.go model_identity_credentials_oidc.go model_identity_credentials_oidc_provider.go model_identity_credentials_password.go -model_identity_credentials_type.go model_identity_patch.go model_identity_patch_response.go model_identity_schema_container.go -model_identity_state.go model_identity_with_credentials.go model_identity_with_credentials_oidc.go model_identity_with_credentials_oidc_config.go diff --git a/internal/httpclient/README.md b/internal/httpclient/README.md index 7fedaba9d3e5..7f5de7166ef1 100644 --- a/internal/httpclient/README.md +++ b/internal/httpclient/README.md @@ -168,11 +168,9 @@ Class | Method | HTTP request | Description - [IdentityCredentialsOidc](docs/IdentityCredentialsOidc.md) - [IdentityCredentialsOidcProvider](docs/IdentityCredentialsOidcProvider.md) - [IdentityCredentialsPassword](docs/IdentityCredentialsPassword.md) - - [IdentityCredentialsType](docs/IdentityCredentialsType.md) - [IdentityPatch](docs/IdentityPatch.md) - [IdentityPatchResponse](docs/IdentityPatchResponse.md) - [IdentitySchemaContainer](docs/IdentitySchemaContainer.md) - - [IdentityState](docs/IdentityState.md) - [IdentityWithCredentials](docs/IdentityWithCredentials.md) - [IdentityWithCredentialsOidc](docs/IdentityWithCredentialsOidc.md) - [IdentityWithCredentialsOidcConfig](docs/IdentityWithCredentialsOidcConfig.md) diff --git a/internal/httpclient/api_identity.go b/internal/httpclient/api_identity.go index 7ebc9fc7ca44..bc1b675876fb 100644 --- a/internal/httpclient/api_identity.go +++ b/internal/httpclient/api_identity.go @@ -114,7 +114,7 @@ type IdentityApi interface { You can only delete second factor (aal2) credentials. * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). * @param id ID is the identity's ID. - * @param type_ Type is the credential's Type. One of totp, webauthn, lookup + * @param type_ Type is the type of credentials to be deleted. password CredentialsTypePassword oidc CredentialsTypeOIDC totp CredentialsTypeTOTP lookup_secret CredentialsTypeLookup webauthn CredentialsTypeWebAuthn code CredentialsTypeCodeAuth link_recovery CredentialsTypeRecoveryLink CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). It is not used within the credentials object itself. code_recovery CredentialsTypeRecoveryCode * @return IdentityApiApiDeleteIdentityCredentialsRequest */ DeleteIdentityCredentials(ctx context.Context, id string, type_ string) IdentityApiApiDeleteIdentityCredentialsRequest @@ -1077,7 +1077,7 @@ func (r IdentityApiApiDeleteIdentityCredentialsRequest) Execute() (*http.Respons You can only delete second factor (aal2) credentials. - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @param id ID is the identity's ID. - - @param type_ Type is the credential's Type. One of totp, webauthn, lookup + - @param type_ Type is the type of credentials to be deleted. password CredentialsTypePassword oidc CredentialsTypeOIDC totp CredentialsTypeTOTP lookup_secret CredentialsTypeLookup webauthn CredentialsTypeWebAuthn code CredentialsTypeCodeAuth link_recovery CredentialsTypeRecoveryLink CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). It is not used within the credentials object itself. code_recovery CredentialsTypeRecoveryCode - @return IdentityApiApiDeleteIdentityCredentialsRequest */ func (a *IdentityApiService) DeleteIdentityCredentials(ctx context.Context, id string, type_ string) IdentityApiApiDeleteIdentityCredentialsRequest { diff --git a/internal/httpclient/model_create_identity_body.go b/internal/httpclient/model_create_identity_body.go index 8a7c7d3c369f..177317c62d2e 100644 --- a/internal/httpclient/model_create_identity_body.go +++ b/internal/httpclient/model_create_identity_body.go @@ -25,8 +25,9 @@ type CreateIdentityBody struct { // RecoveryAddresses contains all the addresses that can be used to recover an identity. Use this structure to import recovery addresses for an identity. Please keep in mind that the address needs to be represented in the Identity Schema or this field will be overwritten on the next identity update. RecoveryAddresses []RecoveryIdentityAddress `json:"recovery_addresses,omitempty"` // SchemaID is the ID of the JSON Schema to be used for validating the identity's traits. - SchemaId string `json:"schema_id"` - State *IdentityState `json:"state,omitempty"` + SchemaId string `json:"schema_id"` + // State is the identity's state. active StateActive inactive StateInactive + State *string `json:"state,omitempty"` // Traits represent an identity's traits. The identity is able to create, modify, and delete traits in a self-service manner. The input will always be validated against the JSON Schema defined in `schema_url`. Traits map[string]interface{} `json:"traits"` // VerifiableAddresses contains all the addresses that can be verified by the user. Use this structure to import verified addresses for an identity. Please keep in mind that the address needs to be represented in the Identity Schema or this field will be overwritten on the next identity update. @@ -207,9 +208,9 @@ func (o *CreateIdentityBody) SetSchemaId(v string) { } // GetState returns the State field value if set, zero value otherwise. -func (o *CreateIdentityBody) GetState() IdentityState { +func (o *CreateIdentityBody) GetState() string { if o == nil || o.State == nil { - var ret IdentityState + var ret string return ret } return *o.State @@ -217,7 +218,7 @@ func (o *CreateIdentityBody) GetState() IdentityState { // GetStateOk returns a tuple with the State field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *CreateIdentityBody) GetStateOk() (*IdentityState, bool) { +func (o *CreateIdentityBody) GetStateOk() (*string, bool) { if o == nil || o.State == nil { return nil, false } @@ -233,8 +234,8 @@ func (o *CreateIdentityBody) HasState() bool { return false } -// SetState gets a reference to the given IdentityState and assigns it to the State field. -func (o *CreateIdentityBody) SetState(v IdentityState) { +// SetState gets a reference to the given string and assigns it to the State field. +func (o *CreateIdentityBody) SetState(v string) { o.State = &v } diff --git a/internal/httpclient/model_identity.go b/internal/httpclient/model_identity.go index 282821f468ed..cd939965877d 100644 --- a/internal/httpclient/model_identity.go +++ b/internal/httpclient/model_identity.go @@ -34,9 +34,10 @@ type Identity struct { // SchemaID is the ID of the JSON Schema to be used for validating the identity's traits. SchemaId string `json:"schema_id"` // SchemaURL is the URL of the endpoint where the identity's traits schema can be fetched from. format: url - SchemaUrl string `json:"schema_url"` - State *IdentityState `json:"state,omitempty"` - StateChangedAt *time.Time `json:"state_changed_at,omitempty"` + SchemaUrl string `json:"schema_url"` + // State is the identity's state. This value has currently no effect. active StateActive inactive StateInactive + State *string `json:"state,omitempty"` + StateChangedAt *time.Time `json:"state_changed_at,omitempty"` // Traits represent an identity's traits. The identity is able to create, modify, and delete traits in a self-service manner. The input will always be validated against the JSON Schema defined in `schema_url`. Traits interface{} `json:"traits"` // UpdatedAt is a helper struct field for gobuffalo.pop. @@ -344,9 +345,9 @@ func (o *Identity) SetSchemaUrl(v string) { } // GetState returns the State field value if set, zero value otherwise. -func (o *Identity) GetState() IdentityState { +func (o *Identity) GetState() string { if o == nil || o.State == nil { - var ret IdentityState + var ret string return ret } return *o.State @@ -354,7 +355,7 @@ func (o *Identity) GetState() IdentityState { // GetStateOk returns a tuple with the State field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *Identity) GetStateOk() (*IdentityState, bool) { +func (o *Identity) GetStateOk() (*string, bool) { if o == nil || o.State == nil { return nil, false } @@ -370,8 +371,8 @@ func (o *Identity) HasState() bool { return false } -// SetState gets a reference to the given IdentityState and assigns it to the State field. -func (o *Identity) SetState(v IdentityState) { +// SetState gets a reference to the given string and assigns it to the State field. +func (o *Identity) SetState(v string) { o.State = &v } diff --git a/internal/httpclient/model_identity_credentials.go b/internal/httpclient/model_identity_credentials.go index 16d0a90a6330..5b454383d520 100644 --- a/internal/httpclient/model_identity_credentials.go +++ b/internal/httpclient/model_identity_credentials.go @@ -22,8 +22,9 @@ type IdentityCredentials struct { // CreatedAt is a helper struct field for gobuffalo.pop. CreatedAt *time.Time `json:"created_at,omitempty"` // Identifiers represents a list of unique identifiers this credential type matches. - Identifiers []string `json:"identifiers,omitempty"` - Type *IdentityCredentialsType `json:"type,omitempty"` + Identifiers []string `json:"identifiers,omitempty"` + // Type discriminates between different types of credentials. password CredentialsTypePassword oidc CredentialsTypeOIDC totp CredentialsTypeTOTP lookup_secret CredentialsTypeLookup webauthn CredentialsTypeWebAuthn code CredentialsTypeCodeAuth link_recovery CredentialsTypeRecoveryLink CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). It is not used within the credentials object itself. code_recovery CredentialsTypeRecoveryCode + Type *string `json:"type,omitempty"` // UpdatedAt is a helper struct field for gobuffalo.pop. UpdatedAt *time.Time `json:"updated_at,omitempty"` // Version refers to the version of the credential. Useful when changing the config schema. @@ -144,9 +145,9 @@ func (o *IdentityCredentials) SetIdentifiers(v []string) { } // GetType returns the Type field value if set, zero value otherwise. -func (o *IdentityCredentials) GetType() IdentityCredentialsType { +func (o *IdentityCredentials) GetType() string { if o == nil || o.Type == nil { - var ret IdentityCredentialsType + var ret string return ret } return *o.Type @@ -154,7 +155,7 @@ func (o *IdentityCredentials) GetType() IdentityCredentialsType { // GetTypeOk returns a tuple with the Type field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *IdentityCredentials) GetTypeOk() (*IdentityCredentialsType, bool) { +func (o *IdentityCredentials) GetTypeOk() (*string, bool) { if o == nil || o.Type == nil { return nil, false } @@ -170,8 +171,8 @@ func (o *IdentityCredentials) HasType() bool { return false } -// SetType gets a reference to the given IdentityCredentialsType and assigns it to the Type field. -func (o *IdentityCredentials) SetType(v IdentityCredentialsType) { +// SetType gets a reference to the given string and assigns it to the Type field. +func (o *IdentityCredentials) SetType(v string) { o.Type = &v } diff --git a/internal/httpclient/model_identity_credentials_type.go b/internal/httpclient/model_identity_credentials_type.go deleted file mode 100644 index a9d01c54e796..000000000000 --- a/internal/httpclient/model_identity_credentials_type.go +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Ory Identities API - * - * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. - * - * API version: - * Contact: office@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" - "fmt" -) - -// IdentityCredentialsType and so on. -type IdentityCredentialsType string - -// List of identityCredentialsType -const ( - IDENTITYCREDENTIALSTYPE_PASSWORD IdentityCredentialsType = "password" - IDENTITYCREDENTIALSTYPE_TOTP IdentityCredentialsType = "totp" - IDENTITYCREDENTIALSTYPE_OIDC IdentityCredentialsType = "oidc" - IDENTITYCREDENTIALSTYPE_WEBAUTHN IdentityCredentialsType = "webauthn" - IDENTITYCREDENTIALSTYPE_LOOKUP_SECRET IdentityCredentialsType = "lookup_secret" - IDENTITYCREDENTIALSTYPE_CODE IdentityCredentialsType = "code" -) - -func (v *IdentityCredentialsType) UnmarshalJSON(src []byte) error { - var value string - err := json.Unmarshal(src, &value) - if err != nil { - return err - } - enumTypeValue := IdentityCredentialsType(value) - for _, existing := range []IdentityCredentialsType{"password", "totp", "oidc", "webauthn", "lookup_secret", "code"} { - if existing == enumTypeValue { - *v = enumTypeValue - return nil - } - } - - return fmt.Errorf("%+v is not a valid IdentityCredentialsType", value) -} - -// Ptr returns reference to identityCredentialsType value -func (v IdentityCredentialsType) Ptr() *IdentityCredentialsType { - return &v -} - -type NullableIdentityCredentialsType struct { - value *IdentityCredentialsType - isSet bool -} - -func (v NullableIdentityCredentialsType) Get() *IdentityCredentialsType { - return v.value -} - -func (v *NullableIdentityCredentialsType) Set(val *IdentityCredentialsType) { - v.value = val - v.isSet = true -} - -func (v NullableIdentityCredentialsType) IsSet() bool { - return v.isSet -} - -func (v *NullableIdentityCredentialsType) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableIdentityCredentialsType(val *IdentityCredentialsType) *NullableIdentityCredentialsType { - return &NullableIdentityCredentialsType{value: val, isSet: true} -} - -func (v NullableIdentityCredentialsType) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableIdentityCredentialsType) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/httpclient/model_identity_state.go b/internal/httpclient/model_identity_state.go deleted file mode 100644 index 239a49c65fe5..000000000000 --- a/internal/httpclient/model_identity_state.go +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Ory Identities API - * - * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. - * - * API version: - * Contact: office@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "encoding/json" - "fmt" -) - -// IdentityState The state can either be `active` or `inactive`. -type IdentityState string - -// List of identityState -const ( - IDENTITYSTATE_ACTIVE IdentityState = "active" - IDENTITYSTATE_INACTIVE IdentityState = "inactive" -) - -func (v *IdentityState) UnmarshalJSON(src []byte) error { - var value string - err := json.Unmarshal(src, &value) - if err != nil { - return err - } - enumTypeValue := IdentityState(value) - for _, existing := range []IdentityState{"active", "inactive"} { - if existing == enumTypeValue { - *v = enumTypeValue - return nil - } - } - - return fmt.Errorf("%+v is not a valid IdentityState", value) -} - -// Ptr returns reference to identityState value -func (v IdentityState) Ptr() *IdentityState { - return &v -} - -type NullableIdentityState struct { - value *IdentityState - isSet bool -} - -func (v NullableIdentityState) Get() *IdentityState { - return v.value -} - -func (v *NullableIdentityState) Set(val *IdentityState) { - v.value = val - v.isSet = true -} - -func (v NullableIdentityState) IsSet() bool { - return v.isSet -} - -func (v *NullableIdentityState) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableIdentityState(val *IdentityState) *NullableIdentityState { - return &NullableIdentityState{value: val, isSet: true} -} - -func (v NullableIdentityState) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableIdentityState) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/internal/httpclient/model_login_flow.go b/internal/httpclient/model_login_flow.go index 161377f6b680..b36abc379568 100644 --- a/internal/httpclient/model_login_flow.go +++ b/internal/httpclient/model_login_flow.go @@ -18,7 +18,8 @@ import ( // LoginFlow This object represents a login flow. A login flow is initiated at the \"Initiate Login API / Browser Flow\" endpoint by a client. Once a login flow is completed successfully, a session cookie or session token will be issued. type LoginFlow struct { - Active *IdentityCredentialsType `json:"active,omitempty"` + // The active login method If set contains the login method used. If the flow is new, it is unset. password CredentialsTypePassword oidc CredentialsTypeOIDC totp CredentialsTypeTOTP lookup_secret CredentialsTypeLookup webauthn CredentialsTypeWebAuthn code CredentialsTypeCodeAuth link_recovery CredentialsTypeRecoveryLink CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). It is not used within the credentials object itself. code_recovery CredentialsTypeRecoveryCode + Active *string `json:"active,omitempty"` // CreatedAt is a helper struct field for gobuffalo.pop. CreatedAt *time.Time `json:"created_at,omitempty"` // ExpiresAt is the time (UTC) when the flow expires. If the user still wishes to log in, a new flow has to be initiated. @@ -74,9 +75,9 @@ func NewLoginFlowWithDefaults() *LoginFlow { } // GetActive returns the Active field value if set, zero value otherwise. -func (o *LoginFlow) GetActive() IdentityCredentialsType { +func (o *LoginFlow) GetActive() string { if o == nil || o.Active == nil { - var ret IdentityCredentialsType + var ret string return ret } return *o.Active @@ -84,7 +85,7 @@ func (o *LoginFlow) GetActive() IdentityCredentialsType { // GetActiveOk returns a tuple with the Active field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *LoginFlow) GetActiveOk() (*IdentityCredentialsType, bool) { +func (o *LoginFlow) GetActiveOk() (*string, bool) { if o == nil || o.Active == nil { return nil, false } @@ -100,8 +101,8 @@ func (o *LoginFlow) HasActive() bool { return false } -// SetActive gets a reference to the given IdentityCredentialsType and assigns it to the Active field. -func (o *LoginFlow) SetActive(v IdentityCredentialsType) { +// SetActive gets a reference to the given string and assigns it to the Active field. +func (o *LoginFlow) SetActive(v string) { o.Active = &v } diff --git a/internal/httpclient/model_registration_flow.go b/internal/httpclient/model_registration_flow.go index 85d0365ddcb1..71ab2c03ebe2 100644 --- a/internal/httpclient/model_registration_flow.go +++ b/internal/httpclient/model_registration_flow.go @@ -18,7 +18,8 @@ import ( // RegistrationFlow struct for RegistrationFlow type RegistrationFlow struct { - Active *IdentityCredentialsType `json:"active,omitempty"` + // Active, if set, contains the registration method that is being used. It is initially not set. password CredentialsTypePassword oidc CredentialsTypeOIDC totp CredentialsTypeTOTP lookup_secret CredentialsTypeLookup webauthn CredentialsTypeWebAuthn code CredentialsTypeCodeAuth link_recovery CredentialsTypeRecoveryLink CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). It is not used within the credentials object itself. code_recovery CredentialsTypeRecoveryCode + Active *string `json:"active,omitempty"` // ExpiresAt is the time (UTC) when the flow expires. If the user still wishes to log in, a new flow has to be initiated. ExpiresAt time.Time `json:"expires_at"` // 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= @@ -69,9 +70,9 @@ func NewRegistrationFlowWithDefaults() *RegistrationFlow { } // GetActive returns the Active field value if set, zero value otherwise. -func (o *RegistrationFlow) GetActive() IdentityCredentialsType { +func (o *RegistrationFlow) GetActive() string { if o == nil || o.Active == nil { - var ret IdentityCredentialsType + var ret string return ret } return *o.Active @@ -79,7 +80,7 @@ func (o *RegistrationFlow) GetActive() IdentityCredentialsType { // GetActiveOk returns a tuple with the Active field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *RegistrationFlow) GetActiveOk() (*IdentityCredentialsType, bool) { +func (o *RegistrationFlow) GetActiveOk() (*string, bool) { if o == nil || o.Active == nil { return nil, false } @@ -95,8 +96,8 @@ func (o *RegistrationFlow) HasActive() bool { return false } -// SetActive gets a reference to the given IdentityCredentialsType and assigns it to the Active field. -func (o *RegistrationFlow) SetActive(v IdentityCredentialsType) { +// SetActive gets a reference to the given string and assigns it to the Active field. +func (o *RegistrationFlow) SetActive(v string) { o.Active = &v } diff --git a/internal/httpclient/model_update_identity_body.go b/internal/httpclient/model_update_identity_body.go index 3f4ac7903207..9009e2a88b30 100644 --- a/internal/httpclient/model_update_identity_body.go +++ b/internal/httpclient/model_update_identity_body.go @@ -23,8 +23,9 @@ type UpdateIdentityBody struct { // Store metadata about the identity which the identity itself can see when calling for example the session endpoint. Do not store sensitive information (e.g. credit score) about the identity in this field. MetadataPublic interface{} `json:"metadata_public,omitempty"` // SchemaID is the ID of the JSON Schema to be used for validating the identity's traits. If set will update the Identity's SchemaID. - SchemaId string `json:"schema_id"` - State IdentityState `json:"state"` + SchemaId string `json:"schema_id"` + // State is the identity's state. active StateActive inactive StateInactive + State string `json:"state"` // Traits represent an identity's traits. The identity is able to create, modify, and delete traits in a self-service manner. The input will always be validated against the JSON Schema defined in `schema_id`. Traits map[string]interface{} `json:"traits"` } @@ -33,7 +34,7 @@ type UpdateIdentityBody struct { // 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 NewUpdateIdentityBody(schemaId string, state IdentityState, traits map[string]interface{}) *UpdateIdentityBody { +func NewUpdateIdentityBody(schemaId string, state string, traits map[string]interface{}) *UpdateIdentityBody { this := UpdateIdentityBody{} this.SchemaId = schemaId this.State = state @@ -172,9 +173,9 @@ func (o *UpdateIdentityBody) SetSchemaId(v string) { } // GetState returns the State field value -func (o *UpdateIdentityBody) GetState() IdentityState { +func (o *UpdateIdentityBody) GetState() string { if o == nil { - var ret IdentityState + var ret string return ret } @@ -183,7 +184,7 @@ func (o *UpdateIdentityBody) GetState() IdentityState { // GetStateOk returns a tuple with the State field value // and a boolean to check if the value has been set. -func (o *UpdateIdentityBody) GetStateOk() (*IdentityState, bool) { +func (o *UpdateIdentityBody) GetStateOk() (*string, bool) { if o == nil { return nil, false } @@ -191,7 +192,7 @@ func (o *UpdateIdentityBody) GetStateOk() (*IdentityState, bool) { } // SetState sets field value -func (o *UpdateIdentityBody) SetState(v IdentityState) { +func (o *UpdateIdentityBody) SetState(v string) { o.State = v } diff --git a/spec/api.json b/spec/api.json index 0ea8c9ef5ba6..212287de0895 100644 --- a/spec/api.json +++ b/spec/api.json @@ -675,7 +675,13 @@ "type": "string" }, "state": { - "$ref": "#/components/schemas/identityState" + "description": "State is the identity's state.\nactive StateActive\ninactive StateInactive", + "enum": [ + "active", + "inactive" + ], + "type": "string", + "x-go-enum-desc": "active StateActive\ninactive StateInactive" }, "traits": { "description": "Traits represent an identity's traits. The identity is able to create, modify, and delete traits\nin a self-service manner. The input will always be validated against the JSON Schema defined\nin `schema_url`.", @@ -938,7 +944,13 @@ "type": "string" }, "state": { - "$ref": "#/components/schemas/identityState" + "description": "State is the identity's state.\n\nThis value has currently no effect.\nactive StateActive\ninactive StateInactive", + "enum": [ + "active", + "inactive" + ], + "type": "string", + "x-go-enum-desc": "active StateActive\ninactive StateInactive" }, "state_changed_at": { "$ref": "#/components/schemas/nullTime" @@ -988,7 +1000,19 @@ "type": "array" }, "type": { - "$ref": "#/components/schemas/identityCredentialsType" + "description": "Type discriminates between different types of credentials.\npassword CredentialsTypePassword\noidc CredentialsTypeOIDC\ntotp CredentialsTypeTOTP\nlookup_secret CredentialsTypeLookup\nwebauthn CredentialsTypeWebAuthn\ncode CredentialsTypeCodeAuth\nlink_recovery CredentialsTypeRecoveryLink CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). It is not used within the credentials object itself.\ncode_recovery CredentialsTypeRecoveryCode", + "enum": [ + "password", + "oidc", + "totp", + "lookup_secret", + "webauthn", + "code", + "link_recovery", + "code_recovery" + ], + "type": "string", + "x-go-enum-desc": "password CredentialsTypePassword\noidc CredentialsTypeOIDC\ntotp CredentialsTypeTOTP\nlookup_secret CredentialsTypeLookup\nwebauthn CredentialsTypeWebAuthn\ncode CredentialsTypeCodeAuth\nlink_recovery CredentialsTypeRecoveryLink CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). It is not used within the credentials object itself.\ncode_recovery CredentialsTypeRecoveryCode" }, "updated_at": { "description": "UpdatedAt is a helper struct field for gobuffalo.pop.", @@ -1062,19 +1086,6 @@ "title": "CredentialsPassword is contains the configuration for credentials of the type password.", "type": "object" }, - "identityCredentialsType": { - "description": "and so on.", - "enum": [ - "password", - "totp", - "oidc", - "webauthn", - "lookup_secret", - "code" - ], - "title": "CredentialsType represents several different credential types, like password credentials, passwordless credentials,", - "type": "string" - }, "identityPatch": { "description": "Payload for patching an identity", "properties": { @@ -1138,15 +1149,6 @@ }, "type": "array" }, - "identityState": { - "description": "The state can either be `active` or `inactive`.", - "enum": [ - "active", - "inactive" - ], - "title": "An Identity's State", - "type": "string" - }, "identityTraits": { "description": "Traits represent an identity's traits. The identity is able to create, modify, and delete traits\nin a self-service manner. The input will always be validated against the JSON Schema defined\nin `schema_url`." }, @@ -1271,7 +1273,19 @@ "description": "This object represents a login flow. A login flow is initiated at the \"Initiate Login API / Browser Flow\"\nendpoint by a client.\n\nOnce a login flow is completed successfully, a session cookie or session token will be issued.", "properties": { "active": { - "$ref": "#/components/schemas/identityCredentialsType" + "description": "The active login method\n\nIf set contains the login method used. If the flow is new, it is unset.\npassword CredentialsTypePassword\noidc CredentialsTypeOIDC\ntotp CredentialsTypeTOTP\nlookup_secret CredentialsTypeLookup\nwebauthn CredentialsTypeWebAuthn\ncode CredentialsTypeCodeAuth\nlink_recovery CredentialsTypeRecoveryLink CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). It is not used within the credentials object itself.\ncode_recovery CredentialsTypeRecoveryCode", + "enum": [ + "password", + "oidc", + "totp", + "lookup_secret", + "webauthn", + "code", + "link_recovery", + "code_recovery" + ], + "type": "string", + "x-go-enum-desc": "password CredentialsTypePassword\noidc CredentialsTypeOIDC\ntotp CredentialsTypeTOTP\nlookup_secret CredentialsTypeLookup\nwebauthn CredentialsTypeWebAuthn\ncode CredentialsTypeCodeAuth\nlink_recovery CredentialsTypeRecoveryLink CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). It is not used within the credentials object itself.\ncode_recovery CredentialsTypeRecoveryCode" }, "created_at": { "description": "CreatedAt is a helper struct field for gobuffalo.pop.", @@ -1703,7 +1717,19 @@ "registrationFlow": { "properties": { "active": { - "$ref": "#/components/schemas/identityCredentialsType" + "description": "Active, if set, contains the registration method that is being used. It is initially\nnot set.\npassword CredentialsTypePassword\noidc CredentialsTypeOIDC\ntotp CredentialsTypeTOTP\nlookup_secret CredentialsTypeLookup\nwebauthn CredentialsTypeWebAuthn\ncode CredentialsTypeCodeAuth\nlink_recovery CredentialsTypeRecoveryLink CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). It is not used within the credentials object itself.\ncode_recovery CredentialsTypeRecoveryCode", + "enum": [ + "password", + "oidc", + "totp", + "lookup_secret", + "webauthn", + "code", + "link_recovery", + "code_recovery" + ], + "type": "string", + "x-go-enum-desc": "password CredentialsTypePassword\noidc CredentialsTypeOIDC\ntotp CredentialsTypeTOTP\nlookup_secret CredentialsTypeLookup\nwebauthn CredentialsTypeWebAuthn\ncode CredentialsTypeCodeAuth\nlink_recovery CredentialsTypeRecoveryLink CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). It is not used within the credentials object itself.\ncode_recovery CredentialsTypeRecoveryCode" }, "expires_at": { "description": "ExpiresAt is the time (UTC) when the flow expires. If the user still wishes to log in,\na new flow has to be initiated.", @@ -2480,7 +2506,13 @@ "type": "string" }, "state": { - "$ref": "#/components/schemas/identityState" + "description": "State is the identity's state.\nactive StateActive\ninactive StateInactive", + "enum": [ + "active", + "inactive" + ], + "type": "string", + "x-go-enum-desc": "active StateActive\ninactive StateInactive" }, "traits": { "description": "Traits represent an identity's traits. The identity is able to create, modify, and delete traits\nin a self-service manner. The input will always be validated against the JSON Schema defined\nin `schema_id`.", @@ -3833,11 +3865,13 @@ "items": { "enum": [ "password", - "totp", "oidc", - "webauthn", + "totp", "lookup_secret", - "code" + "webauthn", + "code", + "link_recovery", + "code_recovery" ], "type": "string" }, @@ -4075,18 +4109,24 @@ } }, { - "description": "Type is the credential's Type.\nOne of totp, webauthn, lookup", + "description": "Type is the type of credentials to be deleted.\npassword CredentialsTypePassword\noidc CredentialsTypeOIDC\ntotp CredentialsTypeTOTP\nlookup_secret CredentialsTypeLookup\nwebauthn CredentialsTypeWebAuthn\ncode CredentialsTypeCodeAuth\nlink_recovery CredentialsTypeRecoveryLink CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). It is not used within the credentials object itself.\ncode_recovery CredentialsTypeRecoveryCode", "in": "path", "name": "type", "required": true, "schema": { "enum": [ + "password", + "oidc", "totp", + "lookup_secret", "webauthn", - "lookup" + "code", + "link_recovery", + "code_recovery" ], "type": "string" - } + }, + "x-go-enum-desc": "password CredentialsTypePassword\noidc CredentialsTypeOIDC\ntotp CredentialsTypeTOTP\nlookup_secret CredentialsTypeLookup\nwebauthn CredentialsTypeWebAuthn\ncode CredentialsTypeCodeAuth\nlink_recovery CredentialsTypeRecoveryLink CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). It is not used within the credentials object itself.\ncode_recovery CredentialsTypeRecoveryCode" } ], "responses": { diff --git a/spec/swagger.json b/spec/swagger.json index ea6f219adb35..445df73fabf7 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -417,6 +417,16 @@ { "type": "array", "items": { + "enum": [ + "password", + "oidc", + "totp", + "lookup_secret", + "webauthn", + "code", + "link_recovery", + "code_recovery" + ], "type": "string" }, "description": "Include Credentials in Response\n\nInclude any credential, for example `password` or `oidc`, in the response. When set to `oidc`, This will return\nthe initial OAuth 2.0 Access Token, OAuth 2.0 Refresh Token and the OpenID Connect ID Token if available.", @@ -667,12 +677,18 @@ }, { "enum": [ + "password", + "oidc", "totp", + "lookup_secret", "webauthn", - "lookup" + "code", + "link_recovery", + "code_recovery" ], "type": "string", - "description": "Type is the credential's Type.\nOne of totp, webauthn, lookup", + "x-go-enum-desc": "password CredentialsTypePassword\noidc CredentialsTypeOIDC\ntotp CredentialsTypeTOTP\nlookup_secret CredentialsTypeLookup\nwebauthn CredentialsTypeWebAuthn\ncode CredentialsTypeCodeAuth\nlink_recovery CredentialsTypeRecoveryLink CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). It is not used within the credentials object itself.\ncode_recovery CredentialsTypeRecoveryCode", + "description": "Type is the type of credentials to be deleted.\npassword CredentialsTypePassword\noidc CredentialsTypeOIDC\ntotp CredentialsTypeTOTP\nlookup_secret CredentialsTypeLookup\nwebauthn CredentialsTypeWebAuthn\ncode CredentialsTypeCodeAuth\nlink_recovery CredentialsTypeRecoveryLink CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). It is not used within the credentials object itself.\ncode_recovery CredentialsTypeRecoveryCode", "name": "type", "in": "path", "required": true @@ -3764,7 +3780,13 @@ "type": "string" }, "state": { - "$ref": "#/definitions/identityState" + "description": "State is the identity's state.\nactive StateActive\ninactive StateInactive", + "type": "string", + "enum": [ + "active", + "inactive" + ], + "x-go-enum-desc": "active StateActive\ninactive StateInactive" }, "traits": { "description": "Traits represent an identity's traits. The identity is able to create, modify, and delete traits\nin a self-service manner. The input will always be validated against the JSON Schema defined\nin `schema_url`.", @@ -4031,7 +4053,13 @@ "type": "string" }, "state": { - "$ref": "#/definitions/identityState" + "description": "State is the identity's state.\n\nThis value has currently no effect.\nactive StateActive\ninactive StateInactive", + "type": "string", + "enum": [ + "active", + "inactive" + ], + "x-go-enum-desc": "active StateActive\ninactive StateInactive" }, "state_changed_at": { "$ref": "#/definitions/nullTime" @@ -4074,7 +4102,19 @@ } }, "type": { - "$ref": "#/definitions/identityCredentialsType" + "description": "Type discriminates between different types of credentials.\npassword CredentialsTypePassword\noidc CredentialsTypeOIDC\ntotp CredentialsTypeTOTP\nlookup_secret CredentialsTypeLookup\nwebauthn CredentialsTypeWebAuthn\ncode CredentialsTypeCodeAuth\nlink_recovery CredentialsTypeRecoveryLink CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). It is not used within the credentials object itself.\ncode_recovery CredentialsTypeRecoveryCode", + "type": "string", + "enum": [ + "password", + "oidc", + "totp", + "lookup_secret", + "webauthn", + "code", + "link_recovery", + "code_recovery" + ], + "x-go-enum-desc": "password CredentialsTypePassword\noidc CredentialsTypeOIDC\ntotp CredentialsTypeTOTP\nlookup_secret CredentialsTypeLookup\nwebauthn CredentialsTypeWebAuthn\ncode CredentialsTypeCodeAuth\nlink_recovery CredentialsTypeRecoveryLink CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). It is not used within the credentials object itself.\ncode_recovery CredentialsTypeRecoveryCode" }, "updated_at": { "description": "UpdatedAt is a helper struct field for gobuffalo.pop.", @@ -4147,11 +4187,6 @@ } } }, - "identityCredentialsType": { - "description": "and so on.", - "type": "string", - "title": "CredentialsType represents several different credential types, like password credentials, passwordless credentials," - }, "identityPatch": { "description": "Payload for patching an identity", "type": "object", @@ -4215,11 +4250,6 @@ "$ref": "#/definitions/identitySchemaContainer" } }, - "identityState": { - "description": "The state can either be `active` or `inactive`.", - "type": "string", - "title": "An Identity's State" - }, "identityTraits": { "description": "Traits represent an identity's traits. The identity is able to create, modify, and delete traits\nin a self-service manner. The input will always be validated against the JSON Schema defined\nin `schema_url`.", "type": "object" @@ -4356,7 +4386,19 @@ ], "properties": { "active": { - "$ref": "#/definitions/identityCredentialsType" + "description": "The active login method\n\nIf set contains the login method used. If the flow is new, it is unset.\npassword CredentialsTypePassword\noidc CredentialsTypeOIDC\ntotp CredentialsTypeTOTP\nlookup_secret CredentialsTypeLookup\nwebauthn CredentialsTypeWebAuthn\ncode CredentialsTypeCodeAuth\nlink_recovery CredentialsTypeRecoveryLink CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). It is not used within the credentials object itself.\ncode_recovery CredentialsTypeRecoveryCode", + "type": "string", + "enum": [ + "password", + "oidc", + "totp", + "lookup_secret", + "webauthn", + "code", + "link_recovery", + "code_recovery" + ], + "x-go-enum-desc": "password CredentialsTypePassword\noidc CredentialsTypeOIDC\ntotp CredentialsTypeTOTP\nlookup_secret CredentialsTypeLookup\nwebauthn CredentialsTypeWebAuthn\ncode CredentialsTypeCodeAuth\nlink_recovery CredentialsTypeRecoveryLink CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). It is not used within the credentials object itself.\ncode_recovery CredentialsTypeRecoveryCode" }, "created_at": { "description": "CreatedAt is a helper struct field for gobuffalo.pop.", @@ -4768,7 +4810,19 @@ ], "properties": { "active": { - "$ref": "#/definitions/identityCredentialsType" + "description": "Active, if set, contains the registration method that is being used. It is initially\nnot set.\npassword CredentialsTypePassword\noidc CredentialsTypeOIDC\ntotp CredentialsTypeTOTP\nlookup_secret CredentialsTypeLookup\nwebauthn CredentialsTypeWebAuthn\ncode CredentialsTypeCodeAuth\nlink_recovery CredentialsTypeRecoveryLink CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). It is not used within the credentials object itself.\ncode_recovery CredentialsTypeRecoveryCode", + "type": "string", + "enum": [ + "password", + "oidc", + "totp", + "lookup_secret", + "webauthn", + "code", + "link_recovery", + "code_recovery" + ], + "x-go-enum-desc": "password CredentialsTypePassword\noidc CredentialsTypeOIDC\ntotp CredentialsTypeTOTP\nlookup_secret CredentialsTypeLookup\nwebauthn CredentialsTypeWebAuthn\ncode CredentialsTypeCodeAuth\nlink_recovery CredentialsTypeRecoveryLink CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). It is not used within the credentials object itself.\ncode_recovery CredentialsTypeRecoveryCode" }, "expires_at": { "description": "ExpiresAt is the time (UTC) when the flow expires. If the user still wishes to log in,\na new flow has to be initiated.", @@ -4920,7 +4974,19 @@ "format": "date-time" }, "method": { - "$ref": "#/definitions/identityCredentialsType" + "description": "The method used in this authenticator.\npassword CredentialsTypePassword\noidc CredentialsTypeOIDC\ntotp CredentialsTypeTOTP\nlookup_secret CredentialsTypeLookup\nwebauthn CredentialsTypeWebAuthn\ncode CredentialsTypeCodeAuth\nlink_recovery CredentialsTypeRecoveryLink CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). It is not used within the credentials object itself.\ncode_recovery CredentialsTypeRecoveryCode", + "type": "string", + "enum": [ + "password", + "oidc", + "totp", + "lookup_secret", + "webauthn", + "code", + "link_recovery", + "code_recovery" + ], + "x-go-enum-desc": "password CredentialsTypePassword\noidc CredentialsTypeOIDC\ntotp CredentialsTypeTOTP\nlookup_secret CredentialsTypeLookup\nwebauthn CredentialsTypeWebAuthn\ncode CredentialsTypeCodeAuth\nlink_recovery CredentialsTypeRecoveryLink CredentialsTypeRecoveryLink is a special credential type linked to the link strategy (recovery flow). It is not used within the credentials object itself.\ncode_recovery CredentialsTypeRecoveryCode" }, "organization": { "description": "The Organization id used for authentication", @@ -5495,7 +5561,13 @@ "type": "string" }, "state": { - "$ref": "#/definitions/identityState" + "description": "State is the identity's state.\nactive StateActive\ninactive StateInactive", + "type": "string", + "enum": [ + "active", + "inactive" + ], + "x-go-enum-desc": "active StateActive\ninactive StateInactive" }, "traits": { "description": "Traits represent an identity's traits. The identity is able to create, modify, and delete traits\nin a self-service manner. The input will always be validated against the JSON Schema defined\nin `schema_id`.", From 90bdc61d28466f10e4e609df014b220afbee0478 Mon Sep 17 00:00:00 2001 From: Henning Perl Date: Tue, 30 Jan 2024 16:24:48 +0100 Subject: [PATCH 252/282] feat: claims from userinfo endpoint (#3718) * feat: claims from userinfo endpoint * chore: update libraries * test: improve coverage --- embedx/config.schema.json | 8 ++ go.mod | 24 +++-- go.sum | 37 +++---- internal/client-go/go.sum | 1 + ...rategy-method=TestPopulateLoginMethod.json | 22 +++++ ...ategy-method=TestPopulateSignUpMethod.json | 22 +++++ selfservice/strategy/oidc/provider_apple.go | 2 +- selfservice/strategy/oidc/provider_config.go | 6 ++ .../strategy/oidc/provider_generic_oidc.go | 97 +++++++++++++++++-- selfservice/strategy/oidc/provider_google.go | 2 +- .../strategy/oidc/provider_microsoft.go | 2 +- selfservice/strategy/oidc/provider_netid.go | 2 +- .../oidc/provider_private_net_test.go | 5 + .../strategy/oidc/strategy_helper_test.go | 11 ++- selfservice/strategy/oidc/strategy_test.go | 64 +++++++----- selfservice/strategy/oidc/token_verifier.go | 2 +- session/tokenizer_test.go | 4 +- 17 files changed, 241 insertions(+), 70 deletions(-) diff --git a/embedx/config.schema.json b/embedx/config.schema.json index e223b4cc1c79..930e7b34e95c 100644 --- a/embedx/config.schema.json +++ b/embedx/config.schema.json @@ -539,6 +539,14 @@ "type": "string", "examples": ["12345678-1234-1234-1234-123456789012"] } + }, + "claims_source": { + "title": "Claims source", + "description": "Can be either `userinfo` (calls the userinfo endpoint to get the claims) or `id_token` (takes the claims from the id token). It defaults to `id_token`", + "type": "string", + "enum": ["id_token", "userinfo"], + "default": "id_token", + "examples": ["id_token", "userinfo"] } }, "additionalProperties": false, diff --git a/go.mod b/go.mod index 96fad3946f5b..c237b4e9e11e 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,6 @@ require ( github.com/bradleyjkemp/cupaloy/v2 v2.8.0 github.com/bwmarrin/discordgo v0.23.0 github.com/cenkalti/backoff v2.2.1+incompatible - github.com/coreos/go-oidc v2.2.1+incompatible github.com/cortesi/modd v0.0.0-20210323234521-b35eddab86cc github.com/davecgh/go-spew v1.1.1 github.com/davidrjonas/semver-cli v0.0.0-20190116233701-ee19a9a0dda6 @@ -58,7 +57,7 @@ require ( github.com/julienschmidt/httprouter v1.3.0 github.com/knadh/koanf/parsers/json v0.1.0 github.com/laher/mergefs v0.1.2-0.20230223191438-d16611b2f4e7 - github.com/lestrrat-go/jwx v1.2.26 + github.com/lestrrat-go/jwx v1.2.26 // indirect github.com/luna-duclos/instrumentedsql v1.1.3 github.com/mailhog/MailHog v1.0.1 github.com/mattn/goveralls v0.0.7 @@ -97,10 +96,10 @@ require ( go.opentelemetry.io/otel v1.21.0 go.opentelemetry.io/otel/sdk v1.21.0 go.opentelemetry.io/otel/trace v1.21.0 - golang.org/x/crypto v0.17.0 + golang.org/x/crypto v0.18.0 golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa - golang.org/x/net v0.18.0 - golang.org/x/oauth2 v0.14.0 + golang.org/x/net v0.20.0 + golang.org/x/oauth2 v0.16.0 golang.org/x/sync v0.5.0 golang.org/x/text v0.14.0 golang.org/x/tools/cmd/cover v0.1.0-deprecated @@ -227,7 +226,7 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/leodido/go-urn v1.2.0 // indirect github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect - github.com/lestrrat-go/blackmagic v1.0.1 // indirect + github.com/lestrrat-go/blackmagic v1.0.2 // indirect github.com/lestrrat-go/httpcc v1.0.1 // indirect github.com/lestrrat-go/iter v1.0.2 // indirect github.com/lestrrat-go/option v1.0.1 // indirect @@ -263,7 +262,6 @@ require ( github.com/philhofer/fwd v1.1.2 // indirect github.com/pkg/profile v1.7.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/pquerna/cachecontrol v0.1.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.37.0 // indirect @@ -307,8 +305,8 @@ require ( go.opentelemetry.io/otel/metric v1.21.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect golang.org/x/mod v0.14.0 // indirect - golang.org/x/sys v0.15.0 // indirect - golang.org/x/term v0.15.0 // indirect + golang.org/x/sys v0.16.0 // indirect + golang.org/x/term v0.16.0 // indirect golang.org/x/tools v0.15.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect google.golang.org/appengine v1.6.8 // indirect @@ -321,14 +319,20 @@ require ( gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 // indirect gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 // indirect - gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect mvdan.cc/sh/v3 v3.3.0-0.dev.0.20210224101809-fb5052e7a010 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) +require ( + github.com/coreos/go-oidc/v3 v3.9.0 + github.com/lestrrat-go/jwx/v2 v2.0.19 +) + require ( github.com/jackc/puddle/v2 v2.1.2 // indirect + github.com/lestrrat-go/httprc v1.0.4 // indirect + github.com/segmentio/asm v1.2.0 // indirect go.uber.org/atomic v1.10.0 // indirect ) diff --git a/go.sum b/go.sum index 42b770741175..0c419864f2d4 100644 --- a/go.sum +++ b/go.sum @@ -128,8 +128,8 @@ github.com/cockroachdb/cockroach-go/v2 v2.3.5/go.mod h1:1wNJ45eSXW9AnOc3skntW9ZU github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= -github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk= -github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-oidc/v3 v3.9.0 h1:0J/ogVOd4y8P0f0xUh8l9t07xRP/d8tccvjHl2dcsSo= +github.com/coreos/go-oidc/v3 v3.9.0/go.mod h1:rTKz2PYwftcrtoCzV5g5kvfJoWcm0Mk8AF8y1iAQro4= 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/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= @@ -672,14 +672,19 @@ github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A= github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y= -github.com/lestrrat-go/blackmagic v1.0.1 h1:lS5Zts+5HIC/8og6cGHb0uCcNCa3OUt1ygh3Qz2Fe80= github.com/lestrrat-go/blackmagic v1.0.1/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU= +github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k= +github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU= github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE= github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= +github.com/lestrrat-go/httprc v1.0.4 h1:bAZymwoZQb+Oq8MEbyipag7iSq6YIga8Wj6GOiJGdI8= +github.com/lestrrat-go/httprc v1.0.4/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo= github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI= github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4= github.com/lestrrat-go/jwx v1.2.26 h1:4iFo8FPRZGDYe1t19mQP0zTRqA7n8HnJ5lkIiDvJcB0= github.com/lestrrat-go/jwx v1.2.26/go.mod h1:MaiCdGbn3/cckbOFSCluJlJMmp9dmZm5hDuIkx8ftpQ= +github.com/lestrrat-go/jwx/v2 v2.0.19 h1:ekv1qEZE6BVct89QA+pRF6+4pCpfVrOnEJnTnT4RXoY= +github.com/lestrrat-go/jwx/v2 v2.0.19/go.mod h1:l3im3coce1lL2cDeAjqmaR+Awx+X8Ih+2k8BuHNJ4CU= github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU= github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= @@ -859,8 +864,6 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= -github.com/pquerna/cachecontrol v0.1.0 h1:yJMy84ti9h/+OEWa752kBTKv4XC30OtVVHYv/8cTqKc= -github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI= github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg= github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -921,6 +924,8 @@ github.com/seatgeek/logrus-gelf-formatter v0.0.0-20210414080842-5b05eb8ff761 h1: github.com/seatgeek/logrus-gelf-formatter v0.0.0-20210414080842-5b05eb8ff761/go.mod h1:/THDZYi7F/BsVEcYzYPqdcWFQ+1C2InkawTKfLOAnzg= github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/segmentio/analytics-go v3.1.0+incompatible/go.mod h1:C7CYBtQWk4vRk2RyLu0qOcbHJ18E3F1HV2C/8JvKN48= +github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= +github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/segmentio/backo-go v0.0.0-20200129164019-23eae7c10bd3/go.mod h1:9/Rh6yILuLysoQnZ2oNooD2g7aBnvM7r/fNVxRNWfBc= github.com/segmentio/backo-go v1.0.1 h1:68RQccglxZeyURy93ASB/2kc9QudzgIDexJ927N++y4= github.com/segmentio/backo-go v1.0.1/go.mod h1:9/Rh6yILuLysoQnZ2oNooD2g7aBnvM7r/fNVxRNWfBc= @@ -1125,8 +1130,8 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1221,8 +1226,8 @@ golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= -golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1235,8 +1240,8 @@ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210810183815-faf39c7919d5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0= -golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= +golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= +golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= 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= @@ -1341,8 +1346,8 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20191110171634-ad39bd3f0407/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1354,8 +1359,8 @@ golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= 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= @@ -1583,8 +1588,6 @@ gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 h1:VpOs+IwYnYBaFnrNAeB8UUWtL3 gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 h1:6D+BvnJ/j6e222UW8s2qTSe3wGBtvo0MbVQG/c5k8RE= gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473/go.mod h1:N1eN2tsCx0Ydtgjl4cqmbRCsY4/+z4cYDeqwZTk6zog= -gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= -gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/validator.v2 v2.0.0-20180514200540-135c24b11c19/go.mod h1:o4V0GXN9/CAmCsvJ0oXYZvrZOe7syiDZSN1GWGZTGzc= diff --git a/internal/client-go/go.sum b/internal/client-go/go.sum index c966c8ddfd0d..6cc3f5911d11 100644 --- a/internal/client-go/go.sum +++ b/internal/client-go/go.sum @@ -4,6 +4,7 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/selfservice/strategy/oidc/.snapshots/TestStrategy-method=TestPopulateLoginMethod.json b/selfservice/strategy/oidc/.snapshots/TestStrategy-method=TestPopulateLoginMethod.json index 04eba3e43565..bacf802cd191 100644 --- a/selfservice/strategy/oidc/.snapshots/TestStrategy-method=TestPopulateLoginMethod.json +++ b/selfservice/strategy/oidc/.snapshots/TestStrategy-method=TestPopulateLoginMethod.json @@ -58,6 +58,28 @@ } } }, + { + "type": "input", + "group": "oidc", + "attributes": { + "name": "provider", + "type": "submit", + "value": "claimsViaUserInfo", + "disabled": false, + "node_type": "input" + }, + "messages": [], + "meta": { + "label": { + "id": 1010002, + "text": "Sign in with claimsViaUserInfo", + "type": "info", + "context": { + "provider": "claimsViaUserInfo" + } + } + } + }, { "type": "input", "group": "oidc", diff --git a/selfservice/strategy/oidc/.snapshots/TestStrategy-method=TestPopulateSignUpMethod.json b/selfservice/strategy/oidc/.snapshots/TestStrategy-method=TestPopulateSignUpMethod.json index e9b5dc03f8e6..6b0a9ba98cf8 100644 --- a/selfservice/strategy/oidc/.snapshots/TestStrategy-method=TestPopulateSignUpMethod.json +++ b/selfservice/strategy/oidc/.snapshots/TestStrategy-method=TestPopulateSignUpMethod.json @@ -58,6 +58,28 @@ } } }, + { + "type": "input", + "group": "oidc", + "attributes": { + "name": "provider", + "type": "submit", + "value": "claimsViaUserInfo", + "disabled": false, + "node_type": "input" + }, + "messages": [], + "meta": { + "label": { + "id": 1040002, + "text": "Sign up with claimsViaUserInfo", + "type": "info", + "context": { + "provider": "claimsViaUserInfo" + } + } + } + }, { "type": "input", "group": "oidc", diff --git a/selfservice/strategy/oidc/provider_apple.go b/selfservice/strategy/oidc/provider_apple.go index d680d0c1faae..706a7150c5e4 100644 --- a/selfservice/strategy/oidc/provider_apple.go +++ b/selfservice/strategy/oidc/provider_apple.go @@ -12,7 +12,7 @@ import ( "net/url" "time" - "github.com/coreos/go-oidc" + "github.com/coreos/go-oidc/v3/oidc" "github.com/golang-jwt/jwt/v4" "github.com/pkg/errors" diff --git a/selfservice/strategy/oidc/provider_config.go b/selfservice/strategy/oidc/provider_config.go index c6fc84f762de..512a5ecc6fa2 100644 --- a/selfservice/strategy/oidc/provider_config.go +++ b/selfservice/strategy/oidc/provider_config.go @@ -112,6 +112,12 @@ type Configuration struct { // AdditionalIDTokenAudiences is a list of additional audiences allowed in the ID Token. // This is only relevant in OIDC flows that submit an IDToken instead of using the callback from the OIDC provider. AdditionalIDTokenAudiences []string `json:"additional_id_token_audiences"` + + // ClaimsSource is a flag which controls where the claims are taken from when + // using the generic provider. Can be either `userinfo` (calls the userinfo + // endpoint to get the claims) or `id_token` (takes the claims from the id + // token). It defaults to `id_token`. + ClaimsSource string `json:"claims_source"` } func (p Configuration) Redir(public *url.URL) string { diff --git a/selfservice/strategy/oidc/provider_generic_oidc.go b/selfservice/strategy/oidc/provider_generic_oidc.go index a0b551649ae7..4f060e8a84e6 100644 --- a/selfservice/strategy/oidc/provider_generic_oidc.go +++ b/selfservice/strategy/oidc/provider_generic_oidc.go @@ -10,10 +10,10 @@ import ( "github.com/pkg/errors" "golang.org/x/oauth2" + gooidc "github.com/coreos/go-oidc/v3/oidc" + "github.com/ory/herodot" "github.com/ory/x/stringslice" - - gooidc "github.com/coreos/go-oidc" ) var _ Provider = new(ProviderGenericOIDC) @@ -34,13 +34,22 @@ func NewProviderGenericOIDC( } } +const ( + ClaimsSourceIDToken = "id_token" + ClaimsSourceUserInfo = "userinfo" +) + func (g *ProviderGenericOIDC) Config() *Configuration { return g.config } +func (g *ProviderGenericOIDC) withHTTPClientContext(ctx context.Context) context.Context { + return gooidc.ClientContext(ctx, g.reg.HTTPClient(ctx).HTTPClient) +} + func (g *ProviderGenericOIDC) provider(ctx context.Context) (*gooidc.Provider, error) { if g.p == nil { - p, err := gooidc.NewProvider(context.WithValue(ctx, oauth2.HTTPClient, g.reg.HTTPClient(ctx).HTTPClient), g.config.IssuerURL) + p, err := gooidc.NewProvider(g.withHTTPClientContext(ctx), g.config.IssuerURL) if err != nil { return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Unable to initialize OpenID Connect Provider: %s", err)) } @@ -88,7 +97,7 @@ func (g *ProviderGenericOIDC) AuthCodeURLOptions(r ider) []oauth2.AuthCodeOption } func (g *ProviderGenericOIDC) verifyAndDecodeClaimsWithProvider(ctx context.Context, provider *gooidc.Provider, raw string) (*Claims, error) { - token, err := provider.Verifier(&gooidc.Config{ClientID: g.config.ClientID}).Verify(ctx, raw) + token, err := provider.VerifierContext(g.withHTTPClientContext(ctx), &gooidc.Config{ClientID: g.config.ClientID}).Verify(ctx, raw) if err != nil { return nil, errors.WithStack(herodot.ErrBadRequest.WithReasonf("%s", err)) } @@ -107,16 +116,90 @@ func (g *ProviderGenericOIDC) verifyAndDecodeClaimsWithProvider(ctx context.Cont return &claims, nil } -func (g *ProviderGenericOIDC) Claims(ctx context.Context, exchange *oauth2.Token, query url.Values) (*Claims, error) { +func (g *ProviderGenericOIDC) Claims(ctx context.Context, exchange *oauth2.Token, _ url.Values) (*Claims, error) { + switch g.config.ClaimsSource { + case ClaimsSourceIDToken, "": + return g.claimsFromIDToken(ctx, exchange) + case ClaimsSourceUserInfo: + return g.claimsFromUserInfo(ctx, exchange) + } + + return nil, errors.WithStack(herodot.ErrInternalServerError. + WithReasonf("Unknown claims source: %q", g.config.ClaimsSource)) +} + +func (g *ProviderGenericOIDC) claimsFromUserInfo(ctx context.Context, exchange *oauth2.Token) (*Claims, error) { + p, err := g.provider(ctx) + if err != nil { + return nil, err + } + + userInfo, err := p.UserInfo(g.withHTTPClientContext(ctx), oauth2.StaticTokenSource(exchange)) + if err != nil { + return nil, err + } + + var claims Claims + if err = userInfo.Claims(&claims); err != nil { + return nil, err + } + var rawClaims map[string]interface{} + if err := userInfo.Claims(&rawClaims); err != nil { + return nil, errors.WithStack(herodot.ErrBadRequest.WithReasonf("%s", err)) + } + claims.RawClaims = rawClaims + + // NOTE: Due to the possibility of token substitution attacks (see Section + // 16.11), the UserInfo Response is not guaranteed to be about the End-User + // identified by the sub (subject) element of the ID Token. The sub Claim in the + // UserInfo Response MUST be verified to exactly match the sub Claim in the ID + // Token; if they do not match, the UserInfo Response values MUST NOT be used. + // See https://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse + idToken, err := g.verifiedIDToken(ctx, exchange) + if err != nil { + return nil, err + } + + if idToken.Subject != claims.Subject { + return nil, errors.WithStack(herodot.ErrBadRequest.WithReason("sub (Subject) claim mismatch between ID token and UserInfo endpoint")) + } + + return &claims, nil +} + +func (g *ProviderGenericOIDC) claimsFromIDToken(ctx context.Context, exchange *oauth2.Token) (*Claims, error) { + p, raw, err := g.idTokenAndProvider(ctx, exchange) + if err != nil { + return nil, err + } + + return g.verifyAndDecodeClaimsWithProvider(ctx, p, raw) +} + +func (g *ProviderGenericOIDC) idTokenAndProvider(ctx context.Context, exchange *oauth2.Token) (*gooidc.Provider, string, error) { raw, ok := exchange.Extra("id_token").(string) if !ok || len(raw) == 0 { - return nil, errors.WithStack(ErrIDTokenMissing) + return nil, "", errors.WithStack(ErrIDTokenMissing) } p, err := g.provider(ctx) + if err != nil { + return nil, "", err + } + + return p, raw, nil +} + +func (g *ProviderGenericOIDC) verifiedIDToken(ctx context.Context, exchange *oauth2.Token) (*gooidc.IDToken, error) { + p, raw, err := g.idTokenAndProvider(ctx, exchange) if err != nil { return nil, err } - return g.verifyAndDecodeClaimsWithProvider(ctx, p, raw) + token, err := p.VerifierContext(g.withHTTPClientContext(ctx), &gooidc.Config{ClientID: g.config.ClientID}).Verify(ctx, raw) + if err != nil { + return nil, errors.WithStack(herodot.ErrBadRequest.WithReasonf("%s", err)) + } + + return token, nil } diff --git a/selfservice/strategy/oidc/provider_google.go b/selfservice/strategy/oidc/provider_google.go index de84a8dc1953..e27832692faa 100644 --- a/selfservice/strategy/oidc/provider_google.go +++ b/selfservice/strategy/oidc/provider_google.go @@ -6,7 +6,7 @@ package oidc import ( "context" - gooidc "github.com/coreos/go-oidc" + gooidc "github.com/coreos/go-oidc/v3/oidc" "golang.org/x/oauth2" "github.com/ory/x/stringslice" diff --git a/selfservice/strategy/oidc/provider_microsoft.go b/selfservice/strategy/oidc/provider_microsoft.go index 8dd17fbbaae5..d69206ec4d87 100644 --- a/selfservice/strategy/oidc/provider_microsoft.go +++ b/selfservice/strategy/oidc/provider_microsoft.go @@ -16,7 +16,7 @@ import ( "github.com/gofrs/uuid" "github.com/golang-jwt/jwt/v4" - gooidc "github.com/coreos/go-oidc" + gooidc "github.com/coreos/go-oidc/v3/oidc" "github.com/pkg/errors" "golang.org/x/oauth2" diff --git a/selfservice/strategy/oidc/provider_netid.go b/selfservice/strategy/oidc/provider_netid.go index 60664b199e7d..dfe83c958433 100644 --- a/selfservice/strategy/oidc/provider_netid.go +++ b/selfservice/strategy/oidc/provider_netid.go @@ -9,7 +9,7 @@ import ( "fmt" "net/url" - gooidc "github.com/coreos/go-oidc" + gooidc "github.com/coreos/go-oidc/v3/oidc" "github.com/ory/x/stringslice" diff --git a/selfservice/strategy/oidc/provider_private_net_test.go b/selfservice/strategy/oidc/provider_private_net_test.go index 1e1d71458ee9..878b8622e993 100644 --- a/selfservice/strategy/oidc/provider_private_net_test.go +++ b/selfservice/strategy/oidc/provider_private_net_test.go @@ -57,8 +57,13 @@ func TestProviderPrivateIP(t *testing.T) { // If the issuer URL is local, we fail {p: generic, c: &oidc.Configuration{IssuerURL: "http://127.0.0.2/"}, e: "is not a permitted destination", id: fakeJWTJWKS}, + {p: generic, c: &oidc.Configuration{IssuerURL: "http://127.0.0.2/", ClaimsSource: "userinfo"}, e: "is not a permitted destination", id: fakeJWTJWKS}, + {p: generic, c: &oidc.Configuration{IssuerURL: "http://127.0.0.2/", ClaimsSource: "invalid"}, e: "Unknown claims source: \"invalid\"", id: fakeJWTJWKS}, + // If the issuer URL has a local JWKs URL, we fail {p: generic, c: &oidc.Configuration{ClientID: "abcd", IssuerURL: wellknownJWKs}, e: "is not a permitted destination", id: fakeJWTJWKS}, + {p: generic, c: &oidc.Configuration{ClientID: "abcd", IssuerURL: wellknownJWKs, ClaimsSource: "userinfo"}, e: "is not a permitted destination", id: fakeJWTJWKS}, + // The next call does not fail because the provider uses only the ID JSON Web Token to verify this call and does // not use the TokenURL at all! // {p: generic, c: &oidc.Configuration{ClientID: "abcd", IssuerURL: wellknownToken, TokenURL: "http://127.0.0.3/"}, e: "127.0.0.3 is not a public IP address", id: fakeJWTToken}, diff --git a/selfservice/strategy/oidc/strategy_helper_test.go b/selfservice/strategy/oidc/strategy_helper_test.go index 51df94357bda..37c45bccd8c9 100644 --- a/selfservice/strategy/oidc/strategy_helper_test.go +++ b/selfservice/strategy/oidc/strategy_helper_test.go @@ -6,6 +6,7 @@ package oidc_test import ( "bytes" "context" + _ "embed" "encoding/json" "fmt" "io" @@ -26,8 +27,6 @@ import ( "github.com/stretchr/testify/require" "github.com/tidwall/gjson" - _ "embed" - "github.com/ory/dockertest/v3" "github.com/ory/dockertest/v3/docker" "github.com/ory/kratos/driver" @@ -313,10 +312,11 @@ func newOIDCProvider( hydraPublic string, hydraAdmin string, id string, + opts ...func(*oidc.Configuration), ) oidc.Configuration { clientID, secret := createClient(t, hydraAdmin, kratos.URL+oidc.RouteBase+"/callback/"+id) - return oidc.Configuration{ + cfg := oidc.Configuration{ Provider: "generic", ID: id, ClientID: clientID, @@ -324,6 +324,11 @@ func newOIDCProvider( IssuerURL: hydraPublic + "/", Mapper: "file://./stub/oidc.hydra.jsonnet", } + for _, opt := range opts { + opt(&cfg) + } + + return cfg } func viperSetProviderConfig(t *testing.T, conf *config.Config, providers ...oidc.Configuration) { diff --git a/selfservice/strategy/oidc/strategy_test.go b/selfservice/strategy/oidc/strategy_test.go index 0b4ca95c6e9e..951f061995e3 100644 --- a/selfservice/strategy/oidc/strategy_test.go +++ b/selfservice/strategy/oidc/strategy_test.go @@ -79,6 +79,9 @@ func TestStrategy(t *testing.T) { conf, newOIDCProvider(t, ts, remotePublic, remoteAdmin, "valid"), newOIDCProvider(t, ts, remotePublic, remoteAdmin, "secondProvider"), + newOIDCProvider(t, ts, remotePublic, remoteAdmin, "claimsViaUserInfo", func(c *oidc.Configuration) { + c.ClaimsSource = oidc.ClaimsSourceUserInfo + }), oidc.Configuration{ Provider: "generic", ID: "invalid-issuer", @@ -836,35 +839,44 @@ func TestStrategy(t *testing.T) { }) t.Run("case=register, merge, and complete data", func(t *testing.T) { - subject = "incomplete-data@ory.sh" - scope = []string{"openid"} - claims = idTokenClaims{} - claims.traits.website = "https://www.ory.sh/kratos" - claims.traits.groups = []string{"group1", "group2"} - claims.metadataPublic.picture = "picture.png" - claims.metadataAdmin.phoneNumber = "911" - t.Run("case=should fail registration on first attempt", func(t *testing.T) { - r := newBrowserRegistrationFlow(t, returnTS.URL, time.Minute) - action := assertFormValues(t, r.ID, "valid") - res, body := makeRequest(t, "valid", action, url.Values{"traits.name": {"i"}}) - require.Contains(t, res.Request.URL.String(), uiTS.URL, "%s", body) + for _, tc := range []struct{ name, provider string }{ + {name: "idtoken", provider: "valid"}, + {name: "userinfo", provider: "claimsViaUserInfo"}, + } { + subject = fmt.Sprintf("incomplete-data@%s.ory.sh", tc.name) + scope = []string{"openid"} + claims = idTokenClaims{} + claims.traits.website = "https://www.ory.sh/kratos" + claims.traits.groups = []string{"group1", "group2"} + claims.metadataPublic.picture = "picture.png" + claims.metadataAdmin.phoneNumber = "911" + + t.Run(fmt.Sprintf("ClaimsSource=%s", tc.name), func(t *testing.T) { + t.Run("case=should fail registration on first attempt", func(t *testing.T) { + r := newBrowserRegistrationFlow(t, returnTS.URL, time.Minute) + action := assertFormValues(t, r.ID, tc.provider) + res, body := makeRequest(t, tc.provider, action, url.Values{"traits.name": {"i"}}) + require.Contains(t, res.Request.URL.String(), uiTS.URL, "%s", body) + + assert.Equal(t, "length must be >= 2, but got 1", gjson.GetBytes(body, "ui.nodes.#(attributes.name==traits.name).messages.0.text").String(), "%s", body) // make sure the field is being echoed + assert.Equal(t, "traits.name", gjson.GetBytes(body, "ui.nodes.#(attributes.name==traits.name).attributes.name").String(), "%s", body) // make sure the field is being echoed + assert.Equal(t, "i", gjson.GetBytes(body, "ui.nodes.#(attributes.name==traits.name).attributes.value").String(), "%s", body) // make sure the field is being echoed + assert.Equal(t, "https://www.ory.sh/kratos", gjson.GetBytes(body, "ui.nodes.#(attributes.name==traits.website).attributes.value").String(), "%s", body) // make sure the field is being echoed + }) - assert.Equal(t, "length must be >= 2, but got 1", gjson.GetBytes(body, "ui.nodes.#(attributes.name==traits.name).messages.0.text").String(), "%s", body) // make sure the field is being echoed - assert.Equal(t, "traits.name", gjson.GetBytes(body, "ui.nodes.#(attributes.name==traits.name).attributes.name").String(), "%s", body) // make sure the field is being echoed - assert.Equal(t, "i", gjson.GetBytes(body, "ui.nodes.#(attributes.name==traits.name).attributes.value").String(), "%s", body) // make sure the field is being echoed - assert.Equal(t, "https://www.ory.sh/kratos", gjson.GetBytes(body, "ui.nodes.#(attributes.name==traits.website).attributes.value").String(), "%s", body) // make sure the field is being echoed - }) + t.Run("case=should pass registration with valid data", func(t *testing.T) { + r := newBrowserRegistrationFlow(t, returnTS.URL, time.Minute) + action := assertFormValues(t, r.ID, tc.provider) + res, body := makeRequest(t, tc.provider, action, url.Values{"traits.name": {"valid-name"}}) + assertIdentity(t, res, body) + assert.Equal(t, "https://www.ory.sh/kratos", gjson.GetBytes(body, "identity.traits.website").String(), "%s", body) + assert.Equal(t, "valid-name", gjson.GetBytes(body, "identity.traits.name").String(), "%s", body) + assert.Equal(t, "[\"group1\",\"group2\"]", gjson.GetBytes(body, "identity.traits.groups").String(), "%s", body) + }) + }) + } - t.Run("case=should pass registration with valid data", func(t *testing.T) { - r := newBrowserRegistrationFlow(t, returnTS.URL, time.Minute) - action := assertFormValues(t, r.ID, "valid") - res, body := makeRequest(t, "valid", action, url.Values{"traits.name": {"valid-name"}}) - assertIdentity(t, res, body) - assert.Equal(t, "https://www.ory.sh/kratos", gjson.GetBytes(body, "identity.traits.website").String(), "%s", body) - assert.Equal(t, "valid-name", gjson.GetBytes(body, "identity.traits.name").String(), "%s", body) - assert.Equal(t, "[\"group1\",\"group2\"]", gjson.GetBytes(body, "identity.traits.groups").String(), "%s", body) - }) }) t.Run("case=should fail to register and return fresh login flow if email is already being used by password credentials", func(t *testing.T) { diff --git a/selfservice/strategy/oidc/token_verifier.go b/selfservice/strategy/oidc/token_verifier.go index e30a529bc6cc..ce9cb8b3d3ee 100644 --- a/selfservice/strategy/oidc/token_verifier.go +++ b/selfservice/strategy/oidc/token_verifier.go @@ -8,7 +8,7 @@ import ( "fmt" "strings" - "github.com/coreos/go-oidc" + "github.com/coreos/go-oidc/v3/oidc" ) func verifyToken(ctx context.Context, keySet oidc.KeySet, config *Configuration, rawIDToken, issuerURL string) (*Claims, error) { diff --git a/session/tokenizer_test.go b/session/tokenizer_test.go index e6e1621e7cd8..fab54f09d99e 100644 --- a/session/tokenizer_test.go +++ b/session/tokenizer_test.go @@ -14,7 +14,7 @@ import ( "github.com/gofrs/uuid" "github.com/golang-jwt/jwt/v5" - "github.com/lestrrat-go/jwx/jwk" + "github.com/lestrrat-go/jwx/v2/jwk" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -39,7 +39,7 @@ func validateTokenized(t *testing.T, raw string, key []byte) *jwt.Token { if err != nil { return nil, err } - key, _ := set.Get(0) + key, _ := set.Key(0) if pk, err := key.PublicKey(); err != nil { return nil, err } else if err := pk.Raw(&target); err != nil { From 31f1a096cbdae81c67fca3bd2c3efcf0801d0958 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Tue, 30 Jan 2024 15:26:40 +0000 Subject: [PATCH 253/282] autogen(openapi): regenerate swagger spec and internal client [skip ci] --- internal/client-go/go.sum | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/client-go/go.sum b/internal/client-go/go.sum index 6cc3f5911d11..c966c8ddfd0d 100644 --- a/internal/client-go/go.sum +++ b/internal/client-go/go.sum @@ -4,7 +4,6 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= From 988be61f8be41929cea8802a3b7083079dec8cd6 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Tue, 30 Jan 2024 16:14:38 +0000 Subject: [PATCH 254/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 83 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 518d3b6c7add..21a3ec5444e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,20 +5,21 @@ **Table of Contents** -- [ (2024-01-26)](#2024-01-26) +- [ (2024-01-30)](#2024-01-30) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) - [Features](#features) - [Reverts](#reverts) - [Tests](#tests) + - [Unclassified](#unclassified) - [1.0.0 (2023-07-12)](#100-2023-07-12) - [Bug Fixes](#bug-fixes-1) - [Code Generation](#code-generation) - [Documentation](#documentation-1) - [Features](#features-1) - [Tests](#tests-1) - - [Unclassified](#unclassified) + - [Unclassified](#unclassified-1) - [0.13.0 (2023-04-18)](#0130-2023-04-18) - [Breaking Changes](#breaking-changes-1) - [Bug Fixes](#bug-fixes-2) @@ -27,7 +28,7 @@ - [Documentation](#documentation-2) - [Features](#features-2) - [Tests](#tests-2) - - [Unclassified](#unclassified-1) + - [Unclassified](#unclassified-2) - [0.11.1 (2023-01-14)](#0111-2023-01-14) - [Breaking Changes](#breaking-changes-2) - [Bug Fixes](#bug-fixes-3) @@ -47,7 +48,7 @@ - [Features](#features-5) - [Reverts](#reverts-1) - [Tests](#tests-4) - - [Unclassified](#unclassified-2) + - [Unclassified](#unclassified-3) - [0.10.1 (2022-06-01)](#0101-2022-06-01) - [Bug Fixes](#bug-fixes-5) - [Code Generation](#code-generation-5) @@ -59,7 +60,7 @@ - [Documentation](#documentation-5) - [Features](#features-6) - [Tests](#tests-5) - - [Unclassified](#unclassified-3) + - [Unclassified](#unclassified-4) - [0.9.0-alpha.3 (2022-03-25)](#090-alpha3-2022-03-25) - [Breaking Changes](#breaking-changes-5) - [Bug Fixes](#bug-fixes-7) @@ -76,7 +77,7 @@ - [Documentation](#documentation-7) - [Features](#features-7) - [Tests](#tests-6) - - [Unclassified](#unclassified-4) + - [Unclassified](#unclassified-5) - [0.8.3-alpha.1.pre.0 (2022-01-21)](#083-alpha1pre0-2022-01-21) - [Breaking Changes](#breaking-changes-7) - [Bug Fixes](#bug-fixes-10) @@ -116,7 +117,7 @@ - [Features](#features-11) - [Reverts](#reverts-2) - [Tests](#tests-10) - - [Unclassified](#unclassified-5) + - [Unclassified](#unclassified-6) - [0.7.6-alpha.1 (2021-09-12)](#076-alpha1-2021-09-12) - [Code Generation](#code-generation-17) - [0.7.5-alpha.1 (2021-09-11)](#075-alpha1-2021-09-11) @@ -145,7 +146,7 @@ - [Documentation](#documentation-16) - [Features](#features-14) - [Tests](#tests-13) - - [Unclassified](#unclassified-6) + - [Unclassified](#unclassified-7) - [0.6.3-alpha.1 (2021-05-17)](#063-alpha1-2021-05-17) - [Breaking Changes](#breaking-changes-11) - [Bug Fixes](#bug-fixes-20) @@ -169,14 +170,14 @@ - [Documentation](#documentation-18) - [Features](#features-17) - [Tests](#tests-14) - - [Unclassified](#unclassified-7) + - [Unclassified](#unclassified-8) - [0.5.5-alpha.1 (2020-12-09)](#055-alpha1-2020-12-09) - [Bug Fixes](#bug-fixes-23) - [Code Generation](#code-generation-28) - [Documentation](#documentation-19) - [Features](#features-18) - [Tests](#tests-15) - - [Unclassified](#unclassified-8) + - [Unclassified](#unclassified-9) - [0.5.4-alpha.1 (2020-11-11)](#054-alpha1-2020-11-11) - [Bug Fixes](#bug-fixes-24) - [Code Generation](#code-generation-29) @@ -200,7 +201,7 @@ - [Documentation](#documentation-23) - [Features](#features-21) - [Tests](#tests-18) - - [Unclassified](#unclassified-9) + - [Unclassified](#unclassified-10) - [0.5.0-alpha.1 (2020-10-15)](#050-alpha1-2020-10-15) - [Breaking Changes](#breaking-changes-13) - [Bug Fixes](#bug-fixes-28) @@ -209,7 +210,7 @@ - [Documentation](#documentation-24) - [Features](#features-22) - [Tests](#tests-19) - - [Unclassified](#unclassified-10) + - [Unclassified](#unclassified-11) - [0.4.6-alpha.1 (2020-07-13)](#046-alpha1-2020-07-13) - [Bug Fixes](#bug-fixes-29) - [Code Generation](#code-generation-34) @@ -233,7 +234,7 @@ - [Code Refactoring](#code-refactoring-11) - [Documentation](#documentation-26) - [Features](#features-23) - - [Unclassified](#unclassified-11) + - [Unclassified](#unclassified-12) - [0.3.0-alpha.1 (2020-05-15)](#030-alpha1-2020-05-15) - [Breaking Changes](#breaking-changes-15) - [Bug Fixes](#bug-fixes-35) @@ -241,7 +242,7 @@ - [Code Refactoring](#code-refactoring-12) - [Documentation](#documentation-27) - [Features](#features-24) - - [Unclassified](#unclassified-12) + - [Unclassified](#unclassified-13) - [0.2.1-alpha.1 (2020-05-05)](#021-alpha1-2020-05-05) - [Chores](#chores-1) - [Documentation](#documentation-28) @@ -252,7 +253,7 @@ - [Code Refactoring](#code-refactoring-13) - [Documentation](#documentation-29) - [Features](#features-25) - - [Unclassified](#unclassified-13) + - [Unclassified](#unclassified-14) - [0.1.1-alpha.1 (2020-02-18)](#011-alpha1-2020-02-18) - [Bug Fixes](#bug-fixes-37) - [Code Refactoring](#code-refactoring-14) @@ -274,47 +275,47 @@ - [Bug Fixes](#bug-fixes-39) - [Documentation](#documentation-34) - [Features](#features-28) - - [Unclassified](#unclassified-14) + - [Unclassified](#unclassified-15) - [0.1.0-alpha.1 (2020-01-31)](#010-alpha1-2020-01-31) - [Documentation](#documentation-35) - [0.0.3-alpha.15 (2020-01-31)](#003-alpha15-2020-01-31) - - [Unclassified](#unclassified-15) -- [0.0.3-alpha.14 (2020-01-31)](#003-alpha14-2020-01-31) - [Unclassified](#unclassified-16) -- [0.0.3-alpha.13 (2020-01-31)](#003-alpha13-2020-01-31) +- [0.0.3-alpha.14 (2020-01-31)](#003-alpha14-2020-01-31) - [Unclassified](#unclassified-17) -- [0.0.3-alpha.11 (2020-01-31)](#003-alpha11-2020-01-31) +- [0.0.3-alpha.13 (2020-01-31)](#003-alpha13-2020-01-31) - [Unclassified](#unclassified-18) -- [0.0.3-alpha.10 (2020-01-31)](#003-alpha10-2020-01-31) +- [0.0.3-alpha.11 (2020-01-31)](#003-alpha11-2020-01-31) - [Unclassified](#unclassified-19) -- [0.0.3-alpha.7 (2020-01-30)](#003-alpha7-2020-01-30) +- [0.0.3-alpha.10 (2020-01-31)](#003-alpha10-2020-01-31) - [Unclassified](#unclassified-20) +- [0.0.3-alpha.7 (2020-01-30)](#003-alpha7-2020-01-30) + - [Unclassified](#unclassified-21) - [0.0.3-alpha.5 (2020-01-30)](#003-alpha5-2020-01-30) - [Continuous Integration](#continuous-integration-2) - - [Unclassified](#unclassified-21) -- [0.0.3-alpha.4 (2020-01-30)](#003-alpha4-2020-01-30) - [Unclassified](#unclassified-22) -- [0.0.3-alpha.2 (2020-01-30)](#003-alpha2-2020-01-30) +- [0.0.3-alpha.4 (2020-01-30)](#003-alpha4-2020-01-30) - [Unclassified](#unclassified-23) -- [0.0.3-alpha.1 (2020-01-30)](#003-alpha1-2020-01-30) +- [0.0.3-alpha.2 (2020-01-30)](#003-alpha2-2020-01-30) - [Unclassified](#unclassified-24) +- [0.0.3-alpha.1 (2020-01-30)](#003-alpha1-2020-01-30) + - [Unclassified](#unclassified-25) - [0.0.1-alpha.9 (2020-01-29)](#001-alpha9-2020-01-29) - [Continuous Integration](#continuous-integration-3) - [0.0.2-alpha.1 (2020-01-29)](#002-alpha1-2020-01-29) - - [Unclassified](#unclassified-25) + - [Unclassified](#unclassified-26) - [0.0.1-alpha.6 (2020-01-29)](#001-alpha6-2020-01-29) - [Continuous Integration](#continuous-integration-4) - [0.0.1-alpha.5 (2020-01-29)](#001-alpha5-2020-01-29) - [Continuous Integration](#continuous-integration-5) - - [Unclassified](#unclassified-26) + - [Unclassified](#unclassified-27) - [0.0.1-alpha.3 (2020-01-28)](#001-alpha3-2020-01-28) - [Continuous Integration](#continuous-integration-6) - [Documentation](#documentation-36) - - [Unclassified](#unclassified-27) + - [Unclassified](#unclassified-28) -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2024-01-26) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2024-01-30) ## Breaking Changes @@ -716,6 +717,9 @@ https://github.com/ory/kratos/pull/3480 ([#3533](https://github.com/ory/kratos/issues/3533)) ([39b0c3c](https://github.com/ory/kratos/commit/39b0c3c03df0aec254b32c840730452d4856872b)), closes [#1528](https://github.com/ory/kratos/issues/1528) +- Improve enum handling and completeness + ([#3714](https://github.com/ory/kratos/issues/3714)) + ([4b881ca](https://github.com/ory/kratos/commit/4b881cae4359bfa068261d2d0765ce3daadcbcf2)) - Remove experimental warnings ([#3406](https://github.com/ory/kratos/issues/3406)) ([d4d26e6](https://github.com/ory/kratos/commit/d4d26e6e1510c8e09346e95251f420f95ec54998)): @@ -881,6 +885,16 @@ https://github.com/ory/kratos/pull/3480 See also https://github.com/ory/kratos/pull/3273 +- Claims from userinfo endpoint + ([#3718](https://github.com/ory/kratos/issues/3718)) + ([90bdc61](https://github.com/ory/kratos/commit/90bdc61d28466f10e4e609df014b220afbee0478)): + + - feat: claims from userinfo endpoint + + - chore: update libraries + + - test: improve coverage + - Emit error details when we find stray cookies in an API flow ([#3496](https://github.com/ory/kratos/issues/3496)) ([df74339](https://github.com/ory/kratos/commit/df74339802d98a292abb32806eca35fb2554960b)) @@ -1062,6 +1076,15 @@ https://github.com/ory/kratos/pull/3480 - Resolve cypress issues ([#3531](https://github.com/ory/kratos/issues/3531)) ([4206d26](https://github.com/ory/kratos/commit/4206d2605dfa30b19e132be31b85b1a35f8dca78)) +### Unclassified + +- Revert "feat: extend Microsoft Graph API capabilities (#3609)" (#3717) + ([549308d](https://github.com/ory/kratos/commit/549308db1f7dca42004631ed6156cae5f827b8fe)), + closes [#3609](https://github.com/ory/kratos/issues/3609) + [#3717](https://github.com/ory/kratos/issues/3717): + + This reverts commit 4a7bcc9322be37e6fd141e411bd65e3977eeb692. + # [1.0.0](https://github.com/ory/kratos/compare/v0.13.0...v1.0.0) (2023-07-12) We are thrilled to announce Ory Kratos v1.0, the powerful Identity, User From 67360cf39482b935604f088a4b7a83cc4deab375 Mon Sep 17 00:00:00 2001 From: Henning Perl Date: Wed, 31 Jan 2024 10:03:06 +0100 Subject: [PATCH 255/282] test: add test for link + oidc challenge (#3720) --- .../code/strategy_verification_test.go | 11 ++++++++-- .../link/strategy_verification_test.go | 20 +++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/selfservice/strategy/code/strategy_verification_test.go b/selfservice/strategy/code/strategy_verification_test.go index 0f6a9fe15a10..6f25e324d8b2 100644 --- a/selfservice/strategy/code/strategy_verification_test.go +++ b/selfservice/strategy/code/strategy_verification_test.go @@ -647,13 +647,20 @@ func TestVerification(t *testing.T) { conf.MustSet(ctx, config.ViperKeyURLsAllowedReturnToDomains, []string{returnToURL}) client := testhelpers.NewClientWithCookies(t) - flow, _, _ := newValidFlow(t, flow.TypeBrowser, public.URL+verification.RouteInitBrowserFlow+"?"+url.Values{"return_to": {returnToURL}, "login_challenge": {"any_valid_challenge"}}.Encode()) + flow, _, _ := newValidFlow(t, flow.TypeBrowser, + public.URL+verification.RouteInitBrowserFlow+"?"+url.Values{ + "return_to": {returnToURL}, + "login_challenge": {"any_valid_challenge"}}.Encode()) body := fmt.Sprintf( `{"csrf_token":"%s","code":"%s"}`, flow.CSRFToken, "2475", ) - res, err := client.Post(public.URL+verification.RouteSubmitFlow+"?"+url.Values{"flow": {flow.ID.String()}}.Encode(), "application/json", bytes.NewBuffer([]byte(body))) + res, err := client.Post( + public.URL+verification.RouteSubmitFlow+"?"+url.Values{"flow": {flow.ID.String()}}.Encode(), + "application/json", + bytes.NewBuffer([]byte(body)), + ) require.NoError(t, err) assert.Equal(t, http.StatusOK, res.StatusCode) responseBody := gjson.ParseBytes(ioutilx.MustReadAll(res.Body)) diff --git a/selfservice/strategy/link/strategy_verification_test.go b/selfservice/strategy/link/strategy_verification_test.go index c81834e32b91..cab8fec60b99 100644 --- a/selfservice/strategy/link/strategy_verification_test.go +++ b/selfservice/strategy/link/strategy_verification_test.go @@ -429,4 +429,24 @@ func TestVerification(t *testing.T) { assert.Equal(t, "The verification token is invalid or has already been used. Please retry the flow.", gjson.GetBytes(body, "ui.messages.0.text").String()) }) + + t.Run("case=doesn't continue with OAuth2 flow if code is invalid", func(t *testing.T) { + globalReturnTo := public.URL + "/global" + conf.MustSet(ctx, config.ViperKeySelfServiceBrowserDefaultReturnTo, globalReturnTo) + + client := testhelpers.NewClientWithCookies(t) + flow, _ := newValidFlow(t, flow.TypeBrowser, public.URL+verification.RouteInitBrowserFlow) + + res, err := client.Get(public.URL + verification.RouteSubmitFlow + "?" + url.Values{ + "flow": {flow.ID.String()}, + "token": {"invalid token"}, + }.Encode()) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, res.StatusCode) + responseBody := gjson.ParseBytes(ioutilx.MustReadAll(res.Body)) + + assert.Equal(t, "choose_method", responseBody.Get("state").String(), "%v", responseBody) + assert.Len(t, responseBody.Get("ui.messages").Array(), 1, "%v", responseBody) + assert.Equal(t, "The verification token is invalid or has already been used. Please retry the flow.", responseBody.Get("ui.messages.0.text").String(), "%v", responseBody) + }) } From 8384f1033988985395dc97cc8a7235efcfd853f2 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Wed, 31 Jan 2024 09:45:51 +0000 Subject: [PATCH 256/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21a3ec5444e9..2a69e16a2362 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2024-01-30)](#2024-01-30) +- [ (2024-01-31)](#2024-01-31) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Documentation](#documentation) @@ -315,7 +315,7 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2024-01-30) +# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2024-01-31) ## Breaking Changes @@ -1063,6 +1063,9 @@ https://github.com/ory/kratos/pull/3480 ### Tests +- Add test for link + oidc challenge + ([#3720](https://github.com/ory/kratos/issues/3720)) + ([67360cf](https://github.com/ory/kratos/commit/67360cf39482b935604f088a4b7a83cc4deab375)) - **e2e:** Logout return_to ([#3418](https://github.com/ory/kratos/issues/3418)) ([c348c12](https://github.com/ory/kratos/commit/c348c12ab3c9cdb4ce8159fe774ed179ff6a4d8a)) - Fix cypress setup ([#3527](https://github.com/ory/kratos/issues/3527)) From 1c3eeb71d6fc83918ac367d1654361f8fd98a93e Mon Sep 17 00:00:00 2001 From: aeneasr <3372410+aeneasr@users.noreply.github.com> Date: Thu, 1 Feb 2024 12:39:56 +0100 Subject: [PATCH 257/282] autogen: pin v1.1.0-pre.0 release commit --- .schemastore/config.schema.json | 866 ++++++++++++++++++-------------- 1 file changed, 478 insertions(+), 388 deletions(-) diff --git a/.schemastore/config.schema.json b/.schemastore/config.schema.json index 5ab6aaa60eff..0980a4ab6d8a 100644 --- a/.schemastore/config.schema.json +++ b/.schemastore/config.schema.json @@ -43,10 +43,7 @@ "description": "Ory Kratos redirects to this URL per default on completion of self-service flows and other browser interaction. Read this [article for more information on browser redirects](https://www.ory.sh/kratos/docs/concepts/browser-redirect-flow-completion).", "type": "string", "format": "uri-reference", - "examples": [ - "https://my-app.com/dashboard", - "/dashboard" - ] + "examples": ["https://my-app.com/dashboard", "/dashboard"] }, "selfServiceSessionRevokerHook": { "type": "object", @@ -56,9 +53,7 @@ } }, "additionalProperties": false, - "required": [ - "hook" - ] + "required": ["hook"] }, "selfServiceSessionIssuerHook": { "type": "object", @@ -68,9 +63,7 @@ } }, "additionalProperties": false, - "required": [ - "hook" - ] + "required": ["hook"] }, "selfServiceRequireVerifiedAddressHook": { "type": "object", @@ -80,9 +73,7 @@ } }, "additionalProperties": false, - "required": [ - "hook" - ] + "required": ["hook"] }, "selfServiceShowVerificationUIHook": { "type": "object", @@ -92,9 +83,21 @@ } }, "additionalProperties": false, - "required": [ - "hook" - ] + "required": ["hook"] + }, + "b2bSSOHook": { + "type": "object", + "properties": { + "hook": { + "const": "b2b_sso" + }, + "config": { + "type": "object", + "additionalProperties": true + } + }, + "additionalProperties": false, + "required": ["hook", "config"] }, "webHookAuthBasicAuthProperties": { "properties": { @@ -114,17 +117,11 @@ } }, "additionalProperties": false, - "required": [ - "user", - "password" - ] + "required": ["user", "password"] } }, "additionalProperties": false, - "required": [ - "type", - "config" - ] + "required": ["type", "config"] }, "httpRequestConfig": { "type": "object", @@ -132,9 +129,7 @@ "url": { "title": "HTTP address of API endpoint", "description": "This URL will be used to send the emails to.", - "examples": [ - "https://example.com/api/v1/email" - ], + "examples": ["https://example.com/api/v1/email"], "type": "string", "pattern": "^https?://" }, @@ -199,25 +194,15 @@ "in": { "type": "string", "description": "How the api key should be transferred", - "enum": [ - "header", - "cookie" - ] + "enum": ["header", "cookie"] } }, "additionalProperties": false, - "required": [ - "name", - "value", - "in" - ] + "required": ["name", "value", "in"] } }, "additionalProperties": false, - "required": [ - "type", - "config" - ] + "required": ["type", "config"] }, "selfServiceWebHook": { "type": "object", @@ -256,10 +241,7 @@ "const": true } }, - "required": [ - "ignore", - "parse" - ] + "required": ["ignore", "parse"] } }, "url": { @@ -298,6 +280,11 @@ "default": false, "description": "Deprecated, please use `response.parse` instead. If enabled allows the web hook to interrupt / abort the self-service flow. It only applies to certain flows (registration/verification/login/settings) and requires a valid response format." }, + "emit_analytics_event": { + "type": "boolean", + "default": true, + "description": "Emit tracing events for this webhook on delivery or error" + }, "auth": { "type": "object", "title": "Auth mechanisms", @@ -320,46 +307,30 @@ "response": { "properties": { "ignore": { - "enum": [ - true - ] + "enum": [true] } }, - "required": [ - "ignore" - ] + "required": ["ignore"] } }, - "required": [ - "response" - ] + "required": ["response"] } }, { "properties": { "can_interrupt": { - "enum": [ - false - ] + "enum": [false] } }, - "require": [ - "can_interrupt" - ] + "require": ["can_interrupt"] } ], "additionalProperties": false, - "required": [ - "url", - "method" - ] + "required": ["url", "method"] } }, "additionalProperties": false, - "required": [ - "hook", - "config" - ] + "required": ["hook", "config"] }, "OIDCClaims": { "title": "OpenID Connect claims", @@ -392,9 +363,7 @@ "essential": true }, "acr": { - "values": [ - "urn:mace:incommon:iap:silver" - ] + "values": ["urn:mace:incommon:iap:silver"] } } } @@ -442,9 +411,7 @@ "properties": { "id": { "type": "string", - "examples": [ - "google" - ] + "examples": ["google"] }, "provider": { "title": "Provider", @@ -471,9 +438,7 @@ "linkedin", "lark" ], - "examples": [ - "google" - ] + "examples": ["google"] }, "label": { "title": "Optional string which will be used when generating labels for UI buttons.", @@ -488,23 +453,17 @@ "issuer_url": { "type": "string", "format": "uri", - "examples": [ - "https://accounts.google.com" - ] + "examples": ["https://accounts.google.com"] }, "auth_url": { "type": "string", "format": "uri", - "examples": [ - "https://accounts.google.com/o/oauth2/v2/auth" - ] + "examples": ["https://accounts.google.com/o/oauth2/v2/auth"] }, "token_url": { "type": "string", "format": "uri", - "examples": [ - "https://www.googleapis.com/oauth2/v4/token" - ] + "examples": ["https://www.googleapis.com/oauth2/v4/token"] }, "mapper_url": { "title": "Jsonnet Mapper URL", @@ -521,10 +480,7 @@ "type": "array", "items": { "type": "string", - "examples": [ - "offline_access", - "profile" - ] + "examples": ["offline_access", "profile"] } }, "microsoft_tenant": { @@ -543,30 +499,21 @@ "title": "Microsoft subject source", "description": "Controls which source the subject identifier is taken from by microsoft provider. If set to `userinfo` (the default) then the identifier is taken from the `sub` field of OIDC ID token or data received from `/userinfo` standard OIDC endpoint. If set to `me` then the `id` field of data structure received from `https://graph.microsoft.com/v1.0/me` is taken as an identifier.", "type": "string", - "enum": [ - "userinfo", - "me" - ], + "enum": ["userinfo", "me"], "default": "userinfo", - "examples": [ - "userinfo" - ] + "examples": ["userinfo"] }, "apple_team_id": { "title": "Apple Developer Team ID", "description": "Apple Developer Team ID needed for generating a JWT token for client secret", "type": "string", - "examples": [ - "KP76DQS54M" - ] + "examples": ["KP76DQS54M"] }, "apple_private_key_id": { "title": "Apple Private Key Identifier", "description": "Sign In with Apple Private Key Identifier needed for generating a JWT token for client secret", "type": "string", - "examples": [ - "UX56C66723" - ] + "examples": ["UX56C66723"] }, "apple_private_key": { "title": "Apple Private Key", @@ -578,15 +525,32 @@ }, "requested_claims": { "$ref": "#/definitions/OIDCClaims" + }, + "organization_id": { + "title": "Organization ID", + "description": "The ID of the organization that this provider belongs to. Only effective in the Ory Network.", + "type": "string", + "examples": ["12345678-1234-1234-1234-123456789012"] + }, + "additional_id_token_audiences": { + "title": "Additional client ids allowed when using ID token submission", + "type": "array", + "items": { + "type": "string", + "examples": ["12345678-1234-1234-1234-123456789012"] + } + }, + "claims_source": { + "title": "Claims source", + "description": "Can be either `userinfo` (calls the userinfo endpoint to get the claims) or `id_token` (takes the claims from the id token). It defaults to `id_token`", + "type": "string", + "enum": ["id_token", "userinfo"], + "default": "id_token", + "examples": ["id_token", "userinfo"] } }, "additionalProperties": false, - "required": [ - "id", - "provider", - "client_id", - "mapper_url" - ], + "required": ["id", "provider", "client_id", "mapper_url"], "allOf": [ { "if": { @@ -595,23 +559,17 @@ "const": "microsoft" } }, - "required": [ - "provider" - ] + "required": ["provider"] }, "then": { - "required": [ - "microsoft_tenant" - ] + "required": ["microsoft_tenant"] }, "else": { "not": { "properties": { "microsoft_tenant": {} }, - "required": [ - "microsoft_tenant" - ] + "required": ["microsoft_tenant"] } } }, @@ -622,9 +580,7 @@ "const": "apple" } }, - "required": [ - "provider" - ] + "required": ["provider"] }, "then": { "not": { @@ -634,9 +590,7 @@ "minLength": 1 } }, - "required": [ - "client_secret" - ] + "required": ["client_secret"] }, "required": [ "apple_private_key_id", @@ -645,9 +599,7 @@ ] }, "else": { - "required": [ - "client_secret" - ], + "required": ["client_secret"], "allOf": [ { "not": { @@ -657,9 +609,7 @@ "minLength": 1 } }, - "required": [ - "apple_team_id" - ] + "required": ["apple_team_id"] } }, { @@ -670,9 +620,7 @@ "minLength": 1 } }, - "required": [ - "apple_private_key_id" - ] + "required": ["apple_private_key_id"] } }, { @@ -683,9 +631,7 @@ "minLength": 1 } }, - "required": [ - "apple_private_key" - ] + "required": ["apple_private_key"] } } ] @@ -699,6 +645,9 @@ "anyOf": [ { "$ref": "#/definitions/selfServiceWebHook" + }, + { + "$ref": "#/definitions/b2bSSOHook" } ] }, @@ -741,6 +690,30 @@ } } }, + "selfServiceAfterSettingsAuthMethod": { + "type": "object", + "additionalProperties": false, + "properties": { + "default_browser_return_url": { + "$ref": "#/definitions/defaultReturnTo" + }, + "hooks": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/selfServiceWebHook" + }, + { + "$ref": "#/definitions/selfServiceSessionRevokerHook" + } + ] + }, + "uniqueItems": true, + "additionalItems": false + } + } + }, "selfServiceAfterDefaultLoginMethod": { "type": "object", "additionalProperties": false, @@ -787,6 +760,9 @@ }, { "$ref": "#/definitions/selfServiceRequireVerifiedAddressHook" + }, + { + "$ref": "#/definitions/b2bSSOHook" } ] }, @@ -814,6 +790,9 @@ }, { "$ref": "#/definitions/selfServiceShowVerificationUIHook" + }, + { + "$ref": "#/definitions/b2bSSOHook" } ] }, @@ -826,10 +805,7 @@ "title": "Required Authenticator Assurance Level", "description": "Sets what Authenticator Assurance Level (used for 2FA) is required to access this feature. If set to `highest_available` then this endpoint requires the highest AAL the identity has set up. If set to `aal1` then the identity can access this feature without 2FA.", "type": "string", - "enum": [ - "aal1", - "highest_available" - ], + "enum": ["aal1", "highest_available"], "default": "highest_available" }, "selfServiceAfterSettings": { @@ -840,7 +816,19 @@ "$ref": "#/definitions/defaultReturnTo" }, "password": { - "$ref": "#/definitions/selfServiceAfterSettingsMethod" + "$ref": "#/definitions/selfServiceAfterSettingsAuthMethod" + }, + "totp": { + "$ref": "#/definitions/selfServiceAfterSettingsAuthMethod" + }, + "oidc": { + "$ref": "#/definitions/selfServiceAfterSettingsAuthMethod" + }, + "webauthn": { + "$ref": "#/definitions/selfServiceAfterSettingsAuthMethod" + }, + "lookup_secret": { + "$ref": "#/definitions/selfServiceAfterSettingsAuthMethod" }, "profile": { "$ref": "#/definitions/selfServiceAfterSettingsMethod" @@ -875,6 +863,15 @@ "oidc": { "$ref": "#/definitions/selfServiceAfterOIDCLoginMethod" }, + "code": { + "$ref": "#/definitions/selfServiceAfterDefaultLoginMethod" + }, + "totp": { + "$ref": "#/definitions/selfServiceAfterDefaultLoginMethod" + }, + "lookup_secret": { + "$ref": "#/definitions/selfServiceAfterDefaultLoginMethod" + }, "hooks": { "type": "array", "items": { @@ -887,6 +884,9 @@ }, { "$ref": "#/definitions/selfServiceRequireVerifiedAddressHook" + }, + { + "$ref": "#/definitions/b2bSSOHook" } ] }, @@ -947,6 +947,9 @@ "oidc": { "$ref": "#/definitions/selfServiceAfterRegistrationMethod" }, + "code": { + "$ref": "#/definitions/selfServiceAfterRegistrationMethod" + }, "hooks": { "$ref": "#/definitions/selfServiceHooks" } @@ -983,9 +986,7 @@ "path": { "title": "Path to PEM-encoded Fle", "type": "string", - "examples": [ - "path/to/file.pem" - ] + "examples": ["path/to/file.pem"] }, "base64": { "title": "Base64 Encoded Inline", @@ -1033,9 +1034,7 @@ "$ref": "#/definitions/emailCourierTemplate" } }, - "required": [ - "email" - ] + "required": ["email"] }, "valid": { "additionalProperties": false, @@ -1043,11 +1042,33 @@ "properties": { "email": { "$ref": "#/definitions/emailCourierTemplate" + }, + "sms": { + "$ref": "#/definitions/smsCourierTemplate" } }, - "required": [ - "email" - ] + "required": ["email"] + } + } + }, + "smsCourierTemplate": { + "additionalProperties": false, + "type": "object", + "properties": { + "body": { + "additionalProperties": false, + "type": "object", + "properties": { + "plaintext": { + "type": "string", + "description": "A template send to the SMS provider.", + "format": "uri", + "examples": [ + "file://path/to/body.plaintext.gotmpl", + "https://foo.bar.com/path/to/body.plaintext.gotmpl" + ] + } + } } } }, @@ -1097,9 +1118,7 @@ "selfservice": { "type": "object", "additionalProperties": false, - "required": [ - "default_browser_return_url" - ], + "required": ["default_browser_return_url"], "properties": { "default_browser_return_url": { "$ref": "#/definitions/defaultReturnTo" @@ -1116,7 +1135,8 @@ [ "https://app.my-app.com/dashboard", "/dashboard", - "https://www.my-app.com/" + "https://www.my-app.com/", + "https://*.my-app.com/" ] ] }, @@ -1133,30 +1153,20 @@ "description": "URL where the Settings UI is hosted. Check the [reference implementation](https://github.com/ory/kratos-selfservice-ui-node).", "type": "string", "format": "uri-reference", - "examples": [ - "https://my-app.com/user/settings" - ], + "examples": ["https://my-app.com/user/settings"], "default": "https://www.ory.sh/kratos/docs/fallback/settings" }, "lifespan": { "type": "string", "pattern": "^([0-9]+(ns|us|ms|s|m|h))+$", "default": "1h", - "examples": [ - "1h", - "1m", - "1s" - ] + "examples": ["1h", "1m", "1s"] }, "privileged_session_max_age": { "type": "string", "pattern": "^([0-9]+(ns|us|ms|s|m|h))+$", "default": "1h", - "examples": [ - "1h", - "1m", - "1s" - ] + "examples": ["1h", "1m", "1s"] }, "required_aal": { "$ref": "#/definitions/featureRequiredAal" @@ -1194,25 +1204,25 @@ "description": "If set to true will enable [User Registration](https://www.ory.sh/kratos/docs/self-service/flows/user-registration/).", "default": true }, + "login_hints": { + "type": "boolean", + "title": "Provide Login Hints on Failed Registration", + "description": "When registration fails because an account with the given credentials or addresses previously signed up, provide login hints about available methods to sign in to the user.", + "default": false + }, "ui_url": { "title": "Registration UI URL", "description": "URL where the Registration UI is hosted. Check the [reference implementation](https://github.com/ory/kratos-selfservice-ui-node).", "type": "string", "format": "uri-reference", - "examples": [ - "https://my-app.com/signup" - ], + "examples": ["https://my-app.com/signup"], "default": "https://www.ory.sh/kratos/docs/fallback/registration" }, "lifespan": { "type": "string", "pattern": "^([0-9]+(ns|us|ms|s|m|h))+$", "default": "1h", - "examples": [ - "1h", - "1m", - "1s" - ] + "examples": ["1h", "1m", "1s"] }, "before": { "$ref": "#/definitions/selfServiceBeforeRegistration" @@ -1231,20 +1241,14 @@ "description": "URL where the Login UI is hosted. Check the [reference implementation](https://github.com/ory/kratos-selfservice-ui-node).", "type": "string", "format": "uri-reference", - "examples": [ - "https://my-app.com/login" - ], + "examples": ["https://my-app.com/login"], "default": "https://www.ory.sh/kratos/docs/fallback/login" }, "lifespan": { "type": "string", "pattern": "^([0-9]+(ns|us|ms|s|m|h))+$", "default": "1h", - "examples": [ - "1h", - "1m", - "1s" - ] + "examples": ["1h", "1m", "1s"] }, "before": { "$ref": "#/definitions/selfServiceBeforeLogin" @@ -1270,9 +1274,7 @@ "description": "URL where the Ory Verify UI is hosted. This is the page where users activate and / or verify their email or telephone number. Check the [reference implementation](https://github.com/ory/kratos-selfservice-ui-node).", "type": "string", "format": "uri-reference", - "examples": [ - "https://my-app.com/verify" - ], + "examples": ["https://my-app.com/verify"], "default": "https://www.ory.sh/kratos/docs/fallback/verification" }, "after": { @@ -1284,11 +1286,7 @@ "type": "string", "pattern": "^([0-9]+(ns|us|ms|s|m|h))+$", "default": "1h", - "examples": [ - "1h", - "1m", - "1s" - ] + "examples": ["1h", "1m", "1s"] }, "before": { "$ref": "#/definitions/selfServiceBeforeVerification" @@ -1297,10 +1295,7 @@ "title": "Verification Strategy", "description": "The strategy to use for verification requests", "type": "string", - "enum": [ - "link", - "code" - ], + "enum": ["link", "code"], "default": "code" }, "notify_unknown_recipients": { @@ -1327,9 +1322,7 @@ "description": "URL where the Ory Recovery UI is hosted. This is the page where users request and complete account recovery. Check the [reference implementation](https://github.com/ory/kratos-selfservice-ui-node).", "type": "string", "format": "uri-reference", - "examples": [ - "https://my-app.com/verify" - ], + "examples": ["https://my-app.com/verify"], "default": "https://www.ory.sh/kratos/docs/fallback/recovery" }, "after": { @@ -1341,11 +1334,7 @@ "type": "string", "pattern": "^([0-9]+(ns|us|ms|s|m|h))+$", "default": "1h", - "examples": [ - "1h", - "1m", - "1s" - ] + "examples": ["1h", "1m", "1s"] }, "before": { "$ref": "#/definitions/selfServiceBeforeRecovery" @@ -1354,10 +1343,7 @@ "title": "Recovery Strategy", "description": "The strategy to use for recovery requests", "type": "string", - "enum": [ - "link", - "code" - ], + "enum": ["link", "code"], "default": "code" }, "notify_unknown_recipients": { @@ -1377,9 +1363,7 @@ "description": "URL where the Ory Kratos Error UI is hosted. Check the [reference implementation](https://github.com/ory/kratos-selfservice-ui-node).", "type": "string", "format": "uri-reference", - "examples": [ - "https://my-app.com/kratos-error" - ], + "examples": ["https://my-app.com/kratos-error"], "default": "https://www.ory.sh/kratos/docs/fallback/error" } } @@ -1418,20 +1402,14 @@ "base_url": { "title": "Override the base URL which should be used as the base for recovery and verification links.", "type": "string", - "examples": [ - "https://my-app.com" - ] + "examples": ["https://my-app.com"] }, "lifespan": { "title": "How long a link is valid for", "type": "string", "pattern": "^([0-9]+(ns|us|ms|s|m|h))+$", "default": "1h", - "examples": [ - "1h", - "1m", - "1s" - ] + "examples": ["1h", "1m", "1s"] } } } @@ -1440,7 +1418,44 @@ "code": { "type": "object", "additionalProperties": false, + "anyOf": [ + { + "properties": { + "passwordless_enabled": { "const": true }, + "mfa_enabled": { "const": false } + } + }, + { + "properties": { + "mfa_enabled": { "const": true }, + "passwordless_enabled": { "const": false } + } + }, + { + "properties": { + "mfa_enabled": { "const": false }, + "passwordless_enabled": { "const": false } + } + } + ], "properties": { + "passwordless_enabled": { + "type": "boolean", + "title": "Enables login and registration with the code method.", + "description": "If set to true, code.enabled will be set to true as well.", + "default": false + }, + "mfa_enabled": { + "type": "boolean", + "title": "Enables login flows code method to fulfil MFA requests", + "default": false + }, + "passwordless_login_fallback_enabled": { + "type": "boolean", + "title": "Passwordless Login Fallback Enabled", + "description": "This setting allows the code method to always login a user with code if they have registered with another authentication method such as password or social sign in.", + "default": false + }, "enabled": { "type": "boolean", "title": "Enables Code Method", @@ -1456,11 +1471,7 @@ "type": "string", "pattern": "^([0-9]+(ns|us|ms|s|m|h))+$", "default": "1h", - "examples": [ - "1h", - "1m", - "1s" - ] + "examples": ["1h", "1m", "1s"] } } } @@ -1578,47 +1589,88 @@ }, "rp": { "title": "Relying Party (RP) Config", - "required": [ - "id", - "display_name" - ], "properties": { "display_name": { "type": "string", "title": "Relying Party Display Name", "description": "An name to help the user identify this RP.", - "examples": [ - "Ory Foundation" - ] + "examples": ["Ory Foundation"] }, "id": { "type": "string", "title": "Relying Party Identifier", "description": "The id must be a subset of the domain currently in the browser.", - "examples": [ - "ory.sh" - ] + "examples": ["ory.sh"] }, "origin": { "type": "string", "title": "Relying Party Origin", - "description": "An explicit RP origin. If left empty, this defaults to `id`.", + "description": "An explicit RP origin. If left empty, this defaults to `id`, prepended with the current protocol schema (HTTP or HTTPS).", "format": "uri", - "examples": [ - "https://www.ory.sh/login" - ] + "deprecationMessage": "This field is deprecated. Use `origins` instead.", + "examples": ["https://www.ory.sh"] + }, + "origins": { + "type": "array", + "title": "Relying Party Origins", + "description": "A list of explicit RP origins. If left empty, this defaults to either `origin` or `id`, prepended with the current protocol schema (HTTP or HTTPS).", + "items": { + "type": "string", + "format": "uri", + "examples": [ + "https://www.ory.sh", + "https://auth.ory.sh" + ] + } }, "icon": { "type": "string", "title": "Relying Party Icon", "description": "An icon to help the user identify this RP.", "format": "uri", - "examples": [ - "https://www.ory.sh/an-icon.png" - ] + "deprecationMessage": "This field is deprecated and ignored due to security considerations.", + "examples": ["https://www.ory.sh/an-icon.png"] } }, - "type": "object" + "type": "object", + "oneOf": [ + { + "required": ["id", "display_name"], + "properties": { + "origin": { + "not": {} + }, + "origins": { + "not": {} + } + } + }, + { + "required": ["id", "display_name", "origin"], + "properties": { + "origin": { + "type": "string" + }, + "origins": { + "not": {} + } + } + }, + { + "required": ["id", "display_name", "origins"], + "properties": { + "origin": { + "not": {} + }, + "origins": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + ] } }, "additionalProperties": false @@ -1630,14 +1682,10 @@ "const": true } }, - "required": [ - "enabled" - ] + "required": ["enabled"] }, "then": { - "required": [ - "config" - ] + "required": ["config"] } }, "oidc": { @@ -1660,9 +1708,7 @@ "title": "Base URL for OAuth2 Redirect URIs", "description": "Can be used to modify the base URL for OAuth2 Redirect URLs. If unset, the Public Base URL will be used.", "format": "uri", - "examples": [ - "https://auth.myexample.org/" - ] + "examples": ["https://auth.myexample.org/"] }, "providers": { "title": "OpenID Connect and OAuth2 Providers", @@ -1754,6 +1800,41 @@ }, "verification_code": { "$ref": "#/definitions/courierTemplates" + }, + "registration_code": { + "additionalProperties": false, + "type": "object", + "properties": { + "valid": { + "additionalProperties": false, + "type": "object", + "properties": { + "email": { + "$ref": "#/definitions/emailCourierTemplate" + } + }, + "required": ["email"] + } + } + }, + "login_code": { + "additionalProperties": false, + "type": "object", + "properties": { + "valid": { + "additionalProperties": false, + "type": "object", + "properties": { + "email": { + "$ref": "#/definitions/emailCourierTemplate" + }, + "sms": { + "$ref": "#/definitions/smsCourierTemplate" + } + }, + "required": ["email"] + } + } } } }, @@ -1761,27 +1842,36 @@ "type": "string", "title": "Override message templates", "description": "You can override certain or all message templates by pointing this key to the path where the templates are located.", - "examples": [ - "/conf/courier-templates" - ] + "examples": ["/conf/courier-templates"] }, "message_retries": { "description": "Defines the maximum number of times the sending of a message is retried after it failed before it is marked as abandoned", "type": "integer", "default": 5, - "examples": [ - 10, - 60 - ] + "examples": [10, 60] + }, + "worker": { + "description": "Configures the dispatch worker.", + "type": "object", + "properties": { + "pull_count": { + "description": "Defines how many messages are pulled from the queue at once.", + "type": "integer", + "default": 10 + }, + "pull_wait": { + "description": "Defines how long the worker waits before pulling messages from the queue again.", + "type": "string", + "pattern": "^([0-9]+(ns|us|ms|s|m|h))+$", + "default": "1s" + } + } }, "delivery_strategy": { "title": "Delivery Strategy", "description": "Defines how emails will be sent, either through SMTP (default) or HTTP.", "type": "string", - "enum": [ - "smtp", - "http" - ], + "enum": ["smtp", "http"], "default": "smtp" }, "http": { @@ -1838,9 +1928,7 @@ "title": "SMTP Sender Name", "description": "The recipient of an email will see this as the sender name.", "type": "string", - "examples": [ - "Bob" - ] + "examples": ["Bob"] }, "headers": { "title": "SMTP Headers", @@ -1864,9 +1952,7 @@ "default": "localhost" } }, - "required": [ - "connection_uri" - ], + "required": ["connection_uri"], "additionalProperties": false }, "sms": { @@ -1891,9 +1977,7 @@ "url": { "title": "HTTP address of API endpoint", "description": "This URL will be used to connect to the SMS provider.", - "examples": [ - "https://api.twillio.com/sms/send" - ], + "examples": ["https://api.twillio.com/sms/send"], "type": "string", "pattern": "^https?:\\/\\/.*" }, @@ -1935,14 +2019,38 @@ }, "additionalProperties": false }, - "required": [ - "url", - "method" - ], + "required": ["url", "method"], "additionalProperties": false } }, "additionalProperties": false + }, + "channels": { + "type": "array", + "items": { + "title": "Courier channel configuration", + "type": "object", + "properties": { + "id": { + "type": "string", + "title": "Channel id", + "description": "The channel id. Corresponds to the .via property of the identity schema for recovery, verification, etc. Currently only phone is supported.", + "maxLength": 32, + "enum": ["sms"] + }, + "type": { + "type": "string", + "title": "Channel type", + "description": "The channel type. Currently only http is supported.", + "enum": ["http"] + }, + "request_config": { + "$ref": "#/definitions/httpRequestConfig" + } + }, + "required": ["id", "request_config"], + "additionalProperties": false + } } }, "additionalProperties": false @@ -1983,6 +2091,19 @@ }, "additionalProperties": false }, + "preview": { + "title": "Configure Preview Features", + "type": "object", + "properties": { + "default_read_consistency_level": { + "type": "string", + "title": "Default Read Consistency Level", + "description": "The default consistency level to use when reading from the database. Defaults to `strong` to not break existing API contracts. Only set this to `eventual` if you can accept that other read APIs will suddenly return eventually consistent results. It is only effective in Ory Network.", + "enum": ["strong", "eventual"], + "default": "strong" + } + } + }, "serve": { "type": "object", "properties": { @@ -2006,9 +2127,7 @@ "description": "The URL where the admin endpoint is exposed at.", "type": "string", "format": "uri", - "examples": [ - "https://kratos.private-network:4434/" - ] + "examples": ["https://kratos.private-network:4434/"] }, "host": { "title": "Admin Host", @@ -2022,9 +2141,7 @@ "type": "integer", "minimum": 1, "maximum": 65535, - "examples": [ - 4434 - ], + "examples": [4434], "default": 4434 }, "socket": { @@ -2083,9 +2200,7 @@ ] }, "uniqueItems": true, - "default": [ - "*" - ], + "default": ["*"], "examples": [ [ "https://example.com", @@ -2097,13 +2212,7 @@ "allowed_methods": { "type": "array", "description": "A list of HTTP methods the user agent is allowed to use with cross-domain requests.", - "default": [ - "POST", - "GET", - "PUT", - "PATCH", - "DELETE" - ], + "default": ["POST", "GET", "PUT", "PATCH", "DELETE"], "items": { "type": "string", "enum": [ @@ -2125,7 +2234,10 @@ "default": [ "Authorization", "Content-Type", - "X-Session-Token" + "Max-Age", + "X-Session-Token", + "X-XSRF-TOKEN", + "X-CSRF-TOKEN" ], "items": { "type": "string" @@ -2134,9 +2246,7 @@ "exposed_headers": { "type": "array", "description": "Sets which headers are safe to expose to the API of a CORS API specification.", - "default": [ - "Content-Type" - ], + "default": ["Content-Type"], "items": { "type": "string" } @@ -2179,9 +2289,7 @@ "type": "integer", "minimum": 1, "maximum": 65535, - "examples": [ - 4433 - ], + "examples": [4433], "default": 4433 }, "socket": { @@ -2197,7 +2305,7 @@ "additionalProperties": false }, "tracing": { - "$ref": "https://raw.githubusercontent.com/ory/x/v0.0.562/otelx/config.schema.json" + "$ref": "https://raw.githubusercontent.com/ory/x/v0.0.611/otelx/config.schema.json" }, "log": { "title": "Log", @@ -2231,10 +2339,7 @@ "format": { "description": "The log format can either be text or JSON.", "type": "string", - "enum": [ - "json", - "text" - ] + "enum": ["json", "text"] } }, "additionalProperties": false @@ -2275,9 +2380,7 @@ "id": { "title": "The schema's ID.", "type": "string", - "examples": [ - "employee" - ] + "examples": ["employee"] }, "url": { "type": "string", @@ -2291,16 +2394,11 @@ ] } }, - "required": [ - "id", - "url" - ] + "required": ["id", "url"] } } }, - "required": [ - "schemas" - ], + "required": ["schemas"], "additionalProperties": false }, "secrets": { @@ -2349,10 +2447,7 @@ "description": "One of the values: argon2, bcrypt.\nAny other hashes will be migrated to the set algorithm once an identity authenticates using their password.", "type": "string", "default": "bcrypt", - "enum": [ - "argon2", - "bcrypt" - ] + "enum": ["argon2", "bcrypt"] }, "argon2": { "title": "Configuration for the Argon2id hasher.", @@ -2408,9 +2503,7 @@ "title": "Configuration for the Bcrypt hasher. Minimum is 4 when --dev flag is used and 12 otherwise.", "type": "object", "additionalProperties": false, - "required": [ - "cost" - ], + "required": ["cost"], "properties": { "cost": { "type": "integer", @@ -2432,11 +2525,7 @@ "description": "One of the values: noop, aes, xchacha20-poly1305", "type": "string", "default": "noop", - "enum": [ - "noop", - "aes", - "xchacha20-poly1305" - ] + "enum": ["noop", "aes", "xchacha20-poly1305"] } } }, @@ -2460,11 +2549,7 @@ "title": "HTTP Cookie Same Site Configuration", "description": "Sets the session and CSRF cookie SameSite.", "type": "string", - "enum": [ - "Strict", - "Lax", - "None" - ], + "enum": ["Strict", "Lax", "None"], "default": "Lax" } }, @@ -2481,6 +2566,42 @@ "properties": { "required_aal": { "$ref": "#/definitions/featureRequiredAal" + }, + "tokenizer": { + "title": "Tokenizer configuration", + "description": "Configure the tokenizer, responsible for converting a session into a token format such as JWT.", + "type": "object", + "properties": { + "templates": { + "title": "Tokenizer templates", + "description": "A list of different templates that govern how a session is converted to a token format.", + "type": "object", + "patternProperties": { + "[a-zA-Z0-9-_.]+": { + "type": "object", + "required": ["jwks_url"], + "properties": { + "ttl": { + "type": "string", + "pattern": "^([0-9]+(ns|us|ms|s|m|h))+$", + "default": "1m", + "title": "Token time to live" + }, + "claims_mapper_url": { + "type": "string", + "format": "uri", + "title": "JsonNet mapper URL" + }, + "jwks_url": { + "type": "string", + "format": "uri", + "title": "JSON Web Key Set URL" + } + } + } + } + } + } } }, "additionalProperties": false @@ -2491,11 +2612,7 @@ "type": "string", "pattern": "^([0-9]+(ns|us|ms|s|m|h))+$", "default": "24h", - "examples": [ - "1h", - "1m", - "1s" - ] + "examples": ["1h", "1m", "1s"] }, "cookie": { "type": "object", @@ -2526,11 +2643,7 @@ "title": "Session Cookie SameSite Configuration", "description": "Sets the session cookie SameSite. Overrides `cookies.same_site`.", "type": "string", - "enum": [ - "Strict", - "Lax", - "None" - ] + "enum": ["Strict", "Lax", "None"] } }, "additionalProperties": false @@ -2540,12 +2653,7 @@ "description": "Sets when a session can be extended. Settings this value to `24h` will prevent the session from being extended before until 24 hours before it expires. This setting prevents excessive writes to the database. We highly recommend setting this value.", "type": "string", "pattern": "^([0-9]+(ns|us|ms|s|m|h))+$", - "default": "24h", - "examples": [ - "1h", - "1m", - "1s" - ] + "examples": ["1h", "1m", "1s"] } } }, @@ -2554,9 +2662,7 @@ "description": "SemVer according to https://semver.org/ prefixed with `v` as in our releases.", "type": "string", "pattern": "^(v(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?)|$", - "examples": [ - "v0.5.0-alpha.1" - ] + "examples": ["v0.5.0-alpha.1"] }, "dev": { "type": "boolean" @@ -2580,9 +2686,7 @@ "type": "integer", "minimum": 0, "maximum": 65535, - "examples": [ - 4434 - ], + "examples": [4434], "default": 0 }, "config": { @@ -2630,9 +2734,21 @@ "title": "Enable Ory Sessions caching", "description": "If enabled allows Ory Sessions to be cached. Only effective in the Ory Network.", "default": false + }, + "use_continue_with_transitions": { + "type": "boolean", + "title": "Enable new flow transitions using `continue_with` items", + "description": "If enabled allows new flow transitions using `continue_with` items.", + "default": false } }, "additionalProperties": false + }, + "organizations": { + "title": "Organizations", + "description": "Secifies which organizations are available. Only effective in the Ory Network.", + "type": "array", + "default": [] } }, "allOf": [ @@ -2651,14 +2767,10 @@ "const": true } }, - "required": [ - "enabled" - ] + "required": ["enabled"] } }, - "required": [ - "verification" - ] + "required": ["verification"] }, { "properties": { @@ -2668,31 +2780,21 @@ "const": true } }, - "required": [ - "enabled" - ] + "required": ["enabled"] } }, - "required": [ - "recovery" - ] + "required": ["recovery"] } ] } }, - "required": [ - "flows" - ] + "required": ["flows"] } }, - "required": [ - "selfservice" - ] + "required": ["selfservice"] }, "then": { - "required": [ - "courier" - ] + "required": ["courier"] } }, { @@ -2711,33 +2813,21 @@ ] } }, - "required": [ - "algorithm" - ] + "required": ["algorithm"] } }, - "required": [ - "ciphers" - ] + "required": ["ciphers"] }, "then": { - "required": [ - "secrets" - ], + "required": ["secrets"], "properties": { "secrets": { - "required": [ - "cipher" - ] + "required": ["cipher"] } } } } ], - "required": [ - "identity", - "dsn", - "selfservice" - ], + "required": ["identity", "dsn", "selfservice"], "additionalProperties": false } From bff9c61b147648ab139e7e86cda4336b5d1cfd39 Mon Sep 17 00:00:00 2001 From: Henning Perl Date: Fri, 2 Feb 2024 09:59:28 +0100 Subject: [PATCH 258/282] feat: list by OIDC cred (#3721) --- identity/handler_test.go | 42 +++++++++++++------ identity/test/pool.go | 6 +-- internal/client-go/go.sum | 1 + .../sql/identity/persister_identity.go | 12 ++++-- 4 files changed, 42 insertions(+), 19 deletions(-) diff --git a/identity/handler_test.go b/identity/handler_test.go index 0d5c031cbfad..ab20e8780ca6 100644 --- a/identity/handler_test.go +++ b/identity/handler_test.go @@ -466,29 +466,47 @@ func TestHandler(t *testing.T) { }) t.Run("case=should be able to lookup the identity using identifier", func(t *testing.T) { - i1 := &identity.Identity{ + ident := &identity.Identity{ Credentials: map[identity.CredentialsType]identity.Credentials{ identity.CredentialsTypePassword: { Type: identity.CredentialsTypePassword, Identifiers: []string{"find.by.identifier@bar.com"}, Config: sqlxx.JSONRawMessage(`{"hashed_password":"$2a$08$.cOYmAd.vCpDOoiVJrO5B.hjTLKQQ6cAK40u8uB.FnZDyPvVvQ9Q."}`), // foobar }, + identity.CredentialsTypeOIDC: { + Type: identity.CredentialsTypeOIDC, + Identifiers: []string{"ProviderID:293b5d9b-1009-4600-a3e9-bd1845de22f2"}, + Config: sqlxx.JSONRawMessage("{\"some\" : \"secret\"}"), + }, }, State: identity.StateActive, Traits: identity.Traits(`{"username":"find.by.identifier@bar.com"}`), } + require.NoError(t, reg.PrivilegedIdentityPool().CreateIdentity(context.Background(), ident)) + + t.Run("type=password", func(t *testing.T) { + res := get(t, adminTS, "/identities?credentials_identifier=FIND.BY.IDENTIFIER@bar.com", http.StatusOK) + assert.EqualValues(t, ident.ID.String(), res.Get("0.id").String(), "%s", res.Raw) + assert.EqualValues(t, "find.by.identifier@bar.com", res.Get("0.traits.username").String(), "%s", res.Raw) + assert.EqualValues(t, defaultSchemaExternalURL, res.Get("0.schema_url").String(), "%s", res.Raw) + assert.EqualValues(t, config.DefaultIdentityTraitsSchemaID, res.Get("0.schema_id").String(), "%s", res.Raw) + assert.EqualValues(t, identity.StateActive, res.Get("0.state").String(), "%s", res.Raw) + assert.EqualValues(t, "password", res.Get("0.credentials.password.type").String(), res.Raw) + assert.EqualValues(t, "1", res.Get("0.credentials.password.identifiers.#").String(), res.Raw) + assert.EqualValues(t, "find.by.identifier@bar.com", res.Get("0.credentials.password.identifiers.0").String(), res.Raw) + }) - require.NoError(t, reg.PrivilegedIdentityPool().CreateIdentity(context.Background(), i1)) - - res := get(t, adminTS, "/identities?credentials_identifier=find.by.identifier@bar.com", http.StatusOK) - assert.EqualValues(t, i1.ID.String(), res.Get("0.id").String(), "%s", res.Raw) - assert.EqualValues(t, "find.by.identifier@bar.com", res.Get("0.traits.username").String(), "%s", res.Raw) - assert.EqualValues(t, defaultSchemaExternalURL, res.Get("0.schema_url").String(), "%s", res.Raw) - assert.EqualValues(t, config.DefaultIdentityTraitsSchemaID, res.Get("0.schema_id").String(), "%s", res.Raw) - assert.EqualValues(t, identity.StateActive, res.Get("0.state").String(), "%s", res.Raw) - assert.EqualValues(t, "password", res.Get("0.credentials.password.type").String(), res.Raw) - assert.EqualValues(t, "1", res.Get("0.credentials.password.identifiers.#").String(), res.Raw) - assert.EqualValues(t, "find.by.identifier@bar.com", res.Get("0.credentials.password.identifiers.0").String(), res.Raw) + t.Run("type=oidc", func(t *testing.T) { + res := get(t, adminTS, "/identities?credentials_identifier=ProviderID:293b5d9b-1009-4600-a3e9-bd1845de22f2", http.StatusOK) + assert.EqualValues(t, ident.ID.String(), res.Get("0.id").String(), "%s", res.Raw) + assert.EqualValues(t, "find.by.identifier@bar.com", res.Get("0.traits.username").String(), "%s", res.Raw) + assert.EqualValues(t, defaultSchemaExternalURL, res.Get("0.schema_url").String(), "%s", res.Raw) + assert.EqualValues(t, config.DefaultIdentityTraitsSchemaID, res.Get("0.schema_id").String(), "%s", res.Raw) + assert.EqualValues(t, identity.StateActive, res.Get("0.state").String(), "%s", res.Raw) + assert.EqualValues(t, "oidc", res.Get("0.credentials.oidc.type").String(), res.Raw) + assert.EqualValues(t, "1", res.Get("0.credentials.oidc.identifiers.#").String(), res.Raw) + assert.EqualValues(t, "ProviderID:293b5d9b-1009-4600-a3e9-bd1845de22f2", res.Get("0.credentials.oidc.identifiers.0").String(), res.Raw) + }) }) t.Run("case=should get oidc credential", func(t *testing.T) { diff --git a/identity/test/pool.go b/identity/test/pool.go index 8acf9dbfd078..c351c57c6160 100644 --- a/identity/test/pool.go +++ b/identity/test/pool.go @@ -771,7 +771,7 @@ func TestPool(ctx context.Context, conf *config.Config, p persistence.Persister, Expand: identity.ExpandCredentials, }) require.NoError(t, err) - assert.Len(t, actual, 3) + assert.Len(t, actual, 4) // webauthn, common, password, oidc outer: for _, e := range append(expectedIdentities[:2], create) { @@ -789,13 +789,13 @@ func TestPool(ctx context.Context, conf *config.Config, p persistence.Persister, } }) - t.Run("only webauthn and password", func(t *testing.T) { + t.Run("find by OIDC identifier", func(t *testing.T) { actual, next, err := p.ListIdentities(ctx, identity.ListIdentityParameters{ CredentialsIdentifier: "find-identity-by-identifier-oidc@ory.sh", Expand: identity.ExpandEverything, }) require.NoError(t, err) - assert.Len(t, actual, 0) + assert.Len(t, actual, 1) assert.True(t, next.IsLast()) }) diff --git a/internal/client-go/go.sum b/internal/client-go/go.sum index c966c8ddfd0d..6cc3f5911d11 100644 --- a/internal/client-go/go.sum +++ b/internal/client-go/go.sum @@ -4,6 +4,7 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/persistence/sql/identity/persister_identity.go b/persistence/sql/identity/persister_identity.go index 1bfbf107ee0a..00f3a22d38dd 100644 --- a/persistence/sql/identity/persister_identity.go +++ b/persistence/sql/identity/persister_identity.go @@ -762,16 +762,20 @@ func (p *IdentityPersister) ListIdentities(ctx context.Context, params identity. if len(identifier) > 0 { // When filtering by credentials identifier, we most likely are looking for a username or email. It is therefore // important to normalize the identifier before querying the database. - identifier = NormalizeIdentifier(identity.CredentialsTypePassword, identifier) joins = ` INNER JOIN identity_credentials ic ON ic.identity_id = identities.id INNER JOIN identity_credential_types ict ON ict.id = ic.identity_credential_type_id INNER JOIN identity_credential_identifiers ici ON ici.identity_credential_id = ic.id` wheres += fmt.Sprintf(` - AND (ic.nid = ? AND ici.nid = ? AND ici.identifier %s ?) - AND ict.name IN (?, ?)`, identifierOperator) - args = append(args, nid, nid, identifier, identity.CredentialsTypeWebAuthn, identity.CredentialsTypePassword) + AND ic.nid = ? AND ici.nid = ? + AND ((ict.name IN (?, ?, ?) AND ici.identifier %s ?) + OR (ict.name IN (?) AND ici.identifier %s ?)) + `, identifierOperator, identifierOperator) + args = append(args, + nid, nid, + identity.CredentialsTypeWebAuthn, identity.CredentialsTypePassword, identity.CredentialsTypeCodeAuth, NormalizeIdentifier(identity.CredentialsTypePassword, identifier), + identity.CredentialsTypeOIDC, identifier) } if params.IdsFilter != nil && len(params.IdsFilter) != 0 { From f082f16e5c525c5bb5bf683faded781b2ad87bf8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Feb 2024 09:59:40 +0100 Subject: [PATCH 259/282] chore(deps): bump github.com/lestrrat-go/jwx from 1.2.26 to 1.2.28 (#3710) Bumps [github.com/lestrrat-go/jwx](https://github.com/lestrrat-go/jwx) from 1.2.26 to 1.2.28. - [Release notes](https://github.com/lestrrat-go/jwx/releases) - [Changelog](https://github.com/lestrrat-go/jwx/blob/v1.2.28/Changes) - [Commits](https://github.com/lestrrat-go/jwx/compare/v1.2.26...v1.2.28) --- updated-dependencies: - dependency-name: github.com/lestrrat-go/jwx dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index c237b4e9e11e..6ebcb1ad1b41 100644 --- a/go.mod +++ b/go.mod @@ -57,7 +57,7 @@ require ( github.com/julienschmidt/httprouter v1.3.0 github.com/knadh/koanf/parsers/json v0.1.0 github.com/laher/mergefs v0.1.2-0.20230223191438-d16611b2f4e7 - github.com/lestrrat-go/jwx v1.2.26 // indirect + github.com/lestrrat-go/jwx v1.2.28 // indirect github.com/luna-duclos/instrumentedsql v1.1.3 github.com/mailhog/MailHog v1.0.1 github.com/mattn/goveralls v0.0.7 diff --git a/go.sum b/go.sum index 0c419864f2d4..742efc83bec1 100644 --- a/go.sum +++ b/go.sum @@ -672,7 +672,6 @@ github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A= github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y= -github.com/lestrrat-go/blackmagic v1.0.1/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU= github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k= github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU= github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE= @@ -681,8 +680,8 @@ github.com/lestrrat-go/httprc v1.0.4 h1:bAZymwoZQb+Oq8MEbyipag7iSq6YIga8Wj6GOiJG github.com/lestrrat-go/httprc v1.0.4/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo= github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI= github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4= -github.com/lestrrat-go/jwx v1.2.26 h1:4iFo8FPRZGDYe1t19mQP0zTRqA7n8HnJ5lkIiDvJcB0= -github.com/lestrrat-go/jwx v1.2.26/go.mod h1:MaiCdGbn3/cckbOFSCluJlJMmp9dmZm5hDuIkx8ftpQ= +github.com/lestrrat-go/jwx v1.2.28 h1:uadI6o0WpOVrBSf498tRXZIwPpEtLnR9CvqPFXeI5sA= +github.com/lestrrat-go/jwx v1.2.28/go.mod h1:nF+91HEMh/MYFVwKPl5HHsBGMPscqbQb+8IDQdIazP8= github.com/lestrrat-go/jwx/v2 v2.0.19 h1:ekv1qEZE6BVct89QA+pRF6+4pCpfVrOnEJnTnT4RXoY= github.com/lestrrat-go/jwx/v2 v2.0.19/go.mod h1:l3im3coce1lL2cDeAjqmaR+Awx+X8Ih+2k8BuHNJ4CU= github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= @@ -1129,7 +1128,7 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1346,6 +1345,7 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20191110171634-ad39bd3f0407/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -1359,6 +1359,7 @@ golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= From c85d95f53520ac61086ecfa565091a3f3d57478b Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Fri, 2 Feb 2024 09:01:29 +0000 Subject: [PATCH 260/282] autogen(openapi): regenerate swagger spec and internal client [skip ci] --- internal/client-go/go.sum | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/client-go/go.sum b/internal/client-go/go.sum index 6cc3f5911d11..c966c8ddfd0d 100644 --- a/internal/client-go/go.sum +++ b/internal/client-go/go.sum @@ -4,7 +4,6 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= From 1d43d22276d8b6ae42dc0014ded0237c542c585a Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Sat, 3 Feb 2024 11:52:31 +0100 Subject: [PATCH 261/282] chore: upgrade github.com/opencontainers/runc to v1.1.12 (#3732) --- go.mod | 2 +- go.sum | 31 ++----------------------------- 2 files changed, 3 insertions(+), 30 deletions(-) diff --git a/go.mod b/go.mod index 6ebcb1ad1b41..9785b1933823 100644 --- a/go.mod +++ b/go.mod @@ -255,7 +255,7 @@ require ( github.com/oklog/ulid v1.3.1 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc2 // indirect - github.com/opencontainers/runc v1.1.5 // indirect + github.com/opencontainers/runc v1.1.12 // indirect github.com/openzipkin/zipkin-go v0.4.2 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect diff --git a/go.sum b/go.sum index 742efc83bec1..7432be113df0 100644 --- a/go.sum +++ b/go.sum @@ -110,11 +110,9 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= 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/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -125,27 +123,23 @@ github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/cockroach-go/v2 v2.3.5 h1:Khtm8K6fTTz/ZCWPzU9Ne3aOW9VyAnj4qIPCJgKtwK0= github.com/cockroachdb/cockroach-go/v2 v2.3.5/go.mod h1:1wNJ45eSXW9AnOc3skntW9ZUZz6gxrQK3cOj3rK+BC8= -github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= github.com/coreos/go-oidc/v3 v3.9.0 h1:0J/ogVOd4y8P0f0xUh8l9t07xRP/d8tccvjHl2dcsSo= github.com/coreos/go-oidc/v3 v3.9.0/go.mod h1:rTKz2PYwftcrtoCzV5g5kvfJoWcm0Mk8AF8y1iAQro4= 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/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cortesi/modd v0.0.0-20210323234521-b35eddab86cc h1:JPkUs3TdeYIbBy9GTDdez9rBbbl6E9BNRa9jlfEDjnE= github.com/cortesi/modd v0.0.0-20210323234521-b35eddab86cc/go.mod h1:h20oNPW+cbtizAJwm90svrR7HlV7XvSNT5di+GP7SbA= github.com/cortesi/moddwatch v0.0.0-20210222043437-a6aaad86a36e h1:vNbhR09qtq9ELJgvhAWng4zl/4CVTPBPVev3R8MlUYc= github.com/cortesi/moddwatch v0.0.0-20210222043437-a6aaad86a36e/go.mod h1:MUkYRZrwFTHATqCI5tDJRPqmBt9xf3q4+Avfut7kCCE= github.com/cortesi/termlog v0.0.0-20210222042314-a1eec763abec h1:v7D8uHsIKsyjfyhhNdY4qivqN558Ejiq+CDXiUljZ+4= github.com/cortesi/termlog v0.0.0-20210222042314-a1eec763abec/go.mod h1:10Fm2kasJmcKf1FSMQGSWb976sfR29hejNtfS9AydB4= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 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/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= 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= @@ -166,7 +160,6 @@ github.com/docker/docker v20.10.24+incompatible h1:Ugvxm7a8+Gz6vqQYQQ2W7GYq5EUPa github.com/docker/docker v20.10.24+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= @@ -193,7 +186,6 @@ github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNu github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -348,8 +340,6 @@ github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-yaml v1.9.6 h1:KhAu1zf9JXnm3vbG49aDE0E5uEBUsM4uwD31/58ZWyI= github.com/goccy/go-yaml v1.9.6/go.mod h1:JubOolP3gh0HpiBc4BLRD4YmjEjHAmIIB2aaXKkTfoE= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= @@ -771,7 +761,6 @@ github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae h1:O4SWKdcHVCvYqyDV+9CJA1fcDN2L11Bule0iFy3YlAI= github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -785,7 +774,6 @@ github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6f github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= @@ -806,10 +794,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= -github.com/opencontainers/runc v1.1.5 h1:L44KXEpKmfWDcS02aeGm8QNTFXTo2D+8MYGDIJ/GDEs= -github.com/opencontainers/runc v1.1.5/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= -github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/opencontainers/runc v1.1.12 h1:BOIssBaW1La0/qbNZHXOOa71dZfZEQOzW7dqQf3phss= +github.com/opencontainers/runc v1.1.12/go.mod h1:S+lQwSfncpBha7XTy/5lBwWgm5+y5Ma/O44Ekby9FK8= github.com/openzipkin/zipkin-go v0.4.2 h1:zjqfqHjUpPmB3c1GlCvvgsM1G4LkvqQbBDueDOCg/jA= github.com/openzipkin/zipkin-go v0.4.2/go.mod h1:ZeVkFjuuBiSy13y8vpSDCjMi9GoI3hPpCJSBx/EYFhY= github.com/ory/analytics-go/v5 v5.0.1 h1:LX8T5B9FN8KZXOtxgN+R3I4THRRVB6+28IKgKBpXmAM= @@ -911,7 +897,6 @@ github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= 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/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samber/lo v1.37.0 h1:XjVcB8g6tgUp8rsPsJ2CvhClfImrpL04YpQHXeHPhRw= @@ -921,7 +906,6 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUt github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/seatgeek/logrus-gelf-formatter v0.0.0-20210414080842-5b05eb8ff761 h1:0b8DF5kR0PhRoRXDiEEdzrgBc8UqVY4JWLkQJCRsLME= github.com/seatgeek/logrus-gelf-formatter v0.0.0-20210414080842-5b05eb8ff761/go.mod h1:/THDZYi7F/BsVEcYzYPqdcWFQ+1C2InkawTKfLOAnzg= -github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/segmentio/analytics-go v3.1.0+incompatible/go.mod h1:C7CYBtQWk4vRk2RyLu0qOcbHJ18E3F1HV2C/8JvKN48= github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= @@ -938,13 +922,11 @@ github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9Nz github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.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.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/slack-go/slack v0.7.4 h1:Z+7CmUDV+ym4lYLA4NNLFIpr3+nDgViHrx8xsuXgrYs= @@ -996,7 +978,6 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/t-k/fluent-logger-golang v1.0.0 h1:4IQzY+/l66Zkkhk9eB3LwF9vPkgKHJ1rpYdrRiap0EI= github.com/t-k/fluent-logger-golang v1.0.0/go.mod h1:6vC3Vzp9Kva0l5J9+YDY5/ROePwkAqwLK+KneCjSm4w= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= @@ -1019,11 +1000,8 @@ github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkC github.com/toqueteos/webbrowser v1.2.0 h1:tVP/gpK69Fx+qMJKsLE7TD8LuGWPnEV71wBN9rrstGQ= github.com/toqueteos/webbrowser v1.2.0/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= -github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= -github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= @@ -1275,7 +1253,6 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1284,7 +1261,6 @@ golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1327,10 +1303,7 @@ golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= From 12166b4370d607a069f268227752bb7b18a50b57 Mon Sep 17 00:00:00 2001 From: Henning Perl Date: Mon, 5 Feb 2024 15:17:32 +0100 Subject: [PATCH 262/282] test: fix hydra tests on master (#3737) --- .github/workflows/ci.yaml | 4 +++- selfservice/strategy/oidc/strategy_helper_test.go | 5 ++++- selfservice/strategy/password/op_helpers_test.go | 3 ++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c39b51455b2b..9e4a3fd1d947 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -68,7 +68,9 @@ jobs: -e URLS_SELF_ISSUER=http://localhost:4444/ \ -e URLS_LOGIN=http://localhost:4499/login \ -e URLS_CONSENT=http://localhost:4499/consent \ - oryd/hydra:v2.0.2 serve all --dev + -e LOG_LEAK_SENSITIVE_VALUES=true \ + -e SECRETS_SYSTEM=someverylongsecretthatis32byteslong \ + oryd/hydra:v2.2.0@sha256:6c0f9195fe04ae16b095417b323881f8c9008837361160502e11587663b37c09 serve all --dev docker start hydra docker logs -f hydra &> /tmp/hydra.log & name: Start Hydra diff --git a/selfservice/strategy/oidc/strategy_helper_test.go b/selfservice/strategy/oidc/strategy_helper_test.go index 37c45bccd8c9..7b39729cc6af 100644 --- a/selfservice/strategy/oidc/strategy_helper_test.go +++ b/selfservice/strategy/oidc/strategy_helper_test.go @@ -251,12 +251,15 @@ func newHydra(t *testing.T, subject *string, claims *idTokenClaims, scope *[]str require.NoError(t, err) hydra, err := pool.RunWithOptions(&dockertest.RunOptions{ Repository: "oryd/hydra", - Tag: "v2.0.2", + // Keep tag in sync with the version in ci.yaml + Tag: "v2.2.0@sha256:6c0f9195fe04ae16b095417b323881f8c9008837361160502e11587663b37c09", Env: []string{ "DSN=memory", fmt.Sprintf("URLS_SELF_ISSUER=http://localhost:%d/", publicPort), "URLS_LOGIN=" + hydraIntegrationTSURL + "/login", "URLS_CONSENT=" + hydraIntegrationTSURL + "/consent", + "LOG_LEAK_SENSITIVE_VALUES=true", + "SECRETS_SYSTEM=someverylongsecretthatis32byteslong", }, Cmd: []string{"serve", "all", "--dev"}, ExposedPorts: []string{"4444/tcp", "4445/tcp"}, diff --git a/selfservice/strategy/password/op_helpers_test.go b/selfservice/strategy/password/op_helpers_test.go index 17422063207b..9e42ae471851 100644 --- a/selfservice/strategy/password/op_helpers_test.go +++ b/selfservice/strategy/password/op_helpers_test.go @@ -133,7 +133,8 @@ func newHydra(t *testing.T, loginUI string, consentUI string) (hydraAdmin string hydraResource, err := pool.RunWithOptions(&dockertest.RunOptions{ Repository: "oryd/hydra", - Tag: "v2.2.0", + // Keep tag in sync with the version in ci.yaml + Tag: "v2.2.0@sha256:6c0f9195fe04ae16b095417b323881f8c9008837361160502e11587663b37c09", Env: []string{ "DSN=memory", fmt.Sprintf("URLS_SELF_ISSUER=http://127.0.0.1:%d/", publicPort), From 35a820bdfa64330da4dd6d4a37d8833a16eaf524 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Mon, 5 Feb 2024 15:27:50 +0000 Subject: [PATCH 263/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 205 ++++++++++++++++++++++++++++----------------------- 1 file changed, 114 insertions(+), 91 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a69e16a2362..bdec52460770 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,235 +5,239 @@ **Table of Contents** -- [ (2024-01-31)](#2024-01-31) +- [ (2024-02-05)](#2024-02-05) + - [Features](#features) + - [Tests](#tests) +- [1.1.0-pre.0 (2024-02-01)](#110-pre0-2024-02-01) - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) + - [Code Generation](#code-generation) - [Documentation](#documentation) - - [Features](#features) + - [Features](#features-1) - [Reverts](#reverts) - - [Tests](#tests) + - [Tests](#tests-1) - [Unclassified](#unclassified) - [1.0.0 (2023-07-12)](#100-2023-07-12) - [Bug Fixes](#bug-fixes-1) - - [Code Generation](#code-generation) + - [Code Generation](#code-generation-1) - [Documentation](#documentation-1) - - [Features](#features-1) - - [Tests](#tests-1) + - [Features](#features-2) + - [Tests](#tests-2) - [Unclassified](#unclassified-1) - [0.13.0 (2023-04-18)](#0130-2023-04-18) - [Breaking Changes](#breaking-changes-1) - [Bug Fixes](#bug-fixes-2) - - [Code Generation](#code-generation-1) + - [Code Generation](#code-generation-2) - [Code Refactoring](#code-refactoring) - [Documentation](#documentation-2) - - [Features](#features-2) - - [Tests](#tests-2) + - [Features](#features-3) + - [Tests](#tests-3) - [Unclassified](#unclassified-2) - [0.11.1 (2023-01-14)](#0111-2023-01-14) - [Breaking Changes](#breaking-changes-2) - [Bug Fixes](#bug-fixes-3) - - [Code Generation](#code-generation-2) + - [Code Generation](#code-generation-3) - [Documentation](#documentation-3) - - [Features](#features-3) - - [Tests](#tests-3) + - [Features](#features-4) + - [Tests](#tests-4) - [0.11.0 (2022-12-02)](#0110-2022-12-02) - - [Code Generation](#code-generation-3) - - [Features](#features-4) + - [Code Generation](#code-generation-4) + - [Features](#features-5) - [0.11.0-alpha.0.pre.2 (2022-11-28)](#0110-alpha0pre2-2022-11-28) - [Breaking Changes](#breaking-changes-3) - [Bug Fixes](#bug-fixes-4) - - [Code Generation](#code-generation-4) + - [Code Generation](#code-generation-5) - [Code Refactoring](#code-refactoring-1) - [Documentation](#documentation-4) - - [Features](#features-5) + - [Features](#features-6) - [Reverts](#reverts-1) - - [Tests](#tests-4) + - [Tests](#tests-5) - [Unclassified](#unclassified-3) - [0.10.1 (2022-06-01)](#0101-2022-06-01) - [Bug Fixes](#bug-fixes-5) - - [Code Generation](#code-generation-5) + - [Code Generation](#code-generation-6) - [0.10.0 (2022-05-30)](#0100-2022-05-30) - [Breaking Changes](#breaking-changes-4) - [Bug Fixes](#bug-fixes-6) - - [Code Generation](#code-generation-6) + - [Code Generation](#code-generation-7) - [Code Refactoring](#code-refactoring-2) - [Documentation](#documentation-5) - - [Features](#features-6) - - [Tests](#tests-5) + - [Features](#features-7) + - [Tests](#tests-6) - [Unclassified](#unclassified-4) - [0.9.0-alpha.3 (2022-03-25)](#090-alpha3-2022-03-25) - [Breaking Changes](#breaking-changes-5) - [Bug Fixes](#bug-fixes-7) - - [Code Generation](#code-generation-7) + - [Code Generation](#code-generation-8) - [Documentation](#documentation-6) - [0.9.0-alpha.2 (2022-03-22)](#090-alpha2-2022-03-22) - [Bug Fixes](#bug-fixes-8) - - [Code Generation](#code-generation-8) + - [Code Generation](#code-generation-9) - [0.9.0-alpha.1 (2022-03-21)](#090-alpha1-2022-03-21) - [Breaking Changes](#breaking-changes-6) - [Bug Fixes](#bug-fixes-9) - - [Code Generation](#code-generation-9) + - [Code Generation](#code-generation-10) - [Code Refactoring](#code-refactoring-3) - [Documentation](#documentation-7) - - [Features](#features-7) - - [Tests](#tests-6) + - [Features](#features-8) + - [Tests](#tests-7) - [Unclassified](#unclassified-5) - [0.8.3-alpha.1.pre.0 (2022-01-21)](#083-alpha1pre0-2022-01-21) - [Breaking Changes](#breaking-changes-7) - [Bug Fixes](#bug-fixes-10) - - [Code Generation](#code-generation-10) + - [Code Generation](#code-generation-11) - [Code Refactoring](#code-refactoring-4) - [Documentation](#documentation-8) - - [Features](#features-8) - - [Tests](#tests-7) + - [Features](#features-9) + - [Tests](#tests-8) - [0.8.2-alpha.1 (2021-12-17)](#082-alpha1-2021-12-17) - [Bug Fixes](#bug-fixes-11) - - [Code Generation](#code-generation-11) + - [Code Generation](#code-generation-12) - [Documentation](#documentation-9) - [0.8.1-alpha.1 (2021-12-13)](#081-alpha1-2021-12-13) - [Bug Fixes](#bug-fixes-12) - - [Code Generation](#code-generation-12) + - [Code Generation](#code-generation-13) - [Documentation](#documentation-10) - - [Features](#features-9) - - [Tests](#tests-8) + - [Features](#features-10) + - [Tests](#tests-9) - [0.8.0-alpha.4.pre.0 (2021-11-09)](#080-alpha4pre0-2021-11-09) - [Breaking Changes](#breaking-changes-8) - [Bug Fixes](#bug-fixes-13) - - [Code Generation](#code-generation-13) + - [Code Generation](#code-generation-14) - [Documentation](#documentation-11) - - [Features](#features-10) - - [Tests](#tests-9) + - [Features](#features-11) + - [Tests](#tests-10) - [0.8.0-alpha.3 (2021-10-28)](#080-alpha3-2021-10-28) - [Bug Fixes](#bug-fixes-14) - - [Code Generation](#code-generation-14) -- [0.8.0-alpha.2 (2021-10-28)](#080-alpha2-2021-10-28) - [Code Generation](#code-generation-15) +- [0.8.0-alpha.2 (2021-10-28)](#080-alpha2-2021-10-28) + - [Code Generation](#code-generation-16) - [0.8.0-alpha.1 (2021-10-27)](#080-alpha1-2021-10-27) - [Breaking Changes](#breaking-changes-9) - [Bug Fixes](#bug-fixes-15) - - [Code Generation](#code-generation-16) + - [Code Generation](#code-generation-17) - [Code Refactoring](#code-refactoring-5) - [Documentation](#documentation-12) - - [Features](#features-11) + - [Features](#features-12) - [Reverts](#reverts-2) - - [Tests](#tests-10) + - [Tests](#tests-11) - [Unclassified](#unclassified-6) - [0.7.6-alpha.1 (2021-09-12)](#076-alpha1-2021-09-12) - - [Code Generation](#code-generation-17) -- [0.7.5-alpha.1 (2021-09-11)](#075-alpha1-2021-09-11) - [Code Generation](#code-generation-18) +- [0.7.5-alpha.1 (2021-09-11)](#075-alpha1-2021-09-11) + - [Code Generation](#code-generation-19) - [0.7.4-alpha.1 (2021-09-09)](#074-alpha1-2021-09-09) - [Bug Fixes](#bug-fixes-16) - - [Code Generation](#code-generation-19) + - [Code Generation](#code-generation-20) - [Documentation](#documentation-13) - - [Features](#features-12) - - [Tests](#tests-11) + - [Features](#features-13) + - [Tests](#tests-12) - [0.7.3-alpha.1 (2021-08-28)](#073-alpha1-2021-08-28) - [Bug Fixes](#bug-fixes-17) - - [Code Generation](#code-generation-20) + - [Code Generation](#code-generation-21) - [Documentation](#documentation-14) - - [Features](#features-13) + - [Features](#features-14) - [0.7.1-alpha.1 (2021-07-22)](#071-alpha1-2021-07-22) - [Bug Fixes](#bug-fixes-18) - - [Code Generation](#code-generation-21) + - [Code Generation](#code-generation-22) - [Documentation](#documentation-15) - - [Tests](#tests-12) + - [Tests](#tests-13) - [0.7.0-alpha.1 (2021-07-13)](#070-alpha1-2021-07-13) - [Breaking Changes](#breaking-changes-10) - [Bug Fixes](#bug-fixes-19) - - [Code Generation](#code-generation-22) + - [Code Generation](#code-generation-23) - [Code Refactoring](#code-refactoring-6) - [Documentation](#documentation-16) - - [Features](#features-14) - - [Tests](#tests-13) + - [Features](#features-15) + - [Tests](#tests-14) - [Unclassified](#unclassified-7) - [0.6.3-alpha.1 (2021-05-17)](#063-alpha1-2021-05-17) - [Breaking Changes](#breaking-changes-11) - [Bug Fixes](#bug-fixes-20) - - [Code Generation](#code-generation-23) + - [Code Generation](#code-generation-24) - [Code Refactoring](#code-refactoring-7) - [0.6.2-alpha.1 (2021-05-14)](#062-alpha1-2021-05-14) - - [Code Generation](#code-generation-24) + - [Code Generation](#code-generation-25) - [Documentation](#documentation-17) - [0.6.1-alpha.1 (2021-05-11)](#061-alpha1-2021-05-11) - - [Code Generation](#code-generation-25) - - [Features](#features-15) -- [0.6.0-alpha.2 (2021-05-07)](#060-alpha2-2021-05-07) - - [Bug Fixes](#bug-fixes-21) - [Code Generation](#code-generation-26) - [Features](#features-16) +- [0.6.0-alpha.2 (2021-05-07)](#060-alpha2-2021-05-07) + - [Bug Fixes](#bug-fixes-21) + - [Code Generation](#code-generation-27) + - [Features](#features-17) - [0.6.0-alpha.1 (2021-05-05)](#060-alpha1-2021-05-05) - [Breaking Changes](#breaking-changes-12) - [Bug Fixes](#bug-fixes-22) - - [Code Generation](#code-generation-27) + - [Code Generation](#code-generation-28) - [Code Refactoring](#code-refactoring-8) - [Documentation](#documentation-18) - - [Features](#features-17) - - [Tests](#tests-14) + - [Features](#features-18) + - [Tests](#tests-15) - [Unclassified](#unclassified-8) - [0.5.5-alpha.1 (2020-12-09)](#055-alpha1-2020-12-09) - [Bug Fixes](#bug-fixes-23) - - [Code Generation](#code-generation-28) + - [Code Generation](#code-generation-29) - [Documentation](#documentation-19) - - [Features](#features-18) - - [Tests](#tests-15) + - [Features](#features-19) + - [Tests](#tests-16) - [Unclassified](#unclassified-9) - [0.5.4-alpha.1 (2020-11-11)](#054-alpha1-2020-11-11) - [Bug Fixes](#bug-fixes-24) - - [Code Generation](#code-generation-29) + - [Code Generation](#code-generation-30) - [Code Refactoring](#code-refactoring-9) - [Documentation](#documentation-20) - - [Features](#features-19) + - [Features](#features-20) - [0.5.3-alpha.1 (2020-10-27)](#053-alpha1-2020-10-27) - [Bug Fixes](#bug-fixes-25) - - [Code Generation](#code-generation-30) + - [Code Generation](#code-generation-31) - [Documentation](#documentation-21) - - [Features](#features-20) - - [Tests](#tests-16) + - [Features](#features-21) + - [Tests](#tests-17) - [0.5.2-alpha.1 (2020-10-22)](#052-alpha1-2020-10-22) - [Bug Fixes](#bug-fixes-26) - - [Code Generation](#code-generation-31) + - [Code Generation](#code-generation-32) - [Documentation](#documentation-22) - - [Tests](#tests-17) + - [Tests](#tests-18) - [0.5.1-alpha.1 (2020-10-20)](#051-alpha1-2020-10-20) - [Bug Fixes](#bug-fixes-27) - - [Code Generation](#code-generation-32) + - [Code Generation](#code-generation-33) - [Documentation](#documentation-23) - - [Features](#features-21) - - [Tests](#tests-18) + - [Features](#features-22) + - [Tests](#tests-19) - [Unclassified](#unclassified-10) - [0.5.0-alpha.1 (2020-10-15)](#050-alpha1-2020-10-15) - [Breaking Changes](#breaking-changes-13) - [Bug Fixes](#bug-fixes-28) - - [Code Generation](#code-generation-33) + - [Code Generation](#code-generation-34) - [Code Refactoring](#code-refactoring-10) - [Documentation](#documentation-24) - - [Features](#features-22) - - [Tests](#tests-19) + - [Features](#features-23) + - [Tests](#tests-20) - [Unclassified](#unclassified-11) - [0.4.6-alpha.1 (2020-07-13)](#046-alpha1-2020-07-13) - [Bug Fixes](#bug-fixes-29) - - [Code Generation](#code-generation-34) + - [Code Generation](#code-generation-35) - [0.4.5-alpha.1 (2020-07-13)](#045-alpha1-2020-07-13) - [Bug Fixes](#bug-fixes-30) - - [Code Generation](#code-generation-35) + - [Code Generation](#code-generation-36) - [0.4.4-alpha.1 (2020-07-10)](#044-alpha1-2020-07-10) - [Bug Fixes](#bug-fixes-31) - - [Code Generation](#code-generation-36) + - [Code Generation](#code-generation-37) - [Documentation](#documentation-25) - [0.4.3-alpha.1 (2020-07-08)](#043-alpha1-2020-07-08) - [Bug Fixes](#bug-fixes-32) - - [Code Generation](#code-generation-37) + - [Code Generation](#code-generation-38) - [0.4.2-alpha.1 (2020-07-08)](#042-alpha1-2020-07-08) - [Bug Fixes](#bug-fixes-33) - - [Code Generation](#code-generation-38) + - [Code Generation](#code-generation-39) - [0.4.0-alpha.1 (2020-07-08)](#040-alpha1-2020-07-08) - [Breaking Changes](#breaking-changes-14) - [Bug Fixes](#bug-fixes-34) - - [Code Generation](#code-generation-39) + - [Code Generation](#code-generation-40) - [Code Refactoring](#code-refactoring-11) - [Documentation](#documentation-26) - - [Features](#features-23) + - [Features](#features-24) - [Unclassified](#unclassified-12) - [0.3.0-alpha.1 (2020-05-15)](#030-alpha1-2020-05-15) - [Breaking Changes](#breaking-changes-15) @@ -241,7 +245,7 @@ - [Chores](#chores) - [Code Refactoring](#code-refactoring-12) - [Documentation](#documentation-27) - - [Features](#features-24) + - [Features](#features-25) - [Unclassified](#unclassified-13) - [0.2.1-alpha.1 (2020-05-05)](#021-alpha1-2020-05-05) - [Chores](#chores-1) @@ -252,7 +256,7 @@ - [Chores](#chores-2) - [Code Refactoring](#code-refactoring-13) - [Documentation](#documentation-29) - - [Features](#features-25) + - [Features](#features-26) - [Unclassified](#unclassified-14) - [0.1.1-alpha.1 (2020-02-18)](#011-alpha1-2020-02-18) - [Bug Fixes](#bug-fixes-37) @@ -262,10 +266,10 @@ - [Bug Fixes](#bug-fixes-38) - [Code Refactoring](#code-refactoring-15) - [Documentation](#documentation-31) - - [Features](#features-26) + - [Features](#features-27) - [0.1.0-alpha.5 (2020-02-06)](#010-alpha5-2020-02-06) - [Documentation](#documentation-32) - - [Features](#features-27) + - [Features](#features-28) - [0.1.0-alpha.4 (2020-02-06)](#010-alpha4-2020-02-06) - [Continuous Integration](#continuous-integration) - [Documentation](#documentation-33) @@ -274,7 +278,7 @@ - [0.1.0-alpha.2 (2020-02-03)](#010-alpha2-2020-02-03) - [Bug Fixes](#bug-fixes-39) - [Documentation](#documentation-34) - - [Features](#features-28) + - [Features](#features-29) - [Unclassified](#unclassified-15) - [0.1.0-alpha.1 (2020-01-31)](#010-alpha1-2020-01-31) - [Documentation](#documentation-35) @@ -315,7 +319,21 @@ -# [](https://github.com/ory/kratos/compare/v1.0.0...v) (2024-01-31) +# [](https://github.com/ory/kratos/compare/v1.1.0-pre.0...v) (2024-02-05) + +### Features + +- List by OIDC cred ([#3721](https://github.com/ory/kratos/issues/3721)) + ([bff9c61](https://github.com/ory/kratos/commit/bff9c61b147648ab139e7e86cda4336b5d1cfd39)) + +### Tests + +- Fix hydra tests on master ([#3737](https://github.com/ory/kratos/issues/3737)) + ([12166b4](https://github.com/ory/kratos/commit/12166b4370d607a069f268227752bb7b18a50b57)) + +# [1.1.0-pre.0](https://github.com/ory/kratos/compare/v1.0.0...v1.1.0-pre.0) (2024-02-01) + +autogen: pin v1.1.0-pre.0 release commit ## Breaking Changes @@ -711,6 +729,11 @@ https://github.com/ory/kratos/pull/3480 ([#3522](https://github.com/ory/kratos/issues/3522)) ([4c34c24](https://github.com/ory/kratos/commit/4c34c2417db0cb1f79b42db5f33544c90b38ad87)) +### Code Generation + +- Pin v1.1.0-pre.0 release commit + ([1c3eeb7](https://github.com/ory/kratos/commit/1c3eeb71d6fc83918ac367d1654361f8fd98a93e)) + ### Documentation - Add example for `allowed_return_urls` to include wildcard url From e3bfa109908e492f62353a275281d95dc5226196 Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Mon, 5 Feb 2024 16:39:02 +0100 Subject: [PATCH 264/282] chore: update Ory Hydra SDK (#3729) --- courier/template/load_template.go | 3 ++- go.mod | 4 ++-- go.sum | 8 ++++---- hydra/hydra.go | 2 +- internal/client-go/go.sum | 1 + request/builder.go | 2 +- selfservice/strategy/oidc/strategy_registration.go | 2 +- selfservice/strategy/password/op_helpers_test.go | 6 +++--- selfservice/strategy/password/op_registration_test.go | 2 +- session/tokenizer.go | 2 +- 10 files changed, 17 insertions(+), 15 deletions(-) diff --git a/courier/template/load_template.go b/courier/template/load_template.go index 47341b8f35af..8ecb7ba9fbae 100644 --- a/courier/template/load_template.go +++ b/courier/template/load_template.go @@ -84,10 +84,11 @@ func loadRemoteTemplate(ctx context.Context, d templateDependencies, url string, b = t.([]byte) } else { f := fetcher.NewFetcher(fetcher.WithClient(d.HTTPClient(ctx))) - b, err = f.FetchContext(ctx, url) + bb, err := f.FetchContext(ctx, url) if err != nil { return nil, errors.WithStack(err) } + b = bb.Bytes() _ = Cache.Add(url, b) } diff --git a/go.mod b/go.mod index 9785b1933823..d0399c35b47b 100644 --- a/go.mod +++ b/go.mod @@ -70,11 +70,11 @@ require ( github.com/ory/go-acc v0.2.9-0.20230103102148-6b1c9a70dbbe github.com/ory/graceful v0.1.4-0.20230301144740-e222150c51d0 github.com/ory/herodot v0.10.3-0.20230626083119-d7e5192f0d88 - github.com/ory/hydra-client-go/v2 v2.2.0-rc.3 + github.com/ory/hydra-client-go/v2 v2.2.0-rc.3.0.20240202131107-1c7b57df3bb0 github.com/ory/jsonschema/v3 v3.0.8 github.com/ory/mail/v3 v3.0.0 github.com/ory/nosurf v1.2.7 - github.com/ory/x v0.0.611 + github.com/ory/x v0.0.613 github.com/peterhellberg/link v1.2.0 github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 github.com/pkg/errors v0.9.1 diff --git a/go.sum b/go.sum index 7432be113df0..4bd6bd41d159 100644 --- a/go.sum +++ b/go.sum @@ -808,8 +808,8 @@ github.com/ory/graceful v0.1.4-0.20230301144740-e222150c51d0 h1:VMUeLRfQD14fOMvh github.com/ory/graceful v0.1.4-0.20230301144740-e222150c51d0/go.mod h1:hg2iCy+LCWOXahBZ+NQa4dk8J2govyQD79rrqrgMyY8= github.com/ory/herodot v0.10.3-0.20230626083119-d7e5192f0d88 h1:J0CIFKdpUeqKbVMw7pQ1qLtUnflRM1JWAcOEq7Hp4yg= github.com/ory/herodot v0.10.3-0.20230626083119-d7e5192f0d88/go.mod h1:MMNmY6MG1uB6fnXYFaHoqdV23DTWctlPsmRCeq/2+wc= -github.com/ory/hydra-client-go/v2 v2.2.0-rc.3 h1:0AT8RYiPhT/+brKMSIX/0guSlDK3tg1AcXZgrb5F/tw= -github.com/ory/hydra-client-go/v2 v2.2.0-rc.3/go.mod h1:BS2mJTU+3d+Ii4JXLHlXcjS/BBSIu8OEH0AO71rAVt0= +github.com/ory/hydra-client-go/v2 v2.2.0-rc.3.0.20240202131107-1c7b57df3bb0 h1:D5w0EQBqZU5UcdW0iLTxqbBiEAhOwT2cWHWE6vjxJ3o= +github.com/ory/hydra-client-go/v2 v2.2.0-rc.3.0.20240202131107-1c7b57df3bb0/go.mod h1:JwnnsLd402LPTmIA+EDMsu5Nwr6IRl777pE0QvOq66c= github.com/ory/jsonschema/v3 v3.0.8 h1:Ssdb3eJ4lDZ/+XnGkvQS/te0p+EkolqwTsDOCxr/FmU= github.com/ory/jsonschema/v3 v3.0.8/go.mod h1:ZPzqjDkwd3QTnb2Z6PAS+OTvBE2x5i6m25wCGx54W/0= github.com/ory/mail v2.3.1+incompatible/go.mod h1:87D9/1gB6ewElQoN0lXJ0ayfqcj3cW3qCTXh+5E9mfU= @@ -819,8 +819,8 @@ github.com/ory/nosurf v1.2.7 h1:YrHrbSensQyU6r6HT/V5+HPdVEgrOTMJiLoJABSBOp4= github.com/ory/nosurf v1.2.7/go.mod h1:d4L3ZBa7Amv55bqxCBtCs63wSlyaiCkWVl4vKf3OUxA= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2 h1:zm6sDvHy/U9XrGpixwHiuAwpp0Ock6khSVHkrv6lQQU= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/ory/x v0.0.611 h1:mB23kkg8EYebmKo25JYubXQZmu1l4qLFJnkwr3DnpzA= -github.com/ory/x v0.0.611/go.mod h1:uH065puz8neija0neqwIN3PmXXfDsB9VbZTZ20Znoos= +github.com/ory/x v0.0.613 h1:MHT0scH7hcrOkc3aH7qqYLzXVJkjhB0szWTwpD2lh8Q= +github.com/ory/x v0.0.613/go.mod h1:uH065puz8neija0neqwIN3PmXXfDsB9VbZTZ20Znoos= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= diff --git a/hydra/hydra.go b/hydra/hydra.go index 1772decce090..a4466307ec9d 100644 --- a/hydra/hydra.go +++ b/hydra/hydra.go @@ -72,7 +72,7 @@ func (h *DefaultHydra) getAdminURL(ctx context.Context) (string, error) { return u.String(), nil } -func (h *DefaultHydra) getAdminAPIClient(ctx context.Context) (hydraclientgo.OAuth2Api, error) { +func (h *DefaultHydra) getAdminAPIClient(ctx context.Context) (*hydraclientgo.OAuth2ApiService, error) { url, err := h.getAdminURL(ctx) if err != nil { return nil, err diff --git a/internal/client-go/go.sum b/internal/client-go/go.sum index c966c8ddfd0d..6cc3f5911d11 100644 --- a/internal/client-go/go.sum +++ b/internal/client-go/go.sum @@ -4,6 +4,7 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/request/builder.go b/request/builder.go index f407c8c5c763..458a16cef130 100644 --- a/request/builder.go +++ b/request/builder.go @@ -238,7 +238,7 @@ func (b *Builder) readTemplate(ctx context.Context) ([]byte, error) { return nil, err } - return tpl, nil + return tpl.Bytes(), nil } func isNilInterface(i interface{}) bool { diff --git a/selfservice/strategy/oidc/strategy_registration.go b/selfservice/strategy/oidc/strategy_registration.go index 27b4a74eb9f5..ca8a83be8c10 100644 --- a/selfservice/strategy/oidc/strategy_registration.go +++ b/selfservice/strategy/oidc/strategy_registration.go @@ -311,7 +311,7 @@ func (s *Strategy) processRegistration(w http.ResponseWriter, r *http.Request, r return nil, s.handleError(w, r, rf, provider.Config().ID, nil, err) } - i, va, err := s.createIdentity(w, r, rf, claims, provider, container, jsonnetMapperSnippet) + i, va, err := s.createIdentity(w, r, rf, claims, provider, container, jsonnetMapperSnippet.Bytes()) if err != nil { return nil, s.handleError(w, r, rf, provider.Config().ID, nil, err) } diff --git a/selfservice/strategy/password/op_helpers_test.go b/selfservice/strategy/password/op_helpers_test.go index 9e42ae471851..ccbb186ae103 100644 --- a/selfservice/strategy/password/op_helpers_test.go +++ b/selfservice/strategy/password/op_helpers_test.go @@ -70,13 +70,13 @@ type testConfig struct { browserClient *http.Client kratosPublicTS *httptest.Server clientAppTS *httptest.Server - hydraAdminClient hydraclientgo.OAuth2Api + hydraAdminClient *hydraclientgo.OAuth2ApiService consentRemember bool requestedScope []string callTrace *[]callTrace } -func createHydraOAuth2ApiClient(url string) hydraclientgo.OAuth2Api { +func createHydraOAuth2ApiClient(url string) *hydraclientgo.OAuth2ApiService { configuration := hydraclientgo.NewConfiguration() configuration.Host = urlx.ParseOrPanic(url).Host configuration.Servers = hydraclientgo.ServerConfigurations{{URL: url}} @@ -84,7 +84,7 @@ func createHydraOAuth2ApiClient(url string) hydraclientgo.OAuth2Api { return hydraclientgo.NewAPIClient(configuration).OAuth2Api } -func createOAuth2Client(t *testing.T, ctx context.Context, hydraAdmin hydraclientgo.OAuth2Api, redirectURIs []string, scope string, skipConsent bool) string { +func createOAuth2Client(t *testing.T, ctx context.Context, hydraAdmin *hydraclientgo.OAuth2ApiService, redirectURIs []string, scope string, skipConsent bool) string { t.Helper() clientName := "kratos-hydra-integration-test-client-1" diff --git a/selfservice/strategy/password/op_registration_test.go b/selfservice/strategy/password/op_registration_test.go index 77f91cfb1ee3..7c0b05c81e5a 100644 --- a/selfservice/strategy/password/op_registration_test.go +++ b/selfservice/strategy/password/op_registration_test.go @@ -39,7 +39,7 @@ func TestOAuth2ProviderRegistration(t *testing.T) { errTS := testhelpers.NewErrorTestServer(t, reg) redirTS := testhelpers.NewRedirSessionEchoTS(t, reg) - var hydraAdminClient hydraclientgo.OAuth2Api + var hydraAdminClient *hydraclientgo.OAuth2ApiService router := x.NewRouterPublic() diff --git a/session/tokenizer.go b/session/tokenizer.go index f3c47ef22e0e..85533f6e397e 100644 --- a/session/tokenizer.go +++ b/session/tokenizer.go @@ -121,7 +121,7 @@ func (s *Tokenizer) TokenizeSession(ctx context.Context, template string, sessio if err != nil { return err } - evaluated, err := vm.EvaluateAnonymousSnippet(tpl.ClaimsMapperURL, string(jsonnet)) + evaluated, err := vm.EvaluateAnonymousSnippet(tpl.ClaimsMapperURL, jsonnet.String()) if err != nil { return errors.WithStack(herodot.ErrBadRequest.WithWrap(err).WithDebug(err.Error()).WithReasonf("Unable to execute tokenizer JsonNet.")) } From 0b8ae74ee24df03c5be525bf8b380a73623f64c5 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Mon, 5 Feb 2024 15:54:22 +0000 Subject: [PATCH 265/282] autogen(openapi): regenerate swagger spec and internal client [skip ci] --- internal/client-go/go.sum | 1 - internal/client-go/model_o_auth2_client.go | 75 ++++++++++--------- ...consent_request_open_id_connect_context.go | 36 --------- .../client-go/model_o_auth2_login_request.go | 36 --------- internal/httpclient/model_o_auth2_client.go | 75 ++++++++++--------- ...consent_request_open_id_connect_context.go | 36 --------- .../httpclient/model_o_auth2_login_request.go | 36 --------- spec/api.json | 18 ++--- spec/swagger.json | 18 ++--- 9 files changed, 86 insertions(+), 245 deletions(-) diff --git a/internal/client-go/go.sum b/internal/client-go/go.sum index 6cc3f5911d11..c966c8ddfd0d 100644 --- a/internal/client-go/go.sum +++ b/internal/client-go/go.sum @@ -4,7 +4,6 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/internal/client-go/model_o_auth2_client.go b/internal/client-go/model_o_auth2_client.go index eab35e350486..be48d3217ade 100644 --- a/internal/client-go/model_o_auth2_client.go +++ b/internal/client-go/model_o_auth2_client.go @@ -18,7 +18,6 @@ import ( // OAuth2Client struct for OAuth2Client type OAuth2Client struct { - AdditionalPropertiesField map[string]interface{} `json:"AdditionalProperties,omitempty"` // OAuth 2.0 Access Token Strategy AccessTokenStrategy is the strategy used to generate access tokens. Valid options are `jwt` and `opaque`. `jwt` is a bad idea, see https://www.ory.sh/docs/hydra/advanced#json-web-tokens Setting the stragegy here overrides the global setting in `strategies.access_token`. AccessTokenStrategy *string `json:"access_token_strategy,omitempty"` AllowedCorsOrigins []string `json:"allowed_cors_origins,omitempty"` @@ -35,7 +34,7 @@ type OAuth2Client struct { BackchannelLogoutUri *string `json:"backchannel_logout_uri,omitempty"` // Specify a time duration in milliseconds, seconds, minutes, hours. ClientCredentialsGrantAccessTokenLifespan *string `json:"client_credentials_grant_access_token_lifespan,omitempty"` - // OAuth 2.0 Client ID The ID is autogenerated and immutable. + // OAuth 2.0 Client ID The ID is immutable. If no ID is provided, a UUID4 will be generated. ClientId *string `json:"client_id,omitempty"` // OAuth 2.0 Client Name The human-readable name of the client to be presented to the end-user during authorization. ClientName *string `json:"client_name,omitempty"` @@ -92,6 +91,8 @@ type OAuth2Client struct { SectorIdentifierUri *string `json:"sector_identifier_uri,omitempty"` // SkipConsent skips the consent screen for this client. This field can only be set from the admin API. SkipConsent *bool `json:"skip_consent,omitempty"` + // SkipLogoutConsent skips the logout consent screen for this client. This field can only be set from the admin API. + SkipLogoutConsent *bool `json:"skip_logout_consent,omitempty"` // OpenID Connect Subject Type 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"` // OAuth 2.0 Token Endpoint Authentication Method Requested Client Authentication method for the Token Endpoint. The options are: `client_secret_basic`: (default) Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` encoded in the HTTP Authorization header. `client_secret_post`: Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` in the HTTP body. `private_key_jwt`: Use JSON Web Tokens to authenticate the client. `none`: Used for public clients (native apps, mobile apps) which can not have secrets. @@ -123,38 +124,6 @@ func NewOAuth2ClientWithDefaults() *OAuth2Client { return &this } -// GetAdditionalPropertiesField returns the AdditionalPropertiesField field value if set, zero value otherwise. -func (o *OAuth2Client) GetAdditionalPropertiesField() map[string]interface{} { - if o == nil || o.AdditionalPropertiesField == nil { - var ret map[string]interface{} - return ret - } - return o.AdditionalPropertiesField -} - -// GetAdditionalPropertiesFieldOk returns a tuple with the AdditionalPropertiesField field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *OAuth2Client) GetAdditionalPropertiesFieldOk() (map[string]interface{}, bool) { - if o == nil || o.AdditionalPropertiesField == nil { - return nil, false - } - return o.AdditionalPropertiesField, true -} - -// HasAdditionalPropertiesField returns a boolean if a field has been set. -func (o *OAuth2Client) HasAdditionalPropertiesField() bool { - if o != nil && o.AdditionalPropertiesField != nil { - return true - } - - return false -} - -// SetAdditionalPropertiesField gets a reference to the given map[string]interface{} and assigns it to the AdditionalPropertiesField field. -func (o *OAuth2Client) SetAdditionalPropertiesField(v map[string]interface{}) { - o.AdditionalPropertiesField = v -} - // GetAccessTokenStrategy returns the AccessTokenStrategy field value if set, zero value otherwise. func (o *OAuth2Client) GetAccessTokenStrategy() string { if o == nil || o.AccessTokenStrategy == nil { @@ -1469,6 +1438,38 @@ func (o *OAuth2Client) SetSkipConsent(v bool) { o.SkipConsent = &v } +// GetSkipLogoutConsent returns the SkipLogoutConsent field value if set, zero value otherwise. +func (o *OAuth2Client) GetSkipLogoutConsent() bool { + if o == nil || o.SkipLogoutConsent == nil { + var ret bool + return ret + } + return *o.SkipLogoutConsent +} + +// GetSkipLogoutConsentOk returns a tuple with the SkipLogoutConsent field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetSkipLogoutConsentOk() (*bool, bool) { + if o == nil || o.SkipLogoutConsent == nil { + return nil, false + } + return o.SkipLogoutConsent, true +} + +// HasSkipLogoutConsent returns a boolean if a field has been set. +func (o *OAuth2Client) HasSkipLogoutConsent() bool { + if o != nil && o.SkipLogoutConsent != nil { + return true + } + + return false +} + +// SetSkipLogoutConsent gets a reference to the given bool and assigns it to the SkipLogoutConsent field. +func (o *OAuth2Client) SetSkipLogoutConsent(v bool) { + o.SkipLogoutConsent = &v +} + // GetSubjectType returns the SubjectType field value if set, zero value otherwise. func (o *OAuth2Client) GetSubjectType() string { if o == nil || o.SubjectType == nil { @@ -1663,9 +1664,6 @@ func (o *OAuth2Client) SetUserinfoSignedResponseAlg(v string) { func (o OAuth2Client) MarshalJSON() ([]byte, error) { toSerialize := map[string]interface{}{} - if o.AdditionalPropertiesField != nil { - toSerialize["AdditionalProperties"] = o.AdditionalPropertiesField - } if o.AccessTokenStrategy != nil { toSerialize["access_token_strategy"] = o.AccessTokenStrategy } @@ -1789,6 +1787,9 @@ func (o OAuth2Client) MarshalJSON() ([]byte, error) { if o.SkipConsent != nil { toSerialize["skip_consent"] = o.SkipConsent } + if o.SkipLogoutConsent != nil { + toSerialize["skip_logout_consent"] = o.SkipLogoutConsent + } if o.SubjectType != nil { toSerialize["subject_type"] = o.SubjectType } diff --git a/internal/client-go/model_o_auth2_consent_request_open_id_connect_context.go b/internal/client-go/model_o_auth2_consent_request_open_id_connect_context.go index 68884830a9ee..c0cbf7f3129e 100644 --- a/internal/client-go/model_o_auth2_consent_request_open_id_connect_context.go +++ b/internal/client-go/model_o_auth2_consent_request_open_id_connect_context.go @@ -17,7 +17,6 @@ import ( // OAuth2ConsentRequestOpenIDConnectContext OAuth2ConsentRequestOpenIDConnectContext struct for OAuth2ConsentRequestOpenIDConnectContext type OAuth2ConsentRequestOpenIDConnectContext struct { - AdditionalPropertiesField map[string]interface{} `json:"AdditionalProperties,omitempty"` // 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. @@ -47,38 +46,6 @@ func NewOAuth2ConsentRequestOpenIDConnectContextWithDefaults() *OAuth2ConsentReq return &this } -// GetAdditionalPropertiesField returns the AdditionalPropertiesField field value if set, zero value otherwise. -func (o *OAuth2ConsentRequestOpenIDConnectContext) GetAdditionalPropertiesField() map[string]interface{} { - if o == nil || o.AdditionalPropertiesField == nil { - var ret map[string]interface{} - return ret - } - return o.AdditionalPropertiesField -} - -// GetAdditionalPropertiesFieldOk returns a tuple with the AdditionalPropertiesField field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *OAuth2ConsentRequestOpenIDConnectContext) GetAdditionalPropertiesFieldOk() (map[string]interface{}, bool) { - if o == nil || o.AdditionalPropertiesField == nil { - return nil, false - } - return o.AdditionalPropertiesField, true -} - -// HasAdditionalPropertiesField returns a boolean if a field has been set. -func (o *OAuth2ConsentRequestOpenIDConnectContext) HasAdditionalPropertiesField() bool { - if o != nil && o.AdditionalPropertiesField != nil { - return true - } - - return false -} - -// SetAdditionalPropertiesField gets a reference to the given map[string]interface{} and assigns it to the AdditionalPropertiesField field. -func (o *OAuth2ConsentRequestOpenIDConnectContext) SetAdditionalPropertiesField(v map[string]interface{}) { - o.AdditionalPropertiesField = v -} - // GetAcrValues returns the AcrValues field value if set, zero value otherwise. func (o *OAuth2ConsentRequestOpenIDConnectContext) GetAcrValues() []string { if o == nil || o.AcrValues == nil { @@ -241,9 +208,6 @@ func (o *OAuth2ConsentRequestOpenIDConnectContext) SetUiLocales(v []string) { func (o OAuth2ConsentRequestOpenIDConnectContext) MarshalJSON() ([]byte, error) { toSerialize := map[string]interface{}{} - if o.AdditionalPropertiesField != nil { - toSerialize["AdditionalProperties"] = o.AdditionalPropertiesField - } if o.AcrValues != nil { toSerialize["acr_values"] = o.AcrValues } diff --git a/internal/client-go/model_o_auth2_login_request.go b/internal/client-go/model_o_auth2_login_request.go index a788c66ed3ca..9fcd87be72fa 100644 --- a/internal/client-go/model_o_auth2_login_request.go +++ b/internal/client-go/model_o_auth2_login_request.go @@ -17,7 +17,6 @@ import ( // OAuth2LoginRequest OAuth2LoginRequest struct for OAuth2LoginRequest type OAuth2LoginRequest struct { - AdditionalPropertiesField map[string]interface{} `json:"AdditionalProperties,omitempty"` // 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"` @@ -51,38 +50,6 @@ func NewOAuth2LoginRequestWithDefaults() *OAuth2LoginRequest { return &this } -// GetAdditionalPropertiesField returns the AdditionalPropertiesField field value if set, zero value otherwise. -func (o *OAuth2LoginRequest) GetAdditionalPropertiesField() map[string]interface{} { - if o == nil || o.AdditionalPropertiesField == nil { - var ret map[string]interface{} - return ret - } - return o.AdditionalPropertiesField -} - -// GetAdditionalPropertiesFieldOk returns a tuple with the AdditionalPropertiesField field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *OAuth2LoginRequest) GetAdditionalPropertiesFieldOk() (map[string]interface{}, bool) { - if o == nil || o.AdditionalPropertiesField == nil { - return nil, false - } - return o.AdditionalPropertiesField, true -} - -// HasAdditionalPropertiesField returns a boolean if a field has been set. -func (o *OAuth2LoginRequest) HasAdditionalPropertiesField() bool { - if o != nil && o.AdditionalPropertiesField != nil { - return true - } - - return false -} - -// SetAdditionalPropertiesField gets a reference to the given map[string]interface{} and assigns it to the AdditionalPropertiesField field. -func (o *OAuth2LoginRequest) SetAdditionalPropertiesField(v map[string]interface{}) { - o.AdditionalPropertiesField = v -} - // GetChallenge returns the Challenge field value if set, zero value otherwise. func (o *OAuth2LoginRequest) GetChallenge() string { if o == nil || o.Challenge == nil { @@ -373,9 +340,6 @@ func (o *OAuth2LoginRequest) SetSubject(v string) { func (o OAuth2LoginRequest) MarshalJSON() ([]byte, error) { toSerialize := map[string]interface{}{} - if o.AdditionalPropertiesField != nil { - toSerialize["AdditionalProperties"] = o.AdditionalPropertiesField - } if o.Challenge != nil { toSerialize["challenge"] = o.Challenge } diff --git a/internal/httpclient/model_o_auth2_client.go b/internal/httpclient/model_o_auth2_client.go index eab35e350486..be48d3217ade 100644 --- a/internal/httpclient/model_o_auth2_client.go +++ b/internal/httpclient/model_o_auth2_client.go @@ -18,7 +18,6 @@ import ( // OAuth2Client struct for OAuth2Client type OAuth2Client struct { - AdditionalPropertiesField map[string]interface{} `json:"AdditionalProperties,omitempty"` // OAuth 2.0 Access Token Strategy AccessTokenStrategy is the strategy used to generate access tokens. Valid options are `jwt` and `opaque`. `jwt` is a bad idea, see https://www.ory.sh/docs/hydra/advanced#json-web-tokens Setting the stragegy here overrides the global setting in `strategies.access_token`. AccessTokenStrategy *string `json:"access_token_strategy,omitempty"` AllowedCorsOrigins []string `json:"allowed_cors_origins,omitempty"` @@ -35,7 +34,7 @@ type OAuth2Client struct { BackchannelLogoutUri *string `json:"backchannel_logout_uri,omitempty"` // Specify a time duration in milliseconds, seconds, minutes, hours. ClientCredentialsGrantAccessTokenLifespan *string `json:"client_credentials_grant_access_token_lifespan,omitempty"` - // OAuth 2.0 Client ID The ID is autogenerated and immutable. + // OAuth 2.0 Client ID The ID is immutable. If no ID is provided, a UUID4 will be generated. ClientId *string `json:"client_id,omitempty"` // OAuth 2.0 Client Name The human-readable name of the client to be presented to the end-user during authorization. ClientName *string `json:"client_name,omitempty"` @@ -92,6 +91,8 @@ type OAuth2Client struct { SectorIdentifierUri *string `json:"sector_identifier_uri,omitempty"` // SkipConsent skips the consent screen for this client. This field can only be set from the admin API. SkipConsent *bool `json:"skip_consent,omitempty"` + // SkipLogoutConsent skips the logout consent screen for this client. This field can only be set from the admin API. + SkipLogoutConsent *bool `json:"skip_logout_consent,omitempty"` // OpenID Connect Subject Type 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"` // OAuth 2.0 Token Endpoint Authentication Method Requested Client Authentication method for the Token Endpoint. The options are: `client_secret_basic`: (default) Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` encoded in the HTTP Authorization header. `client_secret_post`: Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` in the HTTP body. `private_key_jwt`: Use JSON Web Tokens to authenticate the client. `none`: Used for public clients (native apps, mobile apps) which can not have secrets. @@ -123,38 +124,6 @@ func NewOAuth2ClientWithDefaults() *OAuth2Client { return &this } -// GetAdditionalPropertiesField returns the AdditionalPropertiesField field value if set, zero value otherwise. -func (o *OAuth2Client) GetAdditionalPropertiesField() map[string]interface{} { - if o == nil || o.AdditionalPropertiesField == nil { - var ret map[string]interface{} - return ret - } - return o.AdditionalPropertiesField -} - -// GetAdditionalPropertiesFieldOk returns a tuple with the AdditionalPropertiesField field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *OAuth2Client) GetAdditionalPropertiesFieldOk() (map[string]interface{}, bool) { - if o == nil || o.AdditionalPropertiesField == nil { - return nil, false - } - return o.AdditionalPropertiesField, true -} - -// HasAdditionalPropertiesField returns a boolean if a field has been set. -func (o *OAuth2Client) HasAdditionalPropertiesField() bool { - if o != nil && o.AdditionalPropertiesField != nil { - return true - } - - return false -} - -// SetAdditionalPropertiesField gets a reference to the given map[string]interface{} and assigns it to the AdditionalPropertiesField field. -func (o *OAuth2Client) SetAdditionalPropertiesField(v map[string]interface{}) { - o.AdditionalPropertiesField = v -} - // GetAccessTokenStrategy returns the AccessTokenStrategy field value if set, zero value otherwise. func (o *OAuth2Client) GetAccessTokenStrategy() string { if o == nil || o.AccessTokenStrategy == nil { @@ -1469,6 +1438,38 @@ func (o *OAuth2Client) SetSkipConsent(v bool) { o.SkipConsent = &v } +// GetSkipLogoutConsent returns the SkipLogoutConsent field value if set, zero value otherwise. +func (o *OAuth2Client) GetSkipLogoutConsent() bool { + if o == nil || o.SkipLogoutConsent == nil { + var ret bool + return ret + } + return *o.SkipLogoutConsent +} + +// GetSkipLogoutConsentOk returns a tuple with the SkipLogoutConsent field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetSkipLogoutConsentOk() (*bool, bool) { + if o == nil || o.SkipLogoutConsent == nil { + return nil, false + } + return o.SkipLogoutConsent, true +} + +// HasSkipLogoutConsent returns a boolean if a field has been set. +func (o *OAuth2Client) HasSkipLogoutConsent() bool { + if o != nil && o.SkipLogoutConsent != nil { + return true + } + + return false +} + +// SetSkipLogoutConsent gets a reference to the given bool and assigns it to the SkipLogoutConsent field. +func (o *OAuth2Client) SetSkipLogoutConsent(v bool) { + o.SkipLogoutConsent = &v +} + // GetSubjectType returns the SubjectType field value if set, zero value otherwise. func (o *OAuth2Client) GetSubjectType() string { if o == nil || o.SubjectType == nil { @@ -1663,9 +1664,6 @@ func (o *OAuth2Client) SetUserinfoSignedResponseAlg(v string) { func (o OAuth2Client) MarshalJSON() ([]byte, error) { toSerialize := map[string]interface{}{} - if o.AdditionalPropertiesField != nil { - toSerialize["AdditionalProperties"] = o.AdditionalPropertiesField - } if o.AccessTokenStrategy != nil { toSerialize["access_token_strategy"] = o.AccessTokenStrategy } @@ -1789,6 +1787,9 @@ func (o OAuth2Client) MarshalJSON() ([]byte, error) { if o.SkipConsent != nil { toSerialize["skip_consent"] = o.SkipConsent } + if o.SkipLogoutConsent != nil { + toSerialize["skip_logout_consent"] = o.SkipLogoutConsent + } if o.SubjectType != nil { toSerialize["subject_type"] = o.SubjectType } diff --git a/internal/httpclient/model_o_auth2_consent_request_open_id_connect_context.go b/internal/httpclient/model_o_auth2_consent_request_open_id_connect_context.go index 68884830a9ee..c0cbf7f3129e 100644 --- a/internal/httpclient/model_o_auth2_consent_request_open_id_connect_context.go +++ b/internal/httpclient/model_o_auth2_consent_request_open_id_connect_context.go @@ -17,7 +17,6 @@ import ( // OAuth2ConsentRequestOpenIDConnectContext OAuth2ConsentRequestOpenIDConnectContext struct for OAuth2ConsentRequestOpenIDConnectContext type OAuth2ConsentRequestOpenIDConnectContext struct { - AdditionalPropertiesField map[string]interface{} `json:"AdditionalProperties,omitempty"` // 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. @@ -47,38 +46,6 @@ func NewOAuth2ConsentRequestOpenIDConnectContextWithDefaults() *OAuth2ConsentReq return &this } -// GetAdditionalPropertiesField returns the AdditionalPropertiesField field value if set, zero value otherwise. -func (o *OAuth2ConsentRequestOpenIDConnectContext) GetAdditionalPropertiesField() map[string]interface{} { - if o == nil || o.AdditionalPropertiesField == nil { - var ret map[string]interface{} - return ret - } - return o.AdditionalPropertiesField -} - -// GetAdditionalPropertiesFieldOk returns a tuple with the AdditionalPropertiesField field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *OAuth2ConsentRequestOpenIDConnectContext) GetAdditionalPropertiesFieldOk() (map[string]interface{}, bool) { - if o == nil || o.AdditionalPropertiesField == nil { - return nil, false - } - return o.AdditionalPropertiesField, true -} - -// HasAdditionalPropertiesField returns a boolean if a field has been set. -func (o *OAuth2ConsentRequestOpenIDConnectContext) HasAdditionalPropertiesField() bool { - if o != nil && o.AdditionalPropertiesField != nil { - return true - } - - return false -} - -// SetAdditionalPropertiesField gets a reference to the given map[string]interface{} and assigns it to the AdditionalPropertiesField field. -func (o *OAuth2ConsentRequestOpenIDConnectContext) SetAdditionalPropertiesField(v map[string]interface{}) { - o.AdditionalPropertiesField = v -} - // GetAcrValues returns the AcrValues field value if set, zero value otherwise. func (o *OAuth2ConsentRequestOpenIDConnectContext) GetAcrValues() []string { if o == nil || o.AcrValues == nil { @@ -241,9 +208,6 @@ func (o *OAuth2ConsentRequestOpenIDConnectContext) SetUiLocales(v []string) { func (o OAuth2ConsentRequestOpenIDConnectContext) MarshalJSON() ([]byte, error) { toSerialize := map[string]interface{}{} - if o.AdditionalPropertiesField != nil { - toSerialize["AdditionalProperties"] = o.AdditionalPropertiesField - } if o.AcrValues != nil { toSerialize["acr_values"] = o.AcrValues } diff --git a/internal/httpclient/model_o_auth2_login_request.go b/internal/httpclient/model_o_auth2_login_request.go index a788c66ed3ca..9fcd87be72fa 100644 --- a/internal/httpclient/model_o_auth2_login_request.go +++ b/internal/httpclient/model_o_auth2_login_request.go @@ -17,7 +17,6 @@ import ( // OAuth2LoginRequest OAuth2LoginRequest struct for OAuth2LoginRequest type OAuth2LoginRequest struct { - AdditionalPropertiesField map[string]interface{} `json:"AdditionalProperties,omitempty"` // 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"` @@ -51,38 +50,6 @@ func NewOAuth2LoginRequestWithDefaults() *OAuth2LoginRequest { return &this } -// GetAdditionalPropertiesField returns the AdditionalPropertiesField field value if set, zero value otherwise. -func (o *OAuth2LoginRequest) GetAdditionalPropertiesField() map[string]interface{} { - if o == nil || o.AdditionalPropertiesField == nil { - var ret map[string]interface{} - return ret - } - return o.AdditionalPropertiesField -} - -// GetAdditionalPropertiesFieldOk returns a tuple with the AdditionalPropertiesField field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *OAuth2LoginRequest) GetAdditionalPropertiesFieldOk() (map[string]interface{}, bool) { - if o == nil || o.AdditionalPropertiesField == nil { - return nil, false - } - return o.AdditionalPropertiesField, true -} - -// HasAdditionalPropertiesField returns a boolean if a field has been set. -func (o *OAuth2LoginRequest) HasAdditionalPropertiesField() bool { - if o != nil && o.AdditionalPropertiesField != nil { - return true - } - - return false -} - -// SetAdditionalPropertiesField gets a reference to the given map[string]interface{} and assigns it to the AdditionalPropertiesField field. -func (o *OAuth2LoginRequest) SetAdditionalPropertiesField(v map[string]interface{}) { - o.AdditionalPropertiesField = v -} - // GetChallenge returns the Challenge field value if set, zero value otherwise. func (o *OAuth2LoginRequest) GetChallenge() string { if o == nil || o.Challenge == nil { @@ -373,9 +340,6 @@ func (o *OAuth2LoginRequest) SetSubject(v string) { func (o OAuth2LoginRequest) MarshalJSON() ([]byte, error) { toSerialize := map[string]interface{}{} - if o.AdditionalPropertiesField != nil { - toSerialize["AdditionalProperties"] = o.AdditionalPropertiesField - } if o.Challenge != nil { toSerialize["challenge"] = o.Challenge } diff --git a/spec/api.json b/spec/api.json index 212287de0895..c35d62d194e7 100644 --- a/spec/api.json +++ b/spec/api.json @@ -119,10 +119,6 @@ }, "OAuth2Client": { "properties": { - "AdditionalProperties": { - "additionalProperties": {}, - "type": "object" - }, "access_token_strategy": { "description": "OAuth 2.0 Access Token Strategy AccessTokenStrategy is the strategy used to generate access tokens. Valid options are `jwt` and `opaque`. `jwt` is a bad idea, see https://www.ory.sh/docs/hydra/advanced#json-web-tokens Setting the stragegy here overrides the global setting in `strategies.access_token`.", "type": "string" @@ -164,7 +160,7 @@ "type": "string" }, "client_id": { - "description": "OAuth 2.0 Client ID The ID is autogenerated and immutable.", + "description": "OAuth 2.0 Client ID The ID is immutable. If no ID is provided, a UUID4 will be generated.", "type": "string" }, "client_name": { @@ -301,6 +297,10 @@ "description": "SkipConsent skips the consent screen for this client. This field can only be set from the admin API.", "type": "boolean" }, + "skip_logout_consent": { + "description": "SkipLogoutConsent skips the logout consent screen for this client. This field can only be set from the admin API.", + "type": "boolean" + }, "subject_type": { "description": "OpenID Connect Subject Type 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" @@ -333,10 +333,6 @@ "OAuth2ConsentRequestOpenIDConnectContext": { "description": "OAuth2ConsentRequestOpenIDConnectContext struct for OAuth2ConsentRequestOpenIDConnectContext", "properties": { - "AdditionalProperties": { - "additionalProperties": {}, - "type": "object" - }, "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": { @@ -373,10 +369,6 @@ "OAuth2LoginRequest": { "description": "OAuth2LoginRequest struct for OAuth2LoginRequest", "properties": { - "AdditionalProperties": { - "additionalProperties": {}, - "type": "object" - }, "challenge": { "description": "ID is the identifier (\\\"login challenge\\\") of the login request. It is used to identify the session.", "type": "string" diff --git a/spec/swagger.json b/spec/swagger.json index 445df73fabf7..9f074141f069 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -3262,10 +3262,6 @@ "type": "object", "title": "OAuth2Client OAuth 2.0 Clients are used to perform OAuth 2.0 and OpenID Connect flows. Usually, OAuth 2.0 clients are generated for applications which want to consume your OAuth 2.0 or OpenID Connect capabilities.", "properties": { - "AdditionalProperties": { - "type": "object", - "additionalProperties": {} - }, "access_token_strategy": { "description": "OAuth 2.0 Access Token Strategy AccessTokenStrategy is the strategy used to generate access tokens. Valid options are `jwt` and `opaque`. `jwt` is a bad idea, see https://www.ory.sh/docs/hydra/advanced#json-web-tokens Setting the stragegy here overrides the global setting in `strategies.access_token`.", "type": "string" @@ -3307,7 +3303,7 @@ "type": "string" }, "client_id": { - "description": "OAuth 2.0 Client ID The ID is autogenerated and immutable.", + "description": "OAuth 2.0 Client ID The ID is immutable. If no ID is provided, a UUID4 will be generated.", "type": "string" }, "client_name": { @@ -3445,6 +3441,10 @@ "description": "SkipConsent skips the consent screen for this client. This field can only be set from the admin API.", "type": "boolean" }, + "skip_logout_consent": { + "description": "SkipLogoutConsent skips the logout consent screen for this client. This field can only be set from the admin API.", + "type": "boolean" + }, "subject_type": { "description": "OpenID Connect Subject Type 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" @@ -3476,10 +3476,6 @@ "description": "OAuth2ConsentRequestOpenIDConnectContext struct for OAuth2ConsentRequestOpenIDConnectContext", "type": "object", "properties": { - "AdditionalProperties": { - "type": "object", - "additionalProperties": {} - }, "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", @@ -3516,10 +3512,6 @@ "description": "OAuth2LoginRequest struct for OAuth2LoginRequest", "type": "object", "properties": { - "AdditionalProperties": { - "type": "object", - "additionalProperties": {} - }, "challenge": { "description": "ID is the identifier (\\\"login challenge\\\") of the login request. It is used to identify the session.", "type": "string" From fd7995077307cc101550eda5d7724ea1f68fa98a Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Mon, 5 Feb 2024 17:55:53 +0100 Subject: [PATCH 266/282] fix: add consistency flag (#3733) --- cmd/identities/list.go | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/cmd/identities/list.go b/cmd/identities/list.go index 221a5a839715..0fd4f13d20bf 100644 --- a/cmd/identities/list.go +++ b/cmd/identities/list.go @@ -6,6 +6,8 @@ package identities import ( "github.com/spf13/cobra" + "github.com/ory/x/flagx" + "github.com/ory/x/pagination/keysetpagination" "github.com/ory/kratos/cmd/cliclient" @@ -26,10 +28,13 @@ func NewListCmd() *cobra.Command { func NewListIdentitiesCmd() *cobra.Command { c := &cobra.Command{ - Use: "identities", - Short: "List identities", - Long: "Return a list of identities.", - Example: "{{ .CommandPath }} --page-size 100", + Use: "identities", + Short: "List identities", + Long: `Return a list of identities. + +The consistency defaults to ` + "`eventual`" + ` and can be set to ` + "`strong`" + ` or ` + "`eventual`" + `. +Eventual consistency means that the list operation will return faster and might not include recently created or updated identities. Replication lag is about 5 seconds.`, + Example: "{{ .CommandPath }} --page-size 100 --consistency eventual", Args: cmdx.ZeroOrTwoArgs, RunE: func(cmd *cobra.Command, args []string) error { c, err := cliclient.NewClient(cmd) @@ -37,7 +42,8 @@ func NewListIdentitiesCmd() *cobra.Command { return err } - req := c.IdentityApi.ListIdentities(cmd.Context()) + consistency := flagx.MustGetString(cmd, "consistency") + req := c.IdentityApi.ListIdentities(cmd.Context()).Consistency(consistency) page, perPage, err := cmdx.ParseTokenPaginationArgs(cmd) if err != nil { return err @@ -60,6 +66,7 @@ func NewListIdentitiesCmd() *cobra.Command { return nil }, } + c.Flags().String("consistency", "eventual", "The read consistency to use. Can be either \"strong\" or \"eventual\". Defaults to \"eventual\".") cmdx.RegisterTokenPaginationFlags(c) return c } From 34751a1a3ad9b217af2de7b435b9ee70df510265 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Mon, 5 Feb 2024 17:39:30 +0000 Subject: [PATCH 267/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 86 ++++++++++++++++++++++++++++------------------------ 1 file changed, 46 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bdec52460770..d68bb6a06764 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,12 @@ **Table of Contents** - [ (2024-02-05)](#2024-02-05) + - [Bug Fixes](#bug-fixes) - [Features](#features) - [Tests](#tests) - [1.1.0-pre.0 (2024-02-01)](#110-pre0-2024-02-01) - [Breaking Changes](#breaking-changes) - - [Bug Fixes](#bug-fixes) + - [Bug Fixes](#bug-fixes-1) - [Code Generation](#code-generation) - [Documentation](#documentation) - [Features](#features-1) @@ -18,7 +19,7 @@ - [Tests](#tests-1) - [Unclassified](#unclassified) - [1.0.0 (2023-07-12)](#100-2023-07-12) - - [Bug Fixes](#bug-fixes-1) + - [Bug Fixes](#bug-fixes-2) - [Code Generation](#code-generation-1) - [Documentation](#documentation-1) - [Features](#features-2) @@ -26,7 +27,7 @@ - [Unclassified](#unclassified-1) - [0.13.0 (2023-04-18)](#0130-2023-04-18) - [Breaking Changes](#breaking-changes-1) - - [Bug Fixes](#bug-fixes-2) + - [Bug Fixes](#bug-fixes-3) - [Code Generation](#code-generation-2) - [Code Refactoring](#code-refactoring) - [Documentation](#documentation-2) @@ -35,7 +36,7 @@ - [Unclassified](#unclassified-2) - [0.11.1 (2023-01-14)](#0111-2023-01-14) - [Breaking Changes](#breaking-changes-2) - - [Bug Fixes](#bug-fixes-3) + - [Bug Fixes](#bug-fixes-4) - [Code Generation](#code-generation-3) - [Documentation](#documentation-3) - [Features](#features-4) @@ -45,7 +46,7 @@ - [Features](#features-5) - [0.11.0-alpha.0.pre.2 (2022-11-28)](#0110-alpha0pre2-2022-11-28) - [Breaking Changes](#breaking-changes-3) - - [Bug Fixes](#bug-fixes-4) + - [Bug Fixes](#bug-fixes-5) - [Code Generation](#code-generation-5) - [Code Refactoring](#code-refactoring-1) - [Documentation](#documentation-4) @@ -54,11 +55,11 @@ - [Tests](#tests-5) - [Unclassified](#unclassified-3) - [0.10.1 (2022-06-01)](#0101-2022-06-01) - - [Bug Fixes](#bug-fixes-5) + - [Bug Fixes](#bug-fixes-6) - [Code Generation](#code-generation-6) - [0.10.0 (2022-05-30)](#0100-2022-05-30) - [Breaking Changes](#breaking-changes-4) - - [Bug Fixes](#bug-fixes-6) + - [Bug Fixes](#bug-fixes-7) - [Code Generation](#code-generation-7) - [Code Refactoring](#code-refactoring-2) - [Documentation](#documentation-5) @@ -67,15 +68,15 @@ - [Unclassified](#unclassified-4) - [0.9.0-alpha.3 (2022-03-25)](#090-alpha3-2022-03-25) - [Breaking Changes](#breaking-changes-5) - - [Bug Fixes](#bug-fixes-7) + - [Bug Fixes](#bug-fixes-8) - [Code Generation](#code-generation-8) - [Documentation](#documentation-6) - [0.9.0-alpha.2 (2022-03-22)](#090-alpha2-2022-03-22) - - [Bug Fixes](#bug-fixes-8) + - [Bug Fixes](#bug-fixes-9) - [Code Generation](#code-generation-9) - [0.9.0-alpha.1 (2022-03-21)](#090-alpha1-2022-03-21) - [Breaking Changes](#breaking-changes-6) - - [Bug Fixes](#bug-fixes-9) + - [Bug Fixes](#bug-fixes-10) - [Code Generation](#code-generation-10) - [Code Refactoring](#code-refactoring-3) - [Documentation](#documentation-7) @@ -84,37 +85,37 @@ - [Unclassified](#unclassified-5) - [0.8.3-alpha.1.pre.0 (2022-01-21)](#083-alpha1pre0-2022-01-21) - [Breaking Changes](#breaking-changes-7) - - [Bug Fixes](#bug-fixes-10) + - [Bug Fixes](#bug-fixes-11) - [Code Generation](#code-generation-11) - [Code Refactoring](#code-refactoring-4) - [Documentation](#documentation-8) - [Features](#features-9) - [Tests](#tests-8) - [0.8.2-alpha.1 (2021-12-17)](#082-alpha1-2021-12-17) - - [Bug Fixes](#bug-fixes-11) + - [Bug Fixes](#bug-fixes-12) - [Code Generation](#code-generation-12) - [Documentation](#documentation-9) - [0.8.1-alpha.1 (2021-12-13)](#081-alpha1-2021-12-13) - - [Bug Fixes](#bug-fixes-12) + - [Bug Fixes](#bug-fixes-13) - [Code Generation](#code-generation-13) - [Documentation](#documentation-10) - [Features](#features-10) - [Tests](#tests-9) - [0.8.0-alpha.4.pre.0 (2021-11-09)](#080-alpha4pre0-2021-11-09) - [Breaking Changes](#breaking-changes-8) - - [Bug Fixes](#bug-fixes-13) + - [Bug Fixes](#bug-fixes-14) - [Code Generation](#code-generation-14) - [Documentation](#documentation-11) - [Features](#features-11) - [Tests](#tests-10) - [0.8.0-alpha.3 (2021-10-28)](#080-alpha3-2021-10-28) - - [Bug Fixes](#bug-fixes-14) + - [Bug Fixes](#bug-fixes-15) - [Code Generation](#code-generation-15) - [0.8.0-alpha.2 (2021-10-28)](#080-alpha2-2021-10-28) - [Code Generation](#code-generation-16) - [0.8.0-alpha.1 (2021-10-27)](#080-alpha1-2021-10-27) - [Breaking Changes](#breaking-changes-9) - - [Bug Fixes](#bug-fixes-15) + - [Bug Fixes](#bug-fixes-16) - [Code Generation](#code-generation-17) - [Code Refactoring](#code-refactoring-5) - [Documentation](#documentation-12) @@ -127,24 +128,24 @@ - [0.7.5-alpha.1 (2021-09-11)](#075-alpha1-2021-09-11) - [Code Generation](#code-generation-19) - [0.7.4-alpha.1 (2021-09-09)](#074-alpha1-2021-09-09) - - [Bug Fixes](#bug-fixes-16) + - [Bug Fixes](#bug-fixes-17) - [Code Generation](#code-generation-20) - [Documentation](#documentation-13) - [Features](#features-13) - [Tests](#tests-12) - [0.7.3-alpha.1 (2021-08-28)](#073-alpha1-2021-08-28) - - [Bug Fixes](#bug-fixes-17) + - [Bug Fixes](#bug-fixes-18) - [Code Generation](#code-generation-21) - [Documentation](#documentation-14) - [Features](#features-14) - [0.7.1-alpha.1 (2021-07-22)](#071-alpha1-2021-07-22) - - [Bug Fixes](#bug-fixes-18) + - [Bug Fixes](#bug-fixes-19) - [Code Generation](#code-generation-22) - [Documentation](#documentation-15) - [Tests](#tests-13) - [0.7.0-alpha.1 (2021-07-13)](#070-alpha1-2021-07-13) - [Breaking Changes](#breaking-changes-10) - - [Bug Fixes](#bug-fixes-19) + - [Bug Fixes](#bug-fixes-20) - [Code Generation](#code-generation-23) - [Code Refactoring](#code-refactoring-6) - [Documentation](#documentation-16) @@ -153,7 +154,7 @@ - [Unclassified](#unclassified-7) - [0.6.3-alpha.1 (2021-05-17)](#063-alpha1-2021-05-17) - [Breaking Changes](#breaking-changes-11) - - [Bug Fixes](#bug-fixes-20) + - [Bug Fixes](#bug-fixes-21) - [Code Generation](#code-generation-24) - [Code Refactoring](#code-refactoring-7) - [0.6.2-alpha.1 (2021-05-14)](#062-alpha1-2021-05-14) @@ -163,12 +164,12 @@ - [Code Generation](#code-generation-26) - [Features](#features-16) - [0.6.0-alpha.2 (2021-05-07)](#060-alpha2-2021-05-07) - - [Bug Fixes](#bug-fixes-21) + - [Bug Fixes](#bug-fixes-22) - [Code Generation](#code-generation-27) - [Features](#features-17) - [0.6.0-alpha.1 (2021-05-05)](#060-alpha1-2021-05-05) - [Breaking Changes](#breaking-changes-12) - - [Bug Fixes](#bug-fixes-22) + - [Bug Fixes](#bug-fixes-23) - [Code Generation](#code-generation-28) - [Code Refactoring](#code-refactoring-8) - [Documentation](#documentation-18) @@ -176,31 +177,31 @@ - [Tests](#tests-15) - [Unclassified](#unclassified-8) - [0.5.5-alpha.1 (2020-12-09)](#055-alpha1-2020-12-09) - - [Bug Fixes](#bug-fixes-23) + - [Bug Fixes](#bug-fixes-24) - [Code Generation](#code-generation-29) - [Documentation](#documentation-19) - [Features](#features-19) - [Tests](#tests-16) - [Unclassified](#unclassified-9) - [0.5.4-alpha.1 (2020-11-11)](#054-alpha1-2020-11-11) - - [Bug Fixes](#bug-fixes-24) + - [Bug Fixes](#bug-fixes-25) - [Code Generation](#code-generation-30) - [Code Refactoring](#code-refactoring-9) - [Documentation](#documentation-20) - [Features](#features-20) - [0.5.3-alpha.1 (2020-10-27)](#053-alpha1-2020-10-27) - - [Bug Fixes](#bug-fixes-25) + - [Bug Fixes](#bug-fixes-26) - [Code Generation](#code-generation-31) - [Documentation](#documentation-21) - [Features](#features-21) - [Tests](#tests-17) - [0.5.2-alpha.1 (2020-10-22)](#052-alpha1-2020-10-22) - - [Bug Fixes](#bug-fixes-26) + - [Bug Fixes](#bug-fixes-27) - [Code Generation](#code-generation-32) - [Documentation](#documentation-22) - [Tests](#tests-18) - [0.5.1-alpha.1 (2020-10-20)](#051-alpha1-2020-10-20) - - [Bug Fixes](#bug-fixes-27) + - [Bug Fixes](#bug-fixes-28) - [Code Generation](#code-generation-33) - [Documentation](#documentation-23) - [Features](#features-22) @@ -208,7 +209,7 @@ - [Unclassified](#unclassified-10) - [0.5.0-alpha.1 (2020-10-15)](#050-alpha1-2020-10-15) - [Breaking Changes](#breaking-changes-13) - - [Bug Fixes](#bug-fixes-28) + - [Bug Fixes](#bug-fixes-29) - [Code Generation](#code-generation-34) - [Code Refactoring](#code-refactoring-10) - [Documentation](#documentation-24) @@ -216,24 +217,24 @@ - [Tests](#tests-20) - [Unclassified](#unclassified-11) - [0.4.6-alpha.1 (2020-07-13)](#046-alpha1-2020-07-13) - - [Bug Fixes](#bug-fixes-29) + - [Bug Fixes](#bug-fixes-30) - [Code Generation](#code-generation-35) - [0.4.5-alpha.1 (2020-07-13)](#045-alpha1-2020-07-13) - - [Bug Fixes](#bug-fixes-30) + - [Bug Fixes](#bug-fixes-31) - [Code Generation](#code-generation-36) - [0.4.4-alpha.1 (2020-07-10)](#044-alpha1-2020-07-10) - - [Bug Fixes](#bug-fixes-31) + - [Bug Fixes](#bug-fixes-32) - [Code Generation](#code-generation-37) - [Documentation](#documentation-25) - [0.4.3-alpha.1 (2020-07-08)](#043-alpha1-2020-07-08) - - [Bug Fixes](#bug-fixes-32) + - [Bug Fixes](#bug-fixes-33) - [Code Generation](#code-generation-38) - [0.4.2-alpha.1 (2020-07-08)](#042-alpha1-2020-07-08) - - [Bug Fixes](#bug-fixes-33) + - [Bug Fixes](#bug-fixes-34) - [Code Generation](#code-generation-39) - [0.4.0-alpha.1 (2020-07-08)](#040-alpha1-2020-07-08) - [Breaking Changes](#breaking-changes-14) - - [Bug Fixes](#bug-fixes-34) + - [Bug Fixes](#bug-fixes-35) - [Code Generation](#code-generation-40) - [Code Refactoring](#code-refactoring-11) - [Documentation](#documentation-26) @@ -241,7 +242,7 @@ - [Unclassified](#unclassified-12) - [0.3.0-alpha.1 (2020-05-15)](#030-alpha1-2020-05-15) - [Breaking Changes](#breaking-changes-15) - - [Bug Fixes](#bug-fixes-35) + - [Bug Fixes](#bug-fixes-36) - [Chores](#chores) - [Code Refactoring](#code-refactoring-12) - [Documentation](#documentation-27) @@ -252,18 +253,18 @@ - [Documentation](#documentation-28) - [0.2.0-alpha.2 (2020-05-04)](#020-alpha2-2020-05-04) - [Breaking Changes](#breaking-changes-16) - - [Bug Fixes](#bug-fixes-36) + - [Bug Fixes](#bug-fixes-37) - [Chores](#chores-2) - [Code Refactoring](#code-refactoring-13) - [Documentation](#documentation-29) - [Features](#features-26) - [Unclassified](#unclassified-14) - [0.1.1-alpha.1 (2020-02-18)](#011-alpha1-2020-02-18) - - [Bug Fixes](#bug-fixes-37) + - [Bug Fixes](#bug-fixes-38) - [Code Refactoring](#code-refactoring-14) - [Documentation](#documentation-30) - [0.1.0-alpha.6 (2020-02-16)](#010-alpha6-2020-02-16) - - [Bug Fixes](#bug-fixes-38) + - [Bug Fixes](#bug-fixes-39) - [Code Refactoring](#code-refactoring-15) - [Documentation](#documentation-31) - [Features](#features-27) @@ -276,7 +277,7 @@ - [0.1.0-alpha.3 (2020-02-06)](#010-alpha3-2020-02-06) - [Continuous Integration](#continuous-integration-1) - [0.1.0-alpha.2 (2020-02-03)](#010-alpha2-2020-02-03) - - [Bug Fixes](#bug-fixes-39) + - [Bug Fixes](#bug-fixes-40) - [Documentation](#documentation-34) - [Features](#features-29) - [Unclassified](#unclassified-15) @@ -321,6 +322,11 @@ # [](https://github.com/ory/kratos/compare/v1.1.0-pre.0...v) (2024-02-05) +### Bug Fixes + +- Add consistency flag ([#3733](https://github.com/ory/kratos/issues/3733)) + ([fd79950](https://github.com/ory/kratos/commit/fd7995077307cc101550eda5d7724ea1f68fa98a)) + ### Features - List by OIDC cred ([#3721](https://github.com/ory/kratos/issues/3721)) From 241a911af74e8ad7353d6e3cab86db20758b86fc Mon Sep 17 00:00:00 2001 From: Henning Perl Date: Wed, 7 Feb 2024 12:10:40 +0100 Subject: [PATCH 268/282] fix: set iss from userinfo claims if missing (#3744) --- selfservice/strategy/oidc/provider_generic_oidc.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/selfservice/strategy/oidc/provider_generic_oidc.go b/selfservice/strategy/oidc/provider_generic_oidc.go index 4f060e8a84e6..146505165807 100644 --- a/selfservice/strategy/oidc/provider_generic_oidc.go +++ b/selfservice/strategy/oidc/provider_generic_oidc.go @@ -164,6 +164,17 @@ func (g *ProviderGenericOIDC) claimsFromUserInfo(ctx context.Context, exchange * return nil, errors.WithStack(herodot.ErrBadRequest.WithReason("sub (Subject) claim mismatch between ID token and UserInfo endpoint")) } + // If signed, the UserInfo Response MUST contain the Claims iss (issuer) and aud + // (audience) as members. The iss value MUST be the OP's Issuer Identifier URL. + // The aud value MUST be or include the RP's Client ID value. + // See https://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse + // + // Consequently, the issuer might not be present in the UserInfo response and we + // need to set it here. + if claims.Issuer == "" { + claims.Issuer = idToken.Issuer + } + return &claims, nil } From af558345678ac508393858a7fab7ba3657a77b1a Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Wed, 7 Feb 2024 11:52:47 +0000 Subject: [PATCH 269/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d68bb6a06764..ef44b9cc468a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2024-02-05)](#2024-02-05) +- [ (2024-02-07)](#2024-02-07) - [Bug Fixes](#bug-fixes) - [Features](#features) - [Tests](#tests) @@ -320,12 +320,15 @@ -# [](https://github.com/ory/kratos/compare/v1.1.0-pre.0...v) (2024-02-05) +# [](https://github.com/ory/kratos/compare/v1.1.0-pre.0...v) (2024-02-07) ### Bug Fixes - Add consistency flag ([#3733](https://github.com/ory/kratos/issues/3733)) ([fd79950](https://github.com/ory/kratos/commit/fd7995077307cc101550eda5d7724ea1f68fa98a)) +- Set iss from userinfo claims if missing + ([#3744](https://github.com/ory/kratos/issues/3744)) + ([241a911](https://github.com/ory/kratos/commit/241a911af74e8ad7353d6e3cab86db20758b86fc)) ### Features From 84149c4b420ea89f0a16a579c017a8e7e1670204 Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Fri, 9 Feb 2024 11:46:52 +0100 Subject: [PATCH 270/282] fix: http courier using should use lower case json (#3740) --- courier/http_channel.go | 12 +++++----- courier/http_test.go | 24 +++++++++---------- courier/stub/request.config.mailer.jsonnet | 18 +++++++------- courier/stub/request.config.twilio.jsonnet | 4 ++-- courier/template/email/login_code_valid.go | 6 ++--- .../template/email/recovery_code_invalid.go | 2 +- courier/template/email/recovery_code_valid.go | 6 ++--- courier/template/email/recovery_invalid.go | 2 +- courier/template/email/recovery_valid.go | 6 ++--- .../template/email/registration_code_valid.go | 6 ++--- courier/template/email/stub.go | 6 ++--- .../email/verification_code_invalid.go | 2 +- .../template/email/verification_code_valid.go | 8 +++---- .../template/email/verification_invalid.go | 2 +- courier/template/email/verification_valid.go | 6 ++--- courier/template/sms/login_code_valid.go | 6 ++--- courier/template/sms/stub.go | 6 ++--- courier/template/sms/verification_code.go | 6 ++--- embedx/config.schema.json | 2 +- internal/client-go/go.sum | 1 + request/builder_test.go | 22 ++++++++--------- request/stub/test_body.jsonnet | 6 ++--- 22 files changed, 80 insertions(+), 79 deletions(-) diff --git a/courier/http_channel.go b/courier/http_channel.go index e9015dca13fd..13e0a5792623 100644 --- a/courier/http_channel.go +++ b/courier/http_channel.go @@ -47,12 +47,12 @@ func (c *httpChannel) ID() string { } type httpDataModel struct { - Recipient string - Subject string - Body string - TemplateType template.TemplateType - TemplateData Template - MessageType string + Recipient string `json:"recipient"` + Subject string `json:"subject"` + Body string `json:"body"` + TemplateType template.TemplateType `json:"template_type"` + TemplateData Template `json:"template_data"` + MessageType string `json:"message_type"` } func (c *httpChannel) Dispatch(ctx context.Context, msg Message) (err error) { diff --git a/courier/http_test.go b/courier/http_test.go index 4f21e467653b..f6327bdafc4e 100644 --- a/courier/http_test.go +++ b/courier/http_test.go @@ -30,17 +30,17 @@ func TestQueueHTTPEmail(t *testing.T) { ctx := context.Background() type sendEmailRequestBody struct { - IdentityID string - IdentityEmail string - Recipient string - TemplateType string - To string - RecoveryCode string - RecoveryURL string - VerificationURL string - VerificationCode string - Body string - Subject string + IdentityID string `json:"identity_id"` + IdentityEmail string `json:"identity_email"` + Recipient string `json:"recipient"` + TemplateType string `json:"template_type"` + To string `json:"to"` + RecoveryCode string `json:"recovery_code"` + RecoveryURL string `json:"recovery_url"` + VerificationURL string `json:"verification_url"` + VerificationCode string `json:"verification_code"` + Body string `json:"body"` + Subject string `json:"subject"` } expectedEmail := []*email.TestStubModel{ @@ -112,7 +112,7 @@ func TestQueueHTTPEmail(t *testing.T) { if len(actual) == len(expectedEmail) { return nil } - return errors.New("capacity not reached") + return errors.Errorf("capacity not reached: %d of %d", len(actual), len(expectedEmail)) })) for i, message := range actual { diff --git a/courier/stub/request.config.mailer.jsonnet b/courier/stub/request.config.mailer.jsonnet index 903aff05f541..fba51d68f8a2 100644 --- a/courier/stub/request.config.mailer.jsonnet +++ b/courier/stub/request.config.mailer.jsonnet @@ -1,11 +1,11 @@ function(ctx) { - recipient: ctx.Recipient, - template_type: ctx.TemplateType, - to: if "TemplateData" in ctx && "To" in ctx.TemplateData then ctx.TemplateData.To else null, - recovery_code: if "TemplateData" in ctx && "RecoveryCode" in ctx.TemplateData then ctx.TemplateData.RecoveryCode else null, - recovery_url: if "TemplateData" in ctx && "RecoveryURL" in ctx.TemplateData then ctx.TemplateData.RecoveryURL else null, - verification_url: if "TemplateData" in ctx && "VerificationURL" in ctx.TemplateData then ctx.TemplateData.VerificationURL else null, - verification_code: if "TemplateData" in ctx && "VerificationCode" in ctx.TemplateData then ctx.TemplateData.VerificationCode else null, - subject: if "TemplateData" in ctx && "Subject" in ctx.TemplateData then ctx.TemplateData.Subject else null, - body: if "TemplateData" in ctx && "Body" in ctx.TemplateData then ctx.TemplateData.Body else null + recipient: ctx.recipient, + template_type: ctx.template_type, + to: if "template_data" in ctx && "to" in ctx.template_data then ctx.template_data.to else null, + recovery_code: if "template_data" in ctx && "recovery_code" in ctx.template_data then ctx.template_data.recovery_code else null, + recovery_url: if "template_data" in ctx && "recovery_url" in ctx.template_data then ctx.template_data.recovery_url else null, + verification_url: if "template_data" in ctx && "verification_url" in ctx.template_data then ctx.template_data.verification_url else null, + verification_code: if "template_data" in ctx && "verification_code" in ctx.template_data then ctx.template_data.verification_code else null, + subject: if "template_data" in ctx && "subject" in ctx.template_data then ctx.template_data.subject else null, + body: if "template_data" in ctx && "body" in ctx.template_data then ctx.template_data.body else null } diff --git a/courier/stub/request.config.twilio.jsonnet b/courier/stub/request.config.twilio.jsonnet index f3a99db694e5..b8497666a227 100644 --- a/courier/stub/request.config.twilio.jsonnet +++ b/courier/stub/request.config.twilio.jsonnet @@ -1,5 +1,5 @@ function(ctx) { from: "Kratos Test", - to: ctx.Recipient, - body: ctx.Body + to: ctx.recipient, + body: ctx.body } diff --git a/courier/template/email/login_code_valid.go b/courier/template/email/login_code_valid.go index 1b3b55d4807c..ea1dde008728 100644 --- a/courier/template/email/login_code_valid.go +++ b/courier/template/email/login_code_valid.go @@ -18,9 +18,9 @@ type ( model *LoginCodeValidModel } LoginCodeValidModel struct { - To string - LoginCode string - Identity map[string]interface{} + To string `json:"to"` + LoginCode string `json:"login_code"` + Identity map[string]interface{} `json:"identity"` } ) diff --git a/courier/template/email/recovery_code_invalid.go b/courier/template/email/recovery_code_invalid.go index 4914b75c7024..2ac8022bf2d0 100644 --- a/courier/template/email/recovery_code_invalid.go +++ b/courier/template/email/recovery_code_invalid.go @@ -18,7 +18,7 @@ type ( model *RecoveryCodeInvalidModel } RecoveryCodeInvalidModel struct { - To string + To string `json:"to"` } ) diff --git a/courier/template/email/recovery_code_valid.go b/courier/template/email/recovery_code_valid.go index dce31b72e2fa..e386de93d984 100644 --- a/courier/template/email/recovery_code_valid.go +++ b/courier/template/email/recovery_code_valid.go @@ -18,9 +18,9 @@ type ( model *RecoveryCodeValidModel } RecoveryCodeValidModel struct { - To string - RecoveryCode string - Identity map[string]interface{} + To string `json:"to"` + RecoveryCode string `json:"recovery_code"` + Identity map[string]interface{} `json:"identity"` } ) diff --git a/courier/template/email/recovery_invalid.go b/courier/template/email/recovery_invalid.go index dbc8992d5593..4d19808206f5 100644 --- a/courier/template/email/recovery_invalid.go +++ b/courier/template/email/recovery_invalid.go @@ -18,7 +18,7 @@ type ( m *RecoveryInvalidModel } RecoveryInvalidModel struct { - To string + To string `json:"to"` } ) diff --git a/courier/template/email/recovery_valid.go b/courier/template/email/recovery_valid.go index 532d8d1bc4e6..0a9e01e35919 100644 --- a/courier/template/email/recovery_valid.go +++ b/courier/template/email/recovery_valid.go @@ -18,9 +18,9 @@ type ( m *RecoveryValidModel } RecoveryValidModel struct { - To string - RecoveryURL string - Identity map[string]interface{} + To string `json:"to"` + RecoveryURL string `json:"recovery_url"` + Identity map[string]interface{} `json:"identity"` } ) diff --git a/courier/template/email/registration_code_valid.go b/courier/template/email/registration_code_valid.go index f984ffaeb6c6..1c48b89f80c4 100644 --- a/courier/template/email/registration_code_valid.go +++ b/courier/template/email/registration_code_valid.go @@ -18,9 +18,9 @@ type ( model *RegistrationCodeValidModel } RegistrationCodeValidModel struct { - To string - Traits map[string]interface{} - RegistrationCode string + To string `json:"to"` + Traits map[string]interface{} `json:"traits"` + RegistrationCode string `json:"registration_code"` } ) diff --git a/courier/template/email/stub.go b/courier/template/email/stub.go index 57b66e06e4aa..9493ca967a08 100644 --- a/courier/template/email/stub.go +++ b/courier/template/email/stub.go @@ -18,9 +18,9 @@ type ( m *TestStubModel } TestStubModel struct { - To string - Subject string - Body string + To string `json:"to"` + Subject string `json:"subject"` + Body string `json:"body"` } ) diff --git a/courier/template/email/verification_code_invalid.go b/courier/template/email/verification_code_invalid.go index fa76441b3434..491997a50ec3 100644 --- a/courier/template/email/verification_code_invalid.go +++ b/courier/template/email/verification_code_invalid.go @@ -18,7 +18,7 @@ type ( m *VerificationCodeInvalidModel } VerificationCodeInvalidModel struct { - To string + To string `json:"to"` } ) diff --git a/courier/template/email/verification_code_valid.go b/courier/template/email/verification_code_valid.go index e23f48f70b5a..3f6ccb966ed9 100644 --- a/courier/template/email/verification_code_valid.go +++ b/courier/template/email/verification_code_valid.go @@ -18,10 +18,10 @@ type ( m *VerificationCodeValidModel } VerificationCodeValidModel struct { - To string - VerificationURL string - VerificationCode string - Identity map[string]interface{} + To string `json:"to"` + VerificationURL string `json:"verification_url"` + VerificationCode string `json:"verification_code"` + Identity map[string]interface{} `json:"identity"` } ) diff --git a/courier/template/email/verification_invalid.go b/courier/template/email/verification_invalid.go index 5f6623f04352..dc2e050a585e 100644 --- a/courier/template/email/verification_invalid.go +++ b/courier/template/email/verification_invalid.go @@ -18,7 +18,7 @@ type ( m *VerificationInvalidModel } VerificationInvalidModel struct { - To string + To string `json:"to"` } ) diff --git a/courier/template/email/verification_valid.go b/courier/template/email/verification_valid.go index 723ea618e071..9c088d144735 100644 --- a/courier/template/email/verification_valid.go +++ b/courier/template/email/verification_valid.go @@ -18,9 +18,9 @@ type ( m *VerificationValidModel } VerificationValidModel struct { - To string - VerificationURL string - Identity map[string]interface{} + To string `json:"to"` + VerificationURL string `json:"verification_url"` + Identity map[string]interface{} `json:"identity"` } ) diff --git a/courier/template/sms/login_code_valid.go b/courier/template/sms/login_code_valid.go index 194e113e6c6b..2f56aee885a7 100644 --- a/courier/template/sms/login_code_valid.go +++ b/courier/template/sms/login_code_valid.go @@ -17,9 +17,9 @@ type ( model *LoginCodeValidModel } LoginCodeValidModel struct { - To string - LoginCode string - Identity map[string]interface{} + To string `json:"to"` + LoginCode string `json:"login_code"` + Identity map[string]interface{} `json:"identity"` } ) diff --git a/courier/template/sms/stub.go b/courier/template/sms/stub.go index 0d68db1b209b..b75f541e462e 100644 --- a/courier/template/sms/stub.go +++ b/courier/template/sms/stub.go @@ -18,9 +18,9 @@ type ( } TestStubModel struct { - To string - Body string - Identity map[string]interface{} + To string `json:"to"` + Body string `json:"body"` + Identity map[string]interface{} `json:"identity"` } ) diff --git a/courier/template/sms/verification_code.go b/courier/template/sms/verification_code.go index f4ab6fc23359..a4d19e3d4a7d 100644 --- a/courier/template/sms/verification_code.go +++ b/courier/template/sms/verification_code.go @@ -18,9 +18,9 @@ type ( } VerificationCodeValidModel struct { - To string - VerificationCode string - Identity map[string]interface{} + To string `json:"to"` + VerificationCode string `json:"verification_code"` + Identity map[string]interface{} `json:"identity"` } ) diff --git a/embedx/config.schema.json b/embedx/config.schema.json index 930e7b34e95c..a836c21a7af5 100644 --- a/embedx/config.schema.json +++ b/embedx/config.schema.json @@ -150,7 +150,7 @@ "format": "uri", "pattern": "^(http|https|file|base64)://", "description": "URI pointing to the jsonnet template used for payload generation. Only used for those HTTP methods, which support HTTP body payloads", - "default": "base64://ZnVuY3Rpb24oY3R4KSB7CiAgcmVjaXBpZW50OiBjdHguUmVjaXBpZW50LAogIHRlbXBsYXRlX3R5cGU6IGN0eC5UZW1wbGF0ZVR5cGUsCiAgdG86IGlmICJUZW1wbGF0ZURhdGEiIGluIGN0eCAmJiAiVG8iIGluIGN0eC5UZW1wbGF0ZURhdGEgdGhlbiBjdHguVGVtcGxhdGVEYXRhLlRvIGVsc2UgbnVsbCwKICByZWNvdmVyeV9jb2RlOiBpZiAiVGVtcGxhdGVEYXRhIiBpbiBjdHggJiYgIlJlY292ZXJ5Q29kZSIgaW4gY3R4LlRlbXBsYXRlRGF0YSB0aGVuIGN0eC5UZW1wbGF0ZURhdGEuUmVjb3ZlcnlDb2RlIGVsc2UgbnVsbCwKICByZWNvdmVyeV91cmw6IGlmICJUZW1wbGF0ZURhdGEiIGluIGN0eCAmJiAiUmVjb3ZlcnlVUkwiIGluIGN0eC5UZW1wbGF0ZURhdGEgdGhlbiBjdHguVGVtcGxhdGVEYXRhLlJlY292ZXJ5VVJMIGVsc2UgbnVsbCwKICB2ZXJpZmljYXRpb25fdXJsOiBpZiAiVGVtcGxhdGVEYXRhIiBpbiBjdHggJiYgIlZlcmlmaWNhdGlvblVSTCIgaW4gY3R4LlRlbXBsYXRlRGF0YSB0aGVuIGN0eC5UZW1wbGF0ZURhdGEuVmVyaWZpY2F0aW9uVVJMIGVsc2UgbnVsbCwKICB2ZXJpZmljYXRpb25fY29kZTogaWYgIlRlbXBsYXRlRGF0YSIgaW4gY3R4ICYmICJWZXJpZmljYXRpb25Db2RlIiBpbiBjdHguVGVtcGxhdGVEYXRhIHRoZW4gY3R4LlRlbXBsYXRlRGF0YS5WZXJpZmljYXRpb25Db2RlIGVsc2UgbnVsbCwKICBzdWJqZWN0OiBjdHguU3ViamVjdCwKICBib2R5OiBjdHguQm9keQp9Cg==", + "default": "base64://ZnVuY3Rpb24oY3R4KSB7CiAgcmVjaXBpZW50OiBjdHgucmVjaXBpZW50LAogIHRlbXBsYXRlX3R5cGU6IGN0eC50ZW1wbGF0ZV90eXBlLAogIHRvOiBpZiAidGVtcGxhdGVfZGF0YSIgaW4gY3R4ICYmICJ0byIgaW4gY3R4LnRlbXBsYXRlX2RhdGEgdGhlbiBjdHgudGVtcGxhdGVfZGF0YS50byBlbHNlIG51bGwsCiAgcmVjb3ZlcnlfY29kZTogaWYgInRlbXBsYXRlX2RhdGEiIGluIGN0eCAmJiAicmVjb3ZlcnlfY29kZSIgaW4gY3R4LnRlbXBsYXRlX2RhdGEgdGhlbiBjdHgudGVtcGxhdGVfZGF0YS5yZWNvdmVyeV9jb2RlIGVsc2UgbnVsbCwKICByZWNvdmVyeV91cmw6IGlmICJ0ZW1wbGF0ZV9kYXRhIiBpbiBjdHggJiYgInJlY292ZXJ5X3VybCIgaW4gY3R4LnRlbXBsYXRlX2RhdGEgdGhlbiBjdHgudGVtcGxhdGVfZGF0YS5yZWNvdmVyeV91cmwgZWxzZSBudWxsLAogIHZlcmlmaWNhdGlvbl91cmw6IGlmICJ0ZW1wbGF0ZV9kYXRhIiBpbiBjdHggJiYgInZlcmlmaWNhdGlvbl91cmwiIGluIGN0eC50ZW1wbGF0ZV9kYXRhIHRoZW4gY3R4LnRlbXBsYXRlX2RhdGEudmVyaWZpY2F0aW9uX3VybCBlbHNlIG51bGwsCiAgdmVyaWZpY2F0aW9uX2NvZGU6IGlmICJ0ZW1wbGF0ZV9kYXRhIiBpbiBjdHggJiYgInZlcmlmaWNhdGlvbl9jb2RlIiBpbiBjdHgudGVtcGxhdGVfZGF0YSB0aGVuIGN0eC50ZW1wbGF0ZV9kYXRhLnZlcmlmaWNhdGlvbl9jb2RlIGVsc2UgbnVsbCwKICBzdWJqZWN0OiBjdHguc3ViamVjdCwKICBib2R5OiBjdHguYm9keQp9Cg==", "examples": [ "file:///path/to/body.jsonnet", "file://./body.jsonnet", diff --git a/internal/client-go/go.sum b/internal/client-go/go.sum index c966c8ddfd0d..6cc3f5911d11 100644 --- a/internal/client-go/go.sum +++ b/internal/client-go/go.sum @@ -4,6 +4,7 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/request/builder_test.go b/request/builder_test.go index 8269b5133346..3b443dd2ce29 100644 --- a/request/builder_test.go +++ b/request/builder_test.go @@ -22,9 +22,9 @@ import ( ) type testRequestBody struct { - To string - From string - Body string + To string `json:"to"` + From string `json:"from"` + Body string `json:"body"` } //go:embed stub/test_body.jsonnet @@ -53,7 +53,7 @@ func TestBuildRequest(t *testing.T) { From: "+12288534869", Body: "test-sms-body", }, - expectedBody: "{\n \"Body\": \"test-sms-body\",\n \"From\": \"+12288534869\",\n \"To\": \"+15056445993\"\n}\n", + expectedBody: "{\n \"body\": \"test-sms-body\",\n \"from\": \"+12288534869\",\n \"to\": \"+15056445993\"\n}\n", rawConfig: `{ "url": "https://test.kratos.ory.sh/my_endpoint1", "method": "POST", @@ -70,7 +70,7 @@ func TestBuildRequest(t *testing.T) { From: "+12288534869", Body: "test-sms-body", }, - expectedBody: "{\n \"Body\": \"test-sms-body\",\n \"From\": \"+12288534869\",\n \"To\": \"+15056445993\"\n}\n", + expectedBody: "{\n \"body\": \"test-sms-body\",\n \"from\": \"+12288534869\",\n \"to\": \"+15056445993\"\n}\n", rawConfig: `{ "url": "https://test.kratos.ory.sh/my_endpoint1", "method": "POST", @@ -87,7 +87,7 @@ func TestBuildRequest(t *testing.T) { From: "+12288534869", Body: "test-sms-body", }, - expectedBody: "{\n \"Body\": \"test-sms-body\",\n \"From\": \"+12288534869\",\n \"To\": \"+15056445993\"\n}\n", + expectedBody: "{\n \"body\": \"test-sms-body\",\n \"from\": \"+12288534869\",\n \"to\": \"+15056445993\"\n}\n", rawConfig: fmt.Sprintf( `{ "url": "https://test.kratos.ory.sh/my_endpoint1", @@ -108,7 +108,7 @@ func TestBuildRequest(t *testing.T) { From: "+15822228108", Body: "test-sms-body", }, - expectedBody: "{\n \"Body\": \"test-sms-body\",\n \"From\": \"+15822228108\",\n \"To\": \"+12127110378\"\n}\n", + expectedBody: "{\n \"body\": \"test-sms-body\",\n \"from\": \"+15822228108\",\n \"to\": \"+12127110378\"\n}\n", rawConfig: `{ "url": "https://test.kratos.ory.sh/my_endpoint2", "method": "POST", @@ -129,7 +129,7 @@ func TestBuildRequest(t *testing.T) { From: "+13104661805", Body: "test-sms-body", }, - expectedBody: "{\n \"Body\": \"test-sms-body\",\n \"From\": \"+13104661805\",\n \"To\": \"+14134242223\"\n}\n", + expectedBody: "{\n \"body\": \"test-sms-body\",\n \"from\": \"+13104661805\",\n \"to\": \"+14134242223\"\n}\n", rawConfig: `{ "url": "https://test.kratos.ory.sh/my_endpoint3", "method": "GET", @@ -171,7 +171,7 @@ func TestBuildRequest(t *testing.T) { From: "+14253787846", Body: "test-sms-body", }, - expectedBody: "{\n \"Body\": \"test-sms-body\",\n \"From\": \"+14253787846\",\n \"To\": \"+12235499085\"\n}\n", + expectedBody: "{\n \"body\": \"test-sms-body\",\n \"from\": \"+14253787846\",\n \"to\": \"+12235499085\"\n}\n", rawConfig: `{ "url": "https://test.kratos.ory.sh/my_endpoint5", "method": "DELETE", @@ -198,7 +198,7 @@ func TestBuildRequest(t *testing.T) { From: "+13104661805", Body: "test-sms-body", }, - expectedBody: "Body=test-sms-body&From=%2B13104661805&To=%2B14134242223", + expectedBody: "body=test-sms-body&from=%2B13104661805&to=%2B14134242223", rawConfig: `{ "url": "https://test.kratos.ory.sh/my_endpoint6", "method": "POST", @@ -228,7 +228,7 @@ func TestBuildRequest(t *testing.T) { From: "+13104661805", Body: "test-sms-body", }, - expectedBody: "{\n \"Body\": \"test-sms-body\",\n \"From\": \"+13104661805\",\n \"To\": \"+14134242223\"\n}\n", + expectedBody: "{\n \"body\": \"test-sms-body\",\n \"from\": \"+13104661805\",\n \"to\": \"+14134242223\"\n}\n", rawConfig: `{ "url": "https://test.kratos.ory.sh/my_endpoint7", "method": "POST", diff --git a/request/stub/test_body.jsonnet b/request/stub/test_body.jsonnet index 03edc83a65e2..63f5ec813f26 100644 --- a/request/stub/test_body.jsonnet +++ b/request/stub/test_body.jsonnet @@ -1,5 +1,5 @@ function(ctx) { - From: ctx.From, - To: ctx.To, - Body: ctx.Body, + from: ctx.from, + to: ctx.to, + body: ctx.body, } From deeb165d8f19222ca04b9a6de8c3822f0d7eea20 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Fri, 9 Feb 2024 10:48:22 +0000 Subject: [PATCH 271/282] autogen(openapi): regenerate swagger spec and internal client [skip ci] --- internal/client-go/go.sum | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/client-go/go.sum b/internal/client-go/go.sum index 6cc3f5911d11..c966c8ddfd0d 100644 --- a/internal/client-go/go.sum +++ b/internal/client-go/go.sum @@ -4,7 +4,6 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= From dbb3a7ed37cde3f96fe90c45f2613397fe7f3ac6 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Fri, 9 Feb 2024 11:28:47 +0000 Subject: [PATCH 272/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef44b9cc468a..0b71fad43c66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2024-02-07)](#2024-02-07) +- [ (2024-02-09)](#2024-02-09) - [Bug Fixes](#bug-fixes) - [Features](#features) - [Tests](#tests) @@ -320,12 +320,15 @@ -# [](https://github.com/ory/kratos/compare/v1.1.0-pre.0...v) (2024-02-07) +# [](https://github.com/ory/kratos/compare/v1.1.0-pre.0...v) (2024-02-09) ### Bug Fixes - Add consistency flag ([#3733](https://github.com/ory/kratos/issues/3733)) ([fd79950](https://github.com/ory/kratos/commit/fd7995077307cc101550eda5d7724ea1f68fa98a)) +- Http courier using should use lower case json + ([#3740](https://github.com/ory/kratos/issues/3740)) + ([84149c4](https://github.com/ory/kratos/commit/84149c4b420ea89f0a16a579c017a8e7e1670204)) - Set iss from userinfo claims if missing ([#3744](https://github.com/ory/kratos/issues/3744)) ([241a911](https://github.com/ory/kratos/commit/241a911af74e8ad7353d6e3cab86db20758b86fc)) From bf5f8c3cfb2eb523a77239addb8249adf9f8b31d Mon Sep 17 00:00:00 2001 From: aeneasr <3372410+aeneasr@users.noreply.github.com> Date: Mon, 12 Feb 2024 13:12:38 +0100 Subject: [PATCH 273/282] feat: add request URL to email and SMS templates --- courier/template/email/login_code_valid.go | 7 ++-- .../template/email/recovery_code_invalid.go | 3 +- courier/template/email/recovery_code_valid.go | 1 + courier/template/email/recovery_invalid.go | 3 +- courier/template/email/recovery_valid.go | 1 + .../template/email/registration_code_valid.go | 1 + .../email/verification_code_invalid.go | 3 +- .../template/email/verification_code_valid.go | 1 + .../template/email/verification_invalid.go | 3 +- courier/template/email/verification_valid.go | 1 + courier/template/sms/login_code_valid.go | 7 ++-- courier/template/sms/verification_code.go | 1 + selfservice/strategy/code/code_sender.go | 32 +++++++++++++------ selfservice/strategy/link/sender.go | 32 +++++++++++++------ 14 files changed, 67 insertions(+), 29 deletions(-) diff --git a/courier/template/email/login_code_valid.go b/courier/template/email/login_code_valid.go index ea1dde008728..f48ae6116118 100644 --- a/courier/template/email/login_code_valid.go +++ b/courier/template/email/login_code_valid.go @@ -18,9 +18,10 @@ type ( model *LoginCodeValidModel } LoginCodeValidModel struct { - To string `json:"to"` - LoginCode string `json:"login_code"` - Identity map[string]interface{} `json:"identity"` + To string `json:"to"` + LoginCode string `json:"login_code"` + Identity map[string]interface{} `json:"identity"` + RequestURL string `json:"request_url"` } ) diff --git a/courier/template/email/recovery_code_invalid.go b/courier/template/email/recovery_code_invalid.go index 2ac8022bf2d0..e2f648003271 100644 --- a/courier/template/email/recovery_code_invalid.go +++ b/courier/template/email/recovery_code_invalid.go @@ -18,7 +18,8 @@ type ( model *RecoveryCodeInvalidModel } RecoveryCodeInvalidModel struct { - To string `json:"to"` + To string `json:"to"` + RequestURL string `json:"request_url"` } ) diff --git a/courier/template/email/recovery_code_valid.go b/courier/template/email/recovery_code_valid.go index e386de93d984..f9e2ad9ec20f 100644 --- a/courier/template/email/recovery_code_valid.go +++ b/courier/template/email/recovery_code_valid.go @@ -21,6 +21,7 @@ type ( To string `json:"to"` RecoveryCode string `json:"recovery_code"` Identity map[string]interface{} `json:"identity"` + RequestURL string `json:"request_url"` } ) diff --git a/courier/template/email/recovery_invalid.go b/courier/template/email/recovery_invalid.go index 4d19808206f5..38d70d44bdc9 100644 --- a/courier/template/email/recovery_invalid.go +++ b/courier/template/email/recovery_invalid.go @@ -18,7 +18,8 @@ type ( m *RecoveryInvalidModel } RecoveryInvalidModel struct { - To string `json:"to"` + To string `json:"to"` + RequestURL string `json:"request_url"` } ) diff --git a/courier/template/email/recovery_valid.go b/courier/template/email/recovery_valid.go index 0a9e01e35919..18e4fde7bd66 100644 --- a/courier/template/email/recovery_valid.go +++ b/courier/template/email/recovery_valid.go @@ -21,6 +21,7 @@ type ( To string `json:"to"` RecoveryURL string `json:"recovery_url"` Identity map[string]interface{} `json:"identity"` + RequestURL string `json:"request_url"` } ) diff --git a/courier/template/email/registration_code_valid.go b/courier/template/email/registration_code_valid.go index 1c48b89f80c4..e63812b00b80 100644 --- a/courier/template/email/registration_code_valid.go +++ b/courier/template/email/registration_code_valid.go @@ -21,6 +21,7 @@ type ( To string `json:"to"` Traits map[string]interface{} `json:"traits"` RegistrationCode string `json:"registration_code"` + RequestURL string `json:"request_url"` } ) diff --git a/courier/template/email/verification_code_invalid.go b/courier/template/email/verification_code_invalid.go index 491997a50ec3..77aec0c04c3e 100644 --- a/courier/template/email/verification_code_invalid.go +++ b/courier/template/email/verification_code_invalid.go @@ -18,7 +18,8 @@ type ( m *VerificationCodeInvalidModel } VerificationCodeInvalidModel struct { - To string `json:"to"` + To string `json:"to"` + RequestURL string `json:"request_url"` } ) diff --git a/courier/template/email/verification_code_valid.go b/courier/template/email/verification_code_valid.go index 3f6ccb966ed9..7cf5823b0524 100644 --- a/courier/template/email/verification_code_valid.go +++ b/courier/template/email/verification_code_valid.go @@ -22,6 +22,7 @@ type ( VerificationURL string `json:"verification_url"` VerificationCode string `json:"verification_code"` Identity map[string]interface{} `json:"identity"` + RequestURL string `json:"request_url"` } ) diff --git a/courier/template/email/verification_invalid.go b/courier/template/email/verification_invalid.go index dc2e050a585e..7b0a776fa254 100644 --- a/courier/template/email/verification_invalid.go +++ b/courier/template/email/verification_invalid.go @@ -18,7 +18,8 @@ type ( m *VerificationInvalidModel } VerificationInvalidModel struct { - To string `json:"to"` + To string `json:"to"` + RequestURL string `json:"request_url"` } ) diff --git a/courier/template/email/verification_valid.go b/courier/template/email/verification_valid.go index 9c088d144735..c04913953519 100644 --- a/courier/template/email/verification_valid.go +++ b/courier/template/email/verification_valid.go @@ -21,6 +21,7 @@ type ( To string `json:"to"` VerificationURL string `json:"verification_url"` Identity map[string]interface{} `json:"identity"` + RequestURL string `json:"request_url"` } ) diff --git a/courier/template/sms/login_code_valid.go b/courier/template/sms/login_code_valid.go index 2f56aee885a7..439856accb8a 100644 --- a/courier/template/sms/login_code_valid.go +++ b/courier/template/sms/login_code_valid.go @@ -17,9 +17,10 @@ type ( model *LoginCodeValidModel } LoginCodeValidModel struct { - To string `json:"to"` - LoginCode string `json:"login_code"` - Identity map[string]interface{} `json:"identity"` + To string `json:"to"` + LoginCode string `json:"login_code"` + Identity map[string]interface{} `json:"identity"` + RequestURL string `json:"request_url"` } ) diff --git a/courier/template/sms/verification_code.go b/courier/template/sms/verification_code.go index a4d19e3d4a7d..a367de9e584c 100644 --- a/courier/template/sms/verification_code.go +++ b/courier/template/sms/verification_code.go @@ -21,6 +21,7 @@ type ( To string `json:"to"` VerificationCode string `json:"verification_code"` Identity map[string]interface{} `json:"identity"` + RequestURL string `json:"request_url"` } ) diff --git a/selfservice/strategy/code/code_sender.go b/selfservice/strategy/code/code_sender.go index ccc3330f9ba8..d0166e86863f 100644 --- a/selfservice/strategy/code/code_sender.go +++ b/selfservice/strategy/code/code_sender.go @@ -102,6 +102,7 @@ func (s *Sender) SendCode(ctx context.Context, f flow.Flow, id *identity.Identit To: address.To, RegistrationCode: rawCode, Traits: model, + RequestURL: f.GetRequestURL(), } s.deps.Audit(). @@ -143,15 +144,17 @@ func (s *Sender) SendCode(ctx context.Context, f flow.Flow, id *identity.Identit switch address.Via { case identity.ChannelTypeEmail: t = email.NewLoginCodeValid(s.deps, &email.LoginCodeValidModel{ - To: address.To, - LoginCode: rawCode, - Identity: model, + To: address.To, + LoginCode: rawCode, + Identity: model, + RequestURL: f.GetRequestURL(), }) case identity.ChannelTypeSMS: t = sms.NewLoginCodeValid(s.deps, &sms.LoginCodeValidModel{ - To: address.To, - LoginCode: rawCode, - Identity: model, + To: address.To, + LoginCode: rawCode, + Identity: model, + RequestURL: f.GetRequestURL(), }) } @@ -189,7 +192,10 @@ func (s *Sender) SendRecoveryCode(ctx context.Context, f *recovery.Flow, via ide Info("Account recovery was requested for an unknown address.") if !notifyUnknownRecipients { // do nothing - } else if err := s.send(ctx, string(via), email.NewRecoveryCodeInvalid(s.deps, &email.RecoveryCodeInvalidModel{To: to})); err != nil { + } else if err := s.send(ctx, string(via), email.NewRecoveryCodeInvalid(s.deps, &email.RecoveryCodeInvalidModel{ + To: to, + RequestURL: f.RequestURL, + })); err != nil { return err } return errors.WithStack(ErrUnknownAddress) @@ -220,10 +226,10 @@ func (s *Sender) SendRecoveryCode(ctx context.Context, f *recovery.Flow, via ide return err } - return s.SendRecoveryCodeTo(ctx, i, rawCode, code) + return s.SendRecoveryCodeTo(ctx, i, rawCode, code, f) } -func (s *Sender) SendRecoveryCodeTo(ctx context.Context, i *identity.Identity, codeString string, code *RecoveryCode) error { +func (s *Sender) SendRecoveryCodeTo(ctx context.Context, i *identity.Identity, codeString string, code *RecoveryCode, f flow.Flow) error { s.deps.Audit(). WithField("via", code.RecoveryAddress.Via). WithField("identity_id", code.RecoveryAddress.IdentityID). @@ -241,6 +247,7 @@ func (s *Sender) SendRecoveryCodeTo(ctx context.Context, i *identity.Identity, c To: code.RecoveryAddress.Value, RecoveryCode: codeString, Identity: model, + RequestURL: f.GetRequestURL(), } return s.send(ctx, string(code.RecoveryAddress.Via), email.NewRecoveryCodeValid(s.deps, &emailModel)) @@ -268,7 +275,10 @@ func (s *Sender) SendVerificationCode(ctx context.Context, f *verification.Flow, Info("Address verification was requested for an unknown address.") if !notifyUnknownRecipients { // do nothing - } else if err := s.send(ctx, string(via), email.NewVerificationCodeInvalid(s.deps, &email.VerificationCodeInvalidModel{To: to})); err != nil { + } else if err := s.send(ctx, string(via), email.NewVerificationCodeInvalid(s.deps, &email.VerificationCodeInvalidModel{ + To: to, + RequestURL: f.GetRequestURL(), + })); err != nil { return err } return errors.WithStack(ErrUnknownAddress) @@ -333,12 +343,14 @@ func (s *Sender) SendVerificationCodeTo(ctx context.Context, f *verification.Flo VerificationURL: s.constructVerificationLink(ctx, f.ID, codeString), Identity: model, VerificationCode: codeString, + RequestURL: f.GetRequestURL(), }) case identity.ChannelTypeSMS: t = sms.NewVerificationCodeValid(s.deps, &sms.VerificationCodeValidModel{ To: code.VerifiableAddress.Value, VerificationCode: codeString, Identity: model, + RequestURL: f.GetRequestURL(), }) default: return errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Expected email or sms but got %s", code.VerifiableAddress.Via)) diff --git a/selfservice/strategy/link/sender.go b/selfservice/strategy/link/sender.go index d58f167335d7..874f0b92129d 100644 --- a/selfservice/strategy/link/sender.go +++ b/selfservice/strategy/link/sender.go @@ -79,7 +79,10 @@ func (s *Sender) SendRecoveryLink(ctx context.Context, f *recovery.Flow, via ide Info("Account recovery was requested for an unknown address.") if !notifyUnknownRecipients { // do nothing - } else if err := s.send(ctx, string(via), email.NewRecoveryInvalid(s.r, &email.RecoveryInvalidModel{To: to})); err != nil { + } else if err := s.send(ctx, string(via), email.NewRecoveryInvalid(s.r, &email.RecoveryInvalidModel{ + To: to, + RequestURL: f.GetRequestURL(), + })); err != nil { return err } return errors.WithStack(ErrUnknownAddress) @@ -128,7 +131,10 @@ func (s *Sender) SendVerificationLink(ctx context.Context, f *verification.Flow, Info("Address verification was requested for an unknown address.") if !notifyUnknownRecipients { // do nothing - } else if err := s.send(ctx, string(via), email.NewVerificationInvalid(s.r, &email.VerificationInvalidModel{To: to})); err != nil { + } else if err := s.send(ctx, string(via), email.NewVerificationInvalid(s.r, &email.VerificationInvalidModel{ + To: to, + RequestURL: f.GetRequestURL(), + })); err != nil { return err } return errors.WithStack(ErrUnknownAddress) @@ -174,7 +180,10 @@ func (s *Sender) SendRecoveryTokenTo(ctx context.Context, f *recovery.Flow, i *i url.Values{ "token": {token.Token}, "flow": {f.ID.String()}, - }).String(), Identity: model})) + }).String(), + Identity: model, + RequestURL: f.GetRequestURL(), + })) } func (s *Sender) SendVerificationTokenTo(ctx context.Context, f *verification.Flow, i *identity.Identity, address *identity.VerifiableAddress, token *VerificationToken) error { @@ -192,12 +201,17 @@ func (s *Sender) SendVerificationTokenTo(ctx context.Context, f *verification.Fl } if err := s.send(ctx, string(address.Via), email.NewVerificationValid(s.r, - &email.VerificationValidModel{To: address.Value, VerificationURL: urlx.CopyWithQuery( - urlx.AppendPaths(s.r.Config().SelfServiceLinkMethodBaseURL(ctx), verification.RouteSubmitFlow), - url.Values{ - "flow": {f.ID.String()}, - "token": {token.Token}, - }).String(), Identity: model})); err != nil { + &email.VerificationValidModel{ + To: address.Value, + VerificationURL: urlx.CopyWithQuery( + urlx.AppendPaths(s.r.Config().SelfServiceLinkMethodBaseURL(ctx), verification.RouteSubmitFlow), + url.Values{ + "flow": {f.ID.String()}, + "token": {token.Token}, + }).String(), + Identity: model, + RequestURL: f.GetRequestURL(), + })); err != nil { return err } address.Status = identity.VerifiableAddressStatusSent From 0ec3a9afde148528324e53828413e8df209d1687 Mon Sep 17 00:00:00 2001 From: aeneasr <3372410+aeneasr@users.noreply.github.com> Date: Mon, 12 Feb 2024 13:15:24 +0100 Subject: [PATCH 274/282] chore: synchronize workspaces --- internal/client-go/go.sum | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/client-go/go.sum b/internal/client-go/go.sum index c966c8ddfd0d..6cc3f5911d11 100644 --- a/internal/client-go/go.sum +++ b/internal/client-go/go.sum @@ -4,6 +4,7 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= From 6e565d1c0b750c67f29185af85be3ba26a84eabf Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Mon, 12 Feb 2024 12:22:06 +0000 Subject: [PATCH 275/282] autogen(openapi): regenerate swagger spec and internal client [skip ci] --- internal/client-go/go.sum | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/client-go/go.sum b/internal/client-go/go.sum index 6cc3f5911d11..c966c8ddfd0d 100644 --- a/internal/client-go/go.sum +++ b/internal/client-go/go.sum @@ -4,7 +4,6 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= From 9d7021d87f47690c2c1f8000e87b425e49bc9496 Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Mon, 12 Feb 2024 13:26:54 +0100 Subject: [PATCH 276/282] feat: improved webhook tracing (#3746) --- courier/template/load_template.go | 6 +- courier/template/template.go | 8 +- driver/registry_default.go | 12 +- go.mod | 14 +-- go.sum | 28 ++--- persistence/sql/batch/create.go | 5 +- .../sql/identity/persister_identity.go | 106 +++++++++++++----- persistence/sql/persister.go | 5 +- persistence/sql/persister_code.go | 6 +- persistence/sql/persister_continuity.go | 19 ++-- persistence/sql/persister_courier.go | 30 ++--- persistence/sql/persister_login.go | 23 ++-- persistence/sql/persister_login_code.go | 17 +-- persistence/sql/persister_recovery.go | 31 ++--- persistence/sql/persister_recovery_code.go | 13 ++- persistence/sql/persister_registration.go | 19 ++-- .../sql/persister_registration_code.go | 17 +-- persistence/sql/persister_settings.go | 21 ++-- persistence/sql/persister_verification.go | 31 ++--- .../sql/persister_verification_code.go | 13 ++- persistence/sql/update/update.go | 5 +- request/builder.go | 4 +- selfservice/hook/web_hook.go | 14 ++- selfservice/strategy/code/code_sender.go | 4 +- selfservice/strategy/link/sender.go | 6 +- .../strategy/oidc/provider_linkedin_test.go | 15 ++- selfservice/strategy/oidc/strategy_login.go | 3 +- x/http.go | 2 +- 28 files changed, 276 insertions(+), 201 deletions(-) diff --git a/courier/template/load_template.go b/courier/template/load_template.go index 8ecb7ba9fbae..a34427949e95 100644 --- a/courier/template/load_template.go +++ b/courier/template/load_template.go @@ -13,10 +13,8 @@ import ( "path/filepath" "text/template" - "github.com/hashicorp/go-retryablehttp" - + "github.com/ory/kratos/x" "github.com/ory/x/fetcher" - "github.com/ory/x/httpx" "github.com/Masterminds/sprig/v3" lru "github.com/hashicorp/golang-lru" @@ -33,7 +31,7 @@ type Template interface { } type templateDependencies interface { - HTTPClient(ctx context.Context, opts ...httpx.ResilientOptions) *retryablehttp.Client + x.HTTPClientProvider } func loadBuiltInTemplate(filesystem fs.FS, name string, html bool) (Template, error) { diff --git a/courier/template/template.go b/courier/template/template.go index bf7074990253..e1cd68f8c180 100644 --- a/courier/template/template.go +++ b/courier/template/template.go @@ -4,15 +4,11 @@ package template import ( - "context" - - "github.com/hashicorp/go-retryablehttp" - "github.com/ory/kratos/driver/config" - "github.com/ory/x/httpx" + "github.com/ory/kratos/x" ) type Dependencies interface { CourierConfig() config.CourierConfigs - HTTPClient(ctx context.Context, opts ...httpx.ResilientOptions) *retryablehttp.Client + x.HTTPClientProvider } diff --git a/driver/registry_default.go b/driver/registry_default.go index 890fb7d2f5eb..9317846d81f0 100644 --- a/driver/registry_default.go +++ b/driver/registry_default.go @@ -19,6 +19,7 @@ import ( "github.com/hashicorp/go-retryablehttp" "github.com/luna-duclos/instrumentedsql" "github.com/pkg/errors" + "go.opentelemetry.io/otel/trace/noop" "github.com/ory/herodot" "github.com/ory/kratos/cipher" @@ -815,16 +816,13 @@ func (m *RegistryDefault) PrometheusManager() *prometheus.MetricsManager { return m.pmm } -func (m *RegistryDefault) HTTPClient(ctx context.Context, opts ...httpx.ResilientOptions) *retryablehttp.Client { +func (m *RegistryDefault) HTTPClient(_ context.Context, opts ...httpx.ResilientOptions) *retryablehttp.Client { opts = append(opts, httpx.ResilientClientWithLogger(m.Logger()), httpx.ResilientClientWithMaxRetry(2), - httpx.ResilientClientWithConnectionTimeout(30*time.Second)) - - tracer := m.Tracer(ctx) - if tracer.IsLoaded() { - opts = append(opts, httpx.ResilientClientWithTracer(tracer.Tracer())) - } + httpx.ResilientClientWithConnectionTimeout(30*time.Second), + httpx.ResilientClientWithTracer(noop.NewTracerProvider().Tracer("Ory Kratos")), // will use the tracer from a context if available + ) // One of the few exceptions, this usually should not be hot reloaded. if m.Config().ClientHTTPNoPrivateIPRanges(contextx.RootContext) { diff --git a/go.mod b/go.mod index d0399c35b47b..22e8187de37e 100644 --- a/go.mod +++ b/go.mod @@ -74,7 +74,7 @@ require ( github.com/ory/jsonschema/v3 v3.0.8 github.com/ory/mail/v3 v3.0.0 github.com/ory/nosurf v1.2.7 - github.com/ory/x v0.0.613 + github.com/ory/x v0.0.614 github.com/peterhellberg/link v1.2.0 github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 github.com/pkg/errors v0.9.1 @@ -92,10 +92,10 @@ require ( github.com/tidwall/sjson v1.2.5 github.com/urfave/negroni v1.0.0 github.com/zmb3/spotify/v2 v2.4.0 - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 - go.opentelemetry.io/otel v1.21.0 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 + go.opentelemetry.io/otel v1.22.0 go.opentelemetry.io/otel/sdk v1.21.0 - go.opentelemetry.io/otel/trace v1.21.0 + go.opentelemetry.io/otel/trace v1.22.0 golang.org/x/crypto v0.18.0 golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa golang.org/x/net v0.20.0 @@ -145,7 +145,7 @@ require ( github.com/fxamacker/cbor/v2 v2.4.0 // indirect github.com/go-crypt/x v0.2.1 // indirect github.com/go-jose/go-jose/v3 v3.0.1 // indirect - github.com/go-logr/logr v1.3.0 // indirect + github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/analysis v0.21.4 // indirect github.com/go-openapi/errors v0.20.4 // indirect @@ -294,7 +294,7 @@ require ( github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect go.mongodb.org/mongo-driver v1.11.3 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.46.1 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.47.0 // indirect go.opentelemetry.io/contrib/propagators/b3 v1.21.0 // indirect go.opentelemetry.io/contrib/propagators/jaeger v1.21.1 // indirect go.opentelemetry.io/contrib/samplers/jaegerremote v0.15.1 // indirect @@ -302,7 +302,7 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect; / indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 // indirect; / indirect go.opentelemetry.io/otel/exporters/zipkin v1.21.0 // indirect; / indirect - go.opentelemetry.io/otel/metric v1.21.0 // indirect + go.opentelemetry.io/otel/metric v1.22.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect golang.org/x/mod v0.14.0 // indirect golang.org/x/sys v0.16.0 // indirect diff --git a/go.sum b/go.sum index 4bd6bd41d159..d559b4b6ef35 100644 --- a/go.sum +++ b/go.sum @@ -215,8 +215,8 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= -github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= @@ -819,8 +819,8 @@ github.com/ory/nosurf v1.2.7 h1:YrHrbSensQyU6r6HT/V5+HPdVEgrOTMJiLoJABSBOp4= github.com/ory/nosurf v1.2.7/go.mod h1:d4L3ZBa7Amv55bqxCBtCs63wSlyaiCkWVl4vKf3OUxA= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2 h1:zm6sDvHy/U9XrGpixwHiuAwpp0Ock6khSVHkrv6lQQU= github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/ory/x v0.0.613 h1:MHT0scH7hcrOkc3aH7qqYLzXVJkjhB0szWTwpD2lh8Q= -github.com/ory/x v0.0.613/go.mod h1:uH065puz8neija0neqwIN3PmXXfDsB9VbZTZ20Znoos= +github.com/ory/x v0.0.614 h1:amqUBxoY5Z0fN+WqH1sLLtGuJa5GYOBo76LyrwJC0dc= +github.com/ory/x v0.0.614/go.mod h1:uH065puz8neija0neqwIN3PmXXfDsB9VbZTZ20Znoos= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -1039,18 +1039,18 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.46.1 h1:gbhw/u49SS3gkPWiYweQNJGm/uJN5GkI/FrosxSHT7A= -go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.46.1/go.mod h1:GnOaBaFQ2we3b9AGWJpsBa7v1S5RlQzlC3O7dRMxZhM= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.47.0 h1:rw+yB4sMhufNzbVHGG9SDMSrw1CKSnRqfjJnMpAH4dE= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.47.0/go.mod h1:2NonlJyJNVbDK/hCwiLsu5gsD2bVtmIzQ/tGzWq58us= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 h1:sv9kVfal0MK0wBMCOGr+HeJm9v803BkJxGrk2au7j08= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw= go.opentelemetry.io/contrib/propagators/b3 v1.21.0 h1:uGdgDPNzwQWRwCXJgw/7h29JaRqcq9B87Iv4hJDKAZw= go.opentelemetry.io/contrib/propagators/b3 v1.21.0/go.mod h1:D9GQXvVGT2pzyTfp1QBOnD1rzKEWzKjjwu5q2mslCUI= go.opentelemetry.io/contrib/propagators/jaeger v1.21.1 h1:f4beMGDKiVzg9IcX7/VuWVy+oGdjx3dNJ72YehmtY5k= go.opentelemetry.io/contrib/propagators/jaeger v1.21.1/go.mod h1:U9jhkEl8d1LL+QXY7q3kneJWJugiN3kZJV2OWz3hkBY= go.opentelemetry.io/contrib/samplers/jaegerremote v0.15.1 h1:Qb+5A+JbIjXwO7l4HkRUhgIn4Bzz0GNS2q+qdmSx+0c= go.opentelemetry.io/contrib/samplers/jaegerremote v0.15.1/go.mod h1:G4vNCm7fRk0kjZ6pGNLo5SpLxAUvOfSrcaegnT8TPck= -go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= -go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/otel v1.22.0 h1:xS7Ku+7yTFvDfDraDIJVpw7XPyuHlB9MCiqqX5mcJ6Y= +go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI= go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4= go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= @@ -1059,12 +1059,12 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 h1:digkE go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0/go.mod h1:/OpE/y70qVkndM0TrxT4KBoN3RsFZP0QaofcfYrj76I= go.opentelemetry.io/otel/exporters/zipkin v1.21.0 h1:D+Gv6lSfrFBWmQYyxKjDd0Zuld9SRXpIrEsKZvE4DO4= go.opentelemetry.io/otel/exporters/zipkin v1.21.0/go.mod h1:83oMKR6DzmHisFOW3I+yIMGZUTjxiWaiBI8M8+TU5zE= -go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= -go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= +go.opentelemetry.io/otel/metric v1.22.0 h1:lypMQnGyJYeuYPhOM/bgjbFM6WE44W1/T45er4d8Hhg= +go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY= go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= -go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= -go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= +go.opentelemetry.io/otel/trace v1.22.0 h1:Hg6pPujv0XG9QaVbGOBVHunyuLcCC3jN7WEhPx83XD0= +go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= diff --git a/persistence/sql/batch/create.go b/persistence/sql/batch/create.go index 801dcbdd96b5..38254a3b2a80 100644 --- a/persistence/sql/batch/create.go +++ b/persistence/sql/batch/create.go @@ -13,6 +13,8 @@ import ( "time" "github.com/jmoiron/sqlx/reflectx" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" "github.com/ory/x/dbal" @@ -168,7 +170,8 @@ func buildInsertQueryValues[T any](dialect string, mapper *reflectx.Mapper, colu // Create batch-inserts the given models into the database using a single INSERT statement. // The models are either all created or none. func Create[T any](ctx context.Context, p *TracerConnection, models []*T) (err error) { - ctx, span := p.Tracer.Tracer().Start(ctx, "persistence.sql.batch.Create") + ctx, span := p.Tracer.Tracer().Start(ctx, "persistence.sql.batch.Create", + trace.WithAttributes(attribute.Int("count", len(models)))) defer otelx.End(span, &err) if len(models) == 0 { diff --git a/persistence/sql/identity/persister_identity.go b/persistence/sql/identity/persister_identity.go index 00f3a22d38dd..b07275918e17 100644 --- a/persistence/sql/identity/persister_identity.go +++ b/persistence/sql/identity/persister_identity.go @@ -89,7 +89,10 @@ func (p *IdentityPersister) GetConnection(ctx context.Context) *pop.Connection { } func (p *IdentityPersister) ListVerifiableAddresses(ctx context.Context, page, itemsPerPage int) (a []identity.VerifiableAddress, err error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.ListVerifiableAddresses") + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.ListVerifiableAddresses", + trace.WithAttributes( + attribute.Int("per_page", itemsPerPage), + attribute.Stringer("network.id", p.NetworkID(ctx)))) defer otelx.End(span, &err) if err := p.GetConnection(ctx).Where("nid = ?", p.NetworkID(ctx)).Order("id DESC").Paginate(page, x.MaxItemsPerPage(itemsPerPage)).All(&a); err != nil { @@ -100,7 +103,10 @@ func (p *IdentityPersister) ListVerifiableAddresses(ctx context.Context, page, i } func (p *IdentityPersister) ListRecoveryAddresses(ctx context.Context, page, itemsPerPage int) (a []identity.RecoveryAddress, err error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.ListRecoveryAddresses") + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.ListRecoveryAddresses", + trace.WithAttributes( + attribute.Int("per_page", itemsPerPage), + attribute.Stringer("network.id", p.NetworkID(ctx)))) defer otelx.End(span, &err) if err := p.GetConnection(ctx).Where("nid = ?", p.NetworkID(ctx)).Order("id DESC").Paginate(page, x.MaxItemsPerPage(itemsPerPage)).All(&a); err != nil { @@ -136,7 +142,9 @@ func NormalizeIdentifier(ct identity.CredentialsType, match string) string { } func (p *IdentityPersister) FindIdentityByCredentialIdentifier(ctx context.Context, identifier string, caseSensitive bool) (_ *identity.Identity, err error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.FindIdentityByCredentialIdentifier") + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.FindIdentityByCredentialIdentifier", + trace.WithAttributes( + attribute.Stringer("network.id", p.NetworkID(ctx)))) defer otelx.End(span, &err) var find struct { @@ -167,6 +175,7 @@ LIMIT 1`, return nil, sqlcon.HandleError(err) } + span.SetAttributes(attribute.Stringer("identity.id", find.IdentityID)) i, err := p.GetIdentity(ctx, find.IdentityID, identity.ExpandDefault) if err != nil { @@ -178,7 +187,9 @@ LIMIT 1`, } func (p *IdentityPersister) FindByCredentialsIdentifier(ctx context.Context, ct identity.CredentialsType, match string) (_ *identity.Identity, _ *identity.Credentials, err error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.FindByCredentialsIdentifier") + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.FindByCredentialsIdentifier", + trace.WithAttributes( + attribute.Stringer("network.id", p.NetworkID(ctx)))) defer otelx.End(span, &err) nid := p.NetworkID(ctx) @@ -215,6 +226,8 @@ func (p *IdentityPersister) FindByCredentialsIdentifier(ctx context.Context, ct return nil, nil, sqlcon.HandleError(err) } + span.SetAttributes(attribute.String("identity.id", find.IdentityID.String())) + i, err := p.GetIdentityConfidential(ctx, find.IdentityID) if err != nil { return nil, nil, err @@ -259,7 +272,10 @@ func (p *IdentityPersister) findIdentityCredentialsType(ctx context.Context, ct } func (p *IdentityPersister) createIdentityCredentials(ctx context.Context, conn *pop.Connection, identities ...*identity.Identity) (err error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.createIdentityCredentials") + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.createIdentityCredentials", + trace.WithAttributes( + attribute.Int("num_identities", len(identities)), + attribute.Stringer("network.id", p.NetworkID(ctx)))) defer otelx.End(span, &err) var ( @@ -330,7 +346,10 @@ func (p *IdentityPersister) createIdentityCredentials(ctx context.Context, conn } func (p *IdentityPersister) createVerifiableAddresses(ctx context.Context, conn *pop.Connection, identities ...*identity.Identity) (err error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.createVerifiableAddresses") + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.createVerifiableAddresses", + trace.WithAttributes( + attribute.Int("num_identities", len(identities)), + attribute.Stringer("network.id", p.NetworkID(ctx)))) defer otelx.End(span, &err) work := make([]*identity.VerifiableAddress, 0, len(identities)) @@ -347,7 +366,10 @@ func updateAssociation[T interface { Hash() string }](ctx context.Context, p *IdentityPersister, i *identity.Identity, inID []T, ) (err error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.updateAssociation") + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.updateAssociation", + trace.WithAttributes( + attribute.Stringer("identity.id", i.ID), + attribute.Stringer("network.id", p.NetworkID(ctx)))) defer otelx.End(span, &err) var inDB []T @@ -431,7 +453,10 @@ func (p *IdentityPersister) normalizeRecoveryAddresses(ctx context.Context, id * } func (p *IdentityPersister) createRecoveryAddresses(ctx context.Context, conn *pop.Connection, identities ...*identity.Identity) (err error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.createRecoveryAddresses") + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.createRecoveryAddresses", + trace.WithAttributes( + attribute.Int("num_identities", len(identities)), + attribute.Stringer("network.id", p.NetworkID(ctx)))) defer otelx.End(span, &err) // https://go.dev/play/p/b1kU5Bme2Fr @@ -446,25 +471,33 @@ func (p *IdentityPersister) createRecoveryAddresses(ctx context.Context, conn *p } func (p *IdentityPersister) CountIdentities(ctx context.Context) (n int64, err error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CountIdentities") + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CountIdentities", + trace.WithAttributes( + attribute.Stringer("network.id", p.NetworkID(ctx)))) defer otelx.End(span, &err) count, err := p.c.WithContext(ctx).Where("nid = ?", p.NetworkID(ctx)).Count(new(identity.Identity)) if err != nil { return 0, sqlcon.HandleError(err) } + span.SetAttributes(attribute.Int("num_identities", count)) return int64(count), nil } func (p *IdentityPersister) CreateIdentity(ctx context.Context, ident *identity.Identity) (err error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateIdentity") + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateIdentity", + trace.WithAttributes( + attribute.Stringer("network.id", p.NetworkID(ctx)))) defer otelx.End(span, &err) return p.CreateIdentities(ctx, ident) } func (p *IdentityPersister) CreateIdentities(ctx context.Context, identities ...*identity.Identity) (err error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateIdentities") + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateIdentities", + trace.WithAttributes( + attribute.Int("num_identities", len(identities)), + attribute.Stringer("network.id", p.NetworkID(ctx)))) defer otelx.End(span, &err) for _, ident := range identities { @@ -519,7 +552,10 @@ func (p *IdentityPersister) CreateIdentities(ctx context.Context, identities ... } func (p *IdentityPersister) HydrateIdentityAssociations(ctx context.Context, i *identity.Identity, expand identity.Expandables) (err error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.HydrateIdentityAssociations") + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.HydrateIdentityAssociations", + trace.WithAttributes( + attribute.Stringer("identity.id", i.ID), + attribute.Stringer("network.id", p.NetworkID(ctx)))) defer otelx.End(span, &err) var ( @@ -718,7 +754,7 @@ func (p *IdentityPersister) ListIdentities(ctx context.Context, params identity. ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.ListIdentities", trace.WithAttributes(append( paginationAttributes(¶ms, paginator), - attribute.String("network.id", p.NetworkID(ctx).String()))...)) + attribute.Stringer("network.id", p.NetworkID(ctx)))...)) defer otelx.End(span, &err) nid := p.NetworkID(ctx) @@ -878,7 +914,10 @@ func (p *IdentityPersister) ListIdentities(ctx context.Context, params identity. } func (p *IdentityPersister) UpdateIdentity(ctx context.Context, i *identity.Identity) (err error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.UpdateIdentity") + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.UpdateIdentity", + trace.WithAttributes( + attribute.Stringer("identity.id", i.ID), + attribute.Stringer("network.id", p.NetworkID(ctx)))) defer otelx.End(span, &err) if err := p.validateIdentity(ctx, i); err != nil { @@ -915,7 +954,10 @@ func (p *IdentityPersister) UpdateIdentity(ctx context.Context, i *identity.Iden } func (p *IdentityPersister) DeleteIdentity(ctx context.Context, id uuid.UUID) (err error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteIdentity") + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteIdentity", + trace.WithAttributes( + attribute.Stringer("identity.id", id), + attribute.Stringer("network.id", p.NetworkID(ctx)))) defer otelx.End(span, &err) nid := p.NetworkID(ctx) @@ -933,15 +975,13 @@ func (p *IdentityPersister) DeleteIdentity(ctx context.Context, id uuid.UUID) (e } func (p *IdentityPersister) GetIdentity(ctx context.Context, id uuid.UUID, expand identity.Expandables) (_ *identity.Identity, err error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetIdentity") + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetIdentity", + trace.WithAttributes( + attribute.Stringer("identity.id", id), + attribute.Stringer("network.id", p.NetworkID(ctx)), + attribute.StringSlice("expand", expand.ToEager()))) defer otelx.End(span, &err) - span.SetAttributes( - attribute.String("identity.id", id.String()), - attribute.StringSlice("expand", expand.ToEager()), - attribute.String("network.id", p.NetworkID(ctx).String()), - ) - var i identity.Identity if err := p.GetConnection(ctx).Where("id = ? AND nid = ?", id, p.NetworkID(ctx)).First(&i); err != nil { return nil, sqlcon.HandleError(err) @@ -962,7 +1002,9 @@ func (p *IdentityPersister) GetIdentityConfidential(ctx context.Context, id uuid } func (p *IdentityPersister) FindVerifiableAddressByValue(ctx context.Context, via string, value string) (_ *identity.VerifiableAddress, err error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.FindVerifiableAddressByValue") + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.FindVerifiableAddressByValue", + trace.WithAttributes( + attribute.Stringer("network.id", p.NetworkID(ctx)))) otelx.End(span, &err) var address identity.VerifiableAddress @@ -974,7 +1016,9 @@ func (p *IdentityPersister) FindVerifiableAddressByValue(ctx context.Context, vi } func (p *IdentityPersister) FindRecoveryAddressByValue(ctx context.Context, via identity.RecoveryAddressType, value string) (_ *identity.RecoveryAddress, err error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.FindRecoveryAddressByValue") + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.FindRecoveryAddressByValue", + trace.WithAttributes( + attribute.Stringer("network.id", p.NetworkID(ctx)))) defer otelx.End(span, &err) var address identity.RecoveryAddress @@ -986,7 +1030,9 @@ func (p *IdentityPersister) FindRecoveryAddressByValue(ctx context.Context, via } func (p *IdentityPersister) VerifyAddress(ctx context.Context, code string) (err error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.VerifyAddress") + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.VerifyAddress", + trace.WithAttributes( + attribute.Stringer("network.id", p.NetworkID(ctx)))) defer otelx.End(span, &err) newCode, err := otp.New() @@ -1019,7 +1065,10 @@ func (p *IdentityPersister) VerifyAddress(ctx context.Context, code string) (err } func (p *IdentityPersister) UpdateVerifiableAddress(ctx context.Context, address *identity.VerifiableAddress) (err error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.UpdateVerifiableAddress") + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.UpdateVerifiableAddress", + trace.WithAttributes( + attribute.Stringer("identity.id", address.IdentityID), + attribute.Stringer("network.id", p.NetworkID(ctx)))) defer otelx.End(span, &err) address.NID = p.NetworkID(ctx) @@ -1028,7 +1077,10 @@ func (p *IdentityPersister) UpdateVerifiableAddress(ctx context.Context, address } func (p *IdentityPersister) validateIdentity(ctx context.Context, i *identity.Identity) (err error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.validateIdentity") + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.validateIdentity", + trace.WithAttributes( + attribute.Stringer("identity.id", i.ID), + attribute.Stringer("network.id", p.NetworkID(ctx)))) defer otelx.End(span, &err) if err := p.r.IdentityValidator().ValidateWithRunner(ctx, i); err != nil { diff --git a/persistence/sql/persister.go b/persistence/sql/persister.go index fa553cd559f5..99990b7ace91 100644 --- a/persistence/sql/persister.go +++ b/persistence/sql/persister.go @@ -25,6 +25,7 @@ import ( "github.com/ory/kratos/x" "github.com/ory/x/contextx" "github.com/ory/x/networkx" + "github.com/ory/x/otelx" "github.com/ory/x/popx" ) @@ -136,9 +137,9 @@ func (p *Persister) Connection(ctx context.Context) *pop.Connection { return p.c.WithContext(ctx) } -func (p *Persister) MigrationStatus(ctx context.Context) (popx.MigrationStatuses, error) { +func (p *Persister) MigrationStatus(ctx context.Context) (_ popx.MigrationStatuses, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.MigrationStatus") - defer span.End() + defer otelx.End(span, &err) if p.mbs != nil { return p.mbs, nil diff --git a/persistence/sql/persister_code.go b/persistence/sql/persister_code.go index 3b8103a36361..31e0b80dc2d2 100644 --- a/persistence/sql/persister_code.go +++ b/persistence/sql/persister_code.go @@ -14,6 +14,7 @@ import ( "github.com/pkg/errors" "github.com/ory/kratos/selfservice/strategy/code" + "github.com/ory/x/otelx" "github.com/ory/x/sqlcon" ) @@ -39,9 +40,10 @@ func withCheckIdentityID(id uuid.UUID) codeOption { func useOneTimeCode[P any, U interface { *P oneTimeCodeProvider -}](ctx context.Context, p *Persister, flowID uuid.UUID, userProvidedCode string, flowTableName string, foreignKeyName string, opts ...codeOption) (U, error) { +}](ctx context.Context, p *Persister, flowID uuid.UUID, userProvidedCode string, flowTableName string, foreignKeyName string, opts ...codeOption, +) (_ U, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.useOneTimeCode") - defer span.End() + defer otelx.End(span, &err) o := new(codeOptions) for _, opt := range opts { diff --git a/persistence/sql/persister_continuity.go b/persistence/sql/persister_continuity.go index a8759f56d8bd..73078784766c 100644 --- a/persistence/sql/persister_continuity.go +++ b/persistence/sql/persister_continuity.go @@ -12,6 +12,7 @@ import ( "github.com/gofrs/uuid" + "github.com/ory/x/otelx" "github.com/ory/x/sqlcon" "github.com/ory/kratos/continuity" @@ -19,17 +20,17 @@ import ( var _ continuity.Persister = new(Persister) -func (p *Persister) SaveContinuitySession(ctx context.Context, c *continuity.Container) error { +func (p *Persister) SaveContinuitySession(ctx context.Context, c *continuity.Container) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.SaveContinuitySession") - defer span.End() + defer otelx.End(span, &err) c.NID = p.NetworkID(ctx) return sqlcon.HandleError(p.GetConnection(ctx).Create(c)) } -func (p *Persister) GetContinuitySession(ctx context.Context, id uuid.UUID) (*continuity.Container, error) { +func (p *Persister) GetContinuitySession(ctx context.Context, id uuid.UUID) (_ *continuity.Container, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetContinuitySession") - defer span.End() + defer otelx.End(span, &err) var c continuity.Container if err := p.GetConnection(ctx).Where("id = ? AND nid = ?", id, p.NetworkID(ctx)).First(&c); err != nil { @@ -38,9 +39,9 @@ func (p *Persister) GetContinuitySession(ctx context.Context, id uuid.UUID) (*co return &c, nil } -func (p *Persister) DeleteContinuitySession(ctx context.Context, id uuid.UUID) error { +func (p *Persister) DeleteContinuitySession(ctx context.Context, id uuid.UUID) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteContinuitySession") - defer span.End() + defer otelx.End(span, &err) if count, err := p.GetConnection(ctx).RawQuery( //#nosec G201 -- TableName is static @@ -53,9 +54,11 @@ func (p *Persister) DeleteContinuitySession(ctx context.Context, id uuid.UUID) e return nil } -func (p *Persister) DeleteExpiredContinuitySessions(ctx context.Context, expiresAt time.Time, limit int) error { +func (p *Persister) DeleteExpiredContinuitySessions(ctx context.Context, expiresAt time.Time, limit int) (err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteExpiredContinuitySessions") + defer otelx.End(span, &err) //#nosec G201 -- TableName is static - err := p.GetConnection(ctx).RawQuery(fmt.Sprintf( + err = p.GetConnection(ctx).RawQuery(fmt.Sprintf( "DELETE FROM %s WHERE id in (SELECT id FROM (SELECT id FROM %s c WHERE expires_at <= ? and nid = ? ORDER BY expires_at ASC LIMIT %d ) AS s )", new(continuity.Container).TableName(ctx), new(continuity.Container).TableName(ctx), diff --git a/persistence/sql/persister_courier.go b/persistence/sql/persister_courier.go index 437d9132e1d0..456efea4fe70 100644 --- a/persistence/sql/persister_courier.go +++ b/persistence/sql/persister_courier.go @@ -13,6 +13,7 @@ import ( "github.com/pkg/errors" "github.com/ory/herodot" + "github.com/ory/x/otelx" "github.com/ory/x/pagination/keysetpagination" "github.com/ory/x/sqlcon" "github.com/ory/x/uuidx" @@ -23,18 +24,18 @@ import ( var _ courier.Persister = new(Persister) -func (p *Persister) AddMessage(ctx context.Context, m *courier.Message) error { +func (p *Persister) AddMessage(ctx context.Context, m *courier.Message) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.AddMessage") - defer span.End() + defer otelx.End(span, &err) m.NID = p.NetworkID(ctx) m.Status = courier.MessageStatusQueued return sqlcon.HandleError(p.GetConnection(ctx).Create(m)) // do not create eager to avoid identity injection. } -func (p *Persister) ListMessages(ctx context.Context, filter courier.ListCourierMessagesParameters, opts []keysetpagination.Option) ([]courier.Message, int64, *keysetpagination.Paginator, error) { +func (p *Persister) ListMessages(ctx context.Context, filter courier.ListCourierMessagesParameters, opts []keysetpagination.Option) (_ []courier.Message, _ int64, _ *keysetpagination.Paginator, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.ListMessages") - defer span.End() + defer otelx.End(span, &err) q := p.GetConnection(ctx).Where("nid=?", p.NetworkID(ctx)) @@ -68,7 +69,7 @@ func (p *Persister) ListMessages(ctx context.Context, filter courier.ListCourier func (p *Persister) NextMessages(ctx context.Context, limit uint8) (messages []courier.Message, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.NextMessages") - defer span.End() + defer otelx.End(span, &err) if err := p.Transaction(ctx, func(ctx context.Context, tx *pop.Connection) error { var m []courier.Message @@ -111,9 +112,9 @@ func (p *Persister) NextMessages(ctx context.Context, limit uint8) (messages []c return messages, nil } -func (p *Persister) LatestQueuedMessage(ctx context.Context) (*courier.Message, error) { +func (p *Persister) LatestQueuedMessage(ctx context.Context) (_ *courier.Message, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.LatestQueuedMessage") - defer span.End() + defer otelx.End(span, &err) var m courier.Message if err := p.GetConnection(ctx). @@ -132,9 +133,9 @@ func (p *Persister) LatestQueuedMessage(ctx context.Context) (*courier.Message, return &m, nil } -func (p *Persister) SetMessageStatus(ctx context.Context, id uuid.UUID, ms courier.MessageStatus) error { +func (p *Persister) SetMessageStatus(ctx context.Context, id uuid.UUID, ms courier.MessageStatus) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.SetMessageStatus") - defer span.End() + defer otelx.End(span, &err) count, err := p.GetConnection(ctx).RawQuery( "UPDATE courier_messages SET status = ? WHERE id = ? AND nid = ?", @@ -153,16 +154,15 @@ func (p *Persister) SetMessageStatus(ctx context.Context, id uuid.UUID, ms couri return nil } -func (p *Persister) IncrementMessageSendCount(ctx context.Context, id uuid.UUID) error { +func (p *Persister) IncrementMessageSendCount(ctx context.Context, id uuid.UUID) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.SetMessageStatus") - defer span.End() + defer otelx.End(span, &err) count, err := p.GetConnection(ctx).RawQuery( "UPDATE courier_messages SET send_count = send_count + 1 WHERE id = ? AND nid = ?", id, p.NetworkID(ctx), ).ExecWithCount() - if err != nil { return sqlcon.HandleError(err) } @@ -174,9 +174,9 @@ func (p *Persister) IncrementMessageSendCount(ctx context.Context, id uuid.UUID) return nil } -func (p *Persister) FetchMessage(ctx context.Context, msgID uuid.UUID) (*courier.Message, error) { +func (p *Persister) FetchMessage(ctx context.Context, msgID uuid.UUID) (_ *courier.Message, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.FetchMessage") - defer span.End() + defer otelx.End(span, &err) var message courier.Message if err := p.GetConnection(ctx). @@ -191,7 +191,7 @@ func (p *Persister) FetchMessage(ctx context.Context, msgID uuid.UUID) (*courier func (p *Persister) RecordDispatch(ctx context.Context, msgID uuid.UUID, status courier.CourierMessageDispatchStatus, err error) error { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.RecordDispatch") - defer span.End() + defer otelx.End(span, &err) dispatch := courier.MessageDispatch{ ID: uuidx.NewV4(), diff --git a/persistence/sql/persister_login.go b/persistence/sql/persister_login.go index ec1da55babbb..ec3bf522ef7d 100644 --- a/persistence/sql/persister_login.go +++ b/persistence/sql/persister_login.go @@ -11,6 +11,7 @@ import ( "github.com/gobuffalo/pop/v6" "github.com/gofrs/uuid" + "github.com/ory/x/otelx" "github.com/ory/x/sqlcon" "github.com/ory/kratos/persistence/sql/update" @@ -19,18 +20,18 @@ import ( var _ login.FlowPersister = new(Persister) -func (p *Persister) CreateLoginFlow(ctx context.Context, r *login.Flow) error { +func (p *Persister) CreateLoginFlow(ctx context.Context, r *login.Flow) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateLoginFlow") - defer span.End() + defer otelx.End(span, &err) r.NID = p.NetworkID(ctx) r.EnsureInternalContext() return p.GetConnection(ctx).Create(r) } -func (p *Persister) UpdateLoginFlow(ctx context.Context, r *login.Flow) error { +func (p *Persister) UpdateLoginFlow(ctx context.Context, r *login.Flow) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.UpdateLoginFlow") - defer span.End() + defer otelx.End(span, &err) r.EnsureInternalContext() cp := *r @@ -38,9 +39,9 @@ func (p *Persister) UpdateLoginFlow(ctx context.Context, r *login.Flow) error { return update.Generic(ctx, p.GetConnection(ctx), p.r.Tracer(ctx).Tracer(), cp) } -func (p *Persister) GetLoginFlow(ctx context.Context, id uuid.UUID) (*login.Flow, error) { +func (p *Persister) GetLoginFlow(ctx context.Context, id uuid.UUID) (_ *login.Flow, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetLoginFlow") - defer span.End() + defer otelx.End(span, &err) conn := p.GetConnection(ctx) @@ -52,9 +53,9 @@ func (p *Persister) GetLoginFlow(ctx context.Context, id uuid.UUID) (*login.Flow return &r, nil } -func (p *Persister) ForceLoginFlow(ctx context.Context, id uuid.UUID) error { +func (p *Persister) ForceLoginFlow(ctx context.Context, id uuid.UUID) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.ForceLoginFlow") - defer span.End() + defer otelx.End(span, &err) return p.Transaction(ctx, func(ctx context.Context, tx *pop.Connection) error { lr, err := p.GetLoginFlow(ctx, id) @@ -67,9 +68,11 @@ func (p *Persister) ForceLoginFlow(ctx context.Context, id uuid.UUID) error { }) } -func (p *Persister) DeleteExpiredLoginFlows(ctx context.Context, expiresAt time.Time, limit int) error { +func (p *Persister) DeleteExpiredLoginFlows(ctx context.Context, expiresAt time.Time, limit int) (err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteExpiredLoginFlows") + defer otelx.End(span, &err) //#nosec G201 -- TableName is static - err := p.GetConnection(ctx).RawQuery(fmt.Sprintf( + err = p.GetConnection(ctx).RawQuery(fmt.Sprintf( "DELETE FROM %s WHERE id in (SELECT id FROM (SELECT id FROM %s c WHERE expires_at <= ? and nid = ? ORDER BY expires_at ASC LIMIT %d ) AS s )", new(login.Flow).TableName(ctx), new(login.Flow).TableName(ctx), diff --git a/persistence/sql/persister_login_code.go b/persistence/sql/persister_login_code.go index 3d5dd027826d..808e65b9d2a4 100644 --- a/persistence/sql/persister_login_code.go +++ b/persistence/sql/persister_login_code.go @@ -11,12 +11,13 @@ import ( "github.com/ory/kratos/selfservice/flow/login" "github.com/ory/kratos/selfservice/strategy/code" + "github.com/ory/x/otelx" "github.com/ory/x/sqlcon" ) -func (p *Persister) CreateLoginCode(ctx context.Context, params *code.CreateLoginCodeParams) (*code.LoginCode, error) { +func (p *Persister) CreateLoginCode(ctx context.Context, params *code.CreateLoginCodeParams) (_ *code.LoginCode, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateLoginCode") - defer span.End() + defer otelx.End(span, &err) now := time.Now().UTC() loginCode := &code.LoginCode{ @@ -38,9 +39,9 @@ func (p *Persister) CreateLoginCode(ctx context.Context, params *code.CreateLogi return loginCode, nil } -func (p *Persister) UseLoginCode(ctx context.Context, flowID uuid.UUID, identityID uuid.UUID, userProvidedCode string) (*code.LoginCode, error) { +func (p *Persister) UseLoginCode(ctx context.Context, flowID uuid.UUID, identityID uuid.UUID, userProvidedCode string) (_ *code.LoginCode, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.UseLoginCode") - defer span.End() + defer otelx.End(span, &err) codeRow, err := useOneTimeCode[code.LoginCode, *code.LoginCode](ctx, p, flowID, userProvidedCode, new(login.Flow).TableName(ctx), "selfservice_login_flow_id", withCheckIdentityID(identityID)) if err != nil { @@ -50,9 +51,9 @@ func (p *Persister) UseLoginCode(ctx context.Context, flowID uuid.UUID, identity return codeRow, nil } -func (p *Persister) GetUsedLoginCode(ctx context.Context, flowID uuid.UUID) (*code.LoginCode, error) { +func (p *Persister) GetUsedLoginCode(ctx context.Context, flowID uuid.UUID) (_ *code.LoginCode, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetUsedLoginCode") - defer span.End() + defer otelx.End(span, &err) var loginCode code.LoginCode if err := p.Connection(ctx).Where("selfservice_login_flow_id = ? AND nid = ? AND used_at IS NOT NULL", flowID, p.NetworkID(ctx)).First(&loginCode); err != nil { @@ -61,9 +62,9 @@ func (p *Persister) GetUsedLoginCode(ctx context.Context, flowID uuid.UUID) (*co return &loginCode, nil } -func (p *Persister) DeleteLoginCodesOfFlow(ctx context.Context, flowID uuid.UUID) error { +func (p *Persister) DeleteLoginCodesOfFlow(ctx context.Context, flowID uuid.UUID) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteLoginCodesOfFlow") - defer span.End() + defer otelx.End(span, &err) return p.GetConnection(ctx).Where("selfservice_login_flow_id = ? AND nid = ?", flowID, p.NetworkID(ctx)).Delete(&code.LoginCode{}) } diff --git a/persistence/sql/persister_recovery.go b/persistence/sql/persister_recovery.go index 8ac81cd009a5..468ba5a2b144 100644 --- a/persistence/sql/persister_recovery.go +++ b/persistence/sql/persister_recovery.go @@ -17,6 +17,7 @@ import ( "github.com/ory/kratos/persistence/sql/update" "github.com/ory/kratos/selfservice/flow/recovery" "github.com/ory/kratos/selfservice/strategy/link" + "github.com/ory/x/otelx" "github.com/ory/x/sqlcon" ) @@ -25,17 +26,17 @@ var ( _ link.RecoveryTokenPersister = new(Persister) ) -func (p *Persister) CreateRecoveryFlow(ctx context.Context, r *recovery.Flow) error { +func (p *Persister) CreateRecoveryFlow(ctx context.Context, r *recovery.Flow) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateRecoveryFlow") - defer span.End() + defer otelx.End(span, &err) r.NID = p.NetworkID(ctx) return p.GetConnection(ctx).Create(r) } -func (p *Persister) GetRecoveryFlow(ctx context.Context, id uuid.UUID) (*recovery.Flow, error) { +func (p *Persister) GetRecoveryFlow(ctx context.Context, id uuid.UUID) (_ *recovery.Flow, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetRecoveryFlow") - defer span.End() + defer otelx.End(span, &err) var r recovery.Flow if err := p.GetConnection(ctx).Where("id = ? AND nid = ?", id, p.NetworkID(ctx)).First(&r); err != nil { @@ -45,18 +46,18 @@ func (p *Persister) GetRecoveryFlow(ctx context.Context, id uuid.UUID) (*recover return &r, nil } -func (p *Persister) UpdateRecoveryFlow(ctx context.Context, r *recovery.Flow) error { +func (p *Persister) UpdateRecoveryFlow(ctx context.Context, r *recovery.Flow) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.UpdateRecoveryFlow") - defer span.End() + defer otelx.End(span, &err) cp := *r cp.NID = p.NetworkID(ctx) return update.Generic(ctx, p.GetConnection(ctx), p.r.Tracer(ctx).Tracer(), cp) } -func (p *Persister) CreateRecoveryToken(ctx context.Context, token *link.RecoveryToken) error { +func (p *Persister) CreateRecoveryToken(ctx context.Context, token *link.RecoveryToken) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateRecoveryToken") - defer span.End() + defer otelx.End(span, &err) t := token.Token token.Token = p.hmacValue(ctx, t) @@ -72,9 +73,9 @@ func (p *Persister) CreateRecoveryToken(ctx context.Context, token *link.Recover return nil } -func (p *Persister) UseRecoveryToken(ctx context.Context, fID uuid.UUID, token string) (*link.RecoveryToken, error) { +func (p *Persister) UseRecoveryToken(ctx context.Context, fID uuid.UUID, token string) (_ *link.RecoveryToken, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.UseRecoveryToken") - defer span.End() + defer otelx.End(span, &err) var rt link.RecoveryToken @@ -110,17 +111,19 @@ func (p *Persister) UseRecoveryToken(ctx context.Context, fID uuid.UUID, token s return &rt, nil } -func (p *Persister) DeleteRecoveryToken(ctx context.Context, token string) error { +func (p *Persister) DeleteRecoveryToken(ctx context.Context, token string) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteRecoveryToken") - defer span.End() + defer otelx.End(span, &err) //#nosec G201 -- TableName is static return p.GetConnection(ctx).RawQuery(fmt.Sprintf("DELETE FROM %s WHERE token=? AND nid = ?", new(link.RecoveryToken).TableName(ctx)), token, p.NetworkID(ctx)).Exec() } -func (p *Persister) DeleteExpiredRecoveryFlows(ctx context.Context, expiresAt time.Time, limit int) error { +func (p *Persister) DeleteExpiredRecoveryFlows(ctx context.Context, expiresAt time.Time, limit int) (err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteExpiredRecoveryFlows") + defer otelx.End(span, &err) //#nosec G201 -- TableName is static - err := p.GetConnection(ctx).RawQuery(fmt.Sprintf( + err = p.GetConnection(ctx).RawQuery(fmt.Sprintf( "DELETE FROM %s WHERE id in (SELECT id FROM (SELECT id FROM %s c WHERE expires_at <= ? and nid = ? ORDER BY expires_at ASC LIMIT %d ) AS s )", new(recovery.Flow).TableName(ctx), new(recovery.Flow).TableName(ctx), diff --git a/persistence/sql/persister_recovery_code.go b/persistence/sql/persister_recovery_code.go index 725b9578a205..9dc4dd26bb83 100644 --- a/persistence/sql/persister_recovery_code.go +++ b/persistence/sql/persister_recovery_code.go @@ -13,12 +13,13 @@ import ( "github.com/ory/kratos/identity" "github.com/ory/kratos/selfservice/flow/recovery" "github.com/ory/kratos/selfservice/strategy/code" + "github.com/ory/x/otelx" "github.com/ory/x/sqlcon" ) -func (p *Persister) CreateRecoveryCode(ctx context.Context, params *code.CreateRecoveryCodeParams) (*code.RecoveryCode, error) { +func (p *Persister) CreateRecoveryCode(ctx context.Context, params *code.CreateRecoveryCodeParams) (_ *code.RecoveryCode, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateRecoveryCode") - defer span.End() + defer otelx.End(span, &err) now := time.Now() recoveryCode := &code.RecoveryCode{ @@ -53,9 +54,9 @@ func (p *Persister) CreateRecoveryCode(ctx context.Context, params *code.CreateR // // If the supplied code matched a code from the flow, no error is returned // If an invalid code was submitted with this flow more than 5 times, an error is returned -func (p *Persister) UseRecoveryCode(ctx context.Context, flowID uuid.UUID, userProvidedCode string) (*code.RecoveryCode, error) { +func (p *Persister) UseRecoveryCode(ctx context.Context, flowID uuid.UUID, userProvidedCode string) (_ *code.RecoveryCode, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.UseRecoveryCode") - defer span.End() + defer otelx.End(span, &err) codeRow, err := useOneTimeCode[code.RecoveryCode, *code.RecoveryCode](ctx, p, flowID, userProvidedCode, new(recovery.Flow).TableName(ctx), "selfservice_recovery_flow_id") if err != nil { @@ -76,9 +77,9 @@ func (p *Persister) UseRecoveryCode(ctx context.Context, flowID uuid.UUID, userP return codeRow, nil } -func (p *Persister) DeleteRecoveryCodesOfFlow(ctx context.Context, flowID uuid.UUID) error { +func (p *Persister) DeleteRecoveryCodesOfFlow(ctx context.Context, flowID uuid.UUID) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteRecoveryCodesOfFlow") - defer span.End() + defer otelx.End(span, &err) return p.GetConnection(ctx).Where("selfservice_recovery_flow_id = ? AND nid = ?", flowID, p.NetworkID(ctx)).Delete(&code.RecoveryCode{}) } diff --git a/persistence/sql/persister_registration.go b/persistence/sql/persister_registration.go index fe7e25ceeac3..00eb08780ced 100644 --- a/persistence/sql/persister_registration.go +++ b/persistence/sql/persister_registration.go @@ -10,24 +10,25 @@ import ( "github.com/gofrs/uuid" + "github.com/ory/x/otelx" "github.com/ory/x/sqlcon" "github.com/ory/kratos/persistence/sql/update" "github.com/ory/kratos/selfservice/flow/registration" ) -func (p *Persister) CreateRegistrationFlow(ctx context.Context, r *registration.Flow) error { +func (p *Persister) CreateRegistrationFlow(ctx context.Context, r *registration.Flow) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateRegistrationFlow") - defer span.End() + defer otelx.End(span, &err) r.NID = p.NetworkID(ctx) r.EnsureInternalContext() return p.GetConnection(ctx).Create(r) } -func (p *Persister) UpdateRegistrationFlow(ctx context.Context, r *registration.Flow) error { +func (p *Persister) UpdateRegistrationFlow(ctx context.Context, r *registration.Flow) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.UpdateRegistrationFlow") - defer span.End() + defer otelx.End(span, &err) r.EnsureInternalContext() cp := *r @@ -35,9 +36,9 @@ func (p *Persister) UpdateRegistrationFlow(ctx context.Context, r *registration. return update.Generic(ctx, p.GetConnection(ctx), p.r.Tracer(ctx).Tracer(), cp) } -func (p *Persister) GetRegistrationFlow(ctx context.Context, id uuid.UUID) (*registration.Flow, error) { +func (p *Persister) GetRegistrationFlow(ctx context.Context, id uuid.UUID) (_ *registration.Flow, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetRegistrationFlow") - defer span.End() + defer otelx.End(span, &err) var r registration.Flow if err := p.GetConnection(ctx).Where("id = ? AND nid = ?", @@ -48,9 +49,11 @@ func (p *Persister) GetRegistrationFlow(ctx context.Context, id uuid.UUID) (*reg return &r, nil } -func (p *Persister) DeleteExpiredRegistrationFlows(ctx context.Context, expiresAt time.Time, limit int) error { +func (p *Persister) DeleteExpiredRegistrationFlows(ctx context.Context, expiresAt time.Time, limit int) (err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteExpiredRegistrationFlows") + defer otelx.End(span, &err) //#nosec G201 -- TableName is static - err := p.GetConnection(ctx).RawQuery(fmt.Sprintf( + err = p.GetConnection(ctx).RawQuery(fmt.Sprintf( "DELETE FROM %s WHERE id in (SELECT id FROM (SELECT id FROM %s c WHERE expires_at <= ? and nid = ? ORDER BY expires_at ASC LIMIT %d ) AS s )", new(registration.Flow).TableName(ctx), new(registration.Flow).TableName(ctx), diff --git a/persistence/sql/persister_registration_code.go b/persistence/sql/persister_registration_code.go index 29d1af549467..095cb45156ba 100644 --- a/persistence/sql/persister_registration_code.go +++ b/persistence/sql/persister_registration_code.go @@ -13,12 +13,13 @@ import ( "github.com/ory/kratos/selfservice/flow/registration" "github.com/ory/kratos/selfservice/strategy/code" + "github.com/ory/x/otelx" "github.com/ory/x/sqlcon" ) -func (p *Persister) CreateRegistrationCode(ctx context.Context, params *code.CreateRegistrationCodeParams) (*code.RegistrationCode, error) { +func (p *Persister) CreateRegistrationCode(ctx context.Context, params *code.CreateRegistrationCodeParams) (_ *code.RegistrationCode, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateRegistrationCode") - defer span.End() + defer otelx.End(span, &err) now := time.Now().UTC() registrationCode := &code.RegistrationCode{ @@ -39,9 +40,9 @@ func (p *Persister) CreateRegistrationCode(ctx context.Context, params *code.Cre return registrationCode, nil } -func (p *Persister) UseRegistrationCode(ctx context.Context, flowID uuid.UUID, userProvidedCode string, addresses ...string) (*code.RegistrationCode, error) { +func (p *Persister) UseRegistrationCode(ctx context.Context, flowID uuid.UUID, userProvidedCode string, addresses ...string) (_ *code.RegistrationCode, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.UseRegistrationCode") - defer span.End() + defer otelx.End(span, &err) codeRow, err := useOneTimeCode[code.RegistrationCode, *code.RegistrationCode](ctx, p, flowID, userProvidedCode, new(registration.Flow).TableName(ctx), "selfservice_registration_flow_id") if err != nil { @@ -56,9 +57,9 @@ func (p *Persister) UseRegistrationCode(ctx context.Context, flowID uuid.UUID, u return codeRow, nil } -func (p *Persister) GetUsedRegistrationCode(ctx context.Context, flowID uuid.UUID) (*code.RegistrationCode, error) { +func (p *Persister) GetUsedRegistrationCode(ctx context.Context, flowID uuid.UUID) (_ *code.RegistrationCode, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetUsedRegistrationCode") - defer span.End() + defer otelx.End(span, &err) var registrationCode code.RegistrationCode if err := p.Connection(ctx).Where("selfservice_registration_flow_id = ? AND used_at IS NOT NULL AND nid = ?", flowID, p.NetworkID(ctx)).First(®istrationCode); err != nil { @@ -68,9 +69,9 @@ func (p *Persister) GetUsedRegistrationCode(ctx context.Context, flowID uuid.UUI return ®istrationCode, nil } -func (p *Persister) DeleteRegistrationCodesOfFlow(ctx context.Context, flowID uuid.UUID) error { +func (p *Persister) DeleteRegistrationCodesOfFlow(ctx context.Context, flowID uuid.UUID) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteRegistrationCodesOfFlow") - defer span.End() + defer otelx.End(span, &err) return p.GetConnection(ctx).Where("selfservice_registration_flow_id = ? AND nid = ?", flowID, p.NetworkID(ctx)).Delete(&code.RegistrationCode{}) } diff --git a/persistence/sql/persister_settings.go b/persistence/sql/persister_settings.go index 51be36725cbf..8800d55a26d2 100644 --- a/persistence/sql/persister_settings.go +++ b/persistence/sql/persister_settings.go @@ -13,6 +13,7 @@ import ( "github.com/gofrs/uuid" + "github.com/ory/x/otelx" "github.com/ory/x/sqlcon" "github.com/ory/kratos/selfservice/flow/settings" @@ -20,22 +21,22 @@ import ( var _ settings.FlowPersister = new(Persister) -func (p *Persister) CreateSettingsFlow(ctx context.Context, r *settings.Flow) error { +func (p *Persister) CreateSettingsFlow(ctx context.Context, r *settings.Flow) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateSettingsFlow") - defer span.End() + defer otelx.End(span, &err) r.NID = p.NetworkID(ctx) r.EnsureInternalContext() return sqlcon.HandleError(p.GetConnection(ctx).Create(r)) } -func (p *Persister) GetSettingsFlow(ctx context.Context, id uuid.UUID) (*settings.Flow, error) { +func (p *Persister) GetSettingsFlow(ctx context.Context, id uuid.UUID) (_ *settings.Flow, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetSettingsFlow") - defer span.End() + defer otelx.End(span, &err) var r settings.Flow - err := p.GetConnection(ctx).Where("id = ? AND nid = ?", id, p.NetworkID(ctx)).First(&r) + err = p.GetConnection(ctx).Where("id = ? AND nid = ?", id, p.NetworkID(ctx)).First(&r) if err != nil { return nil, sqlcon.HandleError(err) } @@ -48,9 +49,9 @@ func (p *Persister) GetSettingsFlow(ctx context.Context, id uuid.UUID) (*setting return &r, nil } -func (p *Persister) UpdateSettingsFlow(ctx context.Context, r *settings.Flow) error { +func (p *Persister) UpdateSettingsFlow(ctx context.Context, r *settings.Flow) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.UpdateSettingsFlow") - defer span.End() + defer otelx.End(span, &err) r.EnsureInternalContext() cp := *r @@ -58,9 +59,11 @@ func (p *Persister) UpdateSettingsFlow(ctx context.Context, r *settings.Flow) er return update.Generic(ctx, p.GetConnection(ctx), p.r.Tracer(ctx).Tracer(), cp) } -func (p *Persister) DeleteExpiredSettingsFlows(ctx context.Context, expiresAt time.Time, limit int) error { +func (p *Persister) DeleteExpiredSettingsFlows(ctx context.Context, expiresAt time.Time, limit int) (err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteExpiredSettingsFlows") + defer otelx.End(span, &err) //#nosec G201 -- TableName is static - err := p.GetConnection(ctx).RawQuery(fmt.Sprintf( + err = p.GetConnection(ctx).RawQuery(fmt.Sprintf( "DELETE FROM %s WHERE id in (SELECT id FROM (SELECT id FROM %s c WHERE expires_at <= ? and nid = ? ORDER BY expires_at ASC LIMIT %d ) AS s )", new(settings.Flow).TableName(ctx), new(settings.Flow).TableName(ctx), diff --git a/persistence/sql/persister_verification.go b/persistence/sql/persister_verification.go index b2f19f94726b..8d983ed1635d 100644 --- a/persistence/sql/persister_verification.go +++ b/persistence/sql/persister_verification.go @@ -16,6 +16,7 @@ import ( "github.com/gobuffalo/pop/v6" "github.com/gofrs/uuid" + "github.com/ory/x/otelx" "github.com/ory/x/sqlcon" "github.com/ory/kratos/selfservice/flow/verification" @@ -24,9 +25,9 @@ import ( var _ verification.FlowPersister = new(Persister) -func (p *Persister) CreateVerificationFlow(ctx context.Context, r *verification.Flow) error { +func (p *Persister) CreateVerificationFlow(ctx context.Context, r *verification.Flow) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateVerificationFlow") - defer span.End() + defer otelx.End(span, &err) r.NID = p.NetworkID(ctx) // This should not create the request eagerly because otherwise we might accidentally create an address @@ -34,9 +35,9 @@ func (p *Persister) CreateVerificationFlow(ctx context.Context, r *verification. return p.GetConnection(ctx).Create(r) } -func (p *Persister) GetVerificationFlow(ctx context.Context, id uuid.UUID) (*verification.Flow, error) { +func (p *Persister) GetVerificationFlow(ctx context.Context, id uuid.UUID) (_ *verification.Flow, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetVerificationFlow") - defer span.End() + defer otelx.End(span, &err) var r verification.Flow if err := p.GetConnection(ctx).Where("id = ? AND nid = ?", id, p.NetworkID(ctx)).First(&r); err != nil { @@ -46,18 +47,18 @@ func (p *Persister) GetVerificationFlow(ctx context.Context, id uuid.UUID) (*ver return &r, nil } -func (p *Persister) UpdateVerificationFlow(ctx context.Context, r *verification.Flow) error { +func (p *Persister) UpdateVerificationFlow(ctx context.Context, r *verification.Flow) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.UpdateVerificationFlow") - defer span.End() + defer otelx.End(span, &err) cp := *r cp.NID = p.NetworkID(ctx) return update.Generic(ctx, p.GetConnection(ctx), p.r.Tracer(ctx).Tracer(), cp) } -func (p *Persister) CreateVerificationToken(ctx context.Context, token *link.VerificationToken) error { +func (p *Persister) CreateVerificationToken(ctx context.Context, token *link.VerificationToken) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateVerificationToken") - defer span.End() + defer otelx.End(span, &err) t := token.Token token.Token = p.hmacValue(ctx, t) @@ -72,9 +73,9 @@ func (p *Persister) CreateVerificationToken(ctx context.Context, token *link.Ver return nil } -func (p *Persister) UseVerificationToken(ctx context.Context, fID uuid.UUID, token string) (*link.VerificationToken, error) { +func (p *Persister) UseVerificationToken(ctx context.Context, fID uuid.UUID, token string) (_ *link.VerificationToken, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.UseVerificationToken") - defer span.End() + defer otelx.End(span, &err) var rt link.VerificationToken @@ -109,18 +110,20 @@ func (p *Persister) UseVerificationToken(ctx context.Context, fID uuid.UUID, tok return &rt, nil } -func (p *Persister) DeleteVerificationToken(ctx context.Context, token string) error { +func (p *Persister) DeleteVerificationToken(ctx context.Context, token string) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteVerificationToken") - defer span.End() + defer otelx.End(span, &err) nid := p.NetworkID(ctx) //#nosec G201 -- TableName is static return p.GetConnection(ctx).RawQuery(fmt.Sprintf("DELETE FROM %s WHERE token=? AND nid = ?", new(link.VerificationToken).TableName(ctx)), token, nid).Exec() } -func (p *Persister) DeleteExpiredVerificationFlows(ctx context.Context, expiresAt time.Time, limit int) error { +func (p *Persister) DeleteExpiredVerificationFlows(ctx context.Context, expiresAt time.Time, limit int) (err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteExpiredVerificationFlows") + defer otelx.End(span, &err) //#nosec G201 -- TableName is static - err := p.GetConnection(ctx).RawQuery(fmt.Sprintf( + err = p.GetConnection(ctx).RawQuery(fmt.Sprintf( "DELETE FROM %s WHERE id in (SELECT id FROM (SELECT id FROM %s c WHERE expires_at <= ? and nid = ? ORDER BY expires_at ASC LIMIT %d ) AS s )", new(verification.Flow).TableName(ctx), new(verification.Flow).TableName(ctx), diff --git a/persistence/sql/persister_verification_code.go b/persistence/sql/persister_verification_code.go index 0b469bad07ce..3c3fc6d9bed5 100644 --- a/persistence/sql/persister_verification_code.go +++ b/persistence/sql/persister_verification_code.go @@ -14,12 +14,13 @@ import ( "github.com/ory/kratos/identity" "github.com/ory/kratos/selfservice/flow/verification" "github.com/ory/kratos/selfservice/strategy/code" + "github.com/ory/x/otelx" "github.com/ory/x/sqlcon" ) -func (p *Persister) CreateVerificationCode(ctx context.Context, params *code.CreateVerificationCodeParams) (*code.VerificationCode, error) { +func (p *Persister) CreateVerificationCode(ctx context.Context, params *code.CreateVerificationCodeParams) (_ *code.VerificationCode, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateVerificationCode") - defer span.End() + defer otelx.End(span, &err) now := time.Now().UTC() verificationCode := &code.VerificationCode{ @@ -50,9 +51,9 @@ func (p *Persister) CreateVerificationCode(ctx context.Context, params *code.Cre return verificationCode, nil } -func (p *Persister) UseVerificationCode(ctx context.Context, flowID uuid.UUID, userProvidedCode string) (*code.VerificationCode, error) { +func (p *Persister) UseVerificationCode(ctx context.Context, flowID uuid.UUID, userProvidedCode string) (_ *code.VerificationCode, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.UseVerificationCode") - defer span.End() + defer otelx.End(span, &err) codeRow, err := useOneTimeCode[code.VerificationCode, *code.VerificationCode](ctx, p, flowID, userProvidedCode, new(verification.Flow).TableName(ctx), "selfservice_verification_flow_id") if err != nil { @@ -69,9 +70,9 @@ func (p *Persister) UseVerificationCode(ctx context.Context, flowID uuid.UUID, u return codeRow, nil } -func (p *Persister) DeleteVerificationCodesOfFlow(ctx context.Context, fID uuid.UUID) error { +func (p *Persister) DeleteVerificationCodesOfFlow(ctx context.Context, fID uuid.UUID) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteVerificationCodesOfFlow") - defer span.End() + defer otelx.End(span, &err) return p.GetConnection(ctx).Where("selfservice_verification_flow_id = ? AND nid = ?", fID, p.NetworkID(ctx)).Delete(&code.VerificationCode{}) } diff --git a/persistence/sql/update/update.go b/persistence/sql/update/update.go index 27bdf2c9cc93..d212b711c684 100644 --- a/persistence/sql/update/update.go +++ b/persistence/sql/update/update.go @@ -13,6 +13,7 @@ import ( "github.com/pkg/errors" "go.opentelemetry.io/otel/trace" + "github.com/ory/x/otelx" "github.com/ory/x/sqlcon" ) @@ -21,9 +22,9 @@ type Model interface { GetNID() uuid.UUID } -func Generic(ctx context.Context, c *pop.Connection, tracer trace.Tracer, v Model, columnNames ...string) error { +func Generic(ctx context.Context, c *pop.Connection, tracer trace.Tracer, v Model, columnNames ...string) (err error) { ctx, span := tracer.Start(ctx, "persistence.sql.update") - defer span.End() + defer otelx.End(span, &err) quoter, ok := c.Dialect.(interface{ Quote(key string) string }) if !ok { diff --git a/request/builder.go b/request/builder.go index 458a16cef130..4651f64d43e2 100644 --- a/request/builder.go +++ b/request/builder.go @@ -85,9 +85,9 @@ func (b *Builder) addAuth() error { return nil } -func (b *Builder) addBody(ctx context.Context, body interface{}) error { +func (b *Builder) addBody(ctx context.Context, body interface{}) (err error) { ctx, span := b.deps.Tracer(ctx).Tracer().Start(ctx, "request.Builder.addBody") - defer span.End() + defer otelx.End(span, &err) if isNilInterface(body) { return nil diff --git a/selfservice/hook/web_hook.go b/selfservice/hook/web_hook.go index 5c9aa31e92fa..cbb9f0a0b0d4 100644 --- a/selfservice/hook/web_hook.go +++ b/selfservice/hook/web_hook.go @@ -9,7 +9,6 @@ import ( "fmt" "io" "net/http" - "net/http/httputil" "time" "github.com/dgraph-io/ristretto" @@ -516,6 +515,7 @@ func isTimeoutError(err error) bool { } func instrumentHTTPClientForEvents(ctx context.Context, httpClient *retryablehttp.Client) { + // TODO(@alnr): improve this implementation to redact sensitive data var ( attempt = 0 requestID uuid.UUID @@ -525,12 +525,16 @@ func instrumentHTTPClientForEvents(ctx context.Context, httpClient *retryablehtt attempt = retryNumber + 1 requestID = uuid.Must(uuid.NewV4()) req.Header.Set("Ory-Webhook-Request-ID", requestID.String()) - reqBody, _ = httputil.DumpRequestOut(req, true) + // TODO(@alnr): redact sensitive data + // reqBody, _ = httputil.DumpRequestOut(req, true) + reqBody = []byte("") } httpClient.ResponseLogHook = func(_ retryablehttp.Logger, res *http.Response) { - res.Body = io.NopCloser(io.LimitReader(res.Body, 5<<20)) // read at most 5 MB from the response - resBody, _ := httputil.DumpResponse(res, true) - resBody = resBody[:min(len(resBody), 2<<10)] // truncate response body to 2 kB for event + // res.Body = io.NopCloser(io.LimitReader(res.Body, 5<<20)) // read at most 5 MB from the response + // resBody, _ := httputil.DumpResponse(res, true) + // resBody = resBody[:min(len(resBody), 2<<10)] // truncate response body to 2 kB for event + // TODO(@alnr): redact sensitive data + resBody := []byte("") trace.SpanFromContext(ctx).AddEvent(events.NewWebhookDelivered(ctx, res.Request.URL, reqBody, res.StatusCode, resBody, attempt, requestID)) } } diff --git a/selfservice/strategy/code/code_sender.go b/selfservice/strategy/code/code_sender.go index d0166e86863f..479dfaad09bc 100644 --- a/selfservice/strategy/code/code_sender.go +++ b/selfservice/strategy/code/code_sender.go @@ -8,14 +8,12 @@ import ( "net/url" "github.com/gofrs/uuid" - "github.com/hashicorp/go-retryablehttp" "github.com/pkg/errors" "github.com/ory/herodot" "github.com/ory/kratos/courier/template/email" "github.com/ory/kratos/courier/template/sms" - "github.com/ory/x/httpx" "github.com/ory/x/sqlcon" "github.com/ory/x/stringsx" "github.com/ory/x/urlx" @@ -45,7 +43,7 @@ type ( RegistrationCodePersistenceProvider LoginCodePersistenceProvider - HTTPClient(ctx context.Context, opts ...httpx.ResilientOptions) *retryablehttp.Client + x.HTTPClientProvider } SenderProvider interface { CodeSender() *Sender diff --git a/selfservice/strategy/link/sender.go b/selfservice/strategy/link/sender.go index 874f0b92129d..5ecd27bdcf10 100644 --- a/selfservice/strategy/link/sender.go +++ b/selfservice/strategy/link/sender.go @@ -7,12 +7,8 @@ import ( "context" "net/url" - "github.com/hashicorp/go-retryablehttp" - "github.com/ory/kratos/courier/template/email" - "github.com/ory/x/httpx" - "github.com/pkg/errors" "github.com/ory/x/sqlcon" @@ -40,7 +36,7 @@ type ( VerificationTokenPersistenceProvider RecoveryTokenPersistenceProvider - HTTPClient(ctx context.Context, opts ...httpx.ResilientOptions) *retryablehttp.Client + x.HTTPClientProvider } SenderProvider interface { LinkSender() *Sender diff --git a/selfservice/strategy/oidc/provider_linkedin_test.go b/selfservice/strategy/oidc/provider_linkedin_test.go index 501bb38d61ca..5eb7a629c7cc 100644 --- a/selfservice/strategy/oidc/provider_linkedin_test.go +++ b/selfservice/strategy/oidc/provider_linkedin_test.go @@ -10,6 +10,7 @@ import ( "testing" "time" + "github.com/hashicorp/go-retryablehttp" "github.com/jarcoal/httpmock" "github.com/stretchr/testify/assert" @@ -21,8 +22,10 @@ import ( ) func TestProviderLinkedin_Claims(t *testing.T) { - httpmock.Activate() - defer httpmock.DeactivateAndReset() + _, base := internal.NewFastRegistryWithMocks(t) + reg := &mockRegistry{base, retryablehttp.NewClient()} + httpmock.ActivateNonDefault(reg.cl.HTTPClient) + t.Cleanup(httpmock.DeactivateAndReset) httpmock.RegisterResponder("GET", "https://api.linkedin.com/v2/me?projection=(id,localizedFirstName,localizedLastName,profilePicture(displayImage~digitalmediaAsset:playableStreams))", func(req *http.Request) (*http.Response, error) { @@ -101,7 +104,6 @@ func TestProviderLinkedin_Claims(t *testing.T) { }, ) - _, reg := internal.NewFastRegistryWithMocks(t) c := &oidc.Configuration{ ID: "linkedin", Provider: "linkedin", @@ -131,8 +133,10 @@ func TestProviderLinkedin_Claims(t *testing.T) { } func TestProviderLinkedin_No_Picture(t *testing.T) { - httpmock.Activate() - defer httpmock.DeactivateAndReset() + _, base := internal.NewFastRegistryWithMocks(t) + reg := &mockRegistry{base, retryablehttp.NewClient()} + httpmock.ActivateNonDefault(reg.cl.HTTPClient) + t.Cleanup(httpmock.DeactivateAndReset) httpmock.RegisterResponder("GET", "https://api.linkedin.com/v2/me?projection=(id,localizedFirstName,localizedLastName,profilePicture(displayImage~digitalmediaAsset:playableStreams))", func(req *http.Request) (*http.Response, error) { @@ -176,7 +180,6 @@ func TestProviderLinkedin_No_Picture(t *testing.T) { }, ) - _, reg := internal.NewFastRegistryWithMocks(t) c := &oidc.Configuration{ ID: "linkedin", Provider: "linkedin", diff --git a/selfservice/strategy/oidc/strategy_login.go b/selfservice/strategy/oidc/strategy_login.go index 641b3d42b977..be3c6762e3e3 100644 --- a/selfservice/strategy/oidc/strategy_login.go +++ b/selfservice/strategy/oidc/strategy_login.go @@ -16,6 +16,7 @@ import ( "github.com/ory/kratos/session" "github.com/ory/kratos/ui/node" + "github.com/ory/x/otelx" "github.com/ory/x/sqlcon" "github.com/ory/kratos/selfservice/flow/registration" @@ -181,7 +182,7 @@ func (s *Strategy) processLogin(w http.ResponseWriter, r *http.Request, loginFlo func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow, _ *session.Session) (i *identity.Identity, err error) { ctx, span := s.d.Tracer(r.Context()).Tracer().Start(r.Context(), "selfservice.strategy.oidc.strategy.Login") - defer span.End() + defer otelx.End(span, &err) if err := login.CheckAAL(f, identity.AuthenticatorAssuranceLevel1); err != nil { return nil, err diff --git a/x/http.go b/x/http.go index 380ca14a1034..f0b3a34cd404 100644 --- a/x/http.go +++ b/x/http.go @@ -66,5 +66,5 @@ func AcceptsJSON(r *http.Request) bool { } type HTTPClientProvider interface { - HTTPClient(ctx context.Context, opts ...httpx.ResilientOptions) *retryablehttp.Client + HTTPClient(context.Context, ...httpx.ResilientOptions) *retryablehttp.Client } From cfa30744cbe7e61bd37bb44c7befbf010770dbc1 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Mon, 12 Feb 2024 13:12:40 +0000 Subject: [PATCH 277/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b71fad43c66..8a2e174ec48c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2024-02-09)](#2024-02-09) +- [ (2024-02-12)](#2024-02-12) - [Bug Fixes](#bug-fixes) - [Features](#features) - [Tests](#tests) @@ -320,7 +320,7 @@ -# [](https://github.com/ory/kratos/compare/v1.1.0-pre.0...v) (2024-02-09) +# [](https://github.com/ory/kratos/compare/v1.1.0-pre.0...v) (2024-02-12) ### Bug Fixes @@ -335,6 +335,10 @@ ### Features +- Add request URL to email and SMS templates + ([bf5f8c3](https://github.com/ory/kratos/commit/bf5f8c3cfb2eb523a77239addb8249adf9f8b31d)) +- Improved webhook tracing ([#3746](https://github.com/ory/kratos/issues/3746)) + ([9d7021d](https://github.com/ory/kratos/commit/9d7021d87f47690c2c1f8000e87b425e49bc9496)) - List by OIDC cred ([#3721](https://github.com/ory/kratos/issues/3721)) ([bff9c61](https://github.com/ory/kratos/commit/bff9c61b147648ab139e7e86cda4336b5d1cfd39)) From 40ed809db631149874864f216a106c43ea5df670 Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Fri, 16 Feb 2024 10:10:11 +0100 Subject: [PATCH 278/282] fix: don't require code credential for MFA flows (#3753) --- internal/testhelpers/config.go | 8 +++++++- selfservice/strategy/code/strategy_login.go | 19 +++++++++++++++---- .../strategy/code/strategy_login_test.go | 3 ++- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/internal/testhelpers/config.go b/internal/testhelpers/config.go index b7a284767459..2a24709c0745 100644 --- a/internal/testhelpers/config.go +++ b/internal/testhelpers/config.go @@ -24,11 +24,17 @@ func UseConfigFile(t *testing.T, path string) *pflag.FlagSet { return flags } -func SetDefaultIdentitySchema(conf *config.Config, url string) { +func SetDefaultIdentitySchema(conf *config.Config, url string) func() { + schemaUrl, _ := conf.DefaultIdentityTraitsSchemaURL(context.Background()) conf.MustSet(context.Background(), config.ViperKeyDefaultIdentitySchemaID, "default") conf.MustSet(context.Background(), config.ViperKeyIdentitySchemas, config.Schemas{ {ID: "default", URL: url}, }) + return func() { + conf.MustSet(context.Background(), config.ViperKeyIdentitySchemas, config.Schemas{ + {ID: "default", URL: schemaUrl.String()}, + }) + } } // UseIdentitySchema registeres an identity schema in the config with a random ID and returns the ID diff --git a/selfservice/strategy/code/strategy_login.go b/selfservice/strategy/code/strategy_login.go index 5f7d04e395da..ac658e238dcb 100644 --- a/selfservice/strategy/code/strategy_login.go +++ b/selfservice/strategy/code/strategy_login.go @@ -293,10 +293,21 @@ func (s *Strategy) loginVerifyCode(ctx context.Context, r *http.Request, f *logi p.Identifier = maybeNormalizeEmail(p.Identifier) - // Step 1: Get the identity - i, isFallback, err := s.findIdentityByIdentifier(ctx, p.Identifier) - if err != nil { - return nil, err + isFallback := false + var i *identity.Identity + if f.RequestedAAL > identity.AuthenticatorAssuranceLevel1 { + // Don't require the code credential if the user already has a session (e.g. this is an MFA flow) + sess, err := s.deps.SessionManager().FetchFromRequest(ctx, r) + if err != nil { + return nil, err + } + i = sess.Identity + } else { + // Step 1: Get the identity + i, isFallback, err = s.findIdentityByIdentifier(ctx, p.Identifier) + if err != nil { + return nil, err + } } loginCode, err := s.deps.LoginCodePersister().UseLoginCode(ctx, f.ID, i.ID, p.Code) diff --git a/selfservice/strategy/code/strategy_login_test.go b/selfservice/strategy/code/strategy_login_test.go index 06d811362978..19cac6d38375 100644 --- a/selfservice/strategy/code/strategy_login_test.go +++ b/selfservice/strategy/code/strategy_login_test.go @@ -586,7 +586,8 @@ func TestLoginCodeStrategy(t *testing.T) { }) t.Run("case=should be able to get AAL2 session", func(t *testing.T) { - identity := createIdentity(ctx, t, false) + t.Cleanup(testhelpers.SetDefaultIdentitySchema(conf, "file://./stub/default.schema.json")) // doesn't have the code credential + identity := createIdentity(ctx, t, true) var cl *http.Client var f *oryClient.LoginFlow if tc.apiType == ApiTypeNative { From 72bdedacc539199ade947f5c7570fb11bd416688 Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Fri, 16 Feb 2024 09:56:17 +0000 Subject: [PATCH 279/282] autogen(docs): regenerate and update changelog [skip ci] --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a2e174ec48c..6142899fb09f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Table of Contents** -- [ (2024-02-12)](#2024-02-12) +- [ (2024-02-16)](#2024-02-16) - [Bug Fixes](#bug-fixes) - [Features](#features) - [Tests](#tests) @@ -320,12 +320,15 @@ -# [](https://github.com/ory/kratos/compare/v1.1.0-pre.0...v) (2024-02-12) +# [](https://github.com/ory/kratos/compare/v1.1.0-pre.0...v) (2024-02-16) ### Bug Fixes - Add consistency flag ([#3733](https://github.com/ory/kratos/issues/3733)) ([fd79950](https://github.com/ory/kratos/commit/fd7995077307cc101550eda5d7724ea1f68fa98a)) +- Don't require code credential for MFA flows + ([#3753](https://github.com/ory/kratos/issues/3753)) + ([40ed809](https://github.com/ory/kratos/commit/40ed809db631149874864f216a106c43ea5df670)) - Http courier using should use lower case json ([#3740](https://github.com/ory/kratos/issues/3740)) ([84149c4](https://github.com/ory/kratos/commit/84149c4b420ea89f0a16a579c017a8e7e1670204)) From f47675b82012e0ff74b05b9b7e713b3aa2fdda54 Mon Sep 17 00:00:00 2001 From: aeneasr <3372410+aeneasr@users.noreply.github.com> Date: Tue, 20 Feb 2024 10:34:09 +0100 Subject: [PATCH 280/282] autogen: pin v1.1.0 release commit --- .schemastore/config.schema.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.schemastore/config.schema.json b/.schemastore/config.schema.json index 0980a4ab6d8a..d03c22b37246 100644 --- a/.schemastore/config.schema.json +++ b/.schemastore/config.schema.json @@ -150,7 +150,7 @@ "format": "uri", "pattern": "^(http|https|file|base64)://", "description": "URI pointing to the jsonnet template used for payload generation. Only used for those HTTP methods, which support HTTP body payloads", - "default": "base64://ZnVuY3Rpb24oY3R4KSB7CiAgcmVjaXBpZW50OiBjdHguUmVjaXBpZW50LAogIHRlbXBsYXRlX3R5cGU6IGN0eC5UZW1wbGF0ZVR5cGUsCiAgdG86IGlmICJUZW1wbGF0ZURhdGEiIGluIGN0eCAmJiAiVG8iIGluIGN0eC5UZW1wbGF0ZURhdGEgdGhlbiBjdHguVGVtcGxhdGVEYXRhLlRvIGVsc2UgbnVsbCwKICByZWNvdmVyeV9jb2RlOiBpZiAiVGVtcGxhdGVEYXRhIiBpbiBjdHggJiYgIlJlY292ZXJ5Q29kZSIgaW4gY3R4LlRlbXBsYXRlRGF0YSB0aGVuIGN0eC5UZW1wbGF0ZURhdGEuUmVjb3ZlcnlDb2RlIGVsc2UgbnVsbCwKICByZWNvdmVyeV91cmw6IGlmICJUZW1wbGF0ZURhdGEiIGluIGN0eCAmJiAiUmVjb3ZlcnlVUkwiIGluIGN0eC5UZW1wbGF0ZURhdGEgdGhlbiBjdHguVGVtcGxhdGVEYXRhLlJlY292ZXJ5VVJMIGVsc2UgbnVsbCwKICB2ZXJpZmljYXRpb25fdXJsOiBpZiAiVGVtcGxhdGVEYXRhIiBpbiBjdHggJiYgIlZlcmlmaWNhdGlvblVSTCIgaW4gY3R4LlRlbXBsYXRlRGF0YSB0aGVuIGN0eC5UZW1wbGF0ZURhdGEuVmVyaWZpY2F0aW9uVVJMIGVsc2UgbnVsbCwKICB2ZXJpZmljYXRpb25fY29kZTogaWYgIlRlbXBsYXRlRGF0YSIgaW4gY3R4ICYmICJWZXJpZmljYXRpb25Db2RlIiBpbiBjdHguVGVtcGxhdGVEYXRhIHRoZW4gY3R4LlRlbXBsYXRlRGF0YS5WZXJpZmljYXRpb25Db2RlIGVsc2UgbnVsbCwKICBzdWJqZWN0OiBjdHguU3ViamVjdCwKICBib2R5OiBjdHguQm9keQp9Cg==", + "default": "base64://ZnVuY3Rpb24oY3R4KSB7CiAgcmVjaXBpZW50OiBjdHgucmVjaXBpZW50LAogIHRlbXBsYXRlX3R5cGU6IGN0eC50ZW1wbGF0ZV90eXBlLAogIHRvOiBpZiAidGVtcGxhdGVfZGF0YSIgaW4gY3R4ICYmICJ0byIgaW4gY3R4LnRlbXBsYXRlX2RhdGEgdGhlbiBjdHgudGVtcGxhdGVfZGF0YS50byBlbHNlIG51bGwsCiAgcmVjb3ZlcnlfY29kZTogaWYgInRlbXBsYXRlX2RhdGEiIGluIGN0eCAmJiAicmVjb3ZlcnlfY29kZSIgaW4gY3R4LnRlbXBsYXRlX2RhdGEgdGhlbiBjdHgudGVtcGxhdGVfZGF0YS5yZWNvdmVyeV9jb2RlIGVsc2UgbnVsbCwKICByZWNvdmVyeV91cmw6IGlmICJ0ZW1wbGF0ZV9kYXRhIiBpbiBjdHggJiYgInJlY292ZXJ5X3VybCIgaW4gY3R4LnRlbXBsYXRlX2RhdGEgdGhlbiBjdHgudGVtcGxhdGVfZGF0YS5yZWNvdmVyeV91cmwgZWxzZSBudWxsLAogIHZlcmlmaWNhdGlvbl91cmw6IGlmICJ0ZW1wbGF0ZV9kYXRhIiBpbiBjdHggJiYgInZlcmlmaWNhdGlvbl91cmwiIGluIGN0eC50ZW1wbGF0ZV9kYXRhIHRoZW4gY3R4LnRlbXBsYXRlX2RhdGEudmVyaWZpY2F0aW9uX3VybCBlbHNlIG51bGwsCiAgdmVyaWZpY2F0aW9uX2NvZGU6IGlmICJ0ZW1wbGF0ZV9kYXRhIiBpbiBjdHggJiYgInZlcmlmaWNhdGlvbl9jb2RlIiBpbiBjdHgudGVtcGxhdGVfZGF0YSB0aGVuIGN0eC50ZW1wbGF0ZV9kYXRhLnZlcmlmaWNhdGlvbl9jb2RlIGVsc2UgbnVsbCwKICBzdWJqZWN0OiBjdHguc3ViamVjdCwKICBib2R5OiBjdHguYm9keQp9Cg==", "examples": [ "file:///path/to/body.jsonnet", "file://./body.jsonnet", @@ -2305,7 +2305,7 @@ "additionalProperties": false }, "tracing": { - "$ref": "https://raw.githubusercontent.com/ory/x/v0.0.611/otelx/config.schema.json" + "$ref": "https://raw.githubusercontent.com/ory/x/v0.0.614/otelx/config.schema.json" }, "log": { "title": "Log", From b8b3c867bd8b07c24448ddaae6e0b25a62d0ae63 Mon Sep 17 00:00:00 2001 From: apasternak Date: Fri, 8 Mar 2024 15:43:21 +0100 Subject: [PATCH 281/282] Merge 1.1.0 to our fork + make sdk + lint --- driver/registry_default.go | 14 +- internal/client-go/api_default.go | 183 ------------------ .../model_ui_node_input_attributes.go | 78 +++++++- .../model_ui_node_input_attributes.go | 78 +++++++- selfservice/hook/session_issuer.go | 3 +- spec/api.json | 14 +- spec/swagger.json | 18 +- 7 files changed, 183 insertions(+), 205 deletions(-) delete mode 100644 internal/client-go/api_default.go diff --git a/driver/registry_default.go b/driver/registry_default.go index 1ef33b89d184..b248b5d87d76 100644 --- a/driver/registry_default.go +++ b/driver/registry_default.go @@ -24,8 +24,8 @@ import ( "github.com/ory/herodot" "github.com/ory/kratos/cipher" "github.com/ory/kratos/continuity" - "github.com/ory/kratos/credentials" "github.com/ory/kratos/courier" + "github.com/ory/kratos/credentials" "github.com/ory/kratos/driver/config" "github.com/ory/kratos/hash" "github.com/ory/kratos/hydra" @@ -86,12 +86,12 @@ type RegistryDefault struct { persister persistence.Persister migrationStatus popx.MigrationStatuses - hookVerifier *hook.Verifier - hookSessionIssuer *hook.SessionIssuer - hookSessionDestroyer *hook.SessionDestroyer - hookAddressVerifier *hook.AddressVerifier - hookShowVerificationUI *hook.ShowVerificationUIHook - hookCodeAddressVerifier *hook.CodeAddressVerifier + hookVerifier *hook.Verifier + hookSessionIssuer *hook.SessionIssuer + hookSessionDestroyer *hook.SessionDestroyer + hookAddressVerifier *hook.AddressVerifier + hookShowVerificationUI *hook.ShowVerificationUIHook + hookCodeAddressVerifier *hook.CodeAddressVerifier hookTotpSecretsDestroyer *hook.TotpSecretsDestroyer credentialsHandler *credentials.Handler diff --git a/internal/client-go/api_default.go b/internal/client-go/api_default.go deleted file mode 100644 index 9d47a12a6c6b..000000000000 --- a/internal/client-go/api_default.go +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Ory Identities API - * - * This is the API specification for Ory Identities with features such as registration, login, recovery, account verification, profile settings, password reset, identity management, session management, email and sms delivery, and more. - * - * API version: - * Contact: office@ory.sh - */ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package client - -import ( - "bytes" - "context" - "io" - "net/http" - "net/url" -) - -// Linger please -var ( - _ context.Context -) - -type DefaultApi interface { - - /* - * Identity Calling this endpoint refreshes a current user session. If `session.refresh_min_time_left` is set it will only refresh the session after this time has passed. - * This endpoint is useful for: - - Session refresh - * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - * @return DefaultApiApiIdentityRequest - */ - Identity(ctx context.Context) DefaultApiApiIdentityRequest - - /* - * IdentityExecute executes the request - * @return Session - */ - IdentityExecute(r DefaultApiApiIdentityRequest) (*Session, *http.Response, error) -} - -// DefaultApiService DefaultApi service -type DefaultApiService service - -type DefaultApiApiIdentityRequest struct { - ctx context.Context - ApiService DefaultApi -} - -func (r DefaultApiApiIdentityRequest) Execute() (*Session, *http.Response, error) { - return r.ApiService.IdentityExecute(r) -} - -/* - - Identity Calling this endpoint refreshes a current user session. If `session.refresh_min_time_left` is set it will only refresh the session after this time has passed. - - This endpoint is useful for: - -Session refresh - - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - - @return DefaultApiApiIdentityRequest -*/ -func (a *DefaultApiService) Identity(ctx context.Context) DefaultApiApiIdentityRequest { - return DefaultApiApiIdentityRequest{ - ApiService: a, - ctx: ctx, - } -} - -/* - * Execute executes the request - * @return Session - */ -func (a *DefaultApiService) IdentityExecute(r DefaultApiApiIdentityRequest) (*Session, *http.Response, error) { - var ( - localVarHTTPMethod = http.MethodGet - localVarPostBody interface{} - localVarFormFileName string - localVarFileName string - localVarFileBytes []byte - localVarReturnValue *Session - ) - - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "DefaultApiService.Identity") - if err != nil { - return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} - } - - localVarPath := localBasePath + "/admin/token/extend" - - localVarHeaderParams := make(map[string]string) - localVarQueryParams := url.Values{} - localVarFormParams := url.Values{} - - // to determine the Content-Type header - localVarHTTPContentTypes := []string{} - - // set Content-Type header - localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) - if localVarHTTPContentType != "" { - localVarHeaderParams["Content-Type"] = localVarHTTPContentType - } - - // to determine the Accept header - localVarHTTPHeaderAccepts := []string{"application/json"} - - // set Accept header - localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) - if localVarHTTPHeaderAccept != "" { - localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept - } - if r.ctx != nil { - // API Key Authentication - if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { - if apiKey, ok := auth["oryAccessToken"]; ok { - var key string - if apiKey.Prefix != "" { - key = apiKey.Prefix + " " + apiKey.Key - } else { - key = apiKey.Key - } - localVarHeaderParams["Authorization"] = key - } - } - } - req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFormFileName, localVarFileName, localVarFileBytes) - if err != nil { - return localVarReturnValue, nil, err - } - - localVarHTTPResponse, err := a.client.callAPI(req) - if err != nil || localVarHTTPResponse == nil { - return localVarReturnValue, localVarHTTPResponse, err - } - - localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) - localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) - if err != nil { - return localVarReturnValue, localVarHTTPResponse, err - } - - if localVarHTTPResponse.StatusCode >= 300 { - newErr := &GenericOpenAPIError{ - body: localVarBody, - error: localVarHTTPResponse.Status, - } - if localVarHTTPResponse.StatusCode == 404 { - var v ErrorGeneric - err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) - if err != nil { - newErr.error = err.Error() - return localVarReturnValue, localVarHTTPResponse, newErr - } - newErr.model = v - return localVarReturnValue, localVarHTTPResponse, newErr - } - if localVarHTTPResponse.StatusCode == 500 { - var v ErrorGeneric - err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) - if err != nil { - newErr.error = err.Error() - return localVarReturnValue, localVarHTTPResponse, newErr - } - newErr.model = v - } - return localVarReturnValue, localVarHTTPResponse, newErr - } - - err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) - if err != nil { - newErr := &GenericOpenAPIError{ - body: localVarBody, - error: err.Error(), - } - return localVarReturnValue, localVarHTTPResponse, newErr - } - - return localVarReturnValue, localVarHTTPResponse, nil -} diff --git a/internal/client-go/model_ui_node_input_attributes.go b/internal/client-go/model_ui_node_input_attributes.go index fa73337b9160..3ed9dd56e0c6 100644 --- a/internal/client-go/model_ui_node_input_attributes.go +++ b/internal/client-go/model_ui_node_input_attributes.go @@ -19,13 +19,13 @@ import ( type UiNodeInputAttributes struct { // The autocomplete attribute for the input. email InputAttributeAutocompleteEmail tel InputAttributeAutocompleteTel url InputAttributeAutocompleteUrl current-password InputAttributeAutocompleteCurrentPassword new-password InputAttributeAutocompleteNewPassword one-time-code InputAttributeAutocompleteOneTimeCode Autocomplete *string `json:"autocomplete,omitempty"` - // The minlength attribute for the input. - MinLength uint `json:"minlength,omitempty"` - // The maxlength attribute for the input. - MaxLength uint `json:"maxlength,omitempty"` // Sets the input's disabled field to true or false. Disabled bool `json:"disabled"` Label *UiText `json:"label,omitempty"` + // The maxlength attribute for the input. + Maxlength *int32 `json:"maxlength,omitempty"` + // The minlength attribute for the input. + Minlength *int32 `json:"minlength,omitempty"` // The input's element name. Name string `json:"name"` // NodeType represents this node's types. It is a mirror of `node.type` and is primarily used to allow compatibility with OpenAPI 3.0. In this struct it technically always is \"input\". @@ -151,6 +151,70 @@ func (o *UiNodeInputAttributes) SetLabel(v UiText) { o.Label = &v } +// GetMaxlength returns the Maxlength field value if set, zero value otherwise. +func (o *UiNodeInputAttributes) GetMaxlength() int32 { + if o == nil || o.Maxlength == nil { + var ret int32 + return ret + } + return *o.Maxlength +} + +// GetMaxlengthOk returns a tuple with the Maxlength field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UiNodeInputAttributes) GetMaxlengthOk() (*int32, bool) { + if o == nil || o.Maxlength == nil { + return nil, false + } + return o.Maxlength, true +} + +// HasMaxlength returns a boolean if a field has been set. +func (o *UiNodeInputAttributes) HasMaxlength() bool { + if o != nil && o.Maxlength != nil { + return true + } + + return false +} + +// SetMaxlength gets a reference to the given int32 and assigns it to the Maxlength field. +func (o *UiNodeInputAttributes) SetMaxlength(v int32) { + o.Maxlength = &v +} + +// GetMinlength returns the Minlength field value if set, zero value otherwise. +func (o *UiNodeInputAttributes) GetMinlength() int32 { + if o == nil || o.Minlength == nil { + var ret int32 + return ret + } + return *o.Minlength +} + +// GetMinlengthOk returns a tuple with the Minlength field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UiNodeInputAttributes) GetMinlengthOk() (*int32, bool) { + if o == nil || o.Minlength == nil { + return nil, false + } + return o.Minlength, true +} + +// HasMinlength returns a boolean if a field has been set. +func (o *UiNodeInputAttributes) HasMinlength() bool { + if o != nil && o.Minlength != nil { + return true + } + + return false +} + +// SetMinlength gets a reference to the given int32 and assigns it to the Minlength field. +func (o *UiNodeInputAttributes) SetMinlength(v int32) { + o.Minlength = &v +} + // GetName returns the Name field value func (o *UiNodeInputAttributes) GetName() string { if o == nil { @@ -363,6 +427,12 @@ func (o UiNodeInputAttributes) MarshalJSON() ([]byte, error) { if o.Label != nil { toSerialize["label"] = o.Label } + if o.Maxlength != nil { + toSerialize["maxlength"] = o.Maxlength + } + if o.Minlength != nil { + toSerialize["minlength"] = o.Minlength + } if true { toSerialize["name"] = o.Name } diff --git a/internal/httpclient/model_ui_node_input_attributes.go b/internal/httpclient/model_ui_node_input_attributes.go index fa73337b9160..3ed9dd56e0c6 100644 --- a/internal/httpclient/model_ui_node_input_attributes.go +++ b/internal/httpclient/model_ui_node_input_attributes.go @@ -19,13 +19,13 @@ import ( type UiNodeInputAttributes struct { // The autocomplete attribute for the input. email InputAttributeAutocompleteEmail tel InputAttributeAutocompleteTel url InputAttributeAutocompleteUrl current-password InputAttributeAutocompleteCurrentPassword new-password InputAttributeAutocompleteNewPassword one-time-code InputAttributeAutocompleteOneTimeCode Autocomplete *string `json:"autocomplete,omitempty"` - // The minlength attribute for the input. - MinLength uint `json:"minlength,omitempty"` - // The maxlength attribute for the input. - MaxLength uint `json:"maxlength,omitempty"` // Sets the input's disabled field to true or false. Disabled bool `json:"disabled"` Label *UiText `json:"label,omitempty"` + // The maxlength attribute for the input. + Maxlength *int32 `json:"maxlength,omitempty"` + // The minlength attribute for the input. + Minlength *int32 `json:"minlength,omitempty"` // The input's element name. Name string `json:"name"` // NodeType represents this node's types. It is a mirror of `node.type` and is primarily used to allow compatibility with OpenAPI 3.0. In this struct it technically always is \"input\". @@ -151,6 +151,70 @@ func (o *UiNodeInputAttributes) SetLabel(v UiText) { o.Label = &v } +// GetMaxlength returns the Maxlength field value if set, zero value otherwise. +func (o *UiNodeInputAttributes) GetMaxlength() int32 { + if o == nil || o.Maxlength == nil { + var ret int32 + return ret + } + return *o.Maxlength +} + +// GetMaxlengthOk returns a tuple with the Maxlength field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UiNodeInputAttributes) GetMaxlengthOk() (*int32, bool) { + if o == nil || o.Maxlength == nil { + return nil, false + } + return o.Maxlength, true +} + +// HasMaxlength returns a boolean if a field has been set. +func (o *UiNodeInputAttributes) HasMaxlength() bool { + if o != nil && o.Maxlength != nil { + return true + } + + return false +} + +// SetMaxlength gets a reference to the given int32 and assigns it to the Maxlength field. +func (o *UiNodeInputAttributes) SetMaxlength(v int32) { + o.Maxlength = &v +} + +// GetMinlength returns the Minlength field value if set, zero value otherwise. +func (o *UiNodeInputAttributes) GetMinlength() int32 { + if o == nil || o.Minlength == nil { + var ret int32 + return ret + } + return *o.Minlength +} + +// GetMinlengthOk returns a tuple with the Minlength field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UiNodeInputAttributes) GetMinlengthOk() (*int32, bool) { + if o == nil || o.Minlength == nil { + return nil, false + } + return o.Minlength, true +} + +// HasMinlength returns a boolean if a field has been set. +func (o *UiNodeInputAttributes) HasMinlength() bool { + if o != nil && o.Minlength != nil { + return true + } + + return false +} + +// SetMinlength gets a reference to the given int32 and assigns it to the Minlength field. +func (o *UiNodeInputAttributes) SetMinlength(v int32) { + o.Minlength = &v +} + // GetName returns the Name field value func (o *UiNodeInputAttributes) GetName() string { if o == nil { @@ -363,6 +427,12 @@ func (o UiNodeInputAttributes) MarshalJSON() ([]byte, error) { if o.Label != nil { toSerialize["label"] = o.Label } + if o.Maxlength != nil { + toSerialize["maxlength"] = o.Maxlength + } + if o.Minlength != nil { + toSerialize["minlength"] = o.Minlength + } if true { toSerialize["name"] = o.Name } diff --git a/selfservice/hook/session_issuer.go b/selfservice/hook/session_issuer.go index 0aa61d0d777b..b9dfbfaa9df9 100644 --- a/selfservice/hook/session_issuer.go +++ b/selfservice/hook/session_issuer.go @@ -5,9 +5,10 @@ package hook import ( "context" + "net/http" + "github.com/ory/kratos/identity" "github.com/ory/kratos/ui/node" - "net/http" "github.com/pkg/errors" diff --git a/spec/api.json b/spec/api.json index 583f7a43dfca..3ab71a4b9d53 100644 --- a/spec/api.json +++ b/spec/api.json @@ -2317,6 +2317,16 @@ "label": { "$ref": "#/components/schemas/uiText" }, + "maxlength": { + "description": "The maxlength attribute for the input.", + "format": "uint64", + "type": "integer" + }, + "minlength": { + "description": "The minlength attribute for the input.", + "format": "uint64", + "type": "integer" + }, "name": { "description": "The input's element name.", "type": "string" @@ -7287,7 +7297,7 @@ }, "/sessions/whoami": { "get": { - "description": "Uses the HTTP Headers in the GET request to determine (e.g. by using checking the cookies) who is authenticated.\nReturns a session object in the body or 401 if the credentials are invalid or no credentials were sent.\nWhen the request it successful it adds the user ID to the 'X-Kratos-Authenticated-Identity-Id' header\nin the response.\n\nIf you call this endpoint from a server-side application, you must forward the HTTP Cookie Header to this endpoint:\n\n```js\npseudo-code example\nrouter.get('/protected-endpoint', async function (req, res) {\nconst session = await client.toSession(undefined, req.header('cookie'))\n\nconsole.log(session)\n})\n```\n\nWhen calling this endpoint from a non-browser application (e.g. mobile app) you must include the session token:\n\n```js\npseudo-code example\n...\nconst session = await client.toSession(\"the-session-token\")\n\nconsole.log(session)\n```\n\nWhen using a token template, the token is included in the `tokenized` field of the session.\n\n```js\npseudo-code example\n...\nconst session = await client.toSession(\"the-session-token\", { tokenize_as: \"example-jwt-template\" })\n\nconsole.log(session.tokenized) // The JWT\n```\n\nDepending on your configuration this endpoint might return a 403 status code if the session has a lower Authenticator\nAssurance Level (AAL) than is possible for the identity. This can happen if the identity has password + webauthn\ncredentials (which would result in AAL2) but the session has only AAL1. If this error occurs, ask the user\nto sign in with the second factor or change the configuration.\n\nThis endpoint is useful for:\n\nAJAX calls. Remember to send credentials and set up CORS correctly!\nReverse proxies and API Gateways\nServer-side calls - use the `X-Session-Token` header!\n\nThis endpoint authenticates users by checking:\n\nif the `Cookie` HTTP header was set containing an Ory Kratos Session Cookie;\nif the `Authorization: bearer \u003cory-session-token\u003e` HTTP header was set with a valid Ory Kratos Session Token;\nif the `X-Session-Token` HTTP header was set with a valid Ory Kratos Session Token.\n\nIf none of these headers are set or the cookie or token are invalid, the endpoint returns a HTTP 401 status code.\n\nAs explained above, this request may fail due to several reasons. The `error.id` can be one of:\n\n`session_inactive`: No active session was found in the request (e.g. no Ory Session Cookie / Ory Session Token).\n`session_aal2_required`: An active session was found but it does not fulfil the Authenticator Assurance Level, implying that the session must (e.g.) authenticate the second factor.", + "description": "Uses the HTTP Headers in the GET request to determine (e.g. by using checking the cookies) who is authenticated.\nReturns a session object in the body or 401 if the credentials are invalid or no credentials were sent.\nWhen the request it successful it adds the user ID to the 'X-Kratos-Authenticated-Identity-Id' header\nin the response.\n\nIf you call this endpoint from a server-side application, you must forward the HTTP Cookie Header to this endpoint:\n\n```js\npseudo-code example\nrouter.get('/protected-endpoint', async function (req, res) {\nconst session = await client.toSession(undefined, req.header('cookie'))\n\nconsole.log(session)\n})\n```\n\nWhen calling this endpoint from a non-browser application (e.g. mobile app) you must include the session token:\n\n```js\npseudo-code example\n...\nconst session = await client.toSession(\"the-session-token\")\n\nconsole.log(session)\n```\n\nWhen using a token template, the token is included in the `tokenized` field of the session.\n\n```js\npseudo-code example\n...\nconst session = await client.toSession(\"the-session-token\", { tokenize_as: \"example-jwt-template\" })\n\nconsole.log(session.tokenized) // The JWT\n```\n\nDepending on your configuration this endpoint might return a 403 status code if the session has a lower Authenticator\nAssurance Level (AAL) than is possible for the identity. This can happen if the identity has password + webauthn\ncredentials (which would result in AAL2) but the session has only AAL1. If this error occurs, ask the user\nto sign in with the second factor or change the configuration.\n\nThis endpoint is useful for:\n\nAJAX calls. Remember to send credentials and set up CORS correctly!\nReverse proxies and API Gateways\nServer-side calls - use the `X-Session-Token` header!\nSession refresh\n\nThis endpoint authenticates users by checking:\n\nif the `Cookie` HTTP header was set containing an Ory Kratos Session Cookie;\nif the `Authorization: bearer \u003cory-session-token\u003e` HTTP header was set with a valid Ory Kratos Session Token;\nif the `X-Session-Token` HTTP header was set with a valid Ory Kratos Session Token.\n\nIf none of these headers are set or the cookie or token are invalid, the endpoint returns a HTTP 401 status code.\n\nAs explained above, this request may fail due to several reasons. The `error.id` can be one of:\n\n`session_inactive`: No active session was found in the request (e.g. no Ory Session Cookie / Ory Session Token).\n`session_aal2_required`: An active session was found but it does not fulfil the Authenticator Assurance Level, implying that the session must (e.g.) authenticate the second factor.", "operationId": "toSession", "parameters": [ { @@ -7489,4 +7499,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 d7c46bc2b548..d6feba914f27 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -3251,7 +3251,7 @@ }, "/sessions/whoami": { "get": { - "description": "Uses the HTTP Headers in the GET request to determine (e.g. by using checking the cookies) who is authenticated.\nReturns a session object in the body or 401 if the credentials are invalid or no credentials were sent.\nWhen the request it successful it adds the user ID to the 'X-Kratos-Authenticated-Identity-Id' header\nin the response.\n\nIf you call this endpoint from a server-side application, you must forward the HTTP Cookie Header to this endpoint:\n\n```js\npseudo-code example\nrouter.get('/protected-endpoint', async function (req, res) {\nconst session = await client.toSession(undefined, req.header('cookie'))\n\nconsole.log(session)\n})\n```\n\nWhen calling this endpoint from a non-browser application (e.g. mobile app) you must include the session token:\n\n```js\npseudo-code example\n...\nconst session = await client.toSession(\"the-session-token\")\n\nconsole.log(session)\n```\n\nWhen using a token template, the token is included in the `tokenized` field of the session.\n\n```js\npseudo-code example\n...\nconst session = await client.toSession(\"the-session-token\", { tokenize_as: \"example-jwt-template\" })\n\nconsole.log(session.tokenized) // The JWT\n```\n\nDepending on your configuration this endpoint might return a 403 status code if the session has a lower Authenticator\nAssurance Level (AAL) than is possible for the identity. This can happen if the identity has password + webauthn\ncredentials (which would result in AAL2) but the session has only AAL1. If this error occurs, ask the user\nto sign in with the second factor or change the configuration.\n\nThis endpoint is useful for:\n\nAJAX calls. Remember to send credentials and set up CORS correctly!\nReverse proxies and API Gateways\nServer-side calls - use the `X-Session-Token` header!\n\nThis endpoint authenticates users by checking:\n\nif the `Cookie` HTTP header was set containing an Ory Kratos Session Cookie;\nif the `Authorization: bearer \u003cory-session-token\u003e` HTTP header was set with a valid Ory Kratos Session Token;\nif the `X-Session-Token` HTTP header was set with a valid Ory Kratos Session Token.\n\nIf none of these headers are set or the cookie or token are invalid, the endpoint returns a HTTP 401 status code.\n\nAs explained above, this request may fail due to several reasons. The `error.id` can be one of:\n\n`session_inactive`: No active session was found in the request (e.g. no Ory Session Cookie / Ory Session Token).\n`session_aal2_required`: An active session was found but it does not fulfil the Authenticator Assurance Level, implying that the session must (e.g.) authenticate the second factor.", + "description": "Uses the HTTP Headers in the GET request to determine (e.g. by using checking the cookies) who is authenticated.\nReturns a session object in the body or 401 if the credentials are invalid or no credentials were sent.\nWhen the request it successful it adds the user ID to the 'X-Kratos-Authenticated-Identity-Id' header\nin the response.\n\nIf you call this endpoint from a server-side application, you must forward the HTTP Cookie Header to this endpoint:\n\n```js\npseudo-code example\nrouter.get('/protected-endpoint', async function (req, res) {\nconst session = await client.toSession(undefined, req.header('cookie'))\n\nconsole.log(session)\n})\n```\n\nWhen calling this endpoint from a non-browser application (e.g. mobile app) you must include the session token:\n\n```js\npseudo-code example\n...\nconst session = await client.toSession(\"the-session-token\")\n\nconsole.log(session)\n```\n\nWhen using a token template, the token is included in the `tokenized` field of the session.\n\n```js\npseudo-code example\n...\nconst session = await client.toSession(\"the-session-token\", { tokenize_as: \"example-jwt-template\" })\n\nconsole.log(session.tokenized) // The JWT\n```\n\nDepending on your configuration this endpoint might return a 403 status code if the session has a lower Authenticator\nAssurance Level (AAL) than is possible for the identity. This can happen if the identity has password + webauthn\ncredentials (which would result in AAL2) but the session has only AAL1. If this error occurs, ask the user\nto sign in with the second factor or change the configuration.\n\nThis endpoint is useful for:\n\nAJAX calls. Remember to send credentials and set up CORS correctly!\nReverse proxies and API Gateways\nServer-side calls - use the `X-Session-Token` header!\nSession refresh\n\nThis endpoint authenticates users by checking:\n\nif the `Cookie` HTTP header was set containing an Ory Kratos Session Cookie;\nif the `Authorization: bearer \u003cory-session-token\u003e` HTTP header was set with a valid Ory Kratos Session Token;\nif the `X-Session-Token` HTTP header was set with a valid Ory Kratos Session Token.\n\nIf none of these headers are set or the cookie or token are invalid, the endpoint returns a HTTP 401 status code.\n\nAs explained above, this request may fail due to several reasons. The `error.id` can be one of:\n\n`session_inactive`: No active session was found in the request (e.g. no Ory Session Cookie / Ory Session Token).\n`session_aal2_required`: An active session was found but it does not fulfil the Authenticator Assurance Level, implying that the session must (e.g.) authenticate the second factor.", "produces": [ "application/json" ], @@ -3408,9 +3408,9 @@ "title": "JSONRawMessage represents a json.RawMessage that works well with JSON, SQL, and Swagger." }, "NullTime": { - "description": "NullTime implements the Scanner interface so\nit can be used as a scan destination, similar to NullString.", + "description": "NullTime implements the [Scanner] interface so\nit can be used as a scan destination, similar to [NullString].", "type": "object", - "title": "NullTime represents a time.Time that may be null.", + "title": "NullTime represents a [time.Time] that may be null.", "properties": { "Time": { "type": "string", @@ -5548,6 +5548,16 @@ "label": { "$ref": "#/definitions/uiText" }, + "maxlength": { + "description": "The maxlength attribute for the input.", + "type": "integer", + "format": "uint64" + }, + "minlength": { + "description": "The minlength attribute for the input.", + "type": "integer", + "format": "uint64" + }, "name": { "description": "The input's element name.", "type": "string" @@ -6618,4 +6628,4 @@ }, "x-forwarded-proto": "string", "x-request-id": "string" -} +} \ No newline at end of file From 3cc1d497302d720535f673c2174d898306af2491 Mon Sep 17 00:00:00 2001 From: apasternak Date: Mon, 11 Mar 2024 09:13:47 +0100 Subject: [PATCH 282/282] Merge 1.1.0 fix tests after make sdk --- ...le_providers_based_on_linked_credentials-agent=githuber.json | 2 ++ ...e_providers_based_on_linked_credentials-agent=multiuser.json | 2 ++ ...kable_providers_based_on_linked_credentials-agent=oryer.json | 2 ++ ...le_providers_based_on_linked_credentials-agent=password.json | 2 ++ ...egy-suite=link-case=should_link_a_connection-flow=fetch.json | 2 ++ ...-suite=link-case=should_link_a_connection-flow=original.json | 2 ++ ...nection_even_if_user_does_not_have_oidc_credentials_yet.json | 2 ++ ...e_able_to_unlink_a_connection_not_yet_linked-flow=fetch.json | 2 ++ ...be_able_to_unlink_an_non-existing_connection-flow=fetch.json | 2 ++ ...able_to_unlink_the_last_remaining_connection-flow=fetch.json | 2 ++ selfservice/strategy/password/registration_test.go | 2 ++ ...raits-description=hydrate_the_proper_fields-type=api#01.json | 2 ++ ...gyTraits-description=hydrate_the_proper_fields-type=api.json | 2 ++ ...aits-description=hydrate_the_proper_fields-type=browser.json | 2 ++ ...on_does_not_exist_when_passwordless_is_disabled-browser.json | 2 ++ ...button_does_not_exist_when_passwordless_is_disabled-spa.json | 2 ++ .../TestRegistration-case=webauthn_button_exists-browser.json | 2 ++ .../TestRegistration-case=webauthn_button_exists-spa.json | 2 ++ 18 files changed, 36 insertions(+) diff --git a/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-case=should_adjust_linkable_providers_based_on_linked_credentials-agent=githuber.json b/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-case=should_adjust_linkable_providers_based_on_linked_credentials-agent=githuber.json index 19da7fb7f971..5fb6dea7d7db 100644 --- a/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-case=should_adjust_linkable_providers_based_on_linked_credentials-agent=githuber.json +++ b/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-case=should_adjust_linkable_providers_based_on_linked_credentials-agent=githuber.json @@ -61,6 +61,8 @@ "attributes": { "autocomplete": "new-password", "disabled": false, + "maxlength": 1024, + "minlength": 8, "name": "password", "node_type": "input", "required": true, diff --git a/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-case=should_adjust_linkable_providers_based_on_linked_credentials-agent=multiuser.json b/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-case=should_adjust_linkable_providers_based_on_linked_credentials-agent=multiuser.json index dd0dc9e5f179..86822e399e18 100644 --- a/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-case=should_adjust_linkable_providers_based_on_linked_credentials-agent=multiuser.json +++ b/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-case=should_adjust_linkable_providers_based_on_linked_credentials-agent=multiuser.json @@ -61,6 +61,8 @@ "attributes": { "autocomplete": "new-password", "disabled": false, + "maxlength": 1024, + "minlength": 8, "name": "password", "node_type": "input", "required": true, diff --git a/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-case=should_adjust_linkable_providers_based_on_linked_credentials-agent=oryer.json b/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-case=should_adjust_linkable_providers_based_on_linked_credentials-agent=oryer.json index c9b0b11c8a33..5bd74cc6659d 100644 --- a/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-case=should_adjust_linkable_providers_based_on_linked_credentials-agent=oryer.json +++ b/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-case=should_adjust_linkable_providers_based_on_linked_credentials-agent=oryer.json @@ -61,6 +61,8 @@ "attributes": { "autocomplete": "new-password", "disabled": false, + "maxlength": 1024, + "minlength": 8, "name": "password", "node_type": "input", "required": true, diff --git a/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-case=should_adjust_linkable_providers_based_on_linked_credentials-agent=password.json b/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-case=should_adjust_linkable_providers_based_on_linked_credentials-agent=password.json index 55909b7380a6..fcbf804b432a 100644 --- a/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-case=should_adjust_linkable_providers_based_on_linked_credentials-agent=password.json +++ b/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-case=should_adjust_linkable_providers_based_on_linked_credentials-agent=password.json @@ -61,6 +61,8 @@ "attributes": { "autocomplete": "new-password", "disabled": false, + "maxlength": 1024, + "minlength": 8, "name": "password", "node_type": "input", "required": true, diff --git a/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-suite=link-case=should_link_a_connection-flow=fetch.json b/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-suite=link-case=should_link_a_connection-flow=fetch.json index b775cb07f8b3..7d567598f996 100644 --- a/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-suite=link-case=should_link_a_connection-flow=fetch.json +++ b/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-suite=link-case=should_link_a_connection-flow=fetch.json @@ -61,6 +61,8 @@ "attributes": { "autocomplete": "new-password", "disabled": false, + "maxlength": 1024, + "minlength": 8, "name": "password", "node_type": "input", "required": true, diff --git a/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-suite=link-case=should_link_a_connection-flow=original.json b/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-suite=link-case=should_link_a_connection-flow=original.json index 19da7fb7f971..5fb6dea7d7db 100644 --- a/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-suite=link-case=should_link_a_connection-flow=original.json +++ b/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-suite=link-case=should_link_a_connection-flow=original.json @@ -61,6 +61,8 @@ "attributes": { "autocomplete": "new-password", "disabled": false, + "maxlength": 1024, + "minlength": 8, "name": "password", "node_type": "input", "required": true, diff --git a/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-suite=link-case=should_link_a_connection_even_if_user_does_not_have_oidc_credentials_yet.json b/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-suite=link-case=should_link_a_connection_even_if_user_does_not_have_oidc_credentials_yet.json index 1763aae80238..ad948dc9829b 100644 --- a/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-suite=link-case=should_link_a_connection_even_if_user_does_not_have_oidc_credentials_yet.json +++ b/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-suite=link-case=should_link_a_connection_even_if_user_does_not_have_oidc_credentials_yet.json @@ -61,6 +61,8 @@ "attributes": { "autocomplete": "new-password", "disabled": false, + "maxlength": 1024, + "minlength": 8, "name": "password", "node_type": "input", "required": true, diff --git a/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-suite=unlink-case=should_not_be_able_to_unlink_a_connection_not_yet_linked-flow=fetch.json b/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-suite=unlink-case=should_not_be_able_to_unlink_a_connection_not_yet_linked-flow=fetch.json index 19da7fb7f971..5fb6dea7d7db 100644 --- a/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-suite=unlink-case=should_not_be_able_to_unlink_a_connection_not_yet_linked-flow=fetch.json +++ b/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-suite=unlink-case=should_not_be_able_to_unlink_a_connection_not_yet_linked-flow=fetch.json @@ -61,6 +61,8 @@ "attributes": { "autocomplete": "new-password", "disabled": false, + "maxlength": 1024, + "minlength": 8, "name": "password", "node_type": "input", "required": true, diff --git a/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-suite=unlink-case=should_not_be_able_to_unlink_an_non-existing_connection-flow=fetch.json b/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-suite=unlink-case=should_not_be_able_to_unlink_an_non-existing_connection-flow=fetch.json index 19da7fb7f971..5fb6dea7d7db 100644 --- a/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-suite=unlink-case=should_not_be_able_to_unlink_an_non-existing_connection-flow=fetch.json +++ b/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-suite=unlink-case=should_not_be_able_to_unlink_an_non-existing_connection-flow=fetch.json @@ -61,6 +61,8 @@ "attributes": { "autocomplete": "new-password", "disabled": false, + "maxlength": 1024, + "minlength": 8, "name": "password", "node_type": "input", "required": true, diff --git a/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-suite=unlink-case=should_not_be_able_to_unlink_the_last_remaining_connection-flow=fetch.json b/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-suite=unlink-case=should_not_be_able_to_unlink_the_last_remaining_connection-flow=fetch.json index c9b0b11c8a33..5bd74cc6659d 100644 --- a/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-suite=unlink-case=should_not_be_able_to_unlink_the_last_remaining_connection-flow=fetch.json +++ b/selfservice/strategy/oidc/.snapshots/TestSettingsStrategy-suite=unlink-case=should_not_be_able_to_unlink_the_last_remaining_connection-flow=fetch.json @@ -61,6 +61,8 @@ "attributes": { "autocomplete": "new-password", "disabled": false, + "maxlength": 1024, + "minlength": 8, "name": "password", "node_type": "input", "required": true, diff --git a/selfservice/strategy/password/registration_test.go b/selfservice/strategy/password/registration_test.go index ddcf26a20883..a3c87cbefbf6 100644 --- a/selfservice/strategy/password/registration_test.go +++ b/selfservice/strategy/password/registration_test.go @@ -667,6 +667,8 @@ func TestRegistration(t *testing.T) { node.NewInputField("traits.username", nil, node.PasswordGroup, node.InputAttributeTypeText), node.NewInputField("password", nil, node.PasswordGroup, node.InputAttributeTypePassword, node.WithRequiredInputAttribute, node.WithInputAttributes(func(a *node.InputAttributes) { a.Autocomplete = node.InputAttributeAutocompleteNewPassword + a.MinLength = conf.PasswordPolicyConfig(ctx).MinPasswordLength + a.MaxLength = conf.PasswordPolicyConfig(ctx).MaxPasswordLength })).WithMetaLabel(text.NewInfoNodeInputPassword()), node.NewInputField("traits.bar", nil, node.PasswordGroup, node.InputAttributeTypeText), node.NewInputField("method", "password", node.PasswordGroup, node.InputAttributeTypeSubmit).WithMetaLabel(text.NewInfoRegistration()), diff --git a/selfservice/strategy/profile/.snapshots/TestStrategyTraits-description=hydrate_the_proper_fields-type=api#01.json b/selfservice/strategy/profile/.snapshots/TestStrategyTraits-description=hydrate_the_proper_fields-type=api#01.json index d6665e756663..70ba7f442b9a 100644 --- a/selfservice/strategy/profile/.snapshots/TestStrategyTraits-description=hydrate_the_proper_fields-type=api#01.json +++ b/selfservice/strategy/profile/.snapshots/TestStrategyTraits-description=hydrate_the_proper_fields-type=api#01.json @@ -114,6 +114,8 @@ "attributes": { "autocomplete": "new-password", "disabled": false, + "maxlength": 1024, + "minlength": 8, "name": "password", "node_type": "input", "required": true, diff --git a/selfservice/strategy/profile/.snapshots/TestStrategyTraits-description=hydrate_the_proper_fields-type=api.json b/selfservice/strategy/profile/.snapshots/TestStrategyTraits-description=hydrate_the_proper_fields-type=api.json index d6665e756663..70ba7f442b9a 100644 --- a/selfservice/strategy/profile/.snapshots/TestStrategyTraits-description=hydrate_the_proper_fields-type=api.json +++ b/selfservice/strategy/profile/.snapshots/TestStrategyTraits-description=hydrate_the_proper_fields-type=api.json @@ -114,6 +114,8 @@ "attributes": { "autocomplete": "new-password", "disabled": false, + "maxlength": 1024, + "minlength": 8, "name": "password", "node_type": "input", "required": true, diff --git a/selfservice/strategy/profile/.snapshots/TestStrategyTraits-description=hydrate_the_proper_fields-type=browser.json b/selfservice/strategy/profile/.snapshots/TestStrategyTraits-description=hydrate_the_proper_fields-type=browser.json index d6665e756663..70ba7f442b9a 100644 --- a/selfservice/strategy/profile/.snapshots/TestStrategyTraits-description=hydrate_the_proper_fields-type=browser.json +++ b/selfservice/strategy/profile/.snapshots/TestStrategyTraits-description=hydrate_the_proper_fields-type=browser.json @@ -114,6 +114,8 @@ "attributes": { "autocomplete": "new-password", "disabled": false, + "maxlength": 1024, + "minlength": 8, "name": "password", "node_type": "input", "required": true, diff --git a/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_does_not_exist_when_passwordless_is_disabled-browser.json b/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_does_not_exist_when_passwordless_is_disabled-browser.json index cd42a6256ce0..36f9cabbfeb9 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_does_not_exist_when_passwordless_is_disabled-browser.json +++ b/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_does_not_exist_when_passwordless_is_disabled-browser.json @@ -29,6 +29,8 @@ "attributes": { "autocomplete": "new-password", "disabled": false, + "maxlength": 1024, + "minlength": 8, "name": "password", "node_type": "input", "required": true, diff --git a/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_does_not_exist_when_passwordless_is_disabled-spa.json b/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_does_not_exist_when_passwordless_is_disabled-spa.json index cd42a6256ce0..36f9cabbfeb9 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_does_not_exist_when_passwordless_is_disabled-spa.json +++ b/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_does_not_exist_when_passwordless_is_disabled-spa.json @@ -29,6 +29,8 @@ "attributes": { "autocomplete": "new-password", "disabled": false, + "maxlength": 1024, + "minlength": 8, "name": "password", "node_type": "input", "required": true, diff --git a/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-browser.json b/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-browser.json index f95c0ade36aa..8242108ee80d 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-browser.json +++ b/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-browser.json @@ -108,6 +108,8 @@ "attributes": { "autocomplete": "new-password", "disabled": false, + "maxlength": 1024, + "minlength": 8, "name": "password", "node_type": "input", "required": true, diff --git a/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-spa.json b/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-spa.json index f95c0ade36aa..8242108ee80d 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-spa.json +++ b/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-spa.json @@ -108,6 +108,8 @@ "attributes": { "autocomplete": "new-password", "disabled": false, + "maxlength": 1024, + "minlength": 8, "name": "password", "node_type": "input", "required": true,