From 11b5a735518db7596b49f022ade62b41ce0218cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20M=C3=B6hlmann?= Date: Fri, 4 Aug 2023 18:16:27 +0300 Subject: [PATCH 01/38] fix: trigger session by id in verifySessionToken (#6325) --- .../authz/repository/eventsourcing/eventstore/token_verifier.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/authz/repository/eventsourcing/eventstore/token_verifier.go b/internal/authz/repository/eventsourcing/eventstore/token_verifier.go index 1e2153863a..5563db37dc 100644 --- a/internal/authz/repository/eventsourcing/eventstore/token_verifier.go +++ b/internal/authz/repository/eventsourcing/eventstore/token_verifier.go @@ -147,7 +147,7 @@ func (repo *TokenVerifierRepo) verifySessionToken(ctx context.Context, sessionID ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - session, err := repo.Query.SessionByID(ctx, false, sessionID, token) + session, err := repo.Query.SessionByID(ctx, true, sessionID, token) if err != nil { return "", "", "", err } From 3c7b603650531e9cf69b70c93b38cd163cf12f52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20M=C3=B6hlmann?= Date: Fri, 4 Aug 2023 19:17:16 +0300 Subject: [PATCH 02/38] fix: always update the timestamp in trigger (#6326) * always reset timestamp * re-enable test --- .../api/grpc/management/user_integration_test.go | 12 +++++++++--- internal/eventstore/handler/handler_projection.go | 6 ++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/internal/api/grpc/management/user_integration_test.go b/internal/api/grpc/management/user_integration_test.go index c1682a5ccc..ab1e149bda 100644 --- a/internal/api/grpc/management/user_integration_test.go +++ b/internal/api/grpc/management/user_integration_test.go @@ -5,11 +5,20 @@ package management_test import ( "context" "os" + "strconv" + "strings" "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "golang.org/x/text/language" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "github.com/zitadel/zitadel/internal/integration" "github.com/zitadel/zitadel/pkg/grpc/management" + "github.com/zitadel/zitadel/pkg/grpc/user" ) var ( @@ -38,8 +47,6 @@ func TestMain(m *testing.M) { // This test Imports a user and directly tries to Get it, 100 times in a loop. // When the bug still existed, some (between 1 to 7 out of 100) // Get calls would return a Not Found error. - -/* Test disabled because it breaks the pipeline. func TestImport_and_Get(t *testing.T) { const N = 100 var misses int @@ -84,4 +91,3 @@ func TestImport_and_Get(t *testing.T) { } assert.Zerof(t, misses, "Not Found errors %d out of %d", misses, N) } -*/ diff --git a/internal/eventstore/handler/handler_projection.go b/internal/eventstore/handler/handler_projection.go index baab2d3a61..dcd24b3d7b 100644 --- a/internal/eventstore/handler/handler_projection.go +++ b/internal/eventstore/handler/handler_projection.go @@ -140,8 +140,11 @@ func (h *ProjectionHandler) Trigger(ctx context.Context, instances ...string) co // by calling FetchEvents and Process until the amount of events is smaller than the BulkLimit. // If a bulk action was executed, the call timestamp in context will be reset for subsequent queries. // The returned context is never nil. It is either the original context or an updated context. -func (h *ProjectionHandler) TriggerErr(ctx context.Context, instances ...string) (context.Context, error) { +func (h *ProjectionHandler) TriggerErr(ctx context.Context, instances ...string) (outCtx context.Context, err error) { instances = triggerInstances(ctx, instances) + defer func() { + outCtx = call.ResetTimestamp(ctx) + }() for { events, hasLimitExceeded, err := h.FetchEvents(ctx, instances...) if err != nil { @@ -151,7 +154,6 @@ func (h *ProjectionHandler) TriggerErr(ctx context.Context, instances ...string) return ctx, nil } _, err = h.Process(ctx, events...) - ctx = call.ResetTimestamp(ctx) if err != nil { return ctx, err } From d937ee3dda0620cf764d7404d23105cd573411c9 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Fri, 4 Aug 2023 20:12:44 +0200 Subject: [PATCH 03/38] fix: add texts after template reset (#6237) * fix: add texts after template reset * fix unit tests --- internal/command/custom_login_text.go | 444 +++++++++--------- .../command/org_custom_login_text_test.go | 6 + 2 files changed, 228 insertions(+), 222 deletions(-) diff --git a/internal/command/custom_login_text.go b/internal/command/custom_login_text.go index 21147c616d..bc530f00cf 100644 --- a/internal/command/custom_login_text.go +++ b/internal/command/custom_login_text.go @@ -52,35 +52,35 @@ func (c *Commands) createAllLoginTextEvents(ctx context.Context, agg *eventstore func (c *Commands) createSelectLoginTextEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySelectAccountTitle, existingText.SelectAccountTitle, text.SelectAccount.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySelectAccountTitle, existingText.SelectAccountTitle, text.SelectAccount.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySelectAccountDescription, existingText.SelectAccountDescription, text.SelectAccount.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySelectAccountDescription, existingText.SelectAccountDescription, text.SelectAccount.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySelectAccountTitleLinkingProcess, existingText.SelectAccountTitleLinkingProcess, text.SelectAccount.TitleLinking, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySelectAccountTitleLinkingProcess, existingText.SelectAccountTitleLinkingProcess, text.SelectAccount.TitleLinking, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySelectAccountDescriptionLinkingProcess, existingText.SelectAccountDescriptionLinkingProcess, text.SelectAccount.DescriptionLinking, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySelectAccountDescriptionLinkingProcess, existingText.SelectAccountDescriptionLinkingProcess, text.SelectAccount.DescriptionLinking, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySelectAccountOtherUser, existingText.SelectAccountOtherUser, text.SelectAccount.OtherUser, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySelectAccountOtherUser, existingText.SelectAccountOtherUser, text.SelectAccount.OtherUser, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySelectAccountSessionStateActive, existingText.SelectAccountSessionStateActive, text.SelectAccount.SessionState0, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySelectAccountSessionStateActive, existingText.SelectAccountSessionStateActive, text.SelectAccount.SessionState0, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySelectAccountSessionStateInactive, existingText.SelectAccountSessionStateInactive, text.SelectAccount.SessionState1, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySelectAccountSessionStateInactive, existingText.SelectAccountSessionStateInactive, text.SelectAccount.SessionState1, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySelectAccountUserMustBeMemberOfOrg, existingText.SelectAccountUserMustBeMemberOfOrg, text.SelectAccount.MustBeMemberOfOrg, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySelectAccountUserMustBeMemberOfOrg, existingText.SelectAccountUserMustBeMemberOfOrg, text.SelectAccount.MustBeMemberOfOrg, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -89,47 +89,47 @@ func (c *Commands) createSelectLoginTextEvents(ctx context.Context, agg *eventst func (c *Commands) createLoginTextEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginTitle, existingText.LoginTitle, text.Login.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginTitle, existingText.LoginTitle, text.Login.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginDescription, existingText.LoginDescription, text.Login.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginDescription, existingText.LoginDescription, text.Login.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginTitleLinkingProcess, existingText.LoginTitleLinkingProcess, text.Login.TitleLinking, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginTitleLinkingProcess, existingText.LoginTitleLinkingProcess, text.Login.TitleLinking, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginDescriptionLinkingProcess, existingText.LoginDescriptionLinkingProcess, text.Login.DescriptionLinking, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginDescriptionLinkingProcess, existingText.LoginDescriptionLinkingProcess, text.Login.DescriptionLinking, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginNameLabel, existingText.LoginNameLabel, text.Login.LoginNameLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginNameLabel, existingText.LoginNameLabel, text.Login.LoginNameLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginUsernamePlaceHolder, existingText.LoginUsernamePlaceholder, text.Login.UsernamePlaceholder, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginUsernamePlaceHolder, existingText.LoginUsernamePlaceholder, text.Login.UsernamePlaceholder, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginLoginnamePlaceHolder, existingText.LoginLoginnamePlaceholder, text.Login.LoginnamePlaceholder, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginLoginnamePlaceHolder, existingText.LoginLoginnamePlaceholder, text.Login.LoginnamePlaceholder, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginRegisterButtonText, existingText.LoginRegisterButtonText, text.Login.RegisterButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginRegisterButtonText, existingText.LoginRegisterButtonText, text.Login.RegisterButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginNextButtonText, existingText.LoginNextButtonText, text.Login.NextButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginNextButtonText, existingText.LoginNextButtonText, text.Login.NextButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginExternalUserDescription, existingText.LoginExternalUserDescription, text.Login.ExternalUserDescription, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginExternalUserDescription, existingText.LoginExternalUserDescription, text.Login.ExternalUserDescription, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginUserMustBeMemberOfOrg, existingText.LoginUserMustBeMemberOfOrg, text.Login.MustBeMemberOfOrg, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginUserMustBeMemberOfOrg, existingText.LoginUserMustBeMemberOfOrg, text.Login.MustBeMemberOfOrg, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -138,51 +138,51 @@ func (c *Commands) createLoginTextEvents(ctx context.Context, agg *eventstore.Ag func (c *Commands) createPasswordTextEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordTitle, existingText.PasswordTitle, text.Password.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordTitle, existingText.PasswordTitle, text.Password.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordDescription, existingText.PasswordDescription, text.Password.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordDescription, existingText.PasswordDescription, text.Password.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordLabel, existingText.PasswordLabel, text.Password.PasswordLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordLabel, existingText.PasswordLabel, text.Password.PasswordLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordResetLinkText, existingText.PasswordResetLinkText, text.Password.ResetLinkText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordResetLinkText, existingText.PasswordResetLinkText, text.Password.ResetLinkText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordBackButtonText, existingText.PasswordBackButtonText, text.Password.BackButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordBackButtonText, existingText.PasswordBackButtonText, text.Password.BackButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordNextButtonText, existingText.PasswordNextButtonText, text.Password.NextButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordNextButtonText, existingText.PasswordNextButtonText, text.Password.NextButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordMinLength, existingText.PasswordMinLength, text.Password.MinLength, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordMinLength, existingText.PasswordMinLength, text.Password.MinLength, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordHasUppercase, existingText.PasswordHasUppercase, text.Password.HasUppercase, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordHasUppercase, existingText.PasswordHasUppercase, text.Password.HasUppercase, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordHasLowercase, existingText.PasswordHasLowercase, text.Password.HasLowercase, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordHasLowercase, existingText.PasswordHasLowercase, text.Password.HasLowercase, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordHasNumber, existingText.PasswordHasNumber, text.Password.HasNumber, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordHasNumber, existingText.PasswordHasNumber, text.Password.HasNumber, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordHasSymbol, existingText.PasswordHasSymbol, text.Password.HasSymbol, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordHasSymbol, existingText.PasswordHasSymbol, text.Password.HasSymbol, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordConfirmation, existingText.PasswordConfirmation, text.Password.Confirmation, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordConfirmation, existingText.PasswordConfirmation, text.Password.Confirmation, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -191,23 +191,23 @@ func (c *Commands) createPasswordTextEvents(ctx context.Context, agg *eventstore func (c *Commands) createUsernameChangeTextEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyUsernameChangeTitle, existingText.UsernameChangeTitle, text.UsernameChange.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyUsernameChangeTitle, existingText.UsernameChangeTitle, text.UsernameChange.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyUsernameChangeDescription, existingText.UsernameChangeDescription, text.UsernameChange.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyUsernameChangeDescription, existingText.UsernameChangeDescription, text.UsernameChange.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyUsernameChangeUsernameLabel, existingText.UsernameChangeUsernameLabel, text.UsernameChange.UsernameLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyUsernameChangeUsernameLabel, existingText.UsernameChangeUsernameLabel, text.UsernameChange.UsernameLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyUsernameChangeCancelButtonText, existingText.UsernameChangeCancelButtonText, text.UsernameChange.CancelButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyUsernameChangeCancelButtonText, existingText.UsernameChangeCancelButtonText, text.UsernameChange.CancelButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyUsernameChangeNextButtonText, existingText.UsernameChangeNextButtonText, text.UsernameChange.NextButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyUsernameChangeNextButtonText, existingText.UsernameChangeNextButtonText, text.UsernameChange.NextButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -216,15 +216,15 @@ func (c *Commands) createUsernameChangeTextEvents(ctx context.Context, agg *even func (c *Commands) createUsernameChangeDoneTextEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyUsernameChangeDoneTitle, existingText.UsernameChangeDoneTitle, text.UsernameChangeDone.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyUsernameChangeDoneTitle, existingText.UsernameChangeDoneTitle, text.UsernameChangeDone.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyUsernameChangeDoneDescription, existingText.UsernameChangeDoneDescription, text.UsernameChangeDone.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyUsernameChangeDoneDescription, existingText.UsernameChangeDoneDescription, text.UsernameChangeDone.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyUsernameChangeDoneNextButtonText, existingText.UsernameChangeDoneNextButtonText, text.UsernameChangeDone.NextButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyUsernameChangeDoneNextButtonText, existingText.UsernameChangeDoneNextButtonText, text.UsernameChangeDone.NextButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -233,31 +233,31 @@ func (c *Commands) createUsernameChangeDoneTextEvents(ctx context.Context, agg * func (c *Commands) createPasswordInitTextEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordTitle, existingText.InitPasswordTitle, text.InitPassword.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordTitle, existingText.InitPasswordTitle, text.InitPassword.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordDescription, existingText.InitPasswordDescription, text.InitPassword.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordDescription, existingText.InitPasswordDescription, text.InitPassword.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordCodeLabel, existingText.InitPasswordCodeLabel, text.InitPassword.CodeLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordCodeLabel, existingText.InitPasswordCodeLabel, text.InitPassword.CodeLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordNewPasswordLabel, existingText.InitPasswordNewPasswordLabel, text.InitPassword.NewPasswordLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordNewPasswordLabel, existingText.InitPasswordNewPasswordLabel, text.InitPassword.NewPasswordLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordNewPasswordConfirmLabel, existingText.InitPasswordNewPasswordConfirmLabel, text.InitPassword.NewPasswordConfirmLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordNewPasswordConfirmLabel, existingText.InitPasswordNewPasswordConfirmLabel, text.InitPassword.NewPasswordConfirmLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordNextButtonText, existingText.InitPasswordNextButtonText, text.InitPassword.NextButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordNextButtonText, existingText.InitPasswordNextButtonText, text.InitPassword.NextButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordResendButtonText, existingText.InitPasswordResendButtonText, text.InitPassword.ResendButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordResendButtonText, existingText.InitPasswordResendButtonText, text.InitPassword.ResendButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -266,19 +266,19 @@ func (c *Commands) createPasswordInitTextEvents(ctx context.Context, agg *events func (c *Commands) createPasswordInitDoneTextEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordDoneTitle, existingText.InitPasswordDoneTitle, text.InitPasswordDone.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordDoneTitle, existingText.InitPasswordDoneTitle, text.InitPasswordDone.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordDoneDescription, existingText.InitPasswordDoneDescription, text.InitPasswordDone.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordDoneDescription, existingText.InitPasswordDoneDescription, text.InitPasswordDone.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordDoneNextButtonText, existingText.InitPasswordDoneNextButtonText, text.InitPasswordDone.NextButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordDoneNextButtonText, existingText.InitPasswordDoneNextButtonText, text.InitPasswordDone.NextButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordDoneCancelButtonText, existingText.InitPasswordDoneCancelButtonText, text.InitPasswordDone.CancelButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordDoneCancelButtonText, existingText.InitPasswordDoneCancelButtonText, text.InitPasswordDone.CancelButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -287,23 +287,23 @@ func (c *Commands) createPasswordInitDoneTextEvents(ctx context.Context, agg *ev func (c *Commands) createEmailVerificationTextEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationTitle, existingText.EmailVerificationTitle, text.EmailVerification.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationTitle, existingText.EmailVerificationTitle, text.EmailVerification.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationDescription, existingText.EmailVerificationDescription, text.EmailVerification.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationDescription, existingText.EmailVerificationDescription, text.EmailVerification.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationCodeLabel, existingText.EmailVerificationCodeLabel, text.EmailVerification.CodeLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationCodeLabel, existingText.EmailVerificationCodeLabel, text.EmailVerification.CodeLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationNextButtonText, existingText.EmailVerificationNextButtonText, text.EmailVerification.NextButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationNextButtonText, existingText.EmailVerificationNextButtonText, text.EmailVerification.NextButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationResendButtonText, existingText.EmailVerificationResendButtonText, text.EmailVerification.ResendButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationResendButtonText, existingText.EmailVerificationResendButtonText, text.EmailVerification.ResendButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -312,23 +312,23 @@ func (c *Commands) createEmailVerificationTextEvents(ctx context.Context, agg *e func (c *Commands) createEmailVerificationDoneTextEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationDoneTitle, existingText.EmailVerificationDoneTitle, text.EmailVerificationDone.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationDoneTitle, existingText.EmailVerificationDoneTitle, text.EmailVerificationDone.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationDoneDescription, existingText.EmailVerificationDoneDescription, text.EmailVerificationDone.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationDoneDescription, existingText.EmailVerificationDoneDescription, text.EmailVerificationDone.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationDoneNextButtonText, existingText.EmailVerificationDoneNextButtonText, text.EmailVerificationDone.NextButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationDoneNextButtonText, existingText.EmailVerificationDoneNextButtonText, text.EmailVerificationDone.NextButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationDoneCancelButtonText, existingText.EmailVerificationDoneCancelButtonText, text.EmailVerificationDone.CancelButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationDoneCancelButtonText, existingText.EmailVerificationDoneCancelButtonText, text.EmailVerificationDone.CancelButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationDoneLoginButtonText, existingText.EmailVerificationDoneLoginButtonText, text.EmailVerificationDone.LoginButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationDoneLoginButtonText, existingText.EmailVerificationDoneLoginButtonText, text.EmailVerificationDone.LoginButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -337,31 +337,31 @@ func (c *Commands) createEmailVerificationDoneTextEvents(ctx context.Context, ag func (c *Commands) createInitUserEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitializeUserTitle, existingText.InitializeTitle, text.InitUser.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitializeUserTitle, existingText.InitializeTitle, text.InitUser.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitializeUserDescription, existingText.InitializeDescription, text.InitUser.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitializeUserDescription, existingText.InitializeDescription, text.InitUser.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitializeUserCodeLabel, existingText.InitializeCodeLabel, text.InitUser.CodeLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitializeUserCodeLabel, existingText.InitializeCodeLabel, text.InitUser.CodeLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitializeUserNewPasswordLabel, existingText.InitializeNewPassword, text.InitUser.NewPasswordLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitializeUserNewPasswordLabel, existingText.InitializeNewPassword, text.InitUser.NewPasswordLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitializeUserNewPasswordConfirmLabel, existingText.InitializeNewPasswordConfirm, text.InitUser.NewPasswordConfirmLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitializeUserNewPasswordConfirmLabel, existingText.InitializeNewPasswordConfirm, text.InitUser.NewPasswordConfirmLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitializeUserResendButtonText, existingText.InitializeResendButtonText, text.InitUser.ResendButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitializeUserResendButtonText, existingText.InitializeResendButtonText, text.InitUser.ResendButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitializeUserNextButtonText, existingText.InitializeNextButtonText, text.InitUser.NextButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitializeUserNextButtonText, existingText.InitializeNextButtonText, text.InitUser.NextButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -370,19 +370,19 @@ func (c *Commands) createInitUserEvents(ctx context.Context, agg *eventstore.Agg func (c *Commands) createInitUserDoneEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitUserDoneTitle, existingText.InitializeDoneTitle, text.InitUserDone.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitUserDoneTitle, existingText.InitializeDoneTitle, text.InitUserDone.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitUserDoneDescription, existingText.InitializeDoneDescription, text.InitUserDone.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitUserDoneDescription, existingText.InitializeDoneDescription, text.InitUserDone.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitUserDoneCancelButtonText, existingText.InitializeDoneAbortButtonText, text.InitUserDone.CancelButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitUserDoneCancelButtonText, existingText.InitializeDoneAbortButtonText, text.InitUserDone.CancelButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitUserDoneNextButtonText, existingText.InitializeDoneNextButtonText, text.InitUserDone.NextButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitUserDoneNextButtonText, existingText.InitializeDoneNextButtonText, text.InitUserDone.NextButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -391,27 +391,27 @@ func (c *Commands) createInitUserDoneEvents(ctx context.Context, agg *eventstore func (c *Commands) createInitMFAPromptEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAPromptTitle, existingText.InitMFAPromptTitle, text.InitMFAPrompt.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAPromptTitle, existingText.InitMFAPromptTitle, text.InitMFAPrompt.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAPromptDescription, existingText.InitMFAPromptDescription, text.InitMFAPrompt.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAPromptDescription, existingText.InitMFAPromptDescription, text.InitMFAPrompt.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAPromptOTPOption, existingText.InitMFAPromptOTPOption, text.InitMFAPrompt.Provider0, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAPromptOTPOption, existingText.InitMFAPromptOTPOption, text.InitMFAPrompt.Provider0, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAPromptU2FOption, existingText.InitMFAPromptU2FOption, text.InitMFAPrompt.Provider1, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAPromptU2FOption, existingText.InitMFAPromptU2FOption, text.InitMFAPrompt.Provider1, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAPromptSkipButtonText, existingText.InitMFAPromptSkipButtonText, text.InitMFAPrompt.SkipButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAPromptSkipButtonText, existingText.InitMFAPromptSkipButtonText, text.InitMFAPrompt.SkipButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAPromptNextButtonText, existingText.InitMFAPromptNextButtonText, text.InitMFAPrompt.NextButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAPromptNextButtonText, existingText.InitMFAPromptNextButtonText, text.InitMFAPrompt.NextButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -420,31 +420,31 @@ func (c *Commands) createInitMFAPromptEvents(ctx context.Context, agg *eventstor func (c *Commands) createInitMFAOTPEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAOTPTitle, existingText.InitMFAOTPTitle, text.InitMFAOTP.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAOTPTitle, existingText.InitMFAOTPTitle, text.InitMFAOTP.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAOTPDescription, existingText.InitMFAOTPDescription, text.InitMFAOTP.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAOTPDescription, existingText.InitMFAOTPDescription, text.InitMFAOTP.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAOTPDescriptionOTP, existingText.InitMFAOTPDescriptionOTP, text.InitMFAOTP.OTPDescription, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAOTPDescriptionOTP, existingText.InitMFAOTPDescriptionOTP, text.InitMFAOTP.OTPDescription, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAOTPSecretLabel, existingText.InitMFAOTPSecretLabel, text.InitMFAOTP.SecretLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAOTPSecretLabel, existingText.InitMFAOTPSecretLabel, text.InitMFAOTP.SecretLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAOTPCodeLabel, existingText.InitMFAOTPCodeLabel, text.InitMFAOTP.CodeLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAOTPCodeLabel, existingText.InitMFAOTPCodeLabel, text.InitMFAOTP.CodeLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAOTPNextButtonText, existingText.InitMFAOTPNextButtonText, text.InitMFAOTP.NextButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAOTPNextButtonText, existingText.InitMFAOTPNextButtonText, text.InitMFAOTP.NextButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAOTPCancelButtonText, existingText.InitMFAOTPCancelButtonText, text.InitMFAOTP.CancelButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAOTPCancelButtonText, existingText.InitMFAOTPCancelButtonText, text.InitMFAOTP.CancelButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -453,27 +453,27 @@ func (c *Commands) createInitMFAOTPEvents(ctx context.Context, agg *eventstore.A func (c *Commands) createInitMFAU2FEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAU2FTitle, existingText.InitMFAU2FTitle, text.InitMFAU2F.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAU2FTitle, existingText.InitMFAU2FTitle, text.InitMFAU2F.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAU2FDescription, existingText.InitMFAU2FDescription, text.InitMFAU2F.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAU2FDescription, existingText.InitMFAU2FDescription, text.InitMFAU2F.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAU2FTokenNameLabel, existingText.InitMFAU2FTokenNameLabel, text.InitMFAU2F.TokenNameLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAU2FTokenNameLabel, existingText.InitMFAU2FTokenNameLabel, text.InitMFAU2F.TokenNameLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAU2FRegisterTokenButtonText, existingText.InitMFAU2FRegisterTokenButtonText, text.InitMFAU2F.RegisterTokenButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAU2FRegisterTokenButtonText, existingText.InitMFAU2FRegisterTokenButtonText, text.InitMFAU2F.RegisterTokenButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAU2FNotSupported, existingText.InitMFAU2FNotSupported, text.InitMFAU2F.NotSupported, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAU2FNotSupported, existingText.InitMFAU2FNotSupported, text.InitMFAU2F.NotSupported, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAU2FErrorRetry, existingText.InitMFAU2FErrorRetry, text.InitMFAU2F.ErrorRetry, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAU2FErrorRetry, existingText.InitMFAU2FErrorRetry, text.InitMFAU2F.ErrorRetry, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -482,19 +482,19 @@ func (c *Commands) createInitMFAU2FEvents(ctx context.Context, agg *eventstore.A func (c *Commands) createInitMFADoneEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFADoneTitle, existingText.InitMFADoneTitle, text.InitMFADone.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFADoneTitle, existingText.InitMFADoneTitle, text.InitMFADone.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFADoneDescription, existingText.InitMFADoneDescription, text.InitMFADone.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFADoneDescription, existingText.InitMFADoneDescription, text.InitMFADone.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFADoneCancelButtonText, existingText.InitMFADoneAbortButtonText, text.InitMFADone.CancelButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFADoneCancelButtonText, existingText.InitMFADoneAbortButtonText, text.InitMFADone.CancelButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFADoneNextButtonText, existingText.InitMFADoneNextButtonText, text.InitMFADone.NextButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFADoneNextButtonText, existingText.InitMFADoneNextButtonText, text.InitMFADone.NextButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -503,15 +503,15 @@ func (c *Commands) createInitMFADoneEvents(ctx context.Context, agg *eventstore. func (c *Commands) crateMFAProviderEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyMFAProvidersChooseOther, existingText.MFAProvidersChooseOther, text.MFAProvider.ChooseOther, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyMFAProvidersChooseOther, existingText.MFAProvidersChooseOther, text.MFAProvider.ChooseOther, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyMFAProvidersOTP, existingText.MFAProvidersOTP, text.MFAProvider.Provider0, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyMFAProvidersOTP, existingText.MFAProvidersOTP, text.MFAProvider.Provider0, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyMFAProvidersU2F, existingText.MFAProvidersU2F, text.MFAProvider.Provider1, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyMFAProvidersU2F, existingText.MFAProvidersU2F, text.MFAProvider.Provider1, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -520,19 +520,19 @@ func (c *Commands) crateMFAProviderEvents(ctx context.Context, agg *eventstore.A func (c *Commands) createVerifyMFAOTPEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyVerifyMFAOTPTitle, existingText.VerifyMFAOTPTitle, text.VerifyMFAOTP.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyVerifyMFAOTPTitle, existingText.VerifyMFAOTPTitle, text.VerifyMFAOTP.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyVerifyMFAOTPDescription, existingText.VerifyMFAOTPDescription, text.VerifyMFAOTP.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyVerifyMFAOTPDescription, existingText.VerifyMFAOTPDescription, text.VerifyMFAOTP.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyVerifyMFAOTPCodeLabel, existingText.VerifyMFAOTPCodeLabel, text.VerifyMFAOTP.CodeLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyVerifyMFAOTPCodeLabel, existingText.VerifyMFAOTPCodeLabel, text.VerifyMFAOTP.CodeLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyVerifyMFAOTPNextButtonText, existingText.VerifyMFAOTPNextButtonText, text.VerifyMFAOTP.NextButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyVerifyMFAOTPNextButtonText, existingText.VerifyMFAOTPNextButtonText, text.VerifyMFAOTP.NextButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -541,23 +541,23 @@ func (c *Commands) createVerifyMFAOTPEvents(ctx context.Context, agg *eventstore func (c *Commands) createVerifyMFAU2FEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyVerifyMFAU2FTitle, existingText.VerifyMFAU2FTitle, text.VerifyMFAU2F.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyVerifyMFAU2FTitle, existingText.VerifyMFAU2FTitle, text.VerifyMFAU2F.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyVerifyMFAU2FDescription, existingText.VerifyMFAU2FDescription, text.VerifyMFAU2F.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyVerifyMFAU2FDescription, existingText.VerifyMFAU2FDescription, text.VerifyMFAU2F.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyVerifyMFAU2FValidateTokenText, existingText.VerifyMFAU2FValidateTokenText, text.VerifyMFAU2F.ValidateTokenButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyVerifyMFAU2FValidateTokenText, existingText.VerifyMFAU2FValidateTokenText, text.VerifyMFAU2F.ValidateTokenButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyVerifyMFAU2FNotSupported, existingText.VerifyMFAU2FNotSupported, text.VerifyMFAU2F.NotSupported, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyVerifyMFAU2FNotSupported, existingText.VerifyMFAU2FNotSupported, text.VerifyMFAU2F.NotSupported, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyVerifyMFAU2FErrorRetry, existingText.VerifyMFAU2FErrorRetry, text.VerifyMFAU2F.ErrorRetry, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyVerifyMFAU2FErrorRetry, existingText.VerifyMFAU2FErrorRetry, text.VerifyMFAU2F.ErrorRetry, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -566,27 +566,27 @@ func (c *Commands) createVerifyMFAU2FEvents(ctx context.Context, agg *eventstore func (c *Commands) createPasswordlessEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessTitle, existingText.PasswordlessTitle, text.Passwordless.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessTitle, existingText.PasswordlessTitle, text.Passwordless.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessDescription, existingText.PasswordlessDescription, text.Passwordless.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessDescription, existingText.PasswordlessDescription, text.Passwordless.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessLoginWithPwButtonText, existingText.PasswordlessLoginWithPwButtonText, text.Passwordless.LoginWithPwButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessLoginWithPwButtonText, existingText.PasswordlessLoginWithPwButtonText, text.Passwordless.LoginWithPwButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessValidateTokenButtonText, existingText.PasswordlessValidateTokenButtonText, text.Passwordless.ValidateTokenButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessValidateTokenButtonText, existingText.PasswordlessValidateTokenButtonText, text.Passwordless.ValidateTokenButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessNotSupported, existingText.PasswordlessNotSupported, text.Passwordless.NotSupported, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessNotSupported, existingText.PasswordlessNotSupported, text.Passwordless.NotSupported, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessErrorRetry, existingText.PasswordlessErrorRetry, text.Passwordless.ErrorRetry, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessErrorRetry, existingText.PasswordlessErrorRetry, text.Passwordless.ErrorRetry, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -595,27 +595,27 @@ func (c *Commands) createPasswordlessEvents(ctx context.Context, agg *eventstore func (c *Commands) createPasswordlessRegistrationEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessRegistrationTitle, existingText.PasswordlessRegistrationTitle, text.PasswordlessRegistration.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessRegistrationTitle, existingText.PasswordlessRegistrationTitle, text.PasswordlessRegistration.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessRegistrationDescription, existingText.PasswordlessRegistrationDescription, text.PasswordlessRegistration.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessRegistrationDescription, existingText.PasswordlessRegistrationDescription, text.PasswordlessRegistration.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessRegistrationRegisterTokenButtonText, existingText.PasswordlessRegistrationRegisterTokenButtonText, text.PasswordlessRegistration.RegisterTokenButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessRegistrationRegisterTokenButtonText, existingText.PasswordlessRegistrationRegisterTokenButtonText, text.PasswordlessRegistration.RegisterTokenButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessRegistrationTokenNameLabel, existingText.PasswordlessRegistrationTokenNameLabel, text.PasswordlessRegistration.TokenNameLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessRegistrationTokenNameLabel, existingText.PasswordlessRegistrationTokenNameLabel, text.PasswordlessRegistration.TokenNameLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessRegistrationNotSupported, existingText.PasswordlessRegistrationNotSupported, text.PasswordlessRegistration.NotSupported, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessRegistrationNotSupported, existingText.PasswordlessRegistrationNotSupported, text.PasswordlessRegistration.NotSupported, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessRegistrationErrorRetry, existingText.PasswordlessRegistrationErrorRetry, text.PasswordlessRegistration.ErrorRetry, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessRegistrationErrorRetry, existingText.PasswordlessRegistrationErrorRetry, text.PasswordlessRegistration.ErrorRetry, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -624,27 +624,27 @@ func (c *Commands) createPasswordlessRegistrationEvents(ctx context.Context, agg func (c *Commands) createPasswordlessPromptEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessPromptTitle, existingText.PasswordlessPromptTitle, text.PasswordlessPrompt.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessPromptTitle, existingText.PasswordlessPromptTitle, text.PasswordlessPrompt.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessPromptDescription, existingText.PasswordlessPromptDescription, text.PasswordlessPrompt.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessPromptDescription, existingText.PasswordlessPromptDescription, text.PasswordlessPrompt.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessPromptDescriptionInit, existingText.PasswordlessPromptDescriptionInit, text.PasswordlessPrompt.DescriptionInit, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessPromptDescriptionInit, existingText.PasswordlessPromptDescriptionInit, text.PasswordlessPrompt.DescriptionInit, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessPromptPasswordlessButtonText, existingText.PasswordlessPromptPasswordlessButtonText, text.PasswordlessPrompt.PasswordlessButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessPromptPasswordlessButtonText, existingText.PasswordlessPromptPasswordlessButtonText, text.PasswordlessPrompt.PasswordlessButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessPromptNextButtonText, existingText.PasswordlessPromptNextButtonText, text.PasswordlessPrompt.NextButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessPromptNextButtonText, existingText.PasswordlessPromptNextButtonText, text.PasswordlessPrompt.NextButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessPromptSkipButtonText, existingText.PasswordlessPromptSkipButtonText, text.PasswordlessPrompt.SkipButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessPromptSkipButtonText, existingText.PasswordlessPromptSkipButtonText, text.PasswordlessPrompt.SkipButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -653,23 +653,23 @@ func (c *Commands) createPasswordlessPromptEvents(ctx context.Context, agg *even func (c *Commands) createPasswordlessRegistrationDoneEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessRegistrationDoneTitle, existingText.PasswordlessRegistrationDoneTitle, text.PasswordlessRegistrationDone.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessRegistrationDoneTitle, existingText.PasswordlessRegistrationDoneTitle, text.PasswordlessRegistrationDone.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessRegistrationDoneDescription, existingText.PasswordlessRegistrationDoneDescription, text.PasswordlessRegistrationDone.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessRegistrationDoneDescription, existingText.PasswordlessRegistrationDoneDescription, text.PasswordlessRegistrationDone.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessRegistrationDoneDescriptionClose, existingText.PasswordlessRegistrationDoneDescriptionClose, text.PasswordlessRegistrationDone.DescriptionClose, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessRegistrationDoneDescriptionClose, existingText.PasswordlessRegistrationDoneDescriptionClose, text.PasswordlessRegistrationDone.DescriptionClose, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessRegistrationDoneNextButtonText, existingText.PasswordlessRegistrationDoneNextButtonText, text.PasswordlessRegistrationDone.NextButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessRegistrationDoneNextButtonText, existingText.PasswordlessRegistrationDoneNextButtonText, text.PasswordlessRegistrationDone.NextButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessRegistrationDoneCancelButtonText, existingText.PasswordlessRegistrationDoneCancelButtonText, text.PasswordlessRegistrationDone.CancelButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessRegistrationDoneCancelButtonText, existingText.PasswordlessRegistrationDoneCancelButtonText, text.PasswordlessRegistrationDone.CancelButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -678,31 +678,31 @@ func (c *Commands) createPasswordlessRegistrationDoneEvents(ctx context.Context, func (c *Commands) createPasswordChangeEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeTitle, existingText.PasswordChangeTitle, text.PasswordChange.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeTitle, existingText.PasswordChangeTitle, text.PasswordChange.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeDescription, existingText.PasswordChangeDescription, text.PasswordChange.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeDescription, existingText.PasswordChangeDescription, text.PasswordChange.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeOldPasswordLabel, existingText.PasswordChangeOldPasswordLabel, text.PasswordChange.OldPasswordLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeOldPasswordLabel, existingText.PasswordChangeOldPasswordLabel, text.PasswordChange.OldPasswordLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeNewPasswordLabel, existingText.PasswordChangeNewPasswordLabel, text.PasswordChange.NewPasswordLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeNewPasswordLabel, existingText.PasswordChangeNewPasswordLabel, text.PasswordChange.NewPasswordLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeNewPasswordConfirmLabel, existingText.PasswordChangeNewPasswordConfirmLabel, text.PasswordChange.NewPasswordConfirmLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeNewPasswordConfirmLabel, existingText.PasswordChangeNewPasswordConfirmLabel, text.PasswordChange.NewPasswordConfirmLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeCancelButtonText, existingText.PasswordChangeCancelButtonText, text.PasswordChange.CancelButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeCancelButtonText, existingText.PasswordChangeCancelButtonText, text.PasswordChange.CancelButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeNextButtonText, existingText.PasswordChangeNextButtonText, text.PasswordChange.NextButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeNextButtonText, existingText.PasswordChangeNextButtonText, text.PasswordChange.NextButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -711,15 +711,15 @@ func (c *Commands) createPasswordChangeEvents(ctx context.Context, agg *eventsto func (c *Commands) createPasswordChangeDoneEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeDoneTitle, existingText.PasswordChangeDoneTitle, text.PasswordChangeDone.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeDoneTitle, existingText.PasswordChangeDoneTitle, text.PasswordChangeDone.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeDoneDescription, existingText.PasswordChangeDoneDescription, text.PasswordChangeDone.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeDoneDescription, existingText.PasswordChangeDoneDescription, text.PasswordChangeDone.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeDoneNextButtonText, existingText.PasswordChangeDoneNextButtonText, text.PasswordChangeDone.NextButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeDoneNextButtonText, existingText.PasswordChangeDoneNextButtonText, text.PasswordChangeDone.NextButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -728,15 +728,15 @@ func (c *Commands) createPasswordChangeDoneEvents(ctx context.Context, agg *even func (c *Commands) createPasswordResetDoneEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordResetDoneTitle, existingText.PasswordResetDoneTitle, text.PasswordResetDone.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordResetDoneTitle, existingText.PasswordResetDoneTitle, text.PasswordResetDone.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordResetDoneDescription, existingText.PasswordResetDoneDescription, text.PasswordResetDone.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordResetDoneDescription, existingText.PasswordResetDoneDescription, text.PasswordResetDone.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordResetDoneNextButtonText, existingText.PasswordResetDoneNextButtonText, text.PasswordResetDone.NextButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordResetDoneNextButtonText, existingText.PasswordResetDoneNextButtonText, text.PasswordResetDone.NextButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -745,23 +745,23 @@ func (c *Commands) createPasswordResetDoneEvents(ctx context.Context, agg *event func (c *Commands) createRegistrationOptionEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationOptionTitle, existingText.RegistrationOptionTitle, text.RegisterOption.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationOptionTitle, existingText.RegistrationOptionTitle, text.RegisterOption.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationOptionDescription, existingText.RegistrationOptionDescription, text.RegisterOption.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationOptionDescription, existingText.RegistrationOptionDescription, text.RegisterOption.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationOptionUserNameButtonText, existingText.RegistrationOptionUserNameButtonText, text.RegisterOption.RegisterUsernamePasswordButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationOptionUserNameButtonText, existingText.RegistrationOptionUserNameButtonText, text.RegisterOption.RegisterUsernamePasswordButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationOptionExternalLoginDescription, existingText.RegistrationOptionExternalLoginDescription, text.RegisterOption.ExternalLoginDescription, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationOptionExternalLoginDescription, existingText.RegistrationOptionExternalLoginDescription, text.RegisterOption.ExternalLoginDescription, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationOptionLoginButtonText, existingText.RegistrationOptionLoginButtonText, text.RegisterOption.LoginButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationOptionLoginButtonText, existingText.RegistrationOptionLoginButtonText, text.RegisterOption.LoginButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -770,75 +770,75 @@ func (c *Commands) createRegistrationOptionEvents(ctx context.Context, agg *even func (c *Commands) createRegistrationUserEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserTitle, existingText.RegistrationUserTitle, text.RegistrationUser.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserTitle, existingText.RegistrationUserTitle, text.RegistrationUser.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserDescription, existingText.RegistrationUserDescription, text.RegistrationUser.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserDescription, existingText.RegistrationUserDescription, text.RegistrationUser.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserDescriptionOrgRegister, existingText.RegistrationUserDescriptionOrgRegister, text.RegistrationUser.DescriptionOrgRegister, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserDescriptionOrgRegister, existingText.RegistrationUserDescriptionOrgRegister, text.RegistrationUser.DescriptionOrgRegister, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserFirstnameLabel, existingText.RegistrationUserFirstnameLabel, text.RegistrationUser.FirstnameLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserFirstnameLabel, existingText.RegistrationUserFirstnameLabel, text.RegistrationUser.FirstnameLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserLastnameLabel, existingText.RegistrationUserLastnameLabel, text.RegistrationUser.LastnameLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserLastnameLabel, existingText.RegistrationUserLastnameLabel, text.RegistrationUser.LastnameLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserEmailLabel, existingText.RegistrationUserEmailLabel, text.RegistrationUser.EmailLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserEmailLabel, existingText.RegistrationUserEmailLabel, text.RegistrationUser.EmailLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserUsernameLabel, existingText.RegistrationUserUsernameLabel, text.RegistrationUser.UsernameLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserUsernameLabel, existingText.RegistrationUserUsernameLabel, text.RegistrationUser.UsernameLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserLanguageLabel, existingText.RegistrationUserLanguageLabel, text.RegistrationUser.LanguageLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserLanguageLabel, existingText.RegistrationUserLanguageLabel, text.RegistrationUser.LanguageLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserGenderLabel, existingText.RegistrationUserGenderLabel, text.RegistrationUser.GenderLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserGenderLabel, existingText.RegistrationUserGenderLabel, text.RegistrationUser.GenderLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserPasswordLabel, existingText.RegistrationUserPasswordLabel, text.RegistrationUser.PasswordLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserPasswordLabel, existingText.RegistrationUserPasswordLabel, text.RegistrationUser.PasswordLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserPasswordConfirmLabel, existingText.RegistrationUserPasswordConfirmLabel, text.RegistrationUser.PasswordConfirmLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserPasswordConfirmLabel, existingText.RegistrationUserPasswordConfirmLabel, text.RegistrationUser.PasswordConfirmLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserTOSAndPrivacyLabel, existingText.RegistrationUserTOSAndPrivacyLabel, text.RegistrationUser.TOSAndPrivacyLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserTOSAndPrivacyLabel, existingText.RegistrationUserTOSAndPrivacyLabel, text.RegistrationUser.TOSAndPrivacyLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserTOSConfirm, existingText.RegistrationUserTOSConfirm, text.RegistrationUser.TOSConfirm, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserTOSConfirm, existingText.RegistrationUserTOSConfirm, text.RegistrationUser.TOSConfirm, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserTOSLinkText, existingText.RegistrationUserTOSLinkText, text.RegistrationUser.TOSLinkText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserTOSLinkText, existingText.RegistrationUserTOSLinkText, text.RegistrationUser.TOSLinkText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserPrivacyConfirm, existingText.RegistrationUserPrivacyConfirm, text.RegistrationUser.PrivacyConfirm, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserPrivacyConfirm, existingText.RegistrationUserPrivacyConfirm, text.RegistrationUser.PrivacyConfirm, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserPrivacyLinkText, existingText.RegistrationUserPrivacyLinkText, text.RegistrationUser.PrivacyLinkText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserPrivacyLinkText, existingText.RegistrationUserPrivacyLinkText, text.RegistrationUser.PrivacyLinkText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserNextButtonText, existingText.RegistrationUserNextButtonText, text.RegistrationUser.NextButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserNextButtonText, existingText.RegistrationUserNextButtonText, text.RegistrationUser.NextButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserBackButtonText, existingText.RegistrationUserBackButtonText, text.RegistrationUser.BackButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserBackButtonText, existingText.RegistrationUserBackButtonText, text.RegistrationUser.BackButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -847,67 +847,67 @@ func (c *Commands) createRegistrationUserEvents(ctx context.Context, agg *events func (c *Commands) createExternalRegistrationUserOverviewEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewTitle, existingText.ExternalRegistrationUserOverviewTitle, text.ExternalRegistrationUserOverview.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewTitle, existingText.ExternalRegistrationUserOverviewTitle, text.ExternalRegistrationUserOverview.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewDescription, existingText.ExternalRegistrationUserOverviewDescription, text.ExternalRegistrationUserOverview.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewDescription, existingText.ExternalRegistrationUserOverviewDescription, text.ExternalRegistrationUserOverview.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewEmailLabel, existingText.ExternalRegistrationUserOverviewEmailLabel, text.ExternalRegistrationUserOverview.EmailLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewEmailLabel, existingText.ExternalRegistrationUserOverviewEmailLabel, text.ExternalRegistrationUserOverview.EmailLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewUsernameLabel, existingText.ExternalRegistrationUserOverviewUsernameLabel, text.ExternalRegistrationUserOverview.UsernameLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewUsernameLabel, existingText.ExternalRegistrationUserOverviewUsernameLabel, text.ExternalRegistrationUserOverview.UsernameLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewFirstnameLabel, existingText.ExternalRegistrationUserOverviewFirstnameLabel, text.ExternalRegistrationUserOverview.FirstnameLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewFirstnameLabel, existingText.ExternalRegistrationUserOverviewFirstnameLabel, text.ExternalRegistrationUserOverview.FirstnameLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewLastnameLabel, existingText.ExternalRegistrationUserOverviewLastnameLabel, text.ExternalRegistrationUserOverview.LastnameLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewLastnameLabel, existingText.ExternalRegistrationUserOverviewLastnameLabel, text.ExternalRegistrationUserOverview.LastnameLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewNicknameLabel, existingText.ExternalRegistrationUserOverviewNicknameLabel, text.ExternalRegistrationUserOverview.NicknameLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewNicknameLabel, existingText.ExternalRegistrationUserOverviewNicknameLabel, text.ExternalRegistrationUserOverview.NicknameLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewLanguageLabel, existingText.ExternalRegistrationUserOverviewLanguageLabel, text.ExternalRegistrationUserOverview.LanguageLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewLanguageLabel, existingText.ExternalRegistrationUserOverviewLanguageLabel, text.ExternalRegistrationUserOverview.LanguageLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewPhoneLabel, existingText.ExternalRegistrationUserOverviewPhoneLabel, text.ExternalRegistrationUserOverview.PhoneLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewPhoneLabel, existingText.ExternalRegistrationUserOverviewPhoneLabel, text.ExternalRegistrationUserOverview.PhoneLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewTOSAndPrivacyLabel, existingText.ExternalRegistrationUserOverviewTOSAndPrivacyLabel, text.ExternalRegistrationUserOverview.TOSAndPrivacyLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewTOSAndPrivacyLabel, existingText.ExternalRegistrationUserOverviewTOSAndPrivacyLabel, text.ExternalRegistrationUserOverview.TOSAndPrivacyLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewTOSConfirm, existingText.ExternalRegistrationUserOverviewTOSConfirm, text.ExternalRegistrationUserOverview.TOSConfirm, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewTOSConfirm, existingText.ExternalRegistrationUserOverviewTOSConfirm, text.ExternalRegistrationUserOverview.TOSConfirm, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewTOSLinkText, existingText.ExternalRegistrationUserOverviewTOSLinkText, text.ExternalRegistrationUserOverview.TOSLinkText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewTOSLinkText, existingText.ExternalRegistrationUserOverviewTOSLinkText, text.ExternalRegistrationUserOverview.TOSLinkText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewPrivacyConfirm, existingText.ExternalRegistrationUserOverviewPrivacyConfirm, text.ExternalRegistrationUserOverview.PrivacyConfirm, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewPrivacyConfirm, existingText.ExternalRegistrationUserOverviewPrivacyConfirm, text.ExternalRegistrationUserOverview.PrivacyConfirm, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewPrivacyLinkText, existingText.ExternalRegistrationUserOverviewPrivacyLinkText, text.ExternalRegistrationUserOverview.PrivacyLinkText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewPrivacyLinkText, existingText.ExternalRegistrationUserOverviewPrivacyLinkText, text.ExternalRegistrationUserOverview.PrivacyLinkText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewBackButtonText, existingText.ExternalRegistrationUserOverviewBackButtonText, text.ExternalRegistrationUserOverview.BackButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewBackButtonText, existingText.ExternalRegistrationUserOverviewBackButtonText, text.ExternalRegistrationUserOverview.BackButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewNextButtonText, existingText.ExternalRegistrationUserOverviewNextButtonText, text.ExternalRegistrationUserOverview.NextButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewNextButtonText, existingText.ExternalRegistrationUserOverviewNextButtonText, text.ExternalRegistrationUserOverview.NextButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -916,63 +916,63 @@ func (c *Commands) createExternalRegistrationUserOverviewEvents(ctx context.Cont func (c *Commands) createRegistrationOrgEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgTitle, existingText.RegisterOrgTitle, text.RegistrationOrg.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgTitle, existingText.RegisterOrgTitle, text.RegistrationOrg.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgDescription, existingText.RegisterOrgDescription, text.RegistrationOrg.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgDescription, existingText.RegisterOrgDescription, text.RegistrationOrg.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgOrgNameLabel, existingText.RegisterOrgOrgNameLabel, text.RegistrationOrg.OrgNameLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgOrgNameLabel, existingText.RegisterOrgOrgNameLabel, text.RegistrationOrg.OrgNameLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgFirstnameLabel, existingText.RegisterOrgFirstnameLabel, text.RegistrationOrg.FirstnameLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgFirstnameLabel, existingText.RegisterOrgFirstnameLabel, text.RegistrationOrg.FirstnameLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgLastnameLabel, existingText.RegisterOrgLastnameLabel, text.RegistrationOrg.LastnameLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgLastnameLabel, existingText.RegisterOrgLastnameLabel, text.RegistrationOrg.LastnameLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgUsernameLabel, existingText.RegisterOrgUsernameLabel, text.RegistrationOrg.UsernameLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgUsernameLabel, existingText.RegisterOrgUsernameLabel, text.RegistrationOrg.UsernameLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgEmailLabel, existingText.RegisterOrgEmailLabel, text.RegistrationOrg.EmailLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgEmailLabel, existingText.RegisterOrgEmailLabel, text.RegistrationOrg.EmailLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgPasswordLabel, existingText.RegisterOrgPasswordLabel, text.RegistrationOrg.PasswordLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgPasswordLabel, existingText.RegisterOrgPasswordLabel, text.RegistrationOrg.PasswordLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgPasswordConfirmLabel, existingText.RegisterOrgPasswordConfirmLabel, text.RegistrationOrg.PasswordConfirmLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgPasswordConfirmLabel, existingText.RegisterOrgPasswordConfirmLabel, text.RegistrationOrg.PasswordConfirmLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgTOSAndPrivacyLabel, existingText.RegisterOrgTOSAndPrivacyLabel, text.RegistrationOrg.TOSAndPrivacyLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgTOSAndPrivacyLabel, existingText.RegisterOrgTOSAndPrivacyLabel, text.RegistrationOrg.TOSAndPrivacyLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgTOSConfirm, existingText.RegisterOrgTOSConfirm, text.RegistrationOrg.TOSConfirm, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgTOSConfirm, existingText.RegisterOrgTOSConfirm, text.RegistrationOrg.TOSConfirm, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgTOSLinkText, existingText.RegisterOrgTOSLinkText, text.RegistrationOrg.TOSLinkText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgTOSLinkText, existingText.RegisterOrgTOSLinkText, text.RegistrationOrg.TOSLinkText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgPrivacyConfirm, existingText.RegisterOrgPrivacyConfirm, text.RegistrationOrg.PrivacyConfirm, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgPrivacyConfirm, existingText.RegisterOrgPrivacyConfirm, text.RegistrationOrg.PrivacyConfirm, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgPrivacyLinkText, existingText.RegisterOrgPrivacyLinkText, text.RegistrationOrg.PrivacyLinkText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgPrivacyLinkText, existingText.RegisterOrgPrivacyLinkText, text.RegistrationOrg.PrivacyLinkText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgSaveButtonText, existingText.RegisterOrgSaveButtonText, text.RegistrationOrg.SaveButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgSaveButtonText, existingText.RegisterOrgSaveButtonText, text.RegistrationOrg.SaveButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -981,19 +981,19 @@ func (c *Commands) createRegistrationOrgEvents(ctx context.Context, agg *eventst func (c *Commands) createLinkingUserEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLinkingUserDoneTitle, existingText.LinkingUserDoneTitle, text.LinkingUsersDone.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLinkingUserDoneTitle, existingText.LinkingUserDoneTitle, text.LinkingUsersDone.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLinkingUserDoneDescription, existingText.LinkingUserDoneDescription, text.LinkingUsersDone.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLinkingUserDoneDescription, existingText.LinkingUserDoneDescription, text.LinkingUsersDone.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLinkingUserDoneCancelButtonText, existingText.LinkingUserDoneCancelButtonText, text.LinkingUsersDone.CancelButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLinkingUserDoneCancelButtonText, existingText.LinkingUserDoneCancelButtonText, text.LinkingUsersDone.CancelButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLinkingUserDoneNextButtonText, existingText.LinkingUserDoneNextButtonText, text.LinkingUsersDone.NextButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLinkingUserDoneNextButtonText, existingText.LinkingUserDoneNextButtonText, text.LinkingUsersDone.NextButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -1002,39 +1002,39 @@ func (c *Commands) createLinkingUserEvents(ctx context.Context, agg *eventstore. func (c *Commands) createExternalUserNotFoundEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalNotFoundTitle, existingText.ExternalUserNotFoundTitle, text.ExternalNotFound.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalNotFoundTitle, existingText.ExternalUserNotFoundTitle, text.ExternalNotFound.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalNotFoundDescription, existingText.ExternalUserNotFoundDescription, text.ExternalNotFound.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalNotFoundDescription, existingText.ExternalUserNotFoundDescription, text.ExternalNotFound.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalNotFoundLinkButtonText, existingText.ExternalUserNotFoundLinkButtonText, text.ExternalNotFound.LinkButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalNotFoundLinkButtonText, existingText.ExternalUserNotFoundLinkButtonText, text.ExternalNotFound.LinkButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalNotFoundAutoRegisterButtonText, existingText.ExternalUserNotFoundAutoRegisterButtonText, text.ExternalNotFound.AutoRegisterButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalNotFoundAutoRegisterButtonText, existingText.ExternalUserNotFoundAutoRegisterButtonText, text.ExternalNotFound.AutoRegisterButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalNotFoundTOSAndPrivacyLabel, existingText.ExternalUserNotFoundTOSAndPrivacyLabel, text.ExternalNotFound.TOSAndPrivacyLabel, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalNotFoundTOSAndPrivacyLabel, existingText.ExternalUserNotFoundTOSAndPrivacyLabel, text.ExternalNotFound.TOSAndPrivacyLabel, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalNotFoundTOSConfirm, existingText.ExternalUserNotFoundTOSConfirm, text.ExternalNotFound.TOSConfirm, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalNotFoundTOSConfirm, existingText.ExternalUserNotFoundTOSConfirm, text.ExternalNotFound.TOSConfirm, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalNotFoundTOSLinkText, existingText.ExternalUserNotFoundTOSLinkText, text.ExternalNotFound.TOSLinkText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalNotFoundTOSLinkText, existingText.ExternalUserNotFoundTOSLinkText, text.ExternalNotFound.TOSLinkText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalNotFoundPrivacyConfirm, existingText.ExternalUserNotFoundPrivacyConfirm, text.ExternalNotFound.PrivacyConfirm, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalNotFoundPrivacyConfirm, existingText.ExternalUserNotFoundPrivacyConfirm, text.ExternalNotFound.PrivacyConfirm, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalNotFoundPrivacyLinkText, existingText.ExternalUserNotFoundPrivacyLinkText, text.ExternalNotFound.PrivacyLinkText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalNotFoundPrivacyLinkText, existingText.ExternalUserNotFoundPrivacyLinkText, text.ExternalNotFound.PrivacyLinkText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -1043,19 +1043,19 @@ func (c *Commands) createExternalUserNotFoundEvents(ctx context.Context, agg *ev func (c *Commands) createSuccessLoginEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySuccessLoginTitle, existingText.SuccessLoginTitle, text.LoginSuccess.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySuccessLoginTitle, existingText.SuccessLoginTitle, text.LoginSuccess.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySuccessLoginAutoRedirectDescription, existingText.SuccessLoginAutoRedirectDescription, text.LoginSuccess.AutoRedirectDescription, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySuccessLoginAutoRedirectDescription, existingText.SuccessLoginAutoRedirectDescription, text.LoginSuccess.AutoRedirectDescription, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySuccessLoginRedirectedDescription, existingText.SuccessLoginRedirectedDescription, text.LoginSuccess.RedirectedDescription, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySuccessLoginRedirectedDescription, existingText.SuccessLoginRedirectedDescription, text.LoginSuccess.RedirectedDescription, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySuccessLoginNextButtonText, existingText.SuccessLoginNextButtonText, text.LoginSuccess.NextButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySuccessLoginNextButtonText, existingText.SuccessLoginNextButtonText, text.LoginSuccess.NextButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -1064,15 +1064,15 @@ func (c *Commands) createSuccessLoginEvents(ctx context.Context, agg *eventstore func (c *Commands) createLogoutDoneEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLogoutDoneTitle, existingText.LogoutDoneTitle, text.LogoutDone.Title, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLogoutDoneTitle, existingText.LogoutDoneTitle, text.LogoutDone.Title, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLogoutDoneDescription, existingText.LogoutDoneDescription, text.LogoutDone.Description, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLogoutDoneDescription, existingText.LogoutDoneDescription, text.LogoutDone.Description, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLogoutDoneLoginButtonText, existingText.LogoutDoneLoginButtonText, text.LogoutDone.LoginButtonText, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLogoutDoneLoginButtonText, existingText.LogoutDoneLoginButtonText, text.LogoutDone.LoginButtonText, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } @@ -1081,27 +1081,27 @@ func (c *Commands) createLogoutDoneEvents(ctx context.Context, agg *eventstore.A func (c *Commands) createFooterTextEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.Command { events := make([]eventstore.Command, 0) - event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyFooterTOS, existingText.FooterTOS, text.Footer.TOS, text.Language, defaultText) + event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyFooterTOS, existingText.FooterTOS, text.Footer.TOS, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyFooterPrivacyPolicy, existingText.FooterPrivacyPolicy, text.Footer.PrivacyPolicy, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyFooterPrivacyPolicy, existingText.FooterPrivacyPolicy, text.Footer.PrivacyPolicy, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyFooterHelp, existingText.FooterHelp, text.Footer.Help, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyFooterHelp, existingText.FooterHelp, text.Footer.Help, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } - event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyFooterSupportEmail, existingText.FooterSupportEmail, text.Footer.SupportEmail, text.Language, defaultText) + event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyFooterSupportEmail, existingText.FooterSupportEmail, text.Footer.SupportEmail, text.Language, defaultText, existingText.State) if event != nil { events = append(events, event) } return events } -func (c *Commands) createCustomLoginTextEvent(ctx context.Context, agg *eventstore.Aggregate, textKey, existingText, newText string, lang language.Tag, defaultText bool) eventstore.Command { - if existingText == newText { +func (c *Commands) createCustomLoginTextEvent(ctx context.Context, agg *eventstore.Aggregate, textKey, existingText, newText string, lang language.Tag, defaultText bool, policyState domain.PolicyState) eventstore.Command { + if existingText == newText && policyState == domain.PolicyStateActive { return nil } if defaultText { diff --git a/internal/command/org_custom_login_text_test.go b/internal/command/org_custom_login_text_test.go index 3c5cb207e2..46fdcd5a52 100644 --- a/internal/command/org_custom_login_text_test.go +++ b/internal/command/org_custom_login_text_test.go @@ -801,6 +801,11 @@ func TestCommandSide_SetCustomOrgLoginText(t *testing.T) { &org.NewAggregate("org1").Aggregate, domain.LoginCustomText, domain.LoginKeyRegistrationOptionExternalLoginDescription, "ExternalLoginDescription", language.English, ), ), + eventFromEventPusher( + org.NewCustomTextSetEvent(context.Background(), + &org.NewAggregate("org1").Aggregate, domain.LoginCustomText, domain.LoginKeyRegistrationOptionLoginButtonText, "LoginButtonText", language.English, + ), + ), eventFromEventPusher( org.NewCustomTextSetEvent(context.Background(), &org.NewAggregate("org1").Aggregate, domain.LoginCustomText, domain.LoginKeyRegistrationUserTitle, "Title", language.English, @@ -1372,6 +1377,7 @@ func TestCommandSide_SetCustomOrgLoginText(t *testing.T) { Description: "Description", RegisterUsernamePasswordButtonText: "RegisterUsernamePasswordButtonText", ExternalLoginDescription: "ExternalLoginDescription", + LoginButtonText: "LoginButtonText", }, RegistrationUser: domain.RegistrationUserScreenText{ Title: "Title", From 57857b8d30cc76f6d87198258bb936e9990911ba Mon Sep 17 00:00:00 2001 From: Livio Spring Date: Mon, 7 Aug 2023 10:01:24 +0200 Subject: [PATCH 04/38] fix: check if session is reused on reauthentication (#6322) * fix: check if session is reused on reauth steps * add nolint directive --------- Co-authored-by: Silvan --- .../eventsourcing/eventstore/auth_request.go | 91 +++++++++++-------- 1 file changed, 54 insertions(+), 37 deletions(-) diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request.go b/internal/auth/repository/eventsourcing/eventstore/auth_request.go index 0f81e64148..9a4bdfc993 100644 --- a/internal/auth/repository/eventsourcing/eventstore/auth_request.go +++ b/internal/auth/repository/eventsourcing/eventstore/auth_request.go @@ -547,6 +547,13 @@ func (repo *AuthRequestRepo) getAuthRequestEnsureUser(ctx context.Context, authR if err != nil { return nil, err } + // If there's no user, checks if the user could be reused (from the session). + // (the nextStepsUser will update the userID in the request in that case) + if request.UserID == "" { + if _, err = repo.nextStepsUser(request); err != nil { + return nil, err + } + } if request.UserID != userID { return nil, errors.ThrowPreconditionFailed(nil, "EVENT-GBH32", "Errors.User.NotMatchingUserID") } @@ -913,50 +920,19 @@ func (repo *AuthRequestRepo) checkExternalUserLogin(ctx context.Context, request return nil } -func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *domain.AuthRequest, checkLoggedIn bool) ([]domain.NextStep, error) { +//nolint:gocognit +func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *domain.AuthRequest, checkLoggedIn bool) (steps []domain.NextStep, err error) { if request == nil { return nil, errors.ThrowInvalidArgument(nil, "EVENT-ds27a", "Errors.Internal") } - steps := make([]domain.NextStep, 0) + steps = make([]domain.NextStep, 0) if !checkLoggedIn && domain.IsPrompt(request.Prompt, domain.PromptNone) { return append(steps, &domain.RedirectToCallbackStep{}), nil } if request.UserID == "" { - if request.LinkingUsers != nil && len(request.LinkingUsers) > 0 { - steps = append(steps, new(domain.ExternalNotFoundOptionStep)) - return steps, nil - } - if domain.IsPrompt(request.Prompt, domain.PromptCreate) { - return append(steps, &domain.RegistrationStep{}), nil - } - // if there's a login or consent prompt, but not select account, just return the login step - if len(request.Prompt) > 0 && !domain.IsPrompt(request.Prompt, domain.PromptSelectAccount) { - return append(steps, new(domain.LoginStep)), nil - } else { - // if no user was specified, no prompt or select_account was provided, - // then check the active user sessions (of the user agent) - users, err := repo.usersForUserSelection(request) - if err != nil { - return nil, err - } - if domain.IsPrompt(request.Prompt, domain.PromptSelectAccount) { - steps = append(steps, &domain.SelectUserStep{Users: users}) - } - if request.SelectedIDPConfigID != "" { - steps = append(steps, &domain.RedirectToExternalIDPStep{}) - } - if len(request.Prompt) == 0 && len(users) == 0 { - steps = append(steps, new(domain.LoginStep)) - } - // if no prompt was provided, but there are multiple user sessions, then the user must decide which to use - if len(request.Prompt) == 0 && len(users) > 1 { - steps = append(steps, &domain.SelectUserStep{Users: users}) - } - if len(steps) > 0 { - return steps, nil - } - // a single user session was found, use that automatically - request.UserID = users[0].UserID + steps, err = repo.nextStepsUser(request) + if err != nil || len(steps) > 0 { + return steps, err } } user, err := activeUserByID(ctx, repo.UserViewProvider, repo.UserEventProvider, repo.OrgViewProvider, repo.LockoutPolicyViewProvider, request.UserID, request.LoginPolicy.IgnoreUnknownUsernames) @@ -1046,6 +1022,47 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *domain.Auth return append(steps, &domain.RedirectToCallbackStep{}), nil } +func (repo *AuthRequestRepo) nextStepsUser(request *domain.AuthRequest) ([]domain.NextStep, error) { + steps := make([]domain.NextStep, 0) + if request.LinkingUsers != nil && len(request.LinkingUsers) > 0 { + steps = append(steps, new(domain.ExternalNotFoundOptionStep)) + return steps, nil + } + if domain.IsPrompt(request.Prompt, domain.PromptCreate) { + return append(steps, &domain.RegistrationStep{}), nil + } + // if there's a login or consent prompt, but not select account, just return the login step + if len(request.Prompt) > 0 && !domain.IsPrompt(request.Prompt, domain.PromptSelectAccount) { + return append(steps, new(domain.LoginStep)), nil + } else { + // if no user was specified, no prompt or select_account was provided, + // then check the active user sessions (of the user agent) + users, err := repo.usersForUserSelection(request) + if err != nil { + return nil, err + } + if domain.IsPrompt(request.Prompt, domain.PromptSelectAccount) { + steps = append(steps, &domain.SelectUserStep{Users: users}) + } + if request.SelectedIDPConfigID != "" { + steps = append(steps, &domain.RedirectToExternalIDPStep{}) + } + if len(request.Prompt) == 0 && len(users) == 0 { + steps = append(steps, new(domain.LoginStep)) + } + // if no prompt was provided, but there are multiple user sessions, then the user must decide which to use + if len(request.Prompt) == 0 && len(users) > 1 { + steps = append(steps, &domain.SelectUserStep{Users: users}) + } + if len(steps) > 0 { + return steps, nil + } + // a single user session was found, use that automatically + request.SetUserInfo(users[0].UserID, users[0].UserName, users[0].LoginName, users[0].DisplayName, users[0].AvatarKey, users[0].ResourceOwner) + } + return steps, nil +} + func checkExternalIDPsOfUser(ctx context.Context, idpUserLinksProvider idpUserLinksProvider, userID string) (*query.IDPUserLinks, error) { userIDQuery, err := query.NewIDPUserLinksUserIDSearchQuery(userID) if err != nil { From 7bc4aa9c767fba20c2fe5e9f889f7bcc452a92f7 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Mon, 7 Aug 2023 22:32:10 +0200 Subject: [PATCH 05/38] docs: copy config options to docs (#6143) * poc * wip * works * upgrade yaml package * need to add global comments for shifting * wip: need index before working on comments * green * clean up * test null value * comment * package * delete * convert to module * render md table * tests with ESM * comments * top level gitignore * wip: new cases * arrays: green * array_test * treat comments on map without first element * fix some new case * skip leaf comments * output folder * comment * finish up for poc * arrays * create output dir * merge main, create tables * copy config options to docs * cleanup * recommend file configuration * language * add some explanations * some small typo fixes --------- Co-authored-by: mffap Co-authored-by: Florian Forster --- cmd/defaults.yaml | 751 +++++++++--------- cmd/setup/steps.yaml | 66 +- docs/.gitignore | 3 + docs/docs/apis/proto/.gitignore | 2 + .../self-hosting/manage/configure/.gitignore | 2 + .../manage/configure/configure.mdx | 80 +- docs/docs/self-hosting/manage/production.md | 3 + docs/package.json | 5 +- docs/yarn.lock | 5 + 9 files changed, 496 insertions(+), 421 deletions(-) create mode 100644 docs/docs/apis/proto/.gitignore create mode 100644 docs/docs/self-hosting/manage/configure/.gitignore diff --git a/cmd/defaults.yaml b/cmd/defaults.yaml index 3573242d59..9088ff2cf9 100644 --- a/cmd/defaults.yaml +++ b/cmd/defaults.yaml @@ -1,18 +1,18 @@ Log: - Level: info + Level: info # ZITADEL_LOG_LEVEL Formatter: - Format: text + Format: text # ZITADEL_LOG_LEVEL # Exposes metrics on /debug/metrics Metrics: # Select type otel (OpenTelemetry) or none (disables collection and endpoint) - Type: otel + Type: otel # ZITADEL_METRICS_TYPE Tracing: # Choose one in "otel", "google", "log" and "none" - Type: none - Fraction: 1.0 - MetricPrefix: zitadel + Type: none # ZITADEL_TRACING_TYPE + Fraction: 1.0 # ZITADEL_TRACING_FRACTION + MetricPrefix: zitadel # ZITADEL_TRACING_METRICPREFIX Telemetry: # As long as Enabled is true, ZITADEL tries to send usage data to the configured Telemetry.Endpoints. @@ -38,313 +38,325 @@ Telemetry: Limit: 100 # ZITADEL_TELEMETRY_LIMIT # Port ZITADEL will listen on -Port: 8080 +Port: 8080 # ZITADEL_PORT # Port ZITADEL is exposed on, it can differ from port e.g. if you proxy the traffic -# !!! Changing this after initial setup breaks your system !!! -ExternalPort: 8080 -# Domain / hostname ZITADEL is exposed externally -# !!! Changing this after initial setup breaks your system !!! -ExternalDomain: localhost +# !!! Changing this after the initial setup breaks your system !!! +ExternalPort: 8080 # ZITADEL_EXTERNAL_PORT +# Domain/hostname ZITADEL is exposed externally +# !!! Changing this after the initial setup breaks your system !!! +ExternalDomain: localhost # ZITADEL_EXTERNAL_DOMAIN # specifies if ZITADEL is exposed externally through TLS # this must be set to true even if TLS is not enabled on ZITADEL itself # but TLS traffic is terminated on a reverse proxy -# !!! Changing this after initial setup breaks your system !!! -ExternalSecure: true +# !!! Changing this after the initial setup breaks your system !!! +ExternalSecure: true # ZITADEL_EXTERNALSECURE TLS: - # if enabled, ZITADEL will serve all traffic over TLS (HTTPS and gRPC) + # If enabled, ZITADEL will serve all traffic over TLS (HTTPS and gRPC) # you must then also provide a private key and certificate to be used for the connection # either directly or by a path to the corresponding file - Enabled: true - # Path to the private key of the TLS certificate, it will be loaded into the Key - # and overwrite any exising value - KeyPath: #/path/to/key/file.pem - # Private key of the TLS certificate (KeyPath will this overwrite, if specified) - Key: # - # Path to the certificate for the TLS connection, it will be loaded into the Cert - # and overwrite any exising value - CertPath: #/path/to/cert/file.pem - # Certificate for the TLS connection (CertPath will this overwrite, if specified) - Cert: # + Enabled: true # ZITADEL_TLS_ENABLED + # Path to the private key of the TLS certificate, will be loaded into the key + # and overwrite any existing value + # E.g. /path/to/key/file.pem + KeyPath: # ZITADEL_TLS_KEYPATH + # Private key of the TLS certificate (KeyPath has a higher priority than Key) + # base64 encoded content of a pem file + Key: # ZITADEL_TLS_KEY + # Path to the certificate for the TLS connection, will be loaded into the Cert + # and overwrite any existing value + # E.g. /path/to/cert/file.pem + CertPath: # ZITADEL_TLS_CERTPATH + # Certificate for the TLS connection (CertPath will this overwrite if specified) + # base64 encoded content of a pem file + Cert: # ZITADEL_TLS_CERT # Header name of HTTP2 (incl. gRPC) calls from which the instance will be matched -HTTP2HostHeader: ":authority" +HTTP2HostHeader: ":authority" # ZITADEL_HTTP2HOSTHEADER # Header name of HTTP1 calls from which the instance will be matched -HTTP1HostHeader: "host" +HTTP1HostHeader: "host" # ZITADEL_HTTP1HOSTHEADER -WebAuthNName: ZITADEL +WebAuthNName: ZITADEL # ZITADEL_WEBAUTHN_NAME Database: - # CockroachDB is the default datbase of ZITADEL + # CockroachDB is the default database of ZITADEL cockroach: - Host: localhost - Port: 26257 - Database: zitadel - MaxOpenConns: 20 - MaxIdleConns: 10 - MaxConnLifetime: 30m - MaxConnIdleTime: 5m - Options: "" + Host: localhost # ZITADEL_DATABASE_COCKROACH_HOST + Port: 26257 # ZITADEL_DATABASE_COCKROACH_PORT + Database: zitadel # ZITADEL_DATABASE_COCKROACH_DATABASE + MaxOpenConns: 20 # ZITADEL_DATABASE_COCKROACH_MAXOPENCONNS + MaxIdleConns: 10 # ZITADEL_DATABASE_COCKROACH_MAXIDLECONNS + MaxConnLifetime: 30m # ZITADEL_DATABASE_COCKROACH_MAXCONNLIFETIME + MaxConnIdleTime: 5m # ZITADEL_DATABASE_COCKROACH_MAXCONNIDLETIME + Options: "" # ZITADEL_DATABASE_COCKROACH_OPTIONS User: - Username: zitadel - Password: "" + Username: zitadel # ZITADEL_DATABASE_COCKROACH_USER_USERNAME + Password: "" # ZITADEL_DATABASE_COCKROACH_USER_PASSWORD SSL: - Mode: disable - RootCert: "" - Cert: "" - Key: "" + Mode: disable # ZITADEL_DATABASE_COCKROACH_USER_SSL_MODE + RootCert: "" # ZITADEL_DATABASE_COCKROACH_USER_SSL_ROOTCERT + Cert: "" # ZITADEL_DATABASE_COCKROACH_USER_SSL_CERT + Key: "" # ZITADEL_DATABASE_COCKROACH_USER_SSL_KEY Admin: - Username: root - Password: "" + Username: root # ZITADEL_DATABASE_COCKROACH_ADMIN_USERNAME + Password: "" # ZITADEL_DATABASE_COCKROACH_ADMIN_PASSWORD SSL: - Mode: disable - RootCert: "" - Cert: "" - Key: "" + Mode: disable # ZITADEL_DATABASE_COCKROACH_ADMIN_SSL_MODE + RootCert: "" # ZITADEL_DATABASE_COCKROACH_ADMIN_SSL_ROOTCERT + Cert: "" # ZITADEL_DATABASE_COCKROACH_ADMIN_SSL_CERT + Key: "" # ZITADEL_DATABASE_COCKROACH_ADMIN_SSL_KEY # Postgres is used as soon as a value is set # The values describe the possible fields to set values postgres: - Host: - Port: - Database: - MaxOpenConns: - MaxIdleConns: - MaxConnLifetime: - MaxConnIdleTime: - Options: + Host: # ZITADEL_DATABASE_POSTGRES_HOST + Port: # ZITADEL_DATABASE_POSTGRES_PORT + Database: # ZITADEL_DATABASE_POSTGRES_DATABASE + MaxOpenConns: # ZITADEL_DATABASE_POSTGRES_MAXOPENCONNS + MaxIdleConns: # ZITADEL_DATABASE_POSTGRES_MAXIDLECONNS + MaxConnLifetime: # ZITADEL_DATABASE_POSTGRES_MAXCONNLIFETIME + MaxConnIdleTime: # ZITADEL_DATABASE_POSTGRES_MAXCONNIDLETIME + Options: # ZITADEL_DATABASE_POSTGRES_OPTIONS User: - Username: - Password: + Username: # ZITADEL_DATABASE_POSTGRES_USER_USERNAME + Password: # ZITADEL_DATABASE_POSTGRES_USER_PASSWORD SSL: - Mode: - RootCert: - Cert: - Key: + Mode: # ZITADEL_DATABASE_POSTGRES_USER_SSL_MODE + RootCert: # ZITADEL_DATABASE_POSTGRES_USER_SSL_ROOTCERT + Cert: # ZITADEL_DATABASE_POSTGRES_USER_SSL_CERT + Key: # ZITADEL_DATABASE_POSTGRES_USER_SSL_KEY Admin: - Username: - Password: + Username: # ZITADEL_DATABASE_POSTGRES_ADMIN_USERNAME + Password: # ZITADEL_DATABASE_POSTGRES_ADMIN_PASSWORD SSL: - Mode: - RootCert: - Cert: - Key: + Mode: # ZITADEL_DATABASE_POSTGRES_ADMIN_SSL_MODE + RootCert: # ZITADEL_DATABASE_POSTGRES_ADMIN_SSL_ROOTCERT + Cert: # ZITADEL_DATABASE_POSTGRES_ADMIN_SSL_CERT + Key: # ZITADEL_DATABASE_POSTGRES_ADMIN_SSL_KEY Machine: - # Cloud hosted VMs need to specify their metadata endpoint so that the machine can be uniquely identified. + # Cloud-hosted VMs need to specify their metadata endpoint so that the machine can be uniquely identified. Identification: # Use private IP to identify machines uniquely PrivateIp: - Enabled: true + Enabled: true # ZITADEL_MACHINE_IDENTIFICATION_PRIVATEIP_ENABLED # Use hostname to identify machines uniquely # You want the process to be identified uniquely, so this works well in k8s where each pod gets its own - # unique host name, but not as well in some other hosting environments. + # unique hostname, but not as well in some other hosting environments. Hostname: - Enabled: false + Enabled: false # ZITADEL_MACHINE_IDENTIFICATION_HOSTNAME_ENABLED # Use a webhook response to identify machines uniquely # Google Cloud Configuration Webhook: - Enabled: true - Url: "http://metadata.google.internal/computeMetadata/v1/instance/id" + Enabled: true # ZITADEL_MACHINE_IDENTIFICATION_WEBHOOK_ENABLED + Url: "http://metadata.google.internal/computeMetadata/v1/instance/id" # ZITADEL_MACHINE_IDENTIFICATION_WEBHOOK_URL Headers: - "Metadata-Flavor": "Google" + "Metadata-Flavor": "Google" # ZITADEL_MACHINE_IDENTIFICATION_WEBHOOK_HEADERS # # AWS EC2 IMDSv1 Configuration: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html # Webhook: - # Url: "http://169.254.169.254/latest/meta-data/ami-id" + # Url: "http://169.254.169.254/latest/meta-data/ami-id" # ZITADEL_MACHINE_IDENTIFICATION_WEBHOOK_URL # # AWS ECS v4 Configuration: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-metadata-endpoint-v4.html # Webhook: - # Url: "${ECS_CONTAINER_METADATA_URI_V4}" - # JPath: "$.DockerId" + # Url: "${ECS_CONTAINER_METADATA_URI_V4}" # ZITADEL_MACHINE_IDENTIFICATION_WEBHOOK_URL + # JPath: "$.DockerId" # ZITADEL_MACHINE_IDENTIFICATION_WEBHOOK_JPATH # # Azure Configuration: https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service?tabs=linux # Webhook: - # Url: "http://169.254.169.254/metadata/instance?api-version=2021-02-01" - # JPath: "$.compute.vmId" + # Url: "http://169.254.169.254/metadata/instance?api-version=2021-02-01" # ZITADEL_MACHINE_IDENTIFICATION_WEBHOOK_URL + # JPath: "$.compute.vmId" # ZITADEL_MACHINE_IDENTIFICATION_WEBHOOK_JPATH # Storage for assets like user avatar, organization logo, icon, font, ... AssetStorage: - Type: db + Type: db # ZITADEL_ASSET_STORAGE_TYPE # HTTP cache control settings for serving assets in the assets API and login UI # the assets will also be served with an etag and last-modified header Cache: - MaxAge: 5s - SharedMaxAge: 168h #7d + MaxAge: 5s # ZITADEL_ASSETSTORAGE_CACHE_MAXAGE + # 168h are 7 days + SharedMaxAge: 168h # ZITADEL_ASSETSTORAGE_CACHE_SHAREDMAXAGE -# The Projections section defines the behaviour for the scheduled and synchronous events projections. +# The Projections section defines the behavior for the scheduled and synchronous events projections. Projections: # Time interval between scheduled projections - RequeueEvery: 60s + RequeueEvery: 60s # ZITADEL_PROJECTIONS_REQUEUEEVERY # Time between retried database statements resulting from projected events - RetryFailedAfter: 1s + RetryFailedAfter: 1s # ZITADEL_PROJECTIONS_RETRYFAILED # Retried execution number of database statements resulting from projected events - MaxFailureCount: 5 + MaxFailureCount: 5 # ZITADEL_PROJECTIONS_MAXFAILURECOUNT # Number of concurrent projection routines. Values of 0 and below are overwritten to 1 - ConcurrentInstances: 1 + ConcurrentInstances: 1 # ZITADEL_PROJECTIONS_CONCURRENTINSTANCES # Limit of returned events per query - BulkLimit: 200 - # Only instance are projected, for which at least a projection relevant event exists withing the timeframe - # from HandleActiveInstances duration in the past until the projections current time + BulkLimit: 200 # ZITADEL_PROJECTIONS_BULKLIMIT + # Only instances are projected, for which at least a projection-relevant event exists within the timeframe + # from HandleActiveInstances duration in the past until the projection's current time # Defaults to twice the RequeueEvery duration - HandleActiveInstances: 120s + HandleActiveInstances: 120s # ZITADEL_PROJECTIONS_HANDLEACTIVEINSTANCES # In the Customizations section, all settings from above can be overwritten for each specific projection Customizations: Projects: - BulkLimit: 2000 + BulkLimit: 2000 # ZITADEL_PROJECTIONS_CUSTOMIZATIONS_PROJECTS_BULKLIMIT # The Notifications projection is used for sending emails and SMS to users Notifications: - # As notification projections don't result in database statements, retries don't have any effects - MaxFailureCount: 0 + # As notification projections don't result in database statements, retries don't have an effect + MaxFailureCount: 0 # ZITADEL_PROJECTIONS_CUSTOMIZATIONS_NOTIFICATIONS_MAXFAILURECOUNT # The NotificationsQuotas projection is used for calling quota webhooks NotificationsQuotas: # In case of failed deliveries, ZITADEL retries to send the data points to the configured endpoints, but only for active instances. # An instance is active, as long as there are projected events on the instance, that are not older than the HandleActiveInstances duration. # Delivery guarantee requirements are higher for quota webhooks # Defaults to 45 days - HandleActiveInstances: 1080h - # As quota notification projections don't result in database statements, retries don't have any effects - MaxFailureCount: 0 - # Quota notifications are not so time critical. Setting RequeueEvery every five minutes doesn't annoy the database too much. - RequeueEvery: 300s + HandleActiveInstances: 1080h # ZITADEL_PROJECTIONS_CUSTOMIZATIONS_NOTIFICATIONSQUOTAS_HANDLEACTIVEINSTANCES + # As quota notification projections don't result in database statements, retries don't have an effect + MaxFailureCount: 0 # ZITADEL_PROJECTIONS_CUSTOMIZATIONS_NOTIFICATIONSQUOTAS_MAXFAILURECOUNT + # Quota notifications are not so time critical. Setting RequeueEvery every five minutes doesn't annoy the db too much. + RequeueEvery: 300s # ZITADEL_PROJECTIONS_CUSTOMIZATIONS_NOTIFICATIONSQUOTAS_REQUEUEEVERY + # The Telemetry projection is used for calling telemetry webhooks Telemetry: # In case of failed deliveries, ZITADEL retries to send the data points to the configured endpoints, but only for active instances. # An instance is active, as long as there are projected events on the instance, that are not older than the HandleActiveInstances duration. # Telemetry delivery guarantee requirements are a bit higher than normal data projections, as they are not interactively retryable. # Defaults to 15 days - HandleActiveInstances: 360h + HandleActiveInstances: 360h # ZITADEL_PROJECTIONS_CUSTOMIZATIONS_TELEMETRY_HANDLEACTIVEINSTANCES # As sending telemetry data doesn't result in database statements, retries don't have any effects - MaxFailureCount: 0 + MaxFailureCount: 0 # ZITADEL_PROJECTIONS_CUSTOMIZATIONS_TELEMETRY_MAXFAILURECOUNT # Telemetry data synchronization is not time critical. Setting RequeueEvery to 55 minutes doesn't annoy the database too much. - RequeueEvery: 3300s + RequeueEvery: 3300s # ZITADEL_PROJECTIONS_CUSTOMIZATIONS_TELEMETRY_REQUEUEEVERY Auth: - SearchLimit: 1000 + SearchLimit: 1000 # ZITADEL_AUTH_SEARCHLIMIT Spooler: - ConcurrentWorkers: 1 - ConcurrentInstances: 1 - BulkLimit: 10000 - FailureCountUntilSkip: 5 + ConcurrentWorkers: 1 # ZITADEL_AUTH_SPOOLER_CONCURRENTWORKERS + ConcurrentInstances: 1 # ZITADEL_AUTH_SPOOLER_CONCURRENTINSTANCES + BulkLimit: 10000 # ZITADEL_AUTH_SPOOLER_BULKLIMIT + FailureCountUntilSkip: 5 # ZITADEL_AUTH_SPOOLER_FAILURECOUNTUNTILSKIP Admin: - SearchLimit: 1000 + SearchLimit: 1000 # ZITADEL_ADMIN_SEARCHLIMIT Spooler: - ConcurrentWorkers: 1 - ConcurrentInstances: 1 - BulkLimit: 10000 - FailureCountUntilSkip: 5 + ConcurrentWorkers: 1 # ZITADEL_ADMIN_SPOOLER_CONCURRENTWORKERS + ConcurrentInstances: 1 # ZITADEL_ADMIN_SPOOLER_CONCURRENTINSTANCES + BulkLimit: 10000 # ZITADEL_ADMIN_SPOOLER_BULKLIMIT + FailureCountUntilSkip: 5 # ZITADEL_ADMIN_SPOOLER_FAILURECOUNTUNTILSKIP UserAgentCookie: - Name: zitadel.useragent - MaxAge: 8760h #365*24h (1 year) + Name: zitadel.useragent # ZITADEL_USERAGENTCOOKIE_NAME + # 8760h are 365 days, one year + MaxAge: 8760h # ZITADEL_USERAGENTCOOKIE_MAXAGE OIDC: - CodeMethodS256: true - AuthMethodPost: true - AuthMethodPrivateKeyJWT: true - GrantTypeRefreshToken: true - RequestObjectSupported: true - SigningKeyAlgorithm: RS256 + CodeMethodS256: true # ZITADEL_OIDC_CODEMETHODS256 + AuthMethodPost: true # ZITADEL_OIDC_AUTHMETHODPOST + AuthMethodPrivateKeyJWT: true # ZITADEL_OIDC_AUTHMETHODPRIVATEKEYJWT + GrantTypeRefreshToken: true # ZITADEL_OIDC_GRANTTYPEREFRESHTOKEN + RequestObjectSupported: true # ZITADEL_OIDC_REQUESTOBJECTSUPPORTED + SigningKeyAlgorithm: RS256 # ZITADEL_OIDC_SIGNINGKEYALGORITHM # Sets the default values for lifetime and expiration for OIDC # This default can be overwritten in the default instance configuration and for each instance during runtime - # !!! Changing this after initial setup will have no impact without a restart !!! - DefaultAccessTokenLifetime: 12h - DefaultIdTokenLifetime: 12h - DefaultRefreshTokenIdleExpiration: 720h #30d - DefaultRefreshTokenExpiration: 2160h #90d + # !!! Changing this after the initial setup will have no impact without a restart !!! + DefaultAccessTokenLifetime: 12h # ZITADEL_OIDC_DEFAULTACCESSTOKENLIFETIME + DefaultIdTokenLifetime: 12h # ZITADEL_OIDC_DEFAULTIDTOKENLIFETIME + # 720h are 30 days, one month + DefaultRefreshTokenIdleExpiration: 720h # ZITADEL_OIDC_DEFAULTREFRESHTOKENIDLEEXPIRATION + # 2160h are 90 days, three months + DefaultRefreshTokenExpiration: 2160h # ZITADEL_OIDC_DEFAULTREFRESHTOKENEXPIRATION Cache: - MaxAge: 12h - SharedMaxAge: 168h #7d + MaxAge: 12h # ZITADEL_OIDC_CACHE_MAXAGE + # 168h is 7 days, one week + SharedMaxAge: 168h # ZITADEL_OIDC_CACHE_SHAREDMAXAGE CustomEndpoints: Auth: - Path: /oauth/v2/authorize + Path: /oauth/v2/authorize # ZITADEL_OIDC_CUSTOMENDPOINTS_AUTH_PATH Token: - Path: /oauth/v2/token + Path: /oauth/v2/token # ZITADEL_OIDC_CUSTOMENDPOINTS_TOKEN_PATH Introspection: - Path: /oauth/v2/introspect + Path: /oauth/v2/introspect # ZITADEL_OIDC_CUSTOMENDPOINTS_INTROSPECTION_PATH Userinfo: - Path: /oidc/v1/userinfo + Path: /oidc/v1/userinfo # ZITADEL_OIDC_CUSTOMENDPOINTS_USERINFO_PATH Revocation: - Path: /oauth/v2/revoke + Path: /oauth/v2/revoke # ZITADEL_OIDC_CUSTOMENDPOINTS_REVOCATION_PATH EndSession: - Path: /oidc/v1/end_session + Path: /oidc/v1/end_session # ZITADEL_OIDC_CUSTOMENDPOINTS_ENDSESSION_PATH Keys: - Path: /oauth/v2/keys + Path: /oauth/v2/keys # ZITADEL_OIDC_CUSTOMENDPOINTS_KEYS_PATH DeviceAuth: - Path: /oauth/v2/device_authorization - DefaultLoginURLV2: "/login?authRequest=" - DefaultLogoutURLV2: "/logout?post_logout_redirect=" + Path: /oauth/v2/device_authorization # ZITADEL_OIDC_CUSTOMENDPOINTS_DEVICEAUTH_PATH + DefaultLoginURLV2: "/login?authRequest=" # ZITADEL_OIDC_DEFAULTLOGINURLV2 + DefaultLogoutURLV2: "/logout?post_logout_redirect=" # ZITADEL_OIDC_DEFAULTLOGOUTURLV2 SAML: ProviderConfig: MetadataConfig: - Path: "/metadata" - SignatureAlgorithm: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" + Path: "/metadata" # ZITADEL_SAML_PROVIDERCONFIG_METADATACONFIG_PATH + SignatureAlgorithm: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" # ZITADEL_SAML_PROVIDERCONFIG_METADATACONFIG_SIGNATUREALGORITHM IDPConfig: - SignatureAlgorithm: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" - WantAuthRequestsSigned: true + SignatureAlgorithm: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" # ZITADEL_SAML_PROVIDERCONFIG_IDPCONFIG_SIGNATUREALGORITHM + WantAuthRequestsSigned: true # ZITADEL_SAML_PROVIDERCONFIG_IDPCONFIG_WANTAUTHREQUESTSSIGNED Endpoints: #Organisation: - # Name: ZITADEL - # URL: https://zitadel.com + # Name: ZITADEL # ZITADEL_SAML_PROVIDERCONFIG_ORGANISATION_NAME + # URL: https://zitadel.com # ZITADEL_SAML_PROVIDERCONFIG_ORGANISATION_URL #ContactPerson: - # ContactType: "technical" - # Company: ZITADEL - # EmailAddress: hi@zitadel.com + # ContactType: "technical" # ZITADEL_SAML_PROVIDERCONFIG_CONTACTPERSON_CONTACTTYPE + # Company: ZITADEL # ZITADEL_SAML_PROVIDERCONFIG_CONTACTPERSON_COMPANY + # EmailAddress: hi@zitadel.com # ZITADEL_SAML_PROVIDERCONFIG_CONTACTPERSON_EMAILADDRESS Login: - LanguageCookieName: zitadel.login.lang - CSRFCookieName: zitadel.login.csrf + LanguageCookieName: zitadel.login.lang # ZITADEL_LOGIN_LANGUAGECOOKIENAME + CSRFCookieName: zitadel.login.csrf # ZITADEL_LOGIN_CSRFCOOKIENAME Cache: - MaxAge: 12h - SharedMaxAge: 168h #7d + MaxAge: 12h # ZITADEL_LOGIN_CACHE_MAXAGE + # 168h is 7 days, one week + SharedMaxAge: 168h # ZITADEL_LOGIN_CACHE_SHAREDMAXAGE Console: ShortCache: - MaxAge: 0m - SharedMaxAge: 5m + MaxAge: 0m # ZITADEL_CONSOLE_SHORTCACHE_MAXAGE + SharedMaxAge: 5m # ZITADEL_CONSOLE_SHORTCACHE_SHAREDMAXAGE LongCache: - MaxAge: 12h - SharedMaxAge: 168h #7d - InstanceManagementURL: "" + MaxAge: 12h # ZITADEL_CONSOLE_LONGCACHE_MAXAGE + # 168h is 7 days, one week + SharedMaxAge: 168h # ZITADEL_CONSOLE_LONGCACHE_SHAREDMAXAGE + InstanceManagementURL: "" # ZITADEL_CONSOLE_INSTANCEMANAGEMENTURL Notification: Repository: Spooler: - ConcurrentWorkers: 1 - ConcurrentInstances: 10 - BulkLimit: 10000 - FailureCountUntilSkip: 5 + ConcurrentWorkers: 1 # ZITADEL_NOTIFICATION_REPOSITORY_SPOOLER_CONCURRENTWORKERS + ConcurrentInstances: 10 # ZITADEL_NOTIFICATION_REPOSITORY_SPOOLER_CONCURRENTINSTANCES + BulkLimit: 10000 # ZITADEL_NOTIFICATION_REPOSITORY_SPOOLER_BULKLIMIT + FailureCountUntilSkip: 5 # ZITADEL_NOTIFICATION_REPOSITORY_SPOOLER_FAILURECOUNTUNTILSKIP Handlers: EncryptionKeys: DomainVerification: - EncryptionKeyID: "domainVerificationKey" + EncryptionKeyID: "domainVerificationKey" # ZITADEL_ENCRYPTIONKEYS_DOMAINVERIFICATION_ENCRYPTIONKEYID DecryptionKeyIDs: IDPConfig: - EncryptionKeyID: "idpConfigKey" + EncryptionKeyID: "idpConfigKey" # ZITADEL_ENCRYPTIONKEYS_IDPCONFIG_ENCRYPTIONKEYID DecryptionKeyIDs: OIDC: - EncryptionKeyID: "oidcKey" + EncryptionKeyID: "oidcKey" # ZITADEL_ENCRYPTIONKEYS_OIDC_ENCRYPTIONKEYID DecryptionKeyIDs: SAML: - EncryptionKeyID: "samlKey" + EncryptionKeyID: "samlKey" # ZITADEL_ENCRYPTIONKEYS_SAML_ENCRYPTIONKEYID DecryptionKeyIDs: OTP: - EncryptionKeyID: "otpKey" + EncryptionKeyID: "otpKey" # ZITADEL_ENCRYPTIONKEYS_OTP_ENCRYPTIONKEYID DecryptionKeyIDs: SMS: - EncryptionKeyID: "smsKey" + EncryptionKeyID: "smsKey" # ZITADEL_ENCRYPTIONKEYS_SMS_ENCRYPTIONKEYID DecryptionKeyIDs: SMTP: - EncryptionKeyID: "smtpKey" + EncryptionKeyID: "smtpKey" # ZITADEL_ENCRYPTIONKEYS_SMTP_ENCRYPTIONKEYID DecryptionKeyIDs: User: - EncryptionKeyID: "userKey" + EncryptionKeyID: "userKey" # ZITADEL_ENCRYPTIONKEYS_USER_ENCRYPTIONKEYID DecryptionKeyIDs: - CSRFCookieKeyID: "csrfCookieKey" - UserAgentCookieKeyID: "userAgentCookieKey" + CSRFCookieKeyID: "csrfCookieKey" # ZITADEL_ENCRYPTIONKEYS_CSRFCOOKIEKEYID + UserAgentCookieKeyID: "userAgentCookieKey" # ZITADEL_ENCRYPTIONKEYS_USERAGENTCOOKIEKEYID SystemAPIUsers: -# add keys for authentication of the systemAPI here: +# Add keys for authentication of the systemAPI here: # you can specify any name for the user, but they will have to match the `issuer` and `sub` claim in the JWT: # - superuser: # Path: /path/to/superuser/key.pem # you can provide the key either by reference with the path @@ -354,31 +366,31 @@ SystemAPIUsers: #TODO: remove as soon as possible SystemDefaults: SecretGenerators: - PasswordSaltCost: 14 - MachineKeySize: 2048 - ApplicationKeySize: 2048 + PasswordSaltCost: 14 # ZITADEL_SYSTEMDEFAULTS_SECRETGENERATORS_PASSWORDSALTCOST + MachineKeySize: 2048 # ZITADEL_SYSTEMDEFAULTS_SECRETGENERATORS_MACHINEKEYSIZE + ApplicationKeySize: 2048 # ZITADEL_SYSTEMDEFAULTS_SECRETGENERATORS_APPLICATIONKEYSIZE PasswordHasher: # Set hasher configuration for user passwords. # Passwords previously hashed with a different algorithm # or cost are automatically re-hashed using this config, # upon password validation or update. Hasher: - Algorithm: "bcrypt" - Cost: 14 + Algorithm: "bcrypt" # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_HASHER_ALGORITHM + Cost: 14 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_HASHER_COST # Other supported Hasher configs: # Hasher: - # Algorithm: "argon2i" - # Time: 3 - # Memory: 32768 - # Threads: 4 + # Algorithm: "argon2i" # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_HASHER_ALGORITHM + # Time: 3 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_HASHER_TIME + # Memory: 32768 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_HASHER_MEMORY + # Threads: 4 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_HASHER_THREADS # Hasher: - # Algorithm: "argon2id" - # Time: 1 - # Memory: 65536 - # Threads: 4 + # Algorithm: "argon2id" # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_HASHER_ALGORITHM + # Time: 1 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_HASHER_TIME + # Memory: 65536 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_HASHER_MEMORY + # Threads: 4 # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_HASHER_THREADS # Hasher: # Algorithm: "scrypt" @@ -412,26 +424,27 @@ SystemDefaults: OTP: # If this is empty, the issuer is the requested domain # This is helpful in scenarios with multiple ZITADEL environments or virtual instances - Issuer: "ZITADEL" + Issuer: "ZITADEL" # ZITADEL_SYSTEMDEFAULTS_MULTIFACTORS_OTP_ISSUER DomainVerification: VerificationGenerator: - Length: 32 - IncludeLowerLetters: true - IncludeUpperLetters: true - IncludeDigits: true - IncludeSymbols: false + Length: 32 # ZITADEL_SYSTEMDEFAULTS_DOMAINVERIFICATION_VERIFICATIONGENERATOR_LENGTH + IncludeLowerLetters: true # ZITADEL_SYSTEMDEFAULTS_DOMAINVERIFICATION_VERIFICATIONGENERATOR_INCLUDELOWERLETTERS + IncludeUpperLetters: true # ZITADEL_SYSTEMDEFAULTS_DOMAINVERIFICATION_VERIFICATIONGENERATOR_INCLUDEUPPERLETTERS + IncludeDigits: true # ZITADEL_SYSTEMDEFAULTS_DOMAINVERIFICATION_VERIFICATIONGENERATOR_INCLUDEDIGITS + IncludeSymbols: false # ZITADEL_SYSTEMDEFAULTS_DOMAINVERIFICATION_VERIFICATIONGENERATOR_INCLUDESYMBOLS Notifications: - FileSystemPath: ".notifications/" + FileSystemPath: ".notifications/" # ZITADEL_SYSTEMDEFAULTS_NOTIFICATIONS_FILESYSTEMPATH KeyConfig: - Size: 2048 - CertificateSize: 4096 - PrivateKeyLifetime: 6h - PublicKeyLifetime: 30h - CertificateLifetime: 8766h + Size: 2048 # ZITADEL_SYSTEMDEFAULTS_KEYCONFIG_SIZE + CertificateSize: 4096 # ZITADEL_SYSTEMDEFAULTS_KEYCONFIG_CERTIFICATESIZE + PrivateKeyLifetime: 6h # ZITADEL_SYSTEMDEFAULTS_KEYCONFIG_PRIVATEKEYLIFETIME + PublicKeyLifetime: 30h # ZITADEL_SYSTEMDEFAULTS_KEYCONFIG_PUBLICKEYLIFETIME + # 8766h are 1 year + CertificateLifetime: 8766h # ZITADEL_SYSTEMDEFAULTS_KEYCONFIG_CERTIFICATELIFETIME Actions: HTTP: - # wildcard sub domains are currently unsupported + # Wildcard sub domains are currently unsupported DenyList: - localhost - "127.0.0.1" @@ -440,222 +453,240 @@ LogStore: Access: Database: # If enabled, all access logs are stored in the database table logstore.access - Enabled: false + Enabled: false # ZITADEL_LOGSTORE_ACCESS_DATABASE_ENABLED # Logs that are older than the keep duration are cleaned up continuously - Keep: 2160h # 90 days + # 2160h are 90 days, 3 months + Keep: 2160h # ZITADEL_LOGSTORE_ACCESS_DATABASE_KEEP # CleanupInterval defines the time between cleanup iterations - CleanupInterval: 4h + CleanupInterval: 4h # ZITADEL_LOGSTORE_ACCESS_DATABASE_CLEANUPINTERVAL # Debouncing enables to asynchronously emit log entries, so the normal execution performance is not impaired - # Log entries are held in-memory until one of the conditions MinFrequency or MaxBulkSize meets. + # Log entries are held in memory until one of the conditions MinFrequency or MaxBulkSize meets. Debounce: - MinFrequency: 2m - MaxBulkSize: 100 + MinFrequency: 2m # ZITADEL_LOGSTORE_ACCESS_DATABASE_DEBOUNCE_MINFREQUENCY + MaxBulkSize: 100 # ZITADEL_LOGSTORE_ACCESS_DATABASE_DEBOUNCE_MAXBULKSIZE Stdout: - # If enabled, all access logs are printed to the binaries standard output - Enabled: false + # If enabled, all access logs are printed to the binary's standard output + Enabled: false # ZITADEL_LOGSTORE_ACCESS_STDOUT_ENABLED # Debouncing enables to asynchronously emit log entries, so the normal execution performance is not impaired - # Log entries are held in-memory until one of the conditions MinFrequency or MaxBulkSize meets. + # Log entries are held in memory until one of the conditions MinFrequency or MaxBulkSize meets. Debounce: - MinFrequency: 0s - MaxBulkSize: 0 + MinFrequency: 0s # ZITADEL_LOGSTORE_ACCESS_STDOUT_DEBOUNCE_MINFREQUENCY + MaxBulkSize: 0 # ZITADEL_LOGSTORE_ACCESS_STDOUT_DEBOUNCE_MAXBULKSIZE Execution: Database: # If enabled, all action execution logs are stored in the database table logstore.execution - Enabled: false + Enabled: false # ZITADEL_LOGSTORE_EXECUTION_DATABASE_ENABLED # Logs that are older than the keep duration are cleaned up continuously - Keep: 2160h # 90 days + # 2160h are 90 days, 3 months + Keep: 2160h # ZITADEL_LOGSTORE_EXECUTION_DATABASE_KEEP # CleanupInterval defines the time between cleanup iterations - CleanupInterval: 4h + CleanupInterval: 4h # ZITADEL_LOGSTORE_EXECUTION_DATABASE_CLEANUPINTERVAL # Debouncing enables to asynchronously emit log entries, so the normal execution performance is not impaired - # Log entries are held in-memory until one of the conditions MinFrequency or MaxBulkSize meets. + # Log entries are held in memory until one of the conditions MinFrequency or MaxBulkSize meets. Debounce: - MinFrequency: 0s - MaxBulkSize: 0 + MinFrequency: 0s # ZITADEL_LOGSTORE_EXECUTION_DATABASE_DEBOUNCE_MINFREQUENCY + MaxBulkSize: 0 # ZITADEL_LOGSTORE_EXECUTION_DATABASE_DEBOUNCE_MAXBULKSIZE Stdout: - # If enabled, all execution logs are printed to the binaries standard output - Enabled: true + # If enabled, all execution logs are printed to the binary's standard output + Enabled: true # ZITADEL_LOGSTORE_EXECUTION_STDOUT_ENABLED # Debouncing enables to asynchronously emit log entries, so the normal execution performance is not impaired - # Log entries are held in-memory until one of the conditions MinFrequency or MaxBulkSize meets. + # Log entries are held in memory until one of the conditions MinFrequency or MaxBulkSize meets. Debounce: - MinFrequency: 0s - MaxBulkSize: 0 + MinFrequency: 0s # ZITADEL_LOGSTORE_EXECUTION_STDOUT_DEBOUNCE_MINFREQUENCY + MaxBulkSize: 0 # ZITADEL_LOGSTORE_EXECUTION_STDOUT_DEBOUNCE_MAXBULKSIZE Quotas: Access: - ExhaustedCookieKey: "zitadel.quota.exhausted" - ExhaustedCookieMaxAge: "300s" + ExhaustedCookieKey: "zitadel.quota.exhausted" # ZITADEL_QUOTAS_ACCESS_EXHAUSTEDCOOKIEKEY + ExhaustedCookieMaxAge: "300s" # ZITADEL_QUOTAS_ACCESS_EXHAUSTEDCOOKIEMAXAGE Eventstore: - PushTimeout: 15s - AllowOrderByCreationDate: false + PushTimeout: 15s # ZITADEL_EVENTSTORE_PUSHTIMEOUT + AllowOrderByCreationDate: false # ZITADEL_EVENTSTORE_ALLOWORDERBYCREATIONDATE DefaultInstance: - InstanceName: - DefaultLanguage: en + InstanceName: ZITADEL # ZITADEL_DEFAULTINSTANCE_INSTANCENAME + DefaultLanguage: en # ZITADEL_DEFAULTINSTANCE_DEFAULTLANGUAGE Org: - Name: + Name: ZITADEL # ZITADEL_DEFAULTINSTANCE_ORG_NAME + # In the DefaultInstance.Org.Human section, the initial organization's admin user with the role IAM_OWNER is defined. + # ZITADEL either creates a human user or a machine user. + # If DefaultInstance.Org.Machine.Machine is defined, a service user is created with the IAM_OWNER role, not a human user. Human: - # in case that UserLoginMustBeDomain is false (default) and if you don't overwrite the username with an email, + # In case that UserLoginMustBeDomain is false (default) and if you don't overwrite the username with an email, # it will be suffixed by the org domain (org-name + domain from config). - # for example: zitadel-admin in org `My Org` on domain.tld -> zitadel-admin@my-org.domain.tld - UserName: zitadel-admin - FirstName: ZITADEL - LastName: Admin - NickName: - DisplayName: + # for example zitadel-admin in org `My Org` on domain.tld -> zitadel-admin@my-org.domain.tld + UserName: zitadel-admin # ZITADEL_DEFAULTINSTANCE_ORG_HUMAN_USERNAME + FirstName: ZITADEL # ZITADEL_DEFAULTINSTANCE_ORG_HUMAN_FIRSTNAME + LastName: Admin # ZITADEL_DEFAULTINSTANCE_ORG_HUMAN_LASTNAME + NickName: # ZITADEL_DEFAULTINSTANCE_ORG_HUMAN_NICKNAME + DisplayName: # ZITADEL_DEFAULTINSTANCE_ORG_HUMAN_DISPLAYNAME Email: - Address: - Verified: false - PreferredLanguage: en - Gender: + Address: # ZITADEL_DEFAULTINSTANCE_ORG_HUMAN_EMAIL_ADDRESS + Verified: false # ZITADEL_DEFAULTINSTANCE_ORG_HUMAN_EMAIL_VERIFIED + PreferredLanguage: en # ZITADEL_DEFAULTINSTANCE_ORG_HUMAN_PREFERREDLANGUAGE + Gender: # ZITADEL_DEFAULTINSTANCE_ORG_HUMAN_GENDER Phone: - Number: - Verified: - Password: + Number: # ZITADEL_DEFAULTINSTANCE_ORG_HUMAN_PHONE_NUMBER + Verified: # ZITADEL_DEFAULTINSTANCE_ORG_HUMAN_PHONE_VERIFIED + Password: # ZITADEL_DEFAULTINSTANCE_ORG_HUMAN_PASSWORD + # In the DefaultInstance.Org.Machine section, the initial organization's admin user with the role IAM_OWNER is defined. + # ZITADEL either creates a human user or a machine user. + # If DefaultInstance.Org.Machine.Machine is defined, a service user is created with the IAM_OWNER role, not a human user. Machine: Machine: - Username: - Name: + Username: # ZITADEL_DEFAULTINSTANCE_ORG_MACHINE_MACHINE_USERNAME + Name: # ZITADEL_DEFAULTINSTANCE_ORG_MACHINE_MACHINE_NAME MachineKey: - ExpirationDate: - Type: + # date format: 2023-01-01T00:00:00Z + ExpirationDate: # ZITADEL_DEFAULTINSTANCE_ORG_MACHINE_MACHINEKEY_EXPIRATIONDATE + # Currently, the only supported value is 1 for JSON + Type: # ZITADEL_DEFAULTINSTANCE_ORG_MACHINE_MACHINEKEY_TYPE Pat: - ExpirationDate: + # date format: 2023-01-01T00:00:00Z + ExpirationDate: # ZITADEL_DEFAULTINSTANCE_ORG_MACHINE_PAT_EXPIRATIONDATE SecretGenerators: - PasswordSaltCost: 14 + PasswordSaltCost: 14 # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_PASSWORDSALTCOST ClientSecret: - Length: 64 - IncludeLowerLetters: true - IncludeUpperLetters: true - IncludeDigits: true - IncludeSymbols: false + Length: 64 # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_CLIENTSECRET_LENGTH + IncludeLowerLetters: true # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_CLIENTSECRET_INCLUDELOWERLETTERS + IncludeUpperLetters: true # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_CLIENTSECRET_INCLUDEUPPERLETTERS + IncludeDigits: true # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_CLIENTSECRET_INCLUDEDIGITS + IncludeSymbols: false # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_CLIENTSECRET_INCLUDESYMBOLS InitializeUserCode: - Length: 6 - Expiry: "72h" - IncludeLowerLetters: false - IncludeUpperLetters: true - IncludeDigits: true - IncludeSymbols: false + Length: 6 # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_INITIALIZEUSERCODE_LENGTH + Expiry: "72h" # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_INITIALIZEUSERCODE_EXPIRY + IncludeLowerLetters: false # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_INITIALIZEUSERCODE_INCLUDELOWERLETTERS + IncludeUpperLetters: true # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_INITIALIZEUSERCODE_INCLUDEUPPERLETTERS + IncludeDigits: true # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_INITIALIZEUSERCODE_INCLUDEDIGITS + IncludeSymbols: false # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_INITIALIZEUSERCODE_INCLUDESYMBOLS EmailVerificationCode: - Length: 6 - Expiry: "1h" - IncludeLowerLetters: false - IncludeUpperLetters: true - IncludeDigits: true - IncludeSymbols: false + Length: 6 # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_EMAILVERIFICATIONCODE_LENGTH + Expiry: "1h" # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_EMAILVERIFICATIONCODE_EXPIRY + IncludeLowerLetters: false # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_EMAILVERIFICATIONCODE_INCLUDELOWERLETTERS + IncludeUpperLetters: true # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_EMAILVERIFICATIONCODE_INCLUDEUPPERLETTERS + IncludeDigits: true # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_EMAILVERIFICATIONCODE_INCLUDEDIGITS + IncludeSymbols: false # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_EMAILVERIFICATIONCODE_INCLUDESYMBOLS PhoneVerificationCode: - Length: 6 - Expiry: "1h" - IncludeLowerLetters: false - IncludeUpperLetters: true - IncludeDigits: true - IncludeSymbols: false + Length: 6 # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_PHONEVERIFICATIONCODE_LENGTH + Expiry: "1h" # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_PHONEVERIFICATIONCODE_EXPIRY + IncludeLowerLetters: false # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_PHONEVERIFICATIONCODE_INCLUDELOWERLETTERS + IncludeUpperLetters: true # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_PHONEVERIFICATIONCODE_INCLUDEUPPERLETTERS + IncludeDigits: true # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_PHONEVERIFICATIONCODE_INCLUDEDIGITS + IncludeSymbols: false # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_PHONEVERIFICATIONCODE_INCLUDESYMBOLS PasswordVerificationCode: - Length: 6 - Expiry: "1h" - IncludeLowerLetters: false - IncludeUpperLetters: true - IncludeDigits: true - IncludeSymbols: false + Length: 6 # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_PASSWORDVERIFICATIONCODE_LENGTH + Expiry: "1h" # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_PASSWORDVERIFICATIONCODE_EXPIRY + IncludeLowerLetters: false # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_PASSWORDVERIFICATIONCODE_INCLUDELOWERLETTERS + IncludeUpperLetters: true # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_PASSWORDVERIFICATIONCODE_INCLUDEUPPERLETTERS + IncludeDigits: true # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_PASSWORDVERIFICATIONCODE_INCLUDEDIGITS + IncludeSymbols: false # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_PASSWORDVERIFICATIONCODE_INCLUDESYMBOLS PasswordlessInitCode: - Length: 12 - Expiry: "1h" - IncludeLowerLetters: true - IncludeUpperLetters: true - IncludeDigits: true - IncludeSymbols: false + Length: 12 # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_PASSWORDLESSINITCODE_LENGTH + Expiry: "1h" # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_PASSWORDLESSINITCODE_EXPIRY + IncludeLowerLetters: true # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_PASSWORDLESSINITCODE_INCLUDELOWERLETTERS + IncludeUpperLetters: true # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_PASSWORDLESSINITCODE_INCLUDEUPPERLETTERS + IncludeDigits: true # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_PASSWORDLESSINITCODE_INCLUDEDIGITS + IncludeSymbols: false # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_PASSWORDLESSINITCODE_INCLUDESYMBOLS DomainVerification: - Length: 32 - IncludeLowerLetters: true - IncludeUpperLetters: true - IncludeDigits: true - IncludeSymbols: false + Length: 32 # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_DOMAINVERIFICATION_LENGTH + IncludeLowerLetters: true # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_DOMAINVERIFICATION_INCLUDELOWERLETTERS + IncludeUpperLetters: true # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_DOMAINVERIFICATION_INCLUDEUPPERLETTERS + IncludeDigits: true # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_DOMAINVERIFICATION_INCLUDEDIGITS + IncludeSymbols: false # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_DOMAINVERIFICATION_INCLUDESYMBOLS OTPSMS: - Length: 8 - Expiry: "5m" - IncludeLowerLetters: false - IncludeUpperLetters: false - IncludeDigits: true - IncludeSymbols: false + Length: 8 # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_OTPSMS_LENGTH + Expiry: "5m" # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_OTPSMS_EXPIRY + IncludeLowerLetters: false # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_OTPSMS_INCLUDELOWERLETTERS + IncludeUpperLetters: false # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_OTPSMS_INCLUDEUPPERLETTERS + IncludeDigits: true # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_OTPSMS_INCLUDEDIGITS + IncludeSymbols: false # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_OTPSMS_INCLUDESYMBOLS OTPEmail: - Length: 8 - Expiry: "5m" - IncludeLowerLetters: false - IncludeUpperLetters: false - IncludeDigits: true - IncludeSymbols: false + Length: 8 # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_OTPEMAIL_LENGTH + Expiry: "5m" # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_OTPEMAIL_EXPIRY + IncludeLowerLetters: false # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_OTPEMAIL_INCLUDELOWERLETTERS + IncludeUpperLetters: false # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_OTPEMAIL_INCLUDEUPPERLETTERS + IncludeDigits: true # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_OTPEMAIL_INCLUDEDIGITS + IncludeSymbols: false # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_OTPEMAIL_INCLUDESYMBOLS PasswordComplexityPolicy: - MinLength: 8 - HasLowercase: true - HasUppercase: true - HasNumber: true - HasSymbol: true + MinLength: 8 # ZITADEL_DEFAULTINSTANCE_PASSWORDCOMPLEXITYPOLICY_MINLENGTH + HasLowercase: true # ZITADEL_DEFAULTINSTANCE_PASSWORDCOMPLEXITYPOLICY_HASLOWERCASE + HasUppercase: true # ZITADEL_DEFAULTINSTANCE_PASSWORDCOMPLEXITYPOLICY_HASUPPERCASE + HasNumber: true # ZITADEL_DEFAULTINSTANCE_PASSWORDCOMPLEXITYPOLICY_HASNUMBER + HasSymbol: true # ZITADEL_DEFAULTINSTANCE_PASSWORDCOMPLEXITYPOLICY_HASSYMBOL PasswordAgePolicy: - ExpireWarnDays: 0 - MaxAgeDays: 0 + ExpireWarnDays: 0 # ZITADEL_DEFAULTINSTANCE_PASSWORDAGEPOLICY_EXPIREWARNDAYS + MaxAgeDays: 0 # ZITADEL_DEFAULTINSTANCE_PASSWORDAGEPOLICY_MAXAGEDAYS DomainPolicy: - UserLoginMustBeDomain: false - ValidateOrgDomains: true - SMTPSenderAddressMatchesInstanceDomain: false + UserLoginMustBeDomain: false # ZITADEL_DEFAULTINSTANCE_DOMAINPOLICY_USERLOGINMUSTBEDOMAIN + ValidateOrgDomains: true # ZITADEL_DEFAULTINSTANCE_DOMAINPOLICY_VALIDATEORGDOMAINS + SMTPSenderAddressMatchesInstanceDomain: false # ZITADEL_DEFAULTINSTANCE_DOMAINPOLICY_SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN LoginPolicy: - AllowUsernamePassword: true - AllowRegister: true - AllowExternalIDP: true - ForceMFA: false - HidePasswordReset: false - IgnoreUnknownUsernames: false - AllowDomainDiscovery: false - PasswordlessType: 1 #1: allowed 0: not allowed - DefaultRedirectURI: #empty because we use the Console UI - PasswordCheckLifetime: 240h #10d - ExternalLoginCheckLifetime: 240h #10d - MfaInitSkipLifetime: 720h #30d - SecondFactorCheckLifetime: 18h - MultiFactorCheckLifetime: 12h + AllowUsernamePassword: true # ZITADEL_DEFAULTINSTANCE_LOGINPOLICY_ALLOWUSERNAMEPASSWORD + AllowRegister: true # ZITADEL_DEFAULTINSTANCE_LOGINPOLICY_ALLOWREGISTER + AllowExternalIDP: true # ZITADEL_DEFAULTINSTANCE_LOGINPOLICY_ALLOWEXTERNALIDP + ForceMFA: false # ZITADEL_DEFAULTINSTANCE_LOGINPOLICY_FORCEMFA + HidePasswordReset: false # ZITADEL_DEFAULTINSTANCE_LOGINPOLICY_HIDEPASSWORDRESET + IgnoreUnknownUsernames: false # ZITADEL_DEFAULTINSTANCE_LOGINPOLICY_IGNOREUNKNOWNUSERNAMES + AllowDomainDiscovery: false # ZITADEL_DEFAULTINSTANCE_LOGINPOLICY_ALLOWDOMAINDISCOVERY + # 1 is allowed, 0 is not allowed + PasswordlessType: 1 # ZITADEL_DEFAULTINSTANCE_LOGINPOLICY_PASSWORDLESSTYPE + # DefaultRedirectURL is empty by default because we use the Console UI + DefaultRedirectURI: # ZITADEL_DEFAULTINSTANCE_LOGINPOLICY_DEFAULTREDIRECTURI + # 240h = 10d + PasswordCheckLifetime: 240h # ZITADEL_DEFAULTINSTANCE_LOGINPOLICY_PASSWORDCHECKLIFETIME + # 240h = 10d + ExternalLoginCheckLifetime: 240h # ZITADEL_DEFAULTINSTANCE_LOGINPOLICY_EXTERNALLOGINCHECKLIFETIME + # 720h = 30d + MfaInitSkipLifetime: 720h # ZITADEL_DEFAULTINSTANCE_LOGINPOLICY_MFAINITSKIPLIFETIME + SecondFactorCheckLifetime: 18h # ZITADEL_DEFAULTINSTANCE_LOGINPOLICY_SECONDFACTORCHECKLIFETIME + MultiFactorCheckLifetime: 12h # ZITADEL_DEFAULTINSTANCE_LOGINPOLICY_MULTIFACTORCHECKLIFETIME PrivacyPolicy: - TOSLink: https://zitadel.com/docs/legal/terms-of-service - PrivacyLink: https://zitadel.com/docs/legal/privacy-policy - HelpLink: "" - SupportEmail: "" + TOSLink: https://zitadel.com/docs/legal/terms-of-service # ZITADEL_DEFAULTINSTANCE_PRIVACYPOLICY_TOSLINK + PrivacyLink: https://zitadel.com/docs/legal/privacy-policy # ZITADEL_DEFAULTINSTANCE_PRIVACYPOLICY_PRIVACYLINK + HelpLink: "" # ZITADEL_DEFAULTINSTANCE_PRIVACYPOLICY_HELPLINK + SupportEmail: "" # ZITADEL_DEFAULTINSTANCE_PRIVACYPOLICY_SUPPORTEMAIL NotificationPolicy: - PasswordChange: true + PasswordChange: true # ZITADEL_DEFAULTINSTANCE_NOTIFICATIONPOLICY_PASSWORDCHANGE LabelPolicy: - PrimaryColor: "#5469d4" - BackgroundColor: "#fafafa" - WarnColor: "#cd3d56" - FontColor: "#000000" - PrimaryColorDark: "#2073c4" - BackgroundColorDark: "#111827" - WarnColorDark: "#ff3b5b" - FontColorDark: "#ffffff" - HideLoginNameSuffix: false - ErrorMsgPopup: false - DisableWatermark: false + PrimaryColor: "#5469d4" # ZITADEL_DEFAULTINSTANCE_LABELPOLICY_PRIMARYCOLOR + BackgroundColor: "#fafafa" # ZITADEL_DEFAULTINSTANCE_LABELPOLICY_BACKGROUNDCOLOR + WarnColor: "#cd3d56" # ZITADEL_DEFAULTINSTANCE_LABELPOLICY_WARNCOLOR + FontColor: "#000000" # ZITADEL_DEFAULTINSTANCE_LABELPOLICY_FONTCOLOR + PrimaryColorDark: "#2073c4" # ZITADEL_DEFAULTINSTANCE_LABELPOLICY_PRIMARYCOLORDARK + BackgroundColorDark: "#111827" # ZITADEL_DEFAULTINSTANCE_LABELPOLICY_BACKGROUNDCOLORDARK + WarnColorDark: "#ff3b5b" # ZITADEL_DEFAULTINSTANCE_LABELPOLICY_WARNCOLORDARK + FontColorDark: "#ffffff" # ZITADEL_DEFAULTINSTANCE_LABELPOLICY_FONTCOLORDARK + HideLoginNameSuffix: false # ZITADEL_DEFAULTINSTANCE_LABELPOLICY_HIDELOGINNAMESUFFIX + ErrorMsgPopup: false # ZITADEL_DEFAULTINSTANCE_LABELPOLICY_ERRORMSGPOPUP + DisableWatermark: false # ZITADEL_DEFAULTINSTANCE_LABELPOLICY_DISABLEWATERMARK LockoutPolicy: - MaxAttempts: 0 - ShouldShowLockoutFailure: true - EmailTemplate: CjwhZG9jdHlwZSBodG1sPgo8aHRtbCB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCIgeG1sbnM6dj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp2bWwiIHhtbG5zOm89InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206b2ZmaWNlOm9mZmljZSI+CjxoZWFkPgogIDx0aXRsZT4KCiAgPC90aXRsZT4KICA8IS0tW2lmICFtc29dPjwhLS0+CiAgPG1ldGEgaHR0cC1lcXVpdj0iWC1VQS1Db21wYXRpYmxlIiBjb250ZW50PSJJRT1lZGdlIj4KICA8IS0tPCFbZW5kaWZdLS0+CiAgPG1ldGEgaHR0cC1lcXVpdj0iQ29udGVudC1UeXBlIiBjb250ZW50PSJ0ZXh0L2h0bWw7IGNoYXJzZXQ9VVRGLTgiPgogIDxtZXRhIG5hbWU9InZpZXdwb3J0IiBjb250ZW50PSJ3aWR0aD1kZXZpY2Utd2lkdGgsIGluaXRpYWwtc2NhbGU9MSI+CiAgPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KICAgICNvdXRsb29rIGEgeyBwYWRkaW5nOjA7IH0KICAgIGJvZHkgeyBtYXJnaW46MDtwYWRkaW5nOjA7LXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OjEwMCU7LW1zLXRleHQtc2l6ZS1hZGp1c3Q6MTAwJTsgfQogICAgdGFibGUsIHRkIHsgYm9yZGVyLWNvbGxhcHNlOmNvbGxhcHNlO21zby10YWJsZS1sc3BhY2U6MHB0O21zby10YWJsZS1yc3BhY2U6MHB0OyB9CiAgICBpbWcgeyBib3JkZXI6MDtoZWlnaHQ6YXV0bztsaW5lLWhlaWdodDoxMDAlOyBvdXRsaW5lOm5vbmU7dGV4dC1kZWNvcmF0aW9uOm5vbmU7LW1zLWludGVycG9sYXRpb24tbW9kZTpiaWN1YmljOyB9CiAgICBwIHsgZGlzcGxheTpibG9jazttYXJnaW46MTNweCAwOyB9CiAgPC9zdHlsZT4KICA8IS0tW2lmIG1zb10+CiAgPHhtbD4KICAgIDxvOk9mZmljZURvY3VtZW50U2V0dGluZ3M+CiAgICAgIDxvOkFsbG93UE5HLz4KICAgICAgPG86UGl4ZWxzUGVySW5jaD45NjwvbzpQaXhlbHNQZXJJbmNoPgogICAgPC9vOk9mZmljZURvY3VtZW50U2V0dGluZ3M+CiAgPC94bWw+CiAgPCFbZW5kaWZdLS0+CiAgPCEtLVtpZiBsdGUgbXNvIDExXT4KICA8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgogICAgLm1qLW91dGxvb2stZ3JvdXAtZml4IHsgd2lkdGg6MTAwJSAhaW1wb3J0YW50OyB9CiAgPC9zdHlsZT4KICA8IVtlbmRpZl0tLT4KCgogIDxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+CiAgICBAbWVkaWEgb25seSBzY3JlZW4gYW5kIChtaW4td2lkdGg6NDgwcHgpIHsKICAgICAgLm1qLWNvbHVtbi1wZXItMTAwIHsgd2lkdGg6MTAwJSAhaW1wb3J0YW50OyBtYXgtd2lkdGg6IDEwMCU7IH0KICAgICAgLm1qLWNvbHVtbi1wZXItNjAgeyB3aWR0aDo2MCUgIWltcG9ydGFudDsgbWF4LXdpZHRoOiA2MCU7IH0KICAgIH0KICA8L3N0eWxlPgoKCiAgPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KCgoKICAgIEBtZWRpYSBvbmx5IHNjcmVlbiBhbmQgKG1heC13aWR0aDo0ODBweCkgewogICAgICB0YWJsZS5tai1mdWxsLXdpZHRoLW1vYmlsZSB7IHdpZHRoOiAxMDAlICFpbXBvcnRhbnQ7IH0KICAgICAgdGQubWotZnVsbC13aWR0aC1tb2JpbGUgeyB3aWR0aDogYXV0byAhaW1wb3J0YW50OyB9CiAgICB9CgogIDwvc3R5bGU+CiAgPHN0eWxlIHR5cGU9InRleHQvY3NzIj4uc2hhZG93IGEgewogICAgYm94LXNoYWRvdzogMHB4IDNweCAxcHggLTJweCByZ2JhKDAsIDAsIDAsIDAuMiksIDBweCAycHggMnB4IDBweCByZ2JhKDAsIDAsIDAsIDAuMTQpLCAwcHggMXB4IDVweCAwcHggcmdiYSgwLCAwLCAwLCAwLjEyKTsKICB9PC9zdHlsZT4KCiAge3tpZiAuRm9udFVSTH19CiAgPHN0eWxlPgogICAgQGZvbnQtZmFjZSB7CiAgICAgIGZvbnQtZmFtaWx5OiAne3suRm9udEZhY2VGYW1pbHl9fSc7CiAgICAgIGZvbnQtc3R5bGU6IG5vcm1hbDsKICAgICAgZm9udC1kaXNwbGF5OiBzd2FwOwogICAgICBzcmM6IHVybCh7ey5Gb250VVJMfX0pOwogICAgfQogIDwvc3R5bGU+CiAge3tlbmR9fQoKPC9oZWFkPgo8Ym9keSBzdHlsZT0id29yZC1zcGFjaW5nOm5vcm1hbDsiPgoKCjxkaXYKICAgICAgICBzdHlsZT0iIgo+CgogIDx0YWJsZQogICAgICAgICAgYWxpZ249ImNlbnRlciIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHJvbGU9InByZXNlbnRhdGlvbiIgc3R5bGU9ImJhY2tncm91bmQ6e3suQmFja2dyb3VuZENvbG9yfX07YmFja2dyb3VuZC1jb2xvcjp7ey5CYWNrZ3JvdW5kQ29sb3J9fTt3aWR0aDoxMDAlO2JvcmRlci1yYWRpdXM6MTZweDsiCiAgPgogICAgPHRib2R5PgogICAgPHRyPgogICAgICA8dGQ+CgoKICAgICAgICA8IS0tW2lmIG1zbyB8IElFXT48dGFibGUgYWxpZ249ImNlbnRlciIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIGNsYXNzPSIiIHN0eWxlPSJ3aWR0aDo4MDBweDsiIHdpZHRoPSI4MDAiID48dHI+PHRkIHN0eWxlPSJsaW5lLWhlaWdodDowcHg7Zm9udC1zaXplOjBweDttc28tbGluZS1oZWlnaHQtcnVsZTpleGFjdGx5OyI+PCFbZW5kaWZdLS0+CgoKICAgICAgICA8ZGl2ICBzdHlsZT0ibWFyZ2luOjBweCBhdXRvO2JvcmRlci1yYWRpdXM6MTZweDttYXgtd2lkdGg6ODAwcHg7Ij4KCiAgICAgICAgICA8dGFibGUKICAgICAgICAgICAgICAgICAgYWxpZ249ImNlbnRlciIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHJvbGU9InByZXNlbnRhdGlvbiIgc3R5bGU9IndpZHRoOjEwMCU7Ym9yZGVyLXJhZGl1czoxNnB4OyIKICAgICAgICAgID4KICAgICAgICAgICAgPHRib2R5PgogICAgICAgICAgICA8dHI+CiAgICAgICAgICAgICAgPHRkCiAgICAgICAgICAgICAgICAgICAgICBzdHlsZT0iZGlyZWN0aW9uOmx0cjtmb250LXNpemU6MHB4O3BhZGRpbmc6MjBweCAwO3BhZGRpbmctbGVmdDowO3RleHQtYWxpZ246Y2VudGVyOyIKICAgICAgICAgICAgICA+CiAgICAgICAgICAgICAgICA8IS0tW2lmIG1zbyB8IElFXT48dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCI+PHRyPjx0ZCBjbGFzcz0iIiB3aWR0aD0iODAwcHgiID48IVtlbmRpZl0tLT4KCiAgICAgICAgICAgICAgICA8dGFibGUKICAgICAgICAgICAgICAgICAgICAgICAgYWxpZ249ImNlbnRlciIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHJvbGU9InByZXNlbnRhdGlvbiIgc3R5bGU9IndpZHRoOjEwMCU7IgogICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICA8dGJvZHk+CiAgICAgICAgICAgICAgICAgIDx0cj4KICAgICAgICAgICAgICAgICAgICA8dGQ+CgoKICAgICAgICAgICAgICAgICAgICAgIDwhLS1baWYgbXNvIHwgSUVdPjx0YWJsZSBhbGlnbj0iY2VudGVyIiBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgY2xhc3M9IiIgc3R5bGU9IndpZHRoOjgwMHB4OyIgd2lkdGg9IjgwMCIgPjx0cj48dGQgc3R5bGU9ImxpbmUtaGVpZ2h0OjBweDtmb250LXNpemU6MHB4O21zby1saW5lLWhlaWdodC1ydWxlOmV4YWN0bHk7Ij48IVtlbmRpZl0tLT4KCgogICAgICAgICAgICAgICAgICAgICAgPGRpdiAgc3R5bGU9Im1hcmdpbjowcHggYXV0bzttYXgtd2lkdGg6ODAwcHg7Ij4KCiAgICAgICAgICAgICAgICAgICAgICAgIDx0YWJsZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsaWduPSJjZW50ZXIiIGJvcmRlcj0iMCIgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIiByb2xlPSJwcmVzZW50YXRpb24iIHN0eWxlPSJ3aWR0aDoxMDAlOyIKICAgICAgICAgICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICAgICAgICAgIDx0Ym9keT4KICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3R5bGU9ImRpcmVjdGlvbjpsdHI7Zm9udC1zaXplOjBweDtwYWRkaW5nOjA7dGV4dC1hbGlnbjpjZW50ZXI7IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8IS0tW2lmIG1zbyB8IElFXT48dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCI+PHRyPjx0ZCBjbGFzcz0iIiBzdHlsZT0id2lkdGg6ODAwcHg7IiA+PCFbZW5kaWZdLS0+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3M9Im1qLWNvbHVtbi1wZXItMTAwIG1qLW91dGxvb2stZ3JvdXAtZml4IiBzdHlsZT0iZm9udC1zaXplOjA7bGluZS1oZWlnaHQ6MDt0ZXh0LWFsaWduOmxlZnQ7ZGlzcGxheTppbmxpbmUtYmxvY2s7d2lkdGg6MTAwJTtkaXJlY3Rpb246bHRyOyIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwhLS1baWYgbXNvIHwgSUVdPjx0YWJsZSBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgcm9sZT0icHJlc2VudGF0aW9uIiA+PHRyPjx0ZCBzdHlsZT0idmVydGljYWwtYWxpZ246dG9wO3dpZHRoOjgwMHB4OyIgPjwhW2VuZGlmXS0tPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGFzcz0ibWotY29sdW1uLXBlci0xMDAgbWotb3V0bG9vay1ncm91cC1maXgiIHN0eWxlPSJmb250LXNpemU6MHB4O3RleHQtYWxpZ246bGVmdDtkaXJlY3Rpb246bHRyO2Rpc3BsYXk6aW5saW5lLWJsb2NrO3ZlcnRpY2FsLWFsaWduOnRvcDt3aWR0aDoxMDAlOyIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRhYmxlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvcmRlcj0iMCIgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIiByb2xlPSJwcmVzZW50YXRpb24iIHdpZHRoPSIxMDAlIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGJvZHk+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgIHN0eWxlPSJ2ZXJ0aWNhbC1hbGlnbjp0b3A7cGFkZGluZzowOyI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7e2lmIC5Mb2dvVVJMfX0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0YWJsZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgcm9sZT0icHJlc2VudGF0aW9uIiBzdHlsZT0iIiB3aWR0aD0iMTAwJSIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRib2R5PgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxpZ249ImNlbnRlciIgc3R5bGU9ImZvbnQtc2l6ZTowcHg7cGFkZGluZzo1MHB4IDAgMzBweCAwO3dvcmQtYnJlYWs6YnJlYWstd29yZDsiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0YWJsZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgcm9sZT0icHJlc2VudGF0aW9uIiBzdHlsZT0iYm9yZGVyLWNvbGxhcHNlOmNvbGxhcHNlO2JvcmRlci1zcGFjaW5nOjBweDsiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0Ym9keT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCAgc3R5bGU9IndpZHRoOjE4MHB4OyI+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGltZwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoZWlnaHQ9ImF1dG8iIHNyYz0ie3suTG9nb1VSTH19IiBzdHlsZT0iYm9yZGVyOjA7Ym9yZGVyLXJhZGl1czo4cHg7ZGlzcGxheTpibG9jaztvdXRsaW5lOm5vbmU7dGV4dC1kZWNvcmF0aW9uOm5vbmU7aGVpZ2h0OmF1dG87d2lkdGg6MTAwJTtmb250LXNpemU6MTNweDsiIHdpZHRoPSIxODAiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3Rib2R5PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90YWJsZT4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGJvZHk+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RhYmxlPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge3tlbmR9fQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGJvZHk+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RhYmxlPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPCEtLVtpZiBtc28gfCBJRV0+PC90ZD48L3RyPjwvdGFibGU+PCFbZW5kaWZdLS0+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPCEtLVtpZiBtc28gfCBJRV0+PC90ZD48L3RyPjwvdGFibGU+PCFbZW5kaWZdLS0+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPgogICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgPC90Ym9keT4KICAgICAgICAgICAgICAgICAgICAgICAgPC90YWJsZT4KCiAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj4KCgogICAgICAgICAgICAgICAgICAgICAgPCEtLVtpZiBtc28gfCBJRV0+PC90ZD48L3RyPjwvdGFibGU+PCFbZW5kaWZdLS0+CgoKICAgICAgICAgICAgICAgICAgICA8L3RkPgogICAgICAgICAgICAgICAgICA8L3RyPgogICAgICAgICAgICAgICAgICA8L3Rib2R5PgogICAgICAgICAgICAgICAgPC90YWJsZT4KCiAgICAgICAgICAgICAgICA8IS0tW2lmIG1zbyB8IElFXT48L3RkPjwvdHI+PHRyPjx0ZCBjbGFzcz0iIiB3aWR0aD0iODAwcHgiID48IVtlbmRpZl0tLT4KCiAgICAgICAgICAgICAgICA8dGFibGUKICAgICAgICAgICAgICAgICAgICAgICAgYWxpZ249ImNlbnRlciIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHJvbGU9InByZXNlbnRhdGlvbiIgc3R5bGU9IndpZHRoOjEwMCU7IgogICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICA8dGJvZHk+CiAgICAgICAgICAgICAgICAgIDx0cj4KICAgICAgICAgICAgICAgICAgICA8dGQ+CgoKICAgICAgICAgICAgICAgICAgICAgIDwhLS1baWYgbXNvIHwgSUVdPjx0YWJsZSBhbGlnbj0iY2VudGVyIiBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgY2xhc3M9IiIgc3R5bGU9IndpZHRoOjgwMHB4OyIgd2lkdGg9IjgwMCIgPjx0cj48dGQgc3R5bGU9ImxpbmUtaGVpZ2h0OjBweDtmb250LXNpemU6MHB4O21zby1saW5lLWhlaWdodC1ydWxlOmV4YWN0bHk7Ij48IVtlbmRpZl0tLT4KCgogICAgICAgICAgICAgICAgICAgICAgPGRpdiAgc3R5bGU9Im1hcmdpbjowcHggYXV0bzttYXgtd2lkdGg6ODAwcHg7Ij4KCiAgICAgICAgICAgICAgICAgICAgICAgIDx0YWJsZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsaWduPSJjZW50ZXIiIGJvcmRlcj0iMCIgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIiByb2xlPSJwcmVzZW50YXRpb24iIHN0eWxlPSJ3aWR0aDoxMDAlOyIKICAgICAgICAgICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICAgICAgICAgIDx0Ym9keT4KICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3R5bGU9ImRpcmVjdGlvbjpsdHI7Zm9udC1zaXplOjBweDtwYWRkaW5nOjA7dGV4dC1hbGlnbjpjZW50ZXI7IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8IS0tW2lmIG1zbyB8IElFXT48dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCI+PHRyPjx0ZCBjbGFzcz0iIiBzdHlsZT0idmVydGljYWwtYWxpZ246dG9wO3dpZHRoOjQ4MHB4OyIgPjwhW2VuZGlmXS0tPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsYXNzPSJtai1jb2x1bW4tcGVyLTYwIG1qLW91dGxvb2stZ3JvdXAtZml4IiBzdHlsZT0iZm9udC1zaXplOjBweDt0ZXh0LWFsaWduOmxlZnQ7ZGlyZWN0aW9uOmx0cjtkaXNwbGF5OmlubGluZS1ibG9jazt2ZXJ0aWNhbC1hbGlnbjp0b3A7d2lkdGg6MTAwJTsiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRhYmxlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgcm9sZT0icHJlc2VudGF0aW9uIiB3aWR0aD0iMTAwJSIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGJvZHk+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCAgc3R5bGU9InZlcnRpY2FsLWFsaWduOnRvcDtwYWRkaW5nOjA7Ij4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRhYmxlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgcm9sZT0icHJlc2VudGF0aW9uIiBzdHlsZT0iIiB3aWR0aD0iMTAwJSIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGJvZHk+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbGlnbj0iY2VudGVyIiBzdHlsZT0iZm9udC1zaXplOjBweDtwYWRkaW5nOjEwcHggMjVweDt3b3JkLWJyZWFrOmJyZWFrLXdvcmQ7IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0eWxlPSJmb250LWZhbWlseTp7ey5Gb250RmFtaWx5fX07Zm9udC1zaXplOjI0cHg7Zm9udC13ZWlnaHQ6NTAwO2xpbmUtaGVpZ2h0OjE7dGV4dC1hbGlnbjpjZW50ZXI7Y29sb3I6e3suRm9udENvbG9yfX07IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID57ey5HcmVldGluZ319PC9kaXY+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsaWduPSJjZW50ZXIiIHN0eWxlPSJmb250LXNpemU6MHB4O3BhZGRpbmc6MTBweCAyNXB4O3dvcmQtYnJlYWs6YnJlYWstd29yZDsiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3R5bGU9ImZvbnQtZmFtaWx5Ont7LkZvbnRGYW1pbHl9fTtmb250LXNpemU6MTZweDtmb250LXdlaWdodDpsaWdodDtsaW5lLWhlaWdodDoxLjU7dGV4dC1hbGlnbjpjZW50ZXI7Y29sb3I6e3suRm9udENvbG9yfX07IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID57ey5UZXh0fX08L2Rpdj4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPgoKCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsaWduPSJjZW50ZXIiIHZlcnRpY2FsLWFsaWduPSJtaWRkbGUiIGNsYXNzPSJzaGFkb3ciIHN0eWxlPSJmb250LXNpemU6MHB4O3BhZGRpbmc6MTBweCAyNXB4O3dvcmQtYnJlYWs6YnJlYWstd29yZDsiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRhYmxlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgcm9sZT0icHJlc2VudGF0aW9uIiBzdHlsZT0iYm9yZGVyLWNvbGxhcHNlOnNlcGFyYXRlO2xpbmUtaGVpZ2h0OjEwMCU7IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxpZ249ImNlbnRlciIgYmdjb2xvcj0ie3suUHJpbWFyeUNvbG9yfX0iIHJvbGU9InByZXNlbnRhdGlvbiIgc3R5bGU9ImJvcmRlcjpub25lO2JvcmRlci1yYWRpdXM6NnB4O2N1cnNvcjphdXRvO21zby1wYWRkaW5nLWFsdDoxMHB4IDI1cHg7YmFja2dyb3VuZDp7ey5QcmltYXJ5Q29sb3J9fTsiIHZhbGlnbj0ibWlkZGxlIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGEKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhyZWY9Int7LlVSTH19IiByZWw9Im5vb3BlbmVyIG5vcmVmZXJyZXIgbm90cmFjayIgc3R5bGU9ImRpc3BsYXk6aW5saW5lLWJsb2NrO2JhY2tncm91bmQ6e3suUHJpbWFyeUNvbG9yfX07Y29sb3I6I2ZmZmZmZjtmb250LWZhbWlseTp7ey5Gb250RmFtaWx5fX07Zm9udC1zaXplOjE0cHg7Zm9udC13ZWlnaHQ6NTAwO2xpbmUtaGVpZ2h0OjEyMCU7bWFyZ2luOjA7dGV4dC1kZWNvcmF0aW9uOm5vbmU7dGV4dC10cmFuc2Zvcm06bm9uZTtwYWRkaW5nOjEwcHggMjVweDttc28tcGFkZGluZy1hbHQ6MHB4O2JvcmRlci1yYWRpdXM6NnB4OyIgdGFyZ2V0PSJfYmxhbmsiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge3suQnV0dG9uVGV4dH19CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9hPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RhYmxlPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7e2lmIC5JbmNsdWRlRm9vdGVyfX0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxpZ249ImNlbnRlciIgc3R5bGU9ImZvbnQtc2l6ZTowcHg7cGFkZGluZzoxMHB4IDI1cHg7cGFkZGluZy10b3A6MjBweDtwYWRkaW5nLXJpZ2h0OjIwcHg7cGFkZGluZy1ib3R0b206MjBweDtwYWRkaW5nLWxlZnQ6MjBweDt3b3JkLWJyZWFrOmJyZWFrLXdvcmQ7IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxwCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHlsZT0iYm9yZGVyLXRvcDpzb2xpZCAycHggI2RiZGJkYjtmb250LXNpemU6MXB4O21hcmdpbjowcHggYXV0bzt3aWR0aDoxMDAlOyIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9wPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8IS0tW2lmIG1zbyB8IElFXT48dGFibGUgYWxpZ249ImNlbnRlciIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHN0eWxlPSJib3JkZXItdG9wOnNvbGlkIDJweCAjZGJkYmRiO2ZvbnQtc2l6ZToxcHg7bWFyZ2luOjBweCBhdXRvO3dpZHRoOjQ0MHB4OyIgcm9sZT0icHJlc2VudGF0aW9uIiB3aWR0aD0iNDQwcHgiID48dHI+PHRkIHN0eWxlPSJoZWlnaHQ6MDtsaW5lLWhlaWdodDowOyI+ICZuYnNwOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ+PC90cj48L3RhYmxlPjwhW2VuZGlmXS0tPgoKCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxpZ249ImNlbnRlciIgc3R5bGU9ImZvbnQtc2l6ZTowcHg7cGFkZGluZzoxNnB4O3dvcmQtYnJlYWs6YnJlYWstd29yZDsiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3R5bGU9ImZvbnQtZmFtaWx5Ont7LkZvbnRGYW1pbHl9fTtmb250LXNpemU6MTNweDtsaW5lLWhlaWdodDoxO3RleHQtYWxpZ246Y2VudGVyO2NvbG9yOnt7LkZvbnRDb2xvcn19OyIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA+e3suRm9vdGVyVGV4dH19PC9kaXY+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHt7ZW5kfX0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGJvZHk+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90YWJsZT4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90Ym9keT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RhYmxlPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8IS0tW2lmIG1zbyB8IElFXT48L3RkPjwvdHI+PC90YWJsZT48IVtlbmRpZl0tLT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4KICAgICAgICAgICAgICAgICAgICAgICAgICA8L3Rib2R5PgogICAgICAgICAgICAgICAgICAgICAgICA8L3RhYmxlPgoKICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PgoKCiAgICAgICAgICAgICAgICAgICAgICA8IS0tW2lmIG1zbyB8IElFXT48L3RkPjwvdHI+PC90YWJsZT48IVtlbmRpZl0tLT4KCgogICAgICAgICAgICAgICAgICAgIDwvdGQ+CiAgICAgICAgICAgICAgICAgIDwvdHI+CiAgICAgICAgICAgICAgICAgIDwvdGJvZHk+CiAgICAgICAgICAgICAgICA8L3RhYmxlPgoKICAgICAgICAgICAgICAgIDwhLS1baWYgbXNvIHwgSUVdPjwvdGQ+PC90cj48L3RhYmxlPjwhW2VuZGlmXS0tPgogICAgICAgICAgICAgIDwvdGQ+CiAgICAgICAgICAgIDwvdHI+CiAgICAgICAgICAgIDwvdGJvZHk+CiAgICAgICAgICA8L3RhYmxlPgoKICAgICAgICA8L2Rpdj4KCgogICAgICAgIDwhLS1baWYgbXNvIHwgSUVdPjwvdGQ+PC90cj48L3RhYmxlPjwhW2VuZGlmXS0tPgoKCiAgICAgIDwvdGQ+CiAgICA8L3RyPgogICAgPC90Ym9keT4KICA8L3RhYmxlPgoKPC9kaXY+Cgo8L2JvZHk+CjwvaHRtbD4K + MaxAttempts: 0 # ZITADEL_DEFAULTINSTANCE_LOCKOUTPOLICY_MAXATTEMPTS + ShouldShowLockoutFailure: true # ZITADEL_DEFAULTINSTANCE_LOCKOUTPOLICY_SHOULDSHOWLOCKOUTFAILURE + EmailTemplate: CjwhZG9jdHlwZSBodG1sPgo8aHRtbCB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCIgeG1sbnM6dj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp2bWwiIHhtbG5zOm89InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206b2ZmaWNlOm9mZmljZSI+CjxoZWFkPgogIDx0aXRsZT4KCiAgPC90aXRsZT4KICA8IS0tW2lmICFtc29dPjwhLS0+CiAgPG1ldGEgaHR0cC1lcXVpdj0iWC1VQS1Db21wYXRpYmxlIiBjb250ZW50PSJJRT1lZGdlIj4KICA8IS0tPCFbZW5kaWZdLS0+CiAgPG1ldGEgaHR0cC1lcXVpdj0iQ29udGVudC1UeXBlIiBjb250ZW50PSJ0ZXh0L2h0bWw7IGNoYXJzZXQ9VVRGLTgiPgogIDxtZXRhIG5hbWU9InZpZXdwb3J0IiBjb250ZW50PSJ3aWR0aD1kZXZpY2Utd2lkdGgsIGluaXRpYWwtc2NhbGU9MSI+CiAgPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KICAgICNvdXRsb29rIGEgeyBwYWRkaW5nOjA7IH0KICAgIGJvZHkgeyBtYXJnaW46MDtwYWRkaW5nOjA7LXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OjEwMCU7LW1zLXRleHQtc2l6ZS1hZGp1c3Q6MTAwJTsgfQogICAgdGFibGUsIHRkIHsgYm9yZGVyLWNvbGxhcHNlOmNvbGxhcHNlO21zby10YWJsZS1sc3BhY2U6MHB0O21zby10YWJsZS1yc3BhY2U6MHB0OyB9CiAgICBpbWcgeyBib3JkZXI6MDtoZWlnaHQ6YXV0bztsaW5lLWhlaWdodDoxMDAlOyBvdXRsaW5lOm5vbmU7dGV4dC1kZWNvcmF0aW9uOm5vbmU7LW1zLWludGVycG9sYXRpb24tbW9kZTpiaWN1YmljOyB9CiAgICBwIHsgZGlzcGxheTpibG9jazttYXJnaW46MTNweCAwOyB9CiAgPC9zdHlsZT4KICA8IS0tW2lmIG1zb10+CiAgPHhtbD4KICAgIDxvOk9mZmljZURvY3VtZW50U2V0dGluZ3M+CiAgICAgIDxvOkFsbG93UE5HLz4KICAgICAgPG86UGl4ZWxzUGVySW5jaD45NjwvbzpQaXhlbHNQZXJJbmNoPgogICAgPC9vOk9mZmljZURvY3VtZW50U2V0dGluZ3M+CiAgPC94bWw+CiAgPCFbZW5kaWZdLS0+CiAgPCEtLVtpZiBsdGUgbXNvIDExXT4KICA8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgogICAgLm1qLW91dGxvb2stZ3JvdXAtZml4IHsgd2lkdGg6MTAwJSAhaW1wb3J0YW50OyB9CiAgPC9zdHlsZT4KICA8IVtlbmRpZl0tLT4KCgogIDxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+CiAgICBAbWVkaWEgb25seSBzY3JlZW4gYW5kIChtaW4td2lkdGg6NDgwcHgpIHsKICAgICAgLm1qLWNvbHVtbi1wZXItMTAwIHsgd2lkdGg6MTAwJSAhaW1wb3J0YW50OyBtYXgtd2lkdGg6IDEwMCU7IH0KICAgICAgLm1qLWNvbHVtbi1wZXItNjAgeyB3aWR0aDo2MCUgIWltcG9ydGFudDsgbWF4LXdpZHRoOiA2MCU7IH0KICAgIH0KICA8L3N0eWxlPgoKCiAgPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KCgoKICAgIEBtZWRpYSBvbmx5IHNjcmVlbiBhbmQgKG1heC13aWR0aDo0ODBweCkgewogICAgICB0YWJsZS5tai1mdWxsLXdpZHRoLW1vYmlsZSB7IHdpZHRoOiAxMDAlICFpbXBvcnRhbnQ7IH0KICAgICAgdGQubWotZnVsbC13aWR0aC1tb2JpbGUgeyB3aWR0aDogYXV0byAhaW1wb3J0YW50OyB9CiAgICB9CgogIDwvc3R5bGU+CiAgPHN0eWxlIHR5cGU9InRleHQvY3NzIj4uc2hhZG93IGEgewogICAgYm94LXNoYWRvdzogMHB4IDNweCAxcHggLTJweCByZ2JhKDAsIDAsIDAsIDAuMiksIDBweCAycHggMnB4IDBweCByZ2JhKDAsIDAsIDAsIDAuMTQpLCAwcHggMXB4IDVweCAwcHggcmdiYSgwLCAwLCAwLCAwLjEyKTsKICB9PC9zdHlsZT4KCiAge3tpZiAuRm9udFVSTH19CiAgPHN0eWxlPgogICAgQGZvbnQtZmFjZSB7CiAgICAgIGZvbnQtZmFtaWx5OiAne3suRm9udEZhY2VGYW1pbHl9fSc7CiAgICAgIGZvbnQtc3R5bGU6IG5vcm1hbDsKICAgICAgZm9udC1kaXNwbGF5OiBzd2FwOwogICAgICBzcmM6IHVybCh7ey5Gb250VVJMfX0pOwogICAgfQogIDwvc3R5bGU+CiAge3tlbmR9fQoKPC9oZWFkPgo8Ym9keSBzdHlsZT0id29yZC1zcGFjaW5nOm5vcm1hbDsiPgoKCjxkaXYKICAgICAgICBzdHlsZT0iIgo+CgogIDx0YWJsZQogICAgICAgICAgYWxpZ249ImNlbnRlciIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHJvbGU9InByZXNlbnRhdGlvbiIgc3R5bGU9ImJhY2tncm91bmQ6e3suQmFja2dyb3VuZENvbG9yfX07YmFja2dyb3VuZC1jb2xvcjp7ey5CYWNrZ3JvdW5kQ29sb3J9fTt3aWR0aDoxMDAlO2JvcmRlci1yYWRpdXM6MTZweDsiCiAgPgogICAgPHRib2R5PgogICAgPHRyPgogICAgICA8dGQ+CgoKICAgICAgICA8IS0tW2lmIG1zbyB8IElFXT48dGFibGUgYWxpZ249ImNlbnRlciIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIGNsYXNzPSIiIHN0eWxlPSJ3aWR0aDo4MDBweDsiIHdpZHRoPSI4MDAiID48dHI+PHRkIHN0eWxlPSJsaW5lLWhlaWdodDowcHg7Zm9udC1zaXplOjBweDttc28tbGluZS1oZWlnaHQtcnVsZTpleGFjdGx5OyI+PCFbZW5kaWZdLS0+CgoKICAgICAgICA8ZGl2ICBzdHlsZT0ibWFyZ2luOjBweCBhdXRvO2JvcmRlci1yYWRpdXM6MTZweDttYXgtd2lkdGg6ODAwcHg7Ij4KCiAgICAgICAgICA8dGFibGUKICAgICAgICAgICAgICAgICAgYWxpZ249ImNlbnRlciIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHJvbGU9InByZXNlbnRhdGlvbiIgc3R5bGU9IndpZHRoOjEwMCU7Ym9yZGVyLXJhZGl1czoxNnB4OyIKICAgICAgICAgID4KICAgICAgICAgICAgPHRib2R5PgogICAgICAgICAgICA8dHI+CiAgICAgICAgICAgICAgPHRkCiAgICAgICAgICAgICAgICAgICAgICBzdHlsZT0iZGlyZWN0aW9uOmx0cjtmb250LXNpemU6MHB4O3BhZGRpbmc6MjBweCAwO3BhZGRpbmctbGVmdDowO3RleHQtYWxpZ246Y2VudGVyOyIKICAgICAgICAgICAgICA+CiAgICAgICAgICAgICAgICA8IS0tW2lmIG1zbyB8IElFXT48dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCI+PHRyPjx0ZCBjbGFzcz0iIiB3aWR0aD0iODAwcHgiID48IVtlbmRpZl0tLT4KCiAgICAgICAgICAgICAgICA8dGFibGUKICAgICAgICAgICAgICAgICAgICAgICAgYWxpZ249ImNlbnRlciIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHJvbGU9InByZXNlbnRhdGlvbiIgc3R5bGU9IndpZHRoOjEwMCU7IgogICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICA8dGJvZHk+CiAgICAgICAgICAgICAgICAgIDx0cj4KICAgICAgICAgICAgICAgICAgICA8dGQ+CgoKICAgICAgICAgICAgICAgICAgICAgIDwhLS1baWYgbXNvIHwgSUVdPjx0YWJsZSBhbGlnbj0iY2VudGVyIiBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgY2xhc3M9IiIgc3R5bGU9IndpZHRoOjgwMHB4OyIgd2lkdGg9IjgwMCIgPjx0cj48dGQgc3R5bGU9ImxpbmUtaGVpZ2h0OjBweDtmb250LXNpemU6MHB4O21zby1saW5lLWhlaWdodC1ydWxlOmV4YWN0bHk7Ij48IVtlbmRpZl0tLT4KCgogICAgICAgICAgICAgICAgICAgICAgPGRpdiAgc3R5bGU9Im1hcmdpbjowcHggYXV0bzttYXgtd2lkdGg6ODAwcHg7Ij4KCiAgICAgICAgICAgICAgICAgICAgICAgIDx0YWJsZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsaWduPSJjZW50ZXIiIGJvcmRlcj0iMCIgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIiByb2xlPSJwcmVzZW50YXRpb24iIHN0eWxlPSJ3aWR0aDoxMDAlOyIKICAgICAgICAgICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICAgICAgICAgIDx0Ym9keT4KICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3R5bGU9ImRpcmVjdGlvbjpsdHI7Zm9udC1zaXplOjBweDtwYWRkaW5nOjA7dGV4dC1hbGlnbjpjZW50ZXI7IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8IS0tW2lmIG1zbyB8IElFXT48dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCI+PHRyPjx0ZCBjbGFzcz0iIiBzdHlsZT0id2lkdGg6ODAwcHg7IiA+PCFbZW5kaWZdLS0+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3M9Im1qLWNvbHVtbi1wZXItMTAwIG1qLW91dGxvb2stZ3JvdXAtZml4IiBzdHlsZT0iZm9udC1zaXplOjA7bGluZS1oZWlnaHQ6MDt0ZXh0LWFsaWduOmxlZnQ7ZGlzcGxheTppbmxpbmUtYmxvY2s7d2lkdGg6MTAwJTtkaXJlY3Rpb246bHRyOyIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwhLS1baWYgbXNvIHwgSUVdPjx0YWJsZSBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgcm9sZT0icHJlc2VudGF0aW9uIiA+PHRyPjx0ZCBzdHlsZT0idmVydGljYWwtYWxpZ246dG9wO3dpZHRoOjgwMHB4OyIgPjwhW2VuZGlmXS0tPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGFzcz0ibWotY29sdW1uLXBlci0xMDAgbWotb3V0bG9vay1ncm91cC1maXgiIHN0eWxlPSJmb250LXNpemU6MHB4O3RleHQtYWxpZ246bGVmdDtkaXJlY3Rpb246bHRyO2Rpc3BsYXk6aW5saW5lLWJsb2NrO3ZlcnRpY2FsLWFsaWduOnRvcDt3aWR0aDoxMDAlOyIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRhYmxlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvcmRlcj0iMCIgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIiByb2xlPSJwcmVzZW50YXRpb24iIHdpZHRoPSIxMDAlIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGJvZHk+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgIHN0eWxlPSJ2ZXJ0aWNhbC1hbGlnbjp0b3A7cGFkZGluZzowOyI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7e2lmIC5Mb2dvVVJMfX0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0YWJsZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgcm9sZT0icHJlc2VudGF0aW9uIiBzdHlsZT0iIiB3aWR0aD0iMTAwJSIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRib2R5PgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxpZ249ImNlbnRlciIgc3R5bGU9ImZvbnQtc2l6ZTowcHg7cGFkZGluZzo1MHB4IDAgMzBweCAwO3dvcmQtYnJlYWs6YnJlYWstd29yZDsiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0YWJsZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgcm9sZT0icHJlc2VudGF0aW9uIiBzdHlsZT0iYm9yZGVyLWNvbGxhcHNlOmNvbGxhcHNlO2JvcmRlci1zcGFjaW5nOjBweDsiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0Ym9keT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCAgc3R5bGU9IndpZHRoOjE4MHB4OyI+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGltZwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoZWlnaHQ9ImF1dG8iIHNyYz0ie3suTG9nb1VSTH19IiBzdHlsZT0iYm9yZGVyOjA7Ym9yZGVyLXJhZGl1czo4cHg7ZGlzcGxheTpibG9jaztvdXRsaW5lOm5vbmU7dGV4dC1kZWNvcmF0aW9uOm5vbmU7aGVpZ2h0OmF1dG87d2lkdGg6MTAwJTtmb250LXNpemU6MTNweDsiIHdpZHRoPSIxODAiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3Rib2R5PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90YWJsZT4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGJvZHk+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RhYmxlPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge3tlbmR9fQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGJvZHk+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RhYmxlPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPCEtLVtpZiBtc28gfCBJRV0+PC90ZD48L3RyPjwvdGFibGU+PCFbZW5kaWZdLS0+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPCEtLVtpZiBtc28gfCBJRV0+PC90ZD48L3RyPjwvdGFibGU+PCFbZW5kaWZdLS0+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPgogICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgPC90Ym9keT4KICAgICAgICAgICAgICAgICAgICAgICAgPC90YWJsZT4KCiAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj4KCgogICAgICAgICAgICAgICAgICAgICAgPCEtLVtpZiBtc28gfCBJRV0+PC90ZD48L3RyPjwvdGFibGU+PCFbZW5kaWZdLS0+CgoKICAgICAgICAgICAgICAgICAgICA8L3RkPgogICAgICAgICAgICAgICAgICA8L3RyPgogICAgICAgICAgICAgICAgICA8L3Rib2R5PgogICAgICAgICAgICAgICAgPC90YWJsZT4KCiAgICAgICAgICAgICAgICA8IS0tW2lmIG1zbyB8IElFXT48L3RkPjwvdHI+PHRyPjx0ZCBjbGFzcz0iIiB3aWR0aD0iODAwcHgiID48IVtlbmRpZl0tLT4KCiAgICAgICAgICAgICAgICA8dGFibGUKICAgICAgICAgICAgICAgICAgICAgICAgYWxpZ249ImNlbnRlciIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHJvbGU9InByZXNlbnRhdGlvbiIgc3R5bGU9IndpZHRoOjEwMCU7IgogICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICA8dGJvZHk+CiAgICAgICAgICAgICAgICAgIDx0cj4KICAgICAgICAgICAgICAgICAgICA8dGQ+CgoKICAgICAgICAgICAgICAgICAgICAgIDwhLS1baWYgbXNvIHwgSUVdPjx0YWJsZSBhbGlnbj0iY2VudGVyIiBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgY2xhc3M9IiIgc3R5bGU9IndpZHRoOjgwMHB4OyIgd2lkdGg9IjgwMCIgPjx0cj48dGQgc3R5bGU9ImxpbmUtaGVpZ2h0OjBweDtmb250LXNpemU6MHB4O21zby1saW5lLWhlaWdodC1ydWxlOmV4YWN0bHk7Ij48IVtlbmRpZl0tLT4KCgogICAgICAgICAgICAgICAgICAgICAgPGRpdiAgc3R5bGU9Im1hcmdpbjowcHggYXV0bzttYXgtd2lkdGg6ODAwcHg7Ij4KCiAgICAgICAgICAgICAgICAgICAgICAgIDx0YWJsZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsaWduPSJjZW50ZXIiIGJvcmRlcj0iMCIgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIiByb2xlPSJwcmVzZW50YXRpb24iIHN0eWxlPSJ3aWR0aDoxMDAlOyIKICAgICAgICAgICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICAgICAgICAgIDx0Ym9keT4KICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3R5bGU9ImRpcmVjdGlvbjpsdHI7Zm9udC1zaXplOjBweDtwYWRkaW5nOjA7dGV4dC1hbGlnbjpjZW50ZXI7IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8IS0tW2lmIG1zbyB8IElFXT48dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCI+PHRyPjx0ZCBjbGFzcz0iIiBzdHlsZT0idmVydGljYWwtYWxpZ246dG9wO3dpZHRoOjQ4MHB4OyIgPjwhW2VuZGlmXS0tPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsYXNzPSJtai1jb2x1bW4tcGVyLTYwIG1qLW91dGxvb2stZ3JvdXAtZml4IiBzdHlsZT0iZm9udC1zaXplOjBweDt0ZXh0LWFsaWduOmxlZnQ7ZGlyZWN0aW9uOmx0cjtkaXNwbGF5OmlubGluZS1ibG9jazt2ZXJ0aWNhbC1hbGlnbjp0b3A7d2lkdGg6MTAwJTsiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRhYmxlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgcm9sZT0icHJlc2VudGF0aW9uIiB3aWR0aD0iMTAwJSIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGJvZHk+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCAgc3R5bGU9InZlcnRpY2FsLWFsaWduOnRvcDtwYWRkaW5nOjA7Ij4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRhYmxlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgcm9sZT0icHJlc2VudGF0aW9uIiBzdHlsZT0iIiB3aWR0aD0iMTAwJSIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGJvZHk+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbGlnbj0iY2VudGVyIiBzdHlsZT0iZm9udC1zaXplOjBweDtwYWRkaW5nOjEwcHggMjVweDt3b3JkLWJyZWFrOmJyZWFrLXdvcmQ7IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0eWxlPSJmb250LWZhbWlseTp7ey5Gb250RmFtaWx5fX07Zm9udC1zaXplOjI0cHg7Zm9udC13ZWlnaHQ6NTAwO2xpbmUtaGVpZ2h0OjE7dGV4dC1hbGlnbjpjZW50ZXI7Y29sb3I6e3suRm9udENvbG9yfX07IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID57ey5HcmVldGluZ319PC9kaXY+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsaWduPSJjZW50ZXIiIHN0eWxlPSJmb250LXNpemU6MHB4O3BhZGRpbmc6MTBweCAyNXB4O3dvcmQtYnJlYWs6YnJlYWstd29yZDsiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3R5bGU9ImZvbnQtZmFtaWx5Ont7LkZvbnRGYW1pbHl9fTtmb250LXNpemU6MTZweDtmb250LXdlaWdodDpsaWdodDtsaW5lLWhlaWdodDoxLjU7dGV4dC1hbGlnbjpjZW50ZXI7Y29sb3I6e3suRm9udENvbG9yfX07IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID57ey5UZXh0fX08L2Rpdj4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPgoKCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsaWduPSJjZW50ZXIiIHZlcnRpY2FsLWFsaWduPSJtaWRkbGUiIGNsYXNzPSJzaGFkb3ciIHN0eWxlPSJmb250LXNpemU6MHB4O3BhZGRpbmc6MTBweCAyNXB4O3dvcmQtYnJlYWs6YnJlYWstd29yZDsiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRhYmxlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgcm9sZT0icHJlc2VudGF0aW9uIiBzdHlsZT0iYm9yZGVyLWNvbGxhcHNlOnNlcGFyYXRlO2xpbmUtaGVpZ2h0OjEwMCU7IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxpZ249ImNlbnRlciIgYmdjb2xvcj0ie3suUHJpbWFyeUNvbG9yfX0iIHJvbGU9InByZXNlbnRhdGlvbiIgc3R5bGU9ImJvcmRlcjpub25lO2JvcmRlci1yYWRpdXM6NnB4O2N1cnNvcjphdXRvO21zby1wYWRkaW5nLWFsdDoxMHB4IDI1cHg7YmFja2dyb3VuZDp7ey5QcmltYXJ5Q29sb3J9fTsiIHZhbGlnbj0ibWlkZGxlIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGEKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhyZWY9Int7LlVSTH19IiByZWw9Im5vb3BlbmVyIG5vcmVmZXJyZXIgbm90cmFjayIgc3R5bGU9ImRpc3BsYXk6aW5saW5lLWJsb2NrO2JhY2tncm91bmQ6e3suUHJpbWFyeUNvbG9yfX07Y29sb3I6I2ZmZmZmZjtmb250LWZhbWlseTp7ey5Gb250RmFtaWx5fX07Zm9udC1zaXplOjE0cHg7Zm9udC13ZWlnaHQ6NTAwO2xpbmUtaGVpZ2h0OjEyMCU7bWFyZ2luOjA7dGV4dC1kZWNvcmF0aW9uOm5vbmU7dGV4dC10cmFuc2Zvcm06bm9uZTtwYWRkaW5nOjEwcHggMjVweDttc28tcGFkZGluZy1hbHQ6MHB4O2JvcmRlci1yYWRpdXM6NnB4OyIgdGFyZ2V0PSJfYmxhbmsiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge3suQnV0dG9uVGV4dH19CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9hPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RhYmxlPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7e2lmIC5JbmNsdWRlRm9vdGVyfX0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxpZ249ImNlbnRlciIgc3R5bGU9ImZvbnQtc2l6ZTowcHg7cGFkZGluZzoxMHB4IDI1cHg7cGFkZGluZy10b3A6MjBweDtwYWRkaW5nLXJpZ2h0OjIwcHg7cGFkZGluZy1ib3R0b206MjBweDtwYWRkaW5nLWxlZnQ6MjBweDt3b3JkLWJyZWFrOmJyZWFrLXdvcmQ7IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxwCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHlsZT0iYm9yZGVyLXRvcDpzb2xpZCAycHggI2RiZGJkYjtmb250LXNpemU6MXB4O21hcmdpbjowcHggYXV0bzt3aWR0aDoxMDAlOyIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9wPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8IS0tW2lmIG1zbyB8IElFXT48dGFibGUgYWxpZ249ImNlbnRlciIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHN0eWxlPSJib3JkZXItdG9wOnNvbGlkIDJweCAjZGJkYmRiO2ZvbnQtc2l6ZToxcHg7bWFyZ2luOjBweCBhdXRvO3dpZHRoOjQ0MHB4OyIgcm9sZT0icHJlc2VudGF0aW9uIiB3aWR0aD0iNDQwcHgiID48dHI+PHRkIHN0eWxlPSJoZWlnaHQ6MDtsaW5lLWhlaWdodDowOyI+ICZuYnNwOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ+PC90cj48L3RhYmxlPjwhW2VuZGlmXS0tPgoKCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxpZ249ImNlbnRlciIgc3R5bGU9ImZvbnQtc2l6ZTowcHg7cGFkZGluZzoxNnB4O3dvcmQtYnJlYWs6YnJlYWstd29yZDsiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3R5bGU9ImZvbnQtZmFtaWx5Ont7LkZvbnRGYW1pbHl9fTtmb250LXNpemU6MTNweDtsaW5lLWhlaWdodDoxO3RleHQtYWxpZ246Y2VudGVyO2NvbG9yOnt7LkZvbnRDb2xvcn19OyIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA+e3suRm9vdGVyVGV4dH19PC9kaXY+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHt7ZW5kfX0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGJvZHk+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90YWJsZT4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90Ym9keT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RhYmxlPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8IS0tW2lmIG1zbyB8IElFXT48L3RkPjwvdHI+PC90YWJsZT48IVtlbmRpZl0tLT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4KICAgICAgICAgICAgICAgICAgICAgICAgICA8L3Rib2R5PgogICAgICAgICAgICAgICAgICAgICAgICA8L3RhYmxlPgoKICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PgoKCiAgICAgICAgICAgICAgICAgICAgICA8IS0tW2lmIG1zbyB8IElFXT48L3RkPjwvdHI+PC90YWJsZT48IVtlbmRpZl0tLT4KCgogICAgICAgICAgICAgICAgICAgIDwvdGQ+CiAgICAgICAgICAgICAgICAgIDwvdHI+CiAgICAgICAgICAgICAgICAgIDwvdGJvZHk+CiAgICAgICAgICAgICAgICA8L3RhYmxlPgoKICAgICAgICAgICAgICAgIDwhLS1baWYgbXNvIHwgSUVdPjwvdGQ+PC90cj48L3RhYmxlPjwhW2VuZGlmXS0tPgogICAgICAgICAgICAgIDwvdGQ+CiAgICAgICAgICAgIDwvdHI+CiAgICAgICAgICAgIDwvdGJvZHk+CiAgICAgICAgICA8L3RhYmxlPgoKICAgICAgICA8L2Rpdj4KCgogICAgICAgIDwhLS1baWYgbXNvIHwgSUVdPjwvdGQ+PC90cj48L3RhYmxlPjwhW2VuZGlmXS0tPgoKCiAgICAgIDwvdGQ+CiAgICA8L3RyPgogICAgPC90Ym9keT4KICA8L3RhYmxlPgoKPC9kaXY+Cgo8L2JvZHk+CjwvaHRtbD4K # ZITADEL_DEFAULTINSTANCE_EMAILTEMPLATE # Sets the default values for lifetime and expiration for OIDC in each newly created instance # This default can be overwritten for each instance during runtime # Overwrites the system defaults # If defined but not all durations are set it will result in an error OIDCSettings: - AccessTokenLifetime: 12h - IdTokenLifetime: 12h - RefreshTokenIdleExpiration: 720h #30d - RefreshTokenExpiration: 2160h #90d + AccessTokenLifetime: 12h # ZITADEL_DEFAULTINSTANCE_OIDCSETTINGS_ACCESSTOKENLIFETIME + IdTokenLifetime: 12h # ZITADEL_DEFAULTINSTANCE_OIDCSETTINGS_IDTOKENLIFETIME + # 720h are 30 days + RefreshTokenIdleExpiration: 720h # ZITADEL_DEFAULTINSTANCE_OIDCSETTINGS_REFRESHTOKENIDLEEXPIRATION + # 2160h are 90 days + RefreshTokenExpiration: 2160h # ZITADEL_DEFAULTINSTANCE_OIDCSETTINGS_REFRESHTOKENEXPIRATION # this configuration sets the default email configuration SMTPConfiguration: - # configuration of the host + # Configuration of the host SMTP: # must include the port, like smtp.mailtrap.io:2525. IPv6 is also supported, like [2001:db8::1]:2525 - Host: - User: - Password: - TLS: - # if the host of the sender is different from ExternalDomain set DefaultInstance.DomainPolicy.SMTPSenderAddressMatchesInstanceDomain to false - From: - FromName: + Host: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_HOST + User: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_USER + Password: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_PASSWORD + TLS: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_SSL + # If the host of the sender is different from ExternalDomain set DefaultInstance.DomainPolicy.SMTPSenderAddressMatchesInstanceDomain to false + From: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_FROM + FromName: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_FROMNAME MessageTexts: - MessageTextType: InitCode Language: de @@ -735,15 +766,15 @@ DefaultInstance: PreHeader: Verify phone Subject: Verify phone Greeting: Hello {{.DisplayName}}, - Text: A new phonenumber has been added. Please use the following code to verify it {{.Code}}. + Text: A new phone number has been added. Please use the following code to verify it {{.Code}}. ButtonText: Verify phone - MessageTextType: DomainClaimed Language: en Title: Zitadel - Domain has been claimed - PreHeader: Change email / username + PreHeader: Change email/username Subject: Domain has been claimed Greeting: Hello {{.DisplayName}}, - Text: The domain {{.Domain}} has been claimed by an organisation. Your current user {{.UserName}} is not part of this organisation. Therefore you'll have to change your email when you login. We have created a temporary username ({{.TempUsername}}) for this login. + Text: The domain {{.Domain}} has been claimed by an organization. Your current user {{.UserName}} is not part of this organization. Therefore you'll have to change your email when you login. We have created a temporary username ({{.TempUsername}}) for this login. ButtonText: Login - MessageTextType: PasswordChange Language: en @@ -755,7 +786,7 @@ DefaultInstance: ButtonText: Login Quotas: - # Items takes a slice of quota configurations, whereas for each unit type and instance, one or zero quotas may exist. + # Items take a slice of quota configurations, whereas, for each unit type and instance, one or zero quotas may exist. # The following unit types are supported # "requests.all.authenticated" @@ -770,7 +801,7 @@ DefaultInstance: # The sum of all actions run durations in seconds Items: # - Unit: "requests.all.authenticated" -# # From defines the starting time from which the current quota period is calculated from. +# # From defines the starting time from which the current quota period is calculated. # # This is relevant for querying the current usage. # From: "2023-01-01T00:00:00Z" # # ResetInterval defines the quota periods duration diff --git a/cmd/setup/steps.yaml b/cmd/setup/steps.yaml index 3164ac2f4c..1497b7be4a 100644 --- a/cmd/setup/steps.yaml +++ b/cmd/setup/steps.yaml @@ -1,41 +1,53 @@ FirstInstance: - MachineKeyPath: - PatPath: - InstanceName: ZITADEL - DefaultLanguage: en + # The machine key from the section FirstInstance.Org.Machine.MachineKey is written to the MachineKeyPath. + MachineKeyPath: # ZITADEL_FIRSTINSTANCE_MACHINEKEYPATH + # The personal access token from the section FirstInstance.Org.Machine.Pat is written to the PatPath. + PatPath: # ZITADEL_FIRSTINSTANCE_PATPATH + InstanceName: ZITADEL # ZITADEL_FIRSTINSTANCE_INSTANCENAME + DefaultLanguage: en # ZITADEL_FIRSTINSTANCE_DEFAULTLANGUAGE Org: - Name: ZITADEL + Name: ZITADEL # ZITADEL_FIRSTINSTANCE_ORG_NAME + # In the FirstInstance.Org.Human section, the initial organization's admin user with the role IAM_OWNER is defined. + # ZITADEL either creates a human user or a machine user. + # If FirstInstance.Org.Machine.Machine is defined, a service user is created with the IAM_OWNER role, not a human user. Human: - # in case that UserLoginMustBeDomain is false (default) and you don't overwrite the username with an email, + # In case UserLoginMustBeDomain is false (default) and you don't overwrite the username with an email, # it will be suffixed by the org domain (org-name + domain from config). - # for example: zitadel-admin in org ZITADEL on domain.tld -> zitadel-admin@zitadel.domain.tld - UserName: zitadel-admin - FirstName: ZITADEL - LastName: Admin - NickName: - DisplayName: + # for example zitadel-admin in org ZITADEL on domain.tld -> zitadel-admin@zitadel.domain.tld + UserName: zitadel-admin # ZITADEL_FIRSTINSTANCE_ORG_HUMAN_USERNAME + FirstName: ZITADEL # ZITADEL_FIRSTINSTANCE_ORG_HUMAN_FIRSTNAME + LastName: Admin # ZITADEL_FIRSTINSTANCE_ORG_HUMAN_LASTNAME + NickName: # ZITADEL_FIRSTINSTANCE_ORG_HUMAN_NICKNAME + DisplayName: # ZITADEL_FIRSTINSTANCE_ORG_HUMAN_DISPLAYNAME Email: - Address: #uses the username if empty - Verified: true - PreferredLanguage: en - Gender: + # uses the username if empty + Address: # ZITADEL_FIRSTINSTANCE_ORG_HUMAN_EMAIL_ADDRESS + Verified: true # ZITADEL_FIRSTINSTANCE_ORG_HUMAN_EMAIL_VERIFIED + PreferredLanguage: en # ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PREFERREDLANGUAGE + Gender: # ZITADEL_FIRSTINSTANCE_ORG_HUMAN_GENDER Phone: - Number: - Verified: - Password: Password1! - PasswordChangeRequired: true + Number: # ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PHONE_NUMBER + Verified: # ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PHONE_VERIFIED + Password: Password1! # ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORD + PasswordChangeRequired: true # ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORDCHANGEREQUIRED + # In the FirstInstance.Org.Machine section, the initial organization's admin user with the role IAM_OWNER is defined. + # ZITADEL either creates a human user or a machine user. + # If FirstInstance.Org.Machine.Machine is defined, a service user is created with the IAM_OWNER role, not a human user. Machine: Machine: - Username: - Name: + Username: # ZITADEL_FIRSTINSTANCE_ORG_MACHINE_USERNAME + Name: # ZITADEL_FIRSTINSTANCE_ORG_MACHINE_NAME MachineKey: - ExpirationDate: - Type: + # date format: 2023-01-01T00:00:00Z + ExpirationDate: # ZITADEL_FIRSTINSTANCE_ORG_MACHINE_MACHINEKEY_EXPIRATIONDATE + # Currently, the only supported value is 1 for JSON + Type: # ZITADEL_FIRSTINSTANCE_ORG_MACHINE_MACHINEKEY_TYPE Pat: - ExpirationDate: + # date format: 2023-01-01T00:00:00Z + ExpirationDate: # ZITADEL_FIRSTINSTANCE_ORG_MACHINE_PAT_EXPIRATIONDATE CorrectCreationDate: - FailAfter: 5m + FailAfter: 5m # ZITADEL_CORRECTCREATIONDATE_FAILAFTER AddEventCreatedAt: - BulkAmount: 100 \ No newline at end of file + BulkAmount: 100 # ZITADEL_ADDEVENTCREATEDAT_BULKAMOUNT diff --git a/docs/.gitignore b/docs/.gitignore index 7e8329214f..dd1b12666a 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -12,6 +12,9 @@ # Generated by docusaurus-plugin-openapi-docs docs/apis/resources +# Generated markedown from config +/uitls/generate_config/node_modules + # Misc .DS_Store .env.local diff --git a/docs/docs/apis/proto/.gitignore b/docs/docs/apis/proto/.gitignore new file mode 100644 index 0000000000..d6b7ef32c8 --- /dev/null +++ b/docs/docs/apis/proto/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/docs/docs/self-hosting/manage/configure/.gitignore b/docs/docs/self-hosting/manage/configure/.gitignore new file mode 100644 index 0000000000..a0b4906fa2 --- /dev/null +++ b/docs/docs/self-hosting/manage/configure/.gitignore @@ -0,0 +1,2 @@ +defaults.yaml +steps.yaml diff --git a/docs/docs/self-hosting/manage/configure/configure.mdx b/docs/docs/self-hosting/manage/configure/configure.mdx index 6e897b6851..37e909ac10 100644 --- a/docs/docs/self-hosting/manage/configure/configure.mdx +++ b/docs/docs/self-hosting/manage/configure/configure.mdx @@ -4,44 +4,57 @@ title: Configuration Options import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; -import LinuxUnix from './_linuxunix.mdx' -import Compose from './_compose.mdx' -import Helm from './_helm.mdx' - -# Configure ZITADEL +import LinuxUnix from "./_linuxunix.mdx"; +import Compose from "./_compose.mdx"; +import Helm from "./_helm.mdx"; +import CodeBlock from "@theme/CodeBlock"; +import DefaultsYamlSource from "!!raw-loader!./defaults.yaml"; +import StepsYamlSource from "!!raw-loader!./steps.yaml"; This guide assumes you are familiar with [running ZITADEL using the least amount of configuration possible](/docs/self-hosting/deploy/overview). -## Configuration Files +## Configuration files -### Runtime Configuration File +### Runtime configuration file You can configure the runtime using the `--config` flag of the `zitadel` binary. -For a description of all _runtime configuration options_ and their defaults, read the [ZITADEL source code](https://github.com/zitadel/zitadel/blob/main/cmd/defaults.yaml). +Also, you can use the environment variables listed in the defaults.yaml. -### Database Initialization File +
+ defaults.yaml + {DefaultsYamlSource} +
+ +### Database initialization file ZITADEL uses a [different configuration file](https://github.com/zitadel/zitadel/blob/main/cmd/setup/steps.yaml) for _database initialization steps_. Use the `--steps` flag of the `zitadel` binary to provide this configuration file. +Also, you can use the environment variables listed in the steps.yaml. -### Multiple Configuration Files +
+ steps.yaml + {StepsYamlSource} +
+ +### Multiple configuration files ZITADEL merges configuration files when multiple `--config` and `--steps` flags are provided. You can use these flags to handle standard configuration files differently from secret configuration files. For example, standard configuration files stored in git may contain public information such as a database hostname. To use private information — such as a database admin credential — without storing it in git, use an extra `--config` or `--steps` flag that requests the private information from a secret manager. -## Environment Variables +## Environment variables All configuration properties are configurable using environment variables. ZITADEL environment variable keys are prefixed with `ZITADEL_`. -For example, to configure the default ZITADEL IAM admin username and password, set the `zitadel` binary runtime environment variables `ZITADEL_FIRSTINSTANCE_ORG_HUMAN_USERNAME` and `ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORD`. +For example, to configure the default ZITADEL IAM admin username and password set the `zitadel` binary runtime environment variables `ZITADEL_FIRSTINSTANCE_ORG_HUMAN_USERNAME` and `ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORD`. +All supported environment variables are listed in the [runtime configuration file](#runtime-configuration-file) and the [database initialization file](#database-initialization-file). -### Proxy Configuration +### Proxy configuration A proxy for outgoing connections can be configured using the environment variables: Use `HTTP_PROXY` for outgoing HTTP requests, and `HTTPS_PROXY` for outgoing HTTPS requests. These environment variables are used as a proxy URL. -To exclude specific hosts from proxying, set the `NO_PROXY` environment variable: The value is interpreted as a comma separated string. +To exclude specific hosts from proxying, set the `NO_PROXY` environment variable: The value is interpreted as a comma-separated string. For more information on the `NO_PROXY` environment variable, read the [`httpproxy` Go doc](https://pkg.go.dev/golang.org/x/net/http/httpproxy#Config). ## Masterkey @@ -49,6 +62,7 @@ For more information on the `NO_PROXY` environment variable, read the [`httpprox The masterkey is used to AES256-encrypt other generated encryption keys. It must be 32 bytes. There are three ways to pass the masterkey to the `zitadel` binary: + - By value: Use the flag `--masterkey My_Master_Key_Which_Has_32_Bytes` - By environment variable `ZITADEL_MASTERKEY`: Use the flag `--masterkeyFromEnv` - By file: Use the flag `--masterkeyFile /path/to/file` @@ -56,29 +70,30 @@ There are three ways to pass the masterkey to the `zitadel` binary: ## Passing the configuration - - - - - - - - - + + + + + + + + + Open your favorite internet browser at [http://localhost:8080/ui/console](http://localhost:8080/ui/console). This is the IAM admin users login according to your configuration in the [example-zitadel-init-steps.yaml](./example-zitadel-init-steps.yaml): -- **username**: *root@zitadel.localhost* -- **password**: *RootPassword1!* + +- **username**: _root@zitadel.localhost_ +- **password**: _RootPassword1!_ ## What's next @@ -90,4 +105,5 @@ This is the IAM admin users login according to your configuration in the [exampl :::caution + The ZITADEL management console [requires end-to-end HTTP/2 support](/docs/self-hosting/manage/http2) diff --git a/docs/docs/self-hosting/manage/production.md b/docs/docs/self-hosting/manage/production.md index f00e7fe0ef..55e94f4d62 100644 --- a/docs/docs/self-hosting/manage/production.md +++ b/docs/docs/self-hosting/manage/production.md @@ -21,6 +21,9 @@ Read more about separating the init and setup phases on the [Updating and Scalin ## Configuration Read [on the configure page](/docs/self-hosting/manage/configure) about the available options you have to configure ZITADEL. +Prefer passing .yaml files to the ZITADEL binary instead of environment variables. +Restricting access to these files to avoid leaking sensitive information is easier than restricting access to environment variables. +Also, not all configuration options are available as environment variables. ## Networking diff --git a/docs/package.json b/docs/package.json index 02263269fe..99e5a44ce4 100644 --- a/docs/package.json +++ b/docs/package.json @@ -13,9 +13,10 @@ "serve": "docusaurus serve", "write-translations": "docusaurus write-translations", "write-heading-ids": "docusaurus write-heading-ids", - "generate": "yarn generate:grpc && yarn generate:apidocs", + "generate": "yarn generate:grpc && yarn generate:apidocs && yarn generate:configdocs", "generate:grpc": "buf generate ../proto", - "generate:apidocs": "docusaurus clean-api-docs all && docusaurus gen-api-docs all" + "generate:apidocs": "docusaurus clean-api-docs all && docusaurus gen-api-docs all", + "generate:configdocs": "cp -r ../cmd/defaults.yaml ./docs/self-hosting/manage/configure/ && cp -r ../cmd/setup/steps.yaml ./docs/self-hosting/manage/configure/" }, "dependencies": { "@algolia/autocomplete-core": "1.5.2", diff --git a/docs/yarn.lock b/docs/yarn.lock index b15d232580..4aa155755f 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -11090,6 +11090,11 @@ yaml@1.10.2, yaml@^1.10.0, yaml@^1.10.2, yaml@^1.7.2: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== +yaml@2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.1.tgz#02fe0975d23cd441242aa7204e09fc28ac2ac33b" + integrity sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ== + yargs-parser@^18.1.2: version "18.1.3" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" From fb92128b85434a5805affa9f80e0e868aa25d3f8 Mon Sep 17 00:00:00 2001 From: Fabi Date: Tue, 8 Aug 2023 09:00:28 +0200 Subject: [PATCH 06/38] docs: add saml application to console guide (#6195) --- docs/docs/guides/manage/console/applications.mdx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/docs/guides/manage/console/applications.mdx b/docs/docs/guides/manage/console/applications.mdx index 8cad1c9eb7..1939644134 100644 --- a/docs/docs/guides/manage/console/applications.mdx +++ b/docs/docs/guides/manage/console/applications.mdx @@ -41,6 +41,7 @@ At the moment ZITADEL offers four client types: - [**Native**](#native) (native, mobile or desktop applications) - [**User Agent**](#user-agent) (single page applications / SPA, generally JavaScript executed in the browser) - [**API**](#api) (OAuth Resource Server) +- [**SAML**](#saml) The first three options (Web, Native and User Agent) require user interaction, the fourth option (API) has no direct user-interaction. Depending on the app type, there are small differences in the possible settings. @@ -84,6 +85,17 @@ Following authentication types can be used: After selecting your Apps Type and Authentication Method, you may need to specify redirect URIs. +### SAML + +If your application doesn't support the OIDC standard, but SAML this is the right application type to choose. SAML is an open standard used for authentication based on XML. + +After entering a name and choosing the application type "SAML", you will get to the SAML configuration screen. + +You can either add a link to a SAML metadata file or upload it directly. +SAML metadata is an XML document which contains information necessary for interaction with SAML-enabled identity or service providers. + +You can find some example configurations for SAML 2.0 in our [integrate services](/docs/guides/integrate/services) guides + ## Redirect URIs App Types with User interaction (Web, Native and User Agent) require redirect URIs. From 605e683e290688d58e9aec47a243a827bd36837a Mon Sep 17 00:00:00 2001 From: mffap Date: Tue, 8 Aug 2023 09:25:35 +0200 Subject: [PATCH 07/38] docs: update domicile address (#6331) update domicile address Co-authored-by: Livio Spring --- docs/docs/apis/openidoauth/claims.md | 2 +- docs/docs/legal/privacy-policy.mdx | 4 ++-- docs/docs/legal/terms-of-service.md | 2 +- docs/docs/legal/terms-support-service.md | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/docs/apis/openidoauth/claims.md b/docs/docs/apis/openidoauth/claims.md index 74c079c9c1..020a108f63 100644 --- a/docs/docs/apis/openidoauth/claims.md +++ b/docs/docs/apis/openidoauth/claims.md @@ -42,7 +42,7 @@ Please check below the matrix for an overview where which scope is asserted. | Claims | Example | Description | |:-------------------|:-----------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------| | acr | TBA | TBA | -| address | `Teufener Strasse 19, 9000 St. Gallen` | TBA | +| address | `Lerchenfeldstrasse 3, 9014 St. Gallen` | TBA | | amr | `pwd mfa` | Authentication Method References as defined in [RFC8176](https://tools.ietf.org/html/rfc8176)
`password` value is deprecated, please check `pwd` | | aud | `69234237810729019` | The audience of the token, by default all client id's and the project id are included | | auth_time | `1311280969` | Unix time of the authentication | diff --git a/docs/docs/legal/privacy-policy.mdx b/docs/docs/legal/privacy-policy.mdx index e922117e9d..fda2b1d610 100644 --- a/docs/docs/legal/privacy-policy.mdx +++ b/docs/docs/legal/privacy-policy.mdx @@ -14,8 +14,8 @@ The responsible party for the data processing described in this privacy policy **CAOS AG** Data Protection Officer -Teufener Strasse 19 -9000 St. Gallen +Lerchenfeldstrasse 3 +9014 St. Gallen Switzerland [legal@zitadel.com](mailto:legal@zitadel.com) diff --git a/docs/docs/legal/terms-of-service.md b/docs/docs/legal/terms-of-service.md index e963ae58d2..4dfca36d0e 100644 --- a/docs/docs/legal/terms-of-service.md +++ b/docs/docs/legal/terms-of-service.md @@ -6,7 +6,7 @@ custom_edit_url: null ### Introduction -CAOS Ltd. (**"We"**, **CAOS AG**, or simply **CAOS**), with head office in Teufener Strasse 19, 9000 St. Gallen, Switzerland, offers "Identity and Access Management as service" with the brand name "ZITADEL Cloud Services" and all of our Websites (**Services** or **ZITADEL Cloud**). +CAOS Ltd. (**"We"**, **CAOS AG**, or simply **CAOS**), with head office in Lerchenfeldstrasse 3, 9014 St. Gallen, Switzerland, offers "Identity and Access Management as service" with the brand name "ZITADEL Cloud Services" and all of our Websites (**Services** or **ZITADEL Cloud**). The customer relationship (**Framework Agreement** or **The Agreement**) is created by the **Customer** (**"you"**) by creating a user or organization within the ZITADEL Cloud Service. On the basis of this Framework Agreement you may then choose to make use of payable services (**Subscription**) as you wish, i.e. you may book services, options and packages yourself at any time (**Booking**, **Purchase Order**) and subsequently terminate them. diff --git a/docs/docs/legal/terms-support-service.md b/docs/docs/legal/terms-support-service.md index bb8a2fc333..2b1898f93a 100644 --- a/docs/docs/legal/terms-support-service.md +++ b/docs/docs/legal/terms-support-service.md @@ -6,7 +6,7 @@ custom_edit_url: null ### Introduction -CAOS Ltd. (**"We"**, **CAOS AG**, or simply **CAOS**), with head office located at Teufener Strasse 19, 9000 St. Gallen, Switzerland, offers amongst other services and websites (**Services**) as well commercial support services (**Support Services**) for units of CAOS software products (**Unit**), if not otherwise defined a Unit refers to a is a single, dedicated setup of an application or service. +CAOS Ltd. (**"We"**, **CAOS AG**, or simply **CAOS**), with head office located at Lerchenfeldstrasse 3, 9014 St. Gallen, Switzerland, offers amongst other services and websites (**Services**) as well commercial support services (**Support Services**) for units of CAOS software products (**Unit**), if not otherwise defined a Unit refers to a is a single, dedicated setup of an application or service. The customer relationship (**Framework Agreement** or **The Agreement**) is created by the **Customer** (**"you"**) by accepting a **Purchase Order** (**"PO"**) for the specified Support Services (**Booking**). Jointly you and CAOS will be referred to as **the Parties**. The terms of service (**"TOS"**) outlined in this document establish the most important points of this Framework Agreement – independently of the use of any other services. From 8dc1fd06a1068e162db6c2986e402ff349a3964c Mon Sep 17 00:00:00 2001 From: Livio Spring Date: Tue, 8 Aug 2023 11:28:47 +0200 Subject: [PATCH 08/38] fix: provide tokens in azuread idp session (#6334) --- .../api/ui/login/external_provider_handler.go | 2 ++ internal/command/idp_intent.go | 3 +++ internal/command/idp_intent_test.go | 26 +++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/internal/api/ui/login/external_provider_handler.go b/internal/api/ui/login/external_provider_handler.go index ceb2653a33..7f32726d0f 100644 --- a/internal/api/ui/login/external_provider_handler.go +++ b/internal/api/ui/login/external_provider_handler.go @@ -967,6 +967,8 @@ func tokens(session idp.Session) *oidc.Tokens[*oidc.IDTokenClaims] { return s.Tokens case *oauth.Session: return s.Tokens + case *azuread.Session: + return s.Tokens } return nil } diff --git a/internal/command/idp_intent.go b/internal/command/idp_intent.go index 99db0323b6..05f68c2754 100644 --- a/internal/command/idp_intent.go +++ b/internal/command/idp_intent.go @@ -14,6 +14,7 @@ import ( "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/idp" + "github.com/zitadel/zitadel/internal/idp/providers/azuread" "github.com/zitadel/zitadel/internal/idp/providers/jwt" "github.com/zitadel/zitadel/internal/idp/providers/oauth" openid "github.com/zitadel/zitadel/internal/idp/providers/oidc" @@ -165,6 +166,8 @@ func tokensForSucceededIDPIntent(session idp.Session, encryptionAlg crypto.Encry tokens = s.Tokens case *jwt.Session: tokens = s.Tokens + case *azuread.Session: + tokens = s.Tokens default: return nil, "", nil } diff --git a/internal/command/idp_intent_test.go b/internal/command/idp_intent_test.go index acbb1eebf3..0d95bd287a 100644 --- a/internal/command/idp_intent_test.go +++ b/internal/command/idp_intent_test.go @@ -19,6 +19,7 @@ import ( "github.com/zitadel/zitadel/internal/id" "github.com/zitadel/zitadel/internal/id/mock" "github.com/zitadel/zitadel/internal/idp" + "github.com/zitadel/zitadel/internal/idp/providers/azuread" "github.com/zitadel/zitadel/internal/idp/providers/jwt" "github.com/zitadel/zitadel/internal/idp/providers/ldap" "github.com/zitadel/zitadel/internal/idp/providers/oauth" @@ -745,6 +746,31 @@ func Test_tokensForSucceededIDPIntent(t *testing.T) { err: nil, }, }, + { + "azure tokens", + args{ + &azuread.Session{ + Session: &oauth.Session{ + Tokens: &oidc.Tokens[*oidc.IDTokenClaims]{ + Token: &oauth2.Token{ + AccessToken: "accessToken", + }, + }, + }, + }, + crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + res{ + accessToken: &crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("accessToken"), + }, + idToken: "", + err: nil, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From 9aed9f91866b331ca449d3880e07f7c2df0bfe4b Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Wed, 9 Aug 2023 07:14:17 +0200 Subject: [PATCH 09/38] test(e2e): skip quota notifications for now (#6337) --- e2e/cypress/e2e/quotas/quotas.cy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/cypress/e2e/quotas/quotas.cy.ts b/e2e/cypress/e2e/quotas/quotas.cy.ts index 3c8fa6c583..d7a04b1961 100644 --- a/e2e/cypress/e2e/quotas/quotas.cy.ts +++ b/e2e/cypress/e2e/quotas/quotas.cy.ts @@ -149,7 +149,7 @@ describe('quotas', () => { }); }); - describe('notifications', () => { + describe.skip('notifications', () => { const callURL = `http://${Cypress.env('WEBHOOK_HANDLER_HOST')}:${Cypress.env('WEBHOOK_HANDLER_PORT')}/do_something`; beforeEach(() => cy.task('resetWebhookEvents')); From 343a9428b3d1a7cfec685e81bfc2fb7ff8be3606 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Wed, 9 Aug 2023 07:49:12 +0200 Subject: [PATCH 10/38] feat: SMS and email OTP texts (#6281) * manage 2 custom texts proto * implement methods * default texts * console * improve translations * lint * test: fix e2e timeout * fix translations * add missing console translations * remove unused text parts --------- Co-authored-by: Livio Spring --- .../message-texts.component.html | 6 +- .../message-texts/message-texts.component.ts | 285 +++++++++++----- console/src/app/services/admin.service.ts | 140 ++++++++ console/src/app/services/mgmt.service.ts | 116 +++++-- console/src/assets/i18n/bg.json | 6 +- console/src/assets/i18n/de.json | 6 +- console/src/assets/i18n/en.json | 6 +- console/src/assets/i18n/es.json | 6 +- console/src/assets/i18n/fr.json | 6 +- console/src/assets/i18n/it.json | 6 +- console/src/assets/i18n/ja.json | 6 +- console/src/assets/i18n/mk.json | 6 +- console/src/assets/i18n/pl.json | 6 +- console/src/assets/i18n/pt.json | 6 +- console/src/assets/i18n/zh.json | 6 +- e2e/cypress/e2e/quotas/quotas.cy.ts | 76 +++-- internal/api/grpc/admin/custom_text.go | 96 ++++++ .../api/grpc/admin/custom_text_converter.go | 24 ++ internal/api/grpc/admin/export.go | 54 +++ internal/api/grpc/management/custom_text.go | 96 ++++++ .../grpc/management/custom_text_converter.go | 24 ++ internal/domain/custom_message_text.go | 24 +- internal/notification/static/i18n/bg.yaml | 9 + internal/notification/static/i18n/de.yaml | 9 + internal/notification/static/i18n/en.yaml | 9 + internal/notification/static/i18n/es.yaml | 9 + internal/notification/static/i18n/fr.yaml | 9 + internal/notification/static/i18n/it.yaml | 9 + internal/notification/static/i18n/ja.yaml | 9 + internal/notification/static/i18n/mk.yaml | 9 + internal/notification/static/i18n/pl.yaml | 9 + internal/notification/static/i18n/pt.yaml | 9 + internal/notification/static/i18n/zh.yaml | 9 + internal/query/message_text.go | 6 + internal/query/projection/custom_text_test.go | 1 - internal/query/projection/message_texts.go | 2 + internal/static/i18n/de.yaml | 2 +- proto/zitadel/admin.proto | 261 ++++++++++++++ proto/zitadel/management.proto | 318 ++++++++++++++++++ 39 files changed, 1508 insertions(+), 188 deletions(-) diff --git a/console/src/app/modules/policies/message-texts/message-texts.component.html b/console/src/app/modules/policies/message-texts/message-texts.component.html index 105371fcf3..d5b71f2884 100644 --- a/console/src/app/modules/policies/message-texts/message-texts.component.html +++ b/console/src/app/modules/policies/message-texts/message-texts.component.html @@ -37,8 +37,8 @@ [chips]="chips[currentType]" [disabled]="(canWrite$ | async) === false" label="one" - [default$]="getDefaultInitMessageTextMap$" - [current$]="getCustomInitMessageTextMap$" + [default$]="getDefaultMessageTextMap$" + [current$]="getCustomMessageTextMap$" (changedValues)="updateCurrentValues($event)" > @@ -46,7 +46,7 @@
{{if hasRegistration}} @@ -59,5 +62,6 @@ + {{template "main-bottom" .}} From b383892d3603c3c50852146751e5e0c7f4f5bb36 Mon Sep 17 00:00:00 2001 From: Miguel Cabrerizo <30386061+doncicuto@users.noreply.github.com> Date: Fri, 11 Aug 2023 09:21:35 +0200 Subject: [PATCH 16/38] fix(console): filter already selected user in authorization (#6168) * fix: filter already selected user in authorization * fix: change const name --------- Co-authored-by: Max Peintner --- .../search-user-autocomplete.component.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/console/src/app/modules/search-user-autocomplete/search-user-autocomplete.component.ts b/console/src/app/modules/search-user-autocomplete/search-user-autocomplete.component.ts index 97bd6053de..4703a8f06d 100644 --- a/console/src/app/modules/search-user-autocomplete/search-user-autocomplete.component.ts +++ b/console/src/app/modules/search-user-autocomplete/search-user-autocomplete.component.ts @@ -106,7 +106,10 @@ export class SearchUserAutocompleteComponent implements OnInit, AfterContentChec .subscribe((userresp: ListUsersResponse.AsObject | unknown) => { this.isLoading = false; if (this.target === UserTarget.SELF && userresp) { - this.filteredUsers = (userresp as ListUsersResponse.AsObject).resultList; + const results = (userresp as ListUsersResponse.AsObject).resultList; + this.filteredUsers = results.filter((filteredUser) => { + return !this.users.map((u) => u.id).includes(filteredUser.id); + }); } }); } From 6ca789ad44078340ad290a4c619f2cf9c6693d8d Mon Sep 17 00:00:00 2001 From: Miguel Cabrerizo <30386061+doncicuto@users.noreply.github.com> Date: Fri, 11 Aug 2023 10:16:30 +0200 Subject: [PATCH 17/38] fix: footerText has no effect (#6297) --- internal/notification/templates/templateData.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/internal/notification/templates/templateData.go b/internal/notification/templates/templateData.go index 29a74f3328..f9572a4c5d 100644 --- a/internal/notification/templates/templateData.go +++ b/internal/notification/templates/templateData.go @@ -42,5 +42,11 @@ func (data *TemplateData) Translate(translator *i18n.Translator, msgType string, data.Greeting = translator.Localize(fmt.Sprintf("%s.%s", msgType, domain.MessageGreeting), args, langs...) data.Text = html.UnescapeString(translator.Localize(fmt.Sprintf("%s.%s", msgType, domain.MessageText), args, langs...)) data.ButtonText = translator.Localize(fmt.Sprintf("%s.%s", msgType, domain.MessageButtonText), args, langs...) - data.FooterText = translator.Localize(fmt.Sprintf("%s.%s", msgType, domain.MessageFooterText), args, langs...) + // Footer text is neither included in i18n files nor defaults.yaml + footerText := fmt.Sprintf("%s.%s", msgType, domain.MessageFooterText) + data.FooterText = translator.Localize(footerText, args, langs...) + // translator returns the id of the string to be translated if no translation is found for that id + // we'll include the footer if we have a custom non-empty string and if the string doesn't include the + // id of the string that could not be translated example InitCode.Footer + data.IncludeFooter = len(data.FooterText) > 0 && data.FooterText != footerText } From 4123ab7ba7e2c9b7e1ebdd1111fdee2a63434367 Mon Sep 17 00:00:00 2001 From: Miguel Cabrerizo <30386061+doncicuto@users.noreply.github.com> Date: Fri, 11 Aug 2023 11:17:24 +0200 Subject: [PATCH 18/38] fix: add Date header to email headers RFC822 (#6302) --- internal/notification/messages/email.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/notification/messages/email.go b/internal/notification/messages/email.go index f19196a297..ca3e4c96ca 100644 --- a/internal/notification/messages/email.go +++ b/internal/notification/messages/email.go @@ -4,6 +4,7 @@ import ( "fmt" "regexp" "strings" + "time" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/notification/channels" @@ -37,6 +38,7 @@ func (msg *Email) GetContent() (string, error) { headers["Return-Path"] = msg.SenderEmail headers["To"] = strings.Join(msg.Recipients, ", ") headers["Cc"] = strings.Join(msg.CC, ", ") + headers["Date"] = time.Now().Format(time.RFC1123Z) message := "" for k, v := range headers { From 77e561af72bd7e148603f1832a2b4da4fd70cf36 Mon Sep 17 00:00:00 2001 From: Stefan Benz <46600784+stebenz@users.noreply.github.com> Date: Fri, 11 Aug 2023 14:49:28 +0200 Subject: [PATCH 19/38] chore: add assets to releases (#6346) * chore: change pipeline to add assets to the release --- .github/workflows/compile.yml | 6 ++--- .github/workflows/container.yml | 2 +- .github/workflows/e2e.yml | 2 +- .github/workflows/version.yml | 5 +++++ .releaserc.js | 40 ++++++++++++++++++++++++++++++--- 5 files changed, 47 insertions(+), 8 deletions(-) diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml index 10baaae966..47b85f9d87 100644 --- a/.github/workflows/compile.yml +++ b/.github/workflows/compile.yml @@ -70,12 +70,12 @@ jobs: mv zitadel zitadel-${{ matrix.goos }}-${{ matrix.goarch }}/ cp LICENSE zitadel-${{ matrix.goos }}-${{ matrix.goarch }}/ cp README.md zitadel-${{ matrix.goos }}-${{ matrix.goarch }}/ - tar -cvf zitadel-${{ matrix.goos }}-${{ matrix.goarch }}.tar zitadel-${{ matrix.goos }}-${{ matrix.goarch }} + tar -czvf zitadel-${{ matrix.goos }}-${{ matrix.goarch }}.tar.gz zitadel-${{ matrix.goos }}-${{ matrix.goarch }} - uses: actions/upload-artifact@v3 with: name: zitadel-${{ matrix.goos }}-${{ matrix.goarch }} - path: zitadel-${{ matrix.goos }}-${{ matrix.goarch }}.tar + path: zitadel-${{ matrix.goos }}-${{ matrix.goarch }}.tar.gz checksums: runs-on: ubuntu-latest @@ -87,7 +87,7 @@ jobs: path: executables - name: move files one folder up - run: mv */*.tar . && find . -type d -empty -delete + run: mv */*.tar.gz . && find . -type d -empty -delete working-directory: executables - run: sha256sum * > checksums.txt diff --git a/.github/workflows/container.yml b/.github/workflows/container.yml index 015831f5c3..cf13890d56 100644 --- a/.github/workflows/container.yml +++ b/.github/workflows/container.yml @@ -70,7 +70,7 @@ jobs: - name: Unpack executable run: | - tar -xvf .artifacts/zitadel-linux-${{ matrix.arch }}.tar + tar -xvf .artifacts/zitadel-linux-${{ matrix.arch }}.tar.gz mv zitadel-linux-${{ matrix.arch }}/zitadel ./zitadel - name: Debug diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index ea92872ddb..5310d743db 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -22,7 +22,7 @@ jobs: - name: Unpack executable run: | - tar -xvf .artifacts/zitadel-linux-amd64.tar + tar -xvf .artifacts/zitadel-linux-amd64.tar.gz mv zitadel-linux-amd64/zitadel ./zitadel - name: Set up QEMU diff --git a/.github/workflows/version.yml b/.github/workflows/version.yml index a5c8635488..abf5f44807 100644 --- a/.github/workflows/version.yml +++ b/.github/workflows/version.yml @@ -27,6 +27,11 @@ jobs: - name: Source checkout uses: actions/checkout@v3 + - + uses: actions/download-artifact@v3 + if: ${{ !inputs.dry_run }} + with: + path: .artifacts - name: Semantic Release uses: cycjimmy/semantic-release-action@v3 diff --git a/.releaserc.js b/.releaserc.js index 0cafc991a6..6716a53f73 100644 --- a/.releaserc.js +++ b/.releaserc.js @@ -1,11 +1,45 @@ module.exports = { branches: [ { name: "next" }, - { name: "next-rc", prerelease: "rc" } + { name: "next-rc", prerelease: "rc" }, ], plugins: [ "@semantic-release/commit-analyzer", "@semantic-release/release-notes-generator", - "@semantic-release/github" - ] + [ + "@semantic-release/github", + { + assets: [ + { + path: ".artifacts/zitadel-linux-amd64/zitadel-linux-amd64.tar.gz", + label: "zitadel-linux-amd64.tar.gz", + }, + { + path: ".artifacts/zitadel-linux-arm64/zitadel-linux-arm64.tar.gz", + label: "zitadel-linux-arm64.tar.gz", + }, + { + path: ".artifacts/zitadel-windows-amd64/zitadel-windows-amd64.tar.gz", + label: "zitadel-windows-amd64.tar.gz", + }, + { + path: ".artifacts/zitadel-windows-arm64/zitadel-windows-arm64.tar.gz", + label: "zitadel-windows-arm64.tar.gz", + }, + { + path: ".artifacts/zitadel-darwin-amd64/zitadel-darwin-amd64.tar.gz", + label: "zitadel-darwin-amd64.tar.gz", + }, + { + path: ".artifacts/zitadel-darwin-arm64/zitadel-darwin-arm64.tar.gz", + label: "zitadel-darwin-arm64.tar.gz", + }, + { + path: ".artifacts/checksums.txt", + label: "checksums.txt", + } + ], + }, + ], + ], }; From 372755bddda18b20c4f4e8ffd17a15f85f3c8fc5 Mon Sep 17 00:00:00 2001 From: Livio Spring Date: Fri, 11 Aug 2023 16:19:14 +0200 Subject: [PATCH 20/38] feat(api): add organisation service (#6340) * setup org with multiple admins * tests * add missing proto * remove machine users (for now) * update tests with idp case * fix package * organisation -> organization * fix test --- cmd/setup/03.go | 2 +- cmd/start/start.go | 4 + internal/api/grpc/admin/org.go | 20 +- internal/api/grpc/org/v2/org.go | 83 ++++ .../api/grpc/org/v2/org_integration_test.go | 206 ++++++++ internal/api/grpc/org/v2/org_test.go | 172 +++++++ internal/api/grpc/org/v2/server.go | 55 +++ internal/api/grpc/user/v2/user.go | 4 +- internal/api/ui/login/register_org_handler.go | 22 +- internal/command/instance.go | 2 +- internal/command/org.go | 236 +++++++-- internal/command/org_test.go | 451 ++++++++++++++++++ internal/integration/client.go | 5 +- internal/integration/integration.go | 98 ++-- internal/integration/usertype_string.go | 7 +- proto/zitadel/org/v2beta/org_service.proto | 145 ++++++ 16 files changed, 1382 insertions(+), 130 deletions(-) create mode 100644 internal/api/grpc/org/v2/org.go create mode 100644 internal/api/grpc/org/v2/org_integration_test.go create mode 100644 internal/api/grpc/org/v2/org_test.go create mode 100644 internal/api/grpc/org/v2/server.go create mode 100644 proto/zitadel/org/v2beta/org_service.proto diff --git a/cmd/setup/03.go b/cmd/setup/03.go index 867e9d4981..24b0942260 100644 --- a/cmd/setup/03.go +++ b/cmd/setup/03.go @@ -21,7 +21,7 @@ import ( type FirstInstance struct { InstanceName string DefaultLanguage language.Tag - Org command.OrgSetup + Org command.InstanceOrgSetup MachineKeyPath string PatPath string diff --git a/cmd/start/start.go b/cmd/start/start.go index 49cd981e5f..d0df178c94 100644 --- a/cmd/start/start.go +++ b/cmd/start/start.go @@ -36,6 +36,7 @@ import ( "github.com/zitadel/zitadel/internal/api/grpc/auth" "github.com/zitadel/zitadel/internal/api/grpc/management" oidc_v2 "github.com/zitadel/zitadel/internal/api/grpc/oidc/v2" + "github.com/zitadel/zitadel/internal/api/grpc/org/v2" "github.com/zitadel/zitadel/internal/api/grpc/session/v2" "github.com/zitadel/zitadel/internal/api/grpc/settings/v2" "github.com/zitadel/zitadel/internal/api/grpc/system" @@ -351,6 +352,9 @@ func startAPIs( if err := apis.RegisterService(ctx, settings.CreateServer(commands, queries, config.ExternalSecure)); err != nil { return err } + if err := apis.RegisterService(ctx, org.CreateServer(commands, queries, permissionCheck)); err != nil { + return err + } instanceInterceptor := middleware.InstanceInterceptor(queries, config.HTTP1HostHeader, login.IgnoreInstanceEndpoints...) assetsCache := middleware.AssetsCacheInterceptor(config.AssetStorage.Cache.MaxAge, config.AssetStorage.Cache.SharedMaxAge) apis.RegisterHandlerOnPrefix(assets.HandlerPrefix, assets.NewHandler(commands, verifier, config.InternalAuthZ, id.SonyFlakeGenerator(), store, queries, middleware.CallDurationHandler, instanceInterceptor.Handler, assetsCache.Handler, limitingAccessInterceptor.Handle)) diff --git a/internal/api/grpc/admin/org.go b/internal/api/grpc/admin/org.go index 4874b01711..9edd6f123c 100644 --- a/internal/api/grpc/admin/org.go +++ b/internal/api/grpc/admin/org.go @@ -72,18 +72,26 @@ func (s *Server) SetUpOrg(ctx context.Context, req *admin_pb.SetUpOrgRequest) (* } human := setUpOrgHumanToCommand(req.User.(*admin_pb.SetUpOrgRequest_Human_).Human) //TODO: handle machine - userID, objectDetails, err := s.command.SetUpOrg(ctx, &command.OrgSetup{ + createdOrg, err := s.command.SetUpOrg(ctx, &command.OrgSetup{ Name: req.Org.Name, CustomDomain: req.Org.Domain, - Human: human, - Roles: req.Roles, - }, userIDs...) + Admins: []*command.OrgSetupAdmin{ + { + Human: human, + Roles: req.Roles, + }, + }, + }, true, userIDs...) if err != nil { return nil, err } + var userID string + if len(createdOrg.CreatedAdmins) == 1 { + userID = createdOrg.CreatedAdmins[0].ID + } return &admin_pb.SetUpOrgResponse{ - Details: object.DomainToAddDetailsPb(objectDetails), - OrgId: objectDetails.ResourceOwner, + Details: object.DomainToAddDetailsPb(createdOrg.ObjectDetails), + OrgId: createdOrg.ObjectDetails.ResourceOwner, UserId: userID, }, nil } diff --git a/internal/api/grpc/org/v2/org.go b/internal/api/grpc/org/v2/org.go new file mode 100644 index 0000000000..cc8f78cdd6 --- /dev/null +++ b/internal/api/grpc/org/v2/org.go @@ -0,0 +1,83 @@ +package org + +import ( + "context" + + "github.com/zitadel/zitadel/internal/api/grpc/object/v2" + "github.com/zitadel/zitadel/internal/api/grpc/user/v2" + "github.com/zitadel/zitadel/internal/command" + caos_errs "github.com/zitadel/zitadel/internal/errors" + org "github.com/zitadel/zitadel/pkg/grpc/org/v2beta" +) + +func (s *Server) AddOrganization(ctx context.Context, request *org.AddOrganizationRequest) (*org.AddOrganizationResponse, error) { + orgSetup, err := addOrganizationRequestToCommand(request) + if err != nil { + return nil, err + } + createdOrg, err := s.command.SetUpOrg(ctx, orgSetup, false) + if err != nil { + return nil, err + } + return createdOrganizationToPb(createdOrg) +} + +func addOrganizationRequestToCommand(request *org.AddOrganizationRequest) (*command.OrgSetup, error) { + admins, err := addOrganizationRequestAdminsToCommand(request.GetAdmins()) + if err != nil { + return nil, err + } + return &command.OrgSetup{ + Name: request.GetName(), + CustomDomain: "", + Admins: admins, + }, nil +} + +func addOrganizationRequestAdminsToCommand(requestAdmins []*org.AddOrganizationRequest_Admin) (admins []*command.OrgSetupAdmin, err error) { + admins = make([]*command.OrgSetupAdmin, len(requestAdmins)) + for i, admin := range requestAdmins { + admins[i], err = addOrganizationRequestAdminToCommand(admin) + if err != nil { + return nil, err + } + } + return admins, nil +} + +func addOrganizationRequestAdminToCommand(admin *org.AddOrganizationRequest_Admin) (*command.OrgSetupAdmin, error) { + switch a := admin.GetUserType().(type) { + case *org.AddOrganizationRequest_Admin_UserId: + return &command.OrgSetupAdmin{ + ID: a.UserId, + Roles: admin.GetRoles(), + }, nil + case *org.AddOrganizationRequest_Admin_Human: + human, err := user.AddUserRequestToAddHuman(a.Human) + if err != nil { + return nil, err + } + return &command.OrgSetupAdmin{ + Human: human, + Roles: admin.GetRoles(), + }, nil + default: + return nil, caos_errs.ThrowUnimplementedf(nil, "ORGv2-SD2r1", "userType oneOf %T in method AddOrganization not implemented", a) + } +} + +func createdOrganizationToPb(createdOrg *command.CreatedOrg) (_ *org.AddOrganizationResponse, err error) { + admins := make([]*org.AddOrganizationResponse_CreatedAdmin, len(createdOrg.CreatedAdmins)) + for i, admin := range createdOrg.CreatedAdmins { + admins[i] = &org.AddOrganizationResponse_CreatedAdmin{ + UserId: admin.ID, + EmailCode: admin.EmailCode, + PhoneCode: admin.PhoneCode, + } + } + return &org.AddOrganizationResponse{ + Details: object.DomainToDetailsPb(createdOrg.ObjectDetails), + OrganizationId: createdOrg.ObjectDetails.ResourceOwner, + CreatedAdmins: admins, + }, nil +} diff --git a/internal/api/grpc/org/v2/org_integration_test.go b/internal/api/grpc/org/v2/org_integration_test.go new file mode 100644 index 0000000000..570b0afa13 --- /dev/null +++ b/internal/api/grpc/org/v2/org_integration_test.go @@ -0,0 +1,206 @@ +//go:build integration + +package org_test + +import ( + "context" + "fmt" + "os" + "testing" + "time" + + "github.com/muhlemmer/gu" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/zitadel/zitadel/internal/integration" + org "github.com/zitadel/zitadel/pkg/grpc/org/v2beta" + user "github.com/zitadel/zitadel/pkg/grpc/user/v2alpha" +) + +var ( + CTX context.Context + Tester *integration.Tester + Client org.OrganizationServiceClient + User *user.AddHumanUserResponse +) + +func TestMain(m *testing.M) { + os.Exit(func() int { + ctx, errCtx, cancel := integration.Contexts(5 * time.Minute) + defer cancel() + + Tester = integration.NewTester(ctx) + defer Tester.Done() + Client = Tester.Client.OrgV2 + + CTX, _ = Tester.WithAuthorization(ctx, integration.IAMOwner), errCtx + User = Tester.CreateHumanUser(CTX) + return m.Run() + }()) +} + +func TestServer_AddOrganization(t *testing.T) { + idpID := Tester.AddGenericOAuthProvider(t) + + tests := []struct { + name string + ctx context.Context + req *org.AddOrganizationRequest + want *org.AddOrganizationResponse + wantErr bool + }{ + { + name: "missing permission", + ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner), + req: &org.AddOrganizationRequest{ + Name: "name", + Admins: nil, + }, + wantErr: true, + }, + { + name: "empty name", + ctx: CTX, + req: &org.AddOrganizationRequest{ + Name: "", + Admins: nil, + }, + wantErr: true, + }, + { + name: "invalid admin type", + ctx: CTX, + req: &org.AddOrganizationRequest{ + Name: fmt.Sprintf("%d", time.Now().UnixNano()), + Admins: []*org.AddOrganizationRequest_Admin{ + {}, + }, + }, + wantErr: true, + }, + { + name: "admin with init", + ctx: CTX, + req: &org.AddOrganizationRequest{ + Name: fmt.Sprintf("%d", time.Now().UnixNano()), + Admins: []*org.AddOrganizationRequest_Admin{ + { + UserType: &org.AddOrganizationRequest_Admin_Human{ + Human: &user.AddHumanUserRequest{ + Profile: &user.SetHumanProfile{ + FirstName: "firstname", + LastName: "lastname", + }, + Email: &user.SetHumanEmail{ + Email: fmt.Sprintf("%d@mouse.com", time.Now().UnixNano()), + Verification: &user.SetHumanEmail_ReturnCode{ + ReturnCode: &user.ReturnEmailVerificationCode{}, + }, + }, + }, + }, + }, + }, + }, + want: &org.AddOrganizationResponse{ + OrganizationId: integration.NotEmpty, + CreatedAdmins: []*org.AddOrganizationResponse_CreatedAdmin{ + { + UserId: integration.NotEmpty, + EmailCode: gu.Ptr(integration.NotEmpty), + PhoneCode: nil, + }, + }, + }, + }, + { + name: "existing user and new human with idp", + ctx: CTX, + req: &org.AddOrganizationRequest{ + Name: fmt.Sprintf("%d", time.Now().UnixNano()), + Admins: []*org.AddOrganizationRequest_Admin{ + { + UserType: &org.AddOrganizationRequest_Admin_UserId{UserId: User.GetUserId()}, + }, + { + UserType: &org.AddOrganizationRequest_Admin_Human{ + Human: &user.AddHumanUserRequest{ + Profile: &user.SetHumanProfile{ + FirstName: "firstname", + LastName: "lastname", + }, + Email: &user.SetHumanEmail{ + Email: fmt.Sprintf("%d@mouse.com", time.Now().UnixNano()), + Verification: &user.SetHumanEmail_IsVerified{ + IsVerified: true, + }, + }, + IdpLinks: []*user.IDPLink{ + { + IdpId: idpID, + UserId: "userID", + UserName: "username", + }, + }, + }, + }, + }, + }, + }, + want: &org.AddOrganizationResponse{ + CreatedAdmins: []*org.AddOrganizationResponse_CreatedAdmin{ + // a single admin is expected, because the first provided already exists + { + UserId: integration.NotEmpty, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := Client.AddOrganization(tt.ctx, tt.req) + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + + // check details + assert.NotZero(t, got.GetDetails().GetSequence()) + gotCD := got.GetDetails().GetChangeDate().AsTime() + now := time.Now() + assert.WithinRange(t, gotCD, now.Add(-time.Minute), now.Add(time.Minute)) + assert.NotEmpty(t, got.GetDetails().GetResourceOwner()) + + // organization id must be the same as the resourceOwner + assert.Equal(t, got.GetDetails().GetResourceOwner(), got.GetOrganizationId()) + + // check the admins + require.Len(t, got.GetCreatedAdmins(), len(tt.want.GetCreatedAdmins())) + for i, admin := range tt.want.GetCreatedAdmins() { + gotAdmin := got.GetCreatedAdmins()[i] + assertCreatedAdmin(t, admin, gotAdmin) + } + }) + } +} + +func assertCreatedAdmin(t *testing.T, expected, got *org.AddOrganizationResponse_CreatedAdmin) { + if expected.GetUserId() != "" { + assert.NotEmpty(t, got.GetUserId()) + } else { + assert.Empty(t, got.GetUserId()) + } + if expected.GetEmailCode() != "" { + assert.NotEmpty(t, got.GetEmailCode()) + } else { + assert.Empty(t, got.GetEmailCode()) + } + if expected.GetPhoneCode() != "" { + assert.NotEmpty(t, got.GetPhoneCode()) + } else { + assert.Empty(t, got.GetPhoneCode()) + } +} diff --git a/internal/api/grpc/org/v2/org_test.go b/internal/api/grpc/org/v2/org_test.go new file mode 100644 index 0000000000..c48421d666 --- /dev/null +++ b/internal/api/grpc/org/v2/org_test.go @@ -0,0 +1,172 @@ +package org + +import ( + "testing" + "time" + + "github.com/muhlemmer/gu" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/types/known/timestamppb" + + "github.com/zitadel/zitadel/internal/command" + "github.com/zitadel/zitadel/internal/domain" + caos_errs "github.com/zitadel/zitadel/internal/errors" + object "github.com/zitadel/zitadel/pkg/grpc/object/v2alpha" + org "github.com/zitadel/zitadel/pkg/grpc/org/v2beta" + user "github.com/zitadel/zitadel/pkg/grpc/user/v2alpha" +) + +func Test_addOrganizationRequestToCommand(t *testing.T) { + type args struct { + request *org.AddOrganizationRequest + } + tests := []struct { + name string + args args + want *command.OrgSetup + wantErr error + }{ + { + name: "nil user", + args: args{ + request: &org.AddOrganizationRequest{ + Name: "name", + Admins: []*org.AddOrganizationRequest_Admin{ + {}, + }, + }, + }, + wantErr: caos_errs.ThrowUnimplementedf(nil, "ORGv2-SD2r1", "userType oneOf %T in method AddOrganization not implemented", nil), + }, + { + name: "user ID", + args: args{ + request: &org.AddOrganizationRequest{ + Name: "name", + Admins: []*org.AddOrganizationRequest_Admin{ + { + UserType: &org.AddOrganizationRequest_Admin_UserId{ + UserId: "userID", + }, + Roles: nil, + }, + }, + }, + }, + want: &command.OrgSetup{ + Name: "name", + CustomDomain: "", + Admins: []*command.OrgSetupAdmin{ + { + ID: "userID", + }, + }, + }, + }, + { + name: "human user", + args: args{ + request: &org.AddOrganizationRequest{ + Name: "name", + Admins: []*org.AddOrganizationRequest_Admin{ + { + UserType: &org.AddOrganizationRequest_Admin_Human{ + Human: &user.AddHumanUserRequest{ + Profile: &user.SetHumanProfile{ + FirstName: "firstname", + LastName: "lastname", + }, + Email: &user.SetHumanEmail{ + Email: "email@test.com", + }, + }, + }, + Roles: nil, + }, + }, + }, + }, + want: &command.OrgSetup{ + Name: "name", + CustomDomain: "", + Admins: []*command.OrgSetupAdmin{ + { + Human: &command.AddHuman{ + Username: "email@test.com", + FirstName: "firstname", + LastName: "lastname", + Email: command.Email{ + Address: "email@test.com", + }, + Metadata: make([]*command.AddMetadataEntry, 0), + Links: make([]*command.AddLink, 0), + }, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := addOrganizationRequestToCommand(tt.args.request) + require.ErrorIs(t, err, tt.wantErr) + assert.Equal(t, tt.want, got) + }) + } +} + +func Test_createdOrganizationToPb(t *testing.T) { + now := time.Now() + type args struct { + createdOrg *command.CreatedOrg + } + tests := []struct { + name string + args args + want *org.AddOrganizationResponse + wantErr error + }{ + { + name: "human user with phone and email code", + args: args{ + createdOrg: &command.CreatedOrg{ + ObjectDetails: &domain.ObjectDetails{ + Sequence: 1, + EventDate: now, + ResourceOwner: "orgID", + }, + CreatedAdmins: []*command.CreatedOrgAdmin{ + { + ID: "id", + EmailCode: gu.Ptr("emailCode"), + PhoneCode: gu.Ptr("phoneCode"), + }, + }, + }, + }, + want: &org.AddOrganizationResponse{ + Details: &object.Details{ + Sequence: 1, + ChangeDate: timestamppb.New(now), + ResourceOwner: "orgID", + }, + OrganizationId: "orgID", + CreatedAdmins: []*org.AddOrganizationResponse_CreatedAdmin{ + { + UserId: "id", + EmailCode: gu.Ptr("emailCode"), + PhoneCode: gu.Ptr("phoneCode"), + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := createdOrganizationToPb(tt.args.createdOrg) + require.ErrorIs(t, err, tt.wantErr) + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/internal/api/grpc/org/v2/server.go b/internal/api/grpc/org/v2/server.go new file mode 100644 index 0000000000..89dba81702 --- /dev/null +++ b/internal/api/grpc/org/v2/server.go @@ -0,0 +1,55 @@ +package org + +import ( + "google.golang.org/grpc" + + "github.com/zitadel/zitadel/internal/api/authz" + "github.com/zitadel/zitadel/internal/api/grpc/server" + "github.com/zitadel/zitadel/internal/command" + "github.com/zitadel/zitadel/internal/domain" + "github.com/zitadel/zitadel/internal/query" + org "github.com/zitadel/zitadel/pkg/grpc/org/v2beta" +) + +var _ org.OrganizationServiceServer = (*Server)(nil) + +type Server struct { + org.UnimplementedOrganizationServiceServer + command *command.Commands + query *query.Queries + checkPermission domain.PermissionCheck +} + +type Config struct{} + +func CreateServer( + command *command.Commands, + query *query.Queries, + checkPermission domain.PermissionCheck, +) *Server { + return &Server{ + command: command, + query: query, + checkPermission: checkPermission, + } +} + +func (s *Server) RegisterServer(grpcServer *grpc.Server) { + org.RegisterOrganizationServiceServer(grpcServer, s) +} + +func (s *Server) AppName() string { + return org.OrganizationService_ServiceDesc.ServiceName +} + +func (s *Server) MethodPrefix() string { + return org.OrganizationService_ServiceDesc.ServiceName +} + +func (s *Server) AuthMethods() authz.MethodMapping { + return org.OrganizationService_AuthMethods +} + +func (s *Server) RegisterGateway() server.RegisterGatewayFunc { + return org.RegisterOrganizationServiceHandler +} diff --git a/internal/api/grpc/user/v2/user.go b/internal/api/grpc/user/v2/user.go index a5b56014a5..af2da629f4 100644 --- a/internal/api/grpc/user/v2/user.go +++ b/internal/api/grpc/user/v2/user.go @@ -19,7 +19,7 @@ import ( ) func (s *Server) AddHumanUser(ctx context.Context, req *user.AddHumanUserRequest) (_ *user.AddHumanUserResponse, err error) { - human, err := addUserRequestToAddHuman(req) + human, err := AddUserRequestToAddHuman(req) if err != nil { return nil, err } @@ -36,7 +36,7 @@ func (s *Server) AddHumanUser(ctx context.Context, req *user.AddHumanUserRequest }, nil } -func addUserRequestToAddHuman(req *user.AddHumanUserRequest) (*command.AddHuman, error) { +func AddUserRequestToAddHuman(req *user.AddHumanUserRequest) (*command.AddHuman, error) { username := req.GetUsername() if username == "" { username = req.GetEmail().GetEmail() diff --git a/internal/api/ui/login/register_org_handler.go b/internal/api/ui/login/register_org_handler.go index 065d9d0cd6..d216394430 100644 --- a/internal/api/ui/login/register_org_handler.go +++ b/internal/api/ui/login/register_org_handler.go @@ -66,7 +66,7 @@ func (l *Login) handleRegisterOrgCheck(w http.ResponseWriter, r *http.Request) { l.renderRegisterOrg(w, r, authRequest, data, err) return } - _, _, err = l.command.SetUpOrg(ctx, data.toCommandOrg(), userIDs...) + _, err = l.command.SetUpOrg(ctx, data.toCommandOrg(), true, userIDs...) if err != nil { l.renderRegisterOrg(w, r, authRequest, data, err) return @@ -144,15 +144,19 @@ func (d registerOrgFormData) toCommandOrg() *command.OrgSetup { } return &command.OrgSetup{ Name: d.RegisterOrgName, - Human: &command.AddHuman{ - Username: d.Username, - FirstName: d.Firstname, - LastName: d.Lastname, - Email: command.Email{ - Address: d.Email, + Admins: []*command.OrgSetupAdmin{ + { + Human: &command.AddHuman{ + Username: d.Username, + FirstName: d.Firstname, + LastName: d.Lastname, + Email: command.Email{ + Address: d.Email, + }, + Password: d.Password, + Register: true, + }, }, - Password: d.Password, - Register: true, }, } } diff --git a/internal/command/instance.go b/internal/command/instance.go index 8bc43fbd38..e0a471fe93 100644 --- a/internal/command/instance.go +++ b/internal/command/instance.go @@ -38,7 +38,7 @@ type InstanceSetup struct { InstanceName string CustomDomain string DefaultLanguage language.Tag - Org OrgSetup + Org InstanceOrgSetup SecretGenerators struct { PasswordSaltCost uint ClientSecret *crypto.GeneratorConfig diff --git a/internal/command/org.go b/internal/command/org.go index ba64dccb5f..1ba999e97c 100644 --- a/internal/command/org.go +++ b/internal/command/org.go @@ -14,7 +14,10 @@ import ( "github.com/zitadel/zitadel/internal/repository/user" ) -type OrgSetup struct { +// InstanceOrgSetup is used for the first organisation in the instance setup. +// It used to be called OrgSetup, which now allows multiple Users, but it's used in the config.yaml and therefore +// a breaking change was not possible. +type InstanceOrgSetup struct { Name string CustomDomain string Human *AddHuman @@ -22,83 +25,210 @@ type OrgSetup struct { Roles []string } -func (c *Commands) setUpOrgWithIDs(ctx context.Context, o *OrgSetup, orgID string, userIDs ...string) (userID string, token string, machineKey *MachineKey, details *domain.ObjectDetails, err error) { - userID, err = c.idGenerator.Next() - if err != nil { - return "", "", nil, nil, err +type OrgSetup struct { + Name string + CustomDomain string + Admins []*OrgSetupAdmin +} + +// OrgSetupAdmin describes a user to be created (Human / Machine) or an existing (ID) to be used for an org setup. +type OrgSetupAdmin struct { + ID string + Human *AddHuman + Machine *AddMachine + Roles []string +} + +type orgSetupCommands struct { + validations []preparation.Validation + aggregate *org.Aggregate + commands *Commands + + admins []*OrgSetupAdmin + pats []*PersonalAccessToken + machineKeys []*MachineKey +} + +type CreatedOrg struct { + ObjectDetails *domain.ObjectDetails + CreatedAdmins []*CreatedOrgAdmin +} + +type CreatedOrgAdmin struct { + ID string + EmailCode *string + PhoneCode *string + PAT *PersonalAccessToken + MachineKey *MachineKey +} + +func (c *Commands) setUpOrgWithIDs(ctx context.Context, o *OrgSetup, orgID string, allowInitialMail bool, userIDs ...string) (_ *CreatedOrg, err error) { + cmds := c.newOrgSetupCommands(ctx, orgID, o, userIDs) + for _, admin := range o.Admins { + if err = cmds.setupOrgAdmin(admin, allowInitialMail); err != nil { + return nil, err + } } + if err = cmds.addCustomDomain(o.CustomDomain, userIDs); err != nil { + return nil, err + } + + return cmds.push(ctx) +} + +func (c *Commands) newOrgSetupCommands(ctx context.Context, orgID string, orgSetup *OrgSetup, userIDs []string) *orgSetupCommands { orgAgg := org.NewAggregate(orgID) - userAgg := user.NewAggregate(userID, orgID) - - roles := []string{domain.RoleOrgOwner} - if len(o.Roles) > 0 { - roles = o.Roles - } - validations := []preparation.Validation{ - AddOrgCommand(ctx, orgAgg, o.Name, userIDs...), + AddOrgCommand(ctx, orgAgg, orgSetup.Name, userIDs...), } + return &orgSetupCommands{ + validations: validations, + aggregate: orgAgg, + commands: c, + admins: orgSetup.Admins, + } +} +func (c *orgSetupCommands) setupOrgAdmin(admin *OrgSetupAdmin, allowInitialMail bool) error { + if admin.ID != "" { + c.validations = append(c.validations, c.commands.AddOrgMemberCommand(c.aggregate, admin.ID, orgAdminRoles(admin.Roles)...)) + return nil + } + userID, err := c.commands.idGenerator.Next() + if err != nil { + return err + } + if admin.Human != nil { + admin.Human.ID = userID + c.validations = append(c.validations, c.commands.AddHumanCommand(admin.Human, c.aggregate.ID, c.commands.userPasswordHasher, c.commands.userEncryption, allowInitialMail)) + } else if admin.Machine != nil { + admin.Machine.Machine.AggregateID = userID + if err = c.setupOrgAdminMachine(c.aggregate, admin.Machine); err != nil { + return err + } + } + c.validations = append(c.validations, c.commands.AddOrgMemberCommand(c.aggregate, userID, orgAdminRoles(admin.Roles)...)) + return nil +} + +func (c *orgSetupCommands) setupOrgAdminMachine(orgAgg *org.Aggregate, machine *AddMachine) error { + userAgg := user.NewAggregate(machine.Machine.AggregateID, orgAgg.ID) + c.validations = append(c.validations, AddMachineCommand(userAgg, machine.Machine)) var pat *PersonalAccessToken - if o.Human != nil { - o.Human.ID = userID - validations = append(validations, c.AddHumanCommand(o.Human, orgID, c.userPasswordHasher, c.userEncryption, true)) - } else if o.Machine != nil { - validations = append(validations, AddMachineCommand(userAgg, o.Machine.Machine)) - if o.Machine.Pat != nil { - pat = NewPersonalAccessToken(orgID, userID, o.Machine.Pat.ExpirationDate, o.Machine.Pat.Scopes, domain.UserTypeMachine) - tokenID, err := c.idGenerator.Next() - if err != nil { - return "", "", nil, nil, err - } - pat.TokenID = tokenID - validations = append(validations, prepareAddPersonalAccessToken(pat, c.keyAlgorithm)) + var machineKey *MachineKey + if machine.Pat != nil { + pat = NewPersonalAccessToken(orgAgg.ID, machine.Machine.AggregateID, machine.Pat.ExpirationDate, machine.Pat.Scopes, domain.UserTypeMachine) + tokenID, err := c.commands.idGenerator.Next() + if err != nil { + return err } - if o.Machine.MachineKey != nil { - machineKey = NewMachineKey(orgID, userID, o.Machine.MachineKey.ExpirationDate, o.Machine.MachineKey.Type) - keyID, err := c.idGenerator.Next() - if err != nil { - return "", "", nil, nil, err - } - machineKey.KeyID = keyID - validations = append(validations, prepareAddUserMachineKey(machineKey, c.keySize)) + pat.TokenID = tokenID + c.pats = append(c.pats, pat) + c.validations = append(c.validations, prepareAddPersonalAccessToken(pat, c.commands.keyAlgorithm)) + } + if machine.MachineKey != nil { + machineKey = NewMachineKey(orgAgg.ID, machine.Machine.AggregateID, machine.MachineKey.ExpirationDate, machine.MachineKey.Type) + keyID, err := c.commands.idGenerator.Next() + if err != nil { + return err } + machineKey.KeyID = keyID + c.machineKeys = append(c.machineKeys, machineKey) + c.validations = append(c.validations, prepareAddUserMachineKey(machineKey, c.commands.keySize)) } - validations = append(validations, c.AddOrgMemberCommand(orgAgg, userID, roles...)) + return nil +} - if o.CustomDomain != "" { - validations = append(validations, c.prepareAddOrgDomain(orgAgg, o.CustomDomain, userIDs)) +func (c *orgSetupCommands) addCustomDomain(domain string, userIDs []string) error { + if domain != "" { + c.validations = append(c.validations, c.commands.prepareAddOrgDomain(c.aggregate, domain, userIDs)) } + return nil +} - cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, validations...) +func orgAdminRoles(roles []string) []string { + if len(roles) > 0 { + return roles + } + return []string{domain.RoleOrgOwner} +} + +func (c *orgSetupCommands) push(ctx context.Context) (_ *CreatedOrg, err error) { + cmds, err := preparation.PrepareCommands(ctx, c.commands.eventstore.Filter, c.validations...) if err != nil { - return "", "", nil, nil, err + return nil, err } - events, err := c.eventstore.Push(ctx, cmds...) + events, err := c.commands.eventstore.Push(ctx, cmds...) if err != nil { - return "", "", nil, nil, err + return nil, err } - if pat != nil { - token = pat.Token - } - - return userID, token, machineKey, &domain.ObjectDetails{ - Sequence: events[len(events)-1].Sequence(), - EventDate: events[len(events)-1].CreationDate(), - ResourceOwner: orgID, + return &CreatedOrg{ + ObjectDetails: &domain.ObjectDetails{ + Sequence: events[len(events)-1].Sequence(), + EventDate: events[len(events)-1].CreationDate(), + ResourceOwner: c.aggregate.ID, + }, + CreatedAdmins: c.createdAdmins(), }, nil } -func (c *Commands) SetUpOrg(ctx context.Context, o *OrgSetup, userIDs ...string) (string, *domain.ObjectDetails, error) { +func (c *orgSetupCommands) createdAdmins() []*CreatedOrgAdmin { + users := make([]*CreatedOrgAdmin, 0, len(c.admins)) + for _, admin := range c.admins { + if admin.ID != "" { + continue + } + if admin.Human != nil { + users = append(users, c.createdHumanAdmin(admin)) + continue + } + if admin.Machine != nil { + users = append(users, c.createdMachineAdmin(admin)) + } + } + return users +} + +func (c *orgSetupCommands) createdHumanAdmin(admin *OrgSetupAdmin) *CreatedOrgAdmin { + createdAdmin := &CreatedOrgAdmin{ + ID: admin.Human.ID, + } + if admin.Human.EmailCode != nil { + createdAdmin.EmailCode = admin.Human.EmailCode + } + return createdAdmin +} + +func (c *orgSetupCommands) createdMachineAdmin(admin *OrgSetupAdmin) *CreatedOrgAdmin { + createdAdmin := &CreatedOrgAdmin{ + ID: admin.Machine.Machine.AggregateID, + } + if admin.Machine.Pat != nil { + for _, pat := range c.pats { + if pat.AggregateID == createdAdmin.ID { + createdAdmin.PAT = pat + } + } + } + if admin.Machine.MachineKey != nil { + for _, key := range c.machineKeys { + if key.AggregateID == createdAdmin.ID { + createdAdmin.MachineKey = key + } + } + } + return createdAdmin +} + +func (c *Commands) SetUpOrg(ctx context.Context, o *OrgSetup, allowInitialMail bool, userIDs ...string) (*CreatedOrg, error) { orgID, err := c.idGenerator.Next() if err != nil { - return "", nil, err + return nil, err } - userID, _, _, details, err := c.setUpOrgWithIDs(ctx, o, orgID, userIDs...) - return userID, details, err + return c.setUpOrgWithIDs(ctx, o, orgID, allowInitialMail, userIDs...) } // AddOrgCommand defines the commands to create a new org, diff --git a/internal/command/org_test.go b/internal/command/org_test.go index 031703d35c..e67ba69dc8 100644 --- a/internal/command/org_test.go +++ b/internal/command/org_test.go @@ -3,11 +3,15 @@ package command import ( "context" "testing" + "time" + "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" + openid "github.com/zitadel/oidc/v2/pkg/oidc" "golang.org/x/text/language" "github.com/zitadel/zitadel/internal/api/authz" + "github.com/zitadel/zitadel/internal/crypto" "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/eventstore" @@ -1325,3 +1329,450 @@ func TestCommandSide_RemoveOrg(t *testing.T) { }) } } + +func TestCommandSide_SetUpOrg(t *testing.T) { + type fields struct { + eventstore func(t *testing.T) *eventstore.Eventstore + idGenerator id.Generator + newCode cryptoCodeFunc + keyAlgorithm crypto.EncryptionAlgorithm + } + type args struct { + ctx context.Context + setupOrg *OrgSetup + allowInitialMail bool + userIDs []string + } + type res struct { + createdOrg *CreatedOrg + err error + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + name: "org name empty, error", + fields: fields{ + eventstore: expectEventstore(), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "orgID"), + }, + args: args{ + ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"), + setupOrg: &OrgSetup{ + Name: "", + }, + }, + res: res{ + err: errors.ThrowInvalidArgument(nil, "ORG-mruNY", "Errors.Invalid.Argument"), + }, + }, + { + name: "userID not existing, error", + fields: fields{ + eventstore: expectEventstore( + expectFilter(), + ), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "orgID"), + }, + args: args{ + ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"), + setupOrg: &OrgSetup{ + Name: "Org", + Admins: []*OrgSetupAdmin{ + { + ID: "userID", + }, + }, + }, + }, + res: res{ + err: errors.ThrowPreconditionFailed(nil, "ORG-GoXOn", "Errors.User.NotFound"), + }, + }, + { + name: "human invalid, error", + fields: fields{ + eventstore: expectEventstore(), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "orgID", "userID"), + }, + args: args{ + ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"), + setupOrg: &OrgSetup{ + Name: "Org", + Admins: []*OrgSetupAdmin{ + { + Human: &AddHuman{ + Username: "", + FirstName: "firstname", + LastName: "lastname", + Email: Email{ + Address: "email@test.ch", + Verified: true, + }, + PreferredLanguage: language.English, + }, + }, + }, + }, + allowInitialMail: true, + }, + res: res{ + err: errors.ThrowInvalidArgument(nil, "V2-zzad3", "Errors.Invalid.Argument"), + }, + }, + { + name: "human added with initial mail", + fields: fields{ + eventstore: expectEventstore( + expectFilter(), // add human exists check + expectFilter( + eventFromEventPusher( + org.NewDomainPolicyAddedEvent(context.Background(), + &user.NewAggregate("userID", "orgID").Aggregate, + true, + true, + true, + ), + ), + ), + expectFilter(), // org member check + expectFilter( + eventFromEventPusher( + user.NewHumanAddedEvent(context.Background(), + &user.NewAggregate("user1", "orgID").Aggregate, + "username", + "firstname", + "lastname", + "", + "firstname lastname", + language.English, + domain.GenderUnspecified, + "email@test.ch", + true, + ), + ), + ), + expectPush( + []*repository.Event{ + eventFromEventPusher(org.NewOrgAddedEvent(context.Background(), + &org.NewAggregate("orgID").Aggregate, + "Org", + )), + eventFromEventPusher(org.NewDomainAddedEvent(context.Background(), + &org.NewAggregate("orgID").Aggregate, "org.iam-domain", + )), + eventFromEventPusher(org.NewDomainVerifiedEvent(context.Background(), + &org.NewAggregate("orgID").Aggregate, + "org.iam-domain", + )), + eventFromEventPusher(org.NewDomainPrimarySetEvent(context.Background(), + &org.NewAggregate("orgID").Aggregate, + "org.iam-domain", + )), + eventFromEventPusher( + user.NewHumanAddedEvent(context.Background(), + &user.NewAggregate("userID", "orgID").Aggregate, + "username", + "firstname", + "lastname", + "", + "firstname lastname", + language.English, + domain.GenderUnspecified, + "email@test.ch", + true, + ), + ), + eventFromEventPusher( + user.NewHumanEmailVerifiedEvent(context.Background(), + &user.NewAggregate("userID", "orgID").Aggregate, + ), + ), + eventFromEventPusher( + user.NewHumanInitialCodeAddedEvent( + context.Background(), + &user.NewAggregate("userID", "orgID").Aggregate, + &crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("userinit"), + }, + 1*time.Hour, + ), + ), + eventFromEventPusher(org.NewMemberAddedEvent(context.Background(), + &org.NewAggregate("orgID").Aggregate, + "userID", + domain.RoleOrgOwner, + )), + }, + uniqueConstraintsFromEventConstraint(org.NewAddOrgNameUniqueConstraint("Org")), + uniqueConstraintsFromEventConstraint(org.NewAddOrgDomainUniqueConstraint("org.iam-domain")), + uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "orgID", true)), + uniqueConstraintsFromEventConstraint(member.NewAddMemberUniqueConstraint("orgID", "userID")), + ), + ), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "orgID", "userID"), + newCode: mockCode("userinit", time.Hour), + }, + args: args{ + ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"), + setupOrg: &OrgSetup{ + Name: "Org", + Admins: []*OrgSetupAdmin{ + { + Human: &AddHuman{ + Username: "username", + FirstName: "firstname", + LastName: "lastname", + Email: Email{ + Address: "email@test.ch", + Verified: true, + }, + PreferredLanguage: language.English, + }, + }, + }, + }, + allowInitialMail: true, + }, + res: res{ + createdOrg: &CreatedOrg{ + ObjectDetails: &domain.ObjectDetails{ + ResourceOwner: "orgID", + }, + CreatedAdmins: []*CreatedOrgAdmin{ + { + ID: "userID", + }, + }, + }, + }, + }, + { + name: "existing human added", + fields: fields{ + eventstore: expectEventstore( + expectFilter( + eventFromEventPusher( + user.NewHumanAddedEvent(context.Background(), + &user.NewAggregate("user1", "orgID").Aggregate, + "username", + "firstname", + "lastname", + "", + "firstname lastname", + language.English, + domain.GenderUnspecified, + "email@test.ch", + true, + ), + ), + ), + expectFilter(), // org member check + expectPush( + []*repository.Event{ + eventFromEventPusher(org.NewOrgAddedEvent(context.Background(), + &org.NewAggregate("orgID").Aggregate, + "Org", + )), + eventFromEventPusher(org.NewDomainAddedEvent(context.Background(), + &org.NewAggregate("orgID").Aggregate, "org.iam-domain", + )), + eventFromEventPusher(org.NewDomainVerifiedEvent(context.Background(), + &org.NewAggregate("orgID").Aggregate, + "org.iam-domain", + )), + eventFromEventPusher(org.NewDomainPrimarySetEvent(context.Background(), + &org.NewAggregate("orgID").Aggregate, + "org.iam-domain", + )), + eventFromEventPusher(org.NewMemberAddedEvent(context.Background(), + &org.NewAggregate("orgID").Aggregate, + "userID", + domain.RoleOrgOwner, + )), + }, + uniqueConstraintsFromEventConstraint(org.NewAddOrgNameUniqueConstraint("Org")), + uniqueConstraintsFromEventConstraint(org.NewAddOrgDomainUniqueConstraint("org.iam-domain")), + uniqueConstraintsFromEventConstraint(member.NewAddMemberUniqueConstraint("orgID", "userID")), + ), + ), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "orgID"), + }, + args: args{ + ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"), + setupOrg: &OrgSetup{ + Name: "Org", + Admins: []*OrgSetupAdmin{ + { + ID: "userID", + }, + }, + }, + allowInitialMail: true, + }, + res: res{ + createdOrg: &CreatedOrg{ + ObjectDetails: &domain.ObjectDetails{ + ResourceOwner: "orgID", + }, + CreatedAdmins: []*CreatedOrgAdmin{}, + }, + }, + }, + { + name: "machine added with pat", + fields: fields{ + eventstore: expectEventstore( + expectFilter(), // add machine exists check + expectFilter( + eventFromEventPusher( + org.NewDomainPolicyAddedEvent(context.Background(), + &user.NewAggregate("userID", "orgID").Aggregate, + true, + true, + true, + ), + ), + ), + expectFilter(), + expectFilter(), + expectFilter(), // org member check + expectFilter( + eventFromEventPusher( + user.NewHumanAddedEvent(context.Background(), + &user.NewAggregate("user1", "orgID").Aggregate, + "username", + "firstname", + "lastname", + "", + "firstname lastname", + language.English, + domain.GenderUnspecified, + "email@test.ch", + true, + ), + ), + ), + expectPush( + []*repository.Event{ + eventFromEventPusher(org.NewOrgAddedEvent(context.Background(), + &org.NewAggregate("orgID").Aggregate, + "Org", + )), + eventFromEventPusher(org.NewDomainAddedEvent(context.Background(), + &org.NewAggregate("orgID").Aggregate, "org.iam-domain", + )), + eventFromEventPusher(org.NewDomainVerifiedEvent(context.Background(), + &org.NewAggregate("orgID").Aggregate, + "org.iam-domain", + )), + eventFromEventPusher(org.NewDomainPrimarySetEvent(context.Background(), + &org.NewAggregate("orgID").Aggregate, + "org.iam-domain", + )), + eventFromEventPusher( + user.NewMachineAddedEvent(context.Background(), + &user.NewAggregate("userID", "orgID").Aggregate, + "username", + "name", + "description", + true, + domain.OIDCTokenTypeBearer, + ), + ), + eventFromEventPusher( + user.NewPersonalAccessTokenAddedEvent(context.Background(), + &user.NewAggregate("userID", "orgID").Aggregate, + "tokenID", + testNow.Add(time.Hour), + []string{openid.ScopeOpenID}, + ), + ), + eventFromEventPusher(org.NewMemberAddedEvent(context.Background(), + &org.NewAggregate("orgID").Aggregate, + "userID", + domain.RoleOrgOwner, + )), + }, + uniqueConstraintsFromEventConstraint(org.NewAddOrgNameUniqueConstraint("Org")), + uniqueConstraintsFromEventConstraint(org.NewAddOrgDomainUniqueConstraint("org.iam-domain")), + uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "orgID", true)), + uniqueConstraintsFromEventConstraint(member.NewAddMemberUniqueConstraint("orgID", "userID")), + ), + ), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "orgID", "userID", "tokenID"), + newCode: mockCode("userinit", time.Hour), + keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args: args{ + ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"), + setupOrg: &OrgSetup{ + Name: "Org", + Admins: []*OrgSetupAdmin{ + { + Machine: &AddMachine{ + Machine: &Machine{ + Username: "username", + Name: "name", + Description: "description", + AccessTokenType: domain.OIDCTokenTypeBearer, + }, + Pat: &AddPat{ + ExpirationDate: testNow.Add(time.Hour), + Scopes: []string{openid.ScopeOpenID}, + }, + }, + }, + }, + }, + }, + res: res{ + createdOrg: &CreatedOrg{ + ObjectDetails: &domain.ObjectDetails{ + ResourceOwner: "orgID", + }, + CreatedAdmins: []*CreatedOrgAdmin{ + { + ID: "userID", + PAT: &PersonalAccessToken{ + ObjectRoot: models.ObjectRoot{ + AggregateID: "userID", + ResourceOwner: "orgID", + }, + ExpirationDate: testNow.Add(time.Hour), + Scopes: []string{openid.ScopeOpenID}, + AllowedUserType: domain.UserTypeMachine, + TokenID: "tokenID", + Token: "dG9rZW5JRDp1c2VySUQ", // token + }, + }, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := &Commands{ + eventstore: tt.fields.eventstore(t), + idGenerator: tt.fields.idGenerator, + newCode: tt.fields.newCode, + keyAlgorithm: tt.fields.keyAlgorithm, + zitadelRoles: []authz.RoleMapping{ + { + Role: domain.RoleOrgOwner, + }, + }, + } + got, err := r.SetUpOrg(tt.args.ctx, tt.args.setupOrg, tt.args.allowInitialMail, tt.args.userIDs...) + assert.ErrorIs(t, err, tt.res.err) + assert.Equal(t, tt.res.createdOrg, got) + }) + } +} diff --git a/internal/integration/client.go b/internal/integration/client.go index 0daf37c404..dd7ce06d6a 100644 --- a/internal/integration/client.go +++ b/internal/integration/client.go @@ -21,6 +21,7 @@ import ( mgmt "github.com/zitadel/zitadel/pkg/grpc/management" object "github.com/zitadel/zitadel/pkg/grpc/object/v2alpha" oidc_pb "github.com/zitadel/zitadel/pkg/grpc/oidc/v2alpha" + organisation "github.com/zitadel/zitadel/pkg/grpc/org/v2beta" session "github.com/zitadel/zitadel/pkg/grpc/session/v2alpha" "github.com/zitadel/zitadel/pkg/grpc/system" user "github.com/zitadel/zitadel/pkg/grpc/user/v2alpha" @@ -34,6 +35,7 @@ type Client struct { UserV2 user.UserServiceClient SessionV2 session.SessionServiceClient OIDCv2 oidc_pb.OIDCServiceClient + OrgV2 organisation.OrganizationServiceClient System system.SystemServiceClient } @@ -46,6 +48,7 @@ func newClient(cc *grpc.ClientConn) Client { UserV2: user.NewUserServiceClient(cc), SessionV2: session.NewSessionServiceClient(cc), OIDCv2: oidc_pb.NewOIDCServiceClient(cc), + OrgV2: organisation.NewOrganizationServiceClient(cc), System: system.NewSystemServiceClient(cc), } } @@ -153,7 +156,7 @@ func (s *Tester) SetUserPassword(ctx context.Context, userID, password string) { func (s *Tester) AddGenericOAuthProvider(t *testing.T) string { ctx := authz.WithInstance(context.Background(), s.Instance) - id, _, err := s.Commands.AddOrgGenericOAuthProvider(ctx, s.Organisation.ID, command.GenericOAuthProvider{ + id, _, err := s.Commands.AddInstanceGenericOAuthProvider(ctx, command.GenericOAuthProvider{ Name: "idp", ClientID: "clientID", ClientSecret: "clientSecret", diff --git a/internal/integration/integration.go b/internal/integration/integration.go index 0912f8dc0b..c645a188fe 100644 --- a/internal/integration/integration.go +++ b/internal/integration/integration.go @@ -46,6 +46,10 @@ var ( systemUserKey []byte ) +// NotEmpty can be used as placeholder, when the returned values is unknown. +// It can be used in tests to assert whether a value should be empty or not. +const NotEmpty = "not empty" + // UserType provides constants that give // a short explinanation with the purpose // a serverice user. @@ -153,11 +157,38 @@ func (s *Tester) pollHealth(ctx context.Context) (err error) { } const ( - LoginUser = "loginClient" - MachineUser = "integration" + LoginUser = "loginClient" + MachineUserOrgOwner = "integrationOrgOwner" + MachineUserInstanceOwner = "integrationInstanceOwner" ) -func (s *Tester) createMachineUser(ctx context.Context, instanceId string) { +func (s *Tester) createMachineUserOrgOwner(ctx context.Context) { + var err error + + ctx, user := s.createMachineUser(ctx, MachineUserOrgOwner, OrgOwner) + _, err = s.Commands.AddOrgMember(ctx, user.ResourceOwner, user.ID, "ORG_OWNER") + target := new(caos_errs.AlreadyExistsError) + if !errors.As(err, &target) { + logging.OnError(err).Fatal("add org member") + } +} + +func (s *Tester) createMachineUserInstanceOwner(ctx context.Context) { + var err error + + ctx, user := s.createMachineUser(ctx, MachineUserInstanceOwner, IAMOwner) + _, err = s.Commands.AddInstanceMember(ctx, user.ID, "IAM_OWNER") + target := new(caos_errs.AlreadyExistsError) + if !errors.As(err, &target) { + logging.OnError(err).Fatal("add instance member") + } +} + +func (s *Tester) createLoginClient(ctx context.Context) { + s.createMachineUser(ctx, LoginUser, Login) +} + +func (s *Tester) createMachineUser(ctx context.Context, username string, userType UserType) (context.Context, *query.User) { var err error s.Instance, err = s.Queries.InstanceByHost(ctx, s.Host()) @@ -167,7 +198,7 @@ func (s *Tester) createMachineUser(ctx context.Context, instanceId string) { s.Organisation, err = s.Queries.OrgByID(ctx, true, s.Instance.DefaultOrganisationID()) logging.OnError(err).Fatal("query organisation") - usernameQuery, err := query.NewUserUsernameSearchQuery(MachineUser, query.TextEquals) + usernameQuery, err := query.NewUserUsernameSearchQuery(username, query.TextEquals) logging.OnError(err).Fatal("user query") user, err := s.Queries.GetUser(ctx, true, true, usernameQuery) if errors.Is(err, sql.ErrNoRows) { @@ -175,69 +206,25 @@ func (s *Tester) createMachineUser(ctx context.Context, instanceId string) { ObjectRoot: models.ObjectRoot{ ResourceOwner: s.Organisation.ID, }, - Username: MachineUser, - Name: MachineUser, + Username: username, + Name: username, Description: "who cares?", AccessTokenType: domain.OIDCTokenTypeJWT, }) - logging.WithFields("username", SystemUser).OnError(err).Fatal("add machine user") + logging.WithFields("username", username).OnError(err).Fatal("add machine user") user, err = s.Queries.GetUser(ctx, true, true, usernameQuery) } - logging.WithFields("username", SystemUser).OnError(err).Fatal("get user") - - _, err = s.Commands.AddOrgMember(ctx, s.Organisation.ID, user.ID, "ORG_OWNER") - target := new(caos_errs.AlreadyExistsError) - if !errors.As(err, &target) { - logging.OnError(err).Fatal("add org member") - } + logging.WithFields("username", username).OnError(err).Fatal("get user") scopes := []string{oidc.ScopeOpenID, oidc.ScopeProfile, z_oidc.ScopeUserMetaData, z_oidc.ScopeResourceOwner} pat := command.NewPersonalAccessToken(user.ResourceOwner, user.ID, time.Now().Add(time.Hour), scopes, domain.UserTypeMachine) _, err = s.Commands.AddPersonalAccessToken(ctx, pat) logging.WithFields("username", SystemUser).OnError(err).Fatal("add pat") - s.Users.Set(instanceId, OrgOwner, &User{ - User: user, - Token: pat.Token, - }) -} - -func (s *Tester) createLoginClient(ctx context.Context) { - var err error - - s.Instance, err = s.Queries.InstanceByHost(ctx, s.Host()) - logging.OnError(err).Fatal("query instance") - ctx = authz.WithInstance(ctx, s.Instance) - - s.Organisation, err = s.Queries.OrgByID(ctx, true, s.Instance.DefaultOrganisationID()) - logging.OnError(err).Fatal("query organisation") - - usernameQuery, err := query.NewUserUsernameSearchQuery(LoginUser, query.TextEquals) - logging.WithFields("username", LoginUser).OnError(err).Fatal("user query") - user, err := s.Queries.GetUser(ctx, true, true, usernameQuery) - if errors.Is(err, sql.ErrNoRows) { - _, err = s.Commands.AddMachine(ctx, &command.Machine{ - ObjectRoot: models.ObjectRoot{ - ResourceOwner: s.Organisation.ID, - }, - Username: LoginUser, - Name: LoginUser, - Description: "who cares?", - AccessTokenType: domain.OIDCTokenTypeJWT, - }) - logging.WithFields("username", LoginUser).OnError(err).Fatal("add machine user") - user, err = s.Queries.GetUser(ctx, true, true, usernameQuery) - } - logging.WithFields("username", LoginUser).OnError(err).Fatal("get user") - - scopes := []string{oidc.ScopeOpenID, z_oidc.ScopeUserMetaData, z_oidc.ScopeResourceOwner} - pat := command.NewPersonalAccessToken(user.ResourceOwner, user.ID, time.Now().Add(time.Hour), scopes, domain.UserTypeMachine) - _, err = s.Commands.AddPersonalAccessToken(ctx, pat) - logging.OnError(err).Fatal("add pat") - - s.Users.Set(FirstInstanceUsersKey, Login, &User{ + s.Users.Set(FirstInstanceUsersKey, userType, &User{ User: user, Token: pat.Token, }) + return ctx, user } func (s *Tester) WithAuthorization(ctx context.Context, u UserType) context.Context { @@ -333,7 +320,8 @@ func NewTester(ctx context.Context) *Tester { tester.createClientConn(ctx) tester.createLoginClient(ctx) tester.WebAuthN = webauthn.NewClient(tester.Config.WebAuthNName, tester.Config.ExternalDomain, http_util.BuildOrigin(tester.Host(), tester.Config.ExternalSecure)) - tester.createMachineUser(ctx, FirstInstanceUsersKey) + tester.createMachineUserOrgOwner(ctx) + tester.createMachineUserInstanceOwner(ctx) tester.WebAuthN = webauthn.NewClient(tester.Config.WebAuthNName, tester.Config.ExternalDomain, "https://"+tester.Host()) return &tester diff --git a/internal/integration/usertype_string.go b/internal/integration/usertype_string.go index 3f5db98d72..6477630986 100644 --- a/internal/integration/usertype_string.go +++ b/internal/integration/usertype_string.go @@ -10,11 +10,14 @@ func _() { var x [1]struct{} _ = x[Unspecified-0] _ = x[OrgOwner-1] + _ = x[Login-2] + _ = x[IAMOwner-3] + _ = x[SystemUser-4] } -const _UserType_name = "UnspecifiedOrgOwner" +const _UserType_name = "UnspecifiedOrgOwnerLoginIAMOwnerSystemUser" -var _UserType_index = [...]uint8{0, 11, 19} +var _UserType_index = [...]uint8{0, 11, 19, 24, 32, 42} func (i UserType) String() string { if i < 0 || i >= UserType(len(_UserType_index)-1) { diff --git a/proto/zitadel/org/v2beta/org_service.proto b/proto/zitadel/org/v2beta/org_service.proto new file mode 100644 index 0000000000..c1bf6e80b0 --- /dev/null +++ b/proto/zitadel/org/v2beta/org_service.proto @@ -0,0 +1,145 @@ +syntax = "proto3"; + + +package zitadel.org.v2beta; + +import "zitadel/object/v2alpha/object.proto"; +import "zitadel/protoc_gen_zitadel/v2/options.proto"; +import "zitadel/user/v2alpha/auth.proto"; +import "zitadel/user/v2alpha/email.proto"; +import "zitadel/user/v2alpha/phone.proto"; +import "zitadel/user/v2alpha/idp.proto"; +import "zitadel/user/v2alpha/password.proto"; +import "zitadel/user/v2alpha/user.proto"; +import "zitadel/user/v2alpha/user_service.proto"; +import "google/api/annotations.proto"; +import "google/api/field_behavior.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/struct.proto"; +import "protoc-gen-openapiv2/options/annotations.proto"; +import "validate/validate.proto"; + +option go_package = "github.com/zitadel/zitadel/pkg/grpc/org/v2beta;org"; + +option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { + info: { + title: "User Service"; + version: "2.0-alpha"; + description: "This API is intended to manage organizations in a ZITADEL instance. This project is in beta state. It can AND will continue breaking until the services provide the same functionality as the current login."; + contact:{ + name: "ZITADEL" + url: "https://zitadel.com" + email: "hi@zitadel.com" + } + license: { + name: "Apache 2.0", + url: "https://github.com/zitadel/zitadel/blob/main/LICENSE"; + }; + }; + schemes: HTTPS; + schemes: HTTP; + + consumes: "application/json"; + consumes: "application/grpc"; + + produces: "application/json"; + produces: "application/grpc"; + + consumes: "application/grpc-web+proto"; + produces: "application/grpc-web+proto"; + + host: "$ZITADEL_DOMAIN"; + base_path: "/"; + + external_docs: { + description: "Detailed information about ZITADEL", + url: "https://zitadel.com/docs" + } + + responses: { + key: "403"; + value: { + description: "Returned when the user does not have permission to access the resource."; + schema: { + json_schema: { + ref: "#/definitions/rpcStatus"; + } + } + } + } + responses: { + key: "404"; + value: { + description: "Returned when the resource does not exist."; + schema: { + json_schema: { + ref: "#/definitions/rpcStatus"; + } + } + } + } +}; + +service OrganizationService { + + // Create a new organization and grant the user(s) permission to manage it + rpc AddOrganization(AddOrganizationRequest) returns (AddOrganizationResponse) { + option (google.api.http) = { + post: "/v2beta/organizations" + body: "*" + }; + + option (zitadel.protoc_gen_zitadel.v2.options) = { + auth_option: { + permission: "org.create" + } + http_response: { + success_code: 201 + } + }; + + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "Create an Organization"; + description: "Create a new organization with an administrative user. If no specific roles are sent for the users, they will be granted the role ORG_OWNER." + responses: { + key: "200" + value: { + description: "OK"; + } + }; + }; + } +} + +message AddOrganizationRequest{ + message Admin { + oneof user_type{ + string user_id = 1; + zitadel.user.v2alpha.AddHumanUserRequest human = 2; + } + // specify Org Member Roles for the provided user (default is ORG_OWNER if roles are empty) + repeated string roles = 3; + } + + string name = 1 [ + (validate.rules).string = {min_len: 1, max_len: 200}, + (google.api.field_behavior) = REQUIRED, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + min_length: 1; + max_length: 200; + example: "\"ZITADEL\""; + } + ]; + repeated Admin admins = 2; +} + +message AddOrganizationResponse{ + message CreatedAdmin { + string user_id = 1; + optional string email_code = 2; + optional string phone_code = 3; + } + zitadel.object.v2alpha.Details details = 1; + string organization_id = 2; + repeated CreatedAdmin created_admins = 3; +} From 4e0c3115feb14611f4672de5a0fd036d4e9af3ac Mon Sep 17 00:00:00 2001 From: Stefan Benz <46600784+stebenz@users.noreply.github.com> Date: Fri, 11 Aug 2023 16:46:28 +0200 Subject: [PATCH 21/38] chore: delete ignore paths to run required jobs (#6356) Co-authored-by: Florian Forster --- .github/workflows/build.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9488e68aab..a7cf07e9df 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,10 +2,6 @@ name: ZITADEL CI/CD on: pull_request: - paths-ignore: - - 'docs/**' - - 'guides/**' - - '**.md' workflow_dispatch: permissions: From 86af67d1be2bb50852b742d5801cac349f2a0318 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20M=C3=B6hlmann?= Date: Fri, 11 Aug 2023 18:36:18 +0300 Subject: [PATCH 22/38] feat(api/v2): implement U2F session check (#6339) --- .gitignore | 1 - Makefile | 7 +- internal/api/grpc/session/v2/session.go | 57 ++-- .../session/v2/session_integration_test.go | 133 +++++++--- internal/api/grpc/session/v2/session_test.go | 51 +++- .../api/grpc/user/v2/otp_integration_test.go | 14 +- .../api/oidc/auth_request_integration_test.go | 24 +- internal/api/oidc/client_integration_test.go | 4 +- internal/api/oidc/oidc_integration_test.go | 9 +- .../eventstore/token_verifier.go | 11 +- internal/command/auth_request_test.go | 8 +- internal/command/oidc_session_test.go | 4 +- internal/command/session.go | 29 +- internal/command/session_model.go | 71 +++-- internal/command/session_model_test.go | 75 ++++++ internal/command/session_passkey.go | 84 ------ internal/command/session_passkeys_test.go | 131 --------- internal/command/session_test.go | 50 +--- internal/command/session_webauhtn.go | 89 +++++++ internal/command/session_webauthn_test.go | 250 ++++++++++++++++++ internal/command/user_converter.go | 14 +- internal/command/user_human_webauthn.go | 12 +- internal/command/user_human_webauthn_model.go | 14 + internal/integration/client.go | 33 ++- internal/query/projection/session.go | 53 ++-- internal/query/projection/session_test.go | 53 +++- internal/query/session.go | 86 +++--- internal/query/sessions_test.go | 114 ++++---- internal/repository/session/eventstore.go | 4 +- internal/repository/session/session.go | 66 ++--- internal/static/i18n/bg.yaml | 4 +- internal/static/i18n/de.yaml | 4 +- internal/static/i18n/en.yaml | 4 +- internal/static/i18n/es.yaml | 4 +- internal/static/i18n/fr.yaml | 4 +- internal/static/i18n/it.yaml | 4 +- internal/static/i18n/ja.yaml | 4 +- internal/static/i18n/mk.yaml | 4 +- internal/static/i18n/pl.yaml | 4 +- internal/static/i18n/pt.yaml | 4 +- internal/static/i18n/zh.yaml | 4 +- internal/webauthn/client.go | 24 +- internal/webauthn/webauthn.go | 12 +- proto/buf.yaml | 1 + proto/zitadel/session/v2alpha/challenge.proto | 39 ++- proto/zitadel/session/v2alpha/session.proto | 10 +- .../session/v2alpha/session_service.proto | 19 +- 47 files changed, 1035 insertions(+), 665 deletions(-) create mode 100644 internal/command/session_model_test.go delete mode 100644 internal/command/session_passkey.go delete mode 100644 internal/command/session_passkeys_test.go create mode 100644 internal/command/session_webauhtn.go create mode 100644 internal/command/session_webauthn_test.go diff --git a/.gitignore b/.gitignore index 1ed24a2345..db17a6ead4 100644 --- a/.gitignore +++ b/.gitignore @@ -64,7 +64,6 @@ docs/docs/apis/proto **/.sass-cache /internal/api/ui/login/static/resources/themes/zitadel/css/zitadel.css /internal/api/ui/login/static/resources/themes/zitadel/css/zitadel.css.map -zitadel zitadel-*-* # local diff --git a/Makefile b/Makefile index a11884654c..f6ecc754bf 100644 --- a/Makefile +++ b/Makefile @@ -90,12 +90,15 @@ clean: core_unit_test: go test -race -coverprofile=profile.cov ./... -.PHONY: core_integration_test -core_integration_test: +.PHONY: core_integration_setup +core_integration_setup: go build -o zitadel main.go ./zitadel init --config internal/integration/config/zitadel.yaml --config internal/integration/config/${INTEGRATION_DB_FLAVOR}.yaml ./zitadel setup --masterkeyFromEnv --config internal/integration/config/zitadel.yaml --config internal/integration/config/${INTEGRATION_DB_FLAVOR}.yaml $(RM) zitadel + +.PHONY: core_integration_test +core_integration_test: core_integration_setup go test -tags=integration -race -p 1 -v -coverprofile=profile.cov -coverpkg=./internal/...,./cmd/... ./internal/integration ./internal/api/grpc/... ./internal/notification/handlers/... ./internal/api/oidc/... .PHONY: console_lint diff --git a/internal/api/grpc/session/v2/session.go b/internal/api/grpc/session/v2/session.go index e842476c25..ea61528fcb 100644 --- a/internal/api/grpc/session/v2/session.go +++ b/internal/api/grpc/session/v2/session.go @@ -47,7 +47,7 @@ func (s *Server) CreateSession(ctx context.Context, req *session.CreateSessionRe } challengeResponse, cmds := s.challengesToCommand(req.GetChallenges(), checks) - set, err := s.command.CreateSession(ctx, cmds, req.GetDomain(), metadata) + set, err := s.command.CreateSession(ctx, cmds, metadata) if err != nil { return nil, err } @@ -107,7 +107,6 @@ func sessionToPb(s *query.Session) *session.Session { Sequence: s.Sequence, Factors: factorsToPb(s), Metadata: s.Metadata, - Domain: s.Domain, } } @@ -119,7 +118,7 @@ func factorsToPb(s *query.Session) *session.Factors { return &session.Factors{ User: user, Password: passwordFactorToPb(s.PasswordFactor), - Passkey: passkeyFactorToPb(s.PasskeyFactor), + WebAuthN: webAuthNFactorToPb(s.WebAuthNFactor), Intent: intentFactorToPb(s.IntentFactor), } } @@ -142,12 +141,13 @@ func intentFactorToPb(factor query.SessionIntentFactor) *session.IntentFactor { } } -func passkeyFactorToPb(factor query.SessionPasskeyFactor) *session.PasskeyFactor { - if factor.PasskeyCheckedAt.IsZero() { +func webAuthNFactorToPb(factor query.SessionWebAuthNFactor) *session.WebAuthNFactor { + if factor.WebAuthNCheckedAt.IsZero() { return nil } - return &session.PasskeyFactor{ - VerifiedAt: timestamppb.New(factor.PasskeyCheckedAt), + return &session.WebAuthNFactor{ + VerifiedAt: timestamppb.New(factor.WebAuthNCheckedAt), + UserVerified: factor.UserVerified, } } @@ -244,36 +244,47 @@ func (s *Server) checksToCommand(ctx context.Context, checks *session.Checks) ([ if intent := checks.GetIntent(); intent != nil { sessionChecks = append(sessionChecks, command.CheckIntent(intent.GetIntentId(), intent.GetToken())) } - if passkey := checks.GetPasskey(); passkey != nil { - sessionChecks = append(sessionChecks, s.command.CheckPasskey(passkey.GetCredentialAssertionData())) + if passkey := checks.GetWebAuthN(); passkey != nil { + sessionChecks = append(sessionChecks, s.command.CheckWebAuthN(passkey.GetCredentialAssertionData())) } return sessionChecks, nil } -func (s *Server) challengesToCommand(challenges []session.ChallengeKind, cmds []command.SessionCommand) (*session.Challenges, []command.SessionCommand) { - if len(challenges) == 0 { +func (s *Server) challengesToCommand(challenges *session.RequestChallenges, cmds []command.SessionCommand) (*session.Challenges, []command.SessionCommand) { + if challenges == nil { return nil, cmds } resp := new(session.Challenges) - for _, c := range challenges { - switch c { - case session.ChallengeKind_CHALLENGE_KIND_UNSPECIFIED: - continue - case session.ChallengeKind_CHALLENGE_KIND_PASSKEY: - passkeyChallenge, cmd := s.createPasskeyChallengeCommand() - resp.Passkey = passkeyChallenge - cmds = append(cmds, cmd) - } + if req := challenges.GetWebAuthN(); req != nil { + challenge, cmd := s.createWebAuthNChallengeCommand(req) + resp.WebAuthN = challenge + cmds = append(cmds, cmd) } return resp, cmds } -func (s *Server) createPasskeyChallengeCommand() (*session.Challenges_Passkey, command.SessionCommand) { - challenge := &session.Challenges_Passkey{ +func (s *Server) createWebAuthNChallengeCommand(req *session.RequestChallenges_WebAuthN) (*session.Challenges_WebAuthN, command.SessionCommand) { + challenge := &session.Challenges_WebAuthN{ PublicKeyCredentialRequestOptions: new(structpb.Struct), } - return challenge, s.command.CreatePasskeyChallenge(domain.UserVerificationRequirementRequired, challenge.PublicKeyCredentialRequestOptions) + userVerification := userVerificationRequirementToDomain(req.GetUserVerificationRequirement()) + return challenge, s.command.CreateWebAuthNChallenge(userVerification, req.GetDomain(), challenge.PublicKeyCredentialRequestOptions) +} + +func userVerificationRequirementToDomain(req session.UserVerificationRequirement) domain.UserVerificationRequirement { + switch req { + case session.UserVerificationRequirement_USER_VERIFICATION_REQUIREMENT_UNSPECIFIED: + return domain.UserVerificationRequirementUnspecified + case session.UserVerificationRequirement_USER_VERIFICATION_REQUIREMENT_REQUIRED: + return domain.UserVerificationRequirementRequired + case session.UserVerificationRequirement_USER_VERIFICATION_REQUIREMENT_PREFERRED: + return domain.UserVerificationRequirementPreferred + case session.UserVerificationRequirement_USER_VERIFICATION_REQUIREMENT_DISCOURAGED: + return domain.UserVerificationRequirementDiscouraged + default: + return domain.UserVerificationRequirementUnspecified + } } func userCheck(user *session.CheckUser) (userSearch, error) { diff --git a/internal/api/grpc/session/v2/session_integration_test.go b/internal/api/grpc/session/v2/session_integration_test.go index 7f6ad96643..7dd9355a71 100644 --- a/internal/api/grpc/session/v2/session_integration_test.go +++ b/internal/api/grpc/session/v2/session_integration_test.go @@ -69,7 +69,8 @@ type wantFactor int const ( wantUserFactor wantFactor = iota wantPasswordFactor - wantPasskeyFactor + wantWebAuthNFactor + wantWebAuthNFactorUserVerified wantIntentFactor ) @@ -85,10 +86,16 @@ func verifyFactors(t testing.TB, factors *session.Factors, window time.Duration, pf := factors.GetPassword() assert.NotNil(t, pf) assert.WithinRange(t, pf.GetVerifiedAt().AsTime(), time.Now().Add(-window), time.Now().Add(window)) - case wantPasskeyFactor: - pf := factors.GetPasskey() + case wantWebAuthNFactor: + pf := factors.GetWebAuthN() assert.NotNil(t, pf) assert.WithinRange(t, pf.GetVerifiedAt().AsTime(), time.Now().Add(-window), time.Now().Add(window)) + assert.False(t, pf.UserVerified) + case wantWebAuthNFactorUserVerified: + pf := factors.GetWebAuthN() + assert.NotNil(t, pf) + assert.WithinRange(t, pf.GetVerifiedAt().AsTime(), time.Now().Add(-window), time.Now().Add(window)) + assert.True(t, pf.UserVerified) case wantIntentFactor: pf := factors.GetIntent() assert.NotNil(t, pf) @@ -127,7 +134,6 @@ func TestServer_CreateSession(t *testing.T) { }, }, Metadata: map[string][]byte{"foo": []byte("bar")}, - Domain: "domain", }, want: &session.CreateSessionResponse{ Details: &object.Details{ @@ -150,8 +156,11 @@ func TestServer_CreateSession(t *testing.T) { { name: "passkey without user error", req: &session.CreateSessionRequest{ - Challenges: []session.ChallengeKind{ - session.ChallengeKind_CHALLENGE_KIND_PASSKEY, + Challenges: &session.RequestChallenges{ + WebAuthN: &session.RequestChallenges_WebAuthN{ + Domain: Tester.Config.ExternalDomain, + UserVerificationRequirement: session.UserVerificationRequirement_USER_VERIFICATION_REQUIREMENT_REQUIRED, + }, }, }, wantErr: true, @@ -166,8 +175,10 @@ func TestServer_CreateSession(t *testing.T) { }, }, }, - Challenges: []session.ChallengeKind{ - session.ChallengeKind_CHALLENGE_KIND_PASSKEY, + Challenges: &session.RequestChallenges{ + WebAuthN: &session.RequestChallenges_WebAuthN{ + UserVerificationRequirement: session.UserVerificationRequirement_USER_VERIFICATION_REQUIREMENT_REQUIRED, + }, }, }, wantErr: true, @@ -188,8 +199,8 @@ func TestServer_CreateSession(t *testing.T) { } } -func TestServer_CreateSession_passkey(t *testing.T) { - // create new session with user and request the passkey challenge +func TestServer_CreateSession_webauthn(t *testing.T) { + // create new session with user and request the webauthn challenge createResp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{ Checks: &session.Checks{ User: &session.CheckUser{ @@ -198,29 +209,31 @@ func TestServer_CreateSession_passkey(t *testing.T) { }, }, }, - Challenges: []session.ChallengeKind{ - session.ChallengeKind_CHALLENGE_KIND_PASSKEY, + Challenges: &session.RequestChallenges{ + WebAuthN: &session.RequestChallenges_WebAuthN{ + Domain: Tester.Config.ExternalDomain, + UserVerificationRequirement: session.UserVerificationRequirement_USER_VERIFICATION_REQUIREMENT_REQUIRED, + }, }, - Domain: Tester.Config.ExternalDomain, }) require.NoError(t, err) verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil) - assertionData, err := Tester.WebAuthN.CreateAssertionResponse(createResp.GetChallenges().GetPasskey().GetPublicKeyCredentialRequestOptions()) + assertionData, err := Tester.WebAuthN.CreateAssertionResponse(createResp.GetChallenges().GetWebAuthN().GetPublicKeyCredentialRequestOptions(), true) require.NoError(t, err) - // update the session with passkey assertion data + // update the session with webauthn assertion data updateResp, err := Client.SetSession(CTX, &session.SetSessionRequest{ SessionId: createResp.GetSessionId(), SessionToken: createResp.GetSessionToken(), Checks: &session.Checks{ - Passkey: &session.CheckPasskey{ + WebAuthN: &session.CheckWebAuthN{ CredentialAssertionData: assertionData, }, }, }) require.NoError(t, err) - verifyCurrentSession(t, createResp.GetSessionId(), updateResp.GetSessionToken(), updateResp.GetDetails().GetSequence(), time.Minute, nil, wantUserFactor, wantPasskeyFactor) + verifyCurrentSession(t, createResp.GetSessionId(), updateResp.GetSessionToken(), updateResp.GetDetails().GetSequence(), time.Minute, nil, wantUserFactor, wantWebAuthNFactorUserVerified) } func TestServer_CreateSession_successfulIntent(t *testing.T) { @@ -326,16 +339,14 @@ func TestServer_CreateSession_startedIntentFalseToken(t *testing.T) { } func TestServer_SetSession_flow(t *testing.T) { - var wantFactors []wantFactor - // create new, empty session - createResp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{Domain: Tester.Config.ExternalDomain}) + createResp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{}) require.NoError(t, err) - verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, wantFactors...) sessionToken := createResp.GetSessionToken() + verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, createResp.GetDetails().GetSequence(), time.Minute, nil) t.Run("check user", func(t *testing.T) { - wantFactors = append(wantFactors, wantUserFactor) + wantFactors := []wantFactor{wantUserFactor} resp, err := Client.SetSession(CTX, &session.SetSessionRequest{ SessionId: createResp.GetSessionId(), SessionToken: sessionToken, @@ -348,43 +359,92 @@ func TestServer_SetSession_flow(t *testing.T) { }, }) require.NoError(t, err) - verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil, wantFactors...) sessionToken = resp.GetSessionToken() + verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, wantFactors...) }) - t.Run("check passkey", func(t *testing.T) { + t.Run("check webauthn, user verified (passkey)", func(t *testing.T) { resp, err := Client.SetSession(CTX, &session.SetSessionRequest{ SessionId: createResp.GetSessionId(), SessionToken: sessionToken, - Challenges: []session.ChallengeKind{ - session.ChallengeKind_CHALLENGE_KIND_PASSKEY, + Challenges: &session.RequestChallenges{ + WebAuthN: &session.RequestChallenges_WebAuthN{ + Domain: Tester.Config.ExternalDomain, + UserVerificationRequirement: session.UserVerificationRequirement_USER_VERIFICATION_REQUIREMENT_REQUIRED, + }, }, }) require.NoError(t, err) - verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil, wantFactors...) + verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil) sessionToken = resp.GetSessionToken() - wantFactors = append(wantFactors, wantPasskeyFactor) - assertionData, err := Tester.WebAuthN.CreateAssertionResponse(resp.GetChallenges().GetPasskey().GetPublicKeyCredentialRequestOptions()) + wantFactors := []wantFactor{wantUserFactor, wantWebAuthNFactorUserVerified} + assertionData, err := Tester.WebAuthN.CreateAssertionResponse(resp.GetChallenges().GetWebAuthN().GetPublicKeyCredentialRequestOptions(), true) require.NoError(t, err) resp, err = Client.SetSession(CTX, &session.SetSessionRequest{ SessionId: createResp.GetSessionId(), SessionToken: sessionToken, Checks: &session.Checks{ - Passkey: &session.CheckPasskey{ + WebAuthN: &session.CheckWebAuthN{ CredentialAssertionData: assertionData, }, }, }) require.NoError(t, err) - verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil, wantFactors...) + sessionToken = resp.GetSessionToken() + verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, wantFactors...) + }) + + t.Run("check webauthn, user not verified (U2F)", func(t *testing.T) { + Tester.RegisterUserU2F( + Tester.WithAuthorizationToken(context.Background(), sessionToken), + User.GetUserId(), + ) + + for _, userVerificationRequirement := range []session.UserVerificationRequirement{ + session.UserVerificationRequirement_USER_VERIFICATION_REQUIREMENT_PREFERRED, + session.UserVerificationRequirement_USER_VERIFICATION_REQUIREMENT_DISCOURAGED, + } { + t.Run(userVerificationRequirement.String(), func(t *testing.T) { + resp, err := Client.SetSession(CTX, &session.SetSessionRequest{ + SessionId: createResp.GetSessionId(), + SessionToken: sessionToken, + Challenges: &session.RequestChallenges{ + WebAuthN: &session.RequestChallenges_WebAuthN{ + Domain: Tester.Config.ExternalDomain, + UserVerificationRequirement: userVerificationRequirement, + }, + }, + }) + require.NoError(t, err) + verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil) + sessionToken = resp.GetSessionToken() + + wantFactors := []wantFactor{wantUserFactor, wantWebAuthNFactor} + assertionData, err := Tester.WebAuthN.CreateAssertionResponse(resp.GetChallenges().GetWebAuthN().GetPublicKeyCredentialRequestOptions(), false) + require.NoError(t, err) + + resp, err = Client.SetSession(CTX, &session.SetSessionRequest{ + SessionId: createResp.GetSessionId(), + SessionToken: sessionToken, + Checks: &session.Checks{ + WebAuthN: &session.CheckWebAuthN{ + CredentialAssertionData: assertionData, + }, + }, + }) + require.NoError(t, err) + sessionToken = resp.GetSessionToken() + verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, wantFactors...) + }) + } }) } func Test_ZITADEL_API_missing_authentication(t *testing.T) { // create new, empty session - createResp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{Domain: Tester.Config.ExternalDomain}) + createResp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{}) require.NoError(t, err) ctx := metadata.AppendToOutgoingContext(context.Background(), "Authorization", fmt.Sprintf("Bearer %s", createResp.GetSessionToken())) @@ -403,16 +463,19 @@ func Test_ZITADEL_API_missing_mfa(t *testing.T) { } func Test_ZITADEL_API_success(t *testing.T) { - id, token, _, _ := Tester.CreatePasskeySession(t, CTX, User.GetUserId()) + id, token, _, _ := Tester.CreateVerfiedWebAuthNSession(t, CTX, User.GetUserId()) ctx := Tester.WithAuthorizationToken(context.Background(), token) sessionResp, err := Tester.Client.SessionV2.GetSession(ctx, &session.GetSessionRequest{SessionId: id}) require.NoError(t, err) - require.NotNil(t, id, sessionResp.GetSession().GetFactors().GetPasskey().GetVerifiedAt().AsTime()) + + webAuthN := sessionResp.GetSession().GetFactors().GetWebAuthN() + require.NotNil(t, id, webAuthN.GetVerifiedAt().AsTime()) + require.True(t, webAuthN.GetUserVerified()) } func Test_ZITADEL_API_session_not_found(t *testing.T) { - id, token, _, _ := Tester.CreatePasskeySession(t, CTX, User.GetUserId()) + id, token, _, _ := Tester.CreateVerfiedWebAuthNSession(t, CTX, User.GetUserId()) // test session token works ctx := Tester.WithAuthorizationToken(context.Background(), token) diff --git a/internal/api/grpc/session/v2/session_test.go b/internal/api/grpc/session/v2/session_test.go index 410ab43dcd..0f4d9b3c66 100644 --- a/internal/api/grpc/session/v2/session_test.go +++ b/internal/api/grpc/session/v2/session_test.go @@ -70,7 +70,7 @@ func Test_sessionsToPb(t *testing.T) { }, Metadata: map[string][]byte{"hello": []byte("world")}, }, - { // passkey factor + { // webAuthN factor ID: "999", CreationDate: now, ChangeDate: now, @@ -85,8 +85,9 @@ func Test_sessionsToPb(t *testing.T) { DisplayName: "donald duck", ResourceOwner: "org1", }, - PasskeyFactor: query.SessionPasskeyFactor{ - PasskeyCheckedAt: past, + WebAuthNFactor: query.SessionWebAuthNFactor{ + WebAuthNCheckedAt: past, + UserVerified: true, }, Metadata: map[string][]byte{"hello": []byte("world")}, }, @@ -136,7 +137,7 @@ func Test_sessionsToPb(t *testing.T) { }, Metadata: map[string][]byte{"hello": []byte("world")}, }, - { // passkey factor + { // webAuthN factor Id: "999", CreationDate: timestamppb.New(now), ChangeDate: timestamppb.New(now), @@ -149,8 +150,9 @@ func Test_sessionsToPb(t *testing.T) { DisplayName: "donald duck", OrganisationId: "org1", }, - Passkey: &session.PasskeyFactor{ - VerifiedAt: timestamppb.New(past), + WebAuthN: &session.WebAuthNFactor{ + VerifiedAt: timestamppb.New(past), + UserVerified: true, }, }, Metadata: map[string][]byte{"hello": []byte("world")}, @@ -432,3 +434,40 @@ func Test_userCheck(t *testing.T) { }) } } + +func Test_userVerificationRequirementToDomain(t *testing.T) { + type args struct { + req session.UserVerificationRequirement + } + tests := []struct { + args args + want domain.UserVerificationRequirement + }{ + { + args: args{session.UserVerificationRequirement_USER_VERIFICATION_REQUIREMENT_UNSPECIFIED}, + want: domain.UserVerificationRequirementUnspecified, + }, + { + args: args{session.UserVerificationRequirement_USER_VERIFICATION_REQUIREMENT_REQUIRED}, + want: domain.UserVerificationRequirementRequired, + }, + { + args: args{session.UserVerificationRequirement_USER_VERIFICATION_REQUIREMENT_PREFERRED}, + want: domain.UserVerificationRequirementPreferred, + }, + { + args: args{session.UserVerificationRequirement_USER_VERIFICATION_REQUIREMENT_DISCOURAGED}, + want: domain.UserVerificationRequirementDiscouraged, + }, + { + args: args{999}, + want: domain.UserVerificationRequirementUnspecified, + }, + } + for _, tt := range tests { + t.Run(tt.args.req.String(), func(t *testing.T) { + got := userVerificationRequirementToDomain(tt.args.req) + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/internal/api/grpc/user/v2/otp_integration_test.go b/internal/api/grpc/user/v2/otp_integration_test.go index 5d36dd361e..9f99596f2e 100644 --- a/internal/api/grpc/user/v2/otp_integration_test.go +++ b/internal/api/grpc/user/v2/otp_integration_test.go @@ -16,13 +16,13 @@ import ( func TestServer_AddOTPSMS(t *testing.T) { userID := Tester.CreateHumanUser(CTX).GetUserId() Tester.RegisterUserPasskey(CTX, userID) - _, sessionToken, _, _ := Tester.CreatePasskeySession(t, CTX, userID) + _, sessionToken, _, _ := Tester.CreateVerfiedWebAuthNSession(t, CTX, userID) // TODO: add when phone can be added to user /* userIDPhone := Tester.CreateHumanUser(CTX).GetUserId() Tester.RegisterUserPasskey(CTX, userIDPhone) - _, sessionTokenPhone, _, _ := Tester.CreatePasskeySession(t, CTX, userIDPhone) + _, sessionTokenPhone, _, _ := Tester.CreateVerfiedWebAuthNSession(t, CTX, userIDPhone) */ type args struct { ctx context.Context @@ -99,7 +99,7 @@ func TestServer_RemoveOTPSMS(t *testing.T) { /* userID := Tester.CreateHumanUser(CTX).GetUserId() Tester.RegisterUserPasskey(CTX, userID) - _, sessionToken, _, _ := Tester.CreatePasskeySession(t, CTX, userID) + _, sessionToken, _, _ := Tester.CreateVerfiedWebAuthNSession(t, CTX, userID) */ type args struct { @@ -157,7 +157,7 @@ func TestServer_RemoveOTPSMS(t *testing.T) { func TestServer_AddOTPEmail(t *testing.T) { userID := Tester.CreateHumanUser(CTX).GetUserId() Tester.RegisterUserPasskey(CTX, userID) - _, sessionToken, _, _ := Tester.CreatePasskeySession(t, CTX, userID) + _, sessionToken, _, _ := Tester.CreateVerfiedWebAuthNSession(t, CTX, userID) userVerified := Tester.CreateHumanUser(CTX) _, err := Tester.Client.UserV2.VerifyEmail(CTX, &user.VerifyEmailRequest{ @@ -166,7 +166,7 @@ func TestServer_AddOTPEmail(t *testing.T) { }) require.NoError(t, err) Tester.RegisterUserPasskey(CTX, userVerified.GetUserId()) - _, sessionTokenVerified, _, _ := Tester.CreatePasskeySession(t, CTX, userVerified.GetUserId()) + _, sessionTokenVerified, _, _ := Tester.CreateVerfiedWebAuthNSession(t, CTX, userVerified.GetUserId()) type args struct { ctx context.Context @@ -238,11 +238,11 @@ func TestServer_AddOTPEmail(t *testing.T) { func TestServer_RemoveOTPEmail(t *testing.T) { userID := Tester.CreateHumanUser(CTX).GetUserId() Tester.RegisterUserPasskey(CTX, userID) - _, sessionToken, _, _ := Tester.CreatePasskeySession(t, CTX, userID) + _, sessionToken, _, _ := Tester.CreateVerfiedWebAuthNSession(t, CTX, userID) userVerified := Tester.CreateHumanUser(CTX) Tester.RegisterUserPasskey(CTX, userVerified.GetUserId()) - _, sessionTokenVerified, _, _ := Tester.CreatePasskeySession(t, CTX, userVerified.GetUserId()) + _, sessionTokenVerified, _, _ := Tester.CreateVerfiedWebAuthNSession(t, CTX, userVerified.GetUserId()) userVerifiedCtx := Tester.WithAuthorizationToken(context.Background(), sessionTokenVerified) _, err := Tester.Client.UserV2.VerifyEmail(userVerifiedCtx, &user.VerifyEmailRequest{ UserId: userVerified.GetUserId(), diff --git a/internal/api/oidc/auth_request_integration_test.go b/internal/api/oidc/auth_request_integration_test.go index 7651b32c87..1c5074e894 100644 --- a/internal/api/oidc/auth_request_integration_test.go +++ b/internal/api/oidc/auth_request_integration_test.go @@ -36,7 +36,7 @@ func TestOPStorage_CreateAuthRequest(t *testing.T) { func TestOPStorage_CreateAccessToken_code(t *testing.T) { clientID := createClient(t) authRequestID := createAuthRequest(t, clientID, redirectURI) - sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId()) linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ AuthRequestId: authRequestID, CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ @@ -75,7 +75,7 @@ func TestOPStorage_CreateAccessToken_code(t *testing.T) { func TestOPStorage_CreateAccessToken_implicit(t *testing.T) { clientID := createImplicitClient(t) authRequestID := createAuthRequestImplicit(t, clientID, redirectURIImplicit) - sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId()) linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ AuthRequestId: authRequestID, CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ @@ -125,7 +125,7 @@ func TestOPStorage_CreateAccessToken_implicit(t *testing.T) { func TestOPStorage_CreateAccessAndRefreshTokens_code(t *testing.T) { clientID := createClient(t) authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess) - sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId()) linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ AuthRequestId: authRequestID, CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ @@ -150,7 +150,7 @@ func TestOPStorage_CreateAccessAndRefreshTokens_refresh(t *testing.T) { provider, err := Tester.CreateRelyingParty(clientID, redirectURI) require.NoError(t, err) authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess) - sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId()) linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ AuthRequestId: authRequestID, CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ @@ -186,7 +186,7 @@ func TestOPStorage_RevokeToken_access_token(t *testing.T) { provider, err := Tester.CreateRelyingParty(clientID, redirectURI) require.NoError(t, err) authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess) - sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId()) linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ AuthRequestId: authRequestID, CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ @@ -229,7 +229,7 @@ func TestOPStorage_RevokeToken_access_token_invalid_token_hint_type(t *testing.T provider, err := Tester.CreateRelyingParty(clientID, redirectURI) require.NoError(t, err) authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess) - sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId()) linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ AuthRequestId: authRequestID, CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ @@ -266,7 +266,7 @@ func TestOPStorage_RevokeToken_refresh_token(t *testing.T) { provider, err := Tester.CreateRelyingParty(clientID, redirectURI) require.NoError(t, err) authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess) - sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId()) linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ AuthRequestId: authRequestID, CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ @@ -309,7 +309,7 @@ func TestOPStorage_RevokeToken_refresh_token_invalid_token_type_hint(t *testing. provider, err := Tester.CreateRelyingParty(clientID, redirectURI) require.NoError(t, err) authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess) - sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId()) linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ AuthRequestId: authRequestID, CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ @@ -344,7 +344,7 @@ func TestOPStorage_RevokeToken_refresh_token_invalid_token_type_hint(t *testing. func TestOPStorage_RevokeToken_invalid_client(t *testing.T) { clientID := createClient(t) authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess) - sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId()) linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ AuthRequestId: authRequestID, CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ @@ -376,7 +376,7 @@ func TestOPStorage_TerminateSession(t *testing.T) { provider, err := Tester.CreateRelyingParty(clientID, redirectURI) require.NoError(t, err) authRequestID := createAuthRequest(t, clientID, redirectURI) - sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId()) linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ AuthRequestId: authRequestID, CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ @@ -413,7 +413,7 @@ func TestOPStorage_TerminateSession_refresh_grant(t *testing.T) { provider, err := Tester.CreateRelyingParty(clientID, redirectURI) require.NoError(t, err) authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess) - sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId()) linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ AuthRequestId: authRequestID, CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ @@ -457,7 +457,7 @@ func TestOPStorage_TerminateSession_empty_id_token_hint(t *testing.T) { provider, err := Tester.CreateRelyingParty(clientID, redirectURI) require.NoError(t, err) authRequestID := createAuthRequest(t, clientID, redirectURI) - sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId()) linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ AuthRequestId: authRequestID, CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ diff --git a/internal/api/oidc/client_integration_test.go b/internal/api/oidc/client_integration_test.go index 513f25a753..bc806ddd75 100644 --- a/internal/api/oidc/client_integration_test.go +++ b/internal/api/oidc/client_integration_test.go @@ -21,7 +21,7 @@ import ( func TestOPStorage_SetUserinfoFromToken(t *testing.T) { clientID := createClient(t) authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeProfile, oidc.ScopeEmail, oidc.ScopeOfflineAccess) - sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId()) linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ AuthRequestId: authRequestID, CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ @@ -67,7 +67,7 @@ func TestOPStorage_SetIntrospectionFromToken(t *testing.T) { scope := []string{oidc.ScopeOpenID, oidc.ScopeProfile, oidc.ScopeEmail, oidc.ScopeOfflineAccess} authRequestID := createAuthRequest(t, app.GetClientId(), redirectURI, scope...) - sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId()) linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ AuthRequestId: authRequestID, CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ diff --git a/internal/api/oidc/oidc_integration_test.go b/internal/api/oidc/oidc_integration_test.go index da34b30d75..88dda2b926 100644 --- a/internal/api/oidc/oidc_integration_test.go +++ b/internal/api/oidc/oidc_integration_test.go @@ -57,7 +57,7 @@ func TestMain(m *testing.M) { func Test_ZITADEL_API_missing_audience_scope(t *testing.T) { clientID := createClient(t) authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID) - sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId()) linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ AuthRequestId: authRequestID, CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ @@ -92,7 +92,6 @@ func Test_ZITADEL_API_missing_authentication(t *testing.T) { Search: &session.CheckUser_UserId{UserId: User.GetUserId()}, }, }, - Domain: Tester.Config.ExternalDomain, }) require.NoError(t, err) linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ @@ -149,7 +148,7 @@ func Test_ZITADEL_API_missing_mfa(t *testing.T) { func Test_ZITADEL_API_success(t *testing.T) { clientID := createClient(t) authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, zitadelAudienceScope) - sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId()) linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ AuthRequestId: authRequestID, CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ @@ -178,7 +177,7 @@ func Test_ZITADEL_API_success(t *testing.T) { func Test_ZITADEL_API_inactive_access_token(t *testing.T) { clientID := createClient(t) authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess, zitadelAudienceScope) - sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId()) linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ AuthRequestId: authRequestID, CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ @@ -220,7 +219,7 @@ func Test_ZITADEL_API_terminated_session(t *testing.T) { provider, err := Tester.CreateRelyingParty(clientID, redirectURI) require.NoError(t, err) authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess, zitadelAudienceScope) - sessionID, sessionToken, startTime, changeTime := Tester.CreatePasskeySession(t, CTXLOGIN, User.GetUserId()) + sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId()) linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ AuthRequestId: authRequestID, CallbackKind: &oidc_pb.CreateCallbackRequest_Session{ diff --git a/internal/authz/repository/eventsourcing/eventstore/token_verifier.go b/internal/authz/repository/eventsourcing/eventstore/token_verifier.go index 5563db37dc..dcdd62017b 100644 --- a/internal/authz/repository/eventsourcing/eventstore/token_verifier.go +++ b/internal/authz/repository/eventsourcing/eventstore/token_verifier.go @@ -190,8 +190,12 @@ func authMethodsFromSession(session *query.Session) []domain.UserAuthMethodType if !session.PasswordFactor.PasswordCheckedAt.IsZero() { types = append(types, domain.UserAuthMethodTypePassword) } - if !session.PasskeyFactor.PasskeyCheckedAt.IsZero() { - types = append(types, domain.UserAuthMethodTypePasswordless) + if !session.WebAuthNFactor.WebAuthNCheckedAt.IsZero() { + if session.WebAuthNFactor.UserVerified { + types = append(types, domain.UserAuthMethodTypePasswordless) + } else { + types = append(types, domain.UserAuthMethodTypeU2F) + } } if !session.IntentFactor.IntentCheckedAt.IsZero() { types = append(types, domain.UserAuthMethodTypeIDP) @@ -201,9 +205,6 @@ func authMethodsFromSession(session *query.Session) []domain.UserAuthMethodType if !session.TOTPFactor.TOTPCheckedAt.IsZero() { types = append(types, domain.UserAuthMethodTypeTOTP) } - if !session.U2FFactor.U2FCheckedAt.IsZero() { - types = append(types, domain.UserAuthMethodTypeU2F) - } */ // TODO: add checks with https://github.com/zitadel/zitadel/issues/6224 /* diff --git a/internal/command/auth_request_test.go b/internal/command/auth_request_test.go index f54043b368..9e6bf8328d 100644 --- a/internal/command/auth_request_test.go +++ b/internal/command/auth_request_test.go @@ -358,7 +358,7 @@ func TestCommands_LinkSessionToAuthRequest(t *testing.T) { ), expectFilter( eventFromEventPusher( - session.NewAddedEvent(mockCtx, &session.NewAggregate("sessionID", "org1").Aggregate, "domain.tld")), + session.NewAddedEvent(mockCtx, &session.NewAggregate("sessionID", "org1").Aggregate)), ), ), tokenVerifier: func(ctx context.Context, sessionToken, sessionID, tokenID string) (err error) { @@ -401,7 +401,7 @@ func TestCommands_LinkSessionToAuthRequest(t *testing.T) { ), expectFilter( eventFromEventPusher( - session.NewAddedEvent(mockCtx, &session.NewAggregate("sessionID", "org1").Aggregate, "domain.tld")), + session.NewAddedEvent(mockCtx, &session.NewAggregate("sessionID", "org1").Aggregate)), ), ), tokenVerifier: func(ctx context.Context, sessionToken, sessionID, tokenID string) (err error) { @@ -444,7 +444,7 @@ func TestCommands_LinkSessionToAuthRequest(t *testing.T) { ), expectFilter( eventFromEventPusher( - session.NewAddedEvent(mockCtx, &session.NewAggregate("sessionID", "org1").Aggregate, "domain.tld"), + session.NewAddedEvent(mockCtx, &session.NewAggregate("sessionID", "org1").Aggregate), ), eventFromEventPusher( session.NewUserCheckedEvent(mockCtx, &session.NewAggregate("sessionID", "org1").Aggregate, @@ -523,7 +523,7 @@ func TestCommands_LinkSessionToAuthRequest(t *testing.T) { ), expectFilter( eventFromEventPusher( - session.NewAddedEvent(mockCtx, &session.NewAggregate("sessionID", "org1").Aggregate, "domain.tld"), + session.NewAddedEvent(mockCtx, &session.NewAggregate("sessionID", "org1").Aggregate), ), eventFromEventPusher( session.NewUserCheckedEvent(mockCtx, &session.NewAggregate("sessionID", "org1").Aggregate, diff --git a/internal/command/oidc_session_test.go b/internal/command/oidc_session_test.go index afbc59af56..aba917fa24 100644 --- a/internal/command/oidc_session_test.go +++ b/internal/command/oidc_session_test.go @@ -164,7 +164,7 @@ func TestCommands_AddOIDCSessionAccessToken(t *testing.T) { ), expectFilter( eventFromEventPusher( - session.NewAddedEvent(context.Background(), &session.NewAggregate("sessionID", "instanceID").Aggregate, "domain.tld"), + session.NewAddedEvent(context.Background(), &session.NewAggregate("sessionID", "instanceID").Aggregate), ), eventFromEventPusher( session.NewUserCheckedEvent(context.Background(), &session.NewAggregate("sessionID", "instanceID").Aggregate, @@ -365,7 +365,7 @@ func TestCommands_AddOIDCSessionRefreshAndAccessToken(t *testing.T) { ), expectFilter( eventFromEventPusher( - session.NewAddedEvent(context.Background(), &session.NewAggregate("sessionID", "instanceID").Aggregate, "domain.tld"), + session.NewAddedEvent(context.Background(), &session.NewAggregate("sessionID", "instanceID").Aggregate), ), eventFromEventPusher( session.NewUserCheckedEvent(context.Background(), &session.NewAggregate("sessionID", "instanceID").Aggregate, diff --git a/internal/command/session.go b/internal/command/session.go index 86e2498222..6bcf9f044d 100644 --- a/internal/command/session.go +++ b/internal/command/session.go @@ -15,7 +15,6 @@ import ( "github.com/zitadel/zitadel/internal/id" "github.com/zitadel/zitadel/internal/repository/session" "github.com/zitadel/zitadel/internal/repository/user" - usr_repo "github.com/zitadel/zitadel/internal/repository/user" "github.com/zitadel/zitadel/internal/telemetry/tracing" ) @@ -138,10 +137,8 @@ func (s *SessionCommands) Exec(ctx context.Context) error { return nil } -func (s *SessionCommands) Start(ctx context.Context, domain string) { - s.eventCommands = append(s.eventCommands, session.NewAddedEvent(ctx, s.sessionWriteModel.aggregate, domain)) - // set the domain so checks can use it - s.sessionWriteModel.Domain = domain +func (s *SessionCommands) Start(ctx context.Context) { + s.eventCommands = append(s.eventCommands, session.NewAddedEvent(ctx, s.sessionWriteModel.aggregate)) } func (s *SessionCommands) UserChecked(ctx context.Context, userID string, checkedAt time.Time) error { @@ -159,15 +156,23 @@ func (s *SessionCommands) IntentChecked(ctx context.Context, checkedAt time.Time s.eventCommands = append(s.eventCommands, session.NewIntentCheckedEvent(ctx, s.sessionWriteModel.aggregate, checkedAt)) } -func (s *SessionCommands) PasskeyChallenged(ctx context.Context, challenge string, allowedCrentialIDs [][]byte, userVerification domain.UserVerificationRequirement) { - s.eventCommands = append(s.eventCommands, session.NewPasskeyChallengedEvent(ctx, s.sessionWriteModel.aggregate, challenge, allowedCrentialIDs, userVerification)) +func (s *SessionCommands) WebAuthNChallenged(ctx context.Context, challenge string, allowedCrentialIDs [][]byte, userVerification domain.UserVerificationRequirement, rpid string) { + s.eventCommands = append(s.eventCommands, session.NewWebAuthNChallengedEvent(ctx, s.sessionWriteModel.aggregate, challenge, allowedCrentialIDs, userVerification, rpid)) } -func (s *SessionCommands) PasskeyChecked(ctx context.Context, checkedAt time.Time, tokenID string, signCount uint32) { +func (s *SessionCommands) WebAuthNChecked(ctx context.Context, checkedAt time.Time, tokenID string, signCount uint32, userVerified bool) { s.eventCommands = append(s.eventCommands, - session.NewPasskeyCheckedEvent(ctx, s.sessionWriteModel.aggregate, checkedAt), - usr_repo.NewHumanPasswordlessSignCountChangedEvent(ctx, s.sessionWriteModel.aggregate, tokenID, signCount), + session.NewWebAuthNCheckedEvent(ctx, s.sessionWriteModel.aggregate, checkedAt, userVerified), ) + if s.sessionWriteModel.WebAuthNChallenge.UserVerification == domain.UserVerificationRequirementRequired { + s.eventCommands = append(s.eventCommands, + user.NewHumanPasswordlessSignCountChangedEvent(ctx, s.sessionWriteModel.aggregate, tokenID, signCount), + ) + } else { + s.eventCommands = append(s.eventCommands, + user.NewHumanU2FSignCountChangedEvent(ctx, s.sessionWriteModel.aggregate, tokenID, signCount), + ) + } } func (s *SessionCommands) SetToken(ctx context.Context, tokenID string) { @@ -226,7 +231,7 @@ func (s *SessionCommands) commands(ctx context.Context) (string, []eventstore.Co return token, s.eventCommands, nil } -func (c *Commands) CreateSession(ctx context.Context, cmds []SessionCommand, sessionDomain string, metadata map[string][]byte) (set *SessionChanged, err error) { +func (c *Commands) CreateSession(ctx context.Context, cmds []SessionCommand, metadata map[string][]byte) (set *SessionChanged, err error) { sessionID, err := c.idGenerator.Next() if err != nil { return nil, err @@ -237,7 +242,7 @@ func (c *Commands) CreateSession(ctx context.Context, cmds []SessionCommand, ses return nil, err } cmd := c.NewSessionCommands(cmds, sessionWriteModel) - cmd.Start(ctx, sessionDomain) + cmd.Start(ctx) return c.updateSession(ctx, cmd, metadata) } diff --git a/internal/command/session_model.go b/internal/command/session_model.go index 764724e0e1..7674da9bcc 100644 --- a/internal/command/session_model.go +++ b/internal/command/session_model.go @@ -4,22 +4,18 @@ import ( "time" "github.com/zitadel/zitadel/internal/domain" - caos_errs "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/repository/session" ) -type PasskeyChallengeModel struct { +type WebAuthNChallengeModel struct { Challenge string AllowedCrentialIDs [][]byte UserVerification domain.UserVerificationRequirement RPID string } -func (p *PasskeyChallengeModel) WebAuthNLogin(human *domain.Human, credentialAssertionData []byte) (*domain.WebAuthNLogin, error) { - if p == nil { - return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-Ioqu5", "Errors.Session.Passkey.NoChallenge") - } +func (p *WebAuthNChallengeModel) WebAuthNLogin(human *domain.Human, credentialAssertionData []byte) *domain.WebAuthNLogin { return &domain.WebAuthNLogin{ ObjectRoot: human.ObjectRoot, CredentialAssertionData: credentialAssertionData, @@ -27,23 +23,23 @@ func (p *PasskeyChallengeModel) WebAuthNLogin(human *domain.Human, credentialAss AllowedCredentialIDs: p.AllowedCrentialIDs, UserVerification: p.UserVerification, RPID: p.RPID, - }, nil + } } type SessionWriteModel struct { eventstore.WriteModel - TokenID string - UserID string - UserCheckedAt time.Time - PasswordCheckedAt time.Time - IntentCheckedAt time.Time - PasskeyCheckedAt time.Time - Metadata map[string][]byte - Domain string - State domain.SessionState + TokenID string + UserID string + UserCheckedAt time.Time + PasswordCheckedAt time.Time + IntentCheckedAt time.Time + WebAuthNCheckedAt time.Time + WebAuthNUserVerified bool + Metadata map[string][]byte + State domain.SessionState - PasskeyChallenge *PasskeyChallengeModel + WebAuthNChallenge *WebAuthNChallengeModel aggregate *eventstore.Aggregate } @@ -70,10 +66,10 @@ func (wm *SessionWriteModel) Reduce() error { wm.reducePasswordChecked(e) case *session.IntentCheckedEvent: wm.reduceIntentChecked(e) - case *session.PasskeyChallengedEvent: - wm.reducePasskeyChallenged(e) - case *session.PasskeyCheckedEvent: - wm.reducePasskeyChecked(e) + case *session.WebAuthNChallengedEvent: + wm.reduceWebAuthNChallenged(e) + case *session.WebAuthNCheckedEvent: + wm.reduceWebAuthNChecked(e) case *session.TokenSetEvent: wm.reduceTokenSet(e) case *session.TerminateEvent: @@ -93,8 +89,8 @@ func (wm *SessionWriteModel) Query() *eventstore.SearchQueryBuilder { session.UserCheckedType, session.PasswordCheckedType, session.IntentCheckedType, - session.PasskeyChallengedType, - session.PasskeyCheckedType, + session.WebAuthNChallengedType, + session.WebAuthNCheckedType, session.TokenSetType, session.MetadataSetType, session.TerminateType, @@ -108,7 +104,6 @@ func (wm *SessionWriteModel) Query() *eventstore.SearchQueryBuilder { } func (wm *SessionWriteModel) reduceAdded(e *session.AddedEvent) { - wm.Domain = e.Domain wm.State = domain.SessionStateActive } @@ -125,18 +120,19 @@ func (wm *SessionWriteModel) reduceIntentChecked(e *session.IntentCheckedEvent) wm.IntentCheckedAt = e.CheckedAt } -func (wm *SessionWriteModel) reducePasskeyChallenged(e *session.PasskeyChallengedEvent) { - wm.PasskeyChallenge = &PasskeyChallengeModel{ +func (wm *SessionWriteModel) reduceWebAuthNChallenged(e *session.WebAuthNChallengedEvent) { + wm.WebAuthNChallenge = &WebAuthNChallengeModel{ Challenge: e.Challenge, AllowedCrentialIDs: e.AllowedCrentialIDs, UserVerification: e.UserVerification, - RPID: wm.Domain, + RPID: e.RPID, } } -func (wm *SessionWriteModel) reducePasskeyChecked(e *session.PasskeyCheckedEvent) { - wm.PasskeyChallenge = nil - wm.PasskeyCheckedAt = e.CheckedAt +func (wm *SessionWriteModel) reduceWebAuthNChecked(e *session.WebAuthNCheckedEvent) { + wm.WebAuthNChallenge = nil + wm.WebAuthNCheckedAt = e.CheckedAt + wm.WebAuthNUserVerified = e.UserVerified } func (wm *SessionWriteModel) reduceTokenSet(e *session.TokenSetEvent) { @@ -152,9 +148,9 @@ func (wm *SessionWriteModel) AuthenticationTime() time.Time { var authTime time.Time for _, check := range []time.Time{ wm.PasswordCheckedAt, - wm.PasskeyCheckedAt, + wm.WebAuthNCheckedAt, wm.IntentCheckedAt, - // TODO: add U2F and OTP check https://github.com/zitadel/zitadel/issues/5477 + // TODO: add OTP check https://github.com/zitadel/zitadel/issues/5477 // TODO: add OTP (sms and email) check https://github.com/zitadel/zitadel/issues/6224 } { if check.After(authTime) { @@ -170,8 +166,12 @@ func (wm *SessionWriteModel) AuthMethodTypes() []domain.UserAuthMethodType { if !wm.PasswordCheckedAt.IsZero() { types = append(types, domain.UserAuthMethodTypePassword) } - if !wm.PasskeyCheckedAt.IsZero() { - types = append(types, domain.UserAuthMethodTypePasswordless) + if !wm.WebAuthNCheckedAt.IsZero() { + if wm.WebAuthNUserVerified { + types = append(types, domain.UserAuthMethodTypePasswordless) + } else { + types = append(types, domain.UserAuthMethodTypeU2F) + } } if !wm.IntentCheckedAt.IsZero() { types = append(types, domain.UserAuthMethodTypeIDP) @@ -181,9 +181,6 @@ func (wm *SessionWriteModel) AuthMethodTypes() []domain.UserAuthMethodType { if !wm.TOTPCheckedAt.IsZero() { types = append(types, domain.UserAuthMethodTypeTOTP) } - if !wm.U2FCheckedAt.IsZero() { - types = append(types, domain.UserAuthMethodTypeU2F) - } */ // TODO: add checks with https://github.com/zitadel/zitadel/issues/6224 /* diff --git a/internal/command/session_model_test.go b/internal/command/session_model_test.go new file mode 100644 index 0000000000..bddeecf594 --- /dev/null +++ b/internal/command/session_model_test.go @@ -0,0 +1,75 @@ +package command + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "github.com/zitadel/zitadel/internal/domain" +) + +func TestSessionWriteModel_AuthMethodTypes(t *testing.T) { + type fields struct { + PasswordCheckedAt time.Time + IntentCheckedAt time.Time + WebAuthNCheckedAt time.Time + WebAuthNUserVerified bool + } + tests := []struct { + name string + fields fields + want []domain.UserAuthMethodType + }{ + { + name: "password", + fields: fields{ + PasswordCheckedAt: testNow, + }, + want: []domain.UserAuthMethodType{ + domain.UserAuthMethodTypePassword, + }, + }, + { + name: "passwordless", + fields: fields{ + WebAuthNCheckedAt: testNow, + WebAuthNUserVerified: true, + }, + want: []domain.UserAuthMethodType{ + domain.UserAuthMethodTypePasswordless, + }, + }, + { + name: "u2f", + fields: fields{ + WebAuthNCheckedAt: testNow, + WebAuthNUserVerified: false, + }, + want: []domain.UserAuthMethodType{ + domain.UserAuthMethodTypeU2F, + }, + }, + { + name: "intent", + fields: fields{ + IntentCheckedAt: testNow, + }, + want: []domain.UserAuthMethodType{ + domain.UserAuthMethodTypeIDP, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + wm := &SessionWriteModel{ + PasswordCheckedAt: tt.fields.PasswordCheckedAt, + IntentCheckedAt: tt.fields.IntentCheckedAt, + WebAuthNCheckedAt: tt.fields.WebAuthNCheckedAt, + WebAuthNUserVerified: tt.fields.WebAuthNUserVerified, + } + got := wm.AuthMethodTypes() + assert.Equal(t, got, tt.want) + }) + } +} diff --git a/internal/command/session_passkey.go b/internal/command/session_passkey.go deleted file mode 100644 index 6ef3fccb2f..0000000000 --- a/internal/command/session_passkey.go +++ /dev/null @@ -1,84 +0,0 @@ -package command - -import ( - "context" - "encoding/json" - - "github.com/zitadel/zitadel/internal/domain" - caos_errs "github.com/zitadel/zitadel/internal/errors" -) - -type humanPasskeys struct { - human *domain.Human - tokens []*domain.WebAuthNToken -} - -func (s *SessionCommands) getHumanPasskeys(ctx context.Context) (*humanPasskeys, error) { - humanWritemodel, err := s.gethumanWriteModel(ctx) - if err != nil { - return nil, err - } - tokenReadModel, err := s.getHumanPasswordlessTokenReadModel(ctx) - if err != nil { - return nil, err - } - return &humanPasskeys{ - human: writeModelToHuman(humanWritemodel), - tokens: readModelToPasswordlessTokens(tokenReadModel), - }, nil -} - -func (s *SessionCommands) getHumanPasswordlessTokenReadModel(ctx context.Context) (*HumanPasswordlessTokensReadModel, error) { - tokenReadModel := NewHumanPasswordlessTokensReadModel(s.sessionWriteModel.UserID, s.sessionWriteModel.ResourceOwner) - err := s.eventstore.FilterToQueryReducer(ctx, tokenReadModel) - if err != nil { - return nil, err - } - return tokenReadModel, nil -} - -func (c *Commands) CreatePasskeyChallenge(userVerification domain.UserVerificationRequirement, dst json.Unmarshaler) SessionCommand { - return func(ctx context.Context, cmd *SessionCommands) error { - humanPasskeys, err := cmd.getHumanPasskeys(ctx) - if err != nil { - return err - } - webAuthNLogin, err := c.webauthnConfig.BeginLogin(ctx, humanPasskeys.human, userVerification, cmd.sessionWriteModel.Domain, humanPasskeys.tokens...) - if err != nil { - return err - } - if err = json.Unmarshal(webAuthNLogin.CredentialAssertionData, dst); err != nil { - return caos_errs.ThrowInternal(err, "COMMAND-Yah6A", "Errors.Internal") - } - - cmd.PasskeyChallenged(ctx, webAuthNLogin.Challenge, webAuthNLogin.AllowedCredentialIDs, webAuthNLogin.UserVerification) - return nil - } -} - -func (c *Commands) CheckPasskey(credentialAssertionData json.Marshaler) SessionCommand { - return func(ctx context.Context, cmd *SessionCommands) error { - credentialAssertionData, err := json.Marshal(credentialAssertionData) - if err != nil { - return caos_errs.ThrowInvalidArgument(err, "COMMAND-ohG2o", "todo") - } - humanPasskeys, err := cmd.getHumanPasskeys(ctx) - if err != nil { - return err - } - webAuthN, err := cmd.sessionWriteModel.PasskeyChallenge.WebAuthNLogin(humanPasskeys.human, credentialAssertionData) - if err != nil { - return err - } - keyID, signCount, err := c.webauthnConfig.FinishLogin(ctx, humanPasskeys.human, webAuthN, credentialAssertionData, humanPasskeys.tokens...) - if err != nil && keyID == nil { - return err - } - _, token := domain.GetTokenByKeyID(humanPasskeys.tokens, keyID) - if token == nil { - return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-Aej7i", "Errors.User.WebAuthN.NotFound") - } - cmd.PasskeyChecked(ctx, cmd.now(), token.WebAuthNTokenID, signCount) - return nil - } -} diff --git a/internal/command/session_passkeys_test.go b/internal/command/session_passkeys_test.go deleted file mode 100644 index a934c83d77..0000000000 --- a/internal/command/session_passkeys_test.go +++ /dev/null @@ -1,131 +0,0 @@ -package command - -import ( - "context" - "io" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "golang.org/x/text/language" - - "github.com/zitadel/zitadel/internal/domain" - caos_errs "github.com/zitadel/zitadel/internal/errors" - "github.com/zitadel/zitadel/internal/eventstore" - "github.com/zitadel/zitadel/internal/eventstore/v1/models" - "github.com/zitadel/zitadel/internal/repository/org" - "github.com/zitadel/zitadel/internal/repository/user" -) - -func TestSessionCommands_getHumanPasskeys(t *testing.T) { - userAggr := &user.NewAggregate("user1", "org1").Aggregate - - type fields struct { - eventstore *eventstore.Eventstore - sessionWriteModel *SessionWriteModel - } - type res struct { - want *humanPasskeys - err error - } - tests := []struct { - name string - fields fields - res res - }{ - { - name: "missing UID", - fields: fields{ - eventstore: &eventstore.Eventstore{}, - sessionWriteModel: &SessionWriteModel{}, - }, - res: res{ - want: nil, - err: caos_errs.ThrowPreconditionFailed(nil, "COMMAND-eeR2e", "Errors.User.UserIDMissing"), - }, - }, - { - name: "passwordless filter error", - fields: fields{ - eventstore: eventstoreExpect(t, - expectFilter( - eventFromEventPusher( - user.NewHumanAddedEvent(context.Background(), - userAggr, - "", "", "", "", "", language.Georgian, - domain.GenderDiverse, "", true, - ), - ), - ), - expectFilterError(io.ErrClosedPipe), - ), - sessionWriteModel: &SessionWriteModel{ - UserID: "user1", - }, - }, - res: res{ - want: nil, - err: io.ErrClosedPipe, - }, - }, - { - name: "ok", - fields: fields{ - eventstore: eventstoreExpect(t, - expectFilter( - eventFromEventPusher( - user.NewHumanAddedEvent(context.Background(), - userAggr, - "", "", "", "", "", language.Georgian, - domain.GenderDiverse, "", true, - ), - ), - ), - expectFilter(eventFromEventPusher( - user.NewHumanWebAuthNAddedEvent(eventstore.NewBaseEventForPush( - context.Background(), &org.NewAggregate("org1").Aggregate, user.HumanPasswordlessTokenAddedType, - ), "111", "challenge", "rpID"), - )), - ), - sessionWriteModel: &SessionWriteModel{ - UserID: "user1", - }, - }, - res: res{ - want: &humanPasskeys{ - human: &domain.Human{ - ObjectRoot: models.ObjectRoot{ - AggregateID: "user1", - ResourceOwner: "org1", - }, - State: domain.UserStateActive, - Profile: &domain.Profile{ - PreferredLanguage: language.Georgian, - Gender: domain.GenderDiverse, - }, - Email: &domain.Email{}, - }, - tokens: []*domain.WebAuthNToken{{ - ObjectRoot: models.ObjectRoot{ - AggregateID: "org1", - }, - WebAuthNTokenID: "111", - State: domain.MFAStateNotReady, - Challenge: "challenge", - RPID: "rpID", - }}, - }, - err: nil, - }, - }, - } - for _, tt := range tests { - s := &SessionCommands{ - eventstore: tt.fields.eventstore, - sessionWriteModel: tt.fields.sessionWriteModel, - } - got, err := s.getHumanPasskeys(context.Background()) - require.ErrorIs(t, err, tt.res.err) - assert.Equal(t, tt.res.want, got) - } -} diff --git a/internal/command/session_test.go b/internal/command/session_test.go index 2eee78cc02..099740c101 100644 --- a/internal/command/session_test.go +++ b/internal/command/session_test.go @@ -146,7 +146,6 @@ func TestCommands_CreateSession(t *testing.T) { type args struct { ctx context.Context checks []SessionCommand - domain string metadata map[string][]byte } type res struct { @@ -205,40 +204,7 @@ func TestCommands_CreateSession(t *testing.T) { expectFilter(), expectPush( eventPusherToEvents( - session.NewAddedEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate, ""), - session.NewTokenSetEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate, - "tokenID", - ), - ), - ), - }, - res{ - want: &SessionChanged{ - ObjectDetails: &domain.ObjectDetails{ResourceOwner: "org1"}, - ID: "sessionID", - NewToken: "token", - }, - }, - }, - { - "empty session with domain", - fields{ - idGenerator: mock.NewIDGeneratorExpectIDs(t, "sessionID"), - tokenCreator: func(sessionID string) (string, string, error) { - return "tokenID", - "token", - nil - }, - }, - args{ - ctx: authz.NewMockContext("", "org1", ""), - domain: "domain.tld", - }, - []expect{ - expectFilter(), - expectPush( - eventPusherToEvents( - session.NewAddedEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate, "domain.tld"), + session.NewAddedEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate), session.NewTokenSetEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate, "tokenID", ), @@ -262,7 +228,7 @@ func TestCommands_CreateSession(t *testing.T) { idGenerator: tt.fields.idGenerator, sessionTokenCreator: tt.fields.tokenCreator, } - got, err := c.CreateSession(tt.args.ctx, tt.args.checks, tt.args.domain, tt.args.metadata) + got, err := c.CreateSession(tt.args.ctx, tt.args.checks, tt.args.metadata) require.ErrorIs(t, err, tt.res.err) assert.Equal(t, tt.res.want, got) }) @@ -311,7 +277,7 @@ func TestCommands_UpdateSession(t *testing.T) { eventstore: eventstoreExpect(t, expectFilter( eventFromEventPusher( - session.NewAddedEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate, "domain.tld")), + session.NewAddedEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate)), eventFromEventPusher( session.NewTokenSetEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate, "tokenID")), @@ -336,7 +302,7 @@ func TestCommands_UpdateSession(t *testing.T) { eventstore: eventstoreExpect(t, expectFilter( eventFromEventPusher( - session.NewAddedEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate, "domain.tld")), + session.NewAddedEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate)), eventFromEventPusher( session.NewTokenSetEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate, "tokenID")), @@ -769,7 +735,7 @@ func TestCommands_TerminateSession(t *testing.T) { eventstore: eventstoreExpect(t, expectFilter( eventFromEventPusher( - session.NewAddedEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate, "domain.tld")), + session.NewAddedEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate)), eventFromEventPusher( session.NewTokenSetEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate, "tokenID")), @@ -794,7 +760,7 @@ func TestCommands_TerminateSession(t *testing.T) { eventstore: eventstoreExpect(t, expectFilter( eventFromEventPusher( - session.NewAddedEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate, "domain.tld")), + session.NewAddedEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate)), eventFromEventPusher( session.NewTokenSetEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate, "tokenID")), @@ -823,7 +789,7 @@ func TestCommands_TerminateSession(t *testing.T) { eventstore: eventstoreExpect(t, expectFilter( eventFromEventPusher( - session.NewAddedEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate, "domain.tld")), + session.NewAddedEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate)), eventFromEventPusher( session.NewTokenSetEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate, "tokenID"), @@ -854,7 +820,7 @@ func TestCommands_TerminateSession(t *testing.T) { eventstore: eventstoreExpect(t, expectFilter( eventFromEventPusher( - session.NewAddedEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate, "domain.tld")), + session.NewAddedEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate)), eventFromEventPusher( session.NewTokenSetEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate, "tokenID"), diff --git a/internal/command/session_webauhtn.go b/internal/command/session_webauhtn.go new file mode 100644 index 0000000000..410481efbd --- /dev/null +++ b/internal/command/session_webauhtn.go @@ -0,0 +1,89 @@ +package command + +import ( + "context" + "encoding/json" + + "github.com/zitadel/zitadel/internal/domain" + caos_errs "github.com/zitadel/zitadel/internal/errors" +) + +type humanWebAuthNTokens struct { + human *domain.Human + tokens []*domain.WebAuthNToken +} + +func (s *SessionCommands) getHumanWebAuthNTokens(ctx context.Context, userVerification domain.UserVerificationRequirement) (*humanWebAuthNTokens, error) { + humanWritemodel, err := s.gethumanWriteModel(ctx) + if err != nil { + return nil, err + } + tokenReadModel, err := s.getHumanWebAuthNTokenReadModel(ctx, userVerification) + if err != nil { + return nil, err + } + return &humanWebAuthNTokens{ + human: writeModelToHuman(humanWritemodel), + tokens: readModelToWebAuthNTokens(tokenReadModel), + }, nil +} + +func (s *SessionCommands) getHumanWebAuthNTokenReadModel(ctx context.Context, userVerification domain.UserVerificationRequirement) (readModel HumanWebAuthNTokensReadModel, err error) { + readModel = NewHumanU2FTokensReadModel(s.sessionWriteModel.UserID, s.sessionWriteModel.ResourceOwner) + if userVerification == domain.UserVerificationRequirementRequired { + readModel = NewHumanPasswordlessTokensReadModel(s.sessionWriteModel.UserID, s.sessionWriteModel.ResourceOwner) + } + err = s.eventstore.FilterToQueryReducer(ctx, readModel) + if err != nil { + return nil, err + } + return readModel, nil +} + +func (c *Commands) CreateWebAuthNChallenge(userVerification domain.UserVerificationRequirement, rpid string, dst json.Unmarshaler) SessionCommand { + return func(ctx context.Context, cmd *SessionCommands) error { + humanPasskeys, err := cmd.getHumanWebAuthNTokens(ctx, userVerification) + if err != nil { + return err + } + webAuthNLogin, err := c.webauthnConfig.BeginLogin(ctx, humanPasskeys.human, userVerification, rpid, humanPasskeys.tokens...) + if err != nil { + return err + } + if err = json.Unmarshal(webAuthNLogin.CredentialAssertionData, dst); err != nil { + return caos_errs.ThrowInternal(err, "COMMAND-Yah6A", "Errors.Internal") + } + + cmd.WebAuthNChallenged(ctx, webAuthNLogin.Challenge, webAuthNLogin.AllowedCredentialIDs, webAuthNLogin.UserVerification, rpid) + return nil + } +} + +func (c *Commands) CheckWebAuthN(credentialAssertionData json.Marshaler) SessionCommand { + return func(ctx context.Context, cmd *SessionCommands) error { + credentialAssertionData, err := json.Marshal(credentialAssertionData) + if err != nil { + return caos_errs.ThrowInternal(err, "COMMAND-ohG2o", "Errors.Internal") + } + challenge := cmd.sessionWriteModel.WebAuthNChallenge + if challenge == nil { + return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-Ioqu5", "Errors.Session.WebAuthN.NoChallenge") + } + webAuthNTokens, err := cmd.getHumanWebAuthNTokens(ctx, challenge.UserVerification) + if err != nil { + return err + } + webAuthN := challenge.WebAuthNLogin(webAuthNTokens.human, credentialAssertionData) + + credential, err := c.webauthnConfig.FinishLogin(ctx, webAuthNTokens.human, webAuthN, credentialAssertionData, webAuthNTokens.tokens...) + if err != nil && (credential == nil || credential.ID == nil) { + return err + } + _, token := domain.GetTokenByKeyID(webAuthNTokens.tokens, credential.ID) + if token == nil { + return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-Aej7i", "Errors.User.WebAuthN.NotFound") + } + cmd.WebAuthNChecked(ctx, cmd.now(), token.WebAuthNTokenID, credential.Authenticator.SignCount, credential.Flags.UserVerified) + return nil + } +} diff --git a/internal/command/session_webauthn_test.go b/internal/command/session_webauthn_test.go new file mode 100644 index 0000000000..3352286eb2 --- /dev/null +++ b/internal/command/session_webauthn_test.go @@ -0,0 +1,250 @@ +package command + +import ( + "context" + "io" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "golang.org/x/text/language" + + "github.com/zitadel/zitadel/internal/domain" + caos_errs "github.com/zitadel/zitadel/internal/errors" + "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/eventstore/v1/models" + "github.com/zitadel/zitadel/internal/repository/org" + "github.com/zitadel/zitadel/internal/repository/user" +) + +func TestSessionCommands_getHumanWebAuthNTokens(t *testing.T) { + userAggr := &user.NewAggregate("user1", "org1").Aggregate + + type fields struct { + eventstore *eventstore.Eventstore + sessionWriteModel *SessionWriteModel + } + type args struct { + userVerification domain.UserVerificationRequirement + } + type res struct { + want *humanWebAuthNTokens + err error + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + name: "missing UID", + fields: fields{ + eventstore: &eventstore.Eventstore{}, + sessionWriteModel: &SessionWriteModel{}, + }, + args: args{ + domain.UserVerificationRequirementDiscouraged, + }, + res: res{ + want: nil, + err: caos_errs.ThrowPreconditionFailed(nil, "COMMAND-eeR2e", "Errors.User.UserIDMissing"), + }, + }, + { + name: "passwordless filter error", + fields: fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + user.NewHumanAddedEvent(context.Background(), + userAggr, + "", "", "", "", "", language.Georgian, + domain.GenderDiverse, "", true, + ), + ), + ), + expectFilterError(io.ErrClosedPipe), + ), + sessionWriteModel: &SessionWriteModel{ + UserID: "user1", + }, + }, + args: args{ + domain.UserVerificationRequirementDiscouraged, + }, + res: res{ + want: nil, + err: io.ErrClosedPipe, + }, + }, + { + name: "ok, discouraged, u2f", + fields: fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + user.NewHumanAddedEvent(context.Background(), + userAggr, + "", "", "", "", "", language.Georgian, + domain.GenderDiverse, "", true, + ), + ), + ), + expectFilter(eventFromEventPusher( + user.NewHumanWebAuthNAddedEvent(eventstore.NewBaseEventForPush( + context.Background(), &org.NewAggregate("org1").Aggregate, user.HumanU2FTokenAddedType, + ), "111", "challenge", "rpID"), + )), + ), + sessionWriteModel: &SessionWriteModel{ + UserID: "user1", + }, + }, + args: args{ + domain.UserVerificationRequirementDiscouraged, + }, + res: res{ + want: &humanWebAuthNTokens{ + human: &domain.Human{ + ObjectRoot: models.ObjectRoot{ + AggregateID: "user1", + ResourceOwner: "org1", + }, + State: domain.UserStateActive, + Profile: &domain.Profile{ + PreferredLanguage: language.Georgian, + Gender: domain.GenderDiverse, + }, + Email: &domain.Email{}, + }, + tokens: []*domain.WebAuthNToken{{ + ObjectRoot: models.ObjectRoot{ + AggregateID: "org1", + }, + WebAuthNTokenID: "111", + State: domain.MFAStateNotReady, + Challenge: "challenge", + RPID: "rpID", + }}, + }, + err: nil, + }, + }, + { + name: "ok, preferred, u2f", + fields: fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + user.NewHumanAddedEvent(context.Background(), + userAggr, + "", "", "", "", "", language.Georgian, + domain.GenderDiverse, "", true, + ), + ), + ), + expectFilter(eventFromEventPusher( + user.NewHumanWebAuthNAddedEvent(eventstore.NewBaseEventForPush( + context.Background(), &org.NewAggregate("org1").Aggregate, user.HumanU2FTokenAddedType, + ), "111", "challenge", "rpID"), + )), + ), + sessionWriteModel: &SessionWriteModel{ + UserID: "user1", + }, + }, + args: args{ + domain.UserVerificationRequirementPreferred, + }, + res: res{ + want: &humanWebAuthNTokens{ + human: &domain.Human{ + ObjectRoot: models.ObjectRoot{ + AggregateID: "user1", + ResourceOwner: "org1", + }, + State: domain.UserStateActive, + Profile: &domain.Profile{ + PreferredLanguage: language.Georgian, + Gender: domain.GenderDiverse, + }, + Email: &domain.Email{}, + }, + tokens: []*domain.WebAuthNToken{{ + ObjectRoot: models.ObjectRoot{ + AggregateID: "org1", + }, + WebAuthNTokenID: "111", + State: domain.MFAStateNotReady, + Challenge: "challenge", + RPID: "rpID", + }}, + }, + err: nil, + }, + }, + { + name: "ok, required, u2f", + fields: fields{ + eventstore: eventstoreExpect(t, + expectFilter( + eventFromEventPusher( + user.NewHumanAddedEvent(context.Background(), + userAggr, + "", "", "", "", "", language.Georgian, + domain.GenderDiverse, "", true, + ), + ), + ), + expectFilter(eventFromEventPusher( + user.NewHumanWebAuthNAddedEvent(eventstore.NewBaseEventForPush( + context.Background(), &org.NewAggregate("org1").Aggregate, user.HumanPasswordlessTokenAddedType, + ), "111", "challenge", "rpID"), + )), + ), + sessionWriteModel: &SessionWriteModel{ + UserID: "user1", + }, + }, + args: args{ + domain.UserVerificationRequirementRequired, + }, + res: res{ + want: &humanWebAuthNTokens{ + human: &domain.Human{ + ObjectRoot: models.ObjectRoot{ + AggregateID: "user1", + ResourceOwner: "org1", + }, + State: domain.UserStateActive, + Profile: &domain.Profile{ + PreferredLanguage: language.Georgian, + Gender: domain.GenderDiverse, + }, + Email: &domain.Email{}, + }, + tokens: []*domain.WebAuthNToken{{ + ObjectRoot: models.ObjectRoot{ + AggregateID: "org1", + }, + WebAuthNTokenID: "111", + State: domain.MFAStateNotReady, + Challenge: "challenge", + RPID: "rpID", + }}, + }, + err: nil, + }, + }, + } + for _, tt := range tests { + s := &SessionCommands{ + eventstore: tt.fields.eventstore, + sessionWriteModel: tt.fields.sessionWriteModel, + } + got, err := s.getHumanWebAuthNTokens(context.Background(), tt.args.userVerification) + require.ErrorIs(t, err, tt.res.err) + assert.Equal(t, tt.res.want, got) + } +} diff --git a/internal/command/user_converter.go b/internal/command/user_converter.go index 62cee0bedd..7febe68530 100644 --- a/internal/command/user_converter.go +++ b/internal/command/user_converter.go @@ -112,17 +112,9 @@ func personalTokenWriteModelToToken(wm *PersonalAccessTokenWriteModel, algorithm }, base64.RawURLEncoding.EncodeToString(encrypted), nil } -func readModelToU2FTokens(wm *HumanU2FTokensReadModel) []*domain.WebAuthNToken { - tokens := make([]*domain.WebAuthNToken, len(wm.WebAuthNTokens)) - for i, token := range wm.WebAuthNTokens { - tokens[i] = writeModelToWebAuthN(token) - } - return tokens -} - -func readModelToPasswordlessTokens(wm *HumanPasswordlessTokensReadModel) []*domain.WebAuthNToken { - tokens := make([]*domain.WebAuthNToken, len(wm.WebAuthNTokens)) - for i, token := range wm.WebAuthNTokens { +func readModelToWebAuthNTokens(readModel HumanWebAuthNTokensReadModel) []*domain.WebAuthNToken { + tokens := make([]*domain.WebAuthNToken, len(readModel.GetWebAuthNTokens())) + for i, token := range readModel.GetWebAuthNTokens() { tokens[i] = writeModelToWebAuthN(token) } return tokens diff --git a/internal/command/user_human_webauthn.go b/internal/command/user_human_webauthn.go index c5e03bf3d4..70c012884b 100644 --- a/internal/command/user_human_webauthn.go +++ b/internal/command/user_human_webauthn.go @@ -24,7 +24,7 @@ func (c *Commands) getHumanU2FTokens(ctx context.Context, userID, resourceowner if tokenReadModel.UserState == domain.UserStateDeleted { return nil, caos_errs.ThrowNotFound(nil, "COMMAND-4M0ds", "Errors.User.NotFound") } - return readModelToU2FTokens(tokenReadModel), nil + return readModelToWebAuthNTokens(tokenReadModel), nil } func (c *Commands) getHumanPasswordlessTokens(ctx context.Context, userID, resourceOwner string) ([]*domain.WebAuthNToken, error) { @@ -36,7 +36,7 @@ func (c *Commands) getHumanPasswordlessTokens(ctx context.Context, userID, resou if tokenReadModel.UserState == domain.UserStateDeleted { return nil, caos_errs.ThrowNotFound(nil, "COMMAND-Mv9sd", "Errors.User.NotFound") } - return readModelToPasswordlessTokens(tokenReadModel), nil + return readModelToWebAuthNTokens(tokenReadModel), nil } func (c *Commands) getHumanU2FLogin(ctx context.Context, userID, authReqID, resourceowner string) (*domain.WebAuthNLogin, error) { @@ -454,12 +454,12 @@ func (c *Commands) finishWebAuthNLogin(ctx context.Context, userID, resourceOwne if err != nil { return nil, nil, 0, err } - keyID, signCount, err := c.webauthnConfig.FinishLogin(ctx, human, webAuthN, credentialData, tokens...) - if err != nil && keyID == nil { + credential, err := c.webauthnConfig.FinishLogin(ctx, human, webAuthN, credentialData, tokens...) + if err != nil && (credential == nil || credential.ID == nil) { return nil, nil, 0, err } - _, token := domain.GetTokenByKeyID(tokens, keyID) + _, token := domain.GetTokenByKeyID(tokens, credential.ID) if token == nil { return nil, nil, 0, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-3b7zs", "Errors.User.WebAuthN.NotFound") } @@ -470,7 +470,7 @@ func (c *Commands) finishWebAuthNLogin(ctx context.Context, userID, resourceOwne } userAgg := UserAggregateFromWriteModel(&writeModel.WriteModel) - return userAgg, token, signCount, nil + return userAgg, token, credential.Authenticator.SignCount, nil } func (c *Commands) HumanRemoveU2F(ctx context.Context, userID, webAuthNID, resourceOwner string) (*domain.ObjectDetails, error) { diff --git a/internal/command/user_human_webauthn_model.go b/internal/command/user_human_webauthn_model.go index daf9e880d4..aab9e1e57f 100644 --- a/internal/command/user_human_webauthn_model.go +++ b/internal/command/user_human_webauthn_model.go @@ -146,6 +146,12 @@ func (wm *HumanWebAuthNWriteModel) Query() *eventstore.SearchQueryBuilder { Builder() } +type HumanWebAuthNTokensReadModel interface { + eventstore.QueryReducer + GetWebAuthNTokens() []*HumanWebAuthNWriteModel + WebAuthNTokenByID(id string) (int, *HumanWebAuthNWriteModel) +} + type HumanU2FTokensReadModel struct { eventstore.WriteModel @@ -220,6 +226,10 @@ func (rm *HumanU2FTokensReadModel) Query() *eventstore.SearchQueryBuilder { } +func (wm *HumanU2FTokensReadModel) GetWebAuthNTokens() []*HumanWebAuthNWriteModel { + return wm.WebAuthNTokens +} + func (wm *HumanU2FTokensReadModel) WebAuthNTokenByID(id string) (idx int, token *HumanWebAuthNWriteModel) { for idx, token = range wm.WebAuthNTokens { if token.WebauthNTokenID == id { @@ -303,6 +313,10 @@ func (rm *HumanPasswordlessTokensReadModel) Query() *eventstore.SearchQueryBuild } +func (wm *HumanPasswordlessTokensReadModel) GetWebAuthNTokens() []*HumanWebAuthNWriteModel { + return wm.WebAuthNTokens +} + func (wm *HumanPasswordlessTokensReadModel) WebAuthNTokenByID(id string) (idx int, token *HumanWebAuthNWriteModel) { for idx, token = range wm.WebAuthNTokens { if token.WebauthNTokenID == id { diff --git a/internal/integration/client.go b/internal/integration/client.go index dd7ce06d6a..bd3557bdb9 100644 --- a/internal/integration/client.go +++ b/internal/integration/client.go @@ -146,6 +146,24 @@ func (s *Tester) RegisterUserPasskey(ctx context.Context, userID string) { logging.OnError(err).Fatal("create user passkey") } +func (s *Tester) RegisterUserU2F(ctx context.Context, userID string) { + pkr, err := s.Client.UserV2.RegisterU2F(ctx, &user.RegisterU2FRequest{ + UserId: userID, + Domain: s.Config.ExternalDomain, + }) + logging.OnError(err).Fatal("create user u2f") + attestationResponse, err := s.WebAuthN.CreateAttestationResponse(pkr.GetPublicKeyCredentialCreationOptions()) + logging.OnError(err).Fatal("create user u2f") + + _, err = s.Client.UserV2.VerifyU2FRegistration(ctx, &user.VerifyU2FRegistrationRequest{ + UserId: userID, + U2FId: pkr.GetU2FId(), + PublicKeyCredential: attestationResponse, + TokenName: "nice name", + }) + logging.OnError(err).Fatal("create user u2f") +} + func (s *Tester) SetUserPassword(ctx context.Context, userID, password string) { _, err := s.Client.UserV2.SetPassword(ctx, &user.SetPasswordRequest{ UserId: userID, @@ -209,28 +227,30 @@ func (s *Tester) CreateSuccessfulIntent(t *testing.T, idpID, userID, idpUserID s return intentID, token, writeModel.ChangeDate, writeModel.ProcessedSequence } -func (s *Tester) CreatePasskeySession(t *testing.T, ctx context.Context, userID string) (id, token string, start, change time.Time) { +func (s *Tester) CreateVerfiedWebAuthNSession(t *testing.T, ctx context.Context, userID string) (id, token string, start, change time.Time) { createResp, err := s.Client.SessionV2.CreateSession(ctx, &session.CreateSessionRequest{ Checks: &session.Checks{ User: &session.CheckUser{ Search: &session.CheckUser_UserId{UserId: userID}, }, }, - Challenges: []session.ChallengeKind{ - session.ChallengeKind_CHALLENGE_KIND_PASSKEY, + Challenges: &session.RequestChallenges{ + WebAuthN: &session.RequestChallenges_WebAuthN{ + Domain: s.Config.ExternalDomain, + UserVerificationRequirement: session.UserVerificationRequirement_USER_VERIFICATION_REQUIREMENT_REQUIRED, + }, }, - Domain: s.Config.ExternalDomain, }) require.NoError(t, err) - assertion, err := s.WebAuthN.CreateAssertionResponse(createResp.GetChallenges().GetPasskey().GetPublicKeyCredentialRequestOptions()) + assertion, err := s.WebAuthN.CreateAssertionResponse(createResp.GetChallenges().GetWebAuthN().GetPublicKeyCredentialRequestOptions(), true) require.NoError(t, err) updateResp, err := s.Client.SessionV2.SetSession(ctx, &session.SetSessionRequest{ SessionId: createResp.GetSessionId(), SessionToken: createResp.GetSessionToken(), Checks: &session.Checks{ - Passkey: &session.CheckPasskey{ + WebAuthN: &session.CheckWebAuthN{ CredentialAssertionData: assertion, }, }, @@ -250,7 +270,6 @@ func (s *Tester) CreatePasswordSession(t *testing.T, ctx context.Context, userID Password: password, }, }, - Domain: s.Config.ExternalDomain, }) require.NoError(t, err) return createResp.GetSessionId(), createResp.GetSessionToken(), diff --git a/internal/query/projection/session.go b/internal/query/projection/session.go index 2fceb22439..afa48b1c01 100644 --- a/internal/query/projection/session.go +++ b/internal/query/projection/session.go @@ -14,24 +14,24 @@ import ( ) const ( - SessionsProjectionTable = "projections.sessions3" + SessionsProjectionTable = "projections.sessions4" - SessionColumnID = "id" - SessionColumnCreationDate = "creation_date" - SessionColumnChangeDate = "change_date" - SessionColumnSequence = "sequence" - SessionColumnState = "state" - SessionColumnResourceOwner = "resource_owner" - SessionColumnDomain = "domain" - SessionColumnInstanceID = "instance_id" - SessionColumnCreator = "creator" - SessionColumnUserID = "user_id" - SessionColumnUserCheckedAt = "user_checked_at" - SessionColumnPasswordCheckedAt = "password_checked_at" - SessionColumnIntentCheckedAt = "intent_checked_at" - SessionColumnPasskeyCheckedAt = "passkey_checked_at" - SessionColumnMetadata = "metadata" - SessionColumnTokenID = "token_id" + SessionColumnID = "id" + SessionColumnCreationDate = "creation_date" + SessionColumnChangeDate = "change_date" + SessionColumnSequence = "sequence" + SessionColumnState = "state" + SessionColumnResourceOwner = "resource_owner" + SessionColumnInstanceID = "instance_id" + SessionColumnCreator = "creator" + SessionColumnUserID = "user_id" + SessionColumnUserCheckedAt = "user_checked_at" + SessionColumnPasswordCheckedAt = "password_checked_at" + SessionColumnIntentCheckedAt = "intent_checked_at" + SessionColumnWebAuthNCheckedAt = "webauthn_checked_at" + SessionColumnWebAuthNUserVerified = "webauthn_user_verified" + SessionColumnMetadata = "metadata" + SessionColumnTokenID = "token_id" ) type sessionProjection struct { @@ -50,14 +50,14 @@ func newSessionProjection(ctx context.Context, config crdb.StatementHandlerConfi crdb.NewColumn(SessionColumnSequence, crdb.ColumnTypeInt64), crdb.NewColumn(SessionColumnState, crdb.ColumnTypeEnum), crdb.NewColumn(SessionColumnResourceOwner, crdb.ColumnTypeText), - crdb.NewColumn(SessionColumnDomain, crdb.ColumnTypeText), crdb.NewColumn(SessionColumnInstanceID, crdb.ColumnTypeText), crdb.NewColumn(SessionColumnCreator, crdb.ColumnTypeText), crdb.NewColumn(SessionColumnUserID, crdb.ColumnTypeText, crdb.Nullable()), crdb.NewColumn(SessionColumnUserCheckedAt, crdb.ColumnTypeTimestamp, crdb.Nullable()), crdb.NewColumn(SessionColumnPasswordCheckedAt, crdb.ColumnTypeTimestamp, crdb.Nullable()), crdb.NewColumn(SessionColumnIntentCheckedAt, crdb.ColumnTypeTimestamp, crdb.Nullable()), - crdb.NewColumn(SessionColumnPasskeyCheckedAt, crdb.ColumnTypeTimestamp, crdb.Nullable()), + crdb.NewColumn(SessionColumnWebAuthNCheckedAt, crdb.ColumnTypeTimestamp, crdb.Nullable()), + crdb.NewColumn(SessionColumnWebAuthNUserVerified, crdb.ColumnTypeBool, crdb.Nullable()), crdb.NewColumn(SessionColumnMetadata, crdb.ColumnTypeJSONB, crdb.Nullable()), crdb.NewColumn(SessionColumnTokenID, crdb.ColumnTypeText, crdb.Nullable()), }, @@ -90,8 +90,8 @@ func (p *sessionProjection) reducers() []handler.AggregateReducer { Reduce: p.reduceIntentChecked, }, { - Event: session.PasskeyCheckedType, - Reduce: p.reducePasskeyChecked, + Event: session.WebAuthNCheckedType, + Reduce: p.reduceWebAuthNChecked, }, { Event: session.TokenSetType, @@ -142,7 +142,6 @@ func (p *sessionProjection) reduceSessionAdded(event eventstore.Event) (*handler handler.NewCol(SessionColumnCreationDate, e.CreationDate()), handler.NewCol(SessionColumnChangeDate, e.CreationDate()), handler.NewCol(SessionColumnResourceOwner, e.Aggregate().ResourceOwner), - handler.NewCol(SessionColumnDomain, e.Domain), handler.NewCol(SessionColumnState, domain.SessionStateActive), handler.NewCol(SessionColumnSequence, e.Sequence()), handler.NewCol(SessionColumnCreator, e.User), @@ -210,18 +209,18 @@ func (p *sessionProjection) reduceIntentChecked(event eventstore.Event) (*handle ), nil } -func (p *sessionProjection) reducePasskeyChecked(event eventstore.Event) (*handler.Statement, error) { - e, ok := event.(*session.PasskeyCheckedEvent) +func (p *sessionProjection) reduceWebAuthNChecked(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*session.WebAuthNCheckedEvent) if !ok { - return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-WieM4", "reduce.wrong.event.type %s", session.PasskeyCheckedType) + return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-WieM4", "reduce.wrong.event.type %s", session.WebAuthNCheckedType) } - return crdb.NewUpdateStatement( e, []handler.Column{ handler.NewCol(SessionColumnChangeDate, e.CreationDate()), handler.NewCol(SessionColumnSequence, e.Sequence()), - handler.NewCol(SessionColumnPasskeyCheckedAt, e.CheckedAt), + handler.NewCol(SessionColumnWebAuthNCheckedAt, e.CheckedAt), + handler.NewCol(SessionColumnWebAuthNUserVerified, e.UserVerified), }, []handler.Condition{ handler.NewCond(SessionColumnID, e.Aggregate().ID), diff --git a/internal/query/projection/session_test.go b/internal/query/projection/session_test.go index ae19e247ec..5feb0d452c 100644 --- a/internal/query/projection/session_test.go +++ b/internal/query/projection/session_test.go @@ -43,14 +43,13 @@ func TestSessionProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.sessions3 (id, instance_id, creation_date, change_date, resource_owner, domain, state, sequence, creator) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", + expectedStmt: "INSERT INTO projections.sessions4 (id, instance_id, creation_date, change_date, resource_owner, state, sequence, creator) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", expectedArgs: []interface{}{ "agg-id", "instance-id", anyArg{}, anyArg{}, "ro-id", - "domain", domain.SessionStateActive, uint64(15), "editor-user", @@ -80,7 +79,7 @@ func TestSessionProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.sessions3 SET (change_date, sequence, user_id, user_checked_at) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.sessions4 SET (change_date, sequence, user_id, user_checked_at) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, anyArg{}, @@ -113,7 +112,7 @@ func TestSessionProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.sessions3 SET (change_date, sequence, password_checked_at) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.sessions4 SET (change_date, sequence, password_checked_at) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, anyArg{}, @@ -126,6 +125,40 @@ func TestSessionProjection_reduces(t *testing.T) { }, }, }, + { + name: "instance reduceWebAuthNChecked", + args: args{ + event: getEvent(testEvent( + session.WebAuthNCheckedType, + session.AggregateType, + []byte(`{ + "checkedAt": "2023-05-04T00:00:00Z", + "userVerified": true + }`), + ), eventstore.GenericEventMapper[session.WebAuthNCheckedEvent]), + }, + reduce: (&sessionProjection{}).reduceWebAuthNChecked, + want: wantReduce{ + aggregateType: eventstore.AggregateType("session"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.sessions4 SET (change_date, sequence, webauthn_checked_at, webauthn_user_verified) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)", + expectedArgs: []interface{}{ + anyArg{}, + anyArg{}, + time.Date(2023, time.May, 4, 0, 0, 0, 0, time.UTC), + true, + "agg-id", + "instance-id", + }, + }, + }, + }, + }, + }, { name: "instance reduceIntentChecked", args: args{ @@ -145,7 +178,7 @@ func TestSessionProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.sessions3 SET (change_date, sequence, intent_checked_at) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.sessions4 SET (change_date, sequence, intent_checked_at) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, anyArg{}, @@ -177,7 +210,7 @@ func TestSessionProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.sessions3 SET (change_date, sequence, token_id) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.sessions4 SET (change_date, sequence, token_id) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, anyArg{}, @@ -211,7 +244,7 @@ func TestSessionProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.sessions3 SET (change_date, sequence, metadata) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.sessions4 SET (change_date, sequence, metadata) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, anyArg{}, @@ -243,7 +276,7 @@ func TestSessionProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.sessions3 WHERE (id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.sessions4 WHERE (id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -270,7 +303,7 @@ func TestSessionProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.sessions3 WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.sessions4 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, @@ -301,7 +334,7 @@ func TestSessionProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.sessions3 SET password_checked_at = $1 WHERE (user_id = $2) AND (password_checked_at < $3)", + expectedStmt: "UPDATE projections.sessions4 SET password_checked_at = $1 WHERE (user_id = $2) AND (password_checked_at < $3)", expectedArgs: []interface{}{ nil, "agg-id", diff --git a/internal/query/session.go b/internal/query/session.go index bcf62ba5d2..5746fe0592 100644 --- a/internal/query/session.go +++ b/internal/query/session.go @@ -29,12 +29,11 @@ type Session struct { Sequence uint64 State domain.SessionState ResourceOwner string - Domain string Creator string UserFactor SessionUserFactor PasswordFactor SessionPasswordFactor IntentFactor SessionIntentFactor - PasskeyFactor SessionPasskeyFactor + WebAuthNFactor SessionWebAuthNFactor Metadata map[string][]byte } @@ -54,8 +53,9 @@ type SessionIntentFactor struct { IntentCheckedAt time.Time } -type SessionPasskeyFactor struct { - PasskeyCheckedAt time.Time +type SessionWebAuthNFactor struct { + WebAuthNCheckedAt time.Time + UserVerified bool } type SessionsSearchQueries struct { @@ -100,10 +100,6 @@ var ( name: projection.SessionColumnResourceOwner, table: sessionsTable, } - SessionColumnDomain = Column{ - name: projection.SessionColumnDomain, - table: sessionsTable, - } SessionColumnInstanceID = Column{ name: projection.SessionColumnInstanceID, table: sessionsTable, @@ -128,8 +124,12 @@ var ( name: projection.SessionColumnIntentCheckedAt, table: sessionsTable, } - SessionColumnPasskeyCheckedAt = Column{ - name: projection.SessionColumnPasskeyCheckedAt, + SessionColumnWebAuthNCheckedAt = Column{ + name: projection.SessionColumnWebAuthNCheckedAt, + table: sessionsTable, + } + SessionColumnWebAuthNUserVerified = Column{ + name: projection.SessionColumnWebAuthNUserVerified, table: sessionsTable, } SessionColumnMetadata = Column{ @@ -221,7 +221,6 @@ func prepareSessionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil SessionColumnState.identifier(), SessionColumnResourceOwner.identifier(), SessionColumnCreator.identifier(), - SessionColumnDomain.identifier(), SessionColumnUserID.identifier(), SessionColumnUserCheckedAt.identifier(), LoginNameNameCol.identifier(), @@ -229,7 +228,8 @@ func prepareSessionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil UserResourceOwnerCol.identifier(), SessionColumnPasswordCheckedAt.identifier(), SessionColumnIntentCheckedAt.identifier(), - SessionColumnPasskeyCheckedAt.identifier(), + SessionColumnWebAuthNCheckedAt.identifier(), + SessionColumnWebAuthNUserVerified.identifier(), SessionColumnMetadata.identifier(), SessionColumnToken.identifier(), ).From(sessionsTable.identifier()). @@ -240,17 +240,17 @@ func prepareSessionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil session := new(Session) var ( - userID sql.NullString - userCheckedAt sql.NullTime - loginName sql.NullString - displayName sql.NullString - userResourceOwner sql.NullString - passwordCheckedAt sql.NullTime - intentCheckedAt sql.NullTime - passkeyCheckedAt sql.NullTime - metadata database.Map[[]byte] - token sql.NullString - sessionDomain sql.NullString + userID sql.NullString + userCheckedAt sql.NullTime + loginName sql.NullString + displayName sql.NullString + userResourceOwner sql.NullString + passwordCheckedAt sql.NullTime + intentCheckedAt sql.NullTime + webAuthNCheckedAt sql.NullTime + webAuthNUserPresent sql.NullBool + metadata database.Map[[]byte] + token sql.NullString ) err := row.Scan( @@ -261,7 +261,6 @@ func prepareSessionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil &session.State, &session.ResourceOwner, &session.Creator, - &sessionDomain, &userID, &userCheckedAt, &loginName, @@ -269,7 +268,8 @@ func prepareSessionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil &userResourceOwner, &passwordCheckedAt, &intentCheckedAt, - &passkeyCheckedAt, + &webAuthNCheckedAt, + &webAuthNUserPresent, &metadata, &token, ) @@ -281,7 +281,6 @@ func prepareSessionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil return nil, "", errors.ThrowInternal(err, "QUERY-SAder", "Errors.Internal") } - session.Domain = sessionDomain.String session.UserFactor.UserID = userID.String session.UserFactor.UserCheckedAt = userCheckedAt.Time session.UserFactor.LoginName = loginName.String @@ -289,7 +288,8 @@ func prepareSessionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil session.UserFactor.ResourceOwner = userResourceOwner.String session.PasswordFactor.PasswordCheckedAt = passwordCheckedAt.Time session.IntentFactor.IntentCheckedAt = intentCheckedAt.Time - session.PasskeyFactor.PasskeyCheckedAt = passkeyCheckedAt.Time + session.WebAuthNFactor.WebAuthNCheckedAt = webAuthNCheckedAt.Time + session.WebAuthNFactor.UserVerified = webAuthNUserPresent.Bool session.Metadata = metadata return session, token.String, nil @@ -305,7 +305,6 @@ func prepareSessionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBui SessionColumnState.identifier(), SessionColumnResourceOwner.identifier(), SessionColumnCreator.identifier(), - SessionColumnDomain.identifier(), SessionColumnUserID.identifier(), SessionColumnUserCheckedAt.identifier(), LoginNameNameCol.identifier(), @@ -313,7 +312,8 @@ func prepareSessionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBui UserResourceOwnerCol.identifier(), SessionColumnPasswordCheckedAt.identifier(), SessionColumnIntentCheckedAt.identifier(), - SessionColumnPasskeyCheckedAt.identifier(), + SessionColumnWebAuthNCheckedAt.identifier(), + SessionColumnWebAuthNUserVerified.identifier(), SessionColumnMetadata.identifier(), countColumn.identifier(), ).From(sessionsTable.identifier()). @@ -327,16 +327,16 @@ func prepareSessionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBui session := new(Session) var ( - userID sql.NullString - userCheckedAt sql.NullTime - loginName sql.NullString - displayName sql.NullString - userResourceOwner sql.NullString - passwordCheckedAt sql.NullTime - intentCheckedAt sql.NullTime - passkeyCheckedAt sql.NullTime - metadata database.Map[[]byte] - sessionDomain sql.NullString + userID sql.NullString + userCheckedAt sql.NullTime + loginName sql.NullString + displayName sql.NullString + userResourceOwner sql.NullString + passwordCheckedAt sql.NullTime + intentCheckedAt sql.NullTime + webAuthNCheckedAt sql.NullTime + webAuthNUserPresent sql.NullBool + metadata database.Map[[]byte] ) err := rows.Scan( @@ -347,7 +347,6 @@ func prepareSessionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBui &session.State, &session.ResourceOwner, &session.Creator, - &sessionDomain, &userID, &userCheckedAt, &loginName, @@ -355,7 +354,8 @@ func prepareSessionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBui &userResourceOwner, &passwordCheckedAt, &intentCheckedAt, - &passkeyCheckedAt, + &webAuthNCheckedAt, + &webAuthNUserPresent, &metadata, &sessions.Count, ) @@ -363,7 +363,6 @@ func prepareSessionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBui if err != nil { return nil, errors.ThrowInternal(err, "QUERY-SAfeg", "Errors.Internal") } - session.Domain = sessionDomain.String session.UserFactor.UserID = userID.String session.UserFactor.UserCheckedAt = userCheckedAt.Time session.UserFactor.LoginName = loginName.String @@ -371,7 +370,8 @@ func prepareSessionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBui session.UserFactor.ResourceOwner = userResourceOwner.String session.PasswordFactor.PasswordCheckedAt = passwordCheckedAt.Time session.IntentFactor.IntentCheckedAt = intentCheckedAt.Time - session.PasskeyFactor.PasskeyCheckedAt = passkeyCheckedAt.Time + session.WebAuthNFactor.WebAuthNCheckedAt = webAuthNCheckedAt.Time + session.WebAuthNFactor.UserVerified = webAuthNUserPresent.Bool session.Metadata = metadata sessions.Sessions = append(sessions.Sessions, session) diff --git a/internal/query/sessions_test.go b/internal/query/sessions_test.go index eed2ebafdd..92df908849 100644 --- a/internal/query/sessions_test.go +++ b/internal/query/sessions_test.go @@ -17,51 +17,51 @@ import ( ) var ( - expectedSessionQuery = regexp.QuoteMeta(`SELECT projections.sessions3.id,` + - ` projections.sessions3.creation_date,` + - ` projections.sessions3.change_date,` + - ` projections.sessions3.sequence,` + - ` projections.sessions3.state,` + - ` projections.sessions3.resource_owner,` + - ` projections.sessions3.creator,` + - ` projections.sessions3.domain,` + - ` projections.sessions3.user_id,` + - ` projections.sessions3.user_checked_at,` + + expectedSessionQuery = regexp.QuoteMeta(`SELECT projections.sessions4.id,` + + ` projections.sessions4.creation_date,` + + ` projections.sessions4.change_date,` + + ` projections.sessions4.sequence,` + + ` projections.sessions4.state,` + + ` projections.sessions4.resource_owner,` + + ` projections.sessions4.creator,` + + ` projections.sessions4.user_id,` + + ` projections.sessions4.user_checked_at,` + ` projections.login_names2.login_name,` + ` projections.users8_humans.display_name,` + ` projections.users8.resource_owner,` + - ` projections.sessions3.password_checked_at,` + - ` projections.sessions3.intent_checked_at,` + - ` projections.sessions3.passkey_checked_at,` + - ` projections.sessions3.metadata,` + - ` projections.sessions3.token_id` + - ` FROM projections.sessions3` + - ` LEFT JOIN projections.login_names2 ON projections.sessions3.user_id = projections.login_names2.user_id AND projections.sessions3.instance_id = projections.login_names2.instance_id` + - ` LEFT JOIN projections.users8_humans ON projections.sessions3.user_id = projections.users8_humans.user_id AND projections.sessions3.instance_id = projections.users8_humans.instance_id` + - ` LEFT JOIN projections.users8 ON projections.sessions3.user_id = projections.users8.id AND projections.sessions3.instance_id = projections.users8.instance_id` + + ` projections.sessions4.password_checked_at,` + + ` projections.sessions4.intent_checked_at,` + + ` projections.sessions4.webauthn_checked_at,` + + ` projections.sessions4.webauthn_user_verified,` + + ` projections.sessions4.metadata,` + + ` projections.sessions4.token_id` + + ` FROM projections.sessions4` + + ` LEFT JOIN projections.login_names2 ON projections.sessions4.user_id = projections.login_names2.user_id AND projections.sessions4.instance_id = projections.login_names2.instance_id` + + ` LEFT JOIN projections.users8_humans ON projections.sessions4.user_id = projections.users8_humans.user_id AND projections.sessions4.instance_id = projections.users8_humans.instance_id` + + ` LEFT JOIN projections.users8 ON projections.sessions4.user_id = projections.users8.id AND projections.sessions4.instance_id = projections.users8.instance_id` + ` AS OF SYSTEM TIME '-1 ms'`) - expectedSessionsQuery = regexp.QuoteMeta(`SELECT projections.sessions3.id,` + - ` projections.sessions3.creation_date,` + - ` projections.sessions3.change_date,` + - ` projections.sessions3.sequence,` + - ` projections.sessions3.state,` + - ` projections.sessions3.resource_owner,` + - ` projections.sessions3.creator,` + - ` projections.sessions3.domain,` + - ` projections.sessions3.user_id,` + - ` projections.sessions3.user_checked_at,` + + expectedSessionsQuery = regexp.QuoteMeta(`SELECT projections.sessions4.id,` + + ` projections.sessions4.creation_date,` + + ` projections.sessions4.change_date,` + + ` projections.sessions4.sequence,` + + ` projections.sessions4.state,` + + ` projections.sessions4.resource_owner,` + + ` projections.sessions4.creator,` + + ` projections.sessions4.user_id,` + + ` projections.sessions4.user_checked_at,` + ` projections.login_names2.login_name,` + ` projections.users8_humans.display_name,` + ` projections.users8.resource_owner,` + - ` projections.sessions3.password_checked_at,` + - ` projections.sessions3.intent_checked_at,` + - ` projections.sessions3.passkey_checked_at,` + - ` projections.sessions3.metadata,` + + ` projections.sessions4.password_checked_at,` + + ` projections.sessions4.intent_checked_at,` + + ` projections.sessions4.webauthn_checked_at,` + + ` projections.sessions4.webauthn_user_verified,` + + ` projections.sessions4.metadata,` + ` COUNT(*) OVER ()` + - ` FROM projections.sessions3` + - ` LEFT JOIN projections.login_names2 ON projections.sessions3.user_id = projections.login_names2.user_id AND projections.sessions3.instance_id = projections.login_names2.instance_id` + - ` LEFT JOIN projections.users8_humans ON projections.sessions3.user_id = projections.users8_humans.user_id AND projections.sessions3.instance_id = projections.users8_humans.instance_id` + - ` LEFT JOIN projections.users8 ON projections.sessions3.user_id = projections.users8.id AND projections.sessions3.instance_id = projections.users8.instance_id` + + ` FROM projections.sessions4` + + ` LEFT JOIN projections.login_names2 ON projections.sessions4.user_id = projections.login_names2.user_id AND projections.sessions4.instance_id = projections.login_names2.instance_id` + + ` LEFT JOIN projections.users8_humans ON projections.sessions4.user_id = projections.users8_humans.user_id AND projections.sessions4.instance_id = projections.users8_humans.instance_id` + + ` LEFT JOIN projections.users8 ON projections.sessions4.user_id = projections.users8.id AND projections.sessions4.instance_id = projections.users8.instance_id` + ` AS OF SYSTEM TIME '-1 ms'`) sessionCols = []string{ @@ -72,7 +72,6 @@ var ( "state", "resource_owner", "creator", - "domain", "user_id", "user_checked_at", "login_name", @@ -80,7 +79,8 @@ var ( "user_resource_owner", "password_checked_at", "intent_checked_at", - "passkey_checked_at", + "webauthn_checked_at", + "webauthn_user_verified", "metadata", "token", } @@ -93,7 +93,6 @@ var ( "state", "resource_owner", "creator", - "domain", "user_id", "user_checked_at", "login_name", @@ -101,7 +100,8 @@ var ( "user_resource_owner", "password_checked_at", "intent_checked_at", - "passkey_checked_at", + "webauthn_checked_at", + "webauthn_user_verified", "metadata", "count", } @@ -146,7 +146,6 @@ func Test_SessionsPrepare(t *testing.T) { domain.SessionStateActive, "ro", "creator", - "domain", "user-id", testNow, "login-name", @@ -155,6 +154,7 @@ func Test_SessionsPrepare(t *testing.T) { testNow, testNow, testNow, + true, []byte(`{"key": "dmFsdWU="}`), }, }, @@ -173,7 +173,6 @@ func Test_SessionsPrepare(t *testing.T) { State: domain.SessionStateActive, ResourceOwner: "ro", Creator: "creator", - Domain: "domain", UserFactor: SessionUserFactor{ UserID: "user-id", UserCheckedAt: testNow, @@ -187,8 +186,9 @@ func Test_SessionsPrepare(t *testing.T) { IntentFactor: SessionIntentFactor{ IntentCheckedAt: testNow, }, - PasskeyFactor: SessionPasskeyFactor{ - PasskeyCheckedAt: testNow, + WebAuthNFactor: SessionWebAuthNFactor{ + WebAuthNCheckedAt: testNow, + UserVerified: true, }, Metadata: map[string][]byte{ "key": []byte("value"), @@ -213,7 +213,6 @@ func Test_SessionsPrepare(t *testing.T) { domain.SessionStateActive, "ro", "creator", - "domain", "user-id", testNow, "login-name", @@ -222,6 +221,7 @@ func Test_SessionsPrepare(t *testing.T) { testNow, testNow, testNow, + true, []byte(`{"key": "dmFsdWU="}`), }, { @@ -232,7 +232,6 @@ func Test_SessionsPrepare(t *testing.T) { domain.SessionStateActive, "ro", "creator2", - "domain", "user-id2", testNow, "login-name2", @@ -241,6 +240,7 @@ func Test_SessionsPrepare(t *testing.T) { testNow, testNow, testNow, + false, []byte(`{"key": "dmFsdWU="}`), }, }, @@ -259,7 +259,6 @@ func Test_SessionsPrepare(t *testing.T) { State: domain.SessionStateActive, ResourceOwner: "ro", Creator: "creator", - Domain: "domain", UserFactor: SessionUserFactor{ UserID: "user-id", UserCheckedAt: testNow, @@ -273,8 +272,9 @@ func Test_SessionsPrepare(t *testing.T) { IntentFactor: SessionIntentFactor{ IntentCheckedAt: testNow, }, - PasskeyFactor: SessionPasskeyFactor{ - PasskeyCheckedAt: testNow, + WebAuthNFactor: SessionWebAuthNFactor{ + WebAuthNCheckedAt: testNow, + UserVerified: true, }, Metadata: map[string][]byte{ "key": []byte("value"), @@ -288,7 +288,6 @@ func Test_SessionsPrepare(t *testing.T) { State: domain.SessionStateActive, ResourceOwner: "ro", Creator: "creator2", - Domain: "domain", UserFactor: SessionUserFactor{ UserID: "user-id2", UserCheckedAt: testNow, @@ -302,8 +301,9 @@ func Test_SessionsPrepare(t *testing.T) { IntentFactor: SessionIntentFactor{ IntentCheckedAt: testNow, }, - PasskeyFactor: SessionPasskeyFactor{ - PasskeyCheckedAt: testNow, + WebAuthNFactor: SessionWebAuthNFactor{ + WebAuthNCheckedAt: testNow, + UserVerified: false, }, Metadata: map[string][]byte{ "key": []byte("value"), @@ -381,7 +381,6 @@ func Test_SessionPrepare(t *testing.T) { domain.SessionStateActive, "ro", "creator", - "domain", "user-id", testNow, "login-name", @@ -390,6 +389,7 @@ func Test_SessionPrepare(t *testing.T) { testNow, testNow, testNow, + true, []byte(`{"key": "dmFsdWU="}`), "tokenID", }, @@ -403,7 +403,6 @@ func Test_SessionPrepare(t *testing.T) { State: domain.SessionStateActive, ResourceOwner: "ro", Creator: "creator", - Domain: "domain", UserFactor: SessionUserFactor{ UserID: "user-id", UserCheckedAt: testNow, @@ -417,8 +416,9 @@ func Test_SessionPrepare(t *testing.T) { IntentFactor: SessionIntentFactor{ IntentCheckedAt: testNow, }, - PasskeyFactor: SessionPasskeyFactor{ - PasskeyCheckedAt: testNow, + WebAuthNFactor: SessionWebAuthNFactor{ + WebAuthNCheckedAt: testNow, + UserVerified: true, }, Metadata: map[string][]byte{ "key": []byte("value"), diff --git a/internal/repository/session/eventstore.go b/internal/repository/session/eventstore.go index 07f458586d..89f6d775e4 100644 --- a/internal/repository/session/eventstore.go +++ b/internal/repository/session/eventstore.go @@ -7,8 +7,8 @@ func RegisterEventMappers(es *eventstore.Eventstore) { RegisterFilterEventMapper(AggregateType, UserCheckedType, UserCheckedEventMapper). RegisterFilterEventMapper(AggregateType, PasswordCheckedType, PasswordCheckedEventMapper). RegisterFilterEventMapper(AggregateType, IntentCheckedType, IntentCheckedEventMapper). - RegisterFilterEventMapper(AggregateType, PasskeyChallengedType, eventstore.GenericEventMapper[PasskeyChallengedEvent]). - RegisterFilterEventMapper(AggregateType, PasskeyCheckedType, eventstore.GenericEventMapper[PasskeyCheckedEvent]). + RegisterFilterEventMapper(AggregateType, WebAuthNChallengedType, eventstore.GenericEventMapper[WebAuthNChallengedEvent]). + RegisterFilterEventMapper(AggregateType, WebAuthNCheckedType, eventstore.GenericEventMapper[WebAuthNCheckedEvent]). RegisterFilterEventMapper(AggregateType, TokenSetType, TokenSetEventMapper). RegisterFilterEventMapper(AggregateType, MetadataSetType, MetadataSetEventMapper). RegisterFilterEventMapper(AggregateType, TerminateType, TerminateEventMapper) diff --git a/internal/repository/session/session.go b/internal/repository/session/session.go index 9b48543ecb..f2779fa503 100644 --- a/internal/repository/session/session.go +++ b/internal/repository/session/session.go @@ -12,22 +12,20 @@ import ( ) const ( - sessionEventPrefix = "session." - AddedType = sessionEventPrefix + "added" - UserCheckedType = sessionEventPrefix + "user.checked" - PasswordCheckedType = sessionEventPrefix + "password.checked" - IntentCheckedType = sessionEventPrefix + "intent.checked" - PasskeyChallengedType = sessionEventPrefix + "passkey.challenged" - PasskeyCheckedType = sessionEventPrefix + "passkey.checked" - TokenSetType = sessionEventPrefix + "token.set" - MetadataSetType = sessionEventPrefix + "metadata.set" - TerminateType = sessionEventPrefix + "terminated" + sessionEventPrefix = "session." + AddedType = sessionEventPrefix + "added" + UserCheckedType = sessionEventPrefix + "user.checked" + PasswordCheckedType = sessionEventPrefix + "password.checked" + IntentCheckedType = sessionEventPrefix + "intent.checked" + WebAuthNChallengedType = sessionEventPrefix + "webAuthN.challenged" + WebAuthNCheckedType = sessionEventPrefix + "webAuthN.checked" + TokenSetType = sessionEventPrefix + "token.set" + MetadataSetType = sessionEventPrefix + "metadata.set" + TerminateType = sessionEventPrefix + "terminated" ) type AddedEvent struct { eventstore.BaseEvent `json:"-"` - - Domain string `json:"domain,omitempty"` } func (e *AddedEvent) Data() interface{} { @@ -40,7 +38,6 @@ func (e *AddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { func NewAddedEvent(ctx context.Context, aggregate *eventstore.Aggregate, - domain string, ) *AddedEvent { return &AddedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( @@ -48,7 +45,6 @@ func NewAddedEvent(ctx context.Context, aggregate, AddedType, ), - Domain: domain, } } @@ -190,75 +186,81 @@ func IntentCheckedEventMapper(event *repository.Event) (eventstore.Event, error) return added, nil } -type PasskeyChallengedEvent struct { +type WebAuthNChallengedEvent struct { eventstore.BaseEvent `json:"-"` Challenge string `json:"challenge,omitempty"` AllowedCrentialIDs [][]byte `json:"allowedCrentialIDs,omitempty"` UserVerification domain.UserVerificationRequirement `json:"userVerification,omitempty"` + RPID string `json:"rpid,omitempty"` } -func (e *PasskeyChallengedEvent) Data() interface{} { +func (e *WebAuthNChallengedEvent) Data() interface{} { return e } -func (e *PasskeyChallengedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { +func (e *WebAuthNChallengedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { return nil } -func (e *PasskeyChallengedEvent) SetBaseEvent(base *eventstore.BaseEvent) { +func (e *WebAuthNChallengedEvent) SetBaseEvent(base *eventstore.BaseEvent) { e.BaseEvent = *base } -func NewPasskeyChallengedEvent( +func NewWebAuthNChallengedEvent( ctx context.Context, aggregate *eventstore.Aggregate, challenge string, allowedCrentialIDs [][]byte, userVerification domain.UserVerificationRequirement, -) *PasskeyChallengedEvent { - return &PasskeyChallengedEvent{ + rpid string, +) *WebAuthNChallengedEvent { + return &WebAuthNChallengedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, aggregate, - PasskeyChallengedType, + WebAuthNChallengedType, ), Challenge: challenge, AllowedCrentialIDs: allowedCrentialIDs, UserVerification: userVerification, + RPID: rpid, } } -type PasskeyCheckedEvent struct { +type WebAuthNCheckedEvent struct { eventstore.BaseEvent `json:"-"` - CheckedAt time.Time `json:"checkedAt"` + CheckedAt time.Time `json:"checkedAt"` + UserVerified bool `json:"userVerified,omitempty"` } -func (e *PasskeyCheckedEvent) Data() interface{} { +func (e *WebAuthNCheckedEvent) Data() interface{} { return e } -func (e *PasskeyCheckedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { +func (e *WebAuthNCheckedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { return nil } -func (e *PasskeyCheckedEvent) SetBaseEvent(base *eventstore.BaseEvent) { +func (e *WebAuthNCheckedEvent) SetBaseEvent(base *eventstore.BaseEvent) { e.BaseEvent = *base } -func NewPasskeyCheckedEvent( +func NewWebAuthNCheckedEvent( ctx context.Context, aggregate *eventstore.Aggregate, checkedAt time.Time, -) *PasswordCheckedEvent { - return &PasswordCheckedEvent{ + userVerified bool, +) *WebAuthNCheckedEvent { + return &WebAuthNCheckedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, aggregate, - PasskeyCheckedType, + WebAuthNCheckedType, ), - CheckedAt: checkedAt, + CheckedAt: checkedAt, + UserVerified: userVerified, } } diff --git a/internal/static/i18n/bg.yaml b/internal/static/i18n/bg.yaml index 9f0d302cd4..b719bf191f 100644 --- a/internal/static/i18n/bg.yaml +++ b/internal/static/i18n/bg.yaml @@ -496,8 +496,8 @@ Errors: Terminated: Сесията вече е прекратена Token: Invalid: Токенът на сесията е невалиден - Passkey: - NoChallenge: Сесия без предизвикателство за парола + WebAuthN: + NoChallenge: Сесия без WebAuthN предизвикателство Intent: IDPMissing: IDP липсва в заявката SuccessURLMissing: В заявката липсва URL адрес за успех diff --git a/internal/static/i18n/de.yaml b/internal/static/i18n/de.yaml index 9576d6e299..ff6c85d6ad 100644 --- a/internal/static/i18n/de.yaml +++ b/internal/static/i18n/de.yaml @@ -478,8 +478,8 @@ Errors: Terminated: Session bereits beendet Token: Invalid: Session Token ist ungültig - Passkey: - NoChallenge: Sitzung ohne Passkey-Herausforderung + WebAuthN: + NoChallenge: Sitzung ohne WebAuthN-Challenge Intent: IDPMissing: IDP ID fehlt im Request SuccessURLMissing: Success URL fehlt im Request diff --git a/internal/static/i18n/en.yaml b/internal/static/i18n/en.yaml index b9f92456d5..9058c15d97 100644 --- a/internal/static/i18n/en.yaml +++ b/internal/static/i18n/en.yaml @@ -478,8 +478,8 @@ Errors: Terminated: Session already terminated Token: Invalid: Session Token is invalid - Passkey: - NoChallenge: Session without passkey challenge + WebAuthN: + NoChallenge: Session without WebAuthN challenge Intent: IDPMissing: IDP ID is missing in the request SuccessURLMissing: Success URL is missing in the request diff --git a/internal/static/i18n/es.yaml b/internal/static/i18n/es.yaml index e45a075918..475280504d 100644 --- a/internal/static/i18n/es.yaml +++ b/internal/static/i18n/es.yaml @@ -478,8 +478,8 @@ Errors: Terminated: Sesión ya terminada Token: Invalid: El identificador de sesión no es válido - Passkey: - NoChallenge: Sesión sin desafío de contraseña + WebAuthN: + NoChallenge: Sesión sin desafío WebAuthN Intent: IDPMissing: Falta IDP en la solicitud SuccessURLMissing: Falta la URL de éxito en la solicitud diff --git a/internal/static/i18n/fr.yaml b/internal/static/i18n/fr.yaml index 150d9b0302..54ad40236b 100644 --- a/internal/static/i18n/fr.yaml +++ b/internal/static/i18n/fr.yaml @@ -478,8 +478,8 @@ Errors: Terminated: La session est déjà terminée Token: Invalid: Le jeton de session n'est pas valide - Passkey: - NoChallenge: Session sans défi de clé d'accès + WebAuthN: + NoChallenge: Session sans challenge WebAuthN Intent: IDPMissing: IDP manquant dans la requête SuccessURLMissing: Success URL absent de la requête diff --git a/internal/static/i18n/it.yaml b/internal/static/i18n/it.yaml index fc50f082cf..958eea5b12 100644 --- a/internal/static/i18n/it.yaml +++ b/internal/static/i18n/it.yaml @@ -478,8 +478,8 @@ Errors: Terminated: Sessione già terminata Token: Invalid: Il token della sessione non è valido - Passkey: - NoChallenge: Sessione senza sfida passkey + WebAuthN: + NoChallenge: Sessione senza sfida WebAuthN Intent: IDPMissing: IDP mancante nella richiesta SuccessURLMissing: URL di successo mancante nella richiesta diff --git a/internal/static/i18n/ja.yaml b/internal/static/i18n/ja.yaml index bbf565e071..c0a735c1e8 100644 --- a/internal/static/i18n/ja.yaml +++ b/internal/static/i18n/ja.yaml @@ -467,8 +467,8 @@ Errors: Terminated: セッションはすでに終了しています Token: Invalid: セッショントークンが無効です - Passkey: - NoChallenge: パスキーチャレンジなしのセッション + WebAuthN: + NoChallenge: WebAuthN チャレンジを使用しないセッション Intent: IDPMissing: リクエストにIDP IDが含まれていません SuccessURLMissing: リクエストに成功時の URL がありません diff --git a/internal/static/i18n/mk.yaml b/internal/static/i18n/mk.yaml index 78d059f1f3..36d1b1c748 100644 --- a/internal/static/i18n/mk.yaml +++ b/internal/static/i18n/mk.yaml @@ -478,8 +478,8 @@ Errors: Terminated: Сесијата е веќе завршена Token: Invalid: Токенот за сесија е невалиден - Passkey: - NoChallenge: Сесија без предизвик за passkey + WebAuthN: + NoChallenge: Сесија без предизвик WebAuthN Intent: IDPMissing: ID на IDP недостасува во барањето SuccessURLMissing: URL за успех недостасува во барањето diff --git a/internal/static/i18n/pl.yaml b/internal/static/i18n/pl.yaml index fb7b80114a..1e831f6824 100644 --- a/internal/static/i18n/pl.yaml +++ b/internal/static/i18n/pl.yaml @@ -478,8 +478,8 @@ Errors: Terminated: Sesja już zakończona Token: Invalid: Token sesji jest nieprawidłowy - Passkey: - NoChallenge: Sesja bez wyzwania klucza + WebAuthN: + NoChallenge: Sesja bez wyzwania WebAuthN Intent: IDPMissing: Brak identyfikatora IDP w żądaniu SuccessURLMissing: Brak adresu URL powodzenia w żądaniu diff --git a/internal/static/i18n/pt.yaml b/internal/static/i18n/pt.yaml index 932ed66543..9b823dbfec 100644 --- a/internal/static/i18n/pt.yaml +++ b/internal/static/i18n/pt.yaml @@ -477,8 +477,8 @@ Errors: Terminated: A sessão já foi encerrada Token: Invalid: O token da sessão é inválido - Passkey: - NoChallenge: Sessão sem desafio de senha + WebAuthN: + NoChallenge: Sessão sem desafio WebAuthN Intent: IDPMissing: O ID do IDP está faltando na solicitação SuccessURLMissing: A URL de sucesso está faltando na solicitação diff --git a/internal/static/i18n/zh.yaml b/internal/static/i18n/zh.yaml index 10f7072d30..c1d7229cce 100644 --- a/internal/static/i18n/zh.yaml +++ b/internal/static/i18n/zh.yaml @@ -478,8 +478,8 @@ Errors: Terminated: 会话已经终止 Token: Invalid: 会话令牌是无效的 - Passkey: - NoChallenge: 没有密码挑战的会话 + WebAuthN: + NoChallenge: 没有 WebAuthN 质询的会话 Intent: IDPMissing: 请求中缺少IDP ID SuccessURLMissing: 请求中缺少成功URL diff --git a/internal/webauthn/client.go b/internal/webauthn/client.go index 511378feed..62232154bc 100644 --- a/internal/webauthn/client.go +++ b/internal/webauthn/client.go @@ -9,9 +9,10 @@ import ( ) type Client struct { - rp virtualwebauthn.RelyingParty - auth virtualwebauthn.Authenticator - credential virtualwebauthn.Credential + rp virtualwebauthn.RelyingParty + auth virtualwebauthn.Authenticator + authVerifyUser virtualwebauthn.Authenticator + credential virtualwebauthn.Credential } func NewClient(name, domain, origin string) *Client { @@ -21,9 +22,12 @@ func NewClient(name, domain, origin string) *Client { Origin: origin, } return &Client{ - rp: rp, - auth: virtualwebauthn.NewAuthenticator(), - credential: virtualwebauthn.NewCredential(virtualwebauthn.KeyTypeEC2), + rp: rp, + auth: virtualwebauthn.NewAuthenticatorWithOptions(virtualwebauthn.AuthenticatorOptions{ + UserNotVerified: true, + }), + authVerifyUser: virtualwebauthn.NewAuthenticator(), + credential: virtualwebauthn.NewCredential(virtualwebauthn.KeyTypeEC2), } } @@ -46,7 +50,7 @@ func (c *Client) CreateAttestationResponse(optionsPb *structpb.Struct) (*structp return resp, nil } -func (c *Client) CreateAssertionResponse(optionsPb *structpb.Struct) (*structpb.Struct, error) { +func (c *Client) CreateAssertionResponse(optionsPb *structpb.Struct, verifyUser bool) (*structpb.Struct, error) { options, err := protojson.Marshal(optionsPb) if err != nil { return nil, fmt.Errorf("webauthn.Client.CreateAssertionResponse: %w", err) @@ -55,9 +59,13 @@ func (c *Client) CreateAssertionResponse(optionsPb *structpb.Struct) (*structpb. if err != nil { return nil, fmt.Errorf("webauthn.Client.CreateAssertionResponse: %w", err) } + authenticator := c.auth + if verifyUser { + authenticator = c.authVerifyUser + } resp := new(structpb.Struct) err = protojson.Unmarshal([]byte(virtualwebauthn.CreateAssertionResponse( - c.rp, c.auth, c.credential, *parsedAssertionOptions, + c.rp, authenticator, c.credential, *parsedAssertionOptions, )), resp) if err != nil { return nil, fmt.Errorf("webauthn.Client.CreateAssertionResponse: %w", err) diff --git a/internal/webauthn/webauthn.go b/internal/webauthn/webauthn.go index bced4f220f..866f174a2e 100644 --- a/internal/webauthn/webauthn.go +++ b/internal/webauthn/webauthn.go @@ -154,10 +154,10 @@ func (w *Config) BeginLogin(ctx context.Context, user *domain.Human, userVerific }, nil } -func (w *Config) FinishLogin(ctx context.Context, user *domain.Human, webAuthN *domain.WebAuthNLogin, credData []byte, webAuthNs ...*domain.WebAuthNToken) ([]byte, uint32, error) { +func (w *Config) FinishLogin(ctx context.Context, user *domain.Human, webAuthN *domain.WebAuthNLogin, credData []byte, webAuthNs ...*domain.WebAuthNToken) (*webauthn.Credential, error) { assertionData, err := protocol.ParseCredentialRequestResponseBody(bytes.NewReader(credData)) if err != nil { - return nil, 0, caos_errs.ThrowInternal(err, "WEBAU-ADgv4", "Errors.User.WebAuthN.ValidateLoginFailed") + return nil, caos_errs.ThrowInternal(err, "WEBAU-ADgv4", "Errors.User.WebAuthN.ValidateLoginFailed") } webUser := &webUser{ Human: user, @@ -165,17 +165,17 @@ func (w *Config) FinishLogin(ctx context.Context, user *domain.Human, webAuthN * } webAuthNServer, err := w.serverFromContext(ctx, webAuthN.RPID, assertionData.Response.CollectedClientData.Origin) if err != nil { - return nil, 0, err + return nil, err } credential, err := webAuthNServer.ValidateLogin(webUser, WebAuthNLoginToSessionData(webAuthN), assertionData) if err != nil { - return nil, 0, caos_errs.ThrowInternal(err, "WEBAU-3M9si", "Errors.User.WebAuthN.ValidateLoginFailed") + return nil, caos_errs.ThrowInternal(err, "WEBAU-3M9si", "Errors.User.WebAuthN.ValidateLoginFailed") } if credential.Authenticator.CloneWarning { - return credential.ID, credential.Authenticator.SignCount, caos_errs.ThrowInternal(err, "WEBAU-4M90s", "Errors.User.WebAuthN.CloneWarning") + return credential, caos_errs.ThrowInternal(err, "WEBAU-4M90s", "Errors.User.WebAuthN.CloneWarning") } - return credential.ID, credential.Authenticator.SignCount, nil + return credential, nil } func (w *Config) serverFromContext(ctx context.Context, id, origin string) (*webauthn.WebAuthn, error) { diff --git a/proto/buf.yaml b/proto/buf.yaml index 483af8667e..5d5a33e93d 100644 --- a/proto/buf.yaml +++ b/proto/buf.yaml @@ -7,6 +7,7 @@ deps: breaking: use: - FILE + ignore_unstable_packages: true lint: use: - MINIMAL diff --git a/proto/zitadel/session/v2alpha/challenge.proto b/proto/zitadel/session/v2alpha/challenge.proto index 498cb729b4..ed1ef6e647 100644 --- a/proto/zitadel/session/v2alpha/challenge.proto +++ b/proto/zitadel/session/v2alpha/challenge.proto @@ -2,18 +2,47 @@ syntax = "proto3"; package zitadel.session.v2alpha; +import "google/api/field_behavior.proto"; import "google/protobuf/struct.proto"; import "protoc-gen-openapiv2/options/annotations.proto"; +import "validate/validate.proto"; option go_package = "github.com/zitadel/zitadel/pkg/grpc/session/v2alpha;session"; -enum ChallengeKind { - CHALLENGE_KIND_UNSPECIFIED = 0; - CHALLENGE_KIND_PASSKEY = 1; +enum UserVerificationRequirement { + USER_VERIFICATION_REQUIREMENT_UNSPECIFIED = 0; + USER_VERIFICATION_REQUIREMENT_REQUIRED = 1; + USER_VERIFICATION_REQUIREMENT_PREFERRED = 2; + USER_VERIFICATION_REQUIREMENT_DISCOURAGED = 3; +} + +message RequestChallenges { + message WebAuthN { + string domain = 1 [ + (validate.rules).string = {min_len: 1, max_len: 200}, + (google.api.field_behavior) = REQUIRED, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "\"Domain on which the session was created. Will be used in the WebAuthN challenge.\""; + } + ]; + UserVerificationRequirement user_verification_requirement = 2 [ + (validate.rules).enum = { + defined_only: true, + not_in: [0] + }, + (google.api.field_behavior) = REQUIRED, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "\"User verification that is required during validation. When set to `USER_VERIFICATION_REQUIREMENT_REQUIRED` the behaviour is for passkey authentication. Other values will mean U2F\""; + ref: "https://www.w3.org/TR/webauthn/#enum-userVerificationRequirement"; + } + ]; + } + + optional WebAuthN web_auth_n = 1; } message Challenges { - message Passkey { + message WebAuthN { google.protobuf.Struct public_key_credential_request_options = 1 [ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { description: "Options for Assertion Generaration (dictionary PublicKeyCredentialRequestOptions). Generated helper methods transform the field to JSON, for use in a WebauthN client. See also: https://www.w3.org/TR/webauthn/#dictdef-publickeycredentialrequestoptions" @@ -22,5 +51,5 @@ message Challenges { ]; } - optional Passkey passkey = 1; + optional WebAuthN web_auth_n = 1; } diff --git a/proto/zitadel/session/v2alpha/session.proto b/proto/zitadel/session/v2alpha/session.proto index e6e69ca50d..37436ed2d4 100644 --- a/proto/zitadel/session/v2alpha/session.proto +++ b/proto/zitadel/session/v2alpha/session.proto @@ -39,17 +39,12 @@ message Session { description: "\"custom key value list\""; } ]; - string domain = 7 [ - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "\"domain on which the session was created\""; - } - ]; } message Factors { UserFactor user = 1; PasswordFactor password = 2; - PasskeyFactor passkey = 3; + WebAuthNFactor web_auth_n = 3; IntentFactor intent = 4; } @@ -97,12 +92,13 @@ message IntentFactor { ]; } -message PasskeyFactor { +message WebAuthNFactor { google.protobuf.Timestamp verified_at = 1 [ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { description: "\"time when the passkey challenge was last checked\""; } ]; + bool user_verified = 2; } message SearchQuery { diff --git a/proto/zitadel/session/v2alpha/session_service.proto b/proto/zitadel/session/v2alpha/session_service.proto index 2703176262..c201b5e368 100644 --- a/proto/zitadel/session/v2alpha/session_service.proto +++ b/proto/zitadel/session/v2alpha/session_service.proto @@ -244,12 +244,7 @@ message CreateSessionRequest{ description: "\"custom key value list to be stored on the session\""; } ]; - repeated ChallengeKind challenges = 3; - string domain = 4 [ - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "\"Domain on which the session was created. Will be used for Passkey and U2F challenges.\""; - } - ]; + RequestChallenges challenges = 3; } message CreateSessionResponse{ @@ -296,7 +291,7 @@ message SetSessionRequest{ description: "\"custom key value list to be stored on the session\""; } ]; - repeated ChallengeKind challenges = 5; + RequestChallenges challenges = 5; } message SetSessionResponse{ @@ -306,7 +301,7 @@ message SetSessionResponse{ description: "\"token of the session, which is required for further updates of the session or the request other resources\""; } ]; - Challenges challenges = 3; + Challenges challenges = 3; } message DeleteSessionRequest{ @@ -341,9 +336,9 @@ message Checks { description: "\"Checks the password and updates the session on success. Requires that the user is already checked, either in the previous or the same request.\""; } ]; - optional CheckPasskey passkey = 3 [ + optional CheckWebAuthN web_auth_n = 3 [ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "\"Checks the public key credential issued by the passkey client. Requires that the user is already checked and a passkey challenge to be requested, in any previous request.\""; + description: "\"Checks the public key credential issued by the WebAuthN client. Requires that the user is already checked and a WebAuthN challenge to be requested, in any previous request.\""; } ]; optional CheckIntent intent = 4 [ @@ -385,12 +380,12 @@ message CheckPassword { ]; } -message CheckPasskey { +message CheckWebAuthN { google.protobuf.Struct credential_assertion_data = 1 [ (validate.rules).message.required = true, (google.api.field_behavior) = REQUIRED, (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "JSON representation of public key credential issued by the passkey client"; + description: "JSON representation of public key credential issued by the webAuthN client"; min_length: 55; max_length: 1048576; //1 MB } From 88751681d8ebf9e12e996ca42add031df11d3765 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Sat, 12 Aug 2023 10:58:44 +0200 Subject: [PATCH 23/38] docs: cleanup deps (#6313) * docs(search): add getMissingResultsUrl * deps * deps * downgrade docusaurus again to 2.2.0 * fix angualar, nextjs guides * Update docs/docusaurus.config.js Co-authored-by: Florian Forster --------- Co-authored-by: mffap Co-authored-by: Florian Forster --- docs/package.json | 161 +- docs/yarn.lock | 5757 ++++++++++++++++++--------------------------- 2 files changed, 2345 insertions(+), 3573 deletions(-) diff --git a/docs/package.json b/docs/package.json index 99e5a44ce4..338110dbb7 100644 --- a/docs/package.json +++ b/docs/package.json @@ -19,172 +19,28 @@ "generate:configdocs": "cp -r ../cmd/defaults.yaml ./docs/self-hosting/manage/configure/ && cp -r ../cmd/setup/steps.yaml ./docs/self-hosting/manage/configure/" }, "dependencies": { - "@algolia/autocomplete-core": "1.5.2", - "@algolia/autocomplete-preset-algolia": "1.5.2", - "@ampproject/remapping": "2.2.0", - "@babel/core": "7.17.10", - "@babel/plugin-proposal-async-generator-functions": "7.16.8", - "@babel/plugin-proposal-class-static-block": "7.17.6", - "@babel/plugin-proposal-object-rest-spread": "7.17.3", - "@babel/plugin-proposal-private-methods": "7.16.11", - "@babel/plugin-transform-async-to-generator": "7.16.8", - "@babel/plugin-transform-destructuring": "7.17.7", - "@babel/plugin-transform-modules-commonjs": "7.17.9", - "@babel/plugin-transform-modules-systemjs": "7.17.8", - "@babel/plugin-transform-named-capturing-groups-regex": "7.17.10", - "@babel/plugin-transform-regenerator": "7.17.9", - "@babel/plugin-transform-runtime": "7.17.10", - "@babel/preset-env": "7.17.10", - "@babel/preset-react": "7.16.7", - "@babel/preset-typescript": "7.16.7", - "@babel/runtime-corejs3": "7.17.9", "@bufbuild/buf": "^1.14.0", - "@colors/colors": "1.5.0", - "@docsearch/css": "3.0.0", - "@docsearch/react": "3.0.0", "@docusaurus/core": "2.2.0", - "@docusaurus/cssnano-preset": "2.2.0", - "@docusaurus/module-type-aliases": "2.2.0", - "@docusaurus/plugin-debug": "2.2.0", - "@docusaurus/plugin-google-analytics": "2.2.0", - "@docusaurus/plugin-google-gtag": "2.2.0", - "@docusaurus/plugin-sitemap": "2.2.0", "@docusaurus/preset-classic": "2.2.0", - "@docusaurus/theme-classic": "2.2.0", "@docusaurus/theme-search-algolia": "2.2.0", - "@docusaurus/types": "2.2.0", "@headlessui/react": "^1.7.4", "@heroicons/react": "^2.0.13", - "@jridgewell/resolve-uri": "3.0.7", - "@jridgewell/set-array": "1.1.1", - "@jridgewell/trace-mapping": "0.3.11", - "@leichtgewicht/ip-codec": "2.0.4", - "@mdx-js/mdx": "1.6.22", - "@mdx-js/react": "^1.6.22", - "@saucelabs/theme-github-codeblock": "^0.1.1", - "@slorber/static-site-generator-webpack-plugin": "4.0.4", - "@svgr/core": "6.2.1", - "@svgr/hast-util-to-babel-ast": "6.2.1", - "@svgr/plugin-svgo": "6.2.0", - "@swc/core": "^1.3.36", - "@types/eslint-scope": "3.7.3", - "@types/http-proxy": "1.17.9", - "@types/react-router-config": "5.0.6", - "@types/react-router-dom": "5.3.3", - "@types/ws": "8.5.3", + "@saucelabs/theme-github-codeblock": "^0.2.3", + "@swc/core": "^1.3.74", "autoprefixer": "^10.4.13", - "axios": "0.25.0", - "babel-loader": "8.2.5", - "body-parser": "1.20.0", - "bonjour-service": "1.0.12", - "boxen": "6.2.1", - "buffer": "^6.0.3", - "clean-css": "5.3.0", - "cli-boxes": "3.0.0", - "cli-table3": "0.6.2", "clsx": "^1.2.1", - "cookie": "0.5.0", - "copy-webpack-plugin": "10.2.4", - "core-js": "3.22.5", - "core-js-pure": "3.22.5", - "css-declaration-sorter": "6.2.2", - "css-loader": "6.7.1", - "css-minimizer-webpack-plugin": "3.4.1", - "cssnano": "5.1.7", - "cssnano-preset-advanced": "5.3.3", - "dns-packet": "5.3.1", - "docusaurus-plugin-image-zoom": "^0.1.1", - "docusaurus-plugin-openapi-docs": "1.5.2", - "docusaurus-theme-openapi-docs": "1.5.2", - "eastasianwidth": "0.2.0", - "enhanced-resolve": "5.9.3", - "eval": "0.1.8", - "express": "4.18.1", - "finalhandler": "1.2.0", - "follow-redirects": "1.15.0", - "fraction.js": "4.2.0", - "html-minifier-terser": "6.1.0", - "html-tags": "3.2.0", - "html-webpack-plugin": "5.5.0", - "http-proxy-middleware": "2.0.6", - "infima": "0.2.0-alpha.39", - "invariant": "2.2.4", + "docusaurus-plugin-image-zoom": "^1.0.1", + "docusaurus-plugin-openapi-docs": "^1.7.3", + "docusaurus-theme-openapi-docs": "^1.7.3", "mdx-mermaid": "^1.1.0", - "mermaid": "^9.1.2", - "mini-css-extract-plugin": "2.6.0", - "multicast-dns": "7.2.4", - "nanoid": "3.3.4", - "node-forge": "1.3.1", - "object-inspect": "1.12.0", - "plugin-image-zoom": "ataft/plugin-image-zoom", "postcss": "^8.4.19", - "postcss-calc": "8.2.4", - "postcss-colormin": "5.3.0", - "postcss-convert-values": "5.1.0", - "postcss-discard-comments": "5.1.1", - "postcss-discard-duplicates": "5.1.0", - "postcss-discard-empty": "5.1.1", - "postcss-discard-overridden": "5.1.0", - "postcss-discard-unused": "5.1.0", - "postcss-loader": "6.2.1", - "postcss-merge-idents": "5.1.1", - "postcss-merge-longhand": "5.1.4", - "postcss-merge-rules": "5.1.1", - "postcss-minify-font-values": "5.1.0", - "postcss-minify-gradients": "5.1.1", - "postcss-minify-params": "5.1.2", - "postcss-minify-selectors": "5.2.0", - "postcss-normalize-charset": "5.1.0", - "postcss-normalize-display-values": "5.1.0", - "postcss-normalize-positions": "5.1.0", - "postcss-normalize-repeat-style": "5.1.0", - "postcss-normalize-string": "5.1.0", - "postcss-normalize-timing-functions": "5.1.0", - "postcss-normalize-unicode": "5.1.0", - "postcss-normalize-url": "5.1.0", - "postcss-normalize-whitespace": "5.1.1", - "postcss-ordered-values": "5.1.1", - "postcss-reduce-idents": "5.2.0", - "postcss-reduce-initial": "5.1.0", - "postcss-reduce-transforms": "5.1.0", - "postcss-sort-media-queries": "4.2.1", - "postcss-svgo": "5.1.0", - "postcss-unique-selectors": "5.1.1", - "postcss-zindex": "5.1.0", - "prismjs": "1.28.0", - "raw-body": "2.5.1", "raw-loader": "^4.0.2", - "react": "^17.0.2", + "react": "^18.2.0", "react-copy-to-clipboard": "^5.1.0", - "react-dev-utils": "12.0.1", - "react-dom": "^17.0.2", - "react-error-overlay": "6.0.11", - "react-fast-compare": "3.2.0", - "regenerator-transform": "0.15.0", - "remark-emoji": "2.2.0", - "rtlcss": "3.5.0", - "rxjs": "7.5.5", - "selfsigned": "2.0.1", - "serve-static": "1.15.0", - "shallowequal": "1.1.0", - "side-channel": "1.0.4", + "react-dom": "^18.2.0", "sitemap": "7.1.1", - "source-map-js": "1.0.2", - "stylehacks": "5.1.0", "swc-loader": "^0.2.3", - "terser-webpack-plugin": "5.3.1", - "type-fest": "2.12.2", - "url": "^0.11.0", - "wait-on": "6.0.1", - "webpack-bundle-analyzer": "4.5.0", - "webpack-dev-middleware": "5.3.1", - "webpack-dev-server": "4.9.0", - "widest-line": "4.0.1", - "wrap-ansi": "8.0.1" - }, - "resolutions": { - "@docusaurus/theme-common": "2.2.0", - "@paloaltonetworks/postman-code-generators": "1.1.13" + "wait-on": "6.0.1" }, "browserslist": { "production": [ @@ -199,6 +55,7 @@ ] }, "devDependencies": { + "@docusaurus/module-type-aliases": "2.2.0", "tailwindcss": "^3.2.4" } } diff --git a/docs/yarn.lock b/docs/yarn.lock index 4aa155755f..cfd246828a 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -2,182 +2,177 @@ # yarn lockfile v1 -"@algolia/autocomplete-core@1.5.2": - version "1.5.2" - resolved "https://registry.yarnpkg.com/@algolia/autocomplete-core/-/autocomplete-core-1.5.2.tgz#ec0178e07b44fd74a057728ac157291b26cecf37" - integrity sha512-DY0bhyczFSS1b/CqJlTE/nQRtnTAHl6IemIkBy0nEWnhDzRDdtdx4p5Uuk3vwAFxwEEgi1WqKwgSSMx6DpNL4A== +"@algolia/autocomplete-core@1.9.3": + version "1.9.3" + resolved "https://registry.yarnpkg.com/@algolia/autocomplete-core/-/autocomplete-core-1.9.3.tgz#1d56482a768c33aae0868c8533049e02e8961be7" + integrity sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw== dependencies: - "@algolia/autocomplete-shared" "1.5.2" + "@algolia/autocomplete-plugin-algolia-insights" "1.9.3" + "@algolia/autocomplete-shared" "1.9.3" -"@algolia/autocomplete-core@1.7.4": - version "1.7.4" - resolved "https://registry.yarnpkg.com/@algolia/autocomplete-core/-/autocomplete-core-1.7.4.tgz#85ff36b2673654a393c8c505345eaedd6eaa4f70" - integrity sha512-daoLpQ3ps/VTMRZDEBfU8ixXd+amZcNJ4QSP3IERGyzqnL5Ch8uSRFt/4G8pUvW9c3o6GA4vtVv4I4lmnkdXyg== +"@algolia/autocomplete-plugin-algolia-insights@1.9.3": + version "1.9.3" + resolved "https://registry.yarnpkg.com/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.9.3.tgz#9b7f8641052c8ead6d66c1623d444cbe19dde587" + integrity sha512-a/yTUkcO/Vyy+JffmAnTWbr4/90cLzw+CC3bRbhnULr/EM0fGNvM13oQQ14f2moLMcVDyAx/leczLlAOovhSZg== dependencies: - "@algolia/autocomplete-shared" "1.7.4" + "@algolia/autocomplete-shared" "1.9.3" -"@algolia/autocomplete-preset-algolia@1.5.2": - version "1.5.2" - resolved "https://registry.yarnpkg.com/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.5.2.tgz#36c5638cc6dba6ea46a86e5a0314637ca40a77ca" - integrity sha512-3MRYnYQFJyovANzSX2CToS6/5cfVjbLLqFsZTKcvF3abhQzxbqwwaMBlJtt620uBUOeMzhdfasKhCc40+RHiZw== +"@algolia/autocomplete-preset-algolia@1.9.3": + version "1.9.3" + resolved "https://registry.yarnpkg.com/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.9.3.tgz#64cca4a4304cfcad2cf730e83067e0c1b2f485da" + integrity sha512-d4qlt6YmrLMYy95n5TB52wtNDr6EgAIPH81dvvvW8UmuWRgxEtY0NJiPwl/h95JtG2vmRM804M0DSwMCNZlzRA== dependencies: - "@algolia/autocomplete-shared" "1.5.2" + "@algolia/autocomplete-shared" "1.9.3" -"@algolia/autocomplete-preset-algolia@1.7.4": - version "1.7.4" - resolved "https://registry.yarnpkg.com/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.7.4.tgz#610ee1d887962f230b987cba2fd6556478000bc3" - integrity sha512-s37hrvLEIfcmKY8VU9LsAXgm2yfmkdHT3DnA3SgHaY93yjZ2qL57wzb5QweVkYuEBZkT2PIREvRoLXC2sxTbpQ== +"@algolia/autocomplete-shared@1.9.3": + version "1.9.3" + resolved "https://registry.yarnpkg.com/@algolia/autocomplete-shared/-/autocomplete-shared-1.9.3.tgz#2e22e830d36f0a9cf2c0ccd3c7f6d59435b77dfa" + integrity sha512-Wnm9E4Ye6Rl6sTTqjoymD+l8DjSTHsHboVRYrKgEt8Q7UHm9nYbqhN/i0fhUYA3OAEH7WA8x3jfpnmJm3rKvaQ== + +"@algolia/cache-browser-local-storage@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.19.1.tgz#d29f42775ed4d117182897ac164519c593faf399" + integrity sha512-FYAZWcGsFTTaSAwj9Std8UML3Bu8dyWDncM7Ls8g+58UOe4XYdlgzXWbrIgjaguP63pCCbMoExKr61B+ztK3tw== dependencies: - "@algolia/autocomplete-shared" "1.7.4" + "@algolia/cache-common" "4.19.1" -"@algolia/autocomplete-shared@1.5.2": - version "1.5.2" - resolved "https://registry.yarnpkg.com/@algolia/autocomplete-shared/-/autocomplete-shared-1.5.2.tgz#e157f9ad624ab8fd940ff28bd2094cdf199cdd79" - integrity sha512-ylQAYv5H0YKMfHgVWX0j0NmL8XBcAeeeVQUmppnnMtzDbDnca6CzhKj3Q8eF9cHCgcdTDdb5K+3aKyGWA0obug== +"@algolia/cache-common@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@algolia/cache-common/-/cache-common-4.19.1.tgz#faa5eeacaffd6023c2cf26e9866bdb06193f9b26" + integrity sha512-XGghi3l0qA38HiqdoUY+wvGyBsGvKZ6U3vTiMBT4hArhP3fOGLXpIINgMiiGjTe4FVlTa5a/7Zf2bwlIHfRqqg== -"@algolia/autocomplete-shared@1.7.4": - version "1.7.4" - resolved "https://registry.yarnpkg.com/@algolia/autocomplete-shared/-/autocomplete-shared-1.7.4.tgz#78aea1140a50c4d193e1f06a13b7f12c5e2cbeea" - integrity sha512-2VGCk7I9tA9Ge73Km99+Qg87w0wzW4tgUruvWAn/gfey1ZXgmxZtyIRBebk35R1O8TbK77wujVtCnpsGpRy1kg== - -"@algolia/cache-browser-local-storage@4.15.0": - version "4.15.0" - resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.15.0.tgz#84f12aec6b6aa69542a3bfd3a4ba458ed2cc8230" - integrity sha512-uxxFhTWh4JJDb2+FFSmNMfEQ8p9o2vjSpU7iW007QX3OvqljPPN68lk3bpZVaG8pwr5MU1DqpkZ71FcQdVTjgQ== +"@algolia/cache-in-memory@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@algolia/cache-in-memory/-/cache-in-memory-4.19.1.tgz#afe4f0f21149800358379871089e0141fb72415b" + integrity sha512-+PDWL+XALGvIginigzu8oU6eWw+o76Z8zHbBovWYcrtWOEtinbl7a7UTt3x3lthv+wNuFr/YD1Gf+B+A9V8n5w== dependencies: - "@algolia/cache-common" "4.15.0" + "@algolia/cache-common" "4.19.1" -"@algolia/cache-common@4.15.0": - version "4.15.0" - resolved "https://registry.yarnpkg.com/@algolia/cache-common/-/cache-common-4.15.0.tgz#a198098c4b8fa6ef661879ec22d2a2d1ad77d2bb" - integrity sha512-Me3PbI4QurAM+3D+htIE0l1xt6+bl/18SG6Wc7bPQEZAtN7DTGz22HqhKNyLF2lR/cOfpaH7umXZlZEhIHf7gQ== - -"@algolia/cache-in-memory@4.15.0": - version "4.15.0" - resolved "https://registry.yarnpkg.com/@algolia/cache-in-memory/-/cache-in-memory-4.15.0.tgz#77cac4db36a0aa0837f7a7ceb760188191e35268" - integrity sha512-B9mg1wd7CKMfpkbiTQ8KlcKkH6ut/goVaI6XmDCUczOOqeuZlV34tuEi7o3Xo1j66KWr/d9pMjjGYcoVPCVeOA== +"@algolia/client-account@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.19.1.tgz#1fa65881baab79ad35af6bcf44646a13b8d5edc9" + integrity sha512-Oy0ritA2k7AMxQ2JwNpfaEcgXEDgeyKu0V7E7xt/ZJRdXfEpZcwp9TOg4TJHC7Ia62gIeT2Y/ynzsxccPw92GA== dependencies: - "@algolia/cache-common" "4.15.0" + "@algolia/client-common" "4.19.1" + "@algolia/client-search" "4.19.1" + "@algolia/transporter" "4.19.1" -"@algolia/client-account@4.15.0": - version "4.15.0" - resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.15.0.tgz#8e0723052169665b4449dc2f8bcf3075feb6a424" - integrity sha512-8wqI33HRZy5ydfFt6F5vMhtkOiAUhVfSCYXx4U3Go5RALqWLgVUp6wzOo0mr1z08POCkHDpbQMQvyayb1CZ/kw== +"@algolia/client-analytics@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-4.19.1.tgz#e6ed79acd4de5a0284c9696bf4e1c25278ba34db" + integrity sha512-5QCq2zmgdZLIQhHqwl55ZvKVpLM3DNWjFI4T+bHr3rGu23ew2bLO4YtyxaZeChmDb85jUdPDouDlCumGfk6wOg== dependencies: - "@algolia/client-common" "4.15.0" - "@algolia/client-search" "4.15.0" - "@algolia/transporter" "4.15.0" + "@algolia/client-common" "4.19.1" + "@algolia/client-search" "4.19.1" + "@algolia/requester-common" "4.19.1" + "@algolia/transporter" "4.19.1" -"@algolia/client-analytics@4.15.0": - version "4.15.0" - resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-4.15.0.tgz#6b8fe450e1bba114b0d0598cbf9acac482798a36" - integrity sha512-jrPjEeNEIIQKeA1XCZXx3f3aybtwF7wjYlnfHbLARuZ9AuHzimOKjX0ZwqvMmvTsHivpcZ2rqY+j1E8HoH1ELA== +"@algolia/client-common@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.19.1.tgz#40a8387316fa61d62ad1091beb3a8e227f008e75" + integrity sha512-3kAIVqTcPrjfS389KQvKzliC559x+BDRxtWamVJt8IVp7LGnjq+aVAXg4Xogkur1MUrScTZ59/AaUd5EdpyXgA== dependencies: - "@algolia/client-common" "4.15.0" - "@algolia/client-search" "4.15.0" - "@algolia/requester-common" "4.15.0" - "@algolia/transporter" "4.15.0" + "@algolia/requester-common" "4.19.1" + "@algolia/transporter" "4.19.1" -"@algolia/client-common@4.15.0": - version "4.15.0" - resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.15.0.tgz#27dd9441aedf481736696d519e55ea8e2f5a4432" - integrity sha512-PlsJMObZuYw4JlG5EhYv1PHDOv7n5mD5PzqFyoNfSOYaEPRZepa3W579ya29yOu3FZ0VGMNJmB7Q5v/+/fwvIw== +"@algolia/client-personalization@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-4.19.1.tgz#fe362e0684dc74c3504c3641c5a7488c6ae02e07" + integrity sha512-8CWz4/H5FA+krm9HMw2HUQenizC/DxUtsI5oYC0Jxxyce1vsr8cb1aEiSJArQT6IzMynrERif1RVWLac1m36xw== dependencies: - "@algolia/requester-common" "4.15.0" - "@algolia/transporter" "4.15.0" + "@algolia/client-common" "4.19.1" + "@algolia/requester-common" "4.19.1" + "@algolia/transporter" "4.19.1" -"@algolia/client-personalization@4.15.0": - version "4.15.0" - resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-4.15.0.tgz#6f10eda827d2607ab6c2341464cd35107bf8cf99" - integrity sha512-Bf0bhRAiNL9LWurzyHRH8UBi4fDt3VbCNkInxVngKQT1uCZWXecwoPWGhcSSpdanBqFJA/1WBt+BWx7a50Bhlg== +"@algolia/client-search@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.19.1.tgz#5e54601aa5f5cea790cec3f2cde4af9d6403871e" + integrity sha512-mBecfMFS4N+yK/p0ZbK53vrZbL6OtWMk8YmnOv1i0LXx4pelY8TFhqKoTit3NPVPwoSNN0vdSN9dTu1xr1XOVw== dependencies: - "@algolia/client-common" "4.15.0" - "@algolia/requester-common" "4.15.0" - "@algolia/transporter" "4.15.0" - -"@algolia/client-search@4.15.0": - version "4.15.0" - resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.15.0.tgz#2d849faae7943fcc983ac923eac767666a9e6a9a" - integrity sha512-dTwZD4u53WdmexnMcoO2Qd/+YCP3ESXKOtD2MryQ1a9dHwB2Y3Qob0kyS1PG82idwM3enbznvscI9Sf4o9PUWQ== - dependencies: - "@algolia/client-common" "4.15.0" - "@algolia/requester-common" "4.15.0" - "@algolia/transporter" "4.15.0" + "@algolia/client-common" "4.19.1" + "@algolia/requester-common" "4.19.1" + "@algolia/transporter" "4.19.1" "@algolia/events@^4.0.1": version "4.0.1" resolved "https://registry.yarnpkg.com/@algolia/events/-/events-4.0.1.tgz#fd39e7477e7bc703d7f893b556f676c032af3950" integrity sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ== -"@algolia/logger-common@4.15.0": - version "4.15.0" - resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.15.0.tgz#a2cf3d3abbdd00594006164302600ba46d75059f" - integrity sha512-D8OFwn/HpvQz66goIcjxOKsYBMuxiruxJ3cA/bnc0EiDvSA2P2z6bNQWgS5gbstuTZIJmbhr+53NyOxFkmMNAA== +"@algolia/logger-common@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.19.1.tgz#0e46a11510f3e94e1afc0ac780ae52e9597be78f" + integrity sha512-i6pLPZW/+/YXKis8gpmSiNk1lOmYCmRI6+x6d2Qk1OdfvX051nRVdalRbEcVTpSQX6FQAoyeaui0cUfLYW5Elw== -"@algolia/logger-console@4.15.0": - version "4.15.0" - resolved "https://registry.yarnpkg.com/@algolia/logger-console/-/logger-console-4.15.0.tgz#8a0948b0c16ad546af9dd14b9021f21f42737c97" - integrity sha512-pQOvVaRSEJQJRXKTnxEA6nN1hipSQadJJ4einw0nIlfMOGZh/kps1ybh8vRUlUGyfEuN/3dyFs0W3Ac7hIItlg== +"@algolia/logger-console@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@algolia/logger-console/-/logger-console-4.19.1.tgz#656a6f4ebb5de39af6ef7095c398d9ab3cceb87d" + integrity sha512-jj72k9GKb9W0c7TyC3cuZtTr0CngLBLmc8trzZlXdfvQiigpUdvTi1KoWIb2ZMcRBG7Tl8hSb81zEY3zI2RlXg== dependencies: - "@algolia/logger-common" "4.15.0" + "@algolia/logger-common" "4.19.1" -"@algolia/requester-browser-xhr@4.15.0": - version "4.15.0" - resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.15.0.tgz#38b5956d01408ad4291d89915df921ff8534cca6" - integrity sha512-va186EfALF+6msYZXaoBSxcnFCg3SoWJ+uv1yMyhQRJRe7cZSHWSVT3s40vmar90gxlBu80KMVwVlsvJhJv6ew== +"@algolia/requester-browser-xhr@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.19.1.tgz#7341ea2f980b8980a2976110142026721e452187" + integrity sha512-09K/+t7lptsweRTueHnSnmPqIxbHMowejAkn9XIcJMLdseS3zl8ObnS5GWea86mu3vy4+8H+ZBKkUN82Zsq/zg== dependencies: - "@algolia/requester-common" "4.15.0" + "@algolia/requester-common" "4.19.1" -"@algolia/requester-common@4.15.0": - version "4.15.0" - resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.15.0.tgz#c68ad3dccc1de71b5be9b08a07e2baf58ec49d82" - integrity sha512-w0UUzxElbo4hrKg4QP/jiXDNbIJuAthxdlkos9nS8KAPK2XI3R9BlUjLz/ZVs4F9TDGI0mhjrNHhZ12KXcoyhg== +"@algolia/requester-common@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.19.1.tgz#f3396c77631b9d36e8d4d6f819a2c27f9ddbf7a1" + integrity sha512-BisRkcWVxrDzF1YPhAckmi2CFYK+jdMT60q10d7z3PX+w6fPPukxHRnZwooiTUrzFe50UBmLItGizWHP5bDzVQ== -"@algolia/requester-node-http@4.15.0": - version "4.15.0" - resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.15.0.tgz#02f841586e620c7b4e4e555f315cd52dd815f330" - integrity sha512-eeEOhFtgwKcgAlKAZpgBRZJ0ILSEBCXxZ9uwfVWPD24W1b6z08gVoTJ6J7lCeCnJmudg+tMElDnGzHkjup9CJA== +"@algolia/requester-node-http@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.19.1.tgz#ea210de9642628b3bdda1dd7fcd1fcb686da442e" + integrity sha512-6DK52DHviBHTG2BK/Vv2GIlEw7i+vxm7ypZW0Z7vybGCNDeWzADx+/TmxjkES2h15+FZOqVf/Ja677gePsVItA== dependencies: - "@algolia/requester-common" "4.15.0" + "@algolia/requester-common" "4.19.1" -"@algolia/transporter@4.15.0": - version "4.15.0" - resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.15.0.tgz#c65c512206c66aadc2897337220ae5454001967e" - integrity sha512-JoWR+ixG3EmA0UPntQFN/FV5TasYcYu93d5+oKzHFeZ6Z7rtW5Im9iy/Oh/ggk1AAN5fTdqKewtbBpdaYDbKsQ== +"@algolia/transporter@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.19.1.tgz#b5787299740c4bec9ba05502d98c14b5999860c8" + integrity sha512-nkpvPWbpuzxo1flEYqNIbGz7xhfhGOKGAZS7tzC+TELgEmi7z99qRyTfNSUlW7LZmB3ACdnqAo+9A9KFBENviQ== dependencies: - "@algolia/cache-common" "4.15.0" - "@algolia/logger-common" "4.15.0" - "@algolia/requester-common" "4.15.0" + "@algolia/cache-common" "4.19.1" + "@algolia/logger-common" "4.19.1" + "@algolia/requester-common" "4.19.1" -"@ampproject/remapping@2.2.0", "@ampproject/remapping@^2.1.0", "@ampproject/remapping@^2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" - integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== +"@alloc/quick-lru@^5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30" + integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== + +"@ampproject/remapping@^2.2.0": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" + integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== dependencies: - "@jridgewell/gen-mapping" "^0.1.0" + "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" -"@apidevtools/json-schema-ref-parser@^9.0.9": - version "9.1.2" - resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz#8ff5386b365d4c9faa7c8b566ff16a46a577d9b8" - integrity sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg== +"@apidevtools/json-schema-ref-parser@^10.1.0": + version "10.1.0" + resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-10.1.0.tgz#bf54494039a56fa7f77fed17dc6f01dfde50f64c" + integrity sha512-3e+viyMuXdrcK8v5pvP+SDoAQ77FH6OyRmuK48SZKmdHJRFm87RsSs8qm6kP39a/pOPURByJw+OXzQIqcfmKtA== dependencies: "@jsdevtools/ono" "^7.1.3" - "@types/json-schema" "^7.0.6" - call-me-maybe "^1.0.1" + "@types/json-schema" "^7.0.11" + "@types/lodash.clonedeep" "^4.5.7" js-yaml "^4.1.0" + lodash.clonedeep "^4.5.0" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.16.0", "@babel/code-frame@^7.16.7", "@babel/code-frame@^7.18.6", "@babel/code-frame@^7.8.3": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" - integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.16.0", "@babel/code-frame@^7.22.5", "@babel/code-frame@^7.8.3": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.5.tgz#234d98e1551960604f1246e6475891a570ad5658" + integrity sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ== dependencies: - "@babel/highlight" "^7.18.6" + "@babel/highlight" "^7.22.5" -"@babel/compat-data@^7.17.0", "@babel/compat-data@^7.17.10", "@babel/compat-data@^7.17.7", "@babel/compat-data@^7.20.1", "@babel/compat-data@^7.20.5": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.21.0.tgz#c241dc454e5b5917e40d37e525e2f4530c399298" - integrity sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g== +"@babel/compat-data@^7.22.5", "@babel/compat-data@^7.22.6", "@babel/compat-data@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.9.tgz#71cdb00a1ce3a329ce4cbec3a44f9fef35669730" + integrity sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ== "@babel/core@7.12.9": version "7.12.9" @@ -201,389 +196,260 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/core@7.17.10": - version "7.17.10" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.10.tgz#74ef0fbf56b7dfc3f198fc2d927f4f03e12f4b05" - integrity sha512-liKoppandF3ZcBnIYFjfSDHZLKdLHGJRkoWtG8zQyGJBQfIYobpnVGI5+pLBNtS6psFLDzyq8+h5HiVljW9PNA== - dependencies: - "@ampproject/remapping" "^2.1.0" - "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.17.10" - "@babel/helper-compilation-targets" "^7.17.10" - "@babel/helper-module-transforms" "^7.17.7" - "@babel/helpers" "^7.17.9" - "@babel/parser" "^7.17.10" - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.17.10" - "@babel/types" "^7.17.10" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.1" - semver "^6.3.0" - "@babel/core@^7.18.6", "@babel/core@^7.19.6": - version "7.21.3" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.21.3.tgz#cf1c877284a469da5d1ce1d1e53665253fae712e" - integrity sha512-qIJONzoa/qiHghnm0l1n4i/6IIziDpzqc36FBs4pzMhDUraHqponwJLiAKm1hGLP3OSB/TVNz6rMwVGpwxxySw== + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.9.tgz#bd96492c68822198f33e8a256061da3cf391f58f" + integrity sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w== dependencies: "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.18.6" - "@babel/generator" "^7.21.3" - "@babel/helper-compilation-targets" "^7.20.7" - "@babel/helper-module-transforms" "^7.21.2" - "@babel/helpers" "^7.21.0" - "@babel/parser" "^7.21.3" - "@babel/template" "^7.20.7" - "@babel/traverse" "^7.21.3" - "@babel/types" "^7.21.3" + "@babel/code-frame" "^7.22.5" + "@babel/generator" "^7.22.9" + "@babel/helper-compilation-targets" "^7.22.9" + "@babel/helper-module-transforms" "^7.22.9" + "@babel/helpers" "^7.22.6" + "@babel/parser" "^7.22.7" + "@babel/template" "^7.22.5" + "@babel/traverse" "^7.22.8" + "@babel/types" "^7.22.5" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.2.2" - semver "^6.3.0" + semver "^6.3.1" -"@babel/generator@^7.12.5", "@babel/generator@^7.17.10", "@babel/generator@^7.18.7", "@babel/generator@^7.21.3": - version "7.21.3" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.21.3.tgz#232359d0874b392df04045d72ce2fd9bb5045fce" - integrity sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA== +"@babel/generator@^7.12.5", "@babel/generator@^7.18.7", "@babel/generator@^7.22.7", "@babel/generator@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.9.tgz#572ecfa7a31002fa1de2a9d91621fd895da8493d" + integrity sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw== dependencies: - "@babel/types" "^7.21.3" + "@babel/types" "^7.22.5" "@jridgewell/gen-mapping" "^0.3.2" "@jridgewell/trace-mapping" "^0.3.17" jsesc "^2.5.1" -"@babel/helper-annotate-as-pure@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb" - integrity sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA== +"@babel/helper-annotate-as-pure@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz#e7f06737b197d580a01edf75d97e2c8be99d3882" + integrity sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg== dependencies: - "@babel/types" "^7.18.6" + "@babel/types" "^7.22.5" -"@babel/helper-builder-binary-assignment-operator-visitor@^7.18.6": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz#acd4edfd7a566d1d51ea975dff38fd52906981bb" - integrity sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw== +"@babel/helper-builder-binary-assignment-operator-visitor@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.5.tgz#a3f4758efdd0190d8927fcffd261755937c71878" + integrity sha512-m1EP3lVOPptR+2DwD125gziZNcmoNSHGmJROKoy87loWUQyJaVXDgpmruWqDARZSmtYQ+Dl25okU8+qhVzuykw== dependencies: - "@babel/helper-explode-assignable-expression" "^7.18.6" - "@babel/types" "^7.18.9" + "@babel/types" "^7.22.5" -"@babel/helper-compilation-targets@^7.16.7", "@babel/helper-compilation-targets@^7.17.10", "@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.18.9", "@babel/helper-compilation-targets@^7.20.0", "@babel/helper-compilation-targets@^7.20.7": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz#a6cd33e93629f5eb473b021aac05df62c4cd09bb" - integrity sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ== +"@babel/helper-compilation-targets@^7.22.5", "@babel/helper-compilation-targets@^7.22.6", "@babel/helper-compilation-targets@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.9.tgz#f9d0a7aaaa7cd32a3f31c9316a69f5a9bcacb892" + integrity sha512-7qYrNM6HjpnPHJbopxmb8hSPoZ0gsX8IvUS32JGVoy+pU9e5N0nLr1VjJoR6kA4d9dmGLxNYOjeB8sUDal2WMw== dependencies: - "@babel/compat-data" "^7.20.5" - "@babel/helper-validator-option" "^7.18.6" - browserslist "^4.21.3" + "@babel/compat-data" "^7.22.9" + "@babel/helper-validator-option" "^7.22.5" + browserslist "^4.21.9" lru-cache "^5.1.1" - semver "^6.3.0" + semver "^6.3.1" -"@babel/helper-create-class-features-plugin@^7.16.10", "@babel/helper-create-class-features-plugin@^7.17.6", "@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.21.0": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.21.0.tgz#64f49ecb0020532f19b1d014b03bccaa1ab85fb9" - integrity sha512-Q8wNiMIdwsv5la5SPxNYzzkPnjgC0Sy0i7jLkVOCdllu/xcVNkr3TeZzbHBJrj+XXRqzX5uCyCoV9eu6xUG7KQ== +"@babel/helper-create-class-features-plugin@^7.22.5", "@babel/helper-create-class-features-plugin@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.9.tgz#c36ea240bb3348f942f08b0fbe28d6d979fab236" + integrity sha512-Pwyi89uO4YrGKxL/eNJ8lfEH55DnRloGPOseaA8NFNL6jAUnn+KccaISiFazCj5IolPPDjGSdzQzXVzODVRqUQ== dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-function-name" "^7.21.0" - "@babel/helper-member-expression-to-functions" "^7.21.0" - "@babel/helper-optimise-call-expression" "^7.18.6" - "@babel/helper-replace-supers" "^7.20.7" - "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" - "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-member-expression-to-functions" "^7.22.5" + "@babel/helper-optimise-call-expression" "^7.22.5" + "@babel/helper-replace-supers" "^7.22.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + semver "^6.3.1" -"@babel/helper-create-regexp-features-plugin@^7.17.0", "@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.20.5": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.21.0.tgz#53ff78472e5ce10a52664272a239787107603ebb" - integrity sha512-N+LaFW/auRSWdx7SHD/HiARwXQju1vXTW4fKr4u5SgBUTm51OKEjKgj+cs00ggW3kEvNqwErnlwuq7Y3xBe4eg== +"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.22.5": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.9.tgz#9d8e61a8d9366fe66198f57c40565663de0825f6" + integrity sha512-+svjVa/tFwsNSG4NEy1h85+HQ5imbT92Q5/bgtS7P0GTQlP8WuFdqsiABmQouhiFGyV66oGxZFpeYHza1rNsKw== dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-annotate-as-pure" "^7.22.5" regexpu-core "^5.3.1" + semver "^6.3.1" -"@babel/helper-define-polyfill-provider@^0.3.1", "@babel/helper-define-polyfill-provider@^0.3.2", "@babel/helper-define-polyfill-provider@^0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz#8612e55be5d51f0cd1f36b4a5a83924e89884b7a" - integrity sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww== +"@babel/helper-define-polyfill-provider@^0.4.2": + version "0.4.2" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.2.tgz#82c825cadeeeee7aad237618ebbe8fa1710015d7" + integrity sha512-k0qnnOqHn5dK9pZpfD5XXZ9SojAITdCKRn2Lp6rnDGzIbaP0rHyMPk/4wsSxVBVz4RfN0q6VpXWP2pDGIoQ7hw== dependencies: - "@babel/helper-compilation-targets" "^7.17.7" - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-compilation-targets" "^7.22.6" + "@babel/helper-plugin-utils" "^7.22.5" debug "^4.1.1" lodash.debounce "^4.0.8" resolve "^1.14.2" - semver "^6.1.2" -"@babel/helper-environment-visitor@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be" - integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== +"@babel/helper-environment-visitor@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz#f06dd41b7c1f44e1f8da6c4055b41ab3a09a7e98" + integrity sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q== -"@babel/helper-explode-assignable-expression@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz#41f8228ef0a6f1a036b8dfdfec7ce94f9a6bc096" - integrity sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg== +"@babel/helper-function-name@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz#ede300828905bb15e582c037162f99d5183af1be" + integrity sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ== dependencies: - "@babel/types" "^7.18.6" + "@babel/template" "^7.22.5" + "@babel/types" "^7.22.5" -"@babel/helper-function-name@^7.18.9", "@babel/helper-function-name@^7.19.0", "@babel/helper-function-name@^7.21.0": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz#d552829b10ea9f120969304023cd0645fa00b1b4" - integrity sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg== +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== dependencies: - "@babel/template" "^7.20.7" - "@babel/types" "^7.21.0" + "@babel/types" "^7.22.5" -"@babel/helper-hoist-variables@^7.16.7", "@babel/helper-hoist-variables@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" - integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== +"@babel/helper-member-expression-to-functions@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.5.tgz#0a7c56117cad3372fbf8d2fb4bf8f8d64a1e76b2" + integrity sha512-aBiH1NKMG0H2cGZqspNvsaBe6wNGjbJjuLy29aU+eDZjSbbN53BaxlpB02xm9v34pLTZ1nIQPFYn2qMZoa5BQQ== dependencies: - "@babel/types" "^7.18.6" + "@babel/types" "^7.22.5" -"@babel/helper-member-expression-to-functions@^7.20.7", "@babel/helper-member-expression-to-functions@^7.21.0": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.21.0.tgz#319c6a940431a133897148515877d2f3269c3ba5" - integrity sha512-Muu8cdZwNN6mRRNG6lAYErJ5X3bRevgYR2O8wN0yn7jJSnGDu6eG59RfT29JHxGUovyfrh6Pj0XzmR7drNVL3Q== +"@babel/helper-module-imports@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz#1a8f4c9f4027d23f520bd76b364d44434a72660c" + integrity sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg== dependencies: - "@babel/types" "^7.21.0" + "@babel/types" "^7.22.5" -"@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" - integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== +"@babel/helper-module-transforms@^7.12.1", "@babel/helper-module-transforms@^7.22.5", "@babel/helper-module-transforms@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz#92dfcb1fbbb2bc62529024f72d942a8c97142129" + integrity sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ== dependencies: - "@babel/types" "^7.18.6" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-module-imports" "^7.22.5" + "@babel/helper-simple-access" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/helper-validator-identifier" "^7.22.5" -"@babel/helper-module-transforms@^7.12.1", "@babel/helper-module-transforms@^7.17.7", "@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.20.11", "@babel/helper-module-transforms@^7.21.2": - version "7.21.2" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz#160caafa4978ac8c00ac66636cb0fa37b024e2d2" - integrity sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ== +"@babel/helper-optimise-call-expression@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz#f21531a9ccbff644fdd156b4077c16ff0c3f609e" + integrity sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw== dependencies: - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-module-imports" "^7.18.6" - "@babel/helper-simple-access" "^7.20.2" - "@babel/helper-split-export-declaration" "^7.18.6" - "@babel/helper-validator-identifier" "^7.19.1" - "@babel/template" "^7.20.7" - "@babel/traverse" "^7.21.2" - "@babel/types" "^7.21.2" - -"@babel/helper-optimise-call-expression@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz#9369aa943ee7da47edab2cb4e838acf09d290ffe" - integrity sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA== - dependencies: - "@babel/types" "^7.18.6" + "@babel/types" "^7.22.5" "@babel/helper-plugin-utils@7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.19.0", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.20.2" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz#d1b9000752b18d0877cff85a5c376ce5c3121629" - integrity sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ== +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" + integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== -"@babel/helper-remap-async-to-generator@^7.16.8", "@babel/helper-remap-async-to-generator@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz#997458a0e3357080e54e1d79ec347f8a8cd28519" - integrity sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA== +"@babel/helper-remap-async-to-generator@^7.22.5": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.9.tgz#53a25b7484e722d7efb9c350c75c032d4628de82" + integrity sha512-8WWC4oR4Px+tr+Fp0X3RHDVfINGpF3ad1HIbrc8A77epiR6eMMc6jsgozkzT2uDiOOdoS9cLIQ+XD2XvI2WSmQ== dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-wrap-function" "^7.18.9" - "@babel/types" "^7.18.9" + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-wrap-function" "^7.22.9" -"@babel/helper-replace-supers@^7.18.6", "@babel/helper-replace-supers@^7.20.7": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz#243ecd2724d2071532b2c8ad2f0f9f083bcae331" - integrity sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A== +"@babel/helper-replace-supers@^7.22.5", "@babel/helper-replace-supers@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.22.9.tgz#cbdc27d6d8d18cd22c81ae4293765a5d9afd0779" + integrity sha512-LJIKvvpgPOPUThdYqcX6IXRuIcTkcAub0IaDRGCZH0p5GPUp7PhRU9QVgFcDDd51BaPkk77ZjqFwh6DZTAEmGg== dependencies: - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-member-expression-to-functions" "^7.20.7" - "@babel/helper-optimise-call-expression" "^7.18.6" - "@babel/template" "^7.20.7" - "@babel/traverse" "^7.20.7" - "@babel/types" "^7.20.7" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-member-expression-to-functions" "^7.22.5" + "@babel/helper-optimise-call-expression" "^7.22.5" -"@babel/helper-simple-access@^7.17.7", "@babel/helper-simple-access@^7.20.2": - version "7.20.2" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz#0ab452687fe0c2cfb1e2b9e0015de07fc2d62dd9" - integrity sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA== +"@babel/helper-simple-access@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" + integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== dependencies: - "@babel/types" "^7.20.2" + "@babel/types" "^7.22.5" -"@babel/helper-skip-transparent-expression-wrappers@^7.20.0": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz#fbe4c52f60518cab8140d77101f0e63a8a230684" - integrity sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg== +"@babel/helper-skip-transparent-expression-wrappers@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz#007f15240b5751c537c40e77abb4e89eeaaa8847" + integrity sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q== dependencies: - "@babel/types" "^7.20.0" + "@babel/types" "^7.22.5" -"@babel/helper-split-export-declaration@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" - integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== +"@babel/helper-split-export-declaration@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" + integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== dependencies: - "@babel/types" "^7.18.6" + "@babel/types" "^7.22.5" -"@babel/helper-string-parser@^7.19.4": - version "7.19.4" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63" - integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw== +"@babel/helper-string-parser@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" + integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== -"@babel/helper-validator-identifier@^7.16.7", "@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": - version "7.19.1" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" - integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== +"@babel/helper-validator-identifier@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193" + integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ== -"@babel/helper-validator-option@^7.16.7", "@babel/helper-validator-option@^7.18.6", "@babel/helper-validator-option@^7.21.0": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz#8224c7e13ace4bafdc4004da2cf064ef42673180" - integrity sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ== +"@babel/helper-validator-option@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz#de52000a15a177413c8234fa3a8af4ee8102d0ac" + integrity sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw== -"@babel/helper-wrap-function@^7.18.9": - version "7.20.5" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz#75e2d84d499a0ab3b31c33bcfe59d6b8a45f62e3" - integrity sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q== +"@babel/helper-wrap-function@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.22.9.tgz#189937248c45b0182c1dcf32f3444ca153944cb9" + integrity sha512-sZ+QzfauuUEfxSEjKFmi3qDSHgLsTPK/pEpoD/qonZKOtTPTLbf59oabPQ4rKekt9lFcj/hTZaOhWwFYrgjk+Q== dependencies: - "@babel/helper-function-name" "^7.19.0" - "@babel/template" "^7.18.10" - "@babel/traverse" "^7.20.5" - "@babel/types" "^7.20.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/template" "^7.22.5" + "@babel/types" "^7.22.5" -"@babel/helpers@^7.12.5", "@babel/helpers@^7.17.9", "@babel/helpers@^7.21.0": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.21.0.tgz#9dd184fb5599862037917cdc9eecb84577dc4e7e" - integrity sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA== +"@babel/helpers@^7.12.5", "@babel/helpers@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.6.tgz#8e61d3395a4f0c5a8060f309fb008200969b5ecd" + integrity sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA== dependencies: - "@babel/template" "^7.20.7" - "@babel/traverse" "^7.21.0" - "@babel/types" "^7.21.0" + "@babel/template" "^7.22.5" + "@babel/traverse" "^7.22.6" + "@babel/types" "^7.22.5" -"@babel/highlight@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" - integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== +"@babel/highlight@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.5.tgz#aa6c05c5407a67ebce408162b7ede789b4d22031" + integrity sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw== dependencies: - "@babel/helper-validator-identifier" "^7.18.6" + "@babel/helper-validator-identifier" "^7.22.5" chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.12.7", "@babel/parser@^7.17.10", "@babel/parser@^7.18.8", "@babel/parser@^7.20.7", "@babel/parser@^7.21.3": - version "7.21.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.3.tgz#1d285d67a19162ff9daa358d4cb41d50c06220b3" - integrity sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ== +"@babel/parser@^7.12.7", "@babel/parser@^7.18.8", "@babel/parser@^7.22.5", "@babel/parser@^7.22.7": + version "7.22.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.7.tgz#df8cf085ce92ddbdbf668a7f186ce848c9036cae" + integrity sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q== -"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.7", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz#da5b8f9a580acdfbe53494dba45ea389fb09a4d2" - integrity sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ== +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.5.tgz#87245a21cd69a73b0b81bcda98d443d6df08f05e" + integrity sha512-NP1M5Rf+u2Gw9qfSO4ihjcTGW5zXTi36ITLd4/EoAcEhIZ0yjMqmftDNl3QC19CX7olhrjpyU454g/2W7X0jvQ== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.16.7", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.18.9": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.20.7.tgz#d9c85589258539a22a901033853101a6198d4ef1" - integrity sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ== +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.5.tgz#fef09f9499b1f1c930da8a0c419db42167d792ca" + integrity sha512-31Bb65aZaUwqCbWMnZPduIZxCBngHFlzyN6Dq6KAJjtx+lx6ohKHubc61OomYi7XwVD4Ol0XCVz4h+pYFR048g== dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" - "@babel/plugin-proposal-optional-chaining" "^7.20.7" - -"@babel/plugin-proposal-async-generator-functions@7.16.8": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz#3bdd1ebbe620804ea9416706cd67d60787504bc8" - integrity sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-remap-async-to-generator" "^7.16.8" - "@babel/plugin-syntax-async-generators" "^7.8.4" - -"@babel/plugin-proposal-async-generator-functions@^7.16.8", "@babel/plugin-proposal-async-generator-functions@^7.20.1": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz#bfb7276d2d573cb67ba379984a2334e262ba5326" - integrity sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA== - dependencies: - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-remap-async-to-generator" "^7.18.9" - "@babel/plugin-syntax-async-generators" "^7.8.4" - -"@babel/plugin-proposal-class-properties@^7.16.7", "@babel/plugin-proposal-class-properties@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz#b110f59741895f7ec21a6fff696ec46265c446a3" - integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-proposal-class-static-block@7.17.6": - version "7.17.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.17.6.tgz#164e8fd25f0d80fa48c5a4d1438a6629325ad83c" - integrity sha512-X/tididvL2zbs7jZCeeRJ8167U/+Ac135AM6jCAx6gYXDUviZV5Ku9UDvWS2NCuWlFjIRXklYhwo6HhAC7ETnA== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.17.6" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-class-static-block" "^7.14.5" - -"@babel/plugin-proposal-class-static-block@^7.17.6", "@babel/plugin-proposal-class-static-block@^7.18.6": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.21.0.tgz#77bdd66fb7b605f3a61302d224bdfacf5547977d" - integrity sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.21.0" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/plugin-syntax-class-static-block" "^7.14.5" - -"@babel/plugin-proposal-dynamic-import@^7.16.7", "@babel/plugin-proposal-dynamic-import@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz#72bcf8d408799f547d759298c3c27c7e7faa4d94" - integrity sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - -"@babel/plugin-proposal-export-namespace-from@^7.16.7", "@babel/plugin-proposal-export-namespace-from@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz#5f7313ab348cdb19d590145f9247540e94761203" - integrity sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA== - dependencies: - "@babel/helper-plugin-utils" "^7.18.9" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - -"@babel/plugin-proposal-json-strings@^7.16.7", "@babel/plugin-proposal-json-strings@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz#7e8788c1811c393aff762817e7dbf1ebd0c05f0b" - integrity sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-json-strings" "^7.8.3" - -"@babel/plugin-proposal-logical-assignment-operators@^7.16.7", "@babel/plugin-proposal-logical-assignment-operators@^7.18.9": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz#dfbcaa8f7b4d37b51e8bfb46d94a5aea2bb89d83" - integrity sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - -"@babel/plugin-proposal-nullish-coalescing-operator@^7.16.7", "@babel/plugin-proposal-nullish-coalescing-operator@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz#fdd940a99a740e577d6c753ab6fbb43fdb9467e1" - integrity sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - -"@babel/plugin-proposal-numeric-separator@^7.16.7", "@babel/plugin-proposal-numeric-separator@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz#899b14fbafe87f053d2c5ff05b36029c62e13c75" - integrity sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/plugin-transform-optional-chaining" "^7.22.5" "@babel/plugin-proposal-object-rest-spread@7.12.1": version "7.12.1" @@ -594,72 +460,12 @@ "@babel/plugin-syntax-object-rest-spread" "^7.8.0" "@babel/plugin-transform-parameters" "^7.12.1" -"@babel/plugin-proposal-object-rest-spread@7.17.3": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.3.tgz#d9eb649a54628a51701aef7e0ea3d17e2b9dd390" - integrity sha512-yuL5iQA/TbZn+RGAfxQXfi7CNLmKi1f8zInn4IgobuCWcAb7i+zj4TYzQ9l8cEzVyJ89PDGuqxK1xZpUDISesw== - dependencies: - "@babel/compat-data" "^7.17.0" - "@babel/helper-compilation-targets" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.16.7" +"@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2": + version "7.21.0-placeholder-for-preset-env.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703" + integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w== -"@babel/plugin-proposal-object-rest-spread@^7.17.3", "@babel/plugin-proposal-object-rest-spread@^7.20.2": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz#aa662940ef425779c75534a5c41e9d936edc390a" - integrity sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg== - dependencies: - "@babel/compat-data" "^7.20.5" - "@babel/helper-compilation-targets" "^7.20.7" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.20.7" - -"@babel/plugin-proposal-optional-catch-binding@^7.16.7", "@babel/plugin-proposal-optional-catch-binding@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz#f9400d0e6a3ea93ba9ef70b09e72dd6da638a2cb" - integrity sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - -"@babel/plugin-proposal-optional-chaining@^7.16.7", "@babel/plugin-proposal-optional-chaining@^7.18.9", "@babel/plugin-proposal-optional-chaining@^7.20.7": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz#886f5c8978deb7d30f678b2e24346b287234d3ea" - integrity sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - -"@babel/plugin-proposal-private-methods@7.16.11": - version "7.16.11" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz#e8df108288555ff259f4527dbe84813aac3a1c50" - integrity sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.16.10" - "@babel/helper-plugin-utils" "^7.16.7" - -"@babel/plugin-proposal-private-methods@^7.16.11", "@babel/plugin-proposal-private-methods@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz#5209de7d213457548a98436fa2882f52f4be6bea" - integrity sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-proposal-private-property-in-object@^7.16.7", "@babel/plugin-proposal-private-property-in-object@^7.18.6": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0.tgz#19496bd9883dd83c23c7d7fc45dcd9ad02dfa1dc" - integrity sha512-ha4zfehbJjc5MmXBlHec1igel5TJXXLDDRbuJ4+XT2TJcyD9/V1919BA8gMvsdHcNMBy4WBUBiRb3nw/EQUtBw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-create-class-features-plugin" "^7.21.0" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/plugin-syntax-private-property-in-object" "^7.14.5" - -"@babel/plugin-proposal-unicode-property-regex@^7.16.7", "@babel/plugin-proposal-unicode-property-regex@^7.18.6", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": +"@babel/plugin-proposal-unicode-property-regex@^7.4.4": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz#af613d2cd5e643643b65cded64207b15c85cb78e" integrity sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w== @@ -702,12 +508,26 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-syntax-import-assertions@^7.20.0": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz#bb50e0d4bea0957235390641209394e87bdb9cc4" - integrity sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ== +"@babel/plugin-syntax-import-assertions@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.22.5.tgz#07d252e2aa0bc6125567f742cd58619cb14dce98" + integrity sha512-rdV97N7KqsRzeNGoWUOK6yUsWarLjE5Su/Snk9IYPU9CwkWHs4t+rTGOvffTR8XGkJMTAdLfO0xVnXm8wugIJg== dependencies: - "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-import-attributes@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.22.5.tgz#ab840248d834410b829f569f5262b9e517555ecb" + integrity sha512-KwvoWDeNKPETmozyFE0P2rOLqh39EoQHNjqizrI5B8Vt0ZNS7M56s7dAiAqbYfiAYOuIzIh96z3iR2ktgu3tEg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-import-meta@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-json-strings@^7.8.3": version "7.8.3" @@ -723,12 +543,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-jsx@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz#a8feef63b010150abd97f1649ec296e849943ca0" - integrity sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q== +"@babel/plugin-syntax-jsx@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz#a6b68e84fb76e759fc3b93e901876ffabbe1d918" + integrity sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-logical-assignment-operators@^7.10.4": version "7.10.4" @@ -786,501 +606,491 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-typescript@^7.20.0": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz#4e9a0cfc769c85689b77a2e642d24e9f697fc8c7" - integrity sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ== +"@babel/plugin-syntax-typescript@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz#aac8d383b062c5072c647a31ef990c1d0af90272" + integrity sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ== dependencies: - "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-arrow-functions@^7.16.7", "@babel/plugin-transform-arrow-functions@^7.18.6": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.20.7.tgz#bea332b0e8b2dab3dafe55a163d8227531ab0551" - integrity sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - -"@babel/plugin-transform-async-to-generator@7.16.8": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz#b83dff4b970cf41f1b819f8b49cc0cfbaa53a808" - integrity sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg== - dependencies: - "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-remap-async-to-generator" "^7.16.8" - -"@babel/plugin-transform-async-to-generator@^7.16.8", "@babel/plugin-transform-async-to-generator@^7.18.6": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz#dfee18623c8cb31deb796aa3ca84dda9cea94354" - integrity sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q== - dependencies: - "@babel/helper-module-imports" "^7.18.6" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-remap-async-to-generator" "^7.18.9" - -"@babel/plugin-transform-block-scoped-functions@^7.16.7", "@babel/plugin-transform-block-scoped-functions@^7.18.6": +"@babel/plugin-syntax-unicode-sets-regex@^7.18.6": version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz#9187bf4ba302635b9d70d986ad70f038726216a8" - integrity sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ== + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz#d49a3b3e6b52e5be6740022317580234a6a47357" + integrity sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg== dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-block-scoping@^7.16.7", "@babel/plugin-transform-block-scoping@^7.20.2": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.21.0.tgz#e737b91037e5186ee16b76e7ae093358a5634f02" - integrity sha512-Mdrbunoh9SxwFZapeHVrwFmri16+oYotcZysSzhNIVDwIAb1UV+kvnxULSYq9J3/q5MDG+4X6w8QVgD1zhBXNQ== +"@babel/plugin-transform-arrow-functions@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.22.5.tgz#e5ba566d0c58a5b2ba2a8b795450641950b71958" + integrity sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw== dependencies: - "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-classes@^7.16.7", "@babel/plugin-transform-classes@^7.20.2": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.21.0.tgz#f469d0b07a4c5a7dbb21afad9e27e57b47031665" - integrity sha512-RZhbYTCEUAe6ntPehC4hlslPWosNHDox+vAs4On/mCLRLfoDVHf6hVEd7kuxr1RnHwJmxFfUM3cZiZRmPxJPXQ== +"@babel/plugin-transform-async-generator-functions@^7.22.7": + version "7.22.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.7.tgz#053e76c0a903b72b573cb1ab7d6882174d460a1b" + integrity sha512-7HmE7pk/Fmke45TODvxvkxRMV9RazV+ZZzhOL9AG8G29TLrr3jkjwF7uJfxZ30EoXpO+LJkq4oA8NjO2DTnEDg== dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-compilation-targets" "^7.20.7" - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-function-name" "^7.21.0" - "@babel/helper-optimise-call-expression" "^7.18.6" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-replace-supers" "^7.20.7" - "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-remap-async-to-generator" "^7.22.5" + "@babel/plugin-syntax-async-generators" "^7.8.4" + +"@babel/plugin-transform-async-to-generator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.22.5.tgz#c7a85f44e46f8952f6d27fe57c2ed3cc084c3775" + integrity sha512-b1A8D8ZzE/VhNDoV1MSJTnpKkCG5bJo+19R4o4oy03zM7ws8yEMK755j61Dc3EyvdysbqH5BOOTquJ7ZX9C6vQ== + dependencies: + "@babel/helper-module-imports" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-remap-async-to-generator" "^7.22.5" + +"@babel/plugin-transform-block-scoped-functions@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.22.5.tgz#27978075bfaeb9fa586d3cb63a3d30c1de580024" + integrity sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-block-scoping@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.5.tgz#8bfc793b3a4b2742c0983fadc1480d843ecea31b" + integrity sha512-EcACl1i5fSQ6bt+YGuU/XGCeZKStLmyVGytWkpyhCLeQVA0eu6Wtiw92V+I1T/hnezUv7j74dA/Ro69gWcU+hg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-class-properties@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.22.5.tgz#97a56e31ad8c9dc06a0b3710ce7803d5a48cca77" + integrity sha512-nDkQ0NfkOhPTq8YCLiWNxp1+f9fCobEjCb0n8WdbNUBc4IB5V7P1QnX9IjpSoquKrXF5SKojHleVNs2vGeHCHQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-class-static-block@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.5.tgz#3e40c46f048403472d6f4183116d5e46b1bff5ba" + integrity sha512-SPToJ5eYZLxlnp1UzdARpOGeC2GbHvr9d/UV0EukuVx8atktg194oe+C5BqQ8jRTkgLRVOPYeXRSBg1IlMoVRA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + +"@babel/plugin-transform-classes@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.6.tgz#e04d7d804ed5b8501311293d1a0e6d43e94c3363" + integrity sha512-58EgM6nuPNG6Py4Z3zSuu0xWu2VfodiMi72Jt5Kj2FECmaYk1RrTXA45z6KBFsu9tRgwQDwIiY4FXTt+YsSFAQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-compilation-targets" "^7.22.6" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-optimise-call-expression" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-replace-supers" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" globals "^11.1.0" -"@babel/plugin-transform-computed-properties@^7.16.7", "@babel/plugin-transform-computed-properties@^7.18.9": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.20.7.tgz#704cc2fd155d1c996551db8276d55b9d46e4d0aa" - integrity sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ== +"@babel/plugin-transform-computed-properties@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz#cd1e994bf9f316bd1c2dafcd02063ec261bb3869" + integrity sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg== dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/template" "^7.20.7" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/template" "^7.22.5" -"@babel/plugin-transform-destructuring@7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.7.tgz#49dc2675a7afa9a5e4c6bdee636061136c3408d1" - integrity sha512-XVh0r5yq9sLR4vZ6eVZe8FKfIcSgaTBxVBRSYokRj2qksf6QerYnTxz9/GTuKTH/n/HwLP7t6gtlybHetJ/6hQ== +"@babel/plugin-transform-destructuring@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.5.tgz#d3aca7438f6c26c78cdd0b0ba920a336001b27cc" + integrity sha512-GfqcFuGW8vnEqTUBM7UtPd5A4q797LTvvwKxXTgRsFjoqaJiEg9deBG6kWeQYkVEL569NpnmpC0Pkr/8BLKGnQ== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-destructuring@^7.17.7", "@babel/plugin-transform-destructuring@^7.20.2": - version "7.21.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.21.3.tgz#73b46d0fd11cd6ef57dea8a381b1215f4959d401" - integrity sha512-bp6hwMFzuiE4HqYEyoGJ/V2LeIWn+hLVKc4pnj++E5XQptwhtcGmSayM029d/j2X1bPKGTlsyPwAubuU22KhMA== +"@babel/plugin-transform-dotall-regex@^7.22.5", "@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.22.5.tgz#dbb4f0e45766eb544e193fb00e65a1dd3b2a4165" + integrity sha512-5/Yk9QxCQCl+sOIB1WelKnVRxTJDSAIxtJLL2/pqL14ZVlbH0fUQUZa/T5/UnQtBNgghR7mfB8ERBKyKPCi7Vw== dependencies: - "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-dotall-regex@^7.16.7", "@babel/plugin-transform-dotall-regex@^7.18.6", "@babel/plugin-transform-dotall-regex@^7.4.4": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz#b286b3e7aae6c7b861e45bed0a2fafd6b1a4fef8" - integrity sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg== +"@babel/plugin-transform-duplicate-keys@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.22.5.tgz#b6e6428d9416f5f0bba19c70d1e6e7e0b88ab285" + integrity sha512-dEnYD+9BBgld5VBXHnF/DbYGp3fqGMsyxKbtD1mDyIA7AkTSpKXFhCVuj/oQVOoALfBs77DudA0BE4d5mcpmqw== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-duplicate-keys@^7.16.7", "@babel/plugin-transform-duplicate-keys@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz#687f15ee3cdad6d85191eb2a372c4528eaa0ae0e" - integrity sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw== +"@babel/plugin-transform-dynamic-import@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.5.tgz#d6908a8916a810468c4edff73b5b75bda6ad393e" + integrity sha512-0MC3ppTB1AMxd8fXjSrbPa7LT9hrImt+/fcj+Pg5YMD7UQyWp/02+JWpdnCymmsXwIx5Z+sYn1bwCn4ZJNvhqQ== dependencies: - "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" -"@babel/plugin-transform-exponentiation-operator@^7.16.7", "@babel/plugin-transform-exponentiation-operator@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz#421c705f4521888c65e91fdd1af951bfefd4dacd" - integrity sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw== +"@babel/plugin-transform-exponentiation-operator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.22.5.tgz#402432ad544a1f9a480da865fda26be653e48f6a" + integrity sha512-vIpJFNM/FjZ4rh1myqIya9jXwrwwgFRHPjT3DkUA9ZLHuzox8jiXkOLvwm1H+PQIP3CqfC++WPKeuDi0Sjdj1g== dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-for-of@^7.16.7", "@babel/plugin-transform-for-of@^7.18.8": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.21.0.tgz#964108c9988de1a60b4be2354a7d7e245f36e86e" - integrity sha512-LlUYlydgDkKpIY7mcBWvyPPmMcOphEyYA27Ef4xpbh1IiDNLr0kZsos2nf92vz3IccvJI25QUwp86Eo5s6HmBQ== +"@babel/plugin-transform-export-namespace-from@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.5.tgz#57c41cb1d0613d22f548fddd8b288eedb9973a5b" + integrity sha512-X4hhm7FRnPgd4nDA4b/5V280xCx6oL7Oob5+9qVS5C13Zq4bh1qq7LU0GgRU6b5dBWBvhGaXYVB4AcN6+ol6vg== dependencies: - "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" -"@babel/plugin-transform-function-name@^7.16.7", "@babel/plugin-transform-function-name@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz#cc354f8234e62968946c61a46d6365440fc764e0" - integrity sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ== +"@babel/plugin-transform-for-of@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.5.tgz#ab1b8a200a8f990137aff9a084f8de4099ab173f" + integrity sha512-3kxQjX1dU9uudwSshyLeEipvrLjBCVthCgeTp6CzE/9JYrlAIaeekVxRpCWsDDfYTfRZRoCeZatCQvwo+wvK8A== dependencies: - "@babel/helper-compilation-targets" "^7.18.9" - "@babel/helper-function-name" "^7.18.9" - "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-literals@^7.16.7", "@babel/plugin-transform-literals@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz#72796fdbef80e56fba3c6a699d54f0de557444bc" - integrity sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg== +"@babel/plugin-transform-function-name@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.22.5.tgz#935189af68b01898e0d6d99658db6b164205c143" + integrity sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg== dependencies: - "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-compilation-targets" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-member-expression-literals@^7.16.7", "@babel/plugin-transform-member-expression-literals@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz#ac9fdc1a118620ac49b7e7a5d2dc177a1bfee88e" - integrity sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA== +"@babel/plugin-transform-json-strings@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.5.tgz#14b64352fdf7e1f737eed68de1a1468bd2a77ec0" + integrity sha512-DuCRB7fu8MyTLbEQd1ew3R85nx/88yMoqo2uPSjevMj3yoN7CDM8jkgrY0wmVxfJZyJ/B9fE1iq7EQppWQmR5A== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-json-strings" "^7.8.3" -"@babel/plugin-transform-modules-amd@^7.16.7", "@babel/plugin-transform-modules-amd@^7.19.6": - version "7.20.11" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.20.11.tgz#3daccca8e4cc309f03c3a0c4b41dc4b26f55214a" - integrity sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g== +"@babel/plugin-transform-literals@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.22.5.tgz#e9341f4b5a167952576e23db8d435849b1dd7920" + integrity sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g== dependencies: - "@babel/helper-module-transforms" "^7.20.11" - "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-modules-commonjs@7.17.9": - version "7.17.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.9.tgz#274be1a2087beec0254d4abd4d86e52442e1e5b6" - integrity sha512-2TBFd/r2I6VlYn0YRTz2JdazS+FoUuQ2rIFHoAxtyP/0G3D82SBLaRq9rnUkpqlLg03Byfl/+M32mpxjO6KaPw== +"@babel/plugin-transform-logical-assignment-operators@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.5.tgz#66ae5f068fd5a9a5dc570df16f56c2a8462a9d6c" + integrity sha512-MQQOUW1KL8X0cDWfbwYP+TbVbZm16QmQXJQ+vndPtH/BoO0lOKpVoEDMI7+PskYxH+IiE0tS8xZye0qr1lGzSA== dependencies: - "@babel/helper-module-transforms" "^7.17.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-simple-access" "^7.17.7" - babel-plugin-dynamic-import-node "^2.3.3" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" -"@babel/plugin-transform-modules-commonjs@^7.17.9", "@babel/plugin-transform-modules-commonjs@^7.19.6": - version "7.21.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.21.2.tgz#6ff5070e71e3192ef2b7e39820a06fb78e3058e7" - integrity sha512-Cln+Yy04Gxua7iPdj6nOV96smLGjpElir5YwzF0LBPKoPlLDNJePNlrGGaybAJkd0zKRnOVXOgizSqPYMNYkzA== +"@babel/plugin-transform-member-expression-literals@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.22.5.tgz#4fcc9050eded981a468347dd374539ed3e058def" + integrity sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew== dependencies: - "@babel/helper-module-transforms" "^7.21.2" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-simple-access" "^7.20.2" + "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-modules-systemjs@7.17.8": - version "7.17.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.17.8.tgz#81fd834024fae14ea78fbe34168b042f38703859" - integrity sha512-39reIkMTUVagzgA5x88zDYXPCMT6lcaRKs1+S9K6NKBPErbgO/w/kP8GlNQTC87b412ZTlmNgr3k2JrWgHH+Bw== +"@babel/plugin-transform-modules-amd@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.22.5.tgz#4e045f55dcf98afd00f85691a68fc0780704f526" + integrity sha512-R+PTfLTcYEmb1+kK7FNkhQ1gP4KgjpSO6HfH9+f8/yfp2Nt3ggBjiVpRwmwTlfqZLafYKJACy36yDXlEmI9HjQ== dependencies: - "@babel/helper-hoist-variables" "^7.16.7" - "@babel/helper-module-transforms" "^7.17.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-validator-identifier" "^7.16.7" - babel-plugin-dynamic-import-node "^2.3.3" + "@babel/helper-module-transforms" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-modules-systemjs@^7.17.8", "@babel/plugin-transform-modules-systemjs@^7.19.6": - version "7.20.11" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.20.11.tgz#467ec6bba6b6a50634eea61c9c232654d8a4696e" - integrity sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw== +"@babel/plugin-transform-modules-commonjs@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.5.tgz#7d9875908d19b8c0536085af7b053fd5bd651bfa" + integrity sha512-B4pzOXj+ONRmuaQTg05b3y/4DuFz3WcCNAXPLb2Q0GT0TrGKGxNKV4jwsXts+StaM0LQczZbOpj8o1DLPDJIiA== dependencies: - "@babel/helper-hoist-variables" "^7.18.6" - "@babel/helper-module-transforms" "^7.20.11" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-validator-identifier" "^7.19.1" + "@babel/helper-module-transforms" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-simple-access" "^7.22.5" -"@babel/plugin-transform-modules-umd@^7.16.7", "@babel/plugin-transform-modules-umd@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz#81d3832d6034b75b54e62821ba58f28ed0aab4b9" - integrity sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ== +"@babel/plugin-transform-modules-systemjs@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.5.tgz#18c31410b5e579a0092638f95c896c2a98a5d496" + integrity sha512-emtEpoaTMsOs6Tzz+nbmcePl6AKVtS1yC4YNAeMun9U8YCsgadPNxnOPQ8GhHFB2qdx+LZu9LgoC0Lthuu05DQ== dependencies: - "@babel/helper-module-transforms" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-module-transforms" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.5" -"@babel/plugin-transform-named-capturing-groups-regex@7.17.10": - version "7.17.10" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.17.10.tgz#715dbcfafdb54ce8bccd3d12e8917296a4ba66a4" - integrity sha512-v54O6yLaJySCs6mGzaVOUw9T967GnH38T6CQSAtnzdNPwu84l2qAjssKzo/WSO8Yi7NF+7ekm5cVbF/5qiIgNA== +"@babel/plugin-transform-modules-umd@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.22.5.tgz#4694ae40a87b1745e3775b6a7fe96400315d4f98" + integrity sha512-+S6kzefN/E1vkSsKx8kmQuqeQsvCKCd1fraCM7zXm4SFoggI099Tr4G8U81+5gtMdUeMQ4ipdQffbKLX0/7dBQ== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.17.0" + "@babel/helper-module-transforms" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-named-capturing-groups-regex@^7.17.10", "@babel/plugin-transform-named-capturing-groups-regex@^7.19.1": - version "7.20.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz#626298dd62ea51d452c3be58b285d23195ba69a8" - integrity sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA== +"@babel/plugin-transform-named-capturing-groups-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz#67fe18ee8ce02d57c855185e27e3dc959b2e991f" + integrity sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.20.5" - "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-new-target@^7.16.7", "@babel/plugin-transform-new-target@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz#d128f376ae200477f37c4ddfcc722a8a1b3246a8" - integrity sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw== +"@babel/plugin-transform-new-target@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.22.5.tgz#1b248acea54ce44ea06dfd37247ba089fcf9758d" + integrity sha512-AsF7K0Fx/cNKVyk3a+DW0JLo+Ua598/NxMRvxDnkpCIGFh43+h/v2xyhRUYf6oD8gE4QtL83C7zZVghMjHd+iw== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-object-super@^7.16.7", "@babel/plugin-transform-object-super@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz#fb3c6ccdd15939b6ff7939944b51971ddc35912c" - integrity sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA== +"@babel/plugin-transform-nullish-coalescing-operator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.5.tgz#f8872c65776e0b552e0849d7596cddd416c3e381" + integrity sha512-6CF8g6z1dNYZ/VXok5uYkkBBICHZPiGEl7oDnAx2Mt1hlHVHOSIKWJaXHjQJA5VB43KZnXZDIexMchY4y2PGdA== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/helper-replace-supers" "^7.18.6" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" -"@babel/plugin-transform-parameters@^7.12.1", "@babel/plugin-transform-parameters@^7.16.7", "@babel/plugin-transform-parameters@^7.20.1", "@babel/plugin-transform-parameters@^7.20.7": - version "7.21.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.21.3.tgz#18fc4e797cf6d6d972cb8c411dbe8a809fa157db" - integrity sha512-Wxc+TvppQG9xWFYatvCGPvZ6+SIUxQ2ZdiBP+PHYMIjnPXD+uThCshaz4NZOnODAtBjjcVQQ/3OKs9LW28purQ== +"@babel/plugin-transform-numeric-separator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.5.tgz#57226a2ed9e512b9b446517ab6fa2d17abb83f58" + integrity sha512-NbslED1/6M+sXiwwtcAB/nieypGw02Ejf4KtDeMkCEpP6gWFMX1wI9WKYua+4oBneCCEmulOkRpwywypVZzs/g== dependencies: - "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" -"@babel/plugin-transform-property-literals@^7.16.7", "@babel/plugin-transform-property-literals@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz#e22498903a483448e94e032e9bbb9c5ccbfc93a3" - integrity sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg== +"@babel/plugin-transform-object-rest-spread@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.5.tgz#9686dc3447df4753b0b2a2fae7e8bc33cdc1f2e1" + integrity sha512-Kk3lyDmEslH9DnvCDA1s1kkd3YWQITiBOHngOtDL9Pt6BZjzqb6hiOlb8VfjiiQJ2unmegBqZu0rx5RxJb5vmQ== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/compat-data" "^7.22.5" + "@babel/helper-compilation-targets" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.22.5" + +"@babel/plugin-transform-object-super@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.22.5.tgz#794a8d2fcb5d0835af722173c1a9d704f44e218c" + integrity sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-replace-supers" "^7.22.5" + +"@babel/plugin-transform-optional-catch-binding@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.5.tgz#842080be3076703be0eaf32ead6ac8174edee333" + integrity sha512-pH8orJahy+hzZje5b8e2QIlBWQvGpelS76C63Z+jhZKsmzfNaPQ+LaW6dcJ9bxTpo1mtXbgHwy765Ro3jftmUg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-transform-optional-chaining@^7.22.5", "@babel/plugin-transform-optional-chaining@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.6.tgz#4bacfe37001fe1901117672875e931d439811564" + integrity sha512-Vd5HiWml0mDVtcLHIoEU5sw6HOUW/Zk0acLs/SAeuLzkGNOPc9DB4nkUajemhCmTIz3eiaKREZn2hQQqF79YTg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + +"@babel/plugin-transform-parameters@^7.12.1", "@babel/plugin-transform-parameters@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.5.tgz#c3542dd3c39b42c8069936e48717a8d179d63a18" + integrity sha512-AVkFUBurORBREOmHRKo06FjHYgjrabpdqRSwq6+C7R5iTCZOsM4QbcB27St0a4U6fffyAOqh3s/qEfybAhfivg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-private-methods@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.22.5.tgz#21c8af791f76674420a147ae62e9935d790f8722" + integrity sha512-PPjh4gyrQnGe97JTalgRGMuU4icsZFnWkzicB/fUtzlKUqvsWBKEpPPfr5a2JiyirZkHxnAqkQMO5Z5B2kK3fA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-private-property-in-object@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.5.tgz#07a77f28cbb251546a43d175a1dda4cf3ef83e32" + integrity sha512-/9xnaTTJcVoBtSSmrVyhtSvO3kbqS2ODoh2juEU72c3aYonNF0OMGiaz2gjukyKM2wBBYJP38S4JiE0Wfb5VMQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-create-class-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + +"@babel/plugin-transform-property-literals@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.22.5.tgz#b5ddabd73a4f7f26cd0e20f5db48290b88732766" + integrity sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-transform-react-constant-elements@^7.18.12": - version "7.21.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.21.3.tgz#b32a5556100d424b25e388dd689050d78396884d" - integrity sha512-4DVcFeWe/yDYBLp0kBmOGFJ6N2UYg7coGid1gdxb4co62dy/xISDMaYBXBVXEDhfgMk7qkbcYiGtwd5Q/hwDDQ== + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.22.5.tgz#6dfa7c1c37f7d7279e417ceddf5a04abb8bb9c29" + integrity sha512-BF5SXoO+nX3h5OhlN78XbbDrBOffv+AxPP2ENaJOVqjWCgBDeOY3WcaUcddutGSfoap+5NEQ/q/4I3WZIvgkXA== dependencies: - "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-react-display-name@^7.16.7", "@babel/plugin-transform-react-display-name@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz#8b1125f919ef36ebdfff061d664e266c666b9415" - integrity sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA== +"@babel/plugin-transform-react-display-name@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.22.5.tgz#3c4326f9fce31c7968d6cb9debcaf32d9e279a2b" + integrity sha512-PVk3WPYudRF5z4GKMEYUrLjPl38fJSKNaEOkFuoprioowGuWN6w2RKznuFNSlJx7pzzXXStPUnNSOEO0jL5EVw== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-react-jsx-development@^7.16.7", "@babel/plugin-transform-react-jsx-development@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz#dbe5c972811e49c7405b630e4d0d2e1380c0ddc5" - integrity sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA== +"@babel/plugin-transform-react-jsx-development@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz#e716b6edbef972a92165cd69d92f1255f7e73e87" + integrity sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A== dependencies: - "@babel/plugin-transform-react-jsx" "^7.18.6" + "@babel/plugin-transform-react-jsx" "^7.22.5" -"@babel/plugin-transform-react-jsx@^7.16.7", "@babel/plugin-transform-react-jsx@^7.18.6": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.21.0.tgz#656b42c2fdea0a6d8762075d58ef9d4e3c4ab8a2" - integrity sha512-6OAWljMvQrZjR2DaNhVfRz6dkCAVV+ymcLUmaf8bccGOHn2v5rHJK3tTpij0BuhdYWP4LLaqj5lwcdlpAAPuvg== +"@babel/plugin-transform-react-jsx@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.22.5.tgz#932c291eb6dd1153359e2a90cb5e557dcf068416" + integrity sha512-rog5gZaVbUip5iWDMTYbVM15XQq+RkUKhET/IHR6oizR+JEoN6CAfTTuHcK4vwUyzca30qqHqEpzBOnaRMWYMA== dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-module-imports" "^7.18.6" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/plugin-syntax-jsx" "^7.18.6" - "@babel/types" "^7.21.0" + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-module-imports" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-jsx" "^7.22.5" + "@babel/types" "^7.22.5" -"@babel/plugin-transform-react-pure-annotations@^7.16.7", "@babel/plugin-transform-react-pure-annotations@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz#561af267f19f3e5d59291f9950fd7b9663d0d844" - integrity sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ== +"@babel/plugin-transform-react-pure-annotations@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.22.5.tgz#1f58363eef6626d6fa517b95ac66fe94685e32c0" + integrity sha512-gP4k85wx09q+brArVinTXhWiyzLl9UpmGva0+mWyKxk6JZequ05x3eUcIUE+FyttPKJFRRVtAvQaJ6YF9h1ZpA== dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-regenerator@7.17.9": - version "7.17.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.17.9.tgz#0a33c3a61cf47f45ed3232903683a0afd2d3460c" - integrity sha512-Lc2TfbxR1HOyn/c6b4Y/b6NHoTb67n/IoWLxTu4kC7h4KQnWlhCq2S8Tx0t2SVvv5Uu87Hs+6JEJ5kt2tYGylQ== +"@babel/plugin-transform-regenerator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.5.tgz#cd8a68b228a5f75fa01420e8cc2fc400f0fc32aa" + integrity sha512-rR7KePOE7gfEtNTh9Qw+iO3Q/e4DEsoQ+hdvM6QUDH7JRJ5qxq5AA52ZzBWbI5i9lfNuvySgOGP8ZN7LAmaiPw== dependencies: - regenerator-transform "^0.15.0" - -"@babel/plugin-transform-regenerator@^7.17.9", "@babel/plugin-transform-regenerator@^7.18.6": - version "7.20.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz#57cda588c7ffb7f4f8483cc83bdcea02a907f04d" - integrity sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-plugin-utils" "^7.22.5" regenerator-transform "^0.15.1" -"@babel/plugin-transform-reserved-words@^7.16.7", "@babel/plugin-transform-reserved-words@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz#b1abd8ebf8edaa5f7fe6bbb8d2133d23b6a6f76a" - integrity sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA== +"@babel/plugin-transform-reserved-words@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.22.5.tgz#832cd35b81c287c4bcd09ce03e22199641f964fb" + integrity sha512-DTtGKFRQUDm8svigJzZHzb/2xatPc6TzNvAIJ5GqOKDsGFYgAskjRulbR/vGsPKq3OPqtexnz327qYpP57RFyA== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-runtime@7.17.10": - version "7.17.10" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.17.10.tgz#b89d821c55d61b5e3d3c3d1d636d8d5a81040ae1" - integrity sha512-6jrMilUAJhktTr56kACL8LnWC5hx3Lf27BS0R0DSyW/OoJfb/iTHeE96V3b1dgKG3FSFdd/0culnYWMkjcKCig== - dependencies: - "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - babel-plugin-polyfill-corejs2 "^0.3.0" - babel-plugin-polyfill-corejs3 "^0.5.0" - babel-plugin-polyfill-regenerator "^0.3.0" - semver "^6.3.0" + "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-transform-runtime@^7.18.6": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.21.0.tgz#2a884f29556d0a68cd3d152dcc9e6c71dfb6eee8" - integrity sha512-ReY6pxwSzEU0b3r2/T/VhqMKg/AkceBT19X0UptA3/tYi5Pe2eXgEUH+NNMC5nok6c6XQz5tyVTUpuezRfSMSg== + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.22.9.tgz#a87b11e170cbbfb018e6a2bf91f5c6e533b9e027" + integrity sha512-9KjBH61AGJetCPYp/IEyLEp47SyybZb0nDRpBvmtEkm+rUIwxdlKpyNHI1TmsGkeuLclJdleQHRZ8XLBnnh8CQ== dependencies: - "@babel/helper-module-imports" "^7.18.6" - "@babel/helper-plugin-utils" "^7.20.2" - babel-plugin-polyfill-corejs2 "^0.3.3" - babel-plugin-polyfill-corejs3 "^0.6.0" - babel-plugin-polyfill-regenerator "^0.4.1" - semver "^6.3.0" + "@babel/helper-module-imports" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + babel-plugin-polyfill-corejs2 "^0.4.4" + babel-plugin-polyfill-corejs3 "^0.8.2" + babel-plugin-polyfill-regenerator "^0.5.1" + semver "^6.3.1" -"@babel/plugin-transform-shorthand-properties@^7.16.7", "@babel/plugin-transform-shorthand-properties@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz#6d6df7983d67b195289be24909e3f12a8f664dc9" - integrity sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw== +"@babel/plugin-transform-shorthand-properties@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.22.5.tgz#6e277654be82b5559fc4b9f58088507c24f0c624" + integrity sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-spread@^7.16.7", "@babel/plugin-transform-spread@^7.19.0": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.20.7.tgz#c2d83e0b99d3bf83e07b11995ee24bf7ca09401e" - integrity sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw== +"@babel/plugin-transform-spread@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.22.5.tgz#6487fd29f229c95e284ba6c98d65eafb893fea6b" + integrity sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg== dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" -"@babel/plugin-transform-sticky-regex@^7.16.7", "@babel/plugin-transform-sticky-regex@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz#c6706eb2b1524028e317720339583ad0f444adcc" - integrity sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q== +"@babel/plugin-transform-sticky-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.22.5.tgz#295aba1595bfc8197abd02eae5fc288c0deb26aa" + integrity sha512-zf7LuNpHG0iEeiyCNwX4j3gDg1jgt1k3ZdXBKbZSoA3BbGQGvMiSvfbZRR3Dr3aeJe3ooWFZxOOG3IRStYp2Bw== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-template-literals@^7.16.7", "@babel/plugin-transform-template-literals@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz#04ec6f10acdaa81846689d63fae117dd9c243a5e" - integrity sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA== +"@babel/plugin-transform-template-literals@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.22.5.tgz#8f38cf291e5f7a8e60e9f733193f0bcc10909bff" + integrity sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA== dependencies: - "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-typeof-symbol@^7.16.7", "@babel/plugin-transform-typeof-symbol@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz#c8cea68263e45addcd6afc9091429f80925762c0" - integrity sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw== +"@babel/plugin-transform-typeof-symbol@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.22.5.tgz#5e2ba478da4b603af8673ff7c54f75a97b716b34" + integrity sha512-bYkI5lMzL4kPii4HHEEChkD0rkc+nvnlR6+o/qdqR6zrm0Sv/nodmyLhlq2DO0YKLUNd2VePmPRjJXSBh9OIdA== dependencies: - "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-typescript@^7.16.7", "@babel/plugin-transform-typescript@^7.21.0": - version "7.21.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.21.3.tgz#316c5be579856ea890a57ebc5116c5d064658f2b" - integrity sha512-RQxPz6Iqt8T0uw/WsJNReuBpWpBqs/n7mNo18sKLoTbMp+UrEekhH+pKSVC7gWz+DNjo9gryfV8YzCiT45RgMw== +"@babel/plugin-transform-typescript@^7.22.5": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.22.9.tgz#91e08ad1eb1028ecc62662a842e93ecfbf3c7234" + integrity sha512-BnVR1CpKiuD0iobHPaM1iLvcwPYN2uVFAqoLVSpEDKWuOikoCv5HbKLxclhKYUXlWkX86DoZGtqI4XhbOsyrMg== dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-create-class-features-plugin" "^7.21.0" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/plugin-syntax-typescript" "^7.20.0" + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-create-class-features-plugin" "^7.22.9" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-typescript" "^7.22.5" -"@babel/plugin-transform-unicode-escapes@^7.16.7", "@babel/plugin-transform-unicode-escapes@^7.18.10": - version "7.18.10" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz#1ecfb0eda83d09bbcb77c09970c2dd55832aa246" - integrity sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ== +"@babel/plugin-transform-unicode-escapes@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.5.tgz#ce0c248522b1cb22c7c992d88301a5ead70e806c" + integrity sha512-biEmVg1IYB/raUO5wT1tgfacCef15Fbzhkx493D3urBI++6hpJ+RFG4SrWMn0NEZLfvilqKf3QDrRVZHo08FYg== dependencies: - "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-unicode-regex@^7.16.7", "@babel/plugin-transform-unicode-regex@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz#194317225d8c201bbae103364ffe9e2cea36cdca" - integrity sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA== +"@babel/plugin-transform-unicode-property-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.22.5.tgz#098898f74d5c1e86660dc112057b2d11227f1c81" + integrity sha512-HCCIb+CbJIAE6sXn5CjFQXMwkCClcOfPCzTlilJ8cUatfzwHlWQkbtV0zD338u9dZskwvuOYTuuaMaA8J5EI5A== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" -"@babel/preset-env@7.17.10": - version "7.17.10" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.17.10.tgz#a81b093669e3eb6541bb81a23173c5963c5de69c" - integrity sha512-YNgyBHZQpeoBSRBg0xixsZzfT58Ze1iZrajvv0lJc70qDDGuGfonEnMGfWeSY0mQ3JTuCWFbMkzFRVafOyJx4g== +"@babel/plugin-transform-unicode-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.22.5.tgz#ce7e7bb3ef208c4ff67e02a22816656256d7a183" + integrity sha512-028laaOKptN5vHJf9/Arr/HiJekMd41hOEZYvNsrsXqJ7YPYuX2bQxh31fkZzGmq3YqHRJzYFFAVYvKfMPKqyg== dependencies: - "@babel/compat-data" "^7.17.10" - "@babel/helper-compilation-targets" "^7.17.10" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-validator-option" "^7.16.7" - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.16.7" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.16.7" - "@babel/plugin-proposal-async-generator-functions" "^7.16.8" - "@babel/plugin-proposal-class-properties" "^7.16.7" - "@babel/plugin-proposal-class-static-block" "^7.17.6" - "@babel/plugin-proposal-dynamic-import" "^7.16.7" - "@babel/plugin-proposal-export-namespace-from" "^7.16.7" - "@babel/plugin-proposal-json-strings" "^7.16.7" - "@babel/plugin-proposal-logical-assignment-operators" "^7.16.7" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.16.7" - "@babel/plugin-proposal-numeric-separator" "^7.16.7" - "@babel/plugin-proposal-object-rest-spread" "^7.17.3" - "@babel/plugin-proposal-optional-catch-binding" "^7.16.7" - "@babel/plugin-proposal-optional-chaining" "^7.16.7" - "@babel/plugin-proposal-private-methods" "^7.16.11" - "@babel/plugin-proposal-private-property-in-object" "^7.16.7" - "@babel/plugin-proposal-unicode-property-regex" "^7.16.7" - "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/plugin-syntax-class-properties" "^7.12.13" - "@babel/plugin-syntax-class-static-block" "^7.14.5" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-private-property-in-object" "^7.14.5" - "@babel/plugin-syntax-top-level-await" "^7.14.5" - "@babel/plugin-transform-arrow-functions" "^7.16.7" - "@babel/plugin-transform-async-to-generator" "^7.16.8" - "@babel/plugin-transform-block-scoped-functions" "^7.16.7" - "@babel/plugin-transform-block-scoping" "^7.16.7" - "@babel/plugin-transform-classes" "^7.16.7" - "@babel/plugin-transform-computed-properties" "^7.16.7" - "@babel/plugin-transform-destructuring" "^7.17.7" - "@babel/plugin-transform-dotall-regex" "^7.16.7" - "@babel/plugin-transform-duplicate-keys" "^7.16.7" - "@babel/plugin-transform-exponentiation-operator" "^7.16.7" - "@babel/plugin-transform-for-of" "^7.16.7" - "@babel/plugin-transform-function-name" "^7.16.7" - "@babel/plugin-transform-literals" "^7.16.7" - "@babel/plugin-transform-member-expression-literals" "^7.16.7" - "@babel/plugin-transform-modules-amd" "^7.16.7" - "@babel/plugin-transform-modules-commonjs" "^7.17.9" - "@babel/plugin-transform-modules-systemjs" "^7.17.8" - "@babel/plugin-transform-modules-umd" "^7.16.7" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.17.10" - "@babel/plugin-transform-new-target" "^7.16.7" - "@babel/plugin-transform-object-super" "^7.16.7" - "@babel/plugin-transform-parameters" "^7.16.7" - "@babel/plugin-transform-property-literals" "^7.16.7" - "@babel/plugin-transform-regenerator" "^7.17.9" - "@babel/plugin-transform-reserved-words" "^7.16.7" - "@babel/plugin-transform-shorthand-properties" "^7.16.7" - "@babel/plugin-transform-spread" "^7.16.7" - "@babel/plugin-transform-sticky-regex" "^7.16.7" - "@babel/plugin-transform-template-literals" "^7.16.7" - "@babel/plugin-transform-typeof-symbol" "^7.16.7" - "@babel/plugin-transform-unicode-escapes" "^7.16.7" - "@babel/plugin-transform-unicode-regex" "^7.16.7" - "@babel/preset-modules" "^0.1.5" - "@babel/types" "^7.17.10" - babel-plugin-polyfill-corejs2 "^0.3.0" - babel-plugin-polyfill-corejs3 "^0.5.0" - babel-plugin-polyfill-regenerator "^0.3.0" - core-js-compat "^3.22.1" - semver "^6.3.0" + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-unicode-sets-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.22.5.tgz#77788060e511b708ffc7d42fdfbc5b37c3004e91" + integrity sha512-lhMfi4FC15j13eKrh3DnYHjpGj6UKQHtNKTbtc1igvAhRy4+kLhV07OpLcsN0VgDEw/MjAvJO4BdMJsHwMhzCg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" "@babel/preset-env@^7.18.6", "@babel/preset-env@^7.19.4": - version "7.20.2" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.20.2.tgz#9b1642aa47bb9f43a86f9630011780dab7f86506" - integrity sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg== + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.22.9.tgz#57f17108eb5dfd4c5c25a44c1977eba1df310ac7" + integrity sha512-wNi5H/Emkhll/bqPjsjQorSykrlfY5OWakd6AulLvMEytpKasMVUpVy8RL4qBIBs5Ac6/5i0/Rv0b/Fg6Eag/g== dependencies: - "@babel/compat-data" "^7.20.1" - "@babel/helper-compilation-targets" "^7.20.0" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-validator-option" "^7.18.6" - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.18.6" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.18.9" - "@babel/plugin-proposal-async-generator-functions" "^7.20.1" - "@babel/plugin-proposal-class-properties" "^7.18.6" - "@babel/plugin-proposal-class-static-block" "^7.18.6" - "@babel/plugin-proposal-dynamic-import" "^7.18.6" - "@babel/plugin-proposal-export-namespace-from" "^7.18.9" - "@babel/plugin-proposal-json-strings" "^7.18.6" - "@babel/plugin-proposal-logical-assignment-operators" "^7.18.9" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.18.6" - "@babel/plugin-proposal-numeric-separator" "^7.18.6" - "@babel/plugin-proposal-object-rest-spread" "^7.20.2" - "@babel/plugin-proposal-optional-catch-binding" "^7.18.6" - "@babel/plugin-proposal-optional-chaining" "^7.18.9" - "@babel/plugin-proposal-private-methods" "^7.18.6" - "@babel/plugin-proposal-private-property-in-object" "^7.18.6" - "@babel/plugin-proposal-unicode-property-regex" "^7.18.6" + "@babel/compat-data" "^7.22.9" + "@babel/helper-compilation-targets" "^7.22.9" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-validator-option" "^7.22.5" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.22.5" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.22.5" + "@babel/plugin-proposal-private-property-in-object" "7.21.0-placeholder-for-preset-env.2" "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-class-properties" "^7.12.13" "@babel/plugin-syntax-class-static-block" "^7.14.5" "@babel/plugin-syntax-dynamic-import" "^7.8.3" "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - "@babel/plugin-syntax-import-assertions" "^7.20.0" + "@babel/plugin-syntax-import-assertions" "^7.22.5" + "@babel/plugin-syntax-import-attributes" "^7.22.5" + "@babel/plugin-syntax-import-meta" "^7.10.4" "@babel/plugin-syntax-json-strings" "^7.8.3" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" @@ -1290,50 +1100,67 @@ "@babel/plugin-syntax-optional-chaining" "^7.8.3" "@babel/plugin-syntax-private-property-in-object" "^7.14.5" "@babel/plugin-syntax-top-level-await" "^7.14.5" - "@babel/plugin-transform-arrow-functions" "^7.18.6" - "@babel/plugin-transform-async-to-generator" "^7.18.6" - "@babel/plugin-transform-block-scoped-functions" "^7.18.6" - "@babel/plugin-transform-block-scoping" "^7.20.2" - "@babel/plugin-transform-classes" "^7.20.2" - "@babel/plugin-transform-computed-properties" "^7.18.9" - "@babel/plugin-transform-destructuring" "^7.20.2" - "@babel/plugin-transform-dotall-regex" "^7.18.6" - "@babel/plugin-transform-duplicate-keys" "^7.18.9" - "@babel/plugin-transform-exponentiation-operator" "^7.18.6" - "@babel/plugin-transform-for-of" "^7.18.8" - "@babel/plugin-transform-function-name" "^7.18.9" - "@babel/plugin-transform-literals" "^7.18.9" - "@babel/plugin-transform-member-expression-literals" "^7.18.6" - "@babel/plugin-transform-modules-amd" "^7.19.6" - "@babel/plugin-transform-modules-commonjs" "^7.19.6" - "@babel/plugin-transform-modules-systemjs" "^7.19.6" - "@babel/plugin-transform-modules-umd" "^7.18.6" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.19.1" - "@babel/plugin-transform-new-target" "^7.18.6" - "@babel/plugin-transform-object-super" "^7.18.6" - "@babel/plugin-transform-parameters" "^7.20.1" - "@babel/plugin-transform-property-literals" "^7.18.6" - "@babel/plugin-transform-regenerator" "^7.18.6" - "@babel/plugin-transform-reserved-words" "^7.18.6" - "@babel/plugin-transform-shorthand-properties" "^7.18.6" - "@babel/plugin-transform-spread" "^7.19.0" - "@babel/plugin-transform-sticky-regex" "^7.18.6" - "@babel/plugin-transform-template-literals" "^7.18.9" - "@babel/plugin-transform-typeof-symbol" "^7.18.9" - "@babel/plugin-transform-unicode-escapes" "^7.18.10" - "@babel/plugin-transform-unicode-regex" "^7.18.6" + "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" + "@babel/plugin-transform-arrow-functions" "^7.22.5" + "@babel/plugin-transform-async-generator-functions" "^7.22.7" + "@babel/plugin-transform-async-to-generator" "^7.22.5" + "@babel/plugin-transform-block-scoped-functions" "^7.22.5" + "@babel/plugin-transform-block-scoping" "^7.22.5" + "@babel/plugin-transform-class-properties" "^7.22.5" + "@babel/plugin-transform-class-static-block" "^7.22.5" + "@babel/plugin-transform-classes" "^7.22.6" + "@babel/plugin-transform-computed-properties" "^7.22.5" + "@babel/plugin-transform-destructuring" "^7.22.5" + "@babel/plugin-transform-dotall-regex" "^7.22.5" + "@babel/plugin-transform-duplicate-keys" "^7.22.5" + "@babel/plugin-transform-dynamic-import" "^7.22.5" + "@babel/plugin-transform-exponentiation-operator" "^7.22.5" + "@babel/plugin-transform-export-namespace-from" "^7.22.5" + "@babel/plugin-transform-for-of" "^7.22.5" + "@babel/plugin-transform-function-name" "^7.22.5" + "@babel/plugin-transform-json-strings" "^7.22.5" + "@babel/plugin-transform-literals" "^7.22.5" + "@babel/plugin-transform-logical-assignment-operators" "^7.22.5" + "@babel/plugin-transform-member-expression-literals" "^7.22.5" + "@babel/plugin-transform-modules-amd" "^7.22.5" + "@babel/plugin-transform-modules-commonjs" "^7.22.5" + "@babel/plugin-transform-modules-systemjs" "^7.22.5" + "@babel/plugin-transform-modules-umd" "^7.22.5" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.22.5" + "@babel/plugin-transform-new-target" "^7.22.5" + "@babel/plugin-transform-nullish-coalescing-operator" "^7.22.5" + "@babel/plugin-transform-numeric-separator" "^7.22.5" + "@babel/plugin-transform-object-rest-spread" "^7.22.5" + "@babel/plugin-transform-object-super" "^7.22.5" + "@babel/plugin-transform-optional-catch-binding" "^7.22.5" + "@babel/plugin-transform-optional-chaining" "^7.22.6" + "@babel/plugin-transform-parameters" "^7.22.5" + "@babel/plugin-transform-private-methods" "^7.22.5" + "@babel/plugin-transform-private-property-in-object" "^7.22.5" + "@babel/plugin-transform-property-literals" "^7.22.5" + "@babel/plugin-transform-regenerator" "^7.22.5" + "@babel/plugin-transform-reserved-words" "^7.22.5" + "@babel/plugin-transform-shorthand-properties" "^7.22.5" + "@babel/plugin-transform-spread" "^7.22.5" + "@babel/plugin-transform-sticky-regex" "^7.22.5" + "@babel/plugin-transform-template-literals" "^7.22.5" + "@babel/plugin-transform-typeof-symbol" "^7.22.5" + "@babel/plugin-transform-unicode-escapes" "^7.22.5" + "@babel/plugin-transform-unicode-property-regex" "^7.22.5" + "@babel/plugin-transform-unicode-regex" "^7.22.5" + "@babel/plugin-transform-unicode-sets-regex" "^7.22.5" "@babel/preset-modules" "^0.1.5" - "@babel/types" "^7.20.2" - babel-plugin-polyfill-corejs2 "^0.3.3" - babel-plugin-polyfill-corejs3 "^0.6.0" - babel-plugin-polyfill-regenerator "^0.4.1" - core-js-compat "^3.25.1" - semver "^6.3.0" + "@babel/types" "^7.22.5" + babel-plugin-polyfill-corejs2 "^0.4.4" + babel-plugin-polyfill-corejs3 "^0.8.2" + babel-plugin-polyfill-regenerator "^0.5.1" + core-js-compat "^3.31.0" + semver "^6.3.1" "@babel/preset-modules@^0.1.5": - version "0.1.5" - resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9" - integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA== + version "0.1.6" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.6.tgz#31bcdd8f19538437339d17af00d177d854d9d458" + integrity sha512-ID2yj6K/4lKfhuU3+EX4UvNbIt7eACFbHmNUjzA+ep+B5971CknnA/9DEWKbRokfbbtblxxxXFJJrH47UEAMVg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" @@ -1341,156 +1168,124 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" -"@babel/preset-react@7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.16.7.tgz#4c18150491edc69c183ff818f9f2aecbe5d93852" - integrity sha512-fWpyI8UM/HE6DfPBzD8LnhQ/OcH8AgTaqcqP2nGOXEUV+VKBR5JRN9hCk9ai+zQQ57vtm9oWeXguBCPNUjytgA== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-validator-option" "^7.16.7" - "@babel/plugin-transform-react-display-name" "^7.16.7" - "@babel/plugin-transform-react-jsx" "^7.16.7" - "@babel/plugin-transform-react-jsx-development" "^7.16.7" - "@babel/plugin-transform-react-pure-annotations" "^7.16.7" - "@babel/preset-react@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.18.6.tgz#979f76d6277048dc19094c217b507f3ad517dd2d" - integrity sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg== + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.22.5.tgz#c4d6058fbf80bccad02dd8c313a9aaa67e3c3dd6" + integrity sha512-M+Is3WikOpEJHgR385HbuCITPTaPRaNkibTEa9oiofmJvIsrceb4yp9RL9Kb+TE8LznmeyZqpP+Lopwcx59xPQ== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/helper-validator-option" "^7.18.6" - "@babel/plugin-transform-react-display-name" "^7.18.6" - "@babel/plugin-transform-react-jsx" "^7.18.6" - "@babel/plugin-transform-react-jsx-development" "^7.18.6" - "@babel/plugin-transform-react-pure-annotations" "^7.18.6" - -"@babel/preset-typescript@7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.16.7.tgz#ab114d68bb2020afc069cd51b37ff98a046a70b9" - integrity sha512-WbVEmgXdIyvzB77AQjGBEyYPZx+8tTsO50XtfozQrkW8QB2rLJpH2lgx0TRw5EJrBxOZQ+wCcyPVQvS8tjEHpQ== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-validator-option" "^7.16.7" - "@babel/plugin-transform-typescript" "^7.16.7" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-validator-option" "^7.22.5" + "@babel/plugin-transform-react-display-name" "^7.22.5" + "@babel/plugin-transform-react-jsx" "^7.22.5" + "@babel/plugin-transform-react-jsx-development" "^7.22.5" + "@babel/plugin-transform-react-pure-annotations" "^7.22.5" "@babel/preset-typescript@^7.18.6": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.21.0.tgz#bcbbca513e8213691fe5d4b23d9251e01f00ebff" - integrity sha512-myc9mpoVA5m1rF8K8DgLEatOYFDpwC+RkMkjZ0Du6uI62YvDe8uxIEYVs/VCdSJ097nlALiU/yBC7//3nI+hNg== + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.22.5.tgz#16367d8b01d640e9a507577ed4ee54e0101e51c8" + integrity sha512-YbPaal9LxztSGhmndR46FmAbkJ/1fAsw293tSU+I5E5h+cnJ3d4GTwyUgGYmOXJYdGA+uNePle4qbaRzj2NISQ== dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-validator-option" "^7.21.0" - "@babel/plugin-transform-typescript" "^7.21.0" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-validator-option" "^7.22.5" + "@babel/plugin-syntax-jsx" "^7.22.5" + "@babel/plugin-transform-modules-commonjs" "^7.22.5" + "@babel/plugin-transform-typescript" "^7.22.5" "@babel/regjsgen@^0.8.0": version "0.8.0" resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310" integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== -"@babel/runtime-corejs3@7.17.9": - version "7.17.9" - resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.17.9.tgz#3d02d0161f0fbf3ada8e88159375af97690f4055" - integrity sha512-WxYHHUWF2uZ7Hp1K+D1xQgbgkGUfA+5UPOegEXGt2Y5SMog/rYCVaifLZDbw8UkNXozEqqrZTy6bglL7xTaCOw== - dependencies: - core-js-pure "^3.20.2" - regenerator-runtime "^0.13.4" - "@babel/runtime-corejs3@^7.18.6": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.21.0.tgz#6e4939d9d9789ff63e2dc58e88f13a3913a24eba" - integrity sha512-TDD4UJzos3JJtM+tHX+w2Uc+KWj7GV+VKKFdMVd2Rx8sdA19hcc3P3AHFYd5LVOw+pYuSd5lICC3gm52B6Rwxw== + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.22.6.tgz#e8e625eb3db29491e0326b3aeb9929c43b270ae4" + integrity sha512-M+37LLIRBTEVjktoJjbw4KVhupF0U/3PYUCbBwgAd9k17hoKhRu1n935QiG7Tuxv0LJOMrb2vuKEeYUlv0iyiw== dependencies: - core-js-pure "^3.25.1" + core-js-pure "^3.30.2" regenerator-runtime "^0.13.11" -"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.18.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673" - integrity sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw== +"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.18.6", "@babel/runtime@^7.20.13", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.6.tgz#57d64b9ae3cff1d67eb067ae117dac087f5bd438" + integrity sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ== dependencies: regenerator-runtime "^0.13.11" -"@babel/template@^7.12.7", "@babel/template@^7.16.7", "@babel/template@^7.18.10", "@babel/template@^7.20.7": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.20.7.tgz#a15090c2839a83b02aa996c0b4994005841fd5a8" - integrity sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw== +"@babel/template@^7.12.7", "@babel/template@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.5.tgz#0c8c4d944509875849bd0344ff0050756eefc6ec" + integrity sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw== dependencies: - "@babel/code-frame" "^7.18.6" - "@babel/parser" "^7.20.7" - "@babel/types" "^7.20.7" + "@babel/code-frame" "^7.22.5" + "@babel/parser" "^7.22.5" + "@babel/types" "^7.22.5" -"@babel/traverse@^7.12.9", "@babel/traverse@^7.17.10", "@babel/traverse@^7.18.8", "@babel/traverse@^7.20.5", "@babel/traverse@^7.20.7", "@babel/traverse@^7.21.0", "@babel/traverse@^7.21.2", "@babel/traverse@^7.21.3": - version "7.21.3" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.21.3.tgz#4747c5e7903d224be71f90788b06798331896f67" - integrity sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ== +"@babel/traverse@^7.12.9", "@babel/traverse@^7.18.8", "@babel/traverse@^7.22.6", "@babel/traverse@^7.22.8": + version "7.22.8" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.8.tgz#4d4451d31bc34efeae01eac222b514a77aa4000e" + integrity sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw== dependencies: - "@babel/code-frame" "^7.18.6" - "@babel/generator" "^7.21.3" - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-function-name" "^7.21.0" - "@babel/helper-hoist-variables" "^7.18.6" - "@babel/helper-split-export-declaration" "^7.18.6" - "@babel/parser" "^7.21.3" - "@babel/types" "^7.21.3" + "@babel/code-frame" "^7.22.5" + "@babel/generator" "^7.22.7" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.22.7" + "@babel/types" "^7.22.5" debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.12.7", "@babel/types@^7.15.6", "@babel/types@^7.17.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.21.2", "@babel/types@^7.21.3", "@babel/types@^7.4.4": - version "7.21.3" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.3.tgz#4865a5357ce40f64e3400b0f3b737dc6d4f64d05" - integrity sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg== +"@babel/types@^7.12.7", "@babel/types@^7.20.0", "@babel/types@^7.22.5", "@babel/types@^7.4.4": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.5.tgz#cd93eeaab025880a3a47ec881f4b096a5b786fbe" + integrity sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA== dependencies: - "@babel/helper-string-parser" "^7.19.4" - "@babel/helper-validator-identifier" "^7.19.1" + "@babel/helper-string-parser" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.5" to-fast-properties "^2.0.0" -"@braintree/sanitize-url@^6.0.0": - version "6.0.2" - resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-6.0.2.tgz#6110f918d273fe2af8ea1c4398a88774bb9fc12f" - integrity sha512-Tbsj02wXCbqGmzdnXNk0SOF19ChhRU70BsroIi4Pm6Ehp56in6vch94mfbdQ17DozxkL3BAVjbZ4Qc1a0HFRAg== +"@bufbuild/buf-darwin-arm64@1.25.1": + version "1.25.1" + resolved "https://registry.yarnpkg.com/@bufbuild/buf-darwin-arm64/-/buf-darwin-arm64-1.25.1.tgz#37b8eace29fbfe6a15245c54275b1e11e09af274" + integrity sha512-1EjF4swCjxj8A7snyIFCnl0l81idYyrLLhQurAcGYJXtHl/VdF+qE+zuGI+ehuc4uSTTGp1X2BelprOnW17ZDQ== -"@bufbuild/buf-darwin-arm64@1.15.0": - version "1.15.0" - resolved "https://registry.yarnpkg.com/@bufbuild/buf-darwin-arm64/-/buf-darwin-arm64-1.15.0.tgz#4d8b074ca1b697c4769cea2fcea027d85b0b6492" - integrity sha512-sLN6uGc8sIBALa7Q4fB6rW9NM0MXK32pH6RRDUdl7aDrp/3A6TLKKBGiHcY81axUyxDTUNFb8dOwhHTI2H8FzQ== +"@bufbuild/buf-darwin-x64@1.25.1": + version "1.25.1" + resolved "https://registry.yarnpkg.com/@bufbuild/buf-darwin-x64/-/buf-darwin-x64-1.25.1.tgz#74fecb72c714212f337c8748f3570210fb6dc631" + integrity sha512-LSNTqQFF9vrx/CUE2TxNhxb7VwEYmUxA2YXznbElxV6PqWaNt1McrbxCvUF7oYEKXXwps9gPkUi4rzjCOliCsQ== -"@bufbuild/buf-darwin-x64@1.15.0": - version "1.15.0" - resolved "https://registry.yarnpkg.com/@bufbuild/buf-darwin-x64/-/buf-darwin-x64-1.15.0.tgz#33023704c80c8dea32e463e0728bb6297a0abf69" - integrity sha512-iHml29I/hOl7ORyp9ohiV7fC1WqPbM5UjogwVpA8j06o5SgxRhp42nd80XRAXCM+65ecwiu5JVuspicGzQFOgg== +"@bufbuild/buf-linux-aarch64@1.25.1": + version "1.25.1" + resolved "https://registry.yarnpkg.com/@bufbuild/buf-linux-aarch64/-/buf-linux-aarch64-1.25.1.tgz#bb1d36ace33414aa60129ee2b2c3d231d5a27c3d" + integrity sha512-Qwy+xos8bnyjCKSCw1l+VG9aIoZHo4CXp3A7bLtYWUZMn18WZ1xtRPFvw/ntdGoZhcoP+yYNbiVi22m4r/zVbQ== -"@bufbuild/buf-linux-aarch64@1.15.0": - version "1.15.0" - resolved "https://registry.yarnpkg.com/@bufbuild/buf-linux-aarch64/-/buf-linux-aarch64-1.15.0.tgz#8e833440f090b1cafda143135f797aebc6d9e6b0" - integrity sha512-YQHXqV1HhdpmIUrYg+gZNWCf43XHJJO5TlJT+pzXB/92PoN8gNP3KdxeRaM2sExcCs91G6zy1/Ms9N6DpeidUQ== +"@bufbuild/buf-linux-x64@1.25.1": + version "1.25.1" + resolved "https://registry.yarnpkg.com/@bufbuild/buf-linux-x64/-/buf-linux-x64-1.25.1.tgz#1f5072a7f0fe13416b8d4e21952f11a44017539f" + integrity sha512-i8EGo8dqotGdxO+UayEGqwZ4FUg7ejw0XOTgTlwH79yUV1IEuWb1+zItPeWthJHhrNT6gQEsESie/pygDtmhaA== -"@bufbuild/buf-linux-x64@1.15.0": - version "1.15.0" - resolved "https://registry.yarnpkg.com/@bufbuild/buf-linux-x64/-/buf-linux-x64-1.15.0.tgz#68c2cc39833c018c1e2e9660e9a87f6f61df52e3" - integrity sha512-DD2OcsfofawRPQKXLFMqV2GSzi4WyE7kKE1PvXBtJy7sombv5TM26vgdb+DQv4T4Z2i7vhKshnflNkfd3QXtXA== +"@bufbuild/buf-win32-arm64@1.25.1": + version "1.25.1" + resolved "https://registry.yarnpkg.com/@bufbuild/buf-win32-arm64/-/buf-win32-arm64-1.25.1.tgz#7a74322c5656e2f4a901c2d9054a1e33cd0d2f3e" + integrity sha512-ut8hRAy8GQZnNKaPlwiu9cN9bCX0XWvdsPezXFsdMynuYXBgssvJ7dGbzLWDSmOm8evhsJ+ZPmrLYyk+7OD2Ng== -"@bufbuild/buf-win32-arm64@1.15.0": - version "1.15.0" - resolved "https://registry.yarnpkg.com/@bufbuild/buf-win32-arm64/-/buf-win32-arm64-1.15.0.tgz#d9b441854bd4bd26ab678da31936561ab8d82368" - integrity sha512-wk65iDXWRicfrt/9Gb1voAn9eGP2giQfKMrKOoEyytnDHFolMSmQimKH6iQ1uS5Vn0gI/BVp582cF1m9YsbXEg== - -"@bufbuild/buf-win32-x64@1.15.0": - version "1.15.0" - resolved "https://registry.yarnpkg.com/@bufbuild/buf-win32-x64/-/buf-win32-x64-1.15.0.tgz#48ed4c94d195d6a763686821ef23da6afa8a868b" - integrity sha512-KVoMj52ghYfLwGjQ+t19XZiQy8jGSGUYIe/yVZz08rsm5msXHGYOt++Bk3wr48rcv8gts8jo2/h1Ebkj+F6emw== +"@bufbuild/buf-win32-x64@1.25.1": + version "1.25.1" + resolved "https://registry.yarnpkg.com/@bufbuild/buf-win32-x64/-/buf-win32-x64-1.25.1.tgz#d0d3eda541babb5f46263fe9795d38477ea071ac" + integrity sha512-g4npaZs7aqXlTETaDhKh7E4LcSTCDEehUGV7Y+xiTB5r4VyCU8gzykuE7sNHxUsQ+X5lV/pFkFGz+449Pf/tww== "@bufbuild/buf@^1.14.0": - version "1.15.0" - resolved "https://registry.yarnpkg.com/@bufbuild/buf/-/buf-1.15.0.tgz#a2d23b922d41d2c026bd37bd938a0d11717e409b" - integrity sha512-HX6AjKiI8TVFJKWdDGIUC/zZQG/8sf5FbmU5VdbK/U8tbfCwBADkJ6I+qP6HnDDtSU4obS164J0sibdGhAJKqg== + version "1.25.1" + resolved "https://registry.yarnpkg.com/@bufbuild/buf/-/buf-1.25.1.tgz#8600c99c0f75ac0ca2885869020df0100b8498a9" + integrity sha512-Of9mH1xzhi/8EnndGx3uOV/umjGkCSnBnN01pm5O6xUD2aAdqDPjxWrFY09oR0NIHmePpgGQn6az7Ku42mlFPQ== optionalDependencies: - "@bufbuild/buf-darwin-arm64" "1.15.0" - "@bufbuild/buf-darwin-x64" "1.15.0" - "@bufbuild/buf-linux-aarch64" "1.15.0" - "@bufbuild/buf-linux-x64" "1.15.0" - "@bufbuild/buf-win32-arm64" "1.15.0" - "@bufbuild/buf-win32-x64" "1.15.0" + "@bufbuild/buf-darwin-arm64" "1.25.1" + "@bufbuild/buf-darwin-x64" "1.25.1" + "@bufbuild/buf-linux-aarch64" "1.25.1" + "@bufbuild/buf-linux-x64" "1.25.1" + "@bufbuild/buf-win32-arm64" "1.25.1" + "@bufbuild/buf-win32-x64" "1.25.1" "@colors/colors@1.5.0": version "1.5.0" @@ -1502,34 +1297,19 @@ resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== -"@docsearch/css@3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@docsearch/css/-/css-3.0.0.tgz#fe57b474802ffd706d3246eab25d52fac8aa3698" - integrity sha512-1kkV7tkAsiuEd0shunYRByKJe3xQDG2q7wYg24SOw1nV9/2lwEd4WrUYRJC/ukGTl2/kHeFxsaUvtiOy0y6fFA== - -"@docsearch/css@3.3.3": - version "3.3.3" - resolved "https://registry.yarnpkg.com/@docsearch/css/-/css-3.3.3.tgz#f9346c9e24602218341f51b8ba91eb9109add434" - integrity sha512-6SCwI7P8ao+se1TUsdZ7B4XzL+gqeQZnBc+2EONZlcVa0dVrk0NjETxozFKgMv0eEGH8QzP1fkN+A1rH61l4eg== - -"@docsearch/react@3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@docsearch/react/-/react-3.0.0.tgz#d02ebdc67573412185a6a4df13bc254c7c0da491" - integrity sha512-yhMacqS6TVQYoBh/o603zszIb5Bl8MIXuOc6Vy617I74pirisDzzcNh0NEaYQt50fVVR3khUbeEhUEWEWipESg== - dependencies: - "@algolia/autocomplete-core" "1.5.2" - "@algolia/autocomplete-preset-algolia" "1.5.2" - "@docsearch/css" "3.0.0" - algoliasearch "^4.0.0" +"@docsearch/css@3.5.1": + version "3.5.1" + resolved "https://registry.yarnpkg.com/@docsearch/css/-/css-3.5.1.tgz#4adf9884735bbfea621c3716e80ea97baa419b73" + integrity sha512-2Pu9HDg/uP/IT10rbQ+4OrTQuxIWdKVUEdcw9/w7kZJv9NeHS6skJx1xuRiFyoGKwAzcHXnLp7csE99sj+O1YA== "@docsearch/react@^3.1.1": - version "3.3.3" - resolved "https://registry.yarnpkg.com/@docsearch/react/-/react-3.3.3.tgz#907b6936a565f880b4c0892624b4f7a9f132d298" - integrity sha512-pLa0cxnl+G0FuIDuYlW+EBK6Rw2jwLw9B1RHIeS4N4s2VhsfJ/wzeCi3CWcs5yVfxLd5ZK50t//TMA5e79YT7Q== + version "3.5.1" + resolved "https://registry.yarnpkg.com/@docsearch/react/-/react-3.5.1.tgz#35f4a75f948211d8bb6830d2147c575f96a85274" + integrity sha512-t5mEODdLzZq4PTFAm/dvqcvZFdPDMdfPE5rJS5SC8OUq9mPzxEy6b+9THIqNM9P0ocCb4UC5jqBrxKclnuIbzQ== dependencies: - "@algolia/autocomplete-core" "1.7.4" - "@algolia/autocomplete-preset-algolia" "1.7.4" - "@docsearch/css" "3.3.3" + "@algolia/autocomplete-core" "1.9.3" + "@algolia/autocomplete-preset-algolia" "1.9.3" + "@docsearch/css" "3.5.1" algoliasearch "^4.0.0" "@docusaurus/core@2.2.0": @@ -1609,83 +1389,6 @@ webpack-merge "^5.8.0" webpackbar "^5.0.2" -"@docusaurus/core@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-2.3.1.tgz#32849f2ffd2f086a4e55739af8c4195c5eb386f2" - integrity sha512-0Jd4jtizqnRAr7svWaBbbrCCN8mzBNd2xFLoT/IM7bGfFie5y58oz97KzXliwiLY3zWjqMXjQcuP1a5VgCv2JA== - dependencies: - "@babel/core" "^7.18.6" - "@babel/generator" "^7.18.7" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - "@babel/plugin-transform-runtime" "^7.18.6" - "@babel/preset-env" "^7.18.6" - "@babel/preset-react" "^7.18.6" - "@babel/preset-typescript" "^7.18.6" - "@babel/runtime" "^7.18.6" - "@babel/runtime-corejs3" "^7.18.6" - "@babel/traverse" "^7.18.8" - "@docusaurus/cssnano-preset" "2.3.1" - "@docusaurus/logger" "2.3.1" - "@docusaurus/mdx-loader" "2.3.1" - "@docusaurus/react-loadable" "5.5.2" - "@docusaurus/utils" "2.3.1" - "@docusaurus/utils-common" "2.3.1" - "@docusaurus/utils-validation" "2.3.1" - "@slorber/static-site-generator-webpack-plugin" "^4.0.7" - "@svgr/webpack" "^6.2.1" - autoprefixer "^10.4.7" - babel-loader "^8.2.5" - babel-plugin-dynamic-import-node "^2.3.3" - boxen "^6.2.1" - chalk "^4.1.2" - chokidar "^3.5.3" - clean-css "^5.3.0" - cli-table3 "^0.6.2" - combine-promises "^1.1.0" - commander "^5.1.0" - copy-webpack-plugin "^11.0.0" - core-js "^3.23.3" - css-loader "^6.7.1" - css-minimizer-webpack-plugin "^4.0.0" - cssnano "^5.1.12" - del "^6.1.1" - detect-port "^1.3.0" - escape-html "^1.0.3" - eta "^2.0.0" - file-loader "^6.2.0" - fs-extra "^10.1.0" - html-minifier-terser "^6.1.0" - html-tags "^3.2.0" - html-webpack-plugin "^5.5.0" - import-fresh "^3.3.0" - leven "^3.1.0" - lodash "^4.17.21" - mini-css-extract-plugin "^2.6.1" - postcss "^8.4.14" - postcss-loader "^7.0.0" - prompts "^2.4.2" - react-dev-utils "^12.0.1" - react-helmet-async "^1.3.0" - react-loadable "npm:@docusaurus/react-loadable@5.5.2" - react-loadable-ssr-addon-v5-slorber "^1.0.1" - react-router "^5.3.3" - react-router-config "^5.1.1" - react-router-dom "^5.3.3" - rtl-detect "^1.0.4" - semver "^7.3.7" - serve-handler "^6.1.3" - shelljs "^0.8.5" - terser-webpack-plugin "^5.3.3" - tslib "^2.4.0" - update-notifier "^5.1.0" - url-loader "^4.1.1" - wait-on "^6.0.1" - webpack "^5.73.0" - webpack-bundle-analyzer "^4.5.0" - webpack-dev-server "^4.9.3" - webpack-merge "^5.8.0" - webpackbar "^5.0.2" - "@docusaurus/cssnano-preset@2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/cssnano-preset/-/cssnano-preset-2.2.0.tgz#fc05044659051ae74ab4482afcf4a9936e81d523" @@ -1696,16 +1399,6 @@ postcss-sort-media-queries "^4.2.1" tslib "^2.4.0" -"@docusaurus/cssnano-preset@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@docusaurus/cssnano-preset/-/cssnano-preset-2.3.1.tgz#e042487655e3e062417855e12edb3f6eee8f5ecb" - integrity sha512-7mIhAROES6CY1GmCjR4CZkUfjTL6B3u6rKHK0ChQl2d1IevYXq/k/vFgvOrJfcKxiObpMnE9+X6R2Wt1KqxC6w== - dependencies: - cssnano-preset-advanced "^5.3.8" - postcss "^8.4.14" - postcss-sort-media-queries "^4.2.1" - tslib "^2.4.0" - "@docusaurus/logger@2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/logger/-/logger-2.2.0.tgz#ea2f7feda7b8675485933b87f06d9c976d17423f" @@ -1714,14 +1407,6 @@ chalk "^4.1.2" tslib "^2.4.0" -"@docusaurus/logger@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@docusaurus/logger/-/logger-2.3.1.tgz#d76aefb452e3734b4e0e645efc6cbfc0aae52869" - integrity sha512-2lAV/olKKVr9qJhfHFCaqBIl8FgYjbUFwgUnX76+cULwQYss+42ZQ3grHGFvI0ocN2X55WcYe64ellQXz7suqg== - dependencies: - chalk "^4.1.2" - tslib "^2.4.0" - "@docusaurus/mdx-loader@2.2.0", "@docusaurus/mdx-loader@>=2.0.1 <2.3.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-2.2.0.tgz#fd558f429e5d9403d284bd4214e54d9768b041a0" @@ -1745,29 +1430,6 @@ url-loader "^4.1.1" webpack "^5.73.0" -"@docusaurus/mdx-loader@2.3.1", "@docusaurus/mdx-loader@^2.0.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-2.3.1.tgz#7ec6acee5eff0a280e1b399ea4dd690b15a793f7" - integrity sha512-Gzga7OsxQRpt3392K9lv/bW4jGppdLFJh3luKRknCKSAaZrmVkOQv2gvCn8LAOSZ3uRg5No7AgYs/vpL8K94lA== - dependencies: - "@babel/parser" "^7.18.8" - "@babel/traverse" "^7.18.8" - "@docusaurus/logger" "2.3.1" - "@docusaurus/utils" "2.3.1" - "@mdx-js/mdx" "^1.6.22" - escape-html "^1.0.3" - file-loader "^6.2.0" - fs-extra "^10.1.0" - image-size "^1.0.1" - mdast-util-to-string "^2.0.0" - remark-emoji "^2.2.0" - stringify-object "^3.3.0" - tslib "^2.4.0" - unified "^9.2.2" - unist-util-visit "^2.0.3" - url-loader "^4.1.1" - webpack "^5.73.0" - "@docusaurus/module-type-aliases@2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/module-type-aliases/-/module-type-aliases-2.2.0.tgz#1e23e54a1bbb6fde1961e4fa395b1b69f4803ba5" @@ -1782,20 +1444,6 @@ react-helmet-async "*" react-loadable "npm:@docusaurus/react-loadable@5.5.2" -"@docusaurus/module-type-aliases@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@docusaurus/module-type-aliases/-/module-type-aliases-2.3.1.tgz#986186200818fed999be2e18d6c698eaf4683a33" - integrity sha512-6KkxfAVOJqIUynTRb/tphYCl+co3cP0PlHiMDbi+SzmYxMdgIrwYqH9yAnGSDoN6Jk2ZE/JY/Azs/8LPgKP48A== - dependencies: - "@docusaurus/react-loadable" "5.5.2" - "@docusaurus/types" "2.3.1" - "@types/history" "^4.7.11" - "@types/react" "*" - "@types/react-router-config" "*" - "@types/react-router-dom" "*" - react-helmet-async "*" - react-loadable "npm:@docusaurus/react-loadable@5.5.2" - "@docusaurus/plugin-content-blog@2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.2.0.tgz#dc55982e76771f4e678ac10e26d10e1da2011dc1" @@ -1840,28 +1488,6 @@ utility-types "^3.10.0" webpack "^5.73.0" -"@docusaurus/plugin-content-docs@^2.0.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.3.1.tgz#feae1555479558a55182f22f8a07acc5e0d7444d" - integrity sha512-DxztTOBEruv7qFxqUtbsqXeNcHqcVEIEe+NQoI1oi2DBmKBhW/o0MIal8lt+9gvmpx3oYtlwmLOOGepxZgJGkw== - dependencies: - "@docusaurus/core" "2.3.1" - "@docusaurus/logger" "2.3.1" - "@docusaurus/mdx-loader" "2.3.1" - "@docusaurus/module-type-aliases" "2.3.1" - "@docusaurus/types" "2.3.1" - "@docusaurus/utils" "2.3.1" - "@docusaurus/utils-validation" "2.3.1" - "@types/react-router-config" "^5.0.6" - combine-promises "^1.1.0" - fs-extra "^10.1.0" - import-fresh "^3.3.0" - js-yaml "^4.1.0" - lodash "^4.17.21" - tslib "^2.4.0" - utility-types "^3.10.0" - webpack "^5.73.0" - "@docusaurus/plugin-content-pages@2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.2.0.tgz#e3f40408787bbe229545dd50595f87e1393bc3ae" @@ -1980,7 +1606,7 @@ tslib "^2.4.0" utility-types "^3.10.0" -"@docusaurus/theme-common@2.2.0", "@docusaurus/theme-common@^2.0.1": +"@docusaurus/theme-common@2.2.0", "@docusaurus/theme-common@>=2.0.1 <2.3.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/theme-common/-/theme-common-2.2.0.tgz#2303498d80448aafdd588b597ce9d6f4cfa930e4" integrity sha512-R8BnDjYoN90DCL75gP7qYQfSjyitXuP9TdzgsKDmSFPNyrdE3twtPNa2dIN+h+p/pr+PagfxwWbd6dn722A1Dw== @@ -2044,20 +1670,6 @@ webpack "^5.73.0" webpack-merge "^5.8.0" -"@docusaurus/types@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-2.3.1.tgz#785ade2e0f4e35e1eb7fb0d04c27d11c3991a2e8" - integrity sha512-PREbIRhTaNNY042qmfSE372Jb7djZt+oVTZkoqHJ8eff8vOIc2zqqDqBVc5BhOfpZGPTrE078yy/torUEZy08A== - dependencies: - "@types/history" "^4.7.11" - "@types/react" "*" - commander "^5.1.0" - joi "^17.6.0" - react-helmet-async "^1.3.0" - utility-types "^3.10.0" - webpack "^5.73.0" - webpack-merge "^5.8.0" - "@docusaurus/utils-common@2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/utils-common/-/utils-common-2.2.0.tgz#a401c1b93a8697dd566baf6ac64f0fdff1641a78" @@ -2065,13 +1677,6 @@ dependencies: tslib "^2.4.0" -"@docusaurus/utils-common@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@docusaurus/utils-common/-/utils-common-2.3.1.tgz#1abe66846eb641547e4964d44f3011938e58e50b" - integrity sha512-pVlRpXkdNcxmKNxAaB1ya2hfCEvVsLDp2joeM6K6uv55Oc5nVIqgyYSgSNKZyMdw66NnvMfsu0RBylcwZQKo9A== - dependencies: - tslib "^2.4.0" - "@docusaurus/utils-validation@2.2.0", "@docusaurus/utils-validation@>=2.0.1 <2.3.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-2.2.0.tgz#04d4d103137ad0145883971d3aa497f4a1315f25" @@ -2083,17 +1688,6 @@ js-yaml "^4.1.0" tslib "^2.4.0" -"@docusaurus/utils-validation@2.3.1", "@docusaurus/utils-validation@^2.0.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-2.3.1.tgz#b65c718ba9b84b7a891bccf5ac6d19b57ee7d887" - integrity sha512-7n0208IG3k1HVTByMHlZoIDjjOFC8sbViHVXJx0r3Q+3Ezrx+VQ1RZ/zjNn6lT+QBCRCXlnlaoJ8ug4HIVgQ3w== - dependencies: - "@docusaurus/logger" "2.3.1" - "@docusaurus/utils" "2.3.1" - joi "^17.6.0" - js-yaml "^4.1.0" - tslib "^2.4.0" - "@docusaurus/utils@2.2.0", "@docusaurus/utils@>=2.0.1 <2.3.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-2.2.0.tgz#3d6f9b7a69168d5c92d371bf21c556a4f50d1da6" @@ -2115,32 +1709,10 @@ url-loader "^4.1.1" webpack "^5.73.0" -"@docusaurus/utils@2.3.1", "@docusaurus/utils@^2.0.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-2.3.1.tgz#24b9cae3a23b1e6dc88f95c45722c7e82727b032" - integrity sha512-9WcQROCV0MmrpOQDXDGhtGMd52DHpSFbKLfkyaYumzbTstrbA5pPOtiGtxK1nqUHkiIv8UwexS54p0Vod2I1lg== - dependencies: - "@docusaurus/logger" "2.3.1" - "@svgr/webpack" "^6.2.1" - escape-string-regexp "^4.0.0" - file-loader "^6.2.0" - fs-extra "^10.1.0" - github-slugger "^1.4.0" - globby "^11.1.0" - gray-matter "^4.0.3" - js-yaml "^4.1.0" - lodash "^4.17.21" - micromatch "^4.0.5" - resolve-pathname "^3.0.0" - shelljs "^0.8.5" - tslib "^2.4.0" - url-loader "^4.1.1" - webpack "^5.73.0" - "@exodus/schemasafe@^1.0.0-rc.2": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@exodus/schemasafe/-/schemasafe-1.0.0.tgz#f44e252665b1a6bdef0d686e22af3599a6f0a095" - integrity sha512-2cyupPIZI69HQxEAPllLXBjQp4njDKkOjYRCYxvMZe3/LY9pp9fBM3Tb1wiFAdP6Emo4v3OEbCLGj6u73Q5KLw== + version "1.1.1" + resolved "https://registry.yarnpkg.com/@exodus/schemasafe/-/schemasafe-1.1.1.tgz#006ab8b33b1aec6d2992c75e5918c65197388aa2" + integrity sha512-Pd7+aGvWIaTDL5ecV4ZBEtBrjXnk8/ly5xyHbikxVhgcq7qhihzHWHbcYmFupQBT2A5ggNZGvT7Bpj0M6AKHjA== "@hapi/hoek@^9.0.0": version "9.3.0" @@ -2155,98 +1727,77 @@ "@hapi/hoek" "^9.0.0" "@headlessui/react@^1.7.4": - version "1.7.13" - resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.7.13.tgz#fd150b394954e9f1d86ed2340cffd1217d6e7628" - integrity sha512-9n+EQKRtD9266xIHXdY5MfiXPDfYwl7zBM7KOx2Ae3Gdgxy8QML1FkCMjq6AsOf0l6N9uvI4HcFtuFlenaldKg== + version "1.7.16" + resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.7.16.tgz#9c458c9c4dbb708258c9e8da3fe5363f915f7b11" + integrity sha512-2MphIAZdSUacZBT6EXk8AJkj+EuvaaJbtCyHTJrPsz8inhzCl7qeNPI1uk1AUvCgWylVtdN8cVVmnhUDPxPy3g== dependencies: client-only "^0.0.1" "@heroicons/react@^2.0.13": - version "2.0.16" - resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-2.0.16.tgz#562883c19ba2690c83380b42a9a5cce39dcbdb4a" - integrity sha512-x89rFxH3SRdYaA+JCXwfe+RkE1SFTo9GcOkZettHer71Y3T7V+ogKmfw5CjTazgS3d0ClJ7p1NA+SP7VQLQcLw== + version "2.0.18" + resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-2.0.18.tgz#f80301907c243df03c7e9fd76c0286e95361f7c1" + integrity sha512-7TyMjRrZZMBPa+/5Y8lN0iyvUU/01PeMGX2+RE7cQWpEUIcb4QotzUObFkJDejj/HUH4qjP/eQ0gzzKs2f+6Yw== -"@jest/schemas@^29.4.3": - version "29.4.3" - resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.4.3.tgz#39cf1b8469afc40b6f5a2baaa146e332c4151788" - integrity sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg== +"@jest/schemas@^29.6.0": + version "29.6.0" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.0.tgz#0f4cb2c8e3dca80c135507ba5635a4fd755b0040" + integrity sha512-rxLjXyJBTL4LQeJW3aKo0M/+GkCOXsO+8i9Iu7eDb6KwtP65ayoDsitrdPBtujxQ88k4wI2FNYfa6TOGwSn6cQ== dependencies: - "@sinclair/typebox" "^0.25.16" + "@sinclair/typebox" "^0.27.8" -"@jest/types@^29.5.0": - version "29.5.0" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.5.0.tgz#f59ef9b031ced83047c67032700d8c807d6e1593" - integrity sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog== +"@jest/types@^29.6.1": + version "29.6.1" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.1.tgz#ae79080278acff0a6af5eb49d063385aaa897bf2" + integrity sha512-tPKQNMPuXgvdOn2/Lg9HNfUvjYVGolt04Hp03f5hAk878uwOLikN+JzeLY0HcVgKgFl9Hs3EIqpu3WX27XNhnw== dependencies: - "@jest/schemas" "^29.4.3" + "@jest/schemas" "^29.6.0" "@types/istanbul-lib-coverage" "^2.0.0" "@types/istanbul-reports" "^3.0.0" "@types/node" "*" "@types/yargs" "^17.0.8" chalk "^4.0.0" -"@jridgewell/gen-mapping@^0.1.0": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" - integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== - dependencies: - "@jridgewell/set-array" "^1.0.0" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": - version "0.3.2" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" - integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== + version "0.3.3" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" + integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== dependencies: "@jridgewell/set-array" "^1.0.1" "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.9" -"@jridgewell/resolve-uri@3.0.7": - version "3.0.7" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz#30cd49820a962aff48c8fffc5cd760151fca61fe" - integrity sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA== - -"@jridgewell/resolve-uri@3.1.0", "@jridgewell/resolve-uri@^3.0.3": +"@jridgewell/resolve-uri@3.1.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== -"@jridgewell/set-array@1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.1.tgz#36a6acc93987adcf0ba50c66908bd0b70de8afea" - integrity sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ== - -"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": +"@jridgewell/set-array@^1.0.1": version "1.1.2" resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== -"@jridgewell/source-map@^0.3.2": - version "0.3.2" - resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb" - integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw== +"@jridgewell/source-map@^0.3.3": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.5.tgz#a3bb4d5c6825aab0d281268f47f6ad5853431e91" + integrity sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ== dependencies: "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" -"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10": +"@jridgewell/sourcemap-codec@1.4.14": version "1.4.14" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== -"@jridgewell/trace-mapping@0.3.11": - version "0.3.11" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.11.tgz#eb2e124521f27673493030d02dffedf60e56553f" - integrity sha512-RllI476aSMsxzeI9TtlSMoNTgHDxEmnl6GkkHwhr0vdL8W+0WuesyI8Vd3rBOfrwtPXbPxdT9ADJdiOKgzxPQA== - dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.17" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985" - integrity sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g== + version "0.3.18" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6" + integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA== dependencies: "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" @@ -2256,12 +1807,12 @@ resolved "https://registry.yarnpkg.com/@jsdevtools/ono/-/ono-7.1.3.tgz#9df03bbd7c696a5c58885c34aa06da41c8543796" integrity sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg== -"@leichtgewicht/ip-codec@2.0.4", "@leichtgewicht/ip-codec@^2.0.1": +"@leichtgewicht/ip-codec@^2.0.1": version "2.0.4" resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b" integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A== -"@mdx-js/mdx@1.6.22", "@mdx-js/mdx@^1.6.22": +"@mdx-js/mdx@^1.6.22": version "1.6.22" resolved "https://registry.yarnpkg.com/@mdx-js/mdx/-/mdx-1.6.22.tgz#8a723157bf90e78f17dc0f27995398e6c731f1ba" integrity sha512-AMxuLxPz2j5/6TpF/XSdKpQP1NlG0z11dFOlq+2IP/lSgl11GY8ji6S/rgsViN/L0BDvHvUMruRb7ub+24LUYA== @@ -2334,10 +1885,10 @@ path-browserify "1.0.1" yaml "1.10.2" -"@paloaltonetworks/postman-code-generators@1.1.13", "@paloaltonetworks/postman-code-generators@^1.1.12": - version "1.1.13" - resolved "https://registry.yarnpkg.com/@paloaltonetworks/postman-code-generators/-/postman-code-generators-1.1.13.tgz#49dc9baf4d98415fb5395c1aad0bd5362a43c845" - integrity sha512-7OA5k0ngMg/2ODqA6QjqUsauScnCKVvQuTdJbN02fqK/8jDEirEIWstPet5gF663WinuGvIr6sLIveR55w91LQ== +"@paloaltonetworks/postman-code-generators@1.1.15-patch.2": + version "1.1.15-patch.2" + resolved "https://registry.yarnpkg.com/@paloaltonetworks/postman-code-generators/-/postman-code-generators-1.1.15-patch.2.tgz#012051485269a2da6bd9a6b60031ddbc53e5e363" + integrity sha512-tRnAKtV4M8wLxcVnAx6ZCjCqbrR1xiqJNQkf1A71K8UxEP3N/+EspT82N5c0555w02oYFk21ViHuzuhm4gaGLw== dependencies: "@paloaltonetworks/postman-collection" "^4.1.0" async "^3.2.4" @@ -2375,10 +1926,10 @@ require-from-string "^2.0.2" uri-js "^4.2.2" -"@redocly/openapi-core@^1.0.0-beta.103": - version "1.0.0-beta.124" - resolved "https://registry.yarnpkg.com/@redocly/openapi-core/-/openapi-core-1.0.0-beta.124.tgz#8f7d129241bbc4597693f0863c906ded1b1dadbb" - integrity sha512-WvRRR4z1zJgs55fM5wdFrZ9WzuFT8QeEVRgvmERhi/kJcGEUGKHgezuDMmIhDUAnxi/+eJJfwAnLnUzC4c69Fg== +"@redocly/openapi-core@^1.0.0-beta.125": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@redocly/openapi-core/-/openapi-core-1.0.0.tgz#0961f9d6b30d45af5affb1aeda9c2b6d0a035ea9" + integrity sha512-wECCRB0obZuepmqmIUdwU0BB+YO3ibu0sX4IMLGgqWGa7etV14Yq0zjggdcArs3ynki2tBiop7p/+Q37FtsCpw== dependencies: "@redocly/ajv" "^8.11.0" "@types/node" "^14.11.8" @@ -2392,19 +1943,19 @@ yaml-ast-parser "0.0.43" "@reduxjs/toolkit@^1.7.1": - version "1.9.3" - resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.9.3.tgz#27e1a33072b5a312e4f7fa19247fec160bbb2df9" - integrity sha512-GU2TNBQVofL09VGmuSioNPQIu6Ml0YLf4EJhgj0AvBadRlCGzUWet8372LjvO4fqKZF2vH1xU0htAa7BrK9pZg== + version "1.9.5" + resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.9.5.tgz#d3987849c24189ca483baa7aa59386c8e52077c4" + integrity sha512-Rt97jHmfTeaxL4swLRNPD/zV4OxTes4la07Xc4hetpUW/vc75t5m1ANyxG6ymnEQ2FsLQsoMlYB2vV1sO3m8tQ== dependencies: - immer "^9.0.16" - redux "^4.2.0" + immer "^9.0.21" + redux "^4.2.1" redux-thunk "^2.4.2" - reselect "^4.1.7" + reselect "^4.1.8" -"@saucelabs/theme-github-codeblock@^0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@saucelabs/theme-github-codeblock/-/theme-github-codeblock-0.1.1.tgz#d2caa3fbf56c38ae2fe974871f1188226bb57d92" - integrity sha512-iHzODYjcUAYI4eJzLrNCw/Iq9SWxCKB/cMgEKHjRmNMb2NKch1dsI2ZSCg8lNedIPmOaRfqHT29hLyMoc/5Wpg== +"@saucelabs/theme-github-codeblock@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@saucelabs/theme-github-codeblock/-/theme-github-codeblock-0.2.3.tgz#706a43292f600532271979941b0155db667c2c21" + integrity sha512-GSl3Lr/jOWm4OP3BPX2vXxc8FMSOXj1mJnls6cUqMwlGOfKQ1Ia9pq1O9/ES+5TrZHIzAws/n5FFSn1OkGJw/Q== "@sideway/address@^4.1.3": version "4.1.4" @@ -2423,26 +1974,16 @@ resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== -"@sinclair/typebox@^0.25.16": - version "0.25.24" - resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.24.tgz#8c7688559979f7079aacaf31aa881c3aa410b718" - integrity sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ== +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== "@sindresorhus/is@^0.14.0": version "0.14.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== -"@slorber/static-site-generator-webpack-plugin@4.0.4": - version "4.0.4" - resolved "https://registry.yarnpkg.com/@slorber/static-site-generator-webpack-plugin/-/static-site-generator-webpack-plugin-4.0.4.tgz#2bf4a2545e027830d2aa5eb950437c26a289b0f1" - integrity sha512-FvMavoWEIePps6/JwGCOLYKCRhuwIHhMtmbKpBFgzNkxwpa/569LfTkrbRk1m1I3n+ezJK4on9E1A6cjuZmD9g== - dependencies: - bluebird "^3.7.1" - cheerio "^0.22.0" - eval "^0.1.8" - webpack-sources "^1.4.3" - "@slorber/static-site-generator-webpack-plugin@^4.0.7": version "4.0.7" resolved "https://registry.yarnpkg.com/@slorber/static-site-generator-webpack-plugin/-/static-site-generator-webpack-plugin-4.0.7.tgz#fc1678bddefab014e2145cbe25b3ce4e1cfc36f3" @@ -2458,14 +1999,14 @@ integrity sha512-9PYGcXrAxitycIjRmZB+Q0JaN07GZIWaTBIGQzfaZv+qr1n8X1XUEJ5rZ/vx6OVD9RRYlrNnXWExQXcmZeD/BQ== "@svgr/babel-plugin-remove-jsx-attribute@*": - version "6.5.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-6.5.0.tgz#652bfd4ed0a0699843585cda96faeb09d6e1306e" - integrity sha512-8zYdkym7qNyfXpWvu4yq46k41pyNM9SOstoWhKlm+IfdCE1DdnRKeMUPsWIEO/DEkaWxJ8T9esNdG3QwQ93jBA== + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz#69177f7937233caca3a1afb051906698f2f59186" + integrity sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA== "@svgr/babel-plugin-remove-jsx-empty-expression@*": - version "6.5.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-6.5.0.tgz#4b78994ab7d39032c729903fc2dd5c0fa4565cb8" - integrity sha512-NFdxMq3xA42Kb1UbzCVxplUc0iqSyM9X8kopImvFnB+uSDdzIHOdbs1op8ofAvVRtbg4oZiyRl3fTYeKcOe9Iw== + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz#c2c48104cfd7dcd557f373b70a56e9e3bdae1d44" + integrity sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA== "@svgr/babel-plugin-replace-jsx-attribute-value@^6.5.1": version "6.5.1" @@ -2506,15 +2047,6 @@ "@svgr/babel-plugin-transform-react-native-svg" "^6.5.1" "@svgr/babel-plugin-transform-svg-component" "^6.5.1" -"@svgr/core@6.2.1": - version "6.2.1" - resolved "https://registry.yarnpkg.com/@svgr/core/-/core-6.2.1.tgz#195de807a9f27f9e0e0d678e01084b05c54fdf61" - integrity sha512-NWufjGI2WUyrg46mKuySfviEJ6IxHUOm/8a3Ph38VCWSp+83HBraCQrpEM3F3dB6LBs5x8OElS8h3C0oOJaJAA== - dependencies: - "@svgr/plugin-jsx" "^6.2.1" - camelcase "^6.2.0" - cosmiconfig "^7.0.1" - "@svgr/core@^6.5.1": version "6.5.1" resolved "https://registry.yarnpkg.com/@svgr/core/-/core-6.5.1.tgz#d3e8aa9dbe3fbd747f9ee4282c1c77a27410488a" @@ -2526,14 +2058,6 @@ camelcase "^6.2.0" cosmiconfig "^7.0.1" -"@svgr/hast-util-to-babel-ast@6.2.1": - version "6.2.1" - resolved "https://registry.yarnpkg.com/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-6.2.1.tgz#ae065567b74cbe745afae617053adf9a764bea25" - integrity sha512-pt7MMkQFDlWJVy9ULJ1h+hZBDGFfSCwlBNW1HkLnVi7jUhyEXUaGYWi1x6bM2IXuAR9l265khBT4Av4lPmaNLQ== - dependencies: - "@babel/types" "^7.15.6" - entities "^3.0.1" - "@svgr/hast-util-to-babel-ast@^6.5.1": version "6.5.1" resolved "https://registry.yarnpkg.com/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-6.5.1.tgz#81800bd09b5bcdb968bf6ee7c863d2288fdb80d2" @@ -2542,7 +2066,7 @@ "@babel/types" "^7.20.0" entities "^4.4.0" -"@svgr/plugin-jsx@^6.2.1", "@svgr/plugin-jsx@^6.5.1": +"@svgr/plugin-jsx@^6.5.1": version "6.5.1" resolved "https://registry.yarnpkg.com/@svgr/plugin-jsx/-/plugin-jsx-6.5.1.tgz#0e30d1878e771ca753c94e69581c7971542a7072" integrity sha512-+UdQxI3jgtSjCykNSlEMuy1jSRQlGC7pqBCPvkG/2dATdWo082zHTTK3uhnAju2/6XpE6B5mZ3z4Z8Ns01S8Gw== @@ -2552,15 +2076,6 @@ "@svgr/hast-util-to-babel-ast" "^6.5.1" svg-parser "^2.0.4" -"@svgr/plugin-svgo@6.2.0": - version "6.2.0" - resolved "https://registry.yarnpkg.com/@svgr/plugin-svgo/-/plugin-svgo-6.2.0.tgz#4cbe6a33ccccdcae4e3b63ded64cc1cbe1faf48c" - integrity sha512-oDdMQONKOJEbuKwuy4Np6VdV6qoaLLvoY86hjvQEgU82Vx1MSWRyYms6Sl0f+NtqxLI/rDVufATbP/ev996k3Q== - dependencies: - cosmiconfig "^7.0.1" - deepmerge "^4.2.2" - svgo "^2.5.0" - "@svgr/plugin-svgo@^6.5.1": version "6.5.1" resolved "https://registry.yarnpkg.com/@svgr/plugin-svgo/-/plugin-svgo-6.5.1.tgz#0f91910e988fc0b842f88e0960c2862e022abe84" @@ -2584,71 +2099,71 @@ "@svgr/plugin-jsx" "^6.5.1" "@svgr/plugin-svgo" "^6.5.1" -"@swc/core-darwin-arm64@1.3.41": - version "1.3.41" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.41.tgz#c8ec25fb3171e1e53546d0fbf4044c33d5ab42c5" - integrity sha512-D4fybODToO/BvuP35bionDUrSuTVVr8eW+mApr1unOqb3mfiqOrVv0VP2fpWNRYiA+xMq+oBCB6KcGpL60HKWQ== +"@swc/core-darwin-arm64@1.3.74": + version "1.3.74" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.74.tgz#5ec6f504fb8cd74fd5133080f6cc670327a867cd" + integrity sha512-2rMV4QxM583jXcREfo0MhV3Oj5pgRSfSh/kVrB1twL2rQxOrbzkAPT/8flmygdVoL4f2F7o1EY5lKlYxEBiIKQ== -"@swc/core-darwin-x64@1.3.41": - version "1.3.41" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.3.41.tgz#0f9d7077762f4274d50a8ef76a56b76096a8f0ff" - integrity sha512-0RoVyiPCnylf3TG77C3S86PRSmaq+SaYB4VDLJFz3qcEHz1pfP0LhyskhgX4wjQV1mveDzFEn1BVAuo0eOMwZA== +"@swc/core-darwin-x64@1.3.74": + version "1.3.74" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.3.74.tgz#5da7bdc4ad0fb3b4375d9c1039672ae8f61efaeb" + integrity sha512-KKEGE1wXneYXe15fWDRM8/oekd/Q4yAuccA0vWY/7i6nOSPqWYcSDR0nRtR030ltDxWt0rk/eCTmNkrOWrKs3A== -"@swc/core-linux-arm-gnueabihf@1.3.41": - version "1.3.41" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.41.tgz#5f6a03c4e8cae674b6262fc0d625379af14985be" - integrity sha512-mZW7GeY7Uw1nkKoWpx898ou20oCSt8MR+jAVuAhMjX+G4Zr0WWXYSigWNiRymhR6Q9KhyvoFpMckguSvYWmXsw== +"@swc/core-linux-arm-gnueabihf@1.3.74": + version "1.3.74" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.74.tgz#52d818692aaaf9138e1175956271cae8107c1096" + integrity sha512-HehH5DR6r/5fIVu7tu8ZqgrHkhSCQNewf1ztFQJgcmaQWn+H4AJERBjwkjosqh4TvUJucZv8vyRTvrFeBXaCSA== -"@swc/core-linux-arm64-gnu@1.3.41": - version "1.3.41" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.41.tgz#e1c0a1669873dbab9ecb9573c2f7dd81b764212e" - integrity sha512-e91LGn+6KuLFw3sWk5swwGc/dP4tXs0mg3HrhjImRoofU02Bb9aHcj5zgrSO8ZByvDtm/Knn16h1ojxIMOFaxg== +"@swc/core-linux-arm64-gnu@1.3.74": + version "1.3.74" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.74.tgz#b230ba8623edb3c4b9ceffaf9aced8bf7a9fc829" + integrity sha512-+xkbCRz/wczgdknoV4NwYxbRI2dD7x/qkIFcVM2buzLCq8oWLweuV8+aL4pRqu0qDh7ZSb1jcaVTUIsySCJznA== -"@swc/core-linux-arm64-musl@1.3.41": - version "1.3.41" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.41.tgz#add780ae831a72a65ec799009d0c0e3e78bb969c" - integrity sha512-Q7hmrniLWsQ7zjtImGcjx1tl5/Qxpel+fC+OXTnGvAyyoGssSftIBlXMnqVLteL78zhxIPAzi+gizWAe5RGqrA== +"@swc/core-linux-arm64-musl@1.3.74": + version "1.3.74" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.74.tgz#05ff0f3046aba1dd9d2d8793c10cd4a21a46fd7f" + integrity sha512-maKFZSCD3tQznzPV7T3V+TtiWZFEFM8YrnSS5fQNNb+K9J65sL+170uTb3M7H4cFkG+9Sm5k5yCrCIutlvV48g== -"@swc/core-linux-x64-gnu@1.3.41": - version "1.3.41" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.41.tgz#5b2bf83493e6fa0a58c3fb1815b9e59b923e300f" - integrity sha512-h4sv1sCfZQgRIwmykz8WPqVpbvHb13Qm3SsrbOudhAp2MuzpWzsgMP5hAEpdCP/nWreiCz3aoM6L8JeakRDq0g== +"@swc/core-linux-x64-gnu@1.3.74": + version "1.3.74" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.74.tgz#a98d9a984d47404aa2de478dd3cd33dbd195bba2" + integrity sha512-LEXpcShF6DLTWJSiBhMSYZkLQ27UvaQ24fCFhoIV/R3dhYaUpHmIyLPPBNC82T03lB3ONUFVwrRw6fxDJ/f00A== -"@swc/core-linux-x64-musl@1.3.41": - version "1.3.41" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.41.tgz#146547ea3e62466ca971d71ebcc4cfeed3008bda" - integrity sha512-Z7c26i38378d0NT/dcz8qPSAXm41lqhNzykdhKhI+95mA9m4pskP18T/0I45rmyx1ywifypu+Ip+SXmKeVSPgQ== +"@swc/core-linux-x64-musl@1.3.74": + version "1.3.74" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.74.tgz#95e04431eba994b4fae23c578ad1ba73fb72c21d" + integrity sha512-sxsFctbFMZEFmDE7CmYljG0dMumH8XBTwwtGr8s6z0fYAzXBGNq2AFPcmEh2np9rPWkt7pE1m0ByESD+dMkbxQ== -"@swc/core-win32-arm64-msvc@1.3.41": - version "1.3.41" - resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.41.tgz#91e438c1ca102b52172294905821b43f9d429a32" - integrity sha512-I0CYnPc+ZGc912YeN0TykIOf/Q7yJQHRwDuhewwD6RkbiSEaVfSux5pAmmdoKw2aGMSq+cwLmgPe9HYLRNz+4w== +"@swc/core-win32-arm64-msvc@1.3.74": + version "1.3.74" + resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.74.tgz#62cb708094a8902a307fba6eea08682dbccd472d" + integrity sha512-F7hY9/BjFCozA4YPFYFH5FGCyWwa44vIXHqG66F5cDwXDGFn8ZtBsYIsiPfUYcx0AeAo1ojnVWKPxokZhYNYqA== -"@swc/core-win32-ia32-msvc@1.3.41": - version "1.3.41" - resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.41.tgz#77bdb6ab0ae942039756d41300c47315357bd814" - integrity sha512-EygN4CVDWF29/U2T5fXGfWyLvRbMd2hiUgkciAl7zHuyJ6nKl+kpodqV2A0Wd4sFtSNedU0gQEBEXEe7cqvmsA== +"@swc/core-win32-ia32-msvc@1.3.74": + version "1.3.74" + resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.74.tgz#fe5a2d8bbddb609e554e0d8d678093973096330c" + integrity sha512-qBAsiD1AlIdqED6wy3UNRHyAys9pWMUidX0LJ6mj24r/vfrzzTBAUrLJe5m7bzE+F1Rgi001avYJeEW1DLEJ+Q== -"@swc/core-win32-x64-msvc@1.3.41": - version "1.3.41" - resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.41.tgz#a8d766fc7a68752a3060276a90b7328d9f266631" - integrity sha512-Mfp8qD1hNwWWRy0ISdwQJu1g0UYoVTtuQlO0z3aGbXqL51ew9e56+8j3M1U9i95lXFyWkARgjDCcKkQi+WezyA== +"@swc/core-win32-x64-msvc@1.3.74": + version "1.3.74" + resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.74.tgz#4fd459c7264d4c97d1b2965ed6aa86b1725ce38b" + integrity sha512-S3YAvvLprTnPRwQuy9Dkwubb5SRLpVK3JJsqYDbGfgj8PGQyKHZcVJ5X3nfFsoWLy3j9B/3Os2nawprRSzeC5A== -"@swc/core@^1.3.36": - version "1.3.41" - resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.3.41.tgz#8f10559db269da1a5df9863c92653f8afd0bd7c1" - integrity sha512-v6P2dfqJDpZ/7RXPvWge9oI6YgolDM0jtNhQZ2qdXrLBzaWQdDoBGBTJ8KN/nTgGhX3IkNvSB1fafXQ+nVnqAQ== +"@swc/core@^1.3.74": + version "1.3.74" + resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.3.74.tgz#b1d1a3c46ca32b7f10d970c8a209d2913c9de251" + integrity sha512-P+MIExOTdWlfq8Heb1/NhBAke6UTckd4cRDuJoFcFMGBRvgoCMNWhnfP3FRRXPLI7GGg27dRZS+xHiqYyQmSrA== optionalDependencies: - "@swc/core-darwin-arm64" "1.3.41" - "@swc/core-darwin-x64" "1.3.41" - "@swc/core-linux-arm-gnueabihf" "1.3.41" - "@swc/core-linux-arm64-gnu" "1.3.41" - "@swc/core-linux-arm64-musl" "1.3.41" - "@swc/core-linux-x64-gnu" "1.3.41" - "@swc/core-linux-x64-musl" "1.3.41" - "@swc/core-win32-arm64-msvc" "1.3.41" - "@swc/core-win32-ia32-msvc" "1.3.41" - "@swc/core-win32-x64-msvc" "1.3.41" + "@swc/core-darwin-arm64" "1.3.74" + "@swc/core-darwin-x64" "1.3.74" + "@swc/core-linux-arm-gnueabihf" "1.3.74" + "@swc/core-linux-arm64-gnu" "1.3.74" + "@swc/core-linux-arm64-musl" "1.3.74" + "@swc/core-linux-x64-gnu" "1.3.74" + "@swc/core-linux-x64-musl" "1.3.74" + "@swc/core-win32-arm64-msvc" "1.3.74" + "@swc/core-win32-ia32-msvc" "1.3.74" + "@swc/core-win32-x64-msvc" "1.3.74" "@szmarczak/http-timer@^1.1.2": version "1.1.2" @@ -2678,9 +2193,9 @@ "@types/node" "*" "@types/connect-history-api-fallback@^1.3.5": - version "1.3.5" - resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz#d1f7a8a09d0ed5a57aee5ae9c18ab9b803205dae" - integrity sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw== + version "1.5.0" + resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz#9fd20b3974bdc2bcd4ac6567e2e0f6885cb2cf41" + integrity sha512-4x5FkPpLipqwthjPsF7ZRbOv3uoLUFkTA9G9v583qi4pACvq0uTELrB8OLUzPWUI4IJIyvM85vzkV1nyiI2Lig== dependencies: "@types/express-serve-static-core" "*" "@types/node" "*" @@ -2693,20 +2208,12 @@ "@types/node" "*" "@types/debug@^4.0.0": - version "4.1.7" - resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.7.tgz#7cc0ea761509124709b8b2d1090d8f6c17aadb82" - integrity sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg== + version "4.1.8" + resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.8.tgz#cef723a5d0a90990313faec2d1e22aee5eecb317" + integrity sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ== dependencies: "@types/ms" "*" -"@types/eslint-scope@3.7.3": - version "3.7.3" - resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.3.tgz#125b88504b61e3c8bc6f870882003253005c3224" - integrity sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g== - dependencies: - "@types/eslint" "*" - "@types/estree" "*" - "@types/eslint-scope@^3.7.3": version "3.7.4" resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz#37fc1223f0786c39627068a12e94d6e6fc61de16" @@ -2716,31 +2223,27 @@ "@types/estree" "*" "@types/eslint@*": - version "8.21.2" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.21.2.tgz#2b61b43a8b0e66006856a2a4c8e51f6f773ead27" - integrity sha512-EMpxUyystd3uZVByZap1DACsMXvb82ypQnGn89e1Y0a+LYu3JJscUd/gqhRsVFDkaD2MIiWo0MT8EfXr3DGRKw== + version "8.44.1" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.44.1.tgz#d1811559bb6bcd1a76009e3f7883034b78a0415e" + integrity sha512-XpNDc4Z5Tb4x+SW1MriMVeIsMoONHCkWFMkR/aPJbzEsxqHy+4Glu/BqTdPrApfDeMaXbtNh6bseNgl5KaWrSg== dependencies: "@types/estree" "*" "@types/json-schema" "*" -"@types/estree@*": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2" - integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ== - -"@types/estree@^0.0.51": - version "0.0.51" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40" - integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== +"@types/estree@*", "@types/estree@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.1.tgz#aa22750962f3bf0e79d753d3cc067f010c95f194" + integrity sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA== "@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.33": - version "4.17.33" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz#de35d30a9d637dc1450ad18dd583d75d5733d543" - integrity sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA== + version "4.17.35" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz#c95dd4424f0d32e525d23812aa8ab8e4d3906c4f" + integrity sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg== dependencies: "@types/node" "*" "@types/qs" "*" "@types/range-parser" "*" + "@types/send" "*" "@types/express@*", "@types/express@^4.17.13": version "4.17.17" @@ -2753,11 +2256,11 @@ "@types/serve-static" "*" "@types/hast@^2.0.0": - version "2.3.4" - resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.4.tgz#8aa5ef92c117d20d974a82bdfb6a648b08c0bafc" - integrity sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g== + version "2.3.5" + resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.5.tgz#08caac88b44d0fdd04dc17a19142355f43bd8a7a" + integrity sha512-SvQi0L/lNpThgPoleH53cdjB3y9zpLlVjRbqB3rH8hx1jiRSBGAhyjV3H+URFjNVRqt2EdYNrbZE5IsGlNfpRg== dependencies: - "@types/unist" "*" + "@types/unist" "^2" "@types/history@^4.7.11": version "4.7.11" @@ -2777,17 +2280,15 @@ resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#4fc33a00c1d0c16987b1a20cf92d20614c55ac35" integrity sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg== -"@types/http-proxy@1.17.9": - version "1.17.9" - resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.9.tgz#7f0e7931343761efde1e2bf48c40f02f3f75705a" - integrity sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw== - dependencies: - "@types/node" "*" +"@types/http-errors@*": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.1.tgz#20172f9578b225f6c7da63446f56d4ce108d5a65" + integrity sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ== "@types/http-proxy@^1.17.8": - version "1.17.10" - resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.10.tgz#e576c8e4a0cc5c6a138819025a88e167ebb38d6c" - integrity sha512-Qs5aULi+zV1bwKAg5z1PWnDXWmsn+LxIvUGv6E2+OOMYhclZMO+OXd9pYVf2gLykf2I7IV2u7oTHwChPNsvJ7g== + version "1.17.11" + resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.11.tgz#0ca21949a5588d55ac2b659b69035c84bd5da293" + integrity sha512-HC8G7c1WmaF2ekqpnFq626xd3Zz0uvaqFmBJNRZCGEZCXkvSdJoNFn/8Ygbd9fKNQj8UzLdCETaI0UWPAjK7IA== dependencies: "@types/node" "*" @@ -2810,37 +2311,54 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.6", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": - version "7.0.11" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" - integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== +"@types/json-schema@*", "@types/json-schema@^7.0.11", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": + version "7.0.12" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" + integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== + +"@types/lodash.clonedeep@^4.5.7": + version "4.5.7" + resolved "https://registry.yarnpkg.com/@types/lodash.clonedeep/-/lodash.clonedeep-4.5.7.tgz#0e119f582ed6f9e6b373c04a644651763214f197" + integrity sha512-ccNqkPptFIXrpVqUECi60/DFxjNKsfoQxSQsgcBJCX/fuX1wgyQieojkcWH/KpE3xzLoWN/2k+ZeGqIN3paSvw== + dependencies: + "@types/lodash" "*" + +"@types/lodash@*": + version "4.14.196" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.196.tgz#a7c3d6fc52d8d71328b764e28e080b4169ec7a95" + integrity sha512-22y3o88f4a94mKljsZcanlNWPzO0uBsBdzLAngf2tp533LzZcQzb6+eZPJ+vCTt+bqF2XnvT9gejTLsAcJAJyQ== "@types/mdast@^3.0.0": - version "3.0.10" - resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.10.tgz#4724244a82a4598884cbbe9bcfd73dff927ee8af" - integrity sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA== + version "3.0.12" + resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.12.tgz#beeb511b977c875a5b0cc92eab6fcac2f0895514" + integrity sha512-DT+iNIRNX884cx0/Q1ja7NyUPpZuv0KPyL5rGNxm1WC1OtHstl7n4Jb7nk+xacNShQMbczJjt8uFzznpp6kYBg== dependencies: - "@types/unist" "*" + "@types/unist" "^2" "@types/mime@*": version "3.0.1" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10" integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA== +"@types/mime@^1": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" + integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== + "@types/ms@*": version "0.7.31" resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== "@types/node@*": - version "18.15.3" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.3.tgz#f0b991c32cfc6a4e7f3399d6cb4b8cf9a0315014" - integrity sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw== + version "20.4.6" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.6.tgz#b66b66c9bb5d49b199f03399e341c9d6036e9e88" + integrity sha512-q0RkvNgMweWWIvSMDiXhflGUKMdIxBo2M2tYM/0kEGDueQByFzK4KZAgu5YHGFNxziTlppNpTIBcqHQAxlfHdA== "@types/node@^14.11.8": - version "14.18.38" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.38.tgz#2169ca4b70aa59aa5a8923509e50619dde48b0cf" - integrity sha512-zMRIidN2Huikv/+/U7gRPFYsXDR/7IGqFZzTLnCEj5+gkrQjsowfamaxEnyvArct5hxGA3bTxMXlYhH78V6Cew== + version "14.18.54" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.54.tgz#fc304bd66419030141fa997dc5a9e0e374029ae8" + integrity sha512-uq7O52wvo2Lggsx1x21tKZgqkJpvwCseBBPtX/nKQfpVlEsLOb11zZ1CRsWUKvJF0+lzuA9jwvA7Pr2Wt7i3xw== "@types/node@^17.0.5": version "17.0.45" @@ -2887,16 +2405,16 @@ hoist-non-react-statics "^3.3.0" redux "^4.0.0" -"@types/react-router-config@*", "@types/react-router-config@5.0.6", "@types/react-router-config@^5.0.6": - version "5.0.6" - resolved "https://registry.yarnpkg.com/@types/react-router-config/-/react-router-config-5.0.6.tgz#87c5c57e72d241db900d9734512c50ccec062451" - integrity sha512-db1mx37a1EJDf1XeX8jJN7R3PZABmJQXR8r28yUjVMFSjkmnQo6X6pOEEmNl+Tp2gYQOGPdYbFIipBtdElZ3Yg== +"@types/react-router-config@*", "@types/react-router-config@^5.0.6": + version "5.0.7" + resolved "https://registry.yarnpkg.com/@types/react-router-config/-/react-router-config-5.0.7.tgz#36207a3fe08b271abee62b26993ee932d13cbb02" + integrity sha512-pFFVXUIydHlcJP6wJm7sDii5mD/bCmmAY0wQzq+M+uX7bqS95AQqHZWP1iNMKrWVQSuHIzj5qi9BvrtLX2/T4w== dependencies: "@types/history" "^4.7.11" "@types/react" "*" - "@types/react-router" "*" + "@types/react-router" "^5.1.0" -"@types/react-router-dom@*", "@types/react-router-dom@5.3.3": +"@types/react-router-dom@*": version "5.3.3" resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.3.3.tgz#e9d6b4a66fcdbd651a5f106c2656a30088cc1e83" integrity sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw== @@ -2905,7 +2423,7 @@ "@types/react" "*" "@types/react-router" "*" -"@types/react-router@*": +"@types/react-router@*", "@types/react-router@^5.1.0": version "5.1.20" resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.20.tgz#88eccaa122a82405ef3efbcaaa5dcdd9f021387c" integrity sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q== @@ -2914,9 +2432,9 @@ "@types/react" "*" "@types/react@*": - version "18.0.28" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.28.tgz#accaeb8b86f4908057ad629a26635fe641480065" - integrity sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew== + version "18.2.18" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.18.tgz#c8b233919eef1bdc294f6f34b37f9727ad677516" + integrity sha512-da4NTSeBv/P34xoZPhtcLkmZuJ+oYaCxHmyHzwaDQo9RQPBeXV+06gEk2FpqEcsX9XrnNLvRpVh6bdavDSjtiQ== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -2935,9 +2453,17 @@ "@types/node" "*" "@types/scheduler@*": - version "0.16.2" - resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" - integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== + version "0.16.3" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.3.tgz#cef09e3ec9af1d63d2a6cc5b383a737e24e6dcf5" + integrity sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ== + +"@types/send@*": + version "0.17.1" + resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.1.tgz#ed4932b8a2a805f1fe362a70f4e62d0ac994e301" + integrity sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q== + dependencies: + "@types/mime" "^1" + "@types/node" "*" "@types/serve-index@^1.9.1": version "1.9.1" @@ -2947,10 +2473,11 @@ "@types/express" "*" "@types/serve-static@*", "@types/serve-static@^1.13.10": - version "1.15.1" - resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.1.tgz#86b1753f0be4f9a1bee68d459fcda5be4ea52b5d" - integrity sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ== + version "1.15.2" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.2.tgz#3e5419ecd1e40e7405d34093f10befb43f63381a" + integrity sha512-J2LqtvFYCzaj8pVYKw8klQXrLLk7TBZmQ4ShlcdkELFKGwGMfevMLneMMRkMgZxotOD9wg497LpC7O8PcvAmfw== dependencies: + "@types/http-errors" "*" "@types/mime" "*" "@types/node" "*" @@ -2961,22 +2488,15 @@ dependencies: "@types/node" "*" -"@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2", "@types/unist@^2.0.3": - version "2.0.6" - resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" - integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ== +"@types/unist@^2", "@types/unist@^2.0.0", "@types/unist@^2.0.2", "@types/unist@^2.0.3": + version "2.0.7" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.7.tgz#5b06ad6894b236a1d2bd6b2f07850ca5c59cf4d6" + integrity sha512-cputDpIbFgLUaGQn6Vqg3/YsJwxUwHLO13v3i5ouxT4lat0khip9AEWxtERujXV9wxIB1EyF97BSJFt6vpdI8g== -"@types/ws@8.5.3": - version "8.5.3" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.3.tgz#7d25a1ffbecd3c4f2d35068d0b283c037003274d" - integrity sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w== - dependencies: - "@types/node" "*" - -"@types/ws@^8.5.1": - version "8.5.4" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.4.tgz#bb10e36116d6e570dd943735f86c933c1587b8a5" - integrity sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg== +"@types/ws@^8.5.5": + version "8.5.5" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.5.tgz#af587964aa06682702ee6dcbc7be41a80e4b28eb" + integrity sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg== dependencies: "@types/node" "*" @@ -2986,131 +2506,131 @@ integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== "@types/yargs@^17.0.8": - version "17.0.22" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.22.tgz#7dd37697691b5f17d020f3c63e7a45971ff71e9a" - integrity sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g== + version "17.0.24" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.24.tgz#b3ef8d50ad4aa6aecf6ddc97c580a00f5aa11902" + integrity sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw== dependencies: "@types/yargs-parser" "*" -"@webassemblyjs/ast@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7" - integrity sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw== +"@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24" + integrity sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q== dependencies: - "@webassemblyjs/helper-numbers" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/helper-numbers" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" -"@webassemblyjs/floating-point-hex-parser@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz#f6c61a705f0fd7a6aecaa4e8198f23d9dc179e4f" - integrity sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ== +"@webassemblyjs/floating-point-hex-parser@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431" + integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw== -"@webassemblyjs/helper-api-error@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz#1a63192d8788e5c012800ba6a7a46c705288fd16" - integrity sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg== +"@webassemblyjs/helper-api-error@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768" + integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q== -"@webassemblyjs/helper-buffer@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz#832a900eb444884cde9a7cad467f81500f5e5ab5" - integrity sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA== +"@webassemblyjs/helper-buffer@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz#b66d73c43e296fd5e88006f18524feb0f2c7c093" + integrity sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA== -"@webassemblyjs/helper-numbers@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz#64d81da219fbbba1e3bd1bfc74f6e8c4e10a62ae" - integrity sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ== +"@webassemblyjs/helper-numbers@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5" + integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g== dependencies: - "@webassemblyjs/floating-point-hex-parser" "1.11.1" - "@webassemblyjs/helper-api-error" "1.11.1" + "@webassemblyjs/floating-point-hex-parser" "1.11.6" + "@webassemblyjs/helper-api-error" "1.11.6" "@xtuc/long" "4.2.2" -"@webassemblyjs/helper-wasm-bytecode@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz#f328241e41e7b199d0b20c18e88429c4433295e1" - integrity sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q== +"@webassemblyjs/helper-wasm-bytecode@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9" + integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA== -"@webassemblyjs/helper-wasm-section@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz#21ee065a7b635f319e738f0dd73bfbda281c097a" - integrity sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg== +"@webassemblyjs/helper-wasm-section@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz#ff97f3863c55ee7f580fd5c41a381e9def4aa577" + integrity sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g== dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-buffer" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-buffer" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/wasm-gen" "1.11.6" -"@webassemblyjs/ieee754@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz#963929e9bbd05709e7e12243a099180812992614" - integrity sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ== +"@webassemblyjs/ieee754@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a" + integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg== dependencies: "@xtuc/ieee754" "^1.2.0" -"@webassemblyjs/leb128@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.1.tgz#ce814b45574e93d76bae1fb2644ab9cdd9527aa5" - integrity sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw== +"@webassemblyjs/leb128@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7" + integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ== dependencies: "@xtuc/long" "4.2.2" -"@webassemblyjs/utf8@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.1.tgz#d1f8b764369e7c6e6bae350e854dec9a59f0a3ff" - integrity sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ== +"@webassemblyjs/utf8@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a" + integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA== -"@webassemblyjs/wasm-edit@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz#ad206ebf4bf95a058ce9880a8c092c5dec8193d6" - integrity sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA== +"@webassemblyjs/wasm-edit@^1.11.5": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz#c72fa8220524c9b416249f3d94c2958dfe70ceab" + integrity sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw== dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-buffer" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - "@webassemblyjs/helper-wasm-section" "1.11.1" - "@webassemblyjs/wasm-gen" "1.11.1" - "@webassemblyjs/wasm-opt" "1.11.1" - "@webassemblyjs/wasm-parser" "1.11.1" - "@webassemblyjs/wast-printer" "1.11.1" + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-buffer" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/helper-wasm-section" "1.11.6" + "@webassemblyjs/wasm-gen" "1.11.6" + "@webassemblyjs/wasm-opt" "1.11.6" + "@webassemblyjs/wasm-parser" "1.11.6" + "@webassemblyjs/wast-printer" "1.11.6" -"@webassemblyjs/wasm-gen@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz#86c5ea304849759b7d88c47a32f4f039ae3c8f76" - integrity sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA== +"@webassemblyjs/wasm-gen@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz#fb5283e0e8b4551cc4e9c3c0d7184a65faf7c268" + integrity sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA== dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - "@webassemblyjs/ieee754" "1.11.1" - "@webassemblyjs/leb128" "1.11.1" - "@webassemblyjs/utf8" "1.11.1" + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" -"@webassemblyjs/wasm-opt@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz#657b4c2202f4cf3b345f8a4c6461c8c2418985f2" - integrity sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw== +"@webassemblyjs/wasm-opt@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz#d9a22d651248422ca498b09aa3232a81041487c2" + integrity sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g== dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-buffer" "1.11.1" - "@webassemblyjs/wasm-gen" "1.11.1" - "@webassemblyjs/wasm-parser" "1.11.1" + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-buffer" "1.11.6" + "@webassemblyjs/wasm-gen" "1.11.6" + "@webassemblyjs/wasm-parser" "1.11.6" -"@webassemblyjs/wasm-parser@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz#86ca734534f417e9bd3c67c7a1c75d8be41fb199" - integrity sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA== +"@webassemblyjs/wasm-parser@1.11.6", "@webassemblyjs/wasm-parser@^1.11.5": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz#bb85378c527df824004812bbdb784eea539174a1" + integrity sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ== dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-api-error" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - "@webassemblyjs/ieee754" "1.11.1" - "@webassemblyjs/leb128" "1.11.1" - "@webassemblyjs/utf8" "1.11.1" + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-api-error" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" -"@webassemblyjs/wast-printer@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz#d0c73beda8eec5426f10ae8ef55cee5e7084c2f0" - integrity sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg== +"@webassemblyjs/wast-printer@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz#a7bf8dd7e362aeb1668ff43f35cb849f188eff20" + integrity sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A== dependencies: - "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/ast" "1.11.6" "@xtuc/long" "4.2.2" "@xtuc/ieee754@^1.2.0": @@ -3123,6 +2643,13 @@ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== +abort-controller@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: version "1.3.8" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" @@ -3131,39 +2658,20 @@ accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: mime-types "~2.1.34" negotiator "0.6.3" -acorn-import-assertions@^1.7.6: - version "1.8.0" - resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9" - integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== - -acorn-node@^1.8.2: - version "1.8.2" - resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8" - integrity sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A== - dependencies: - acorn "^7.0.0" - acorn-walk "^7.0.0" - xtend "^4.0.2" - -acorn-walk@^7.0.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" - integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== +acorn-import-assertions@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" + integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== acorn-walk@^8.0.0: version "8.2.0" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== -acorn@^7.0.0: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== - -acorn@^8.0.4, acorn@^8.5.0, acorn@^8.7.1: - version "8.8.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" - integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== +acorn@^8.0.4, acorn@^8.7.1, acorn@^8.8.2: + version "8.10.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" + integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== address@^1.0.1, address@^1.1.2: version "1.2.2" @@ -3190,7 +2698,7 @@ ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv-keywords@^5.0.0: +ajv-keywords@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== @@ -3217,7 +2725,7 @@ ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.0, ajv@^8.8.0: +ajv@^8.0.0, ajv@^8.9.0: version "8.12.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== @@ -3228,31 +2736,31 @@ ajv@^8.0.0, ajv@^8.8.0: uri-js "^4.2.2" algoliasearch-helper@^3.10.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/algoliasearch-helper/-/algoliasearch-helper-3.12.0.tgz#0fe39d49b0290e4aa5e1fe733bd24d857d258e94" - integrity sha512-/j1U3PEwdan0n6P/QqSnSpNSLC5+cEMvyljd5CnmNmUjDlGrys+vFEOwjVEnqELIiAGMHEA/Nl3CiKVFBUYqyQ== + version "3.14.0" + resolved "https://registry.yarnpkg.com/algoliasearch-helper/-/algoliasearch-helper-3.14.0.tgz#2409c2591952719ab6fba1de77b3bbe5094ab85e" + integrity sha512-gXDXzsSS0YANn5dHr71CUXOo84cN4azhHKUbg71vAWnH+1JBiR4jf7to3t3JHXknXkbV0F7f055vUSBKrltHLQ== dependencies: "@algolia/events" "^4.0.1" algoliasearch@^4.0.0, algoliasearch@^4.13.1: - version "4.15.0" - resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.15.0.tgz#8279576f06667a1d0705e8c22a17daa8e707b469" - integrity sha512-+vgKQF5944dYsz9zhKk07JbOYeNdKisoD5GeG0woBL3nLzbn2a+nGwki60DXg7CXvaFXBcTXyJG4C+VaBVd44g== + version "4.19.1" + resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.19.1.tgz#18111fb422eaf841737adb92d5ab12133d244218" + integrity sha512-IJF5b93b2MgAzcE/tuzW0yOPnuUyRgGAtaPv5UUywXM8kzqfdwZTO4sPJBzoGz1eOy6H9uEchsJsBFTELZSu+g== dependencies: - "@algolia/cache-browser-local-storage" "4.15.0" - "@algolia/cache-common" "4.15.0" - "@algolia/cache-in-memory" "4.15.0" - "@algolia/client-account" "4.15.0" - "@algolia/client-analytics" "4.15.0" - "@algolia/client-common" "4.15.0" - "@algolia/client-personalization" "4.15.0" - "@algolia/client-search" "4.15.0" - "@algolia/logger-common" "4.15.0" - "@algolia/logger-console" "4.15.0" - "@algolia/requester-browser-xhr" "4.15.0" - "@algolia/requester-common" "4.15.0" - "@algolia/requester-node-http" "4.15.0" - "@algolia/transporter" "4.15.0" + "@algolia/cache-browser-local-storage" "4.19.1" + "@algolia/cache-common" "4.19.1" + "@algolia/cache-in-memory" "4.19.1" + "@algolia/client-account" "4.19.1" + "@algolia/client-analytics" "4.19.1" + "@algolia/client-common" "4.19.1" + "@algolia/client-personalization" "4.19.1" + "@algolia/client-search" "4.19.1" + "@algolia/logger-common" "4.19.1" + "@algolia/logger-console" "4.19.1" + "@algolia/requester-browser-xhr" "4.19.1" + "@algolia/requester-common" "4.19.1" + "@algolia/requester-node-http" "4.19.1" + "@algolia/transporter" "4.19.1" ansi-align@^3.0.0, ansi-align@^3.0.1: version "3.0.1" @@ -3340,16 +2848,31 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -array-union@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-3.0.1.tgz#da52630d327f8b88cfbfb57728e2af5cd9b6b975" - integrity sha512-1OvF9IbWwaeiM9VhzYXVQacMibxpXOMYVNIvMtKRyX9SImBXpKcFr8XvFDeEslCyuH/t6KRt7HEO94AlP8Iatw== - asap@^2.0.0, asap@~2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== +asn1.js@^5.2.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" + integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + safer-buffer "^2.1.0" + +assert@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-2.0.0.tgz#95fc1c616d48713510680f2eaf2d10dd22e02d32" + integrity sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A== + dependencies: + es6-object-assign "^1.1.0" + is-nan "^1.2.1" + object-is "^1.0.1" + util "^0.12.0" + async@3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/async/-/async-3.2.1.tgz#d3274ec66d107a47476a4c49136aacdb00665fc8" @@ -3370,7 +2893,7 @@ at-least-node@^1.0.0: resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== -autoprefixer@^10.3.7, autoprefixer@^10.4.12, autoprefixer@^10.4.13, autoprefixer@^10.4.7: +autoprefixer@^10.4.12, autoprefixer@^10.4.13, autoprefixer@^10.4.7: version "10.4.14" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.14.tgz#e28d49902f8e759dd25b153264e862df2705f79d" integrity sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ== @@ -3382,23 +2905,18 @@ autoprefixer@^10.3.7, autoprefixer@^10.4.12, autoprefixer@^10.4.13, autoprefixer picocolors "^1.0.0" postcss-value-parser "^4.2.0" -axios@0.25.0, axios@^0.25.0: +available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== + +axios@^0.25.0: version "0.25.0" resolved "https://registry.yarnpkg.com/axios/-/axios-0.25.0.tgz#349cfbb31331a9b4453190791760a8d35b093e0a" integrity sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g== dependencies: follow-redirects "^1.14.7" -babel-loader@8.2.5: - version "8.2.5" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.5.tgz#d45f585e654d5a5d90f5350a779d7647c5ed512e" - integrity sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ== - dependencies: - find-cache-dir "^3.3.1" - loader-utils "^2.0.0" - make-dir "^3.1.0" - schema-utils "^2.6.5" - babel-loader@^8.2.5: version "8.3.0" resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.3.0.tgz#124936e841ba4fe8176786d6ff28add1f134d6a8" @@ -3431,44 +2949,29 @@ babel-plugin-extract-import-names@1.6.22: dependencies: "@babel/helper-plugin-utils" "7.10.4" -babel-plugin-polyfill-corejs2@^0.3.0, babel-plugin-polyfill-corejs2@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz#5d1bd3836d0a19e1b84bbf2d9640ccb6f951c122" - integrity sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q== +babel-plugin-polyfill-corejs2@^0.4.4: + version "0.4.5" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.5.tgz#8097b4cb4af5b64a1d11332b6fb72ef5e64a054c" + integrity sha512-19hwUH5FKl49JEsvyTcoHakh6BE0wgXLLptIyKZ3PijHc/Ci521wygORCUCCred+E/twuqRyAkE02BAWPmsHOg== dependencies: - "@babel/compat-data" "^7.17.7" - "@babel/helper-define-polyfill-provider" "^0.3.3" - semver "^6.1.1" + "@babel/compat-data" "^7.22.6" + "@babel/helper-define-polyfill-provider" "^0.4.2" + semver "^6.3.1" -babel-plugin-polyfill-corejs3@^0.5.0: - version "0.5.3" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.3.tgz#d7e09c9a899079d71a8b670c6181af56ec19c5c7" - integrity sha512-zKsXDh0XjnrUEW0mxIHLfjBfnXSMr5Q/goMe/fxpQnLm07mcOZiIZHBNWCMx60HmdvjxfXcalac0tfFg0wqxyw== +babel-plugin-polyfill-corejs3@^0.8.2: + version "0.8.3" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.3.tgz#b4f719d0ad9bb8e0c23e3e630c0c8ec6dd7a1c52" + integrity sha512-z41XaniZL26WLrvjy7soabMXrfPWARN25PZoriDEiLMxAp50AUW3t35BGQUMg5xK3UrpVTtagIDklxYa+MhiNA== dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.2" - core-js-compat "^3.21.0" + "@babel/helper-define-polyfill-provider" "^0.4.2" + core-js-compat "^3.31.0" -babel-plugin-polyfill-corejs3@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz#56ad88237137eade485a71b52f72dbed57c6230a" - integrity sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA== +babel-plugin-polyfill-regenerator@^0.5.1: + version "0.5.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.2.tgz#80d0f3e1098c080c8b5a65f41e9427af692dc326" + integrity sha512-tAlOptU0Xj34V1Y2PNTL4Y0FOJMDB6bZmoW39FeCQIhigGLkqu3Fj6uiXpxIf6Ij274ENdYx64y6Au+ZKlb1IA== dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.3" - core-js-compat "^3.25.1" - -babel-plugin-polyfill-regenerator@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz#2c0678ea47c75c8cc2fbb1852278d8fb68233990" - integrity sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.1" - -babel-plugin-polyfill-regenerator@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz#390f91c38d90473592ed43351e801a9d3e0fd747" - integrity sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.3" + "@babel/helper-define-polyfill-provider" "^0.4.2" bail@^1.0.0: version "1.0.5" @@ -3510,28 +3013,15 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== -bluebird@^3.7.1: - version "3.7.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: + version "4.12.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== -body-parser@1.20.0: - version "1.20.0" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.0.tgz#3de69bd89011c11573d7bfee6a64f11b6bd27cc5" - integrity sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg== - dependencies: - bytes "3.1.2" - content-type "~1.0.4" - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - http-errors "2.0.0" - iconv-lite "0.4.24" - on-finished "2.4.1" - qs "6.10.3" - raw-body "2.5.1" - type-is "~1.6.18" - unpipe "1.0.0" +bn.js@^5.0.0, bn.js@^5.1.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== body-parser@1.20.1: version "1.20.1" @@ -3551,45 +3041,21 @@ body-parser@1.20.1: type-is "~1.6.18" unpipe "1.0.0" -bonjour-service@1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/bonjour-service/-/bonjour-service-1.0.12.tgz#28fbd4683f5f2e36feedb833e24ba661cac960c3" - integrity sha512-pMmguXYCu63Ug37DluMKEHdxc+aaIf/ay4YbF8Gxtba+9d3u+rmEWy61VK3Z3hp8Rskok3BunHYnG0dUHAsblw== - dependencies: - array-flatten "^2.1.2" - dns-equal "^1.0.0" - fast-deep-equal "^3.1.3" - multicast-dns "^7.2.4" - bonjour-service@^1.0.11: - version "1.1.0" - resolved "https://registry.yarnpkg.com/bonjour-service/-/bonjour-service-1.1.0.tgz#424170268d68af26ff83a5c640b95def01803a13" - integrity sha512-LVRinRB3k1/K0XzZ2p58COnWvkQknIY6sf0zF2rpErvcJXpMBttEPQSxK+HEXSS9VmpZlDoDnQWv8ftJT20B0Q== + version "1.1.1" + resolved "https://registry.yarnpkg.com/bonjour-service/-/bonjour-service-1.1.1.tgz#960948fa0e0153f5d26743ab15baf8e33752c135" + integrity sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg== dependencies: array-flatten "^2.1.2" dns-equal "^1.0.0" fast-deep-equal "^3.1.3" multicast-dns "^7.2.5" -boolbase@^1.0.0, boolbase@~1.0.0: +boolbase@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== -boxen@6.2.1, boxen@^6.2.1: - version "6.2.1" - resolved "https://registry.yarnpkg.com/boxen/-/boxen-6.2.1.tgz#b098a2278b2cd2845deef2dff2efc38d329b434d" - integrity sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw== - dependencies: - ansi-align "^3.0.1" - camelcase "^6.2.0" - chalk "^4.1.2" - cli-boxes "^3.0.0" - string-width "^5.0.1" - type-fest "^2.5.0" - widest-line "^4.0.1" - wrap-ansi "^8.0.1" - boxen@^5.0.0: version "5.1.2" resolved "https://registry.yarnpkg.com/boxen/-/boxen-5.1.2.tgz#788cb686fc83c1f486dfa8a40c68fc2b831d2b50" @@ -3604,6 +3070,20 @@ boxen@^5.0.0: widest-line "^3.1.0" wrap-ansi "^7.0.0" +boxen@^6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-6.2.1.tgz#b098a2278b2cd2845deef2dff2efc38d329b434d" + integrity sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw== + dependencies: + ansi-align "^3.0.1" + camelcase "^6.2.0" + chalk "^4.1.2" + cli-boxes "^3.0.0" + string-width "^5.0.1" + type-fest "^2.5.0" + widest-line "^4.0.1" + wrap-ansi "^8.0.1" + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -3626,21 +3106,92 @@ braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" -browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.6, browserslist@^4.18.1, browserslist@^4.21.3, browserslist@^4.21.4, browserslist@^4.21.5: - version "4.21.5" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.5.tgz#75c5dae60063ee641f977e00edd3cfb2fb7af6a7" - integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w== +brorand@^1.0.1, brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== dependencies: - caniuse-lite "^1.0.30001449" - electron-to-chromium "^1.4.284" - node-releases "^2.0.8" - update-browserslist-db "^1.0.10" + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" + integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== + dependencies: + bn.js "^5.0.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" + integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== + dependencies: + bn.js "^5.1.1" + browserify-rsa "^4.0.1" + create-hash "^1.2.0" + create-hmac "^1.1.7" + elliptic "^6.5.3" + inherits "^2.0.4" + parse-asn1 "^5.1.5" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== + dependencies: + pako "~1.0.5" + +browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.18.1, browserslist@^4.21.4, browserslist@^4.21.5, browserslist@^4.21.9: + version "4.21.10" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.10.tgz#dbbac576628c13d3b2231332cb2ec5a46e015bb0" + integrity sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ== + dependencies: + caniuse-lite "^1.0.30001517" + electron-to-chromium "^1.4.477" + node-releases "^2.0.13" + update-browserslist-db "^1.0.11" buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== + buffer@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" @@ -3649,6 +3200,11 @@ buffer@^6.0.3: base64-js "^1.3.1" ieee754 "^1.2.1" +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + integrity sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ== + bytes@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" @@ -3723,10 +3279,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001449, caniuse-lite@^1.0.30001464: - version "1.0.30001467" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001467.tgz#1afc9c16ed61f50dd87139da87ca43a3e0051c77" - integrity sha512-cEdN/5e+RPikvl9AHm4uuLXxeCNq8rFsQ+lPHTfe/OtypP3WwnVVbjn+6uBV7PaFL6xUFzTh+sSCOz1rKhcO+Q== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001464, caniuse-lite@^1.0.30001517: + version "1.0.30001519" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001519.tgz#3e7b8b8a7077e78b0eb054d69e6edf5c7df35601" + integrity sha512-0QHgqR+Jv4bxHMp8kZ1Kn8CH55OikjKJ6JmKkZYP1F3D7w+lnFXF70nG5eNfsZS89jadi5Ywy5UCSKLAglIRkg== ccount@^1.0.0: version "1.1.0" @@ -3787,28 +3343,6 @@ cheerio-select@^2.1.0: domhandler "^5.0.3" domutils "^3.0.1" -cheerio@^0.22.0: - version "0.22.0" - resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-0.22.0.tgz#a9baa860a3f9b595a6b81b1a86873121ed3a269e" - integrity sha512-8/MzidM6G/TgRelkzDG13y3Y9LxBjCb+8yOEZ9+wwq5gVF2w2pV0wmHvjfT0RvuxGyR7UEuK36r+yYMbT4uKgA== - dependencies: - css-select "~1.2.0" - dom-serializer "~0.1.0" - entities "~1.1.1" - htmlparser2 "^3.9.1" - lodash.assignin "^4.0.9" - lodash.bind "^4.1.4" - lodash.defaults "^4.0.1" - lodash.filter "^4.4.0" - lodash.flatten "^4.2.0" - lodash.foreach "^4.3.0" - lodash.map "^4.4.0" - lodash.merge "^4.4.0" - lodash.pick "^4.2.1" - lodash.reduce "^4.4.0" - lodash.reject "^4.4.0" - lodash.some "^4.4.0" - cheerio@^1.0.0-rc.12: version "1.0.0-rc.12" resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.12.tgz#788bf7466506b1c6bf5fae51d24a2c4d62e47683" @@ -3852,12 +3386,13 @@ ci-info@^3.2.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== -clean-css@5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.0.tgz#ad3d8238d5f3549e83d5f87205189494bc7cbb59" - integrity sha512-YYuuxv4H/iNb1Z/5IbMRoxgrzjWGhOEFfd+groZ5dMCVkpENiMZmwspdrzBo9286JjM1gZJPAyL7ZIdzuvu2AQ== +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== dependencies: - source-map "~0.6.0" + inherits "^2.0.1" + safe-buffer "^5.0.1" clean-css@^5.2.2, clean-css@^5.3.0: version "5.3.2" @@ -3871,24 +3406,15 @@ clean-stack@^2.0.0: resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== -cli-boxes@3.0.0, cli-boxes@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-3.0.0.tgz#71a10c716feeba005e4504f36329ef0b17cf3145" - integrity sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g== - cli-boxes@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== -cli-table3@0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.2.tgz#aaf5df9d8b5bf12634dc8b3040806a0c07120d2a" - integrity sha512-QyavHCaIC80cMivimWu4aWHilIpiDpfm3hGmqAmXVL1UsnbLuBSMd21hTX6VY4ZSDSM73ESLeF8TOYId3rBTbw== - dependencies: - string-width "^4.2.0" - optionalDependencies: - "@colors/colors" "1.5.0" +cli-boxes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-3.0.0.tgz#71a10c716feeba005e4504f36329ef0b17cf3145" + integrity sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g== cli-table3@^0.6.2: version "0.6.3" @@ -3967,7 +3493,7 @@ color-name@1.1.3: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== -color-name@^1.1.4, color-name@~1.1.4: +color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== @@ -3983,9 +3509,9 @@ colorette@^1.2.0: integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g== colorette@^2.0.10: - version "2.0.19" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" - integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== combine-promises@^1.1.0: version "1.1.0" @@ -4014,11 +3540,6 @@ commander@2.20.3, commander@^2.20.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -commander@7, commander@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" - integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== - commander@^4.0.0, commander@~4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" @@ -4029,6 +3550,11 @@ commander@^5.1.0: resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== +commander@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" + integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== + commander@^8.3.0: version "8.3.0" resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" @@ -4100,11 +3626,6 @@ configstore@^5.0.1: write-file-atomic "^3.0.0" xdg-basedir "^4.0.0" -connect-history-api-fallback@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" - integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== - connect-history-api-fallback@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz#647264845251a0daf25b97ce87834cace0f5f1c8" @@ -4115,6 +3636,16 @@ consola@^2.15.3: resolved "https://registry.yarnpkg.com/consola/-/consola-2.15.3.tgz#2e11f98d6a4be71ff72e0bdf07bd23e12cb61550" integrity sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw== +console-browserify@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" + integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== + +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + integrity sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ== + content-disposition@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" @@ -4153,9 +3684,9 @@ cookiejar@^2.1.3: integrity sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw== copy-text-to-clipboard@^3.0.1: - version "3.1.0" - resolved "https://registry.yarnpkg.com/copy-text-to-clipboard/-/copy-text-to-clipboard-3.1.0.tgz#6bf40deef0a51ac6858efb0d76ded2c6d6a15059" - integrity sha512-PFM6BnjLnOON/lB3ta/Jg7Ywsv+l9kQGD4TWDCSlRBGmqnnTM5MrDkhAFgw+8HZt0wW6Q2BBE4cmy9sq+s9Qng== + version "3.2.0" + resolved "https://registry.yarnpkg.com/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.0.tgz#0202b2d9bdae30a49a53f898626dcc3b49ad960b" + integrity sha512-RnJFp1XR/LOBDckxTib5Qjr/PMfkatD0MUCQgdpqS8MdKiNUzBjAQBEN6oUy+jW7LI93BBG3DtMB2KOOKpGs2Q== copy-to-clipboard@^3.3.1: version "3.3.3" @@ -4164,18 +3695,6 @@ copy-to-clipboard@^3.3.1: dependencies: toggle-selection "^1.0.6" -copy-webpack-plugin@10.2.4: - version "10.2.4" - resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-10.2.4.tgz#6c854be3fdaae22025da34b9112ccf81c63308fe" - integrity sha512-xFVltahqlsRcyyJqQbDY6EYTtyQZF9rf+JPjwHObLdPFMEISqkFkr7mFoVOC6BfYS/dNThyoQKvziugm+OnwBg== - dependencies: - fast-glob "^3.2.7" - glob-parent "^6.0.1" - globby "^12.0.2" - normalize-path "^3.0.0" - schema-utils "^4.0.0" - serialize-javascript "^6.0.0" - copy-webpack-plugin@^11.0.0: version "11.0.0" resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz#96d4dbdb5f73d02dd72d0528d1958721ab72e04a" @@ -4188,52 +3707,28 @@ copy-webpack-plugin@^11.0.0: schema-utils "^4.0.0" serialize-javascript "^6.0.0" -core-js-compat@^3.21.0, core-js-compat@^3.22.1, core-js-compat@^3.25.1: - version "3.29.1" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.29.1.tgz#15c0fb812ea27c973c18d425099afa50b934b41b" - integrity sha512-QmchCua884D8wWskMX8tW5ydINzd8oSJVx38lx/pVkFGqztxt73GYre3pm/hyYq8bPf+MW5In4I/uRShFDsbrA== +core-js-compat@^3.31.0: + version "3.32.0" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.32.0.tgz#f41574b6893ab15ddb0ac1693681bd56c8550a90" + integrity sha512-7a9a3D1k4UCVKnLhrgALyFcP7YCsLOQIxPd0dKjf/6GuPcgyiGP70ewWdCGrSK7evyhymi0qO4EqCmSJofDeYw== dependencies: - browserslist "^4.21.5" + browserslist "^4.21.9" -core-js-pure@3.22.5: - version "3.22.5" - resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.22.5.tgz#bdee0ed2f9b78f2862cda4338a07b13a49b6c9a9" - integrity sha512-8xo9R00iYD7TcV7OrC98GwxiUEAabVWO3dix+uyWjnYrx9fyASLlIX+f/3p5dW5qByaP2bcZ8X/T47s55et/tA== - -core-js-pure@^3.20.2, core-js-pure@^3.25.1: - version "3.29.1" - resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.29.1.tgz#1be6ca2b8772f6b4df7fc4621743286e676c6162" - integrity sha512-4En6zYVi0i0XlXHVz/bi6l1XDjCqkKRq765NXuX+SnaIatlE96Odt5lMLjdxUiNI1v9OXI5DSLWYPlmTfkTktg== - -core-js@3.22.5: - version "3.22.5" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.22.5.tgz#a5f5a58e663d5c0ebb4e680cd7be37536fb2a9cf" - integrity sha512-VP/xYuvJ0MJWRAobcmQ8F2H6Bsn+s7zqAAjFaHGBMc5AQm7zaelhD1LGduFn2EehEcQcU+br6t+fwbpQ5d1ZWA== +core-js-pure@^3.30.2: + version "3.32.0" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.32.0.tgz#5d79f85da7a4373e9a06494ccbef995a4c639f8b" + integrity sha512-qsev1H+dTNYpDUEURRuOXMvpdtAnNEvQWS/FMJ2Vb5AY8ZP4rAPQldkE27joykZPJTe0+IVgHZYh1P5Xu1/i1g== core-js@^3.23.3: - version "3.29.1" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.29.1.tgz#40ff3b41588b091aaed19ca1aa5cb111803fa9a6" - integrity sha512-+jwgnhg6cQxKYIIjGtAHq2nwUOolo9eoFZ4sHfUH09BLXBgxnH4gA0zEd+t+BO2cNB8idaBtZFcFTRjQJRJmAw== + version "3.32.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.32.0.tgz#7643d353d899747ab1f8b03d2803b0312a0fb3b6" + integrity sha512-rd4rYZNlF3WuoYuRIDEmbR/ga9CeuWX9U05umAvgrrZoHY4Z++cp/xwPQMvUpBB4Ag6J8KfD80G0zwCyaSxDww== core-util-is@~1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== -cose-base@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/cose-base/-/cose-base-1.0.3.tgz#650334b41b869578a543358b80cda7e0abe0a60a" - integrity sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg== - dependencies: - layout-base "^1.0.0" - -cose-base@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/cose-base/-/cose-base-2.2.0.tgz#1c395c35b6e10bb83f9769ca8b817d614add5c01" - integrity sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g== - dependencies: - layout-base "^2.0.0" - cosmiconfig@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" @@ -4245,7 +3740,7 @@ cosmiconfig@^6.0.0: path-type "^4.0.0" yaml "^1.7.2" -cosmiconfig@^7.0.0, cosmiconfig@^7.0.1: +cosmiconfig@^7.0.1: version "7.1.0" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6" integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA== @@ -4256,22 +3751,53 @@ cosmiconfig@^7.0.0, cosmiconfig@^7.0.1: path-type "^4.0.0" yaml "^1.10.0" -cosmiconfig@^8.0.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.1.0.tgz#947e174c796483ccf0a48476c24e4fefb7e1aea8" - integrity sha512-0tLZ9URlPGU7JsKq0DQOQ3FoRsYX8xDZ7xMiATQfaiGMz7EHowNkbU9u1coAOmnh9p/1ySpm0RB3JNWRXM5GCg== +cosmiconfig@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.2.0.tgz#f7d17c56a590856cd1e7cee98734dca272b0d8fd" + integrity sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ== dependencies: import-fresh "^3.2.1" js-yaml "^4.1.0" parse-json "^5.0.0" path-type "^4.0.0" -cross-fetch@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" - integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== +create-ecdh@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" + integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== dependencies: - node-fetch "2.6.7" + bn.js "^4.1.0" + elliptic "^6.5.3" + +create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-fetch@^3.1.5: + version "3.1.8" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.8.tgz#0327eba65fd68a7d119f8fb2bf9334a1a7956f82" + integrity sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg== + dependencies: + node-fetch "^2.6.12" cross-spawn@^7.0.3: version "7.0.3" @@ -4282,6 +3808,23 @@ cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +crypto-browserify@^3.12.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + crypto-js@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.1.1.tgz#9e485bcf03521041bd85844786b83fb7619736cf" @@ -4292,56 +3835,25 @@ crypto-random-string@^2.0.0: resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== -css-declaration-sorter@6.2.2: - version "6.2.2" - resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.2.2.tgz#bfd2f6f50002d6a3ae779a87d3a0c5d5b10e0f02" - integrity sha512-Ufadglr88ZLsrvS11gjeu/40Lw74D9Am/Jpr3LlYm5Q4ZP5KdlUhG+6u2EjyXeZcxmZ2h1ebCKngDjolpeLHpg== - css-declaration-sorter@^6.3.1: - version "6.3.1" - resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.3.1.tgz#be5e1d71b7a992433fb1c542c7a1b835e45682ec" - integrity sha512-fBffmak0bPAnyqc/HO8C3n2sHrp9wcqQz6ES9koRF2/mLOVAx9zIQ3Y7R29sYCteTPqMCwns4WYQoCX91Xl3+w== - -css-loader@6.7.1: - version "6.7.1" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.7.1.tgz#e98106f154f6e1baf3fc3bc455cb9981c1d5fd2e" - integrity sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw== - dependencies: - icss-utils "^5.1.0" - postcss "^8.4.7" - postcss-modules-extract-imports "^3.0.0" - postcss-modules-local-by-default "^4.0.0" - postcss-modules-scope "^3.0.0" - postcss-modules-values "^4.0.0" - postcss-value-parser "^4.2.0" - semver "^7.3.5" + version "6.4.1" + resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz#28beac7c20bad7f1775be3a7129d7eae409a3a71" + integrity sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g== css-loader@^6.7.1: - version "6.7.3" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.7.3.tgz#1e8799f3ccc5874fdd55461af51137fcc5befbcd" - integrity sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ== + version "6.8.1" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.8.1.tgz#0f8f52699f60f5e679eab4ec0fcd68b8e8a50a88" + integrity sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g== dependencies: icss-utils "^5.1.0" - postcss "^8.4.19" + postcss "^8.4.21" postcss-modules-extract-imports "^3.0.0" - postcss-modules-local-by-default "^4.0.0" + postcss-modules-local-by-default "^4.0.3" postcss-modules-scope "^3.0.0" postcss-modules-values "^4.0.0" postcss-value-parser "^4.2.0" semver "^7.3.8" -css-minimizer-webpack-plugin@3.4.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz#ab78f781ced9181992fe7b6e4f3422e76429878f" - integrity sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q== - dependencies: - cssnano "^5.0.6" - jest-worker "^27.0.2" - postcss "^8.3.5" - schema-utils "^4.0.0" - serialize-javascript "^6.0.0" - source-map "^0.6.1" - css-minimizer-webpack-plugin@^4.0.0: version "4.2.2" resolved "https://registry.yarnpkg.com/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-4.2.2.tgz#79f6199eb5adf1ff7ba57f105e3752d15211eb35" @@ -4376,16 +3888,6 @@ css-select@^5.1.0: domutils "^3.0.1" nth-check "^2.0.1" -css-select@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" - integrity sha512-dUQOBoqdR7QwV90WysXPLXG5LO7nhYBgiWVfxF80DKPF8zx1t/pUd2FYy73emg3zrjtM6dzmYgbHKfV2rxiHQA== - dependencies: - boolbase "~1.0.0" - css-what "2.1" - domutils "1.5.1" - nth-check "~1.0.1" - css-tree@^1.1.2, css-tree@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" @@ -4394,11 +3896,6 @@ css-tree@^1.1.2, css-tree@^1.1.3: mdn-data "2.0.14" source-map "^0.6.1" -css-what@2.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" - integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== - css-what@^6.0.1, css-what@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" @@ -4409,18 +3906,6 @@ cssesc@^3.0.0: resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== -cssnano-preset-advanced@5.3.3: - version "5.3.3" - resolved "https://registry.yarnpkg.com/cssnano-preset-advanced/-/cssnano-preset-advanced-5.3.3.tgz#848422118d7a62b5b29a53edc160f58c7f7f7539" - integrity sha512-AB9SmTSC2Gd8T7PpKUsXFJ3eNsg7dc4CTZ0+XAJ29MNxyJsrCEk7N1lw31bpHrsQH2PVJr21bbWgGAfA9j0dIA== - dependencies: - autoprefixer "^10.3.7" - cssnano-preset-default "^5.2.7" - postcss-discard-unused "^5.1.0" - postcss-merge-idents "^5.1.1" - postcss-reduce-idents "^5.2.0" - postcss-zindex "^5.1.0" - cssnano-preset-advanced@^5.3.8: version "5.3.10" resolved "https://registry.yarnpkg.com/cssnano-preset-advanced/-/cssnano-preset-advanced-5.3.10.tgz#25558a1fbf3a871fb6429ce71e41be7f5aca6eef" @@ -4433,7 +3918,7 @@ cssnano-preset-advanced@^5.3.8: postcss-reduce-idents "^5.2.0" postcss-zindex "^5.1.0" -cssnano-preset-default@^5.2.14, cssnano-preset-default@^5.2.7: +cssnano-preset-default@^5.2.14: version "5.2.14" resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz#309def4f7b7e16d71ab2438052093330d9ab45d8" integrity sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A== @@ -4473,16 +3958,7 @@ cssnano-utils@^3.1.0: resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-3.1.0.tgz#95684d08c91511edfc70d2636338ca37ef3a6861" integrity sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA== -cssnano@5.1.7: - version "5.1.7" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.1.7.tgz#99858bef6c76c9240f0cdc9239570bc7db8368be" - integrity sha512-pVsUV6LcTXif7lvKKW9ZrmX+rGRzxkEdJuVJcp5ftUjWITgwam5LMZOgaTvUrWPkcORBey6he7JKb4XAJvrpKg== - dependencies: - cssnano-preset-default "^5.2.7" - lilconfig "^2.0.3" - yaml "^1.10.2" - -cssnano@^5.0.6, cssnano@^5.1.12, cssnano@^5.1.8: +cssnano@^5.1.12, cssnano@^5.1.8: version "5.1.15" resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.1.15.tgz#ded66b5480d5127fcb44dac12ea5a983755136bf" integrity sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw== @@ -4499,288 +3975,9 @@ csso@^4.2.0: css-tree "^1.1.2" csstype@^3.0.2: - version "3.1.1" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.1.tgz#841b532c45c758ee546a11d5bd7b7b473c8c30b9" - integrity sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw== - -cytoscape-cose-bilkent@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz#762fa121df9930ffeb51a495d87917c570ac209b" - integrity sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ== - dependencies: - cose-base "^1.0.0" - -cytoscape-fcose@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz#e4d6f6490df4fab58ae9cea9e5c3ab8d7472f471" - integrity sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ== - dependencies: - cose-base "^2.2.0" - -cytoscape@^3.23.0: - version "3.23.0" - resolved "https://registry.yarnpkg.com/cytoscape/-/cytoscape-3.23.0.tgz#054ee05a6d0aa3b4f139382bbf2f4e5226df3c6d" - integrity sha512-gRZqJj/1kiAVPkrVFvz/GccxsXhF3Qwpptl32gKKypO4IlqnKBjTOu+HbXtEggSGzC5KCaHp3/F7GgENrtsFkA== - dependencies: - heap "^0.2.6" - lodash "^4.17.21" - -"d3-array@2 - 3", "d3-array@2.10.0 - 3", "d3-array@2.5.0 - 3", d3-array@3, d3-array@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-3.2.2.tgz#f8ac4705c5b06914a7e0025bbf8d5f1513f6a86e" - integrity sha512-yEEyEAbDrF8C6Ob2myOBLjwBLck1Z89jMGFee0oPsn95GqjerpaOA4ch+vc2l0FNFFwMD5N7OCSEN5eAlsUbgQ== - dependencies: - internmap "1 - 2" - -d3-axis@3: - version "3.0.0" - resolved "https://registry.yarnpkg.com/d3-axis/-/d3-axis-3.0.0.tgz#c42a4a13e8131d637b745fc2973824cfeaf93322" - integrity sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw== - -d3-brush@3: - version "3.0.0" - resolved "https://registry.yarnpkg.com/d3-brush/-/d3-brush-3.0.0.tgz#6f767c4ed8dcb79de7ede3e1c0f89e63ef64d31c" - integrity sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ== - dependencies: - d3-dispatch "1 - 3" - d3-drag "2 - 3" - d3-interpolate "1 - 3" - d3-selection "3" - d3-transition "3" - -d3-chord@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-chord/-/d3-chord-3.0.1.tgz#d156d61f485fce8327e6abf339cb41d8cbba6966" - integrity sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g== - dependencies: - d3-path "1 - 3" - -"d3-color@1 - 3", d3-color@3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-3.1.0.tgz#395b2833dfac71507f12ac2f7af23bf819de24e2" - integrity sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA== - -d3-contour@4: - version "4.0.2" - resolved "https://registry.yarnpkg.com/d3-contour/-/d3-contour-4.0.2.tgz#bb92063bc8c5663acb2422f99c73cbb6c6ae3bcc" - integrity sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA== - dependencies: - d3-array "^3.2.0" - -d3-delaunay@6: - version "6.0.2" - resolved "https://registry.yarnpkg.com/d3-delaunay/-/d3-delaunay-6.0.2.tgz#7fd3717ad0eade2fc9939f4260acfb503f984e92" - integrity sha512-IMLNldruDQScrcfT+MWnazhHbDJhcRJyOEBAJfwQnHle1RPh6WDuLvxNArUju2VSMSUuKlY5BGHRJ2cYyoFLQQ== - dependencies: - delaunator "5" - -"d3-dispatch@1 - 3", d3-dispatch@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-3.0.1.tgz#5fc75284e9c2375c36c839411a0cf550cbfc4d5e" - integrity sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg== - -"d3-drag@2 - 3", d3-drag@3: - version "3.0.0" - resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-3.0.0.tgz#994aae9cd23c719f53b5e10e3a0a6108c69607ba" - integrity sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg== - dependencies: - d3-dispatch "1 - 3" - d3-selection "3" - -"d3-dsv@1 - 3", d3-dsv@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-dsv/-/d3-dsv-3.0.1.tgz#c63af978f4d6a0d084a52a673922be2160789b73" - integrity sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q== - dependencies: - commander "7" - iconv-lite "0.6" - rw "1" - -"d3-ease@1 - 3", d3-ease@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-3.0.1.tgz#9658ac38a2140d59d346160f1f6c30fda0bd12f4" - integrity sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w== - -d3-fetch@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-fetch/-/d3-fetch-3.0.1.tgz#83141bff9856a0edb5e38de89cdcfe63d0a60a22" - integrity sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw== - dependencies: - d3-dsv "1 - 3" - -d3-force@3: - version "3.0.0" - resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-3.0.0.tgz#3e2ba1a61e70888fe3d9194e30d6d14eece155c4" - integrity sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg== - dependencies: - d3-dispatch "1 - 3" - d3-quadtree "1 - 3" - d3-timer "1 - 3" - -"d3-format@1 - 3", d3-format@3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-3.1.0.tgz#9260e23a28ea5cb109e93b21a06e24e2ebd55641" - integrity sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA== - -d3-geo@3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/d3-geo/-/d3-geo-3.1.0.tgz#74fd54e1f4cebd5185ac2039217a98d39b0a4c0e" - integrity sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA== - dependencies: - d3-array "2.5.0 - 3" - -d3-hierarchy@3: version "3.1.2" - resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz#b01cd42c1eed3d46db77a5966cf726f8c09160c6" - integrity sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA== - -"d3-interpolate@1 - 3", "d3-interpolate@1.2.0 - 3", d3-interpolate@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz#3c47aa5b32c5b3dfb56ef3fd4342078a632b400d" - integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g== - dependencies: - d3-color "1 - 3" - -"d3-path@1 - 3", d3-path@3, d3-path@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-3.1.0.tgz#22df939032fb5a71ae8b1800d61ddb7851c42526" - integrity sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ== - -d3-polygon@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-polygon/-/d3-polygon-3.0.1.tgz#0b45d3dd1c48a29c8e057e6135693ec80bf16398" - integrity sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg== - -"d3-quadtree@1 - 3", d3-quadtree@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-quadtree/-/d3-quadtree-3.0.1.tgz#6dca3e8be2b393c9a9d514dabbd80a92deef1a4f" - integrity sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw== - -d3-random@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-random/-/d3-random-3.0.1.tgz#d4926378d333d9c0bfd1e6fa0194d30aebaa20f4" - integrity sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ== - -d3-scale-chromatic@3: - version "3.0.0" - resolved "https://registry.yarnpkg.com/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz#15b4ceb8ca2bb0dcb6d1a641ee03d59c3b62376a" - integrity sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g== - dependencies: - d3-color "1 - 3" - d3-interpolate "1 - 3" - -d3-scale@4: - version "4.0.2" - resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-4.0.2.tgz#82b38e8e8ff7080764f8dcec77bd4be393689396" - integrity sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ== - dependencies: - d3-array "2.10.0 - 3" - d3-format "1 - 3" - d3-interpolate "1.2.0 - 3" - d3-time "2.1.1 - 3" - d3-time-format "2 - 4" - -"d3-selection@2 - 3", d3-selection@3: - version "3.0.0" - resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-3.0.0.tgz#c25338207efa72cc5b9bd1458a1a41901f1e1b31" - integrity sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ== - -d3-shape@3: - version "3.2.0" - resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-3.2.0.tgz#a1a839cbd9ba45f28674c69d7f855bcf91dfc6a5" - integrity sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA== - dependencies: - d3-path "^3.1.0" - -"d3-time-format@2 - 4", d3-time-format@4: - version "4.1.0" - resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-4.1.0.tgz#7ab5257a5041d11ecb4fe70a5c7d16a195bb408a" - integrity sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg== - dependencies: - d3-time "1 - 3" - -"d3-time@1 - 3", "d3-time@2.1.1 - 3", d3-time@3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-3.1.0.tgz#9310db56e992e3c0175e1ef385e545e48a9bb5c7" - integrity sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q== - dependencies: - d3-array "2 - 3" - -"d3-timer@1 - 3", d3-timer@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0" - integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA== - -"d3-transition@2 - 3", d3-transition@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-3.0.1.tgz#6869fdde1448868077fdd5989200cb61b2a1645f" - integrity sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w== - dependencies: - d3-color "1 - 3" - d3-dispatch "1 - 3" - d3-ease "1 - 3" - d3-interpolate "1 - 3" - d3-timer "1 - 3" - -d3-zoom@3: - version "3.0.0" - resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-3.0.0.tgz#d13f4165c73217ffeaa54295cd6969b3e7aee8f3" - integrity sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw== - dependencies: - d3-dispatch "1 - 3" - d3-drag "2 - 3" - d3-interpolate "1 - 3" - d3-selection "2 - 3" - d3-transition "2 - 3" - -d3@^7.4.0, d3@^7.8.2: - version "7.8.2" - resolved "https://registry.yarnpkg.com/d3/-/d3-7.8.2.tgz#2bdb3c178d095ae03b107a18837ae049838e372d" - integrity sha512-WXty7qOGSHb7HR7CfOzwN1Gw04MUOzN8qh9ZUsvwycIMb4DYMpY9xczZ6jUorGtO6bR9BPMPaueIKwiDxu9uiQ== - dependencies: - d3-array "3" - d3-axis "3" - d3-brush "3" - d3-chord "3" - d3-color "3" - d3-contour "4" - d3-delaunay "6" - d3-dispatch "3" - d3-drag "3" - d3-dsv "3" - d3-ease "3" - d3-fetch "3" - d3-force "3" - d3-format "3" - d3-geo "3" - d3-hierarchy "3" - d3-interpolate "3" - d3-path "3" - d3-polygon "3" - d3-quadtree "3" - d3-random "3" - d3-scale "4" - d3-scale-chromatic "3" - d3-selection "3" - d3-shape "3" - d3-time "3" - d3-time-format "4" - d3-timer "3" - d3-transition "3" - d3-zoom "3" - -dagre-d3-es@7.0.9: - version "7.0.9" - resolved "https://registry.yarnpkg.com/dagre-d3-es/-/dagre-d3-es-7.0.9.tgz#aca12fccd9d09955a4430029ba72ee6934542a8d" - integrity sha512-rYR4QfVmy+sR44IBDvVtcAmOReGBvRCWDpO2QjYwqgh9yijw6eSHBqaPG/LIOEy7aBsniLvtMW6pg19qJhq60w== - dependencies: - d3 "^7.8.2" - lodash-es "^4.17.21" - -dayjs@^1.11.7: - version "1.11.7" - resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.7.tgz#4b296922642f70999544d1144a2c25730fce63e2" - integrity sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ== + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b" + integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ== debug@2.6.9, debug@^2.6.0: version "2.6.9" @@ -4842,7 +4039,7 @@ define-lazy-prop@^2.0.0: resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== -define-properties@^1.1.4: +define-properties@^1.1.3, define-properties@^1.1.4: version "1.2.0" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5" integrity sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA== @@ -4850,11 +4047,6 @@ define-properties@^1.1.4: has-property-descriptors "^1.0.0" object-keys "^1.1.1" -defined@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.1.tgz#c0b9db27bfaffd95d6f61399419b893df0f91ebf" - integrity sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q== - del@^6.1.1: version "6.1.1" resolved "https://registry.yarnpkg.com/del/-/del-6.1.1.tgz#3b70314f1ec0aa325c6b14eb36b95786671edb7a" @@ -4869,13 +4061,6 @@ del@^6.1.1: rimraf "^3.0.2" slash "^3.0.0" -delaunator@5: - version "5.0.0" - resolved "https://registry.yarnpkg.com/delaunator/-/delaunator-5.0.0.tgz#60f052b28bd91c9b4566850ebf7756efe821d81b" - integrity sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw== - dependencies: - robust-predicates "^3.0.0" - delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -4896,6 +4081,14 @@ dequal@^2.0.0: resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== +des.js@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.1.0.tgz#1d37f5766f3bbff4ee9638e871a8768c173b81da" + integrity sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg== + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + destroy@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" @@ -4929,15 +4122,6 @@ detect-port@^1.3.0: address "^1.0.1" debug "4" -detective@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/detective/-/detective-5.2.1.tgz#6af01eeda11015acb0e73f933242b70f24f91034" - integrity sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw== - dependencies: - acorn-node "^1.8.2" - defined "^1.0.0" - minimist "^1.2.6" - dezalgo@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.4.tgz#751235260469084c132157dfa857f386d4c33d81" @@ -4956,6 +4140,15 @@ diff@^5.0.0: resolved "https://registry.yarnpkg.com/diff/-/diff-5.1.0.tgz#bc52d298c5ea8df9194800224445ed43ffc87e40" integrity sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw== +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -4973,68 +4166,34 @@ dns-equal@^1.0.0: resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" integrity sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg== -dns-packet@5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.3.1.tgz#eb94413789daec0f0ebe2fcc230bdc9d7c91b43d" - integrity sha512-spBwIj0TK0Ey3666GwIdWVfUpLyubpU53BTCu8iPn4r4oXd9O14Hjg3EHw3ts2oed77/SeckunUYCyRlSngqHw== - dependencies: - "@leichtgewicht/ip-codec" "^2.0.1" - dns-packet@^5.2.2: - version "5.4.0" - resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.4.0.tgz#1f88477cf9f27e78a213fb6d118ae38e759a879b" - integrity sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g== + version "5.6.0" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.6.0.tgz#2202c947845c7a63c23ece58f2f70ff6ab4c2f7d" + integrity sha512-rza3UH1LwdHh9qyPXp8lkwpjSNk/AMD3dPytUoRoqnypDUhY0xvbdmVhWOfxO68frEfV9BU8V12Ez7ZsHGZpCQ== dependencies: "@leichtgewicht/ip-codec" "^2.0.1" -docusaurus-plugin-image-zoom@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/docusaurus-plugin-image-zoom/-/docusaurus-plugin-image-zoom-0.1.1.tgz#f5e16ae568f7b74e8a357ee67ea7922521f64539" - integrity sha512-cJXo5TKh9OR1gE4B5iS5ovLWYYDFwatqRm00iXFPOaShZG99l5tgkDKgbQPAwSL9wg4I+wz3aMwkOtDhMIpKDQ== +docusaurus-plugin-image-zoom@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/docusaurus-plugin-image-zoom/-/docusaurus-plugin-image-zoom-1.0.1.tgz#17afec39f2e630cac50a4ed3a8bbdad8d0aa8b9d" + integrity sha512-96IpSKUx2RWy3db9aZ0s673OQo5DWgV9UVWouS+CPOSIVEdCWh6HKmWf6tB9rsoaiIF3oNn9keiyv6neEyKb1Q== dependencies: medium-zoom "^1.0.6" + validate-peer-dependencies "^2.2.0" -docusaurus-plugin-openapi-docs@1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/docusaurus-plugin-openapi-docs/-/docusaurus-plugin-openapi-docs-1.5.2.tgz#02ba9ba6821e99e135963042183a5b2dedc52e02" - integrity sha512-fec3tEucAKYYskSEUOmQOte43wm57O4W0zRFN9ebktVuenddtM0fz9YQRb5EILOqHXYybjvvYyl1fLH/3CnnbA== +docusaurus-plugin-openapi-docs@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/docusaurus-plugin-openapi-docs/-/docusaurus-plugin-openapi-docs-1.7.3.tgz#22533dd93c8aa4bf57fea00c959ecef56e744a73" + integrity sha512-h0SmUJJjjN1ewNDFcxXxGF41pg6aCm8GI0cMBBvlLcxmaFuKVkQ57w+cDyX2Ip+Vd0kPrgtcssfI0ujmYQjC2g== dependencies: - "@apidevtools/json-schema-ref-parser" "^9.0.9" - "@docusaurus/mdx-loader" "^2.0.1" - "@docusaurus/plugin-content-docs" "^2.0.1" - "@docusaurus/utils" "^2.0.1" - "@docusaurus/utils-validation" "^2.0.1" - "@paloaltonetworks/openapi-to-postmanv2" "3.1.0-hotfix.1" - "@paloaltonetworks/postman-collection" "^4.1.0" - "@redocly/openapi-core" "^1.0.0-beta.103" - chalk "^4.1.2" - clsx "^1.1.1" - fs-extra "^9.0.1" - js-yaml "^4.1.0" - json-pointer "^0.6.2" - json-refs "^3.0.15" - json-schema-merge-allof "^0.8.1" - lodash "^4.17.20" - mustache "^4.2.0" - slugify "^1.6.5" - swagger2openapi "^7.0.8" - url-template "^3.0.0" - webpack "^5.61.0" - xml-formatter "^2.6.1" - -docusaurus-plugin-openapi-docs@^1.5.2: - version "1.6.1" - resolved "https://registry.yarnpkg.com/docusaurus-plugin-openapi-docs/-/docusaurus-plugin-openapi-docs-1.6.1.tgz#3be6234c878aabafe5ebc65be3c234dbbf19e970" - integrity sha512-3zQ+s2pXXcSNLWzO39tkIAku8O5jysCQyIyaiK9mfxLMqQH8VBXge64wwVWlWYWtGzlEwNkeyu2fiFYOkfiifw== - dependencies: - "@apidevtools/json-schema-ref-parser" "^9.0.9" + "@apidevtools/json-schema-ref-parser" "^10.1.0" "@docusaurus/mdx-loader" ">=2.0.1 <2.3.0" "@docusaurus/plugin-content-docs" ">=2.0.1 <2.3.0" "@docusaurus/utils" ">=2.0.1 <2.3.0" "@docusaurus/utils-validation" ">=2.0.1 <2.3.0" "@paloaltonetworks/openapi-to-postmanv2" "3.1.0-hotfix.1" "@paloaltonetworks/postman-collection" "^4.1.0" - "@redocly/openapi-core" "^1.0.0-beta.103" + "@redocly/openapi-core" "^1.0.0-beta.125" chalk "^4.1.2" clsx "^1.1.1" fs-extra "^9.0.1" @@ -5050,23 +4209,24 @@ docusaurus-plugin-openapi-docs@^1.5.2: webpack "^5.61.0" xml-formatter "^2.6.1" -docusaurus-theme-openapi-docs@1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/docusaurus-theme-openapi-docs/-/docusaurus-theme-openapi-docs-1.5.2.tgz#8dc0cd91fc9792aec598fc61b707dcfdfd65eb92" - integrity sha512-4cUhn+ukltJTXv4bbnSzE9GgaUYWcDCR/ZHwXzcv7Q4oKFtSmVJL6qleeVL1vSYTc8ocGbq2mY1TMIwKeokTuA== +docusaurus-theme-openapi-docs@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/docusaurus-theme-openapi-docs/-/docusaurus-theme-openapi-docs-1.7.3.tgz#3073e7e79dff52f7b88b5a45fe0f914dc9a71268" + integrity sha512-riLEj2tNGLDAMs0eMrStLoOSgsvpa0tmwzhIDYhETxZSBZ50Gd9sBPW58LRhuzQ5d9UZMTu6tg2swZiYQAlnag== dependencies: - "@docusaurus/theme-common" "^2.0.1" + "@docusaurus/theme-common" ">=2.0.1 <2.3.0" "@mdx-js/react" "^1.6.21" - "@paloaltonetworks/postman-code-generators" "^1.1.12" + "@paloaltonetworks/postman-code-generators" "1.1.15-patch.2" "@paloaltonetworks/postman-collection" "^4.1.0" "@reduxjs/toolkit" "^1.7.1" buffer "^6.0.3" clsx "^1.1.1" crypto-js "^4.1.1" - docusaurus-plugin-openapi-docs "^1.5.2" + docusaurus-plugin-openapi-docs "^1.7.3" file-saver "^2.0.5" immer "^9.0.7" lodash "^4.17.20" + node-polyfill-webpack-plugin "^2.0.1" process "^0.11.10" react-live "^3.1.1" react-magic-dropzone "^1.0.1" @@ -5085,14 +4245,6 @@ dom-converter@^0.2.0: dependencies: utila "~0.4" -dom-serializer@0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" - integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== - dependencies: - domelementtype "^2.0.1" - entities "^2.0.0" - dom-serializer@^1.0.1: version "1.4.1" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30" @@ -5111,31 +4263,16 @@ dom-serializer@^2.0.0: domhandler "^5.0.2" entities "^4.2.0" -dom-serializer@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0" - integrity sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA== - dependencies: - domelementtype "^1.3.0" - entities "^1.1.1" - -domelementtype@1, domelementtype@^1.3.0, domelementtype@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" - integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== +domain-browser@^4.22.0: + version "4.22.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-4.22.0.tgz#6ddd34220ec281f9a65d3386d267ddd35c491f9f" + integrity sha512-IGBwjF7tNk3cwypFNH/7bfzBcgSCbaMOD3GsaY1AU/JRrnHnYgEM0+9kQt52iZxjNsjBtJYtao146V+f8jFZNw== domelementtype@^2.0.1, domelementtype@^2.2.0, domelementtype@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== -domhandler@^2.3.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" - integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA== - dependencies: - domelementtype "1" - domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c" @@ -5143,34 +4280,13 @@ domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.1: dependencies: domelementtype "^2.2.0" -domhandler@^5.0.1, domhandler@^5.0.2, domhandler@^5.0.3: +domhandler@^5.0.2, domhandler@^5.0.3: version "5.0.3" resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31" integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w== dependencies: domelementtype "^2.3.0" -dompurify@2.4.3: - version "2.4.3" - resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.4.3.tgz#f4133af0e6a50297fc8874e2eaedc13a3c308c03" - integrity sha512-q6QaLcakcRjebxjg8/+NP+h0rPfatOgOzc46Fst9VAA3jF2ApfKBNKMzdP4DYTqtUMXSCd5pRS/8Po/OmoCHZQ== - -domutils@1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" - integrity sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw== - dependencies: - dom-serializer "0" - domelementtype "1" - -domutils@^1.5.1: - version "1.7.0" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" - integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== - dependencies: - dom-serializer "0" - domelementtype "1" - domutils@^2.5.2, domutils@^2.8.0: version "2.8.0" resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" @@ -5181,13 +4297,13 @@ domutils@^2.5.2, domutils@^2.8.0: domhandler "^4.2.0" domutils@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.0.1.tgz#696b3875238338cb186b6c0612bd4901c89a4f1c" - integrity sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q== + version "3.1.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.1.0.tgz#c47f551278d3dc4b0b1ab8cbb42d751a6f0d824e" + integrity sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA== dependencies: dom-serializer "^2.0.0" domelementtype "^2.3.0" - domhandler "^5.0.1" + domhandler "^5.0.3" dot-case@^3.0.4: version "3.0.4" @@ -5214,7 +4330,7 @@ duplexer@^0.1.2: resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== -eastasianwidth@0.2.0, eastasianwidth@^0.2.0: +eastasianwidth@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== @@ -5224,15 +4340,23 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== -electron-to-chromium@^1.4.284: - version "1.4.332" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.332.tgz#b981fcf61587abe03c24b301b2cfbdcc2b70e8a5" - integrity sha512-c1Vbv5tuUlBFp0mb3mCIjw+REEsgthRgNE8BlbEDKmvzb8rxjcVki6OkQP83vLN34s0XCxpSkq7AZNep1a6xhw== +electron-to-chromium@^1.4.477: + version "1.4.482" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.482.tgz#77c5ed37b93d4dda860e27538e0e2a01d6a19e02" + integrity sha512-h+UqpfmEr1Qkk0zp7ej/jid7CXoq4m4QzW6wNTb0ELJ/BZCpA4wgUylBIMGCe621tnr4l5VmoHjdoSx2lbnNJA== -elkjs@^0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/elkjs/-/elkjs-0.8.2.tgz#c37763c5a3e24e042e318455e0147c912a7c248e" - integrity sha512-L6uRgvZTH+4OF5NE/MBbzQx/WYpru1xCBE9respNj6qznEewGUIfhzmm7horWWxbNO2M0WckQypGctR8lH79xQ== +elliptic@^6.5.3: + version "6.5.4" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" emoji-regex@^8.0.0: version "8.0.0" @@ -5266,41 +4390,23 @@ end-of-stream@^1.1.0: dependencies: once "^1.4.0" -enhanced-resolve@5.9.3: - version "5.9.3" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz#44a342c012cbc473254af5cc6ae20ebd0aae5d88" - integrity sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow== +enhanced-resolve@^5.15.0: + version "5.15.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35" + integrity sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg== dependencies: graceful-fs "^4.2.4" tapable "^2.2.0" -enhanced-resolve@^5.10.0: - version "5.12.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz#300e1c90228f5b570c4d35babf263f6da7155634" - integrity sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ== - dependencies: - graceful-fs "^4.2.4" - tapable "^2.2.0" - -entities@^1.1.1, entities@~1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" - integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== - entities@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== -entities@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/entities/-/entities-3.0.1.tgz#2b887ca62585e96db3903482d336c1006c3001d4" - integrity sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q== - -entities@^4.2.0, entities@^4.3.0, entities@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-4.4.0.tgz#97bdaba170339446495e653cfd2db78962900174" - integrity sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA== +entities@^4.2.0, entities@^4.4.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== error-ex@^1.3.1: version "1.3.2" @@ -5309,10 +4415,15 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-module-lexer@^0.9.0: - version "0.9.3" - resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19" - integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ== +es-module-lexer@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.3.0.tgz#6be9c9e0b4543a60cd166ff6f8b4e9dae0b0c16f" + integrity sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA== + +es6-object-assign@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/es6-object-assign/-/es6-object-assign-1.1.0.tgz#c2c3582656247c39ea107cb1e6652b6f9f24523c" + integrity sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw== es6-promise@^3.2.1: version "3.3.1" @@ -5384,17 +4495,12 @@ eta@^1.12.3: resolved "https://registry.yarnpkg.com/eta/-/eta-1.14.2.tgz#5e6181a26ec13d8444c559ce51f7b3090cebbdd1" integrity sha512-wZmJAV7EFUG5W8XNXSazIdichnWEhGB1OWg4tnXWPj0CPNUcFdgorGNO6N9p6WBUgoUe4P0OziJYn1+6zxP2aQ== -eta@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/eta/-/eta-2.0.1.tgz#199e675359cb6e19d38f29e1f405e1ba0e79a6df" - integrity sha512-46E2qDPDm7QA+usjffUWz9KfXsxVZclPOuKsXs4ZWZdI/X1wpDF7AO424pt7fdYohCzWsIkXAhNGXSlwo5naAg== - etag@~1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== -eval@0.1.8, eval@^0.1.8: +eval@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/eval/-/eval-0.1.8.tgz#2b903473b8cc1d1989b83a1e7923f883eb357f85" integrity sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw== @@ -5402,16 +4508,29 @@ eval@0.1.8, eval@^0.1.8: "@types/node" "*" require-like ">= 0.1.1" +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + eventemitter3@^4.0.0: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== -events@^3.2.0: +events@^3.2.0, events@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + execa@^5.0.0: version "5.1.1" resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" @@ -5432,43 +4551,6 @@ exenv@^1.2.0: resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d" integrity sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw== -express@4.18.1: - version "4.18.1" - resolved "https://registry.yarnpkg.com/express/-/express-4.18.1.tgz#7797de8b9c72c857b9cd0e14a5eea80666267caf" - integrity sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q== - dependencies: - accepts "~1.3.8" - array-flatten "1.1.1" - body-parser "1.20.0" - content-disposition "0.5.4" - content-type "~1.0.4" - cookie "0.5.0" - cookie-signature "1.0.6" - debug "2.6.9" - depd "2.0.0" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "1.2.0" - fresh "0.5.2" - http-errors "2.0.0" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "2.4.1" - parseurl "~1.3.3" - path-to-regexp "0.1.7" - proxy-addr "~2.0.7" - qs "6.10.3" - range-parser "~1.2.1" - safe-buffer "5.2.1" - send "0.18.0" - serve-static "1.15.0" - setprototypeof "1.2.0" - statuses "2.0.1" - type-is "~1.6.18" - utils-merge "1.0.1" - vary "~1.1.2" - express@^4.17.3: version "4.18.2" resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" @@ -5523,10 +4605,10 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.2.11, fast-glob@^3.2.12, fast-glob@^3.2.7, fast-glob@^3.2.9: - version "3.2.12" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" - integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== +fast-glob@^3.2.11, fast-glob@^3.2.12, fast-glob@^3.2.9, fast-glob@^3.3.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" + integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" @@ -5578,9 +4660,9 @@ fbjs-css-vars@^1.0.0: integrity sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ== fbjs@^3.0.0, fbjs@^3.0.1: - version "3.0.4" - resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-3.0.4.tgz#e1871c6bd3083bac71ff2da868ad5067d37716c6" - integrity sha512-ucV0tDODnGV3JCnnkmoszb5lf4bNpzjv80K41wd4k798Etq+UYD0y0TIfalLjZoKgjive6/adkRnszwapiDgBQ== + version "3.0.5" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-3.0.5.tgz#aa0edb7d5caa6340011790bd9249dbef8a81128d" + integrity sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg== dependencies: cross-fetch "^3.1.5" fbjs-css-vars "^1.0.0" @@ -5588,7 +4670,7 @@ fbjs@^3.0.0, fbjs@^3.0.1: object-assign "^4.1.0" promise "^7.1.1" setimmediate "^1.0.5" - ua-parser-js "^0.7.30" + ua-parser-js "^1.0.35" feed@^4.2.2: version "4.2.2" @@ -5627,6 +4709,11 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" +filter-obj@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-2.0.2.tgz#fff662368e505d69826abb113f0f6a98f56e9d5f" + integrity sha512-lO3ttPjHZRfjMcxWKb1j1eDhTFsu4meeR3lnMcnBFhk6RuLhvEiuALu2TlfL310ph4lCYYwgF/ElIjdP739tdg== + finalhandler@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" @@ -5673,23 +4760,25 @@ find-up@^5.0.0: path-exists "^4.0.0" flux@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/flux/-/flux-4.0.3.tgz#573b504a24982c4768fdfb59d8d2ea5637d72ee7" - integrity sha512-yKAbrp7JhZhj6uiT1FTuVMlIAT1J4jqEyBpFApi1kxpGZCvacMVc/t1pMQyotqHhAgvoE3bNvAykhCo2CLjnYw== + version "4.0.4" + resolved "https://registry.yarnpkg.com/flux/-/flux-4.0.4.tgz#9661182ea81d161ee1a6a6af10d20485ef2ac572" + integrity sha512-NCj3XlayA2UsapRpM7va6wU1+9rE5FIL7qoMcmxWHRzbp0yujihMBm9BBHZ1MDIk5h5o2Bl6eGiCe8rYELAmYw== dependencies: fbemitter "^3.0.0" fbjs "^3.0.1" -follow-redirects@1.15.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.0.tgz#06441868281c86d0dda4ad8bdaead2d02dca89d4" - integrity sha512-aExlJShTV4qOUOL7yF1U5tvLCB0xQuudbf6toyYA0E/acBNw71mvjFTnLaRp50aQaYocMR0a/RMMBIHeZnGyjQ== - follow-redirects@^1.0.0, follow-redirects@^1.14.7: version "1.15.2" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + foreach@^2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.6.tgz#87bcc8a1a0e74000ff2bf9802110708cfb02eb6e" @@ -5724,9 +4813,9 @@ form-data@^4.0.0: mime-types "^2.1.12" formidable@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/formidable/-/formidable-2.1.1.tgz#81269cbea1a613240049f5f61a9d97731517414f" - integrity sha512-0EcS9wCFEzLvfiks7omJ+SiYJAiD+TzK4Pcw1UlUoGnhUxDcMKjt0P7x8wEb0u6OHu8Nb98WG3nxtlF5C7bvUQ== + version "2.1.2" + resolved "https://registry.yarnpkg.com/formidable/-/formidable-2.1.2.tgz#fa973a2bec150e4ce7cac15589d7a25fc30ebd89" + integrity sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g== dependencies: dezalgo "^1.0.4" hexoid "^1.0.0" @@ -5738,7 +4827,7 @@ forwarded@0.2.0: resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== -fraction.js@4.2.0, fraction.js@^4.2.0: +fraction.js@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== @@ -5767,10 +4856,10 @@ fs-extra@^9.0.0, fs-extra@^9.0.1: jsonfile "^6.0.1" universalify "^2.0.0" -fs-monkey@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.3.tgz#ae3ac92d53bb328efe0e9a1d9541f6ad8d48e2d3" - integrity sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q== +fs-monkey@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.4.tgz#ee8c1b53d3fe8bb7e5d2c5c5dfc0168afdd2f747" + integrity sha512-INM/fWAxMICjttnD0DX1rBvinKskj5G1w+oy/pnm9u/tSlnBrzFonJMcalKJ30P8RRsPzKcCG7Q8l0jx5Fh9YQ== fs.realpath@^1.0.0: version "1.0.0" @@ -5797,13 +4886,14 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.0.2, get-intrinsic@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.0.tgz#7ad1dc0535f3a2904bba075772763e5051f6d05f" - integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q== +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3: + version "1.2.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" + integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== dependencies: function-bind "^1.1.1" has "^1.0.3" + has-proto "^1.0.1" has-symbols "^1.0.3" get-own-enumerable-property-symbols@^3.0.0: @@ -5918,28 +5008,23 @@ globby@^11.0.1, globby@^11.0.4, globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" -globby@^12.0.2: - version "12.2.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-12.2.0.tgz#2ab8046b4fba4ff6eede835b29f678f90e3d3c22" - integrity sha512-wiSuFQLZ+urS9x2gGPl1H5drc5twabmm4m2gTR27XDFyjUHJUNsS8o/2aKyIF6IoBaR630atdher0XJ5g6OMmA== +globby@^13.1.1: + version "13.2.2" + resolved "https://registry.yarnpkg.com/globby/-/globby-13.2.2.tgz#63b90b1bf68619c2135475cbd4e71e66aa090592" + integrity sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w== dependencies: - array-union "^3.0.1" dir-glob "^3.0.1" - fast-glob "^3.2.7" - ignore "^5.1.9" + fast-glob "^3.3.0" + ignore "^5.2.4" merge2 "^1.4.1" slash "^4.0.0" -globby@^13.1.1: - version "13.1.3" - resolved "https://registry.yarnpkg.com/globby/-/globby-13.1.3.tgz#f62baf5720bcb2c1330c8d4ef222ee12318563ff" - integrity sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw== +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== dependencies: - dir-glob "^3.0.1" - fast-glob "^3.2.11" - ignore "^5.2.0" - merge2 "^1.4.1" - slash "^4.0.0" + get-intrinsic "^1.1.3" got@^9.6.0: version "9.6.0" @@ -6009,11 +5094,23 @@ has-property-descriptors@^1.0.0: dependencies: get-intrinsic "^1.1.1" -has-symbols@^1.0.3: +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + +has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + has-yarn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" @@ -6026,6 +5123,23 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + hast-to-hyperscript@^9.0.0: version "9.0.1" resolved "https://registry.yarnpkg.com/hast-to-hyperscript/-/hast-to-hyperscript-9.0.1.tgz#9b67fd188e4c81e8ad66f803855334173920218d" @@ -6164,11 +5278,6 @@ he@^1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== -heap@^0.2.6: - version "0.2.7" - resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.7.tgz#1e6adf711d3f27ce35a81fe3b7bd576c2260a8fc" - integrity sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg== - hexoid@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-1.0.0.tgz#ad10c6573fb907de23d9ec63a711267d9dc9bc18" @@ -6186,6 +5295,15 @@ history@^4.9.0: tiny-warning "^1.0.0" value-equal "^1.0.1" +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" @@ -6204,11 +5322,11 @@ hpack.js@^2.1.6: wbuf "^1.1.0" html-entities@^2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.3.tgz#117d7626bece327fc8baace8868fa6f5ef856e46" - integrity sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA== + version "2.4.0" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.4.0.tgz#edd0cee70402584c8c76cc2c0556db09d1f45061" + integrity sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ== -html-minifier-terser@6.1.0, html-minifier-terser@^6.0.2, html-minifier-terser@^6.1.0: +html-minifier-terser@^6.0.2, html-minifier-terser@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#bfc818934cc07918f6b3669f5774ecdfd48f32ab" integrity sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw== @@ -6221,10 +5339,10 @@ html-minifier-terser@6.1.0, html-minifier-terser@^6.0.2, html-minifier-terser@^6 relateurl "^0.2.7" terser "^5.10.0" -html-tags@3.2.0, html-tags@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.2.0.tgz#dbb3518d20b726524e4dd43de397eb0a95726961" - integrity sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg== +html-tags@^3.2.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.3.1.tgz#a04026a18c882e4bba8a01a3d39cfe465d40b5ce" + integrity sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ== html-void-elements@^1.0.0: version "1.0.5" @@ -6236,10 +5354,10 @@ html-void-elements@^2.0.0: resolved "https://registry.yarnpkg.com/html-void-elements/-/html-void-elements-2.0.1.tgz#29459b8b05c200b6c5ee98743c41b979d577549f" integrity sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A== -html-webpack-plugin@5.5.0, html-webpack-plugin@^5.5.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz#c3911936f57681c1f9f4d8b68c158cd9dfe52f50" - integrity sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw== +html-webpack-plugin@^5.5.0: + version "5.5.3" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.5.3.tgz#72270f4a78e222b5825b296e5e3e1328ad525a3e" + integrity sha512-6YrDKTuqaP/TquFH7h4srYWsZx+x6k6+FbsTm0ziCwGHDP78Unr1r9F/H4+sGmMbX08GQcJ+K64x55b+7VM/jg== dependencies: "@types/html-minifier-terser" "^6.0.0" html-minifier-terser "^6.0.2" @@ -6247,18 +5365,6 @@ html-webpack-plugin@5.5.0, html-webpack-plugin@^5.5.0: pretty-error "^4.0.0" tapable "^2.0.0" -htmlparser2@^3.9.1: - version "3.10.1" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" - integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== - dependencies: - domelementtype "^1.3.1" - domhandler "^2.3.0" - domutils "^1.5.1" - entities "^1.1.1" - inherits "^2.0.1" - readable-stream "^3.1.1" - htmlparser2@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" @@ -6270,14 +5376,14 @@ htmlparser2@^6.1.0: entities "^2.0.0" htmlparser2@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-8.0.1.tgz#abaa985474fcefe269bc761a779b544d7196d010" - integrity sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA== + version "8.0.2" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-8.0.2.tgz#f002151705b383e62433b5cf466f5b716edaec21" + integrity sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA== dependencies: domelementtype "^2.3.0" - domhandler "^5.0.2" + domhandler "^5.0.3" domutils "^3.0.1" - entities "^4.3.0" + entities "^4.4.0" http-cache-semantics@^4.0.0: version "4.1.1" @@ -6315,7 +5421,7 @@ http-parser-js@>=0.5.1: resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.8.tgz#af23090d9ac4e24573de6f6aecc9d84a48bf20e3" integrity sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q== -http-proxy-middleware@2.0.6, http-proxy-middleware@^2.0.3: +http-proxy-middleware@^2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz#e1a4dd6979572c7ab5a4e4b55095d1f32a74963f" integrity sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw== @@ -6345,6 +5451,11 @@ http2-client@^1.2.5: resolved "https://registry.yarnpkg.com/http2-client/-/http2-client-1.3.5.tgz#20c9dc909e3cc98284dd20af2432c524086df181" integrity sha512-EC2utToWl4RKfs5zd36Mxq7nzHHBuomZboI0yYL6Y0RmBgT7Sgkq4rQ0ezFTYoIsSs7Tm9SJe+o2FcAg6GBhGA== +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + integrity sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg== + human-signals@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" @@ -6357,7 +5468,7 @@ iconv-lite@0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@0.6, iconv-lite@0.6.3: +iconv-lite@0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== @@ -6374,7 +5485,7 @@ ieee754@^1.2.1: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -ignore@^5.1.9, ignore@^5.2.0: +ignore@^5.2.0, ignore@^5.2.4: version "5.2.4" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== @@ -6386,10 +5497,10 @@ image-size@^1.0.1: dependencies: queue "6.0.2" -immer@^9.0.16, immer@^9.0.7: - version "9.0.19" - resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.19.tgz#67fb97310555690b5f9cd8380d38fc0aabb6b38b" - integrity sha512-eY+Y0qcsB4TZKwgQzLaE/lqYMlKhv5J9dyd2RhhtGhNo2njPXDqU9XPfcNfa3MIDsdtZt5KlkIsirlo4dHsWdQ== +immer@^9.0.21, immer@^9.0.7: + version "9.0.21" + resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.21.tgz#1e025ea31a40f24fb064f1fef23e931496330176" + integrity sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA== import-fresh@^3.1.0, import-fresh@^3.2.1, import-fresh@^3.3.0: version "3.3.0" @@ -6414,11 +5525,6 @@ indent-string@^4.0.0: resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== -infima@0.2.0-alpha.39: - version "0.2.0-alpha.39" - resolved "https://registry.yarnpkg.com/infima/-/infima-0.2.0-alpha.39.tgz#054b13ac44f3e9a42bc083988f1a1586add2f59c" - integrity sha512-UyYiwD3nwHakGhuOUfpe3baJ8gkiPpRVx4a4sE/Ag+932+Y6swtLsdPoRR8ezhwqGnduzxmFkjumV9roz6QoLw== - infima@0.2.0-alpha.42: version "0.2.0-alpha.42" resolved "https://registry.yarnpkg.com/infima/-/infima-0.2.0-alpha.42.tgz#f6e86a655ad40877c6b4d11b2ede681eb5470aa5" @@ -6432,7 +5538,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3, inherits@~2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -6457,17 +5563,12 @@ inline-style-parser@0.1.1: resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1" integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q== -"internmap@1 - 2": - version "2.0.3" - resolved "https://registry.yarnpkg.com/internmap/-/internmap-2.0.3.tgz#6685f23755e43c524e251d29cbc97248e3061009" - integrity sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg== - interpret@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== -invariant@2.2.4, invariant@^2.2.4: +invariant@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== @@ -6480,9 +5581,9 @@ ipaddr.js@1.9.1: integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== ipaddr.js@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz#eca256a7a877e917aeb368b0a7497ddf42ef81c0" - integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng== + version "2.1.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.1.0.tgz#2119bc447ff8c257753b196fc5f1ce08a4cdf39f" + integrity sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ== is-alphabetical@1.0.4, is-alphabetical@^1.0.0: version "1.0.4" @@ -6497,6 +5598,14 @@ is-alphanumerical@^1.0.0: is-alphabetical "^1.0.0" is-decimal "^1.0.0" +is-arguments@^1.0.4: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" @@ -6514,6 +5623,11 @@ is-buffer@^2.0.0: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== +is-callable@^1.1.3: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + is-ci@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" @@ -6521,10 +5635,10 @@ is-ci@^2.0.0: dependencies: ci-info "^2.0.0" -is-core-module@^2.9.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" - integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw== +is-core-module@^2.11.0: + version "2.12.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.1.tgz#0c0b6885b6f80011c71541ce15c8d66cf5a4f9fd" + integrity sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg== dependencies: has "^1.0.3" @@ -6553,6 +5667,13 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== +is-generator-function@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" + integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== + dependencies: + has-tostringtag "^1.0.0" + is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" @@ -6573,6 +5694,14 @@ is-installed-globally@^0.4.0: global-dirs "^3.0.0" is-path-inside "^3.0.2" +is-nan@^1.2.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d" + integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + is-npm@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-5.0.0.tgz#43e8d65cc56e1b67f8d47262cf667099193f45a8" @@ -6640,6 +5769,13 @@ is-stream@^2.0.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== +is-typed-array@^1.1.3: + version "1.1.12" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" + integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== + dependencies: + which-typed-array "^1.1.11" + is-typedarray@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -6687,19 +5823,19 @@ isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== -jest-util@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.5.0.tgz#24a4d3d92fc39ce90425311b23c27a6e0ef16b8f" - integrity sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ== +jest-util@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.6.2.tgz#8a052df8fff2eebe446769fd88814521a517664d" + integrity sha512-3eX1qb6L88lJNCFlEADKOkjpXJQyZRiavX1INZ4tRnrBVr2COd3RgcTLyUiEXMNBlDU/cgYq6taUS0fExrWW4w== dependencies: - "@jest/types" "^29.5.0" + "@jest/types" "^29.6.1" "@types/node" "*" chalk "^4.0.0" ci-info "^3.2.0" graceful-fs "^4.2.9" picomatch "^2.2.3" -jest-worker@^27.0.2, jest-worker@^27.4.5: +jest-worker@^27.4.5: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== @@ -6709,19 +5845,24 @@ jest-worker@^27.0.2, jest-worker@^27.4.5: supports-color "^8.0.0" jest-worker@^29.1.2: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.5.0.tgz#bdaefb06811bd3384d93f009755014d8acb4615d" - integrity sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA== + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.6.2.tgz#682fbc4b6856ad0aa122a5403c6d048b83f3fb44" + integrity sha512-l3ccBOabTdkng8I/ORCkADz4eSMKejTYv1vB/Z83UiubqhC1oQ5Li6dWCyqOIvSifGjUBxuvxvlm6KGK2DtuAQ== dependencies: "@types/node" "*" - jest-util "^29.5.0" + jest-util "^29.6.2" merge-stream "^2.0.0" supports-color "^8.0.0" +jiti@^1.18.2: + version "1.19.1" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.19.1.tgz#fa99e4b76a23053e0e7cde098efe1704a14c16f1" + integrity sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg== + joi@^17.6.0: - version "17.8.4" - resolved "https://registry.yarnpkg.com/joi/-/joi-17.8.4.tgz#f2d91ab8acd3cca4079ba70669c65891739234aa" - integrity sha512-jjdRHb5WtL+KgSHvOULQEPPv4kcl+ixd1ybOFQq3rWLgEEqc03QMmilodL0GVJE14U/SQDXkUhQUSZANGDH/AA== + version "17.9.2" + resolved "https://registry.yarnpkg.com/joi/-/joi-17.9.2.tgz#8b2e4724188369f55451aebd1d0b1d9482470690" + integrity sha512-Itk/r+V4Dx0V3c7RLFdRh12IOjySm2/WGPMubBT92cQvRfYZhPM2W0hZlctjj72iES8jsRCwp7S/cRmWBnJ4nw== dependencies: "@hapi/hoek" "^9.0.0" "@hapi/topo" "^5.0.0" @@ -6821,7 +5962,7 @@ json-schema-traverse@^1.0.0: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== -json5@^2.1.2, json5@^2.2.1, json5@^2.2.2: +json5@^2.1.2, json5@^2.2.2: version "2.2.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== @@ -6842,11 +5983,6 @@ keyv@^3.0.0: dependencies: json-buffer "3.0.0" -khroma@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/khroma/-/khroma-2.0.0.tgz#7577de98aed9f36c7a474c4d453d94c0d6c6588b" - integrity sha512-2J8rDNlQWbtiNYThZRvmMv5yt44ZakX+Tz5ZIp/mN1pt4snn+m030Va5Z4v8xA0cQFDXBwO/8i42xL4QPsVk3g== - kind-of@^6.0.0, kind-of@^6.0.2: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" @@ -6862,11 +5998,6 @@ kleur@^4.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780" integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ== -klona@^2.0.5, klona@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.6.tgz#85bffbf819c03b2f53270412420a4555ef882e22" - integrity sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA== - latest-version@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face" @@ -6882,22 +6013,12 @@ launch-editor@^2.6.0: picocolors "^1.0.0" shell-quote "^1.7.3" -layout-base@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/layout-base/-/layout-base-1.0.2.tgz#1291e296883c322a9dd4c5dd82063721b53e26e2" - integrity sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg== - -layout-base@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/layout-base/-/layout-base-2.0.1.tgz#d0337913586c90f9c2c075292069f5c2da5dd285" - integrity sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg== - leven@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== -lilconfig@^2.0.3, lilconfig@^2.0.5, lilconfig@^2.0.6: +lilconfig@^2.0.3, lilconfig@^2.0.5, lilconfig@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== @@ -6953,20 +6074,10 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" -lodash-es@^4.17.21: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" - integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== - -lodash.assignin@^4.0.9: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" - integrity sha512-yX/rx6d/UTVh7sSVWVSIMjfnz95evAgDFdb1ZozC35I9mSFCkmzptOzevxjgbQUsc78NR44LVHWjsoMQXy9FDg== - -lodash.bind@^4.1.4: - version "4.2.1" - resolved "https://registry.yarnpkg.com/lodash.bind/-/lodash.bind-4.2.1.tgz#7ae3017e939622ac31b7d7d7dcb1b34db1690d35" - integrity sha512-lxdsn7xxlCymgLYo1gGvVrfHmkjDiyqVv62FAeF2i5ta72BipE1SLxw8hPEPLhD4/247Ijw07UQH7Hq/chT5LA== +lodash.clonedeep@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ== lodash.curry@^4.0.1: version "4.1.1" @@ -6978,71 +6089,21 @@ lodash.debounce@^4.0.8: resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== -lodash.defaults@^4.0.1: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" - integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ== - -lodash.filter@^4.4.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.filter/-/lodash.filter-4.6.0.tgz#668b1d4981603ae1cc5a6fa760143e480b4c4ace" - integrity sha512-pXYUy7PR8BCLwX5mgJ/aNtyOvuJTdZAo9EQFUvMIYugqmJxnrYaANvTbgndOzHSCSR0wnlBBfRXJL5SbWxo3FQ== - -lodash.flatten@^4.2.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" - integrity sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g== - lodash.flow@^3.3.0: version "3.5.0" resolved "https://registry.yarnpkg.com/lodash.flow/-/lodash.flow-3.5.0.tgz#87bf40292b8cf83e4e8ce1a3ae4209e20071675a" integrity sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw== -lodash.foreach@^4.3.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53" - integrity sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ== - lodash.isequal@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== -lodash.map@^4.4.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3" - integrity sha512-worNHGKLDetmcEYDvh2stPCrrQRkP20E4l0iIS7F8EvzMqBBi7ltvFN5m1HvTf1P7Jk1txKhvFcmYsCr8O2F1Q== - lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== -lodash.merge@^4.4.0: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" - integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== - -lodash.pick@^4.2.1: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" - integrity sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q== - -lodash.reduce@^4.4.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b" - integrity sha512-6raRe2vxCYBhpBu+B+TtNGUzah+hQjVdu3E17wfusjyrXBka2nBS8OH/gjVZ5PvHOhWmIZTYri09Z6n/QfnNMw== - -lodash.reject@^4.4.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.reject/-/lodash.reject-4.6.0.tgz#80d6492dc1470864bbf583533b651f42a9f52415" - integrity sha512-qkTuvgEzYdyhiJBx42YPzPo71R1aEr0z79kAv7Ixg8wPFEjgRgJdUsGMG3Hf3OYSF/kHI79XhNlt+5Ar6OzwxQ== - -lodash.some@^4.4.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" - integrity sha512-j7MJE+TuT51q9ggt4fSgVqro163BEFjAt3u97IqU+JA2DkWl80nFTrowzLpZ/BnpN7rrl0JA/593NAdd8p/scQ== - lodash.uniq@4.5.0, lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" @@ -7103,6 +6164,15 @@ markdown-escapes@^1.0.0: resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535" integrity sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg== +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + mdast-squeeze-paragraphs@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/mdast-squeeze-paragraphs/-/mdast-squeeze-paragraphs-4.0.0.tgz#7c4c114679c3bee27ef10b58e2e015be79f1ef97" @@ -7127,9 +6197,9 @@ mdast-util-definitions@^5.0.0: unist-util-visit "^4.0.0" mdast-util-from-markdown@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.0.tgz#0214124154f26154a2b3f9d401155509be45e894" - integrity sha512-HN3W1gRIuN/ZW295c7zi7g9lVBllMgZE40RxCX37wrTPWXCWtpvOZdfnuK+1WNpvZje6XuJeI3Wnb4TJEUem+g== + version "1.3.1" + resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz#9421a5a247f10d31d2faed2a30df5ec89ceafcf0" + integrity sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww== dependencies: "@types/mdast" "^3.0.0" "@types/unist" "^2.0.0" @@ -7178,9 +6248,9 @@ mdast-util-to-string@^2.0.0: integrity sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w== mdast-util-to-string@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-3.1.1.tgz#db859050d79d48cf9896d294de06f3ede7474d16" - integrity sha512-tGvhT94e+cVnQt8JWE9/b3cUQZWS732TJxXHktvP+BYo62PpYD53Ls/6cC60rW21dW+txxiM4zMdc6abASvZKA== + version "3.2.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-3.2.0.tgz#66f7bb6324756741c5f47a53557f0cbf16b6f789" + integrity sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg== dependencies: "@types/mdast" "^3.0.0" @@ -7204,17 +6274,17 @@ media-typer@0.3.0: resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== -medium-zoom@^1.0.4, medium-zoom@^1.0.6: +medium-zoom@^1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/medium-zoom/-/medium-zoom-1.0.8.tgz#2bd1fbcf2961fa7b0e318fe284462aa9b8608ed2" integrity sha512-CjFVuFq/IfrdqesAXfg+hzlDKu6A2n80ZIq0Kl9kWjoHh9j1N9Uvk5X0/MmN0hOfm5F9YBswlClhcwnmtwz7gA== -memfs@^3.1.2, memfs@^3.4.1, memfs@^3.4.3: - version "3.4.13" - resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.4.13.tgz#248a8bd239b3c240175cd5ec548de5227fc4f345" - integrity sha512-omTM41g3Skpvx5dSYeZIbXKcXoAVc/AoMNwn9TKx++L/gaen/+4TTttmu8ZSch5vfVJ8uJvGbroTsIlslRg6lg== +memfs@^3.1.2, memfs@^3.4.3: + version "3.6.0" + resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.6.0.tgz#d7a2110f86f79dd950a8b6df6d57bc984aa185f6" + integrity sha512-EGowvkkgbMcIChjMTMkESFDbZeSh8xZ7kNSF0hAiAN4Jh6jgHCRS0Ga/+C8y6Au+oqpezRHCfPsmJ2+DwAgiwQ== dependencies: - fs-monkey "^1.0.3" + fs-monkey "^1.0.4" merge-descriptors@1.0.1: version "1.0.1" @@ -7231,37 +6301,15 @@ merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -mermaid@^9.1.2: - version "9.4.3" - resolved "https://registry.yarnpkg.com/mermaid/-/mermaid-9.4.3.tgz#62cf210c246b74972ea98c19837519b6f03427f2" - integrity sha512-TLkQEtqhRSuEHSE34lh5bCa94KATCyluAXmFnNI2PRZwOpXFeqiJWwZl+d2CcemE1RS6QbbueSSq9QIg8Uxcyw== - dependencies: - "@braintree/sanitize-url" "^6.0.0" - cytoscape "^3.23.0" - cytoscape-cose-bilkent "^4.1.0" - cytoscape-fcose "^2.1.0" - d3 "^7.4.0" - dagre-d3-es "7.0.9" - dayjs "^1.11.7" - dompurify "2.4.3" - elkjs "^0.8.2" - khroma "^2.0.0" - lodash-es "^4.17.21" - non-layered-tidy-tree-layout "^2.0.2" - stylis "^4.1.2" - ts-dedent "^2.2.0" - uuid "^9.0.0" - web-worker "^1.2.0" - methods@^1.1.2, methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== micromark-core-commonmark@^1.0.1: - version "1.0.6" - resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-1.0.6.tgz#edff4c72e5993d93724a3c206970f5a15b0585ad" - integrity sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA== + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-1.1.0.tgz#1386628df59946b2d39fb2edfd10f3e8e0a75bb8" + integrity sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw== dependencies: decode-named-character-reference "^1.0.0" micromark-factory-destination "^1.0.0" @@ -7281,18 +6329,18 @@ micromark-core-commonmark@^1.0.1: uvu "^0.5.0" micromark-factory-destination@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz#fef1cb59ad4997c496f887b6977aa3034a5a277e" - integrity sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw== + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-1.1.0.tgz#eb815957d83e6d44479b3df640f010edad667b9f" + integrity sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg== dependencies: micromark-util-character "^1.0.0" micromark-util-symbol "^1.0.0" micromark-util-types "^1.0.0" micromark-factory-label@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/micromark-factory-label/-/micromark-factory-label-1.0.2.tgz#6be2551fa8d13542fcbbac478258fb7a20047137" - integrity sha512-CTIwxlOnU7dEshXDQ+dsr2n+yxpP0+fn271pu0bwDIS8uqfFcumXpj5mLn3hSC8iw2MUr6Gx8EcKng1dD7i6hg== + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-factory-label/-/micromark-factory-label-1.1.0.tgz#cc95d5478269085cfa2a7282b3de26eb2e2dec68" + integrity sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w== dependencies: micromark-util-character "^1.0.0" micromark-util-symbol "^1.0.0" @@ -7300,28 +6348,27 @@ micromark-factory-label@^1.0.0: uvu "^0.5.0" micromark-factory-space@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-factory-space/-/micromark-factory-space-1.0.0.tgz#cebff49968f2b9616c0fcb239e96685cb9497633" - integrity sha512-qUmqs4kj9a5yBnk3JMLyjtWYN6Mzfcx8uJfi5XAveBniDevmZasdGBba5b4QsvRcAkmvGo5ACmSUmyGiKTLZew== + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz#c8f40b0640a0150751d3345ed885a080b0d15faf" + integrity sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ== dependencies: micromark-util-character "^1.0.0" micromark-util-types "^1.0.0" micromark-factory-title@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/micromark-factory-title/-/micromark-factory-title-1.0.2.tgz#7e09287c3748ff1693930f176e1c4a328382494f" - integrity sha512-zily+Nr4yFqgMGRKLpTVsNl5L4PMu485fGFDOQJQBl2NFpjGte1e86zC0da93wf97jrc4+2G2GQudFMHn3IX+A== + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-factory-title/-/micromark-factory-title-1.1.0.tgz#dd0fe951d7a0ac71bdc5ee13e5d1465ad7f50ea1" + integrity sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ== dependencies: micromark-factory-space "^1.0.0" micromark-util-character "^1.0.0" micromark-util-symbol "^1.0.0" micromark-util-types "^1.0.0" - uvu "^0.5.0" micromark-factory-whitespace@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-factory-whitespace/-/micromark-factory-whitespace-1.0.0.tgz#e991e043ad376c1ba52f4e49858ce0794678621c" - integrity sha512-Qx7uEyahU1lt1RnsECBiuEbfr9INjQTGa6Err+gF3g0Tx4YEviPbqqGKNv/NrBaE7dVHdn1bVZKM/n5I/Bak7A== + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-factory-whitespace/-/micromark-factory-whitespace-1.1.0.tgz#798fb7489f4c8abafa7ca77eed6b5745853c9705" + integrity sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ== dependencies: micromark-factory-space "^1.0.0" micromark-util-character "^1.0.0" @@ -7329,48 +6376,48 @@ micromark-factory-whitespace@^1.0.0: micromark-util-types "^1.0.0" micromark-util-character@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/micromark-util-character/-/micromark-util-character-1.1.0.tgz#d97c54d5742a0d9611a68ca0cd4124331f264d86" - integrity sha512-agJ5B3unGNJ9rJvADMJ5ZiYjBRyDpzKAOk01Kpi1TKhlT1APx3XZk6eN7RtSz1erbWHC2L8T3xLZ81wdtGRZzg== + version "1.2.0" + resolved "https://registry.yarnpkg.com/micromark-util-character/-/micromark-util-character-1.2.0.tgz#4fedaa3646db249bc58caeb000eb3549a8ca5dcc" + integrity sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg== dependencies: micromark-util-symbol "^1.0.0" micromark-util-types "^1.0.0" micromark-util-chunked@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-chunked/-/micromark-util-chunked-1.0.0.tgz#5b40d83f3d53b84c4c6bce30ed4257e9a4c79d06" - integrity sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g== + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-util-chunked/-/micromark-util-chunked-1.1.0.tgz#37a24d33333c8c69a74ba12a14651fd9ea8a368b" + integrity sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ== dependencies: micromark-util-symbol "^1.0.0" micromark-util-classify-character@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-classify-character/-/micromark-util-classify-character-1.0.0.tgz#cbd7b447cb79ee6997dd274a46fc4eb806460a20" - integrity sha512-F8oW2KKrQRb3vS5ud5HIqBVkCqQi224Nm55o5wYLzY/9PwHGXC01tr3d7+TqHHz6zrKQ72Okwtvm/xQm6OVNZA== + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-util-classify-character/-/micromark-util-classify-character-1.1.0.tgz#6a7f8c8838e8a120c8e3c4f2ae97a2bff9190e9d" + integrity sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw== dependencies: micromark-util-character "^1.0.0" micromark-util-symbol "^1.0.0" micromark-util-types "^1.0.0" micromark-util-combine-extensions@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.0.0.tgz#91418e1e74fb893e3628b8d496085639124ff3d5" - integrity sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA== + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.1.0.tgz#192e2b3d6567660a85f735e54d8ea6e3952dbe84" + integrity sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA== dependencies: micromark-util-chunked "^1.0.0" micromark-util-types "^1.0.0" micromark-util-decode-numeric-character-reference@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.0.0.tgz#dcc85f13b5bd93ff8d2868c3dba28039d490b946" - integrity sha512-OzO9AI5VUtrTD7KSdagf4MWgHMtET17Ua1fIpXTpuhclCqD8egFWo85GxSGvxgkGS74bEahvtM0WP0HjvV0e4w== + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.1.0.tgz#b1e6e17009b1f20bc652a521309c5f22c85eb1c6" + integrity sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw== dependencies: micromark-util-symbol "^1.0.0" micromark-util-decode-string@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/micromark-util-decode-string/-/micromark-util-decode-string-1.0.2.tgz#942252ab7a76dec2dbf089cc32505ee2bc3acf02" - integrity sha512-DLT5Ho02qr6QWVNYbRZ3RYOSSWWFuH3tJexd3dgN1odEuPNxCngTCXJum7+ViRAd9BbdxCvMToPOD/IvVhzG6Q== + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-util-decode-string/-/micromark-util-decode-string-1.1.0.tgz#dc12b078cba7a3ff690d0203f95b5d5537f2809c" + integrity sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ== dependencies: decode-named-character-reference "^1.0.0" micromark-util-character "^1.0.0" @@ -7378,42 +6425,42 @@ micromark-util-decode-string@^1.0.0: micromark-util-symbol "^1.0.0" micromark-util-encode@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-1.0.1.tgz#2c1c22d3800870ad770ece5686ebca5920353383" - integrity sha512-U2s5YdnAYexjKDel31SVMPbfi+eF8y1U4pfiRW/Y8EFVCy/vgxk/2wWTxzcqE71LHtCuCzlBDRU2a5CQ5j+mQA== + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz#92e4f565fd4ccb19e0dcae1afab9a173bbeb19a5" + integrity sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw== micromark-util-html-tag-name@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.1.0.tgz#eb227118befd51f48858e879b7a419fc0df20497" - integrity sha512-BKlClMmYROy9UiV03SwNmckkjn8QHVaWkqoAqzivabvdGcwNGMMMH/5szAnywmsTBUzDsU57/mFi0sp4BQO6dA== + version "1.2.0" + resolved "https://registry.yarnpkg.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.2.0.tgz#48fd7a25826f29d2f71479d3b4e83e94829b3588" + integrity sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q== micromark-util-normalize-identifier@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.0.0.tgz#4a3539cb8db954bbec5203952bfe8cedadae7828" - integrity sha512-yg+zrL14bBTFrQ7n35CmByWUTFsgst5JhA4gJYoty4Dqzj4Z4Fr/DHekSS5aLfH9bdlfnSvKAWsAgJhIbogyBg== + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.1.0.tgz#7a73f824eb9f10d442b4d7f120fecb9b38ebf8b7" + integrity sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q== dependencies: micromark-util-symbol "^1.0.0" micromark-util-resolve-all@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-resolve-all/-/micromark-util-resolve-all-1.0.0.tgz#a7c363f49a0162e931960c44f3127ab58f031d88" - integrity sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw== + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-util-resolve-all/-/micromark-util-resolve-all-1.1.0.tgz#4652a591ee8c8fa06714c9b54cd6c8e693671188" + integrity sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA== dependencies: micromark-util-types "^1.0.0" micromark-util-sanitize-uri@^1.0.0, micromark-util-sanitize-uri@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.1.0.tgz#f12e07a85106b902645e0364feb07cf253a85aee" - integrity sha512-RoxtuSCX6sUNtxhbmsEFQfWzs8VN7cTctmBPvYivo98xb/kDEoTCtJQX5wyzIYEmk/lvNFTat4hL8oW0KndFpg== + version "1.2.0" + resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.2.0.tgz#613f738e4400c6eedbc53590c67b197e30d7f90d" + integrity sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A== dependencies: micromark-util-character "^1.0.0" micromark-util-encode "^1.0.0" micromark-util-symbol "^1.0.0" micromark-util-subtokenize@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-1.0.2.tgz#ff6f1af6ac836f8bfdbf9b02f40431760ad89105" - integrity sha512-d90uqCnXp/cy4G881Ub4psE57Sf8YD0pim9QdjCRNjfas2M1u6Lbt+XZK9gnHL2XFhnozZiEdCa9CNfXSfQ6xA== + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-1.1.0.tgz#941c74f93a93eaf687b9054aeb94642b0e92edb1" + integrity sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A== dependencies: micromark-util-chunked "^1.0.0" micromark-util-symbol "^1.0.0" @@ -7421,19 +6468,19 @@ micromark-util-subtokenize@^1.0.0: uvu "^0.5.0" micromark-util-symbol@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-1.0.1.tgz#b90344db62042ce454f351cf0bebcc0a6da4920e" - integrity sha512-oKDEMK2u5qqAptasDAwWDXq0tG9AssVwAx3E9bBF3t/shRIGsWIRG+cGafs2p/SnDSOecnt6hZPCE2o6lHfFmQ== + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz#813cd17837bdb912d069a12ebe3a44b6f7063142" + integrity sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag== micromark-util-types@^1.0.0, micromark-util-types@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-1.0.2.tgz#f4220fdb319205812f99c40f8c87a9be83eded20" - integrity sha512-DCfg/T8fcrhrRKTPjRrw/5LLvdGV7BHySf/1LOZx7TzWZdYRjogNtyNq885z3nNallwr3QUKARjqvHqX1/7t+w== + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-1.1.0.tgz#e6676a8cae0bb86a2171c498167971886cb7e283" + integrity sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg== micromark@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/micromark/-/micromark-3.1.0.tgz#eeba0fe0ac1c9aaef675157b52c166f125e89f62" - integrity sha512-6Mj0yHLdUZjHnOPgr5xfWIMqMWS12zDN6iws9SLuSz76W8jTtAv24MN4/CL7gJrl5vtxGInkkqDv/JIoRsQOvA== + version "3.2.0" + resolved "https://registry.yarnpkg.com/micromark/-/micromark-3.2.0.tgz#1af9fef3f995ea1ea4ac9c7e2f19c48fd5c006e9" + integrity sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA== dependencies: "@types/debug" "^4.0.0" debug "^4.0.0" @@ -7461,6 +6508,14 @@ micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: braces "^3.0.2" picomatch "^2.3.1" +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + mime-db@1.51.0: version "1.51.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" @@ -7524,25 +6579,23 @@ mimic-response@^1.0.0, mimic-response@^1.0.1: resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== -mini-css-extract-plugin@2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.0.tgz#578aebc7fc14d32c0ad304c2c34f08af44673f5e" - integrity sha512-ndG8nxCEnAemsg4FSgS+yNyHKgkTB4nPKqCOgh65j3/30qqC5RaSQQXMm++Y6sb6E1zRSxPkztj9fqxhS1Eo6w== - dependencies: - schema-utils "^4.0.0" - mini-css-extract-plugin@^2.6.1: - version "2.7.5" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.5.tgz#afbb344977659ec0f1f6e050c7aea456b121cfc5" - integrity sha512-9HaR++0mlgom81s95vvNjxkg52n2b5s//3ZTI1EtzFb98awsLSivs2LMsVqnQ3ay0PVhqWcGNyDaTE961FOcjQ== + version "2.7.6" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.6.tgz#282a3d38863fddcd2e0c220aaed5b90bc156564d" + integrity sha512-Qk7HcgaPkGG6eD77mLvZS1nmxlao3j+9PkrT9Uc7HAE1id3F41+DdBRYRYkbyfNRGzm8/YWtzhw7nVPmwhqTQw== dependencies: schema-utils "^4.0.0" -minimalistic-assert@^1.0.0: +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== + minimatch@3.1.2, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -7557,7 +6610,7 @@ minimatch@^5.0.1: dependencies: brace-expansion "^2.0.1" -minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: +minimist@^1.2.0, minimist@^1.2.5: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -7587,15 +6640,7 @@ ms@2.1.3: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -multicast-dns@7.2.4: - version "7.2.4" - resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-7.2.4.tgz#cf0b115c31e922aeb20b64e6556cbeb34cf0dd19" - integrity sha512-XkCYOU+rr2Ft3LI6w4ye51M3VK31qJXFIxu0XLw169PtKG0Zx47OrXeVW/GCYOfpC9s1yyyf1S+L8/4LY0J9Zw== - dependencies: - dns-packet "^5.2.2" - thunky "^1.0.2" - -multicast-dns@^7.2.4, multicast-dns@^7.2.5: +multicast-dns@^7.2.5: version "7.2.5" resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-7.2.5.tgz#77eb46057f4d7adbd16d9290fa7299f6fa64cced" integrity sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg== @@ -7617,10 +6662,10 @@ mz@^2.7.0: object-assign "^4.0.1" thenify-all "^1.0.0" -nanoid@3.3.4, nanoid@^3.3.4: - version "3.3.4" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" - integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== +nanoid@^3.3.6: + version "3.3.6" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" + integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== native-promise-only@^0.8.1: version "0.8.1" @@ -7659,25 +6704,49 @@ node-fetch-h2@^2.3.0: dependencies: http2-client "^1.2.5" -node-fetch@2.6.7: - version "2.6.7" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" - integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== +node-fetch@^2.6.1, node-fetch@^2.6.12: + version "2.6.12" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.12.tgz#02eb8e22074018e3d5a83016649d04df0e348fba" + integrity sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g== dependencies: whatwg-url "^5.0.0" -node-fetch@^2.6.1: - version "2.6.9" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6" - integrity sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg== - dependencies: - whatwg-url "^5.0.0" - -node-forge@1.3.1, node-forge@^1: +node-forge@^1: version "1.3.1" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== +node-polyfill-webpack-plugin@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/node-polyfill-webpack-plugin/-/node-polyfill-webpack-plugin-2.0.1.tgz#141d86f177103a8517c71d99b7c6a46edbb1bb58" + integrity sha512-ZUMiCnZkP1LF0Th2caY6J/eKKoA0TefpoVa68m/LQU1I/mE8rGt4fNYGgNuCcK+aG8P8P43nbeJ2RqJMOL/Y1A== + dependencies: + assert "^2.0.0" + browserify-zlib "^0.2.0" + buffer "^6.0.3" + console-browserify "^1.2.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.12.0" + domain-browser "^4.22.0" + events "^3.3.0" + filter-obj "^2.0.2" + https-browserify "^1.0.0" + os-browserify "^0.3.0" + path-browserify "^1.0.1" + process "^0.11.10" + punycode "^2.1.1" + querystring-es3 "^0.2.1" + readable-stream "^4.0.0" + stream-browserify "^3.0.0" + stream-http "^3.2.0" + string_decoder "^1.3.0" + timers-browserify "^2.0.12" + tty-browserify "^0.0.1" + type-fest "^2.14.0" + url "^0.11.0" + util "^0.12.4" + vm-browserify "^1.1.2" + node-readfiles@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/node-readfiles/-/node-readfiles-0.2.0.tgz#dbbd4af12134e2e635c245ef93ffcf6f60673a5d" @@ -7685,15 +6754,10 @@ node-readfiles@^0.2.0: dependencies: es6-promise "^3.2.1" -node-releases@^2.0.8: - version "2.0.10" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.10.tgz#c311ebae3b6a148c89b1813fd7c4d3c024ef537f" - integrity sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w== - -non-layered-tidy-tree-layout@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/non-layered-tidy-tree-layout/-/non-layered-tidy-tree-layout-2.0.2.tgz#57d35d13c356643fc296a55fb11ac15e74da7804" - integrity sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw== +node-releases@^2.0.13: + version "2.0.13" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" + integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" @@ -7734,13 +6798,6 @@ nth-check@^2.0.1: dependencies: boolbase "^1.0.0" -nth-check@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" - integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== - dependencies: - boolbase "~1.0.0" - oas-kit-common@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/oas-kit-common/-/oas-kit-common-1.0.8.tgz#6d8cacf6e9097967a4c7ea8bcbcbd77018e1f535" @@ -7809,16 +6866,19 @@ object-hash@^3.0.0: resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== -object-inspect@1.12.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" - integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== - object-inspect@^1.9.0: version "1.12.3" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== +object-is@^1.0.1: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -7879,6 +6939,11 @@ opener@^1.5.2: resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A== +os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + integrity sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A== + p-cancelable@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" @@ -7949,6 +7014,11 @@ package-json@^6.3.0: registry-url "^5.0.0" semver "^6.2.0" +pako@~1.0.5: + version "1.0.11" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== + param-case@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" @@ -7964,6 +7034,17 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" +parse-asn1@^5.0.0, parse-asn1@^5.1.5: + version "5.1.6" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" + integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== + dependencies: + asn1.js "^5.2.0" + browserify-aes "^1.0.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + safe-buffer "^5.1.1" + parse-entities@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8" @@ -8067,6 +7148,18 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-root-regex@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d" + integrity sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ== + +path-root@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7" + integrity sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg== + dependencies: + path-root-regex "^0.1.0" + path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" @@ -8097,6 +7190,17 @@ path@^0.12.7: process "^0.11.1" util "^0.10.3" +pbkdf2@^3.0.3: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" + integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + picocolors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" @@ -8113,9 +7217,9 @@ pify@^2.3.0: integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== pirates@^4.0.1: - version "4.0.5" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" - integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== + version "4.0.6" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" + integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== pkg-dir@^4.1.0: version "4.2.0" @@ -8131,18 +7235,12 @@ pkg-up@^3.1.0: dependencies: find-up "^3.0.0" -plugin-image-zoom@ataft/plugin-image-zoom: - version "1.1.0" - resolved "https://codeload.github.com/ataft/plugin-image-zoom/tar.gz/aaa95390dded2f80f503fa44bab2967423bbda1f" - dependencies: - medium-zoom "^1.0.4" - pluralize@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== -postcss-calc@8.2.4, postcss-calc@^8.2.3: +postcss-calc@^8.2.3: version "8.2.4" resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-8.2.4.tgz#77b9c29bfcbe8a07ff6693dc87050828889739a5" integrity sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q== @@ -8150,16 +7248,6 @@ postcss-calc@8.2.4, postcss-calc@^8.2.3: postcss-selector-parser "^6.0.9" postcss-value-parser "^4.2.0" -postcss-colormin@5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.3.0.tgz#3cee9e5ca62b2c27e84fce63affc0cfb5901956a" - integrity sha512-WdDO4gOFG2Z8n4P8TWBpshnL3JpmNmJwdnfP2gbk2qBA8PWwOYcmjmI/t3CmMeL72a7Hkd+x/Mg9O2/0rD54Pg== - dependencies: - browserslist "^4.16.6" - caniuse-api "^3.0.0" - colord "^2.9.1" - postcss-value-parser "^4.2.0" - postcss-colormin@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.3.1.tgz#86c27c26ed6ba00d96c79e08f3ffb418d1d1988f" @@ -8170,13 +7258,6 @@ postcss-colormin@^5.3.1: colord "^2.9.1" postcss-value-parser "^4.2.0" -postcss-convert-values@5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.1.0.tgz#f8d3abe40b4ce4b1470702a0706343eac17e7c10" - integrity sha512-GkyPbZEYJiWtQB0KZ0X6qusqFHUepguBCNFi9t5JJc7I2OTXG7C0twbTLvCfaKOLl3rSXmpAwV7W5txd91V84g== - dependencies: - postcss-value-parser "^4.2.0" - postcss-convert-values@^5.1.3: version "5.1.3" resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz#04998bb9ba6b65aa31035d669a6af342c5f9d393" @@ -8185,81 +7266,67 @@ postcss-convert-values@^5.1.3: browserslist "^4.21.4" postcss-value-parser "^4.2.0" -postcss-discard-comments@5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-5.1.1.tgz#e90019e1a0e5b99de05f63516ce640bd0df3d369" - integrity sha512-5JscyFmvkUxz/5/+TB3QTTT9Gi9jHkcn8dcmmuN68JQcv3aQg4y88yEHHhwFB52l/NkaJ43O0dbksGMAo49nfQ== - postcss-discard-comments@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz#8df5e81d2925af2780075840c1526f0660e53696" integrity sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ== -postcss-discard-duplicates@5.1.0, postcss-discard-duplicates@^5.1.0: +postcss-discard-duplicates@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz#9eb4fe8456706a4eebd6d3b7b777d07bad03e848" integrity sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw== -postcss-discard-empty@5.1.1, postcss-discard-empty@^5.1.1: +postcss-discard-empty@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz#e57762343ff7f503fe53fca553d18d7f0c369c6c" integrity sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A== -postcss-discard-overridden@5.1.0, postcss-discard-overridden@^5.1.0: +postcss-discard-overridden@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz#7e8c5b53325747e9d90131bb88635282fb4a276e" integrity sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw== -postcss-discard-unused@5.1.0, postcss-discard-unused@^5.1.0: +postcss-discard-unused@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-discard-unused/-/postcss-discard-unused-5.1.0.tgz#8974e9b143d887677304e558c1166d3762501142" integrity sha512-KwLWymI9hbwXmJa0dkrzpRbSJEh0vVUd7r8t0yOGPcfKzyJJxFM8kLyC5Ev9avji6nY95pOp1W6HqIrfT+0VGw== dependencies: postcss-selector-parser "^6.0.5" -postcss-import@^14.1.0: - version "14.1.0" - resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-14.1.0.tgz#a7333ffe32f0b8795303ee9e40215dac922781f0" - integrity sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw== +postcss-import@^15.1.0: + version "15.1.0" + resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-15.1.0.tgz#41c64ed8cc0e23735a9698b3249ffdbf704adc70" + integrity sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew== dependencies: postcss-value-parser "^4.0.0" read-cache "^1.0.0" resolve "^1.1.7" -postcss-js@^4.0.0: +postcss-js@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.1.tgz#61598186f3703bab052f1c4f7d805f3991bee9d2" integrity sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw== dependencies: camelcase-css "^2.0.1" -postcss-load-config@^3.1.4: - version "3.1.4" - resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-3.1.4.tgz#1ab2571faf84bb078877e1d07905eabe9ebda855" - integrity sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg== +postcss-load-config@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-4.0.1.tgz#152383f481c2758274404e4962743191d73875bd" + integrity sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA== dependencies: lilconfig "^2.0.5" - yaml "^1.10.2" - -postcss-loader@6.2.1: - version "6.2.1" - resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-6.2.1.tgz#0895f7346b1702103d30fdc66e4d494a93c008ef" - integrity sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q== - dependencies: - cosmiconfig "^7.0.0" - klona "^2.0.5" - semver "^7.3.5" + yaml "^2.1.1" postcss-loader@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-7.1.0.tgz#3ba0dfddff06043f3eac7690a1d8b432264bb866" - integrity sha512-vTD2DJ8vJD0Vr1WzMQkRZWRjcynGh3t7NeoLg+Sb1TeuK7etiZfL/ZwHbaVa3M+Qni7Lj/29voV9IggnIUjlIw== + version "7.3.3" + resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-7.3.3.tgz#6da03e71a918ef49df1bb4be4c80401df8e249dd" + integrity sha512-YgO/yhtevGO/vJePCQmTxiaEwER94LABZN0ZMT4A0vsak9TpO+RvKRs7EmJ8peIlB9xfXCsS7M8LjqncsUZ5HA== dependencies: - cosmiconfig "^8.0.0" - klona "^2.0.6" + cosmiconfig "^8.2.0" + jiti "^1.18.2" semver "^7.3.8" -postcss-merge-idents@5.1.1, postcss-merge-idents@^5.1.1: +postcss-merge-idents@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-5.1.1.tgz#7753817c2e0b75d0853b56f78a89771e15ca04a1" integrity sha512-pCijL1TREiCoog5nQp7wUe+TUonA2tC2sQ54UGeMmryK3UFGIYKqDyjnqd6RcuI4znFn9hWSLNN8xKE/vWcUQw== @@ -8267,14 +7334,6 @@ postcss-merge-idents@5.1.1, postcss-merge-idents@^5.1.1: cssnano-utils "^3.1.0" postcss-value-parser "^4.2.0" -postcss-merge-longhand@5.1.4: - version "5.1.4" - resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.1.4.tgz#0f46f8753989a33260efc47de9a0cdc571f2ec5c" - integrity sha512-hbqRRqYfmXoGpzYKeW0/NCZhvNyQIlQeWVSao5iKWdyx7skLvCfQFGIUsP9NUs3dSbPac2IC4Go85/zG+7MlmA== - dependencies: - postcss-value-parser "^4.2.0" - stylehacks "^5.1.0" - postcss-merge-longhand@^5.1.7: version "5.1.7" resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz#24a1bdf402d9ef0e70f568f39bdc0344d568fb16" @@ -8283,16 +7342,6 @@ postcss-merge-longhand@^5.1.7: postcss-value-parser "^4.2.0" stylehacks "^5.1.1" -postcss-merge-rules@5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.1.1.tgz#d327b221cd07540bcc8d9ff84446d8b404d00162" - integrity sha512-8wv8q2cXjEuCcgpIB1Xx1pIy8/rhMPIQqYKNzEdyx37m6gpq83mQQdCxgIkFgliyEnKvdwJf/C61vN4tQDq4Ww== - dependencies: - browserslist "^4.16.6" - caniuse-api "^3.0.0" - cssnano-utils "^3.1.0" - postcss-selector-parser "^6.0.5" - postcss-merge-rules@^5.1.4: version "5.1.4" resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz#2f26fa5cacb75b1402e213789f6766ae5e40313c" @@ -8303,14 +7352,14 @@ postcss-merge-rules@^5.1.4: cssnano-utils "^3.1.0" postcss-selector-parser "^6.0.5" -postcss-minify-font-values@5.1.0, postcss-minify-font-values@^5.1.0: +postcss-minify-font-values@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz#f1df0014a726083d260d3bd85d7385fb89d1f01b" integrity sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA== dependencies: postcss-value-parser "^4.2.0" -postcss-minify-gradients@5.1.1, postcss-minify-gradients@^5.1.1: +postcss-minify-gradients@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz#f1fe1b4f498134a5068240c2f25d46fcd236ba2c" integrity sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw== @@ -8319,15 +7368,6 @@ postcss-minify-gradients@5.1.1, postcss-minify-gradients@^5.1.1: cssnano-utils "^3.1.0" postcss-value-parser "^4.2.0" -postcss-minify-params@5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.1.2.tgz#77e250780c64198289c954884ebe3ee4481c3b1c" - integrity sha512-aEP+p71S/urY48HWaRHasyx4WHQJyOYaKpQ6eXl8k0kxg66Wt/30VR6/woh8THgcpRbonJD5IeD+CzNhPi1L8g== - dependencies: - browserslist "^4.16.6" - cssnano-utils "^3.1.0" - postcss-value-parser "^4.2.0" - postcss-minify-params@^5.1.4: version "5.1.4" resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz#c06a6c787128b3208b38c9364cfc40c8aa5d7352" @@ -8337,13 +7377,6 @@ postcss-minify-params@^5.1.4: cssnano-utils "^3.1.0" postcss-value-parser "^4.2.0" -postcss-minify-selectors@5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-5.2.0.tgz#17c2be233e12b28ffa8a421a02fc8b839825536c" - integrity sha512-vYxvHkW+iULstA+ctVNx0VoRAR4THQQRkG77o0oa4/mBS0OzGvvzLIvHDv/nNEM0crzN2WIyFU5X7wZhaUK3RA== - dependencies: - postcss-selector-parser "^6.0.5" - postcss-minify-selectors@^5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz#d4e7e6b46147b8117ea9325a915a801d5fe656c6" @@ -8356,10 +7389,10 @@ postcss-modules-extract-imports@^3.0.0: resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw== -postcss-modules-local-by-default@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz#ebbb54fae1598eecfdf691a02b3ff3b390a5a51c" - integrity sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ== +postcss-modules-local-by-default@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz#b08eb4f083050708998ba2c6061b50c2870ca524" + integrity sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA== dependencies: icss-utils "^5.0.0" postcss-selector-parser "^6.0.2" @@ -8379,32 +7412,25 @@ postcss-modules-values@^4.0.0: dependencies: icss-utils "^5.0.0" -postcss-nested@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-6.0.0.tgz#1572f1984736578f360cffc7eb7dca69e30d1735" - integrity sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w== +postcss-nested@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-6.0.1.tgz#f83dc9846ca16d2f4fa864f16e9d9f7d0961662c" + integrity sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ== dependencies: - postcss-selector-parser "^6.0.10" + postcss-selector-parser "^6.0.11" -postcss-normalize-charset@5.1.0, postcss-normalize-charset@^5.1.0: +postcss-normalize-charset@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz#9302de0b29094b52c259e9b2cf8dc0879879f0ed" integrity sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg== -postcss-normalize-display-values@5.1.0, postcss-normalize-display-values@^5.1.0: +postcss-normalize-display-values@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz#72abbae58081960e9edd7200fcf21ab8325c3da8" integrity sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA== dependencies: postcss-value-parser "^4.2.0" -postcss-normalize-positions@5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-5.1.0.tgz#902a7cb97cf0b9e8b1b654d4a43d451e48966458" - integrity sha512-8gmItgA4H5xiUxgN/3TVvXRoJxkAWLW6f/KKhdsH03atg0cB8ilXnrB5PpSshwVu/dD2ZsRFQcR1OEmSBDAgcQ== - dependencies: - postcss-value-parser "^4.2.0" - postcss-normalize-positions@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz#ef97279d894087b59325b45c47f1e863daefbb92" @@ -8412,13 +7438,6 @@ postcss-normalize-positions@^5.1.1: dependencies: postcss-value-parser "^4.2.0" -postcss-normalize-repeat-style@5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.0.tgz#f6d6fd5a54f51a741cc84a37f7459e60ef7a6398" - integrity sha512-IR3uBjc+7mcWGL6CtniKNQ4Rr5fTxwkaDHwMBDGGs1x9IVRkYIT/M4NelZWkAOBdV6v3Z9S46zqaKGlyzHSchw== - dependencies: - postcss-value-parser "^4.2.0" - postcss-normalize-repeat-style@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz#e9eb96805204f4766df66fd09ed2e13545420fb2" @@ -8426,28 +7445,20 @@ postcss-normalize-repeat-style@^5.1.1: dependencies: postcss-value-parser "^4.2.0" -postcss-normalize-string@5.1.0, postcss-normalize-string@^5.1.0: +postcss-normalize-string@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz#411961169e07308c82c1f8c55f3e8a337757e228" integrity sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w== dependencies: postcss-value-parser "^4.2.0" -postcss-normalize-timing-functions@5.1.0, postcss-normalize-timing-functions@^5.1.0: +postcss-normalize-timing-functions@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz#d5614410f8f0b2388e9f240aa6011ba6f52dafbb" integrity sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg== dependencies: postcss-value-parser "^4.2.0" -postcss-normalize-unicode@5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.0.tgz#3d23aede35e160089a285e27bf715de11dc9db75" - integrity sha512-J6M3MizAAZ2dOdSjy2caayJLQT8E8K9XjLce8AUQMwOrCvjCHv24aLC/Lps1R1ylOfol5VIDMaM/Lo9NGlk1SQ== - dependencies: - browserslist "^4.16.6" - postcss-value-parser "^4.2.0" - postcss-normalize-unicode@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz#f67297fca3fea7f17e0d2caa40769afc487aa030" @@ -8456,7 +7467,7 @@ postcss-normalize-unicode@^5.1.1: browserslist "^4.21.4" postcss-value-parser "^4.2.0" -postcss-normalize-url@5.1.0, postcss-normalize-url@^5.1.0: +postcss-normalize-url@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz#ed9d88ca82e21abef99f743457d3729a042adcdc" integrity sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew== @@ -8464,21 +7475,13 @@ postcss-normalize-url@5.1.0, postcss-normalize-url@^5.1.0: normalize-url "^6.0.1" postcss-value-parser "^4.2.0" -postcss-normalize-whitespace@5.1.1, postcss-normalize-whitespace@^5.1.1: +postcss-normalize-whitespace@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz#08a1a0d1ffa17a7cc6efe1e6c9da969cc4493cfa" integrity sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA== dependencies: postcss-value-parser "^4.2.0" -postcss-ordered-values@5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.1.1.tgz#0b41b610ba02906a3341e92cab01ff8ebc598adb" - integrity sha512-7lxgXF0NaoMIgyihL/2boNAEZKiW0+HkMhdKMTD93CjW8TdCy2hSdj8lsAo+uwm7EDG16Da2Jdmtqpedl0cMfw== - dependencies: - cssnano-utils "^3.1.0" - postcss-value-parser "^4.2.0" - postcss-ordered-values@^5.1.3: version "5.1.3" resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz#b6fd2bd10f937b23d86bc829c69e7732ce76ea38" @@ -8487,21 +7490,13 @@ postcss-ordered-values@^5.1.3: cssnano-utils "^3.1.0" postcss-value-parser "^4.2.0" -postcss-reduce-idents@5.2.0, postcss-reduce-idents@^5.2.0: +postcss-reduce-idents@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-5.2.0.tgz#c89c11336c432ac4b28792f24778859a67dfba95" integrity sha512-BTrLjICoSB6gxbc58D5mdBK8OhXRDqud/zodYfdSi52qvDHdMwk+9kB9xsM8yJThH/sZU5A6QVSmMmaN001gIg== dependencies: postcss-value-parser "^4.2.0" -postcss-reduce-initial@5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.1.0.tgz#fc31659ea6e85c492fb2a7b545370c215822c5d6" - integrity sha512-5OgTUviz0aeH6MtBjHfbr57tml13PuedK/Ecg8szzd4XRMbYxH4572JFG067z+FqBIf6Zp/d+0581glkvvWMFw== - dependencies: - browserslist "^4.16.6" - caniuse-api "^3.0.0" - postcss-reduce-initial@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz#798cd77b3e033eae7105c18c9d371d989e1382d6" @@ -8510,36 +7505,29 @@ postcss-reduce-initial@^5.1.2: browserslist "^4.21.4" caniuse-api "^3.0.0" -postcss-reduce-transforms@5.1.0, postcss-reduce-transforms@^5.1.0: +postcss-reduce-transforms@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz#333b70e7758b802f3dd0ddfe98bb1ccfef96b6e9" integrity sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ== dependencies: postcss-value-parser "^4.2.0" -postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5, postcss-selector-parser@^6.0.9: - version "6.0.11" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz#2e41dc39b7ad74046e1615185185cd0b17d0c8dc" - integrity sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g== +postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5, postcss-selector-parser@^6.0.9: + version "6.0.13" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz#d05d8d76b1e8e173257ef9d60b706a8e5e99bf1b" + integrity sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ== dependencies: cssesc "^3.0.0" util-deprecate "^1.0.2" -postcss-sort-media-queries@4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/postcss-sort-media-queries/-/postcss-sort-media-queries-4.2.1.tgz#a99bae69ef1098ee3b64a5fa94d258ec240d0355" - integrity sha512-9VYekQalFZ3sdgcTjXMa0dDjsfBVHXlraYJEMiOJ/2iMmI2JGCMavP16z3kWOaRu8NSaJCTgVpB/IVpH5yT9YQ== - dependencies: - sort-css-media-queries "2.0.4" - postcss-sort-media-queries@^4.2.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/postcss-sort-media-queries/-/postcss-sort-media-queries-4.3.0.tgz#f48a77d6ce379e86676fc3f140cf1b10a06f6051" - integrity sha512-jAl8gJM2DvuIJiI9sL1CuiHtKM4s5aEIomkU8G3LFvbP+p8i7Sz8VV63uieTgoewGqKbi+hxBTiOKJlB35upCg== + version "4.4.1" + resolved "https://registry.yarnpkg.com/postcss-sort-media-queries/-/postcss-sort-media-queries-4.4.1.tgz#04a5a78db3921eb78f28a1a781a2e68e65258128" + integrity sha512-QDESFzDDGKgpiIh4GYXsSy6sek2yAwQx1JASl5AxBtU1Lq2JfKBljIPNdil989NcSKRQX1ToiaKphImtBuhXWw== dependencies: sort-css-media-queries "2.1.0" -postcss-svgo@5.1.0, postcss-svgo@^5.1.0: +postcss-svgo@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-5.1.0.tgz#0a317400ced789f233a28826e77523f15857d80d" integrity sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA== @@ -8547,7 +7535,7 @@ postcss-svgo@5.1.0, postcss-svgo@^5.1.0: postcss-value-parser "^4.2.0" svgo "^2.7.0" -postcss-unique-selectors@5.1.1, postcss-unique-selectors@^5.1.1: +postcss-unique-selectors@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz#a9f273d1eacd09e9aa6088f4b0507b18b1b541b6" integrity sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA== @@ -8559,17 +7547,17 @@ postcss-value-parser@^4.0.0, postcss-value-parser@^4.1.0, postcss-value-parser@^ resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss-zindex@5.1.0, postcss-zindex@^5.1.0: +postcss-zindex@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-5.1.0.tgz#4a5c7e5ff1050bd4c01d95b1847dfdcc58a496ff" integrity sha512-fgFMf0OtVSBR1va1JNHYgMxYk73yhn/qb4uQDq1DLGYolz8gHCyr/sesEuGUaYs58E3ZJRcpoGuPVoB7Meiq9A== -postcss@^8.0.9, postcss@^8.3.11, postcss@^8.3.5, postcss@^8.4.14, postcss@^8.4.17, postcss@^8.4.19, postcss@^8.4.7: - version "8.4.21" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.21.tgz#c639b719a57efc3187b13a1d765675485f4134f4" - integrity sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg== +postcss@^8.3.11, postcss@^8.4.14, postcss@^8.4.17, postcss@^8.4.19, postcss@^8.4.21, postcss@^8.4.23: + version "8.4.27" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.27.tgz#234d7e4b72e34ba5a92c29636734349e0d9c3057" + integrity sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ== dependencies: - nanoid "^3.3.4" + nanoid "^3.3.6" picocolors "^1.0.0" source-map-js "^1.0.2" @@ -8603,11 +7591,6 @@ prism-react-renderer@^1.3.1, prism-react-renderer@^1.3.5: resolved "https://registry.yarnpkg.com/prism-react-renderer/-/prism-react-renderer-1.3.5.tgz#786bb69aa6f73c32ba1ee813fbe17a0115435085" integrity sha512-IJ+MSwBWKG+SM3b2SUfdrhC+gu01QkV2KmRQgREThBfSQRoufqRfxfHUxpG1WcaFjP+kojcFyO9Qqtpgt3qLCg== -prismjs@1.28.0: - version "1.28.0" - resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.28.0.tgz#0d8f561fa0f7cf6ebca901747828b149147044b6" - integrity sha512-8aaXdYvl1F7iC7Xm1spqSaY/OJBpYW3v+KJ+F17iYxvdc8sfjW194COK5wVhMZX45tGteiBQgdvD/nhxcRwylw== - prismjs@^1.28.0: version "1.29.0" resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.29.0.tgz#f113555a8fa9b57c35e637bba27509dcf802dd12" @@ -8667,6 +7650,18 @@ proxy-addr@~2.0.7: forwarded "0.2.0" ipaddr.js "1.9.1" +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + pump@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" @@ -8675,12 +7670,7 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -punycode@1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - integrity sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw== - -punycode@^1.3.2: +punycode@^1.3.2, punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== @@ -8702,13 +7692,6 @@ pure-color@^1.2.0: resolved "https://registry.yarnpkg.com/pure-color/-/pure-color-1.3.0.tgz#1fe064fb0ac851f0de61320a8bf796836422f33e" integrity sha512-QFADYnsVoBMw1srW7OVKEYjG+MbIa49s54w1MA1EDY6r2r/sTcKKYqRX1f4GYvnXP7eN/Pe9HFcX+hwzmrXRHA== -qs@6.10.3: - version "6.10.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.3.tgz#d6cde1b2ffca87b5aa57889816c5f81535e22e8e" - integrity sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ== - dependencies: - side-channel "^1.0.4" - qs@6.11.0: version "6.11.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" @@ -8717,16 +7700,16 @@ qs@6.11.0: side-channel "^1.0.4" qs@^6.10.3, qs@^6.11.0: - version "6.11.1" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.1.tgz#6c29dff97f0c0060765911ba65cbc9764186109f" - integrity sha512-0wsrzgTz/kAVIeuxSjnpGC56rzYtr6JT/2BwEvMaPhFIoYa1aGO8LbzuU1R0uUYQkLpWBTOj0l/CLAJB64J6nQ== + version "6.11.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" + integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA== dependencies: side-channel "^1.0.4" -querystring@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - integrity sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g== +querystring-es3@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + integrity sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA== queue-microtask@^1.2.2: version "1.2.3" @@ -8740,18 +7723,21 @@ queue@6.0.2: dependencies: inherits "~2.0.3" -quick-lru@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" - integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== - -randombytes@^2.1.0: +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== dependencies: safe-buffer "^5.1.0" +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + range-parser@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" @@ -8808,7 +7794,7 @@ react-copy-to-clipboard@^5.1.0: copy-to-clipboard "^3.3.1" prop-types "^15.8.1" -react-dev-utils@12.0.1, react-dev-utils@^12.0.1: +react-dev-utils@^12.0.1: version "12.0.1" resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-12.0.1.tgz#ba92edb4a1f379bd46ccd6bcd4e7bc398df33e73" integrity sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ== @@ -8838,29 +7824,23 @@ react-dev-utils@12.0.1, react-dev-utils@^12.0.1: strip-ansi "^6.0.1" text-table "^0.2.0" -react-dom@^17.0.2: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" - integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== +react-dom@^18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" + integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== dependencies: loose-envify "^1.1.0" - object-assign "^4.1.1" - scheduler "^0.20.2" + scheduler "^0.23.0" -react-error-overlay@6.0.11, react-error-overlay@^6.0.11: +react-error-overlay@^6.0.11: version "6.0.11" resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.11.tgz#92835de5841c5cf08ba00ddd2d677b6d17ff9adb" integrity sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg== -react-fast-compare@3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" - integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== - react-fast-compare@^3.2.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.1.tgz#53933d9e14f364281d6cba24bfed7a4afb808b5f" - integrity sha512-xTYf9zFim2pEif/Fw16dBiXpe0hoy5PxcD8+OwBnTtNLfIm3g6WxhKNurY+6OmdH1u6Ta/W/Vl6vjbYP1MFnDg== + version "3.2.2" + resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.2.tgz#929a97a532304ce9fee4bcae44234f1ce2c21d49" + integrity sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ== react-helmet-async@*, react-helmet-async@^1.3.0: version "1.3.0" @@ -8904,9 +7884,9 @@ react-lifecycles-compat@^3.0.0, react-lifecycles-compat@^3.0.4: integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== react-live@^3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/react-live/-/react-live-3.1.2.tgz#1927e429afce12c82f8236f96125fb930c50252a" - integrity sha512-U9LhpvOBd1o9ajylgk6yyM7sfkMv0CM6Ya40DBlp4QcPlvwKH6tbDnGXyA5qv/wx1dwIj+cYhAzn3YoxPeMaAw== + version "3.2.0" + resolved "https://registry.yarnpkg.com/react-live/-/react-live-3.2.0.tgz#d3c243b8d4ce4b3e6a6009e6238b0f972bf99cac" + integrity sha512-tHkft6spWgNOlW21XUQKqoFDP9ZVhrEUBD80sYwL1ykOovj9DN2z0GXW3d4G7gAphcUXCy+BLfe1S/IpdE5AAQ== dependencies: prism-react-renderer "^1.3.1" sucrase "^3.21.0" @@ -8925,9 +7905,9 @@ react-magic-dropzone@^1.0.1: integrity sha512-0BIROPARmXHpk4AS3eWBOsewxoM5ndk2psYP/JmbCq8tz3uR2LIV1XiroZ9PKrmDRMctpW+TvsBCtWasuS8vFA== react-markdown@^8.0.1: - version "8.0.5" - resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-8.0.5.tgz#c9a70a33ca9aeeafb769c6582e7e38843b9d70ad" - integrity sha512-jGJolWWmOWAvzf+xMdB9zwStViODyyFQhNB/bwCerbBKmrTmgmA599CGiOlP58OId1IMoIRsA8UdI1Lod4zb5A== + version "8.0.7" + resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-8.0.7.tgz#c8dbd1b9ba5f1c5e7e5f2a44de465a3caafdf89b" + integrity sha512-bvWbzG4MtOU62XqBx3Xx+zB2raaFFsq4mYiAzfjXJMEz2sixgeAfraA3tvzULF02ZdOMUOKTBFFaZJDDrq+BJQ== dependencies: "@types/hast" "^2.0.0" "@types/prop-types" "^15.0.0" @@ -9003,21 +7983,20 @@ react-router@5.3.4, react-router@^5.3.3: tiny-warning "^1.0.0" react-textarea-autosize@^8.3.2: - version "8.4.0" - resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-8.4.0.tgz#4d0244d6a50caa897806b8c44abc0540a69bfc8c" - integrity sha512-YrTFaEHLgJsi8sJVYHBzYn+mkP3prGkmP2DKb/tm0t7CLJY5t1Rxix8070LAKb0wby7bl/lf2EeHkuMihMZMwQ== + version "8.5.2" + resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-8.5.2.tgz#6421df2b5b50b9ca8c5e96fd31be688ea7fa2f9d" + integrity sha512-uOkyjkEl0ByEK21eCJMHDGBAAd/BoFQBawYK5XItjAmCTeSbjxghd8qnt7nzsLYzidjnoObu6M26xts0YGKsGg== dependencies: - "@babel/runtime" "^7.10.2" + "@babel/runtime" "^7.20.13" use-composed-ref "^1.3.0" use-latest "^1.2.1" -react@^17.0.2: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" - integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== +react@^18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" + integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== dependencies: loose-envify "^1.1.0" - object-assign "^4.1.1" read-cache@^1.0.0: version "1.0.0" @@ -9039,7 +8018,7 @@ readable-stream@^2.0.1: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.6.0: +readable-stream@^3.0.6, readable-stream@^3.5.0, readable-stream@^3.6.0: version "3.6.2" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== @@ -9048,6 +8027,17 @@ readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.6.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" +readable-stream@^4.0.0: + version "4.4.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.4.2.tgz#e6aced27ad3b9d726d8308515b9a1b98dc1b9d13" + integrity sha512-Lk/fICSyIhodxy1IDK2HazkeGjSmezAWX2egdtJnYhtzKEsBPJowlI6F6LPb5tqIQILrMbx22S5o3GuJavPusA== + dependencies: + abort-controller "^3.0.0" + buffer "^6.0.3" + events "^3.3.0" + process "^0.11.10" + string_decoder "^1.3.0" + readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -9084,7 +8074,7 @@ redux-thunk@^2.4.2: resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.4.2.tgz#b9d05d11994b99f7a91ea223e8b04cf0afa5ef3b" integrity sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q== -redux@^4.0.0, redux@^4.2.0: +redux@^4.0.0, redux@^4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.1.tgz#c08f4306826c49b5e9dc901dee0452ea8fce6197" integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w== @@ -9108,19 +8098,12 @@ regenerate@^1.4.2: resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== -regenerator-runtime@^0.13.11, regenerator-runtime@^0.13.4: +regenerator-runtime@^0.13.11: version "0.13.11" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== -regenerator-transform@0.15.0: - version "0.15.0" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.0.tgz#cbd9ead5d77fae1a48d957cf889ad0586adb6537" - integrity sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg== - dependencies: - "@babel/runtime" "^7.8.4" - -regenerator-transform@^0.15.0, regenerator-transform@^0.15.1: +regenerator-transform@^0.15.1: version "0.15.1" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.1.tgz#f6c4e99fc1b4591f780db2586328e4d9a9d8dc56" integrity sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg== @@ -9174,7 +8157,7 @@ relateurl@^0.2.7: resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" integrity sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog== -remark-emoji@2.2.0, remark-emoji@^2.2.0: +remark-emoji@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/remark-emoji/-/remark-emoji-2.2.0.tgz#1c702090a1525da5b80e15a8f963ef2c8236cac7" integrity sha512-P3cj9s5ggsUvWw5fS2uzCHJMGuXYRb0NnZqYlNecewXt8QBU9n5vW3DUUKOhepS8F9CwdMx9B8a3i7pqFWAI5w== @@ -9225,9 +8208,9 @@ remark-parse@8.0.3: xtend "^4.0.1" remark-parse@^10.0.0: - version "10.0.1" - resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-10.0.1.tgz#6f60ae53edbf0cf38ea223fe643db64d112e0775" - integrity sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw== + version "10.0.2" + resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-10.0.2.tgz#ca241fde8751c2158933f031a4e3efbaeb8bc262" + integrity sha512-3ydxgHa/ZQzG8LvC7jTXccARYDcRld3VfcgIIFs7bI6vbRSxJJmzgLEIIoYKyrfhaY+ujuWaf/PJiMZXoiCXgw== dependencies: "@types/mdast" "^3.0.0" mdast-util-from-markdown "^1.0.0" @@ -9291,27 +8274,34 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== -reselect@^4.1.7: - version "4.1.7" - resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.7.tgz#56480d9ff3d3188970ee2b76527bd94a95567a42" - integrity sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A== +reselect@^4.1.8: + version "4.1.8" + resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.8.tgz#3f5dc671ea168dccdeb3e141236f69f02eaec524" + integrity sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ== resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== +resolve-package-path@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/resolve-package-path/-/resolve-package-path-4.0.3.tgz#31dab6897236ea6613c72b83658d88898a9040aa" + integrity sha512-SRpNAPW4kewOaNUt8VPqhJ0UMxawMwzJD8V7m1cJfdSTK9ieZwS6K7Dabsm4bmLFM96Z5Y/UznrpG5kt1im8yA== + dependencies: + path-root "^0.1.1" + resolve-pathname@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== -resolve@^1.1.6, resolve@^1.1.7, resolve@^1.14.2, resolve@^1.22.1, resolve@^1.3.2: - version "1.22.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" - integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== +resolve@^1.1.6, resolve@^1.1.7, resolve@^1.14.2, resolve@^1.22.2, resolve@^1.3.2: + version "1.22.2" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f" + integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== dependencies: - is-core-module "^2.9.0" + is-core-module "^2.11.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" @@ -9339,17 +8329,20 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" -robust-predicates@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/robust-predicates/-/robust-predicates-3.0.1.tgz#ecde075044f7f30118682bd9fb3f123109577f9a" - integrity sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g== +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" rtl-detect@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/rtl-detect/-/rtl-detect-1.0.4.tgz#40ae0ea7302a150b96bc75af7d749607392ecac6" integrity sha512-EBR4I2VDSSYr7PkBmFy04uhycIpDKp+21p/jARYXlCSjQksTBQcJ0HFUPOO79EPPH5JS6VAhiIQbycf0O3JAxQ== -rtlcss@3.5.0, rtlcss@^3.5.0: +rtlcss@^3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/rtlcss/-/rtlcss-3.5.0.tgz#c9eb91269827a102bac7ae3115dd5d049de636c3" integrity sha512-wzgMaMFHQTnyi9YOwsx9LjOxYXJPzS8sYnFaKm6R5ysvTkwzHiB0vxnbHwchHQT65PTdBjDG21/kQBWI7q9O7A== @@ -9366,22 +8359,10 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rw@1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4" - integrity sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ== - -rxjs@7.5.5: - version "7.5.5" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.5.tgz#2ebad89af0f560f460ad5cc4213219e1f7dd4e9f" - integrity sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw== - dependencies: - tslib "^2.1.0" - rxjs@^7.5.4: - version "7.8.0" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.0.tgz#90a938862a82888ff4c7359811a595e14e1e09a4" - integrity sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg== + version "7.8.1" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" + integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== dependencies: tslib "^2.1.0" @@ -9397,12 +8378,12 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.1.0, safe-buffer@~5.2.0: +safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -9412,13 +8393,12 @@ sax@^1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -scheduler@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" - integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== +scheduler@^0.23.0: + version "0.23.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe" + integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw== dependencies: loose-envify "^1.1.0" - object-assign "^4.1.1" schema-utils@2.7.0: version "2.7.0" @@ -9438,24 +8418,24 @@ schema-utils@^2.6.5: ajv "^6.12.4" ajv-keywords "^3.5.2" -schema-utils@^3.0.0, schema-utils@^3.1.0, schema-utils@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" - integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== +schema-utils@^3.0.0, schema-utils@^3.1.1, schema-utils@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe" + integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== dependencies: "@types/json-schema" "^7.0.8" ajv "^6.12.5" ajv-keywords "^3.5.2" schema-utils@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.0.0.tgz#60331e9e3ae78ec5d16353c467c34b3a0a1d3df7" - integrity sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg== + version "4.2.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.2.0.tgz#70d7c93e153a273a805801882ebd3bff20d89c8b" + integrity sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw== dependencies: "@types/json-schema" "^7.0.9" - ajv "^8.8.0" + ajv "^8.9.0" ajv-formats "^2.1.1" - ajv-keywords "^5.0.0" + ajv-keywords "^5.1.0" section-matter@^1.0.0: version "1.0.0" @@ -9470,14 +8450,7 @@ select-hose@^2.0.0: resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" integrity sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg== -selfsigned@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.0.1.tgz#8b2df7fa56bf014d19b6007655fff209c0ef0a56" - integrity sha512-LmME957M1zOsUhG+67rAjKfiWFox3SBxE/yymatMZsAx+oMrJ0YQ8AToOnyCm7xbeg2ep37IHLxdu0o2MavQOQ== - dependencies: - node-forge "^1" - -selfsigned@^2.0.1, selfsigned@^2.1.1: +selfsigned@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.1.1.tgz#18a7613d714c0cd3385c48af0075abf3f266af61" integrity sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ== @@ -9499,19 +8472,19 @@ semver@7.3.5: lru-cache "^6.0.0" semver@^5.4.1: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== -semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^6.0.0, semver@^6.2.0, semver@^6.3.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8: - version "7.3.8" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" - integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== +semver@^7.3.2, semver@^7.3.4, semver@^7.3.7, semver@^7.3.8: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== dependencies: lru-cache "^6.0.0" @@ -9583,7 +8556,7 @@ set-blocking@^2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== -setimmediate@^1.0.5: +setimmediate@^1.0.4, setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== @@ -9598,6 +8571,14 @@ setprototypeof@1.2.0: resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + shallow-clone@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" @@ -9605,7 +8586,7 @@ shallow-clone@^3.0.0: dependencies: kind-of "^6.0.2" -shallowequal@1.1.0, shallowequal@^1.1.0: +shallowequal@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== @@ -9623,9 +8604,9 @@ shebang-regex@^3.0.0: integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== shell-quote@^1.7.3: - version "1.8.0" - resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.0.tgz#20d078d0eaf71d54f43bd2ba14a1b5b9bfa5c8ba" - integrity sha512-QHsz8GgQIGKlRi24yFc6a6lN69Idnx634w49ay6+jA5yFh7a1UY+4Rp6HPx/L/1zcEDPEij8cIsiqR6bQsE5VQ== + version "1.8.1" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" + integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== shelljs@^0.8.5: version "0.8.5" @@ -9680,7 +8661,7 @@ should@^13.2.1: should-type-adaptors "^1.0.1" should-util "^1.0.0" -side-channel@1.0.4, side-channel@^1.0.4: +side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== @@ -9729,11 +8710,11 @@ slash@^4.0.0: integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew== slugify@^1.6.5: - version "1.6.5" - resolved "https://registry.yarnpkg.com/slugify/-/slugify-1.6.5.tgz#c8f5c072bf2135b80703589b39a3d41451fbe8c8" - integrity sha512-8mo9bslnBO3tr5PEVFzMPIWwWnipGS0xVbYf65zxDqfNwmzYn1LpiKNrR6DlClusuvo+hDHd1zKpmfAe83NQSQ== + version "1.6.6" + resolved "https://registry.yarnpkg.com/slugify/-/slugify-1.6.6.tgz#2d4ac0eacb47add6af9e04d3be79319cbcc7924b" + integrity sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw== -sockjs@^0.3.21, sockjs@^0.3.24: +sockjs@^0.3.24: version "0.3.24" resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.24.tgz#c9bc8995f33a111bea0395ec30aa3206bdb5ccce" integrity sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ== @@ -9742,22 +8723,12 @@ sockjs@^0.3.21, sockjs@^0.3.24: uuid "^8.3.2" websocket-driver "^0.7.4" -sort-css-media-queries@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/sort-css-media-queries/-/sort-css-media-queries-2.0.4.tgz#b2badfa519cb4a938acbc6d3aaa913d4949dc908" - integrity sha512-PAIsEK/XupCQwitjv7XxoMvYhT7EAfyzI3hsy/MyDgTvc+Ft55ctdkctJLOy6cQejaIC+zjpUL4djFVm2ivOOw== - sort-css-media-queries@2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/sort-css-media-queries/-/sort-css-media-queries-2.1.0.tgz#7c85e06f79826baabb232f5560e9745d7a78c4ce" integrity sha512-IeWvo8NkNiY2vVYdPa27MCQiR0MN0M80johAYFVxWWXQ44KU84WNxjslwBHmc/7ZL2ccwkM7/e6S5aiKZXm7jA== -source-list-map@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" - integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== - -source-map-js@1.0.2, source-map-js@^1.0.2: +source-map-js@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== @@ -9775,7 +8746,7 @@ source-map@^0.5.0: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== -source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== @@ -9839,9 +8810,27 @@ statuses@2.0.1: integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== std-env@^3.0.1: - version "3.3.2" - resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.3.2.tgz#af27343b001616015534292178327b202b9ee955" - integrity sha512-uUZI65yrV2Qva5gqE0+A7uVAvO40iPo6jGhs7s8keRfHCmtg+uB2X6EiLGCI9IgL1J17xGhvoOqSz79lzICPTA== + version "3.3.3" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.3.3.tgz#a54f06eb245fdcfef53d56f3c0251f1d5c3d01fe" + integrity sha512-Rz6yejtVyWnVjC1RFvNmYL10kgjC49EOghxWn0RFqlCHGFpQx+Xe7yW3I4ceK1SGrWIGMjD5Kbue8W/udkbMJg== + +stream-browserify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f" + integrity sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA== + dependencies: + inherits "~2.0.4" + readable-stream "^3.5.0" + +stream-http@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-3.2.0.tgz#1872dfcf24cb15752677e40e5c3f9cc1926028b5" + integrity sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A== + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.4" + readable-stream "^3.6.0" + xtend "^4.0.2" string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" @@ -9861,7 +8850,7 @@ string-width@^5.0.1: emoji-regex "^9.2.2" strip-ansi "^7.0.1" -string_decoder@^1.1.1: +string_decoder@^1.1.1, string_decoder@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== @@ -9892,9 +8881,9 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: ansi-regex "^5.0.1" strip-ansi@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2" - integrity sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw== + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== dependencies: ansi-regex "^6.0.1" @@ -9926,21 +8915,13 @@ style-to-object@0.3.0, style-to-object@^0.3.0: inline-style-parser "0.1.1" style-to-object@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.4.1.tgz#53cf856f7cf7f172d72939d9679556469ba5de37" - integrity sha512-HFpbb5gr2ypci7Qw+IOhnP2zOU7e77b+rzM+wTzXzfi1PrtBCX0E7Pk4wL4iTLnhzZ+JgEGAhX81ebTg/aYjQw== + version "0.4.2" + resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.4.2.tgz#a8247057111dea8bd3b8a1a66d2d0c9cf9218a54" + integrity sha512-1JGpfPB3lo42ZX8cuPrheZbfQ6kqPPnPHlKMyeRYtfKD+0jG+QsXgXN57O/dvJlzlB2elI6dGmrPnl5VPQFPaA== dependencies: inline-style-parser "0.1.1" -stylehacks@5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.1.0.tgz#a40066490ca0caca04e96c6b02153ddc39913520" - integrity sha512-SzLmvHQTrIWfSgljkQCw2++C9+Ne91d/6Sp92I8c5uHTcy/PgeHamwITIbBW9wnFTY/3ZfSXR9HIL6Ikqmcu6Q== - dependencies: - browserslist "^4.16.6" - postcss-selector-parser "^6.0.4" - -stylehacks@^5.1.0, stylehacks@^5.1.1: +stylehacks@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.1.1.tgz#7934a34eb59d7152149fa69d6e9e56f2fc34bcc9" integrity sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw== @@ -9948,16 +8929,12 @@ stylehacks@^5.1.0, stylehacks@^5.1.1: browserslist "^4.21.4" postcss-selector-parser "^6.0.4" -stylis@^4.1.2: - version "4.1.3" - resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.1.3.tgz#fd2fbe79f5fed17c55269e16ed8da14c84d069f7" - integrity sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA== - -sucrase@^3.21.0: - version "3.29.0" - resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.29.0.tgz#3207c5bc1b980fdae1e539df3f8a8a518236da7d" - integrity sha512-bZPAuGA5SdFHuzqIhTAqt9fvNEo9rESqXIG3oiKdF8K4UmkQxC4KlNL3lVyAErXp+mPvUqZ5l13qx6TrDIGf3A== +sucrase@^3.21.0, sucrase@^3.32.0: + version "3.34.0" + resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.34.0.tgz#1e0e2d8fcf07f8b9c3569067d92fbd8690fb576f" + integrity sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw== dependencies: + "@jridgewell/gen-mapping" "^0.3.2" commander "^4.0.0" glob "7.1.6" lines-and-columns "^1.1.6" @@ -10013,7 +8990,7 @@ svg-parser@^2.0.4: resolved "https://registry.yarnpkg.com/svg-parser/-/svg-parser-2.0.4.tgz#fdc2e29e13951736140b76cb122c8ee6630eb6b5" integrity sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ== -svgo@^2.5.0, svgo@^2.7.0, svgo@^2.8.0: +svgo@^2.7.0, svgo@^2.8.0: version "2.8.0" resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24" integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg== @@ -10049,33 +9026,32 @@ swc-loader@^0.2.3: integrity sha512-D1p6XXURfSPleZZA/Lipb3A8pZ17fP4NObZvFCDjK/OKljroqDpPmsBdTraWhVBqUNpcWBQY1imWdoPScRlQ7A== tailwindcss@^3.2.4: - version "3.2.7" - resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.2.7.tgz#5936dd08c250b05180f0944500c01dce19188c07" - integrity sha512-B6DLqJzc21x7wntlH/GsZwEXTBttVSl1FtCzC8WP4oBc/NKef7kaax5jeihkkCEWc831/5NDJ9gRNDK6NEioQQ== + version "3.3.3" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.3.tgz#90da807393a2859189e48e9e7000e6880a736daf" + integrity sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w== dependencies: + "@alloc/quick-lru" "^5.2.0" arg "^5.0.2" chokidar "^3.5.3" - color-name "^1.1.4" - detective "^5.2.1" didyoumean "^1.2.2" dlv "^1.1.3" fast-glob "^3.2.12" glob-parent "^6.0.2" is-glob "^4.0.3" - lilconfig "^2.0.6" + jiti "^1.18.2" + lilconfig "^2.1.0" micromatch "^4.0.5" normalize-path "^3.0.0" object-hash "^3.0.0" picocolors "^1.0.0" - postcss "^8.0.9" - postcss-import "^14.1.0" - postcss-js "^4.0.0" - postcss-load-config "^3.1.4" - postcss-nested "6.0.0" + postcss "^8.4.23" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.1" + postcss-nested "^6.0.1" postcss-selector-parser "^6.0.11" - postcss-value-parser "^4.2.0" - quick-lru "^5.1.1" - resolve "^1.22.1" + resolve "^1.22.2" + sucrase "^3.32.0" tapable@^1.0.0: version "1.1.3" @@ -10087,35 +9063,24 @@ tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0: resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== -terser-webpack-plugin@5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz#0320dcc270ad5372c1e8993fabbd927929773e54" - integrity sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g== - dependencies: - jest-worker "^27.4.5" - schema-utils "^3.1.1" - serialize-javascript "^6.0.0" - source-map "^0.6.1" - terser "^5.7.2" - -terser-webpack-plugin@^5.1.3, terser-webpack-plugin@^5.3.3: - version "5.3.7" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz#ef760632d24991760f339fe9290deb936ad1ffc7" - integrity sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw== +terser-webpack-plugin@^5.3.3, terser-webpack-plugin@^5.3.7: + version "5.3.9" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz#832536999c51b46d468067f9e37662a3b96adfe1" + integrity sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA== dependencies: "@jridgewell/trace-mapping" "^0.3.17" jest-worker "^27.4.5" schema-utils "^3.1.1" serialize-javascript "^6.0.1" - terser "^5.16.5" + terser "^5.16.8" -terser@^5.10.0, terser@^5.16.5, terser@^5.7.2: - version "5.16.6" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.16.6.tgz#f6c7a14a378ee0630fbe3ac8d1f41b4681109533" - integrity sha512-IBZ+ZQIA9sMaXmRZCUMDjNH0D5AQQfdn4WUjHL0+1lF4TP1IHRJbrhb6fNaXWikrYQTSkb7SLxkeXAiy1p7mbg== +terser@^5.10.0, terser@^5.16.8: + version "5.19.2" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.19.2.tgz#bdb8017a9a4a8de4663a7983f45c506534f9234e" + integrity sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA== dependencies: - "@jridgewell/source-map" "^0.3.2" - acorn "^8.5.0" + "@jridgewell/source-map" "^0.3.3" + acorn "^8.8.2" commander "^2.20.0" source-map-support "~0.5.20" @@ -10143,6 +9108,13 @@ thunky@^1.0.2: resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== +timers-browserify@^2.0.12: + version "2.0.12" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.12.tgz#44a45c11fbf407f34f97bccd1577c652361b00ee" + integrity sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ== + dependencies: + setimmediate "^1.0.4" + tiny-invariant@^1.0.2: version "1.3.1" resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.1.tgz#8560808c916ef02ecfd55e66090df23a4b7aa642" @@ -10215,32 +9187,27 @@ trough@^2.0.0: resolved "https://registry.yarnpkg.com/trough/-/trough-2.1.0.tgz#0f7b511a4fde65a46f18477ab38849b22c554876" integrity sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g== -ts-dedent@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.2.0.tgz#39e4bd297cd036292ae2394eb3412be63f563bb5" - integrity sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ== - ts-interface-checker@^0.1.9: version "0.1.13" resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" - integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== + version "2.6.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.1.tgz#fd8c9a0ff42590b25703c0acb3de3d3f4ede0410" + integrity sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig== -type-fest@2.12.2: - version "2.12.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.12.2.tgz#80a53614e6b9b475eb9077472fb7498dc7aa51d0" - integrity sha512-qt6ylCGpLjZ7AaODxbpyBZSs9fCI9SkL3Z9q2oxMBQhs/uyY+VD8jHA8ULCGmWQJlBgqvO3EJeAngOHD8zQCrQ== +tty-browserify@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811" + integrity sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw== type-fest@^0.20.2: version "0.20.2" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== -type-fest@^2.5.0: +type-fest@^2.14.0, type-fest@^2.5.0: version "2.19.0" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== @@ -10260,10 +9227,10 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" -ua-parser-js@^0.7.30: - version "0.7.34" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.34.tgz#afb439e2e3e394bdc90080acb661a39c685b67d7" - integrity sha512-cJMeh/eOILyGu0ejgTKB95yKT3zOenSe9UGE3vj6WfiOwgGYnmATUsnDixMFvdU+rNMvWih83hrUP8VwhF9yXQ== +ua-parser-js@^1.0.35: + version "1.0.35" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-1.0.35.tgz#c4ef44343bc3db0a3cbefdf21822f1b1fc1ab011" + integrity sha512-fKnGuqmTBnIE+/KXSzCn4db8RTigUzw1AN0DmdU6hJovUTbYJKyqj+8Mt1c4VfRDnOVJnENmfYkIPZ946UrSAA== unherit@^1.0.4: version "1.1.3" @@ -10451,10 +9418,10 @@ unpipe@1.0.0, unpipe@~1.0.0: resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== -update-browserslist-db@^1.0.10: - version "1.0.10" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3" - integrity sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ== +update-browserslist-db@^1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" + integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA== dependencies: escalade "^3.1.1" picocolors "^1.0.0" @@ -10508,12 +9475,12 @@ url-template@^3.0.0: integrity sha512-vB/eHWttzhN+NZzk9FcQB2h1cSEgb7zDYyvyxPhw02LYw7YqIzO+w1AqkcKvZ51gPH8o4+nyiWve/xuQqMdJZw== url@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" - integrity sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ== + version "0.11.1" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.1.tgz#26f90f615427eca1b9f4d6a28288c147e2302a32" + integrity sha512-rWS3H04/+mzzJkv0eZ7vEDGiQbgquI1fGfOad6zKvgYQi1SzMmhl7c/DdRGxhaWrVH6z0qWITo8rpnxK/RfEhA== dependencies: - punycode "1.3.2" - querystring "0.2.0" + punycode "^1.4.1" + qs "^6.11.0" use-composed-ref@^1.3.0: version "1.3.0" @@ -10549,6 +9516,17 @@ util@^0.10.3: dependencies: inherits "2.0.3" +util@^0.12.0, util@^0.12.4: + version "0.12.5" + resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc" + integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA== + dependencies: + inherits "^2.0.3" + is-arguments "^1.0.4" + is-generator-function "^1.0.7" + is-typed-array "^1.1.3" + which-typed-array "^1.1.2" + utila@~0.4: version "0.4.0" resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" @@ -10569,11 +9547,6 @@ uuid@8.3.2, uuid@^8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -uuid@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" - integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== - uvu@^0.5.0: version "0.5.6" resolved "https://registry.yarnpkg.com/uvu/-/uvu-0.5.6.tgz#2754ca20bcb0bb59b64e9985e84d2e81058502df" @@ -10584,6 +9557,14 @@ uvu@^0.5.0: kleur "^4.0.3" sade "^1.7.3" +validate-peer-dependencies@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/validate-peer-dependencies/-/validate-peer-dependencies-2.2.0.tgz#47b8ff008f66a66fc5d8699123844522c1d874f4" + integrity sha512-8X1OWlERjiUY6P6tdeU9E0EwO8RA3bahoOVG7ulOZT5MqgNDUO/BQoVjYiHPcNe+v8glsboZRIw9iToMAA2zAA== + dependencies: + resolve-package-path "^4.0.3" + semver "^7.3.8" + validate.io-array@^1.0.3: version "1.0.6" resolved "https://registry.yarnpkg.com/validate.io-array/-/validate.io-array-1.0.6.tgz#5b5a2cafd8f8b85abb2f886ba153f2d93a27774d" @@ -10673,6 +9654,11 @@ vfile@^5.0.0: unist-util-stringify-position "^3.0.0" vfile-message "^3.0.0" +vm-browserify@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" + integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== + wait-on@6.0.1, wait-on@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-6.0.1.tgz#16bbc4d1e4ebdd41c5b4e63a2e16dbd1f4e5601e" @@ -10716,35 +9702,15 @@ web-namespaces@^2.0.0: resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-2.0.1.tgz#1010ff7c650eccb2592cebeeaf9a1b253fd40692" integrity sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ== -web-worker@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/web-worker/-/web-worker-1.2.0.tgz#5d85a04a7fbc1e7db58f66595d7a3ac7c9c180da" - integrity sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA== - webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== -webpack-bundle-analyzer@4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.5.0.tgz#1b0eea2947e73528754a6f9af3e91b2b6e0f79d5" - integrity sha512-GUMZlM3SKwS8Z+CKeIFx7CVoHn3dXFcUAjT/dcZQQmfSZGvitPfMob2ipjai7ovFFqPvTqkEZ/leL4O0YOdAYQ== - dependencies: - acorn "^8.0.4" - acorn-walk "^8.0.0" - chalk "^4.1.0" - commander "^7.2.0" - gzip-size "^6.0.0" - lodash "^4.17.20" - opener "^1.5.2" - sirv "^1.0.7" - ws "^7.3.1" - webpack-bundle-analyzer@^4.5.0: - version "4.8.0" - resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.8.0.tgz#951b8aaf491f665d2ae325d8b84da229157b1d04" - integrity sha512-ZzoSBePshOKhr+hd8u6oCkZVwpVaXgpw23ScGLFpR6SjYI7+7iIWYarjN6OEYOfRt8o7ZyZZQk0DuMizJ+LEIg== + version "4.9.0" + resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.9.0.tgz#fc093c4ab174fd3dcbd1c30b763f56d10141209d" + integrity sha512-+bXGmO1LyiNx0i9enBu3H8mv42sj/BJWhZNFwjz92tVnBa9J3JMGo2an2IXlEleoDOPn/Hofl5hr/xCpObUDtw== dependencies: "@discoveryjs/json-ext" "0.5.7" acorn "^8.0.4" @@ -10757,17 +9723,6 @@ webpack-bundle-analyzer@^4.5.0: sirv "^1.0.7" ws "^7.3.1" -webpack-dev-middleware@5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.1.tgz#aa079a8dedd7e58bfeab358a9af7dab304cee57f" - integrity sha512-81EujCKkyles2wphtdrnPg/QqegC/AtqNH//mQkBYSMqwFVCQrxM6ktB2O/SPlZy7LqeEfTbV3cZARGQz6umhg== - dependencies: - colorette "^2.0.10" - memfs "^3.4.1" - mime-types "^2.1.31" - range-parser "^1.2.1" - schema-utils "^4.0.0" - webpack-dev-middleware@^5.3.1: version "5.3.3" resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz#efae67c2793908e7311f1d9b06f2a08dcc97e51f" @@ -10779,44 +9734,10 @@ webpack-dev-middleware@^5.3.1: range-parser "^1.2.1" schema-utils "^4.0.0" -webpack-dev-server@4.9.0: - version "4.9.0" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.9.0.tgz#737dbf44335bb8bde68f8f39127fc401c97a1557" - integrity sha512-+Nlb39iQSOSsFv0lWUuUTim3jDQO8nhK3E68f//J2r5rIcp4lULHXz2oZ0UVdEeWXEh5lSzYUlzarZhDAeAVQw== - dependencies: - "@types/bonjour" "^3.5.9" - "@types/connect-history-api-fallback" "^1.3.5" - "@types/express" "^4.17.13" - "@types/serve-index" "^1.9.1" - "@types/sockjs" "^0.3.33" - "@types/ws" "^8.5.1" - ansi-html-community "^0.0.8" - bonjour-service "^1.0.11" - chokidar "^3.5.3" - colorette "^2.0.10" - compression "^1.7.4" - connect-history-api-fallback "^1.6.0" - default-gateway "^6.0.3" - express "^4.17.3" - graceful-fs "^4.2.6" - html-entities "^2.3.2" - http-proxy-middleware "^2.0.3" - ipaddr.js "^2.0.1" - open "^8.0.9" - p-retry "^4.5.0" - rimraf "^3.0.2" - schema-utils "^4.0.0" - selfsigned "^2.0.1" - serve-index "^1.9.1" - sockjs "^0.3.21" - spdy "^4.0.2" - webpack-dev-middleware "^5.3.1" - ws "^8.4.2" - webpack-dev-server@^4.9.3: - version "4.12.0" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.12.0.tgz#e2dcad4d43e486c3bac48ddbf346e77ef03c7428" - integrity sha512-XRN9YRnvOj3TQQ5w/0pR1y1xDcVnbWtNkTri46kuEbaWUPTHsWUvOyAAI7PZHLY+hsFki2kRltJjKMw7e+IiqA== + version "4.15.1" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz#8944b29c12760b3a45bdaa70799b17cb91b03df7" + integrity sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA== dependencies: "@types/bonjour" "^3.5.9" "@types/connect-history-api-fallback" "^1.3.5" @@ -10824,7 +9745,7 @@ webpack-dev-server@^4.9.3: "@types/serve-index" "^1.9.1" "@types/serve-static" "^1.13.10" "@types/sockjs" "^0.3.33" - "@types/ws" "^8.5.1" + "@types/ws" "^8.5.5" ansi-html-community "^0.0.8" bonjour-service "^1.0.11" chokidar "^3.5.3" @@ -10850,42 +9771,34 @@ webpack-dev-server@^4.9.3: ws "^8.13.0" webpack-merge@^5.8.0: - version "5.8.0" - resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.8.0.tgz#2b39dbf22af87776ad744c390223731d30a68f61" - integrity sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q== + version "5.9.0" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.9.0.tgz#dc160a1c4cf512ceca515cc231669e9ddb133826" + integrity sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg== dependencies: clone-deep "^4.0.1" wildcard "^2.0.0" -webpack-sources@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" - integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== - dependencies: - source-list-map "^2.0.0" - source-map "~0.6.1" - webpack-sources@^3.2.2, webpack-sources@^3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== webpack@^5.61.0, webpack@^5.73.0: - version "5.76.2" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.76.2.tgz#6f80d1c1d1e3bf704db571b2504a0461fac80230" - integrity sha512-Th05ggRm23rVzEOlX8y67NkYCHa9nTNcwHPBhdg+lKG+mtiW7XgggjAeeLnADAe7mLjJ6LUNfgHAuRRh+Z6J7w== + version "5.88.2" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.88.2.tgz#f62b4b842f1c6ff580f3fcb2ed4f0b579f4c210e" + integrity sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ== dependencies: "@types/eslint-scope" "^3.7.3" - "@types/estree" "^0.0.51" - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/wasm-edit" "1.11.1" - "@webassemblyjs/wasm-parser" "1.11.1" + "@types/estree" "^1.0.0" + "@webassemblyjs/ast" "^1.11.5" + "@webassemblyjs/wasm-edit" "^1.11.5" + "@webassemblyjs/wasm-parser" "^1.11.5" acorn "^8.7.1" - acorn-import-assertions "^1.7.6" + acorn-import-assertions "^1.9.0" browserslist "^4.14.5" chrome-trace-event "^1.0.2" - enhanced-resolve "^5.10.0" - es-module-lexer "^0.9.0" + enhanced-resolve "^5.15.0" + es-module-lexer "^1.2.1" eslint-scope "5.1.1" events "^3.2.0" glob-to-regexp "^0.4.1" @@ -10894,9 +9807,9 @@ webpack@^5.61.0, webpack@^5.73.0: loader-runner "^4.2.0" mime-types "^2.1.27" neo-async "^2.6.2" - schema-utils "^3.1.0" + schema-utils "^3.2.0" tapable "^2.1.1" - terser-webpack-plugin "^5.1.3" + terser-webpack-plugin "^5.3.7" watchpack "^2.4.0" webpack-sources "^3.2.3" @@ -10933,9 +9846,20 @@ whatwg-url@^5.0.0: webidl-conversions "^3.0.0" which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q== + version "2.0.1" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" + integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== + +which-typed-array@^1.1.11, which-typed-array@^1.1.2: + version "1.1.11" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.11.tgz#99d691f23c72aab6768680805a271b69761ed61a" + integrity sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" which@^1.3.1: version "1.3.1" @@ -10951,13 +9875,6 @@ which@^2.0.1: dependencies: isexe "^2.0.0" -widest-line@4.0.1, widest-line@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-4.0.1.tgz#a0fc673aaba1ea6f0a0d35b3c2795c9a9cc2ebf2" - integrity sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig== - dependencies: - string-width "^5.0.1" - widest-line@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" @@ -10965,19 +9882,17 @@ widest-line@^3.1.0: dependencies: string-width "^4.0.0" -wildcard@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec" - integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw== - -wrap-ansi@8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.0.1.tgz#2101e861777fec527d0ea90c57c6b03aac56a5b3" - integrity sha512-QFF+ufAqhoYHvoHdajT/Po7KoXVBPXS2bgjIam5isfWJPfIOnQZ50JtUiVvCv/sjgacf3yRrt2ZKUZ/V4itN4g== +widest-line@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-4.0.1.tgz#a0fc673aaba1ea6f0a0d35b3c2795c9a9cc2ebf2" + integrity sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig== dependencies: - ansi-styles "^6.1.0" string-width "^5.0.1" - strip-ansi "^7.0.1" + +wildcard@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67" + integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ== wrap-ansi@^6.2.0: version "6.2.0" @@ -11026,7 +9941,7 @@ ws@^7.3.1: resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== -ws@^8.13.0, ws@^8.4.2: +ws@^8.13.0: version "8.13.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA== @@ -11090,7 +10005,7 @@ yaml@1.10.2, yaml@^1.10.0, yaml@^1.10.2, yaml@^1.7.2: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== -yaml@2.3.1: +yaml@^2.1.1: version "2.3.1" resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.1.tgz#02fe0975d23cd441242aa7204e09fc28ac2ac33b" integrity sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ== @@ -11126,9 +10041,9 @@ yargs@^15.3.1: yargs-parser "^18.1.2" yargs@^17.0.1: - version "17.7.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.1.tgz#34a77645201d1a8fc5213ace787c220eabbd0967" - integrity sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw== + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== dependencies: cliui "^8.0.1" escalade "^3.1.1" From faf547f0909db907cb620d2d548bad13aa79d6d3 Mon Sep 17 00:00:00 2001 From: mffap Date: Sat, 12 Aug 2023 14:29:37 +0200 Subject: [PATCH 24/38] docs(guide): cloudflare zero trust (#6345) --- .../integrate/application/_application.mdx | 1 - .../integrate/application/_generate-key.mdx | 1 + .../integrate/services/cloudflare-oidc.mdx | 54 ++++++++++++++++++ docs/sidebars.js | 1 + .../services/user-info-inside-id-token.png | Bin 0 -> 224996 bytes 5 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 docs/docs/guides/integrate/services/cloudflare-oidc.mdx create mode 100644 docs/static/img/guides/integrate/services/user-info-inside-id-token.png diff --git a/docs/docs/guides/integrate/application/_application.mdx b/docs/docs/guides/integrate/application/_application.mdx index ff04926293..969cbeb417 100644 --- a/docs/docs/guides/integrate/application/_application.mdx +++ b/docs/docs/guides/integrate/application/_application.mdx @@ -39,7 +39,6 @@ export default function CreateApp(props) { />

Review your configuration

-

Create key for private key JWT

); diff --git a/docs/docs/guides/integrate/application/_generate-key.mdx b/docs/docs/guides/integrate/application/_generate-key.mdx index 947d05346d..7287134885 100644 --- a/docs/docs/guides/integrate/application/_generate-key.mdx +++ b/docs/docs/guides/integrate/application/_generate-key.mdx @@ -3,6 +3,7 @@ import ThemedImage from "@theme/ThemedImage"; export default function GenerateKey(props) { return props.appType == "api" || props.authType == "jwt" ? (
+

Create key for private key JWT

After you successfully created your application with authentication type JWT your can create keys in the Configuration section and Keys Card of diff --git a/docs/docs/guides/integrate/services/cloudflare-oidc.mdx b/docs/docs/guides/integrate/services/cloudflare-oidc.mdx new file mode 100644 index 0000000000..16fcf638f0 --- /dev/null +++ b/docs/docs/guides/integrate/services/cloudflare-oidc.mdx @@ -0,0 +1,54 @@ +--- +title: Configure as OIDC Identity Provider for Cloudflare Zero Trust +sidebar_label: Cloudflare Zero Trust +--- + +import CreateApp from "../application/_application.mdx"; + +This guide shows how to configure ZITADEL as OpenID Connect identity provider for Cloudflare Zero Trust. + +Prerequisites: + +- Existing ZITADEL instance, organization, and project. Follow our [get started](/guides/start/quickstart) guide to get started. If not present follow [this guide](/guides/start/quickstart) +- Existing Cloudflare account and [team domain](https://developers.cloudflare.com/cloudflare-one/glossary/#team-domain) + +## Create the client in ZITADEL + + + +## Send user info in tokens + +Make sure to enable "User Info inside ID Token" on your application settings. + +![user info inside id token](/img/guides/integrate/services/user-info-inside-id-token.png) + +:::info +Cloudflare will return an error "User email was not returned. API permissions are likely incorrect". Enable to send the user information inside the token on your client settings. +::: + +## Configure Cloudflare Zero Trust Authentication + +1. On the Cloudflare dashboard go to Zero Trust, click settings, and then select "Authentication" +2. Add a new login method with the type "OpenID Connect" +3. Fill in the required information. Check the discovery endpoint of your instance (https://{your_domain}/.well-known/openid-configuration) for the urls. As mentioned in the Cloudflare docs the Certificate Url is jwks_uri. +4. Disable PKCE (Cloudflare requires a client secret for PKCE, which is currently not supported) +5. Add the following claims: "openid", "profile", "email" +6. Test the connection + +### Example configuration + +```json +{ + "config": { + "client_id": "", + "client_secret": "", + "auth_url": "https://{your_domain}.zitadel.cloud/oauth/v2/authorize", + "token_url": "https://{your_domain}.zitadel.cloud/oauth/v2/token", + "certs_url": "https://{your_domain}.zitadel.cloud/oauth/v2/keys", + "scopes": ["openid", "email", "profile"], + "pkce_enabled": false, + }, + "type": "oidc", + "name": "Generic Google" +} +``` \ No newline at end of file diff --git a/docs/sidebars.js b/docs/sidebars.js index 6c66b5f8e0..571da0de6d 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -276,6 +276,7 @@ module.exports = { collapsed: true, items: [ "guides/integrate/services/gitlab-self-hosted", + "guides/integrate/services/cloudflare-oidc", "guides/integrate/services/aws-saml", "guides/integrate/services/google-cloud", "guides/integrate/services/atlassian-saml", diff --git a/docs/static/img/guides/integrate/services/user-info-inside-id-token.png b/docs/static/img/guides/integrate/services/user-info-inside-id-token.png new file mode 100644 index 0000000000000000000000000000000000000000..5d407ffc0c80886d5a3496410b5847939baa1d37 GIT binary patch literal 224996 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

UbQJ5-e3Ob!OdZF=(Jjdg%?}qU;iHBLqG51 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%0DpjOw=kggj2(PRCQ8*$xB9E<;hdt!RZk-jfW1 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≦J_!re(zYJTvp0BVl0PXNN{IiK#~>FE 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

(kG@%|klxgPtHU-ahRn|{~` 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 Date: Sat, 12 Aug 2023 16:37:42 +0300 Subject: [PATCH 25/38] feat: get multiple users by id (#6210) * feat: introduce InTextQuery, and the ability to get multiple users by id * added in query tests * remove append call * fix lints --- internal/api/grpc/user/query.go | 6 ++ internal/query/search_query.go | 29 ++++++- internal/query/search_query_test.go | 115 ++++++++++++++++++++++++++++ internal/query/user.go | 4 + proto/zitadel/user.proto | 10 +++ 5 files changed, 163 insertions(+), 1 deletion(-) diff --git a/internal/api/grpc/user/query.go b/internal/api/grpc/user/query.go index 81fc738e90..af06c4660d 100644 --- a/internal/api/grpc/user/query.go +++ b/internal/api/grpc/user/query.go @@ -40,6 +40,8 @@ func UserQueryToQuery(query *user_pb.SearchQuery) (query.SearchQuery, error) { return LoginNameQueryToQuery(q.LoginNameQuery) case *user_pb.SearchQuery_ResourceOwner: return ResourceOwnerQueryToQuery(q.ResourceOwner) + case *user_pb.SearchQuery_InUserIdsQuery: + return InUserIdsQueryToQuery(q.InUserIdsQuery) default: return nil, errors.ThrowInvalidArgument(nil, "GRPC-vR9nC", "List.Query.Invalid") } @@ -84,3 +86,7 @@ func LoginNameQueryToQuery(q *user_pb.LoginNameQuery) (query.SearchQuery, error) func ResourceOwnerQueryToQuery(q *user_pb.ResourceOwnerQuery) (query.SearchQuery, error) { return query.NewUserResourceOwnerSearchQuery(q.OrgID, query.TextEquals) } + +func InUserIdsQueryToQuery(q *user_pb.InUserIDQuery) (query.SearchQuery, error) { + return query.NewUserInUserIdsSearchQuery(q.UserIds) +} diff --git a/internal/query/search_query.go b/internal/query/search_query.go index 16d37502d2..63dd6739fc 100644 --- a/internal/query/search_query.go +++ b/internal/query/search_query.go @@ -156,6 +156,10 @@ const ( columnCompareMax ) +type InTextQuery struct { + Column Column + Values []string +} type TextQuery struct { Column Column Text string @@ -167,8 +171,22 @@ var ( ErrInvalidCompare = errors.New("invalid compare") ErrMissingColumn = errors.New("missing column") ErrInvalidNumber = errors.New("value is no number") + ErrEmptyValues = errors.New("values array must not be empty") ) +func NewInTextQuery(col Column, values []string) (*InTextQuery, error) { + if len(values) == 0 { + return nil, ErrEmptyValues + } + if col.isZero() { + return nil, ErrMissingColumn + } + return &InTextQuery{ + Column: col, + Values: values, + }, nil +} + func NewTextQuery(col Column, value string, compare TextComparison) (*TextQuery, error) { if compare < 0 || compare >= textCompareMax { return nil, ErrInvalidCompare @@ -183,6 +201,15 @@ func NewTextQuery(col Column, value string, compare TextComparison) (*TextQuery, }, nil } +func (q *InTextQuery) toQuery(query sq.SelectBuilder) sq.SelectBuilder { + return query.Where(q.comp()) +} + +func (s *InTextQuery) comp() sq.Sqlizer { + // This translates to an IN query + return sq.Eq{s.Column.identifier(): s.Values} +} + func (q *TextQuery) toQuery(query sq.SelectBuilder) sq.SelectBuilder { return query.Where(q.comp()) } @@ -269,7 +296,7 @@ func NewNumberQuery(c Column, value interface{}, compare NumberComparison) (*Num } switch reflect.TypeOf(value).Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64: - //everything fine + // everything fine default: return nil, ErrInvalidNumber } diff --git a/internal/query/search_query_test.go b/internal/query/search_query_test.go index db74c7c048..5316565653 100644 --- a/internal/query/search_query_test.go +++ b/internal/query/search_query_test.go @@ -1382,3 +1382,118 @@ func TestNumberComparisonFromMethod(t *testing.T) { }) } } + +func TestNewInTextQuery(t *testing.T) { + type args struct { + column Column + value []string + } + tests := []struct { + name string + args args + want *InTextQuery + wantErr func(error) bool + }{ + { + name: "empty values", + args: args{ + column: testCol, + value: []string{}, + }, + wantErr: func(err error) bool { + return errors.Is(err, ErrEmptyValues) + }, + }, + { + name: "no column", + args: args{ + column: Column{}, + value: []string{"adler", "hurst"}, + }, + wantErr: func(err error) bool { + return errors.Is(err, ErrMissingColumn) + }, + }, + { + name: "no column name", + args: args{ + column: testNoCol, + value: []string{"adler", "hurst"}, + }, + wantErr: func(err error) bool { + return errors.Is(err, ErrMissingColumn) + }, + }, + { + name: "correct", + args: args{ + column: testCol, + value: []string{"adler", "hurst"}, + }, + want: &InTextQuery{ + Column: testCol, + Values: []string{"adler", "hurst"}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := NewInTextQuery(tt.args.column, tt.args.value) + if err != nil && tt.wantErr == nil { + t.Errorf("NewTextQuery() no error expected got %v", err) + return + } else if tt.wantErr != nil && !tt.wantErr(err) { + t.Errorf("NewTextQuery() unexpeted error = %v", err) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("NewTextQuery() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestInTextQuery_comp(t *testing.T) { + type fields struct { + Column Column + Values []string + } + type want struct { + query interface{} + isNil bool + } + tests := []struct { + name string + fields fields + want want + }{ + { + name: "equals", + fields: fields{ + Column: testCol, + Values: []string{"Adler", "Hurst"}, + }, + want: want{ + query: sq.Eq{"test_table.test_col": []string{"Adler", "Hurst"}}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &InTextQuery{ + Column: tt.fields.Column, + Values: tt.fields.Values, + } + query := s.comp() + if query == nil && tt.want.isNil { + return + } else if tt.want.isNil && query != nil { + t.Error("query should not be nil") + } + + if !reflect.DeepEqual(query, tt.want.query) { + t.Errorf("wrong query: want: %v, (%T), got: %v, (%T)", tt.want.query, tt.want.query, query, query) + } + }) + } +} diff --git a/internal/query/user.go b/internal/query/user.go index 46a683e677..c335129ed0 100644 --- a/internal/query/user.go +++ b/internal/query/user.go @@ -605,6 +605,10 @@ func (r *UserSearchQueries) AppendMyResourceOwnerQuery(orgID string) error { return nil } +func NewUserInUserIdsSearchQuery(values []string) (SearchQuery, error) { + return NewInTextQuery(UserIDCol, values) +} + func NewUserResourceOwnerSearchQuery(value string, comparison TextComparison) (SearchQuery, error) { return NewTextQuery(UserResourceOwnerCol, value, comparison) } diff --git a/proto/zitadel/user.proto b/proto/zitadel/user.proto index bbe4f0be52..493db3acaf 100644 --- a/proto/zitadel/user.proto +++ b/proto/zitadel/user.proto @@ -184,9 +184,19 @@ message SearchQuery { StateQuery state_query = 7; TypeQuery type_query = 8; LoginNameQuery login_name_query = 9; + InUserIDQuery in_user_ids_query = 10; } } +message InUserIDQuery { + repeated string user_ids = 1 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "the ids of the users to include" + example: "[\"69629023906488334\",\"69622366012355662\"]"; + } + ]; +} + message UserNameQuery { string user_name = 1 [ (validate.rules).string = {max_len: 200}, From c5c773531c0c60bb85fda8e5ae8ed0f301be51d7 Mon Sep 17 00:00:00 2001 From: Fabian Haenel Date: Mon, 14 Aug 2023 15:51:33 +0200 Subject: [PATCH 26/38] fix: Improve and sync checkSSL functions for CockroachDB and PostgreSQL (#6271) * Improve and sync checkSSL functions for cockroach and postgres * Add missing prefer mode * Fix missing return in postgres checkSSL on disable --- internal/database/cockroach/config.go | 8 ++++++++ internal/database/postgres/config.go | 16 ++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/internal/database/cockroach/config.go b/internal/database/cockroach/config.go index 841787b9fd..f48f026e24 100644 --- a/internal/database/cockroach/config.go +++ b/internal/database/cockroach/config.go @@ -15,6 +15,9 @@ import ( const ( sslDisabledMode = "disable" + sslRequireMode = "require" + sslAllowMode = "allow" + sslPreferMode = "prefer" ) type Config struct { @@ -121,6 +124,11 @@ func (c *Config) checkSSL(user User) { user.SSL = SSL{Mode: sslDisabledMode} return } + + if user.SSL.Mode == sslRequireMode || user.SSL.Mode == sslAllowMode || user.SSL.Mode == sslPreferMode { + return + } + if user.SSL.RootCert == "" { logging.WithFields( "cert set", user.SSL.Cert != "", diff --git a/internal/database/postgres/config.go b/internal/database/postgres/config.go index a567f8bc36..5521891685 100644 --- a/internal/database/postgres/config.go +++ b/internal/database/postgres/config.go @@ -13,6 +13,9 @@ import ( const ( sslDisabledMode = "disable" + sslRequireMode = "require" + sslAllowMode = "allow" + sslPreferMode = "prefer" ) type Config struct { @@ -113,6 +116,19 @@ type SSL struct { func (s *Config) checkSSL(user User) { if user.SSL.Mode == sslDisabledMode || user.SSL.Mode == "" { user.SSL = SSL{Mode: sslDisabledMode} + return + } + + if user.SSL.Mode == sslRequireMode || user.SSL.Mode == sslAllowMode || user.SSL.Mode == sslPreferMode { + return + } + + if user.SSL.RootCert == "" { + logging.WithFields( + "cert set", user.SSL.Cert != "", + "key set", user.SSL.Key != "", + "rootCert set", user.SSL.RootCert != "", + ).Fatal("at least ssl root cert has to be set") } } From cc4499ec2d8038383f082d13521c8c0bda689fe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20M=C3=B6hlmann?= Date: Mon, 14 Aug 2023 21:16:20 +0300 Subject: [PATCH 27/38] fix(make): add buf command to core_grpc_dependencies (#6319) --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index f6ecc754bf..ec88b80a0b 100644 --- a/Makefile +++ b/Makefile @@ -49,6 +49,7 @@ core_grpc_dependencies: go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@v2.15.2 go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@v2.15.2 go install github.com/envoyproxy/protoc-gen-validate@v0.10.1 + go install github.com/bufbuild/buf/cmd/buf@v1.25.1 .PHONY: core_api core_api: core_api_generator core_grpc_dependencies From 895335321099fd4c7502959068dadca7ab9102a2 Mon Sep 17 00:00:00 2001 From: Florian Forster Date: Tue, 15 Aug 2023 10:49:05 +0200 Subject: [PATCH 28/38] chore: initial version of a devcontainer (#6352) * chore: initial version of a devcontainer * test * add make --- .devcontainer/devcontainer.json | 24 ++++++++++++++++++++++++ .devcontainer/docker-compose.yml | 22 ++++++++++++++++++++++ .gitignore | 1 + internal/notification/statik/generate.go | 2 +- internal/statik/generate.go | 2 +- 5 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 .devcontainer/devcontainer.json create mode 100644 .devcontainer/docker-compose.yml diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000000..b5c16134db --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,24 @@ +{ + "name": "zitadel", + "dockerComposeFile": "docker-compose.yml", + "service": "devcontainer", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + "features": { + "ghcr.io/devcontainers/features/go:1": { + "version": "1.20" + }, + "ghcr.io/devcontainers/features/node:1": { + "version": "18" + }, + "ghcr.io/guiyomh/features/golangci-lint:0": {}, + "ghcr.io/devcontainers/features/docker-outside-of-docker:1": {}, + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/jungaretti/features/make:1": {} + }, + "forwardPorts": [ + 3000, + 4200, + 8080 + ], + "onCreateCommand": "npm install -g sass@1.64.1" +} \ No newline at end of file diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml new file mode 100644 index 0000000000..c7f273a49e --- /dev/null +++ b/.devcontainer/docker-compose.yml @@ -0,0 +1,22 @@ +version: '3.8' +services: + devcontainer: + image: mcr.microsoft.com/devcontainers/base:ubuntu + volumes: + - ../..:/workspaces:cached + - /var/run/docker.sock:/var/run/docker.sock + network_mode: service:db + command: sleep infinity + + db: + image: postgres:latest + restart: unless-stopped + volumes: + - postgres-data:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + POSTGRES_USER: postgres + POSTGRES_DB: postgres + +volumes: + postgres-data: diff --git a/.gitignore b/.gitignore index db17a6ead4..f93505b4b8 100644 --- a/.gitignore +++ b/.gitignore @@ -73,6 +73,7 @@ migrations/cockroach/migrate_cloud.go /.artifacts/* !/.artifacts/zitadel /zitadel +node_modules/ go.work go.work.sum diff --git a/internal/notification/statik/generate.go b/internal/notification/statik/generate.go index 0f9e4ac17a..f840619a94 100644 --- a/internal/notification/statik/generate.go +++ b/internal/notification/statik/generate.go @@ -1,3 +1,3 @@ package statik -//go:generate statik -src=../static -dest=.. -ns=notification +//go:generate statik -f -src=../static -dest=.. -ns=notification diff --git a/internal/statik/generate.go b/internal/statik/generate.go index 96148570c4..e407630ae6 100644 --- a/internal/statik/generate.go +++ b/internal/statik/generate.go @@ -1,3 +1,3 @@ package statik -//go:generate statik -src=../static -dest=.. -ns=zitadel +//go:generate statik -f -src=../static -dest=.. -ns=zitadel From 0017542aa2d0d43886a90e461cd4b6d192cecc72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20M=C3=B6hlmann?= Date: Tue, 15 Aug 2023 12:50:42 +0300 Subject: [PATCH 29/38] feat(api/v2): implement TOTP session check (#6362) * feat(api/v2): implement TOTP session check * add integration test * correct typo in projection test * fix event type typos --------- Co-authored-by: Livio Spring --- internal/api/grpc/session/v2/session.go | 14 +- .../session/v2/session_integration_test.go | 62 ++++++-- internal/api/grpc/session/v2/session_test.go | 39 +++++ internal/command/session.go | 29 ++++ internal/command/session_model.go | 19 ++- internal/command/session_test.go | 133 ++++++++++++++++++ internal/integration/integration.go | 7 +- internal/query/projection/session.go | 26 ++++ internal/query/projection/session_test.go | 32 +++++ internal/query/session.go | 17 +++ internal/query/sessions_test.go | 20 +++ internal/repository/session/eventstore.go | 1 + internal/repository/session/session.go | 34 +++++ proto/zitadel/session/v2alpha/session.proto | 9 ++ .../session/v2alpha/session_service.proto | 16 +++ 15 files changed, 437 insertions(+), 21 deletions(-) diff --git a/internal/api/grpc/session/v2/session.go b/internal/api/grpc/session/v2/session.go index ea61528fcb..54e01ae64c 100644 --- a/internal/api/grpc/session/v2/session.go +++ b/internal/api/grpc/session/v2/session.go @@ -120,6 +120,7 @@ func factorsToPb(s *query.Session) *session.Factors { Password: passwordFactorToPb(s.PasswordFactor), WebAuthN: webAuthNFactorToPb(s.WebAuthNFactor), Intent: intentFactorToPb(s.IntentFactor), + Totp: totpFactorToPb(s.TOTPFactor), } } @@ -151,6 +152,15 @@ func webAuthNFactorToPb(factor query.SessionWebAuthNFactor) *session.WebAuthNFac } } +func totpFactorToPb(factor query.SessionTOTPFactor) *session.TOTPFactor { + if factor.TOTPCheckedAt.IsZero() { + return nil + } + return &session.TOTPFactor{ + VerifiedAt: timestamppb.New(factor.TOTPCheckedAt), + } +} + func userFactorToPb(factor query.SessionUserFactor) *session.UserFactor { if factor.UserID == "" || factor.UserCheckedAt.IsZero() { return nil @@ -247,7 +257,9 @@ func (s *Server) checksToCommand(ctx context.Context, checks *session.Checks) ([ if passkey := checks.GetWebAuthN(); passkey != nil { sessionChecks = append(sessionChecks, s.command.CheckWebAuthN(passkey.GetCredentialAssertionData())) } - + if totp := checks.GetTotp(); totp != nil { + sessionChecks = append(sessionChecks, command.CheckTOTP(totp.GetTotp())) + } return sessionChecks, nil } diff --git a/internal/api/grpc/session/v2/session_integration_test.go b/internal/api/grpc/session/v2/session_integration_test.go index 7dd9355a71..14e99c6926 100644 --- a/internal/api/grpc/session/v2/session_integration_test.go +++ b/internal/api/grpc/session/v2/session_integration_test.go @@ -10,6 +10,7 @@ import ( "time" "github.com/muhlemmer/gu" + "github.com/pquerna/otp/totp" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc/metadata" @@ -45,6 +46,7 @@ func TestMain(m *testing.M) { } func verifyCurrentSession(t testing.TB, id, token string, sequence uint64, window time.Duration, metadata map[string][]byte, factors ...wantFactor) *session.Session { + t.Helper() require.NotEmpty(t, id) require.NotEmpty(t, token) @@ -71,6 +73,7 @@ const ( wantPasswordFactor wantWebAuthNFactor wantWebAuthNFactorUserVerified + wantTOTPFactor wantIntentFactor ) @@ -90,12 +93,16 @@ func verifyFactors(t testing.TB, factors *session.Factors, window time.Duration, pf := factors.GetWebAuthN() assert.NotNil(t, pf) assert.WithinRange(t, pf.GetVerifiedAt().AsTime(), time.Now().Add(-window), time.Now().Add(window)) - assert.False(t, pf.UserVerified) + assert.False(t, pf.GetUserVerified()) case wantWebAuthNFactorUserVerified: pf := factors.GetWebAuthN() assert.NotNil(t, pf) assert.WithinRange(t, pf.GetVerifiedAt().AsTime(), time.Now().Add(-window), time.Now().Add(window)) - assert.True(t, pf.UserVerified) + assert.True(t, pf.GetUserVerified()) + case wantTOTPFactor: + pf := factors.GetTotp() + assert.NotNil(t, pf) + assert.WithinRange(t, pf.GetVerifiedAt().AsTime(), time.Now().Add(-window), time.Now().Add(window)) case wantIntentFactor: pf := factors.GetIntent() assert.NotNil(t, pf) @@ -338,6 +345,23 @@ func TestServer_CreateSession_startedIntentFalseToken(t *testing.T) { require.Error(t, err) } +func registerTOTP(ctx context.Context, t *testing.T, userID string) (secret string) { + resp, err := Tester.Client.UserV2.RegisterTOTP(ctx, &user.RegisterTOTPRequest{ + UserId: userID, + }) + require.NoError(t, err) + secret = resp.GetSecret() + code, err := totp.GenerateCode(secret, time.Now()) + require.NoError(t, err) + + _, err = Tester.Client.UserV2.VerifyTOTPRegistration(ctx, &user.VerifyTOTPRegistrationRequest{ + UserId: userID, + Code: code, + }) + require.NoError(t, err) + return secret +} + func TestServer_SetSession_flow(t *testing.T) { // create new, empty session createResp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{}) @@ -346,7 +370,6 @@ func TestServer_SetSession_flow(t *testing.T) { verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, createResp.GetDetails().GetSequence(), time.Minute, nil) t.Run("check user", func(t *testing.T) { - wantFactors := []wantFactor{wantUserFactor} resp, err := Client.SetSession(CTX, &session.SetSessionRequest{ SessionId: createResp.GetSessionId(), SessionToken: sessionToken, @@ -360,7 +383,7 @@ func TestServer_SetSession_flow(t *testing.T) { }) require.NoError(t, err) sessionToken = resp.GetSessionToken() - verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, wantFactors...) + verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, wantUserFactor) }) t.Run("check webauthn, user verified (passkey)", func(t *testing.T) { @@ -378,7 +401,6 @@ func TestServer_SetSession_flow(t *testing.T) { verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil) sessionToken = resp.GetSessionToken() - wantFactors := []wantFactor{wantUserFactor, wantWebAuthNFactorUserVerified} assertionData, err := Tester.WebAuthN.CreateAssertionResponse(resp.GetChallenges().GetWebAuthN().GetPublicKeyCredentialRequestOptions(), true) require.NoError(t, err) @@ -393,14 +415,14 @@ func TestServer_SetSession_flow(t *testing.T) { }) require.NoError(t, err) sessionToken = resp.GetSessionToken() - verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, wantFactors...) + verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, wantUserFactor, wantWebAuthNFactorUserVerified) }) + userAuthCtx := Tester.WithAuthorizationToken(CTX, sessionToken) + Tester.RegisterUserU2F(userAuthCtx, User.GetUserId()) + totpSecret := registerTOTP(userAuthCtx, t, User.GetUserId()) + t.Run("check webauthn, user not verified (U2F)", func(t *testing.T) { - Tester.RegisterUserU2F( - Tester.WithAuthorizationToken(context.Background(), sessionToken), - User.GetUserId(), - ) for _, userVerificationRequirement := range []session.UserVerificationRequirement{ session.UserVerificationRequirement_USER_VERIFICATION_REQUIREMENT_PREFERRED, @@ -421,7 +443,6 @@ func TestServer_SetSession_flow(t *testing.T) { verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil) sessionToken = resp.GetSessionToken() - wantFactors := []wantFactor{wantUserFactor, wantWebAuthNFactor} assertionData, err := Tester.WebAuthN.CreateAssertionResponse(resp.GetChallenges().GetWebAuthN().GetPublicKeyCredentialRequestOptions(), false) require.NoError(t, err) @@ -436,10 +457,27 @@ func TestServer_SetSession_flow(t *testing.T) { }) require.NoError(t, err) sessionToken = resp.GetSessionToken() - verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, wantFactors...) + verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, wantUserFactor, wantWebAuthNFactor) }) } }) + + t.Run("check TOTP", func(t *testing.T) { + code, err := totp.GenerateCode(totpSecret, time.Now()) + require.NoError(t, err) + resp, err := Client.SetSession(CTX, &session.SetSessionRequest{ + SessionId: createResp.GetSessionId(), + SessionToken: sessionToken, + Checks: &session.Checks{ + Totp: &session.CheckTOTP{ + Totp: code, + }, + }, + }) + require.NoError(t, err) + sessionToken = resp.GetSessionToken() + verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, wantUserFactor, wantWebAuthNFactor, wantTOTPFactor) + }) } func Test_ZITADEL_API_missing_authentication(t *testing.T) { diff --git a/internal/api/grpc/session/v2/session_test.go b/internal/api/grpc/session/v2/session_test.go index 0f4d9b3c66..a7d725899c 100644 --- a/internal/api/grpc/session/v2/session_test.go +++ b/internal/api/grpc/session/v2/session_test.go @@ -91,6 +91,26 @@ func Test_sessionsToPb(t *testing.T) { }, Metadata: map[string][]byte{"hello": []byte("world")}, }, + { // totp factor + ID: "999", + CreationDate: now, + ChangeDate: now, + Sequence: 123, + State: domain.SessionStateActive, + ResourceOwner: "me", + Creator: "he", + UserFactor: query.SessionUserFactor{ + UserID: "345", + UserCheckedAt: past, + LoginName: "donald", + DisplayName: "donald duck", + ResourceOwner: "org1", + }, + TOTPFactor: query.SessionTOTPFactor{ + TOTPCheckedAt: past, + }, + Metadata: map[string][]byte{"hello": []byte("world")}, + }, } want := []*session.Session{ @@ -157,6 +177,25 @@ func Test_sessionsToPb(t *testing.T) { }, Metadata: map[string][]byte{"hello": []byte("world")}, }, + { // totp factor + Id: "999", + CreationDate: timestamppb.New(now), + ChangeDate: timestamppb.New(now), + Sequence: 123, + Factors: &session.Factors{ + User: &session.UserFactor{ + VerifiedAt: timestamppb.New(past), + Id: "345", + LoginName: "donald", + DisplayName: "donald duck", + OrganisationId: "org1", + }, + Totp: &session.TOTPFactor{ + VerifiedAt: timestamppb.New(past), + }, + }, + Metadata: map[string][]byte{"hello": []byte("world")}, + }, } out := sessionsToPb(sessions) diff --git a/internal/command/session.go b/internal/command/session.go index 6bcf9f044d..fead616c2f 100644 --- a/internal/command/session.go +++ b/internal/command/session.go @@ -26,11 +26,13 @@ type SessionCommands struct { sessionWriteModel *SessionWriteModel passwordWriteModel *HumanPasswordWriteModel intentWriteModel *IDPIntentWriteModel + totpWriteModel *HumanTOTPWriteModel eventstore *eventstore.Eventstore eventCommands []eventstore.Command hasher *crypto.PasswordHasher intentAlg crypto.EncryptionAlgorithm + totpAlg crypto.EncryptionAlgorithm createToken func(sessionID string) (id string, token string, err error) now func() time.Time } @@ -42,6 +44,7 @@ func (c *Commands) NewSessionCommands(cmds []SessionCommand, session *SessionWri eventstore: c.eventstore, hasher: c.userPasswordHasher, intentAlg: c.idpConfigEncryption, + totpAlg: c.multifactors.OTP.CryptoMFA, createToken: c.sessionTokenCreator, now: time.Now, } @@ -127,6 +130,28 @@ func CheckIntent(intentID, token string) SessionCommand { } } +func CheckTOTP(code string) SessionCommand { + return func(ctx context.Context, cmd *SessionCommands) (err error) { + if cmd.sessionWriteModel.UserID == "" { + return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-Neil7", "Errors.User.UserIDMissing") + } + cmd.totpWriteModel = NewHumanTOTPWriteModel(cmd.sessionWriteModel.UserID, "") + err = cmd.eventstore.FilterToQueryReducer(ctx, cmd.totpWriteModel) + if err != nil { + return err + } + if cmd.totpWriteModel.State != domain.MFAStateReady { + return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-eej1U", "Errors.User.MFA.OTP.NotReady") + } + err = domain.VerifyTOTP(code, cmd.totpWriteModel.Secret, cmd.totpAlg) + if err != nil { + return err + } + cmd.TOTPChecked(ctx, cmd.now()) + return nil + } +} + // Exec will execute the commands specified and returns an error on the first occurrence func (s *SessionCommands) Exec(ctx context.Context) error { for _, cmd := range s.sessionCommands { @@ -175,6 +200,10 @@ func (s *SessionCommands) WebAuthNChecked(ctx context.Context, checkedAt time.Ti } } +func (s *SessionCommands) TOTPChecked(ctx context.Context, checkedAt time.Time) { + s.eventCommands = append(s.eventCommands, session.NewTOTPCheckedEvent(ctx, s.sessionWriteModel.aggregate, checkedAt)) +} + func (s *SessionCommands) SetToken(ctx context.Context, tokenID string) { s.eventCommands = append(s.eventCommands, session.NewTokenSetEvent(ctx, s.sessionWriteModel.aggregate, tokenID)) } diff --git a/internal/command/session_model.go b/internal/command/session_model.go index 7674da9bcc..373e5b96b4 100644 --- a/internal/command/session_model.go +++ b/internal/command/session_model.go @@ -35,6 +35,7 @@ type SessionWriteModel struct { PasswordCheckedAt time.Time IntentCheckedAt time.Time WebAuthNCheckedAt time.Time + TOTPCheckedAt time.Time WebAuthNUserVerified bool Metadata map[string][]byte State domain.SessionState @@ -70,6 +71,8 @@ func (wm *SessionWriteModel) Reduce() error { wm.reduceWebAuthNChallenged(e) case *session.WebAuthNCheckedEvent: wm.reduceWebAuthNChecked(e) + case *session.TOTPCheckedEvent: + wm.reduceTOTPChecked(e) case *session.TokenSetEvent: wm.reduceTokenSet(e) case *session.TerminateEvent: @@ -91,6 +94,7 @@ func (wm *SessionWriteModel) Query() *eventstore.SearchQueryBuilder { session.IntentCheckedType, session.WebAuthNChallengedType, session.WebAuthNCheckedType, + session.TOTPCheckedType, session.TokenSetType, session.MetadataSetType, session.TerminateType, @@ -135,6 +139,10 @@ func (wm *SessionWriteModel) reduceWebAuthNChecked(e *session.WebAuthNCheckedEve wm.WebAuthNUserVerified = e.UserVerified } +func (wm *SessionWriteModel) reduceTOTPChecked(e *session.TOTPCheckedEvent) { + wm.TOTPCheckedAt = e.CheckedAt +} + func (wm *SessionWriteModel) reduceTokenSet(e *session.TokenSetEvent) { wm.TokenID = e.TokenID } @@ -149,8 +157,8 @@ func (wm *SessionWriteModel) AuthenticationTime() time.Time { for _, check := range []time.Time{ wm.PasswordCheckedAt, wm.WebAuthNCheckedAt, + wm.TOTPCheckedAt, wm.IntentCheckedAt, - // TODO: add OTP check https://github.com/zitadel/zitadel/issues/5477 // TODO: add OTP (sms and email) check https://github.com/zitadel/zitadel/issues/6224 } { if check.After(authTime) { @@ -176,12 +184,9 @@ func (wm *SessionWriteModel) AuthMethodTypes() []domain.UserAuthMethodType { if !wm.IntentCheckedAt.IsZero() { types = append(types, domain.UserAuthMethodTypeIDP) } - // TODO: add checks with https://github.com/zitadel/zitadel/issues/5477 - /* - if !wm.TOTPCheckedAt.IsZero() { - types = append(types, domain.UserAuthMethodTypeTOTP) - } - */ + if !wm.TOTPCheckedAt.IsZero() { + types = append(types, domain.UserAuthMethodTypeTOTP) + } // TODO: add checks with https://github.com/zitadel/zitadel/issues/6224 /* if !wm.TOTPFactor.OTPSMSCheckedAt.IsZero() { diff --git a/internal/command/session_test.go b/internal/command/session_test.go index 099740c101..57f3ba971c 100644 --- a/internal/command/session_test.go +++ b/internal/command/session_test.go @@ -7,6 +7,7 @@ import ( "time" "github.com/golang/mock/gomock" + "github.com/pquerna/otp/totp" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "golang.org/x/text/language" @@ -695,6 +696,138 @@ func TestCommands_updateSession(t *testing.T) { } } +func TestCheckTOTP(t *testing.T) { + ctx := authz.NewMockContext("", "org1", "user1") + + cryptoAlg := crypto.CreateMockEncryptionAlg(gomock.NewController(t)) + key, secret, err := domain.NewTOTPKey("example.com", "user1", cryptoAlg) + require.NoError(t, err) + + sessAgg := &session.NewAggregate("session1", "org1").Aggregate + userAgg := &user.NewAggregate("user1", "org1").Aggregate + + code, err := totp.GenerateCode(key.Secret(), testNow) + require.NoError(t, err) + + type fields struct { + sessionWriteModel *SessionWriteModel + eventstore func(*testing.T) *eventstore.Eventstore + } + + tests := []struct { + name string + code string + fields fields + wantEventCommands []eventstore.Command + wantErr error + }{ + { + name: "missing userID", + code: code, + fields: fields{ + sessionWriteModel: &SessionWriteModel{ + aggregate: sessAgg, + }, + eventstore: expectEventstore(), + }, + wantErr: caos_errs.ThrowPreconditionFailed(nil, "COMMAND-Neil7", "Errors.User.UserIDMissing"), + }, + { + name: "filter error", + code: code, + fields: fields{ + sessionWriteModel: &SessionWriteModel{ + UserID: "user1", + UserCheckedAt: testNow, + aggregate: sessAgg, + }, + eventstore: expectEventstore( + expectFilterError(io.ErrClosedPipe), + ), + }, + wantErr: io.ErrClosedPipe, + }, + { + name: "otp not ready error", + code: code, + fields: fields{ + sessionWriteModel: &SessionWriteModel{ + UserID: "user1", + UserCheckedAt: testNow, + aggregate: sessAgg, + }, + eventstore: expectEventstore( + expectFilter( + eventFromEventPusher( + user.NewHumanOTPAddedEvent(ctx, userAgg, secret), + ), + ), + ), + }, + wantErr: caos_errs.ThrowPreconditionFailed(nil, "COMMAND-eej1U", "Errors.User.MFA.OTP.NotReady"), + }, + { + name: "otp verify error", + code: "foobar", + fields: fields{ + sessionWriteModel: &SessionWriteModel{ + UserID: "user1", + UserCheckedAt: testNow, + aggregate: sessAgg, + }, + eventstore: expectEventstore( + expectFilter( + eventFromEventPusher( + user.NewHumanOTPAddedEvent(ctx, userAgg, secret), + ), + eventFromEventPusher( + user.NewHumanOTPVerifiedEvent(ctx, userAgg, "agent1"), + ), + ), + ), + }, + wantErr: caos_errs.ThrowInvalidArgument(nil, "EVENT-8isk2", "Errors.User.MFA.OTP.InvalidCode"), + }, + { + name: "ok", + code: code, + fields: fields{ + sessionWriteModel: &SessionWriteModel{ + UserID: "user1", + UserCheckedAt: testNow, + aggregate: sessAgg, + }, + eventstore: expectEventstore( + expectFilter( + eventFromEventPusher( + user.NewHumanOTPAddedEvent(ctx, userAgg, secret), + ), + eventFromEventPusher( + user.NewHumanOTPVerifiedEvent(ctx, userAgg, "agent1"), + ), + ), + ), + }, + wantEventCommands: []eventstore.Command{ + session.NewTOTPCheckedEvent(ctx, sessAgg, testNow), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cmd := &SessionCommands{ + sessionWriteModel: tt.fields.sessionWriteModel, + eventstore: tt.fields.eventstore(t), + totpAlg: cryptoAlg, + now: func() time.Time { return testNow }, + } + err := CheckTOTP(tt.code)(ctx, cmd) + require.ErrorIs(t, err, tt.wantErr) + assert.Equal(t, tt.wantEventCommands, cmd.eventCommands) + }) + } +} + func TestCommands_TerminateSession(t *testing.T) { type fields struct { eventstore *eventstore.Eventstore diff --git a/internal/integration/integration.go b/internal/integration/integration.go index c645a188fe..d652311190 100644 --- a/internal/integration/integration.go +++ b/internal/integration/integration.go @@ -239,7 +239,12 @@ func (s *Tester) WithInstanceAuthorization(ctx context.Context, u UserType, inst } func (s *Tester) WithAuthorizationToken(ctx context.Context, token string) context.Context { - return metadata.AppendToOutgoingContext(ctx, "Authorization", fmt.Sprintf("Bearer %s", token)) + md, ok := metadata.FromOutgoingContext(ctx) + if !ok { + md = make(metadata.MD) + } + md.Set("Authorization", fmt.Sprintf("Bearer %s", token)) + return metadata.NewOutgoingContext(ctx, md) } func (s *Tester) ensureSystemUser() { diff --git a/internal/query/projection/session.go b/internal/query/projection/session.go index afa48b1c01..654e804270 100644 --- a/internal/query/projection/session.go +++ b/internal/query/projection/session.go @@ -30,6 +30,7 @@ const ( SessionColumnIntentCheckedAt = "intent_checked_at" SessionColumnWebAuthNCheckedAt = "webauthn_checked_at" SessionColumnWebAuthNUserVerified = "webauthn_user_verified" + SessionColumnTOTPCheckedAt = "totp_checked_at" SessionColumnMetadata = "metadata" SessionColumnTokenID = "token_id" ) @@ -58,6 +59,7 @@ func newSessionProjection(ctx context.Context, config crdb.StatementHandlerConfi crdb.NewColumn(SessionColumnIntentCheckedAt, crdb.ColumnTypeTimestamp, crdb.Nullable()), crdb.NewColumn(SessionColumnWebAuthNCheckedAt, crdb.ColumnTypeTimestamp, crdb.Nullable()), crdb.NewColumn(SessionColumnWebAuthNUserVerified, crdb.ColumnTypeBool, crdb.Nullable()), + crdb.NewColumn(SessionColumnTOTPCheckedAt, crdb.ColumnTypeTimestamp, crdb.Nullable()), crdb.NewColumn(SessionColumnMetadata, crdb.ColumnTypeJSONB, crdb.Nullable()), crdb.NewColumn(SessionColumnTokenID, crdb.ColumnTypeText, crdb.Nullable()), }, @@ -93,6 +95,10 @@ func (p *sessionProjection) reducers() []handler.AggregateReducer { Event: session.WebAuthNCheckedType, Reduce: p.reduceWebAuthNChecked, }, + { + Event: session.TOTPCheckedType, + Reduce: p.reduceTOTPChecked, + }, { Event: session.TokenSetType, Reduce: p.reduceTokenSet, @@ -229,6 +235,26 @@ func (p *sessionProjection) reduceWebAuthNChecked(event eventstore.Event) (*hand ), nil } +func (p *sessionProjection) reduceTOTPChecked(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*session.TOTPCheckedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-Oqu8i", "reduce.wrong.event.type %s", session.TOTPCheckedType) + } + + return crdb.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(SessionColumnChangeDate, e.CreationDate()), + handler.NewCol(SessionColumnSequence, e.Sequence()), + handler.NewCol(SessionColumnTOTPCheckedAt, e.CheckedAt), + }, + []handler.Condition{ + handler.NewCond(SessionColumnID, e.Aggregate().ID), + handler.NewCond(SessionColumnInstanceID, e.Aggregate().InstanceID), + }, + ), nil +} + func (p *sessionProjection) reduceTokenSet(event eventstore.Event) (*handler.Statement, error) { e, ok := event.(*session.TokenSetEvent) if !ok { diff --git a/internal/query/projection/session_test.go b/internal/query/projection/session_test.go index 5feb0d452c..c22310d620 100644 --- a/internal/query/projection/session_test.go +++ b/internal/query/projection/session_test.go @@ -191,6 +191,38 @@ func TestSessionProjection_reduces(t *testing.T) { }, }, }, + { + name: "instance reduceOTPChecked", + args: args{ + event: getEvent(testEvent( + session.AddedType, + session.AggregateType, + []byte(`{ + "checkedAt": "2023-05-04T00:00:00Z" + }`), + ), eventstore.GenericEventMapper[session.TOTPCheckedEvent]), + }, + reduce: (&sessionProjection{}).reduceTOTPChecked, + want: wantReduce{ + aggregateType: eventstore.AggregateType("session"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.sessions4 SET (change_date, sequence, totp_checked_at) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedArgs: []interface{}{ + anyArg{}, + anyArg{}, + time.Date(2023, time.May, 4, 0, 0, 0, 0, time.UTC), + "agg-id", + "instance-id", + }, + }, + }, + }, + }, + }, { name: "instance reduceTokenSet", args: args{ diff --git a/internal/query/session.go b/internal/query/session.go index 5746fe0592..0c7d67dbf8 100644 --- a/internal/query/session.go +++ b/internal/query/session.go @@ -34,6 +34,7 @@ type Session struct { PasswordFactor SessionPasswordFactor IntentFactor SessionIntentFactor WebAuthNFactor SessionWebAuthNFactor + TOTPFactor SessionTOTPFactor Metadata map[string][]byte } @@ -58,6 +59,10 @@ type SessionWebAuthNFactor struct { UserVerified bool } +type SessionTOTPFactor struct { + TOTPCheckedAt time.Time +} + type SessionsSearchQueries struct { SearchRequest Queries []SearchQuery @@ -132,6 +137,10 @@ var ( name: projection.SessionColumnWebAuthNUserVerified, table: sessionsTable, } + SessionColumnTOTPCheckedAt = Column{ + name: projection.SessionColumnTOTPCheckedAt, + table: sessionsTable, + } SessionColumnMetadata = Column{ name: projection.SessionColumnMetadata, table: sessionsTable, @@ -230,6 +239,7 @@ func prepareSessionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil SessionColumnIntentCheckedAt.identifier(), SessionColumnWebAuthNCheckedAt.identifier(), SessionColumnWebAuthNUserVerified.identifier(), + SessionColumnTOTPCheckedAt.identifier(), SessionColumnMetadata.identifier(), SessionColumnToken.identifier(), ).From(sessionsTable.identifier()). @@ -249,6 +259,7 @@ func prepareSessionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil intentCheckedAt sql.NullTime webAuthNCheckedAt sql.NullTime webAuthNUserPresent sql.NullBool + totpCheckedAt sql.NullTime metadata database.Map[[]byte] token sql.NullString ) @@ -270,6 +281,7 @@ func prepareSessionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil &intentCheckedAt, &webAuthNCheckedAt, &webAuthNUserPresent, + &totpCheckedAt, &metadata, &token, ) @@ -290,6 +302,7 @@ func prepareSessionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil session.IntentFactor.IntentCheckedAt = intentCheckedAt.Time session.WebAuthNFactor.WebAuthNCheckedAt = webAuthNCheckedAt.Time session.WebAuthNFactor.UserVerified = webAuthNUserPresent.Bool + session.TOTPFactor.TOTPCheckedAt = totpCheckedAt.Time session.Metadata = metadata return session, token.String, nil @@ -314,6 +327,7 @@ func prepareSessionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBui SessionColumnIntentCheckedAt.identifier(), SessionColumnWebAuthNCheckedAt.identifier(), SessionColumnWebAuthNUserVerified.identifier(), + SessionColumnTOTPCheckedAt.identifier(), SessionColumnMetadata.identifier(), countColumn.identifier(), ).From(sessionsTable.identifier()). @@ -336,6 +350,7 @@ func prepareSessionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBui intentCheckedAt sql.NullTime webAuthNCheckedAt sql.NullTime webAuthNUserPresent sql.NullBool + totpCheckedAt sql.NullTime metadata database.Map[[]byte] ) @@ -356,6 +371,7 @@ func prepareSessionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBui &intentCheckedAt, &webAuthNCheckedAt, &webAuthNUserPresent, + &totpCheckedAt, &metadata, &sessions.Count, ) @@ -372,6 +388,7 @@ func prepareSessionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBui session.IntentFactor.IntentCheckedAt = intentCheckedAt.Time session.WebAuthNFactor.WebAuthNCheckedAt = webAuthNCheckedAt.Time session.WebAuthNFactor.UserVerified = webAuthNUserPresent.Bool + session.TOTPFactor.TOTPCheckedAt = totpCheckedAt.Time session.Metadata = metadata sessions.Sessions = append(sessions.Sessions, session) diff --git a/internal/query/sessions_test.go b/internal/query/sessions_test.go index 92df908849..bc9e8bc6a0 100644 --- a/internal/query/sessions_test.go +++ b/internal/query/sessions_test.go @@ -33,6 +33,7 @@ var ( ` projections.sessions4.intent_checked_at,` + ` projections.sessions4.webauthn_checked_at,` + ` projections.sessions4.webauthn_user_verified,` + + ` projections.sessions4.totp_checked_at,` + ` projections.sessions4.metadata,` + ` projections.sessions4.token_id` + ` FROM projections.sessions4` + @@ -56,6 +57,7 @@ var ( ` projections.sessions4.intent_checked_at,` + ` projections.sessions4.webauthn_checked_at,` + ` projections.sessions4.webauthn_user_verified,` + + ` projections.sessions4.totp_checked_at,` + ` projections.sessions4.metadata,` + ` COUNT(*) OVER ()` + ` FROM projections.sessions4` + @@ -81,6 +83,7 @@ var ( "intent_checked_at", "webauthn_checked_at", "webauthn_user_verified", + "totp_checked_at", "metadata", "token", } @@ -102,6 +105,7 @@ var ( "intent_checked_at", "webauthn_checked_at", "webauthn_user_verified", + "totp_checked_at", "metadata", "count", } @@ -155,6 +159,7 @@ func Test_SessionsPrepare(t *testing.T) { testNow, testNow, true, + testNow, []byte(`{"key": "dmFsdWU="}`), }, }, @@ -190,6 +195,9 @@ func Test_SessionsPrepare(t *testing.T) { WebAuthNCheckedAt: testNow, UserVerified: true, }, + TOTPFactor: SessionTOTPFactor{ + TOTPCheckedAt: testNow, + }, Metadata: map[string][]byte{ "key": []byte("value"), }, @@ -222,6 +230,7 @@ func Test_SessionsPrepare(t *testing.T) { testNow, testNow, true, + testNow, []byte(`{"key": "dmFsdWU="}`), }, { @@ -241,6 +250,7 @@ func Test_SessionsPrepare(t *testing.T) { testNow, testNow, false, + testNow, []byte(`{"key": "dmFsdWU="}`), }, }, @@ -276,6 +286,9 @@ func Test_SessionsPrepare(t *testing.T) { WebAuthNCheckedAt: testNow, UserVerified: true, }, + TOTPFactor: SessionTOTPFactor{ + TOTPCheckedAt: testNow, + }, Metadata: map[string][]byte{ "key": []byte("value"), }, @@ -305,6 +318,9 @@ func Test_SessionsPrepare(t *testing.T) { WebAuthNCheckedAt: testNow, UserVerified: false, }, + TOTPFactor: SessionTOTPFactor{ + TOTPCheckedAt: testNow, + }, Metadata: map[string][]byte{ "key": []byte("value"), }, @@ -390,6 +406,7 @@ func Test_SessionPrepare(t *testing.T) { testNow, testNow, true, + testNow, []byte(`{"key": "dmFsdWU="}`), "tokenID", }, @@ -420,6 +437,9 @@ func Test_SessionPrepare(t *testing.T) { WebAuthNCheckedAt: testNow, UserVerified: true, }, + TOTPFactor: SessionTOTPFactor{ + TOTPCheckedAt: testNow, + }, Metadata: map[string][]byte{ "key": []byte("value"), }, diff --git a/internal/repository/session/eventstore.go b/internal/repository/session/eventstore.go index 89f6d775e4..efa52b6582 100644 --- a/internal/repository/session/eventstore.go +++ b/internal/repository/session/eventstore.go @@ -9,6 +9,7 @@ func RegisterEventMappers(es *eventstore.Eventstore) { RegisterFilterEventMapper(AggregateType, IntentCheckedType, IntentCheckedEventMapper). RegisterFilterEventMapper(AggregateType, WebAuthNChallengedType, eventstore.GenericEventMapper[WebAuthNChallengedEvent]). RegisterFilterEventMapper(AggregateType, WebAuthNCheckedType, eventstore.GenericEventMapper[WebAuthNCheckedEvent]). + RegisterFilterEventMapper(AggregateType, TOTPCheckedType, eventstore.GenericEventMapper[TOTPCheckedEvent]). RegisterFilterEventMapper(AggregateType, TokenSetType, TokenSetEventMapper). RegisterFilterEventMapper(AggregateType, MetadataSetType, MetadataSetEventMapper). RegisterFilterEventMapper(AggregateType, TerminateType, TerminateEventMapper) diff --git a/internal/repository/session/session.go b/internal/repository/session/session.go index f2779fa503..556cd033c7 100644 --- a/internal/repository/session/session.go +++ b/internal/repository/session/session.go @@ -19,6 +19,7 @@ const ( IntentCheckedType = sessionEventPrefix + "intent.checked" WebAuthNChallengedType = sessionEventPrefix + "webAuthN.challenged" WebAuthNCheckedType = sessionEventPrefix + "webAuthN.checked" + TOTPCheckedType = sessionEventPrefix + "totp.checked" TokenSetType = sessionEventPrefix + "token.set" MetadataSetType = sessionEventPrefix + "metadata.set" TerminateType = sessionEventPrefix + "terminated" @@ -264,6 +265,39 @@ func NewWebAuthNCheckedEvent( } } +type TOTPCheckedEvent struct { + eventstore.BaseEvent `json:"-"` + + CheckedAt time.Time `json:"checkedAt"` +} + +func (e *TOTPCheckedEvent) Data() interface{} { + return e +} + +func (e *TOTPCheckedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + return nil +} + +func (e *TOTPCheckedEvent) SetBaseEvent(base *eventstore.BaseEvent) { + e.BaseEvent = *base +} + +func NewTOTPCheckedEvent( + ctx context.Context, + aggregate *eventstore.Aggregate, + checkedAt time.Time, +) *TOTPCheckedEvent { + return &TOTPCheckedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + TOTPCheckedType, + ), + CheckedAt: checkedAt, + } +} + type TokenSetEvent struct { eventstore.BaseEvent `json:"-"` diff --git a/proto/zitadel/session/v2alpha/session.proto b/proto/zitadel/session/v2alpha/session.proto index 37436ed2d4..44f337c0d6 100644 --- a/proto/zitadel/session/v2alpha/session.proto +++ b/proto/zitadel/session/v2alpha/session.proto @@ -46,6 +46,7 @@ message Factors { PasswordFactor password = 2; WebAuthNFactor web_auth_n = 3; IntentFactor intent = 4; + TOTPFactor totp = 5; } message UserFactor { @@ -101,6 +102,14 @@ message WebAuthNFactor { bool user_verified = 2; } +message TOTPFactor { + google.protobuf.Timestamp verified_at = 1 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "\"time when the Time-based One-Time Password was last checked\""; + } + ]; +} + message SearchQuery { oneof query { option (validate.required) = true; diff --git a/proto/zitadel/session/v2alpha/session_service.proto b/proto/zitadel/session/v2alpha/session_service.proto index c201b5e368..693d6a7103 100644 --- a/proto/zitadel/session/v2alpha/session_service.proto +++ b/proto/zitadel/session/v2alpha/session_service.proto @@ -346,6 +346,11 @@ message Checks { description: "\"Checks the intent. Requires that the userlink is already checked and a successful intent.\""; } ]; + optional CheckTOTP totp = 5 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "\"Checks the Time-based One-Time Password and updates the session on success. Requires that the user is already checked, either in the previous or the same request.\""; + } + ]; } message CheckUser { @@ -412,3 +417,14 @@ message CheckIntent { } ]; } + +message CheckTOTP { + string totp = 1 [ + (validate.rules).string = {min_len: 6, max_len: 6}, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + min_length: 6; + max_length: 6; + example: "\"323764\""; + } + ]; +} \ No newline at end of file From faa9ed4de968298fdddd394b29cf38a59a11f83c Mon Sep 17 00:00:00 2001 From: Alan Hughes Date: Tue, 15 Aug 2023 12:53:26 +0100 Subject: [PATCH 30/38] docs: fix external domain and external key env var names (#6367) --- cmd/defaults.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/defaults.yaml b/cmd/defaults.yaml index 9088ff2cf9..7f90aca5c9 100644 --- a/cmd/defaults.yaml +++ b/cmd/defaults.yaml @@ -41,10 +41,10 @@ Telemetry: Port: 8080 # ZITADEL_PORT # Port ZITADEL is exposed on, it can differ from port e.g. if you proxy the traffic # !!! Changing this after the initial setup breaks your system !!! -ExternalPort: 8080 # ZITADEL_EXTERNAL_PORT +ExternalPort: 8080 # ZITADEL_EXTERNALPORT # Domain/hostname ZITADEL is exposed externally # !!! Changing this after the initial setup breaks your system !!! -ExternalDomain: localhost # ZITADEL_EXTERNAL_DOMAIN +ExternalDomain: localhost # ZITADEL_EXTERNALDOMAIN # specifies if ZITADEL is exposed externally through TLS # this must be set to true even if TLS is not enabled on ZITADEL itself # but TLS traffic is terminated on a reverse proxy From 7c494fd21921f94a69474c17ef79f2ea0962dfd6 Mon Sep 17 00:00:00 2001 From: Livio Spring Date: Tue, 15 Aug 2023 14:47:05 +0200 Subject: [PATCH 31/38] feat(login): add OTP (email and sms) (#6353) * feat: login with otp * fix(i18n): japanese translation * add missing files * fix provider change * add event types translations to en * add tests * resourceOwner * remove unused handler * fix: secret generators and add comments * add setup step * rename * linting * fix setup * improve otp handling * fix autocomplete * translations for login and notifications * translations for event types * changes from review * check selected mfa type --- cmd/setup/12.go | 26 + cmd/setup/12/12_add_otp_columns.sql | 2 + cmd/setup/config.go | 1 + cmd/setup/setup.go | 3 + .../dialog-add-secret-generator.component.ts | 4 +- internal/api/grpc/auth/phone.go | 6 +- internal/api/grpc/management/user.go | 6 +- internal/api/oidc/auth_request_converter.go | 4 +- internal/api/ui/login/custom_action.go | 2 + internal/api/ui/login/login.go | 8 + internal/api/ui/login/mfa_init_sms.go | 125 ++ internal/api/ui/login/mfa_prompt_handler.go | 20 + internal/api/ui/login/mfa_verify_handler.go | 6 + .../api/ui/login/mfa_verify_otp_handler.go | 126 ++ internal/api/ui/login/renderer.go | 10 +- internal/api/ui/login/router.go | 5 + internal/api/ui/login/static/i18n/bg.yaml | 13 + internal/api/ui/login/static/i18n/de.yaml | 21 + internal/api/ui/login/static/i18n/en.yaml | 23 +- internal/api/ui/login/static/i18n/es.yaml | 14 + internal/api/ui/login/static/i18n/fr.yaml | 14 + internal/api/ui/login/static/i18n/it.yaml | 14 + internal/api/ui/login/static/i18n/ja.yaml | 14 + internal/api/ui/login/static/i18n/mk.yaml | 14 + internal/api/ui/login/static/i18n/pl.yaml | 14 + internal/api/ui/login/static/i18n/pt.yaml | 14 + internal/api/ui/login/static/i18n/zh.yaml | 14 + .../ui/login/static/resources/scripts/edit.js | 6 + .../themes/scss/styles/mfa/mfa_base.scss | 5 +- .../static/templates/mfa_init_otp_sms.html | 63 + .../ui/login/static/templates/mfa_prompt.html | 10 + .../static/templates/mfa_verify_otp.html | 21 +- .../static/templates/mfa_verify_totp.html | 48 + internal/auth/repository/auth_request.go | 4 + .../eventsourcing/eventstore/auth_request.go | 42 + .../repository/eventsourcing/handler/user.go | 4 + internal/command/user_converter.go | 3 + internal/command/user_human_otp.go | 291 +++- internal/command/user_human_otp_model.go | 156 +- internal/command/user_human_otp_test.go | 1366 +++++++++++++++++ internal/command/user_human_phone.go | 16 +- internal/command/user_human_phone_test.go | 40 +- internal/crypto/code_mocker.go | 29 +- internal/domain/auth_request.go | 2 + .../notification/handlers/user_notifier.go | 141 +- internal/notification/static/i18n/bg.yaml | 5 +- internal/notification/static/i18n/de.yaml | 5 +- internal/notification/static/i18n/en.yaml | 7 +- internal/notification/static/i18n/es.yaml | 5 +- internal/notification/static/i18n/fr.yaml | 5 +- internal/notification/static/i18n/it.yaml | 5 +- internal/notification/static/i18n/ja.yaml | 7 +- internal/notification/static/i18n/mk.yaml | 5 +- internal/notification/static/i18n/pl.yaml | 5 +- internal/notification/static/i18n/pt.yaml | 5 +- internal/notification/static/i18n/zh.yaml | 5 +- internal/notification/types/otp.go | 29 + .../types/phone_verification_code.go | 3 +- internal/query/projection/user_auth_method.go | 8 + .../repository/instance/secret_generator.go | 2 +- internal/repository/user/eventstore.go | 4 + internal/repository/user/human_mfa_otp.go | 149 ++ internal/static/i18n/bg.yaml | 18 + internal/static/i18n/de.yaml | 18 + internal/static/i18n/en.yaml | 18 + internal/static/i18n/es.yaml | 18 + internal/static/i18n/fr.yaml | 18 + internal/static/i18n/it.yaml | 18 + internal/static/i18n/ja.yaml | 18 + internal/static/i18n/mk.yaml | 18 + internal/static/i18n/pl.yaml | 18 + internal/static/i18n/pt.yaml | 18 + internal/static/i18n/zh.yaml | 18 + internal/user/model/user_view.go | 20 +- internal/user/repository/view/model/user.go | 23 +- .../repository/view/model/user_session.go | 26 +- 76 files changed, 3203 insertions(+), 88 deletions(-) create mode 100644 cmd/setup/12.go create mode 100644 cmd/setup/12/12_add_otp_columns.sql create mode 100644 internal/api/ui/login/mfa_init_sms.go create mode 100644 internal/api/ui/login/mfa_verify_otp_handler.go create mode 100644 internal/api/ui/login/static/resources/scripts/edit.js create mode 100644 internal/api/ui/login/static/templates/mfa_init_otp_sms.html create mode 100644 internal/api/ui/login/static/templates/mfa_verify_totp.html create mode 100644 internal/notification/types/otp.go diff --git a/cmd/setup/12.go b/cmd/setup/12.go new file mode 100644 index 0000000000..ce0e23aa00 --- /dev/null +++ b/cmd/setup/12.go @@ -0,0 +1,26 @@ +package setup + +import ( + "context" + _ "embed" + + "github.com/zitadel/zitadel/internal/database" +) + +var ( + //go:embed 12/12_add_otp_columns.sql + addOTPColumns string +) + +type AddOTPColumns struct { + dbClient *database.DB +} + +func (mig *AddOTPColumns) Execute(ctx context.Context) error { + _, err := mig.dbClient.ExecContext(ctx, addOTPColumns) + return err +} + +func (mig *AddOTPColumns) String() string { + return "12_auth_users_otp_columns" +} diff --git a/cmd/setup/12/12_add_otp_columns.sql b/cmd/setup/12/12_add_otp_columns.sql new file mode 100644 index 0000000000..4386bf9fec --- /dev/null +++ b/cmd/setup/12/12_add_otp_columns.sql @@ -0,0 +1,2 @@ +ALTER TABLE auth.users2 ADD COLUMN otp_sms_added BOOL DEFAULT false; +ALTER TABLE auth.users2 ADD COLUMN otp_email_added BOOL DEFAULT false; \ No newline at end of file diff --git a/cmd/setup/config.go b/cmd/setup/config.go index 2f1bfbd6fa..939fc9adf9 100644 --- a/cmd/setup/config.go +++ b/cmd/setup/config.go @@ -67,6 +67,7 @@ type Steps struct { s9EventstoreIndexes2 *EventstoreIndexesNew CorrectCreationDate *CorrectCreationDate AddEventCreatedAt *AddEventCreatedAt + s12AddOTPColumns *AddOTPColumns } type encryptionKeyConfig struct { diff --git a/cmd/setup/setup.go b/cmd/setup/setup.go index 25f2f4fa4f..beba81611a 100644 --- a/cmd/setup/setup.go +++ b/cmd/setup/setup.go @@ -94,6 +94,7 @@ func Setup(config *Config, steps *Steps, masterKey string) { steps.CorrectCreationDate.dbClient = dbClient steps.AddEventCreatedAt.dbClient = dbClient steps.AddEventCreatedAt.step10 = steps.CorrectCreationDate + steps.s12AddOTPColumns = &AddOTPColumns{dbClient: dbClient} err = projection.Create(ctx, dbClient, eventstoreClient, config.Projections, nil, nil) logging.OnError(err).Fatal("unable to start projections") @@ -134,6 +135,8 @@ func Setup(config *Config, steps *Steps, masterKey string) { logging.OnError(err).Fatal("unable to migrate step 10") err = migration.Migrate(ctx, eventstoreClient, steps.AddEventCreatedAt) logging.OnError(err).Fatal("unable to migrate step 11") + err = migration.Migrate(ctx, eventstoreClient, steps.s12AddOTPColumns) + logging.OnError(err).Fatal("unable to migrate step 12") for _, repeatableStep := range repeatableSteps { err = migration.Migrate(ctx, eventstoreClient, repeatableStep) diff --git a/console/src/app/modules/policies/secret-generator/dialog-add-secret-generator/dialog-add-secret-generator.component.ts b/console/src/app/modules/policies/secret-generator/dialog-add-secret-generator/dialog-add-secret-generator.component.ts index 6d72286111..0161625c2e 100644 --- a/console/src/app/modules/policies/secret-generator/dialog-add-secret-generator/dialog-add-secret-generator.component.ts +++ b/console/src/app/modules/policies/secret-generator/dialog-add-secret-generator/dialog-add-secret-generator.component.ts @@ -32,8 +32,8 @@ export class DialogAddSecretGeneratorComponent { expiry: [exp, [requiredValidator]], length: [data.config?.length ?? 6, [requiredValidator]], includeDigits: [data.config?.includeDigits ?? true, [requiredValidator]], - includeLowerLetters: [data.config?.includeSymbols ?? true, [requiredValidator]], - includeSymbols: [data.config?.includeLowerLetters ?? true, [requiredValidator]], + includeSymbols: [data.config?.includeSymbols ?? true, [requiredValidator]], + includeLowerLetters: [data.config?.includeLowerLetters ?? true, [requiredValidator]], includeUpperLetters: [data.config?.includeUpperLetters ?? true, [requiredValidator]], }); } diff --git a/internal/api/grpc/auth/phone.go b/internal/api/grpc/auth/phone.go index 6c474831bc..5d5b722afc 100644 --- a/internal/api/grpc/auth/phone.go +++ b/internal/api/grpc/auth/phone.go @@ -62,11 +62,7 @@ func (s *Server) VerifyMyPhone(ctx context.Context, req *auth_pb.VerifyMyPhoneRe func (s *Server) ResendMyPhoneVerification(ctx context.Context, _ *auth_pb.ResendMyPhoneVerificationRequest) (*auth_pb.ResendMyPhoneVerificationResponse, error) { ctxData := authz.GetCtxData(ctx) - phoneCodeGenerator, err := s.query.InitEncryptionGenerator(ctx, domain.SecretGeneratorTypeVerifyPhoneCode, s.userCodeAlg) - if err != nil { - return nil, err - } - objectDetails, err := s.command.CreateHumanPhoneVerificationCode(ctx, ctxData.UserID, ctxData.ResourceOwner, phoneCodeGenerator) + objectDetails, err := s.command.CreateHumanPhoneVerificationCode(ctx, ctxData.UserID, ctxData.ResourceOwner) if err != nil { return nil, err } diff --git a/internal/api/grpc/management/user.go b/internal/api/grpc/management/user.go index c37ce3728c..804a905210 100644 --- a/internal/api/grpc/management/user.go +++ b/internal/api/grpc/management/user.go @@ -549,11 +549,7 @@ func (s *Server) RemoveHumanPhone(ctx context.Context, req *mgmt_pb.RemoveHumanP } func (s *Server) ResendHumanPhoneVerification(ctx context.Context, req *mgmt_pb.ResendHumanPhoneVerificationRequest) (*mgmt_pb.ResendHumanPhoneVerificationResponse, error) { - phoneCodeGenerator, err := s.query.InitEncryptionGenerator(ctx, domain.SecretGeneratorTypeVerifyPhoneCode, s.userCodeAlg) - if err != nil { - return nil, err - } - objectDetails, err := s.command.CreateHumanPhoneVerificationCode(ctx, req.UserId, authz.GetCtxData(ctx).OrgID, phoneCodeGenerator) + objectDetails, err := s.command.CreateHumanPhoneVerificationCode(ctx, req.UserId, authz.GetCtxData(ctx).OrgID) if err != nil { return nil, err } diff --git a/internal/api/oidc/auth_request_converter.go b/internal/api/oidc/auth_request_converter.go index d424abfc50..5999f21e5e 100644 --- a/internal/api/oidc/auth_request_converter.go +++ b/internal/api/oidc/auth_request_converter.go @@ -261,7 +261,9 @@ func CodeChallengeToOIDC(challenge *domain.OIDCCodeChallenge) *oidc.CodeChalleng func AMRFromMFAType(mfaType domain.MFAType) string { switch mfaType { - case domain.MFATypeTOTP: + case domain.MFATypeTOTP, + domain.MFATypeOTPSMS, + domain.MFATypeOTPEmail: return OTP case domain.MFATypeU2F, domain.MFATypeU2FUserVerification: diff --git a/internal/api/ui/login/custom_action.go b/internal/api/ui/login/custom_action.go index d6dbe6cdd4..516f7bc3d0 100644 --- a/internal/api/ui/login/custom_action.go +++ b/internal/api/ui/login/custom_action.go @@ -149,6 +149,8 @@ type authMethod string const ( authMethodPassword authMethod = "password" authMethodOTP authMethod = "OTP" + authMethodOTPSMS authMethod = "OTP SMS" + authMethodOTPEmail authMethod = "OTP Email" authMethodU2F authMethod = "U2F" authMethodPasswordless authMethod = "passwordless" ) diff --git a/internal/api/ui/login/login.go b/internal/api/ui/login/login.go index de42f7e68d..1a76ad1780 100644 --- a/internal/api/ui/login/login.go +++ b/internal/api/ui/login/login.go @@ -171,6 +171,14 @@ func setContext(ctx context.Context, resourceOwner string) context.Context { return authz.SetCtxData(ctx, data) } +func setUserContext(ctx context.Context, userID, resourceOwner string) context.Context { + data := authz.CtxData{ + UserID: userID, + OrgID: resourceOwner, + } + return authz.SetCtxData(ctx, data) +} + func (l *Login) baseURL(ctx context.Context) string { return http_utils.BuildOrigin(authz.GetInstance(ctx).RequestedHost(), l.externalSecure) + HandlerPrefix } diff --git a/internal/api/ui/login/mfa_init_sms.go b/internal/api/ui/login/mfa_init_sms.go new file mode 100644 index 0000000000..6443d6172e --- /dev/null +++ b/internal/api/ui/login/mfa_init_sms.go @@ -0,0 +1,125 @@ +package login + +import ( + "net/http" + + "github.com/zitadel/zitadel/internal/domain" +) + +const ( + tmplMFASMSInit = "mfainitsms" +) + +type smsInitData struct { + userData + Edit bool + MFAType domain.MFAType + Phone string +} + +type smsInitFormData struct { + Edit bool `schema:"edit"` + Resend bool `schema:"resend"` + Phone string `schema:"phone"` + NewPhone string `schema:"newPhone"` + Code string `schema:"code"` +} + +// handleRegisterOTPSMS checks if the user has a verified phone number and will directly add OTP SMS as 2FA. +// It will also add a successful OTP SMS check to the auth request. +// If there's no verified phone number, the potential last phone number will be used to render the registration page +func (l *Login) handleRegisterOTPSMS(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest) { + user, err := l.query.GetNotifyUserByID(r.Context(), true, authReq.UserID, false) + if err != nil { + l.renderError(w, r, authReq, err) + return + } + if user.VerifiedPhone == "" { + data := new(smsInitData) + data.Phone = user.LastPhone + data.Edit = user.LastPhone == "" + l.renderRegisterSMS(w, r, authReq, data, nil) + return + } + _, err = l.command.AddHumanOTPSMSWithCheckSucceeded(setUserContext(r.Context(), authReq.UserID, authReq.UserOrgID), authReq.UserID, authReq.UserOrgID, authReq) + if err != nil { + l.renderError(w, r, authReq, err) + return + } + done := &mfaDoneData{ + MFAType: domain.MFATypeOTPSMS, + } + l.renderMFAInitDone(w, r, authReq, done) +} + +func (l *Login) renderRegisterSMS(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, data *smsInitData, err error) { + var errID, errMessage string + if err != nil { + errID, errMessage = l.getErrorMessage(r, err) + } + data.baseData = l.getBaseData(r, authReq, "InitMFAOTP.Title", "InitMFAOTP.Description", errID, errMessage) + data.profileData = l.getProfileData(authReq) + data.MFAType = domain.MFATypeOTPSMS + l.renderer.RenderTemplate(w, r, l.getTranslator(r.Context(), authReq), l.renderer.Templates[tmplMFASMSInit], data, nil) +} + +// handleRegisterSMSCheck handles form submissions of the SMS registration. +// The user can be either in edit mode, where a phone number can be entered / changed. +// If a phone was set, the user can either switch to edit mode, have a resend of the code or verify the code by entering it. +// On successful code verification, the phone will be added to the user as well as his MFA +// and a successful OTP SMS check will be added to the auth request. +func (l *Login) handleRegisterSMSCheck(w http.ResponseWriter, r *http.Request) { + formData := new(smsInitFormData) + authReq, err := l.getAuthRequestAndParseData(r, formData) + if err != nil { + l.renderError(w, r, authReq, err) + return + } + + ctx := setUserContext(r.Context(), authReq.UserID, authReq.UserOrgID) + // save the current state + data := &smsInitData{Phone: formData.Phone} + + if formData.Edit { + data.Edit = true + l.renderRegisterSMS(w, r, authReq, data, err) + return + } + + if formData.Resend { + _, err = l.command.CreateHumanPhoneVerificationCode(ctx, authReq.UserID, authReq.UserOrgID) + l.renderRegisterSMS(w, r, authReq, data, err) + return + } + + // if the user is currently in edit mode, + // he can either change the phone number + // or just return to the code verification again + if formData.Code == "" { + data.Phone = formData.NewPhone + if formData.NewPhone != formData.Phone { + _, err = l.command.ChangeUserPhone(ctx, authReq.UserID, authReq.UserOrgID, formData.NewPhone, l.userCodeAlg) + if err != nil { + // stay in edit more + data.Edit = true + } + } + l.renderRegisterSMS(w, r, authReq, data, err) + return + } + + _, err = l.command.VerifyUserPhone(ctx, authReq.UserID, authReq.UserOrgID, formData.Code, l.userCodeAlg) + if err != nil { + l.renderRegisterSMS(w, r, authReq, data, err) + return + } + _, err = l.command.AddHumanOTPSMSWithCheckSucceeded(ctx, authReq.UserID, authReq.UserOrgID, authReq) + if err != nil { + l.renderRegisterSMS(w, r, authReq, data, err) + return + } + done := &mfaDoneData{ + MFAType: domain.MFATypeOTPSMS, + } + l.renderMFAInitDone(w, r, authReq, done) +} diff --git a/internal/api/ui/login/mfa_prompt_handler.go b/internal/api/ui/login/mfa_prompt_handler.go index c18511d317..9f4e8be409 100644 --- a/internal/api/ui/login/mfa_prompt_handler.go +++ b/internal/api/ui/login/mfa_prompt_handler.go @@ -83,6 +83,12 @@ func (l *Login) handleMFACreation(w http.ResponseWriter, r *http.Request, authRe case domain.MFATypeTOTP: l.handleTOTPCreation(w, r, authReq, data) return + case domain.MFATypeOTPSMS: + l.handleRegisterOTPSMS(w, r, authReq) + return + case domain.MFATypeOTPEmail: + l.handleRegisterOTPEmail(w, r, authReq) + return case domain.MFATypeU2F: l.renderRegisterU2F(w, r, authReq, nil) return @@ -103,3 +109,17 @@ func (l *Login) handleTOTPCreation(w http.ResponseWriter, r *http.Request, authR } l.renderMFAInitVerify(w, r, authReq, data, nil) } + +// handleRegisterOTPEmail will directly add OTP Email as 2FA. +// It will also add a successful OTP Email check to the auth request. +func (l *Login) handleRegisterOTPEmail(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest) { + _, err := l.command.AddHumanOTPEmailWithCheckSucceeded(setUserContext(r.Context(), authReq.UserID, authReq.UserOrgID), authReq.UserID, authReq.UserOrgID, authReq) + if err != nil { + l.renderError(w, r, authReq, err) + return + } + done := &mfaDoneData{ + MFAType: domain.MFATypeOTPEmail, + } + l.renderMFAInitDone(w, r, authReq, done) +} diff --git a/internal/api/ui/login/mfa_verify_handler.go b/internal/api/ui/login/mfa_verify_handler.go index b65809c894..addb7347fb 100644 --- a/internal/api/ui/login/mfa_verify_handler.go +++ b/internal/api/ui/login/mfa_verify_handler.go @@ -84,6 +84,12 @@ func (l *Login) renderMFAVerifySelected(w http.ResponseWriter, r *http.Request, data.SelectedMFAProvider = domain.MFATypeTOTP data.Title = translator.LocalizeWithoutArgs("VerifyMFAOTP.Title") data.Description = translator.LocalizeWithoutArgs("VerifyMFAOTP.Description") + case domain.MFATypeOTPSMS: + l.handleOTPVerification(w, r, authReq, verificationStep.MFAProviders, domain.MFATypeOTPSMS, nil) + return + case domain.MFATypeOTPEmail: + l.handleOTPVerification(w, r, authReq, verificationStep.MFAProviders, domain.MFATypeOTPEmail, nil) + return default: l.renderError(w, r, authReq, err) return diff --git a/internal/api/ui/login/mfa_verify_otp_handler.go b/internal/api/ui/login/mfa_verify_otp_handler.go new file mode 100644 index 0000000000..88aa37c947 --- /dev/null +++ b/internal/api/ui/login/mfa_verify_otp_handler.go @@ -0,0 +1,126 @@ +package login + +import ( + "context" + "fmt" + "net/http" + + http_mw "github.com/zitadel/zitadel/internal/api/http/middleware" + "github.com/zitadel/zitadel/internal/domain" +) + +const ( + tmplOTPVerification = "otpverification" + querySelectedProvider = "selectedProvider" +) + +type mfaOTPData struct { + userData + MFAProviders []domain.MFAType + SelectedProvider domain.MFAType +} + +type mfaOTPFormData struct { + Resend bool `schema:"resend"` + Code string `schema:"code"` + SelectedProvider domain.MFAType `schema:"selectedProvider"` + Provider domain.MFAType `schema:"provider"` +} + +func OTPLink(origin, authRequestID, code string, provider domain.MFAType) string { + return fmt.Sprintf("%s%s?%s=%s&%s=%s&%s=%d", externalLink(origin), EndpointMFAOTPVerify, QueryAuthRequestID, authRequestID, queryCode, code, querySelectedProvider, provider) +} + +// renderOTPVerification renders the OTP verification for SMS and Email based on the passed MFAType. +// It will send a new code to either phone or email first. +func (l *Login) handleOTPVerification(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, providers []domain.MFAType, selectedProvider domain.MFAType, err error) { + if err != nil { + l.renderOTPVerification(w, r, authReq, providers, selectedProvider, err) + return + } + userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) + var sendCode func(ctx context.Context, userID, resourceOwner, authRequestID, userAgentID string) error + switch selectedProvider { + case domain.MFATypeOTPSMS: + sendCode = l.authRepo.SendMFAOTPSMS + case domain.MFATypeOTPEmail: + sendCode = l.authRepo.SendMFAOTPEmail + // another type should never be passed, but just making sure + case domain.MFATypeU2F, + domain.MFATypeTOTP, + domain.MFATypeU2FUserVerification: + l.renderError(w, r, authReq, err) + return + } + err = sendCode(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, authReq.UserOrgID, authReq.ID, userAgentID) + l.renderOTPVerification(w, r, authReq, providers, selectedProvider, err) +} + +func (l *Login) renderOTPVerification(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, providers []domain.MFAType, selectedProvider domain.MFAType, err error) { + var errID, errMessage string + if err != nil { + errID, errMessage = l.getErrorMessage(r, err) + } + data := &mfaOTPData{ + userData: l.getUserData(r, authReq, "VerifyMFAU2F.Title", "VerifyMFAU2F.Description", errID, errMessage), + MFAProviders: removeSelectedProviderFromList(providers, selectedProvider), + SelectedProvider: selectedProvider, + } + l.renderer.RenderTemplate(w, r, l.getTranslator(r.Context(), authReq), l.renderer.Templates[tmplOTPVerification], data, nil) +} + +// handleOTPVerificationCheck handles form submissions of the OTP verification. +// On successful code verification, the check will be added to the auth request. +// A user is also able to request a code resend or choose another provider. +func (l *Login) handleOTPVerificationCheck(w http.ResponseWriter, r *http.Request) { + formData := new(mfaOTPFormData) + authReq, err := l.getAuthRequestAndParseData(r, formData) + if err != nil { + l.renderError(w, r, authReq, err) + return + } + step, ok := authReq.PossibleSteps[0].(*domain.MFAVerificationStep) + if !ok { + l.renderError(w, r, authReq, err) + return + } + if formData.Resend { + l.handleOTPVerification(w, r, authReq, step.MFAProviders, formData.SelectedProvider, nil) + return + } + if formData.Code == "" { + l.renderMFAVerifySelected(w, r, authReq, step, formData.Provider, nil) + return + } + userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) + var actionType authMethod + var verifyCode func(ctx context.Context, userID, resourceOwner, code, authRequestID, userAgentID string, info *domain.BrowserInfo) error + switch formData.SelectedProvider { + case domain.MFATypeOTPSMS: + actionType = authMethodOTPSMS + verifyCode = l.authRepo.VerifyMFAOTPSMS + case domain.MFATypeOTPEmail: + actionType = authMethodOTPEmail + verifyCode = l.authRepo.VerifyMFAOTPEmail + // another type should never be passed, but just making sure + case domain.MFATypeU2F, + domain.MFATypeTOTP, + domain.MFATypeU2FUserVerification: + l.renderOTPVerification(w, r, authReq, step.MFAProviders, formData.SelectedProvider, err) + return + } + err = verifyCode(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, authReq.UserOrgID, formData.Code, authReq.ID, userAgentID, domain.BrowserInfoFromRequest(r)) + + metadata, actionErr := l.runPostInternalAuthenticationActions(authReq, r, actionType, err) + if err == nil && actionErr == nil && len(metadata) > 0 { + _, err = l.command.BulkSetUserMetadata(r.Context(), authReq.UserID, authReq.UserOrgID, metadata...) + } else if actionErr != nil && err == nil { + err = actionErr + } + + if err != nil { + l.renderOTPVerification(w, r, authReq, step.MFAProviders, formData.SelectedProvider, err) + return + } + l.renderNextStep(w, r, authReq) +} diff --git a/internal/api/ui/login/renderer.go b/internal/api/ui/login/renderer.go index bcbe4ad9af..29fed4eda6 100644 --- a/internal/api/ui/login/renderer.go +++ b/internal/api/ui/login/renderer.go @@ -54,9 +54,11 @@ func CreateRenderer(pathPrefix string, staticDir http.FileSystem, staticStorage tmplPasswordlessRegistration: "passwordless_registration.html", tmplPasswordlessRegistrationDone: "passwordless_registration_done.html", tmplPasswordlessPrompt: "passwordless_prompt.html", - tmplMFAVerify: "mfa_verify_otp.html", + tmplMFAVerify: "mfa_verify_totp.html", tmplMFAPrompt: "mfa_prompt.html", tmplMFAInitVerify: "mfa_init_otp.html", + tmplMFASMSInit: "mfa_init_otp_sms.html", + tmplOTPVerification: "mfa_verify_otp.html", tmplMFAU2FInit: "mfa_init_u2f.html", tmplU2FVerification: "mfa_verification_u2f.html", tmplMFAInitDone: "mfa_init_done.html", @@ -170,6 +172,12 @@ func CreateRenderer(pathPrefix string, staticDir http.FileSystem, staticStorage "mfaInitVerifyUrl": func() string { return path.Join(r.pathPrefix, EndpointMFAInitVerify) }, + "mfaInitSMSVerifyUrl": func() string { + return path.Join(r.pathPrefix, EndpointMFASMSInitVerify) + }, + "mfaOTPVerifyUrl": func() string { + return path.Join(r.pathPrefix, EndpointMFAOTPVerify) + }, "mfaInitU2FVerifyUrl": func() string { return path.Join(r.pathPrefix, EndpointMFAInitU2FVerify) }, diff --git a/internal/api/ui/login/router.go b/internal/api/ui/login/router.go index 8ad27d7573..62ac4d9af2 100644 --- a/internal/api/ui/login/router.go +++ b/internal/api/ui/login/router.go @@ -31,6 +31,8 @@ const ( EndpointMFAVerify = "/mfa/verify" EndpointMFAPrompt = "/mfa/prompt" EndpointMFAInitVerify = "/mfa/init/verify" + EndpointMFASMSInitVerify = "/mfa/init/sms/verify" + EndpointMFAOTPVerify = "/mfa/otp/verify" EndpointMFAInitU2FVerify = "/mfa/init/u2f/verify" EndpointU2FVerification = "/mfa/u2f/verify" EndpointMailVerification = "/mail/verification" @@ -89,6 +91,9 @@ func CreateRouter(login *Login, staticDir http.FileSystem, interceptors ...mux.M router.HandleFunc(EndpointMFAPrompt, login.handleMFAPromptSelection).Methods(http.MethodGet) router.HandleFunc(EndpointMFAPrompt, login.handleMFAPrompt).Methods(http.MethodPost) router.HandleFunc(EndpointMFAInitVerify, login.handleMFAInitVerify).Methods(http.MethodPost) + router.HandleFunc(EndpointMFASMSInitVerify, login.handleRegisterSMSCheck).Methods(http.MethodPost) + router.HandleFunc(EndpointMFAOTPVerify, login.handleOTPVerificationCheck).Methods(http.MethodGet) + router.HandleFunc(EndpointMFAOTPVerify, login.handleOTPVerificationCheck).Methods(http.MethodPost) router.HandleFunc(EndpointMFAInitU2FVerify, login.handleRegisterU2F).Methods(http.MethodPost) router.HandleFunc(EndpointU2FVerification, login.handleU2FVerification).Methods(http.MethodPost) router.HandleFunc(EndpointMailVerification, login.handleMailVerification).Methods(http.MethodGet) diff --git a/internal/api/ui/login/static/i18n/bg.yaml b/internal/api/ui/login/static/i18n/bg.yaml index 33e963c63d..ab1ebe768b 100644 --- a/internal/api/ui/login/static/i18n/bg.yaml +++ b/internal/api/ui/login/static/i18n/bg.yaml @@ -85,6 +85,8 @@ InitMFAPrompt: потребителски акаунт. Provider0: 'Приложение за удостоверяване (напр. Google/Microsoft Authenticator, Authy)' Provider1: 'Зависи от устройството (напр. FaceID, Windows Hello, пръстов отпечатък)' + Provider3: OTP SMS + Provider4: OTP имейл NextButtonText: следващия SkipButtonText: пропуснете InitMFAOTP: @@ -98,6 +100,15 @@ InitMFAOTP: CodeLabel: Код NextButtonText: следващия CancelButtonText: анулиране +InitMFAOTPSMS: + Title: 2-факторна проверка + DescriptionPhone: Създайте своя 2-фактор. Въведете телефонния си номер, за да го потвърдите. + DescriptionCode: Създайте своя 2-фактор. Въведете получения код, за да потвърдите своя телефонен номер. + PhoneLabel: Тайна + CodeLabel: Код + EditButtonText: редактиране + ResendButtonText: код за препращане + NextButtonText: следващия InitMFAU2F: Title: Добавете ключ за сигурност Description: >- @@ -118,6 +129,8 @@ InitMFADone: MFAProvider: Provider0: 'Приложение за удостоверяване (напр. Google/Microsoft Authenticator, Authy)' Provider1: 'Зависи от устройството (напр. FaceID, Windows Hello, пръстов отпечатък)' + Provider3: OTP SMS + Provider4: OTP имейл ChooseOther: или изберете друга опция VerifyMFAOTP: Title: Проверете 2-фактора diff --git a/internal/api/ui/login/static/i18n/de.yaml b/internal/api/ui/login/static/i18n/de.yaml index 490d9ebc08..eb39591eae 100644 --- a/internal/api/ui/login/static/i18n/de.yaml +++ b/internal/api/ui/login/static/i18n/de.yaml @@ -89,6 +89,8 @@ InitMFAPrompt: Description: 2-Faktor-Authentifizierung gibt dir eine zusätzliche Sicherheit für dein Benutzerkonto. Damit stellst du sicher, dass nur du Zugriff auf deinen Account hast. Provider0: Authenticator App (e.g Google/Microsoft Authenticator, Authy) Provider1: Geräte abhängig (e.g FaceID, Windows Hello, Fingerprint) + Provider3: OTP SMS + Provider4: OTP Email NextButtonText: weiter SkipButtonText: überspringen @@ -101,6 +103,16 @@ InitMFAOTP: NextButtonText: weiter CancelButtonText: abbrechen +InitMFAOTPSMS: + Title: 2-Faktor hinzufügen + DescriptionPhone: Erstelle deinen 2-Faktor. Gib deine Telefonnummer ein, um sie zu verifizieren. + DescriptionCode: Erstelle deinen 2-Faktor. Gib den erhaltenen Code ein um deinen Telefonnummer zu verifizieren. + PhoneLabel: Telefonnummer + CodeLabel: Code + EditButtonText: bearbeiten + ResendButtonText: Code erneut senden + NextButtonText: weiter + InitMFAU2F: Title: Sicherheitsschlüssel hinzufügen Description: Ein Sicherheitsschlüssel ist eine Verifizierungsmethode, die in Ihrem Telefon integriert sein kann, Bluetooth verwenden oder direkt an den USB-Anschluss Ihres Computers angeschlossen werden. @@ -118,9 +130,18 @@ InitMFADone: MFAProvider: Provider0: Authenticator App (e.g Google/Microsoft Authenticator, Authy) Provider1: Geräte abhängig (e.g FaceID, Windows Hello, Fingerprint) + Provider3: OTP SMS + Provider4: OTP Email ChooseOther: oder wähle eine andere Option aus VerifyMFAOTP: + Title: 2-Faktor verifizieren + Description: Verifiziere deinen Zweitfaktor + CodeLabel: Code + ResendButtonText: Code erneut senden + NextButtonText: next + +VerifyOTP: Title: 2-Faktor verifizieren Description: Verifiziere deinen Zweitfaktor CodeLabel: Code diff --git a/internal/api/ui/login/static/i18n/en.yaml b/internal/api/ui/login/static/i18n/en.yaml index 76c7e0ff0e..b174ef74b6 100644 --- a/internal/api/ui/login/static/i18n/en.yaml +++ b/internal/api/ui/login/static/i18n/en.yaml @@ -89,6 +89,8 @@ InitMFAPrompt: Description: 2-factor authentication gives you an additional security for your user account. This ensures that only you have access to your account. Provider0: Authenticator App (e.g Google/Microsoft Authenticator, Authy) Provider1: Device dependent (e.g FaceID, Windows Hello, Fingerprint) + Provider3: OTP SMS + Provider4: OTP Email NextButtonText: next SkipButtonText: skip @@ -101,6 +103,16 @@ InitMFAOTP: NextButtonText: next CancelButtonText: cancel +InitMFAOTPSMS: + Title: 2-Factor Verification + DescriptionPhone: Create your 2-factor. Enter your phone number to verify it. + DescriptionCode: Create your 2-factor. Enter the received code to verify your phone number. + PhoneLabel: Phone + CodeLabel: Code + EditButtonText: edit + ResendButtonText: resend code + NextButtonText: next + InitMFAU2F: Title: Add security key Description: A security key is a verification method that can be built into your phone, use Bluetooth, or plug directly into your computer's USB port. @@ -110,7 +122,7 @@ InitMFAU2F: ErrorRetry: Retry, create a new challenge or choose a different method. InitMFADone: - Title: Security key verified + Title: 2-factor verified Description: Awesome! You just successfully set up your 2-factor and made your account way more secure. The Factor has to be entered on each login. NextButtonText: next CancelButtonText: cancel @@ -118,6 +130,8 @@ InitMFADone: MFAProvider: Provider0: Authenticator App (e.g Google/Microsoft Authenticator, Authy) Provider1: Device dependent (e.g FaceID, Windows Hello, Fingerprint) + Provider3: OTP SMS + Provider4: OTP Email ChooseOther: or choose another option VerifyMFAOTP: @@ -126,6 +140,13 @@ VerifyMFAOTP: CodeLabel: Code NextButtonText: next +VerifyOTP: + Title: Verify 2-Factor + Description: Verify your second factor + CodeLabel: Code + ResendButtonText: resend code + NextButtonText: next + VerifyMFAU2F: Title: 2-Factor Verification Description: Verify your 2-Factor with the registered device (e.g FaceID, Windows Hello, Fingerprint) diff --git a/internal/api/ui/login/static/i18n/es.yaml b/internal/api/ui/login/static/i18n/es.yaml index ed98842db9..3d41001a58 100644 --- a/internal/api/ui/login/static/i18n/es.yaml +++ b/internal/api/ui/login/static/i18n/es.yaml @@ -89,6 +89,8 @@ InitMFAPrompt: Description: La autenticación de doble factor te proporciona seguridad adicional para tu cuenta de usuario. Ésta asegura que solo tú tienes acceso a tu cuenta. Provider0: App autenticadora (p.e Google/Microsoft Authenticator, Authy) Provider1: Dependiente de un dispositivo (p.e FaceID, Windows Hello, Huella dactilar) + Provider3: OTP SMS + Provider4: OTP email NextButtonText: siguiente SkipButtonText: saltar @@ -101,6 +103,16 @@ InitMFAOTP: NextButtonText: siguiente CancelButtonText: cancelar +InitMFASMS: + Title: Verificación de doble factor + DescriptionPhone: Crea tu doble factor de autenticación. Introduce tu número de teléfono para verificarlo. + DescriptionCode: Crea tu doble factor de autenticación. Ingrese el código recibido para verificar su número de teléfono. + PhoneLabel: Número de teléfono + CodeLabel: Código + EditButtonText: editar + ResendButtonText: reenviar código + NextButtonText: siguiente + InitMFAU2F: Title: Añadir clave de seguridad Description: Una clave de seguridad es un método de verificación que puede integrarse en tu teléfono móvil, con Bluetooth, o conectándolo directamente en el puerto USB de tu ordenador. @@ -118,6 +130,8 @@ InitMFADone: MFAProvider: Provider0: App autenticadora (p.e Google/Microsoft Authenticator, Authy) Provider1: Dependiente de un dispositivo (p.e FaceID, Windows Hello, Huella dactilar) + Provider3: OTP SMS + Provider4: OTP email ChooseOther: o elige otra opción VerifyMFAOTP: diff --git a/internal/api/ui/login/static/i18n/fr.yaml b/internal/api/ui/login/static/i18n/fr.yaml index 29db5b3e2c..95a58d2825 100644 --- a/internal/api/ui/login/static/i18n/fr.yaml +++ b/internal/api/ui/login/static/i18n/fr.yaml @@ -89,6 +89,8 @@ InitMFAPrompt: Description: L'authentification à deux facteurs vous offre une sécurité supplémentaire pour votre compte d'utilisateur. Vous êtes ainsi assuré d'être le seul à avoir accès à votre compte. Provider0: Application d'authentification (par exemple, Google/Microsoft Authenticator, Authy) Provider1: Dépend de l'appareil (par ex. FaceID, Windows Hello, empreinte digitale) + Provider3: OTP SMS + Provider4: OTP e-mail NextButtonText: Suivant SkipButtonText: Passer @@ -101,6 +103,16 @@ InitMFAOTP: NextButtonText: Suivant CancelButtonText: Annuler +InitMFASMS: + Title: Vérification à deux facteurs + DescriptionPhone: Créez votre 2-facteurs. Entrez votre numéro de téléphone pour le vérifier. + DescriptionCode: Créez votre 2-facteurs. Entrez le code reçu pour vérifier votre numéro de téléphone. + PhoneLabel: Numéro de téléphone + CodeLabel: Code + EditButtonText: Modifier + ResendButtonText: Renvoyer le code + NextButtonText: Suivant + InitMFAU2F: Title: Ajouter une clé de sécurité Description: Une clé de sécurité est une méthode de vérification qui peut être intégrée à votre téléphone, utiliser Bluetooth ou se brancher directement sur le port USB de votre ordinateur. @@ -118,6 +130,8 @@ InitMFADone: MFAProvider: Provider0: Application d'authentification (par exemple, Google/Microsoft Authenticator, Authy) Provider1: Dépend de l'appareil (par ex. FaceID, Windows Hello, empreinte digitale) + Provider3: OTP SMS + Provider4: OTP e-mail ChooseOther: ou choisissez une autre option VerifyMFAOTP: diff --git a/internal/api/ui/login/static/i18n/it.yaml b/internal/api/ui/login/static/i18n/it.yaml index 5e998c2e54..3ed763f3e7 100644 --- a/internal/api/ui/login/static/i18n/it.yaml +++ b/internal/api/ui/login/static/i18n/it.yaml @@ -89,6 +89,8 @@ InitMFAPrompt: Description: L'autenticazione a due fattori offre un'ulteriore sicurezza al vostro account utente. Questo garantisce che solo voi possiate accedere al vostro account. Provider0: App Autenticatore (ad esempio Google/Microsoft Authenticator, Authy) Provider1: Dipende dal dispositivo (ad es. FaceID, Windows Hello, impronta digitale) + Provider3: OTP SMS + Provider4: OTP e-mail NextButtonText: Avanti SkipButtonText: salta @@ -101,6 +103,16 @@ InitMFAOTP: NextButtonText: Avanti CancelButtonText: annulla +InitMFASMS: + Title: Verificazione a 2 fattori + DescriptionPhone: Crea il tuo 2 fattori. Inserisci il tuo numero di telefono per verificarlo. + DescriptionCode: Crea il tuo 2 fattori. Inserisci il codice ricevuto per verificare il tuo numero di telefono. + PhoneLabel: Numero di telefono + CodeLabel: Codice + EditButtonText: Modifica + ResendButtonText: Reinvia codice + NextButtonText: Avanti + InitMFAU2F: Title: Aggiungi chiave di sicurezza Description: Una chiave di sicurezza è un metodo di verifica che può essere integrato nel telefono, utilizzare il Bluetooth o collegarlo direttamente alla porta USB del computer. @@ -118,6 +130,8 @@ InitMFADone: MFAProvider: Provider0: App Autenticatore (ad esempio Google/Microsoft Authenticator, Authy) Provider1: Dipende dal dispositivo (ad es. FaceID, Windows Hello, impronta digitale) + Provider3: OTP SMS + Provider4: OTP e-mail ChooseOther: o scegli un'altra opzione VerifyMFAOTP: diff --git a/internal/api/ui/login/static/i18n/ja.yaml b/internal/api/ui/login/static/i18n/ja.yaml index f51a1ca3d1..c43975f544 100644 --- a/internal/api/ui/login/static/i18n/ja.yaml +++ b/internal/api/ui/login/static/i18n/ja.yaml @@ -82,6 +82,8 @@ InitMFAPrompt: Description: 二要素認証でアカウントのセキュリティを強化します。 Provider0: 認証アプリ(Google/Microsoft Authenticator、Authyなど) Provider1: デバイス依存(例:FaceID、Windows Hello、指紋など) + Provider3: OTP SMS + Provider4: OTPメール NextButtonText: 次へ SkipButtonText: スキップ @@ -94,6 +96,16 @@ InitMFAOTP: NextButtonText: 次へ CancelButtonText: キャンセル +InitMFASMS: + Title: 二要素認証 + DescriptionPhone: 二要素認証を作成します。確認するには電話番号を入力してください。 + DescriptionCode: 二要素認証を作成します。受信したコードを入力して電話番号を確認します。 + PhoneLabel: 電話番号 + CodeLabel: コード + EditButtonText: 編集 + ResendButtonText: コードを再送信 + NextButtonText: 次へ + InitMFAU2F: Title: セキュリティキーの追加 Description: セキュリティキーは、携帯電話への組み込みや、Bluetoothの使用、パソコンのUSBポートに直接差し込むことなどで認証する方法です。 @@ -111,6 +123,8 @@ InitMFADone: MFAProvider: Provider0: Authenticatorアプリ(Google/Microsoft Authenticator、Authyなど) Provider1: デバイス依存(FaceID、Windows Hello、指紋など) + Provider3: OTP SMS + Provider4: OTPメール ChooseOther: または、他のオプションを選択 VerifyMFAOTP: diff --git a/internal/api/ui/login/static/i18n/mk.yaml b/internal/api/ui/login/static/i18n/mk.yaml index 217ab7e2f6..e0a8c20d8b 100644 --- a/internal/api/ui/login/static/i18n/mk.yaml +++ b/internal/api/ui/login/static/i18n/mk.yaml @@ -89,6 +89,8 @@ InitMFAPrompt: Description: 2-факторската автентикација ви дава дополнителна безбедност за вашата корисничка сметка. Ова обезбедува само вие да имате пристап до вашата сметка. Provider0: Апликација за автентикација (на пример Google/Microsoft Authenticator, Authy) Provider1: Во зависност од вашиот уред (на пример FaceID, Windows Hello, отпечаток од прст) + Provider3: ОТП СМС + Provider4: ОТП е-пошта NextButtonText: следно SkipButtonText: прескокни @@ -101,6 +103,16 @@ InitMFAOTP: NextButtonText: следно CancelButtonText: откажи +InitMFASMS: + Title: Потврда на 2-факторска автентикација + DescriptionPhone: Направете двофакторна автентикација. Внесете го вашиот телефонски број за да го потврдите. + DescriptionCode: Направете двофакторна автентикација. Внесете го примениот код за да го потврдите вашиот телефонски број. + PhoneLabel: Телефонски број + CodeLabel: Код + EditButtonText: Уредување + ResendButtonText: повторно испрати код + NextButtonText: следно + InitMFAU2F: Title: Додајте безбедносен клуч Description: Безбедносниот клуч е метод на верификација кој може да се интегрира во вашиот телефон, да користи Bluetooth или директно да се поврзе во USB приклучокот на вашиот компјутер. @@ -118,6 +130,8 @@ InitMFADone: MFAProvider: Provider0: Апликација за автентикација (на пример Google/Microsoft Authenticator, Authy) Provider1: Во зависност од вашиот уред (на пример FaceID, Windows Hello, отпечаток од прст) + Provider3: ОТП СМС + Provider4: ОТП е-пошта ChooseOther: или изберете друга опција VerifyMFAOTP: diff --git a/internal/api/ui/login/static/i18n/pl.yaml b/internal/api/ui/login/static/i18n/pl.yaml index 8561cec9e3..38c4b28602 100644 --- a/internal/api/ui/login/static/i18n/pl.yaml +++ b/internal/api/ui/login/static/i18n/pl.yaml @@ -89,6 +89,8 @@ InitMFAPrompt: Description: 2-etapowe uwierzytelnianie daje Ci dodatkową ochronę dla Twojego konta użytkownika. Dzięki temu masz pewność, że tylko Ty masz dostęp do swojego konta. Provider0: Aplikacja uwierzytelniająca (np. Google/Microsoft Authenticator, Authy) Provider1: Zależny od urządzenia (np. FaceID, Windows Hello, Odcisk palca) + Provider3: OTP SMS + Provider4: OTP e-mail NextButtonText: dalej SkipButtonText: pomiń @@ -101,6 +103,16 @@ InitMFAOTP: NextButtonText: dalej CancelButtonText: anuluj +InitMFASMS: + Title: Weryfikacja 2-etapowa + DescriptionPhone: Utwórz uwierzytelnianie dwuskładnikowe. Wprowadź swój numer telefonu, aby go zweryfikować. + DescriptionCode: Utwórz uwierzytelnianie dwuskładnikowe. Wprowadź otrzymany kod, aby zweryfikować swój numer telefonu. + PhoneLabel: Numer telefonu + CodeLabel: Kod + EditButtonText: edytować + ResendButtonText: wyślij kod ponownie + NextButtonText: dalej + InitMFAU2F: Title: Dodaj klucz zabezpieczeń Description: Klucz zabezpieczeń to metoda weryfikacji, która może być zintegrowana z twoim telefonem, używająca Bluetooth lub podłączana bezpośrednio do portu USB komputera. @@ -118,6 +130,8 @@ InitMFADone: MFAProvider: Provider0: Aplikacja uwierzytelniająca (np. Google/Microsoft Authenticator, Authy) Provider1: Zależny od urządzenia (np. FaceID, Windows Hello, Odcisk palca) + Provider3: OTP SMS + Provider4: OTP e-mail ChooseOther: lub wybierz inną opcję VerifyMFAOTP: diff --git a/internal/api/ui/login/static/i18n/pt.yaml b/internal/api/ui/login/static/i18n/pt.yaml index 42c6c27a0f..54d65fb1e4 100644 --- a/internal/api/ui/login/static/i18n/pt.yaml +++ b/internal/api/ui/login/static/i18n/pt.yaml @@ -89,6 +89,8 @@ InitMFAPrompt: Description: A autenticação de 2 fatores fornece uma segurança adicional para sua conta de usuário. Isso garante que apenas você tenha acesso à sua conta. Provider0: Aplicativo de autenticação (por exemplo, Google/Microsoft Authenticator, Authy) Provider1: Dependente do dispositivo (por exemplo, FaceID, Windows Hello, Impressão digital) + Provider3: OTP SMS + Provider4: OTP e-mail NextButtonText: próximo SkipButtonText: pular @@ -101,6 +103,16 @@ InitMFAOTP: NextButtonText: próximo CancelButtonText: cancelar +InitMFASMS: + Title: Verificação de 2 fatores + DescriptionPhone: Crie sua verificação de 2 fatores. Digite seu número de telefone para verificá-lo. + DescriptionCode: Crie sua verificação de 2 fatores. Digite o código recebido para verificar seu número de telefone. + PhoneLabel: Número de telefone + CodeLabel: Código + EditButtonText: editar + ResendButtonText: reenviar código + NextButtonText: próximo + InitMFAU2F: Title: Adicionar chave de segurança Description: Uma chave de segurança é um método de verificação que pode ser incorporado ao seu telefone, usar Bluetooth ou conectar diretamente à porta USB do seu computador. @@ -118,6 +130,8 @@ InitMFADone: MFAProvider: Provider0: Aplicativo de autenticação (por exemplo, Google/Microsoft Authenticator, Authy) Provider1: Dependente do dispositivo (por exemplo, FaceID, Windows Hello, Impressão digital) + Provider3: OTP SMS + Provider4: OTP e-mail ChooseOther: ou escolha outra opção VerifyMFAOTP: diff --git a/internal/api/ui/login/static/i18n/zh.yaml b/internal/api/ui/login/static/i18n/zh.yaml index 204e1a45ad..e2c0f2e437 100644 --- a/internal/api/ui/login/static/i18n/zh.yaml +++ b/internal/api/ui/login/static/i18n/zh.yaml @@ -89,6 +89,8 @@ InitMFAPrompt: Description: 两步验证为您的账户提供了额外的安全保障。这确保只有你能访问你的账户。 Provider0: 软件应用(如 Google/Migrosoft Authenticator、Authy) Provider1: 硬件设备(如 Face ID、Windows Hello、指纹) + Provider3: 一次性密码短信 + Provider4: 一次性密码电子邮件 NextButtonText: 继续 SkipButtonText: 跳过 @@ -96,6 +98,16 @@ InitMFAOTP: Title: 双因素验证 Description: 创建你的双因素。如果你还没有,请下载一个认证器应用程序。 OTPDescription: 使用您的身份验证器应用程序(例如 Google Authenticator)扫描代码或复制密码并在下方插入生成的代码。 + PhoneLabel: 电话号码 + CodeLabel: 验证码 + EditButtonText: 编辑 + ResendButtonText: 重发代码 + NextButtonText: 继续 + +InitMFASMS: + Title: 双因素验证 + DescriptionPhone: 创建双因素身份验证。输入您的电话号码进行验证。 + DescriptionCode: 创建双因素身份验证。输入收到的代码以验证您的电话号码。 SecretLabel: 秘钥 CodeLabel: 验证码 NextButtonText: 继续 @@ -118,6 +130,8 @@ InitMFADone: MFAProvider: Provider0: 软件应用(如 Google/Migrosoft Authenticator、Authy) Provider1: 硬件设备(如 Face ID、Windows Hello、指纹) + Provider3: 一次性密码短信 + Provider4: 一次性密码电子邮件 ChooseOther: 或选择其他选项 VerifyMFAOTP: diff --git a/internal/api/ui/login/static/resources/scripts/edit.js b/internal/api/ui/login/static/resources/scripts/edit.js new file mode 100644 index 0000000000..562e3effa4 --- /dev/null +++ b/internal/api/ui/login/static/resources/scripts/edit.js @@ -0,0 +1,6 @@ +let form = document.getElementsByTagName('form')[0]; +let editButton = document.getElementById('edit'); +editButton.addEventListener('click', function () { + form.submit(); +}); + diff --git a/internal/api/ui/login/static/resources/themes/scss/styles/mfa/mfa_base.scss b/internal/api/ui/login/static/resources/themes/scss/styles/mfa/mfa_base.scss index 040f6aaf5c..baba57416e 100644 --- a/internal/api/ui/login/static/resources/themes/scss/styles/mfa/mfa_base.scss +++ b/internal/api/ui/login/static/resources/themes/scss/styles/mfa/mfa_base.scss @@ -1,15 +1,16 @@ @mixin lgn-mfa-base { display: flex; flex-direction: row; + flex-wrap: wrap; justify-content: space-evenly; - margin: 2rem 0; + margin: 1rem 0; .mfa { display: flex; flex-direction: column; align-items: center; flex: 1; - padding: 0 0.5rem; + padding: 1rem 0.5rem; label { display: flex; diff --git a/internal/api/ui/login/static/templates/mfa_init_otp_sms.html b/internal/api/ui/login/static/templates/mfa_init_otp_sms.html new file mode 100644 index 0000000000..e409096c55 --- /dev/null +++ b/internal/api/ui/login/static/templates/mfa_init_otp_sms.html @@ -0,0 +1,63 @@ +{{template "main-top" .}} + +
+

{{t "InitMFAOTPSMS.Title"}}

+ + {{ template "user-profile" . }} + + {{if .Edit}} +

{{t "InitMFAOTPSMS.DescriptionPhone"}}

+ {{else}} +

{{t "InitMFAOTPSMS.DescriptionCode"}}

+ {{end}} +
+ +
+ + {{ .CSRF }} + + + + + +
+ {{if .Edit}} +
+ + +
+ {{else}} +
+

{{.Phone}}

+ + +
+ {{end}} + {{if and .Phone (not .Edit) }} +
+ + +
+ {{end}} +
+ + {{ template "error-message" .}} + +
+ + + + + + {{if and .Phone (not .Edit) }} + + + {{end}} +
+
+ + + + + +{{template "main-bottom" .}} diff --git a/internal/api/ui/login/static/templates/mfa_prompt.html b/internal/api/ui/login/static/templates/mfa_prompt.html index f6f9366483..17170eb0bb 100644 --- a/internal/api/ui/login/static/templates/mfa_prompt.html +++ b/internal/api/ui/login/static/templates/mfa_prompt.html @@ -34,6 +34,16 @@ OTP

+ {{ end }} {{ if eq $provider 3 }} +
+ OTP SMS // TODO: image +
+ {{ end }}{{ if eq $provider 4 }} +
+ OTP Email // TODO: image +
{{ end }} {{ $providerName }} diff --git a/internal/api/ui/login/static/templates/mfa_verify_otp.html b/internal/api/ui/login/static/templates/mfa_verify_otp.html index 345391660d..95046ba45a 100644 --- a/internal/api/ui/login/static/templates/mfa_verify_otp.html +++ b/internal/api/ui/login/static/templates/mfa_verify_otp.html @@ -1,34 +1,37 @@ {{template "main-top" .}}
-

{{t "VerifyMFAOTP.Title"}}

+

{{t "VerifyOTP.Title"}}

{{ template "user-profile" . }} -

{{t "VerifyMFAOTP.Description"}}

+

{{t "VerifyOTP.Description"}}

-
+ {{ .CSRF }} - +
- - + +
{{ template "error-message" .}} -
+
+ + - + +
{{ if .MFAProviders }} @@ -45,4 +48,4 @@ -{{template "main-bottom" .}} \ No newline at end of file +{{template "main-bottom" .}} diff --git a/internal/api/ui/login/static/templates/mfa_verify_totp.html b/internal/api/ui/login/static/templates/mfa_verify_totp.html new file mode 100644 index 0000000000..345391660d --- /dev/null +++ b/internal/api/ui/login/static/templates/mfa_verify_totp.html @@ -0,0 +1,48 @@ +{{template "main-top" .}} + +
+

{{t "VerifyMFAOTP.Title"}}

+ + {{ template "user-profile" . }} + +

{{t "VerifyMFAOTP.Description"}}

+
+ + + + {{ .CSRF }} + + + + +
+ + +
+ + {{ template "error-message" .}} + +
+ + + + + + +
+ + {{ if .MFAProviders }} +
+

{{t "MFAProvider.ChooseOther"}}

+ {{ range $provider := .MFAProviders}} + {{ $providerName := (t (printf "MFAProvider.Provider%v" $provider)) }} + + {{ end }} +
+ {{ end }} + + + + +{{template "main-bottom" .}} \ No newline at end of file diff --git a/internal/auth/repository/auth_request.go b/internal/auth/repository/auth_request.go index 8851b4f67e..db22705050 100644 --- a/internal/auth/repository/auth_request.go +++ b/internal/auth/repository/auth_request.go @@ -23,6 +23,10 @@ type AuthRequestRepository interface { VerifyPassword(ctx context.Context, id, userID, resourceOwner, password, userAgentID string, info *domain.BrowserInfo) error VerifyMFAOTP(ctx context.Context, authRequestID, userID, resourceOwner, code, userAgentID string, info *domain.BrowserInfo) error + SendMFAOTPSMS(ctx context.Context, userID, resourceOwner, authRequestID, userAgentID string) error + VerifyMFAOTPSMS(ctx context.Context, userID, resourceOwner, code, authRequestID, userAgentID string, info *domain.BrowserInfo) error + SendMFAOTPEmail(ctx context.Context, userID, resourceOwner, authRequestID, userAgentID string) error + VerifyMFAOTPEmail(ctx context.Context, userID, resourceOwner, code, authRequestID, userAgentID string, info *domain.BrowserInfo) error BeginMFAU2FLogin(ctx context.Context, userID, resourceOwner, authRequestID, userAgentID string) (*domain.WebAuthNLogin, error) VerifyMFAU2F(ctx context.Context, userID, resourceOwner, authRequestID, userAgentID string, credentialData []byte, info *domain.BrowserInfo) error BeginPasswordlessSetup(ctx context.Context, userID, resourceOwner string, preferredPlatformType domain.AuthenticatorAttachment) (login *domain.WebAuthNToken, err error) diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request.go b/internal/auth/repository/eventsourcing/eventstore/auth_request.go index 80be2a8e3b..0bfa0fe829 100644 --- a/internal/auth/repository/eventsourcing/eventstore/auth_request.go +++ b/internal/auth/repository/eventsourcing/eventstore/auth_request.go @@ -376,6 +376,48 @@ func (repo *AuthRequestRepo) VerifyMFAOTP(ctx context.Context, authRequestID, us return repo.Command.HumanCheckMFATOTP(ctx, userID, code, resourceOwner, request.WithCurrentInfo(info)) } +func (repo *AuthRequestRepo) SendMFAOTPSMS(ctx context.Context, userID, resourceOwner, authRequestID, userAgentID string) (err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + + request, err := repo.getAuthRequestEnsureUser(ctx, authRequestID, userAgentID, userID) + if err != nil { + return err + } + return repo.Command.HumanSendOTPSMS(ctx, userID, resourceOwner, request) +} + +func (repo *AuthRequestRepo) VerifyMFAOTPSMS(ctx context.Context, userID, resourceOwner, code, authRequestID, userAgentID string, info *domain.BrowserInfo) (err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + request, err := repo.getAuthRequestEnsureUser(ctx, authRequestID, userAgentID, userID) + if err != nil { + return err + } + return repo.Command.HumanCheckOTPSMS(ctx, userID, code, resourceOwner, request.WithCurrentInfo(info)) +} + +func (repo *AuthRequestRepo) SendMFAOTPEmail(ctx context.Context, userID, resourceOwner, authRequestID, userAgentID string) (err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + + request, err := repo.getAuthRequestEnsureUser(ctx, authRequestID, userAgentID, userID) + if err != nil { + return err + } + return repo.Command.HumanSendOTPEmail(ctx, userID, resourceOwner, request) +} + +func (repo *AuthRequestRepo) VerifyMFAOTPEmail(ctx context.Context, userID, resourceOwner, code, authRequestID, userAgentID string, info *domain.BrowserInfo) (err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + request, err := repo.getAuthRequestEnsureUser(ctx, authRequestID, userAgentID, userID) + if err != nil { + return err + } + return repo.Command.HumanCheckOTPEmail(ctx, userID, code, resourceOwner, request.WithCurrentInfo(info)) +} + func (repo *AuthRequestRepo) BeginMFAU2FLogin(ctx context.Context, userID, resourceOwner, authRequestID, userAgentID string) (login *domain.WebAuthNLogin, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() diff --git a/internal/auth/repository/eventsourcing/handler/user.go b/internal/auth/repository/eventsourcing/handler/user.go index 847f483ea6..4224a0ca6c 100644 --- a/internal/auth/repository/eventsourcing/handler/user.go +++ b/internal/auth/repository/eventsourcing/handler/user.go @@ -138,6 +138,10 @@ func (u *User) ProcessUser(event *es_models.Event) (err error) { user_repo.HumanMFAOTPAddedType, user_repo.HumanMFAOTPVerifiedType, user_repo.HumanMFAOTPRemovedType, + user_repo.HumanOTPSMSAddedType, + user_repo.HumanOTPSMSRemovedType, + user_repo.HumanOTPEmailAddedType, + user_repo.HumanOTPEmailRemovedType, user_repo.HumanU2FTokenAddedType, user_repo.HumanU2FTokenVerifiedType, user_repo.HumanU2FTokenRemovedType, diff --git a/internal/command/user_converter.go b/internal/command/user_converter.go index 7febe68530..076b0bfd52 100644 --- a/internal/command/user_converter.go +++ b/internal/command/user_converter.go @@ -137,6 +137,9 @@ func writeModelToWebAuthN(wm *HumanWebAuthNWriteModel) *domain.WebAuthNToken { } func authRequestDomainToAuthRequestInfo(authRequest *domain.AuthRequest) *user.AuthRequestInfo { + if authRequest == nil { + return nil + } info := &user.AuthRequestInfo{ ID: authRequest.ID, UserAgentID: authRequest.AgentID, diff --git a/internal/command/user_human_otp.go b/internal/command/user_human_otp.go index a1f207b402..c3a8e84f09 100644 --- a/internal/command/user_human_otp.go +++ b/internal/command/user_human_otp.go @@ -2,6 +2,7 @@ package command import ( "context" + "time" "github.com/pquerna/otp" "github.com/zitadel/logging" @@ -15,16 +16,16 @@ import ( "github.com/zitadel/zitadel/internal/telemetry/tracing" ) -func (c *Commands) ImportHumanTOTP(ctx context.Context, userID, userAgentID, resourceowner string, key string) error { +func (c *Commands) ImportHumanTOTP(ctx context.Context, userID, userAgentID, resourceOwner string, key string) error { encryptedSecret, err := crypto.Encrypt([]byte(key), c.multifactors.OTP.CryptoMFA) if err != nil { return err } - if err = c.checkUserExists(ctx, userID, resourceowner); err != nil { + if err = c.checkUserExists(ctx, userID, resourceOwner); err != nil { return err } - otpWriteModel, err := c.totpWriteModelByID(ctx, userID, resourceowner) + otpWriteModel, err := c.totpWriteModelByID(ctx, userID, resourceOwner) if err != nil { return err } @@ -40,11 +41,11 @@ func (c *Commands) ImportHumanTOTP(ctx context.Context, userID, userAgentID, res return err } -func (c *Commands) AddHumanTOTP(ctx context.Context, userID, resourceowner string) (*domain.TOTP, error) { +func (c *Commands) AddHumanTOTP(ctx context.Context, userID, resourceOwner string) (*domain.TOTP, error) { if userID == "" { return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-5M0sd", "Errors.User.UserIDMissing") } - prep, err := c.createHumanTOTP(ctx, userID, resourceowner) + prep, err := c.createHumanTOTP(ctx, userID, resourceOwner) if err != nil { return nil, err } @@ -114,12 +115,12 @@ func (c *Commands) createHumanTOTP(ctx context.Context, userID, resourceOwner st }, nil } -func (c *Commands) HumanCheckMFATOTPSetup(ctx context.Context, userID, code, userAgentID, resourceowner string) (*domain.ObjectDetails, error) { +func (c *Commands) HumanCheckMFATOTPSetup(ctx context.Context, userID, code, userAgentID, resourceOwner string) (*domain.ObjectDetails, error) { if userID == "" { return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-8N9ds", "Errors.User.UserIDMissing") } - existingOTP, err := c.totpWriteModelByID(ctx, userID, resourceowner) + existingOTP, err := c.totpWriteModelByID(ctx, userID, resourceOwner) if err != nil { return nil, err } @@ -145,11 +146,11 @@ func (c *Commands) HumanCheckMFATOTPSetup(ctx context.Context, userID, code, use return writeModelToObjectDetails(&existingOTP.WriteModel), nil } -func (c *Commands) HumanCheckMFATOTP(ctx context.Context, userID, code, resourceowner string, authRequest *domain.AuthRequest) error { +func (c *Commands) HumanCheckMFATOTP(ctx context.Context, userID, code, resourceOwner string, authRequest *domain.AuthRequest) error { if userID == "" { return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-8N9ds", "Errors.User.UserIDMissing") } - existingOTP, err := c.totpWriteModelByID(ctx, userID, resourceowner) + existingOTP, err := c.totpWriteModelByID(ctx, userID, resourceOwner) if err != nil { return err } @@ -191,7 +192,26 @@ func (c *Commands) HumanRemoveTOTP(ctx context.Context, userID, resourceOwner st return writeModelToObjectDetails(&existingOTP.WriteModel), nil } +// AddHumanOTPSMS adds the OTP SMS factor to a user. +// It can only be added if it not already is and the phone has to be verified. func (c *Commands) AddHumanOTPSMS(ctx context.Context, userID, resourceOwner string) (*domain.ObjectDetails, error) { + return c.addHumanOTPSMS(ctx, userID, resourceOwner) +} + +// AddHumanOTPSMSWithCheckSucceeded adds the OTP SMS factor to a user. +// It can only be added if it's not already and the phone has to be verified. +// An OTPSMSCheckSucceededEvent will be added to the passed AuthRequest, if not nil. +func (c *Commands) AddHumanOTPSMSWithCheckSucceeded(ctx context.Context, userID, resourceOwner string, authRequest *domain.AuthRequest) (*domain.ObjectDetails, error) { + if authRequest == nil { + return c.addHumanOTPSMS(ctx, userID, resourceOwner) + } + event := func(ctx context.Context, userAgg *eventstore.Aggregate) eventstore.Command { + return user.NewHumanOTPSMSCheckSucceededEvent(ctx, userAgg, authRequestDomainToAuthRequestInfo(authRequest)) + } + return c.addHumanOTPSMS(ctx, userID, resourceOwner, event) +} + +func (c *Commands) addHumanOTPSMS(ctx context.Context, userID, resourceOwner string, events ...eventCallback) (*domain.ObjectDetails, error) { if userID == "" { return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-QSF2s", "Errors.User.UserIDMissing") } @@ -209,7 +229,12 @@ func (c *Commands) AddHumanOTPSMS(ctx context.Context, userID, resourceOwner str return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-Q54j2", "Errors.User.MFA.OTP.NotReady") } userAgg := UserAggregateFromWriteModel(&otpWriteModel.WriteModel) - if err = c.pushAppendAndReduce(ctx, otpWriteModel, user.NewHumanOTPSMSAddedEvent(ctx, userAgg)); err != nil { + cmds := make([]eventstore.Command, len(events)+1) + cmds[0] = user.NewHumanOTPSMSAddedEvent(ctx, userAgg) + for i, event := range events { + cmds[i+1] = event(ctx, userAgg) + } + if err = c.pushAppendAndReduce(ctx, otpWriteModel, cmds...); err != nil { return nil, err } return writeModelToObjectDetails(&otpWriteModel.WriteModel), nil @@ -225,7 +250,7 @@ func (c *Commands) RemoveHumanOTPSMS(ctx context.Context, userID, resourceOwner return nil, err } if userID != authz.GetCtxData(ctx).UserID { - if err := c.checkPermission(ctx, domain.PermissionUserWrite, existingOTP.ResourceOwner, userID); err != nil { + if err := c.checkPermission(ctx, domain.PermissionUserWrite, existingOTP.WriteModel.ResourceOwner, userID); err != nil { return nil, err } } @@ -239,7 +264,77 @@ func (c *Commands) RemoveHumanOTPSMS(ctx context.Context, userID, resourceOwner return writeModelToObjectDetails(&existingOTP.WriteModel), nil } +func (c *Commands) HumanSendOTPSMS(ctx context.Context, userID, resourceOwner string, authRequest *domain.AuthRequest) error { + smsWriteModel := func(ctx context.Context, userID string, resourceOwner string) (OTPWriteModel, error) { + return c.otpSMSWriteModelByID(ctx, userID, resourceOwner) + } + codeAddedEvent := func(ctx context.Context, aggregate *eventstore.Aggregate, code *crypto.CryptoValue, expiry time.Duration, info *user.AuthRequestInfo) eventstore.Command { + return user.NewHumanOTPSMSCodeAddedEvent(ctx, aggregate, code, expiry, info) + } + return c.sendHumanOTP( + ctx, + userID, + resourceOwner, + authRequest, + smsWriteModel, + domain.SecretGeneratorTypeOTPSMS, + codeAddedEvent, + ) +} + +func (c *Commands) HumanOTPSMSCodeSent(ctx context.Context, userID, resourceOwner string) (err error) { + smsWriteModel := func(ctx context.Context, userID string, resourceOwner string) (OTPWriteModel, error) { + return c.otpSMSWriteModelByID(ctx, userID, resourceOwner) + } + codeSentEvent := func(ctx context.Context, aggregate *eventstore.Aggregate) eventstore.Command { + return user.NewHumanOTPSMSCodeSentEvent(ctx, aggregate) + } + return c.humanOTPSent(ctx, userID, resourceOwner, smsWriteModel, codeSentEvent) +} + +func (c *Commands) HumanCheckOTPSMS(ctx context.Context, userID, code, resourceOwner string, authRequest *domain.AuthRequest) error { + writeModel := func(ctx context.Context, userID string, resourceOwner string) (OTPCodeWriteModel, error) { + return c.otpSMSCodeWriteModelByID(ctx, userID, resourceOwner) + } + succeededEvent := func(ctx context.Context, aggregate *eventstore.Aggregate, info *user.AuthRequestInfo) eventstore.Command { + return user.NewHumanOTPSMSCheckSucceededEvent(ctx, aggregate, authRequestDomainToAuthRequestInfo(authRequest)) + } + failedEvent := func(ctx context.Context, aggregate *eventstore.Aggregate, info *user.AuthRequestInfo) eventstore.Command { + return user.NewHumanOTPSMSCheckFailedEvent(ctx, aggregate, authRequestDomainToAuthRequestInfo(authRequest)) + } + return c.humanCheckOTP( + ctx, + userID, + code, + resourceOwner, + authRequest, + writeModel, + domain.SecretGeneratorTypeOTPSMS, + succeededEvent, + failedEvent, + ) +} + +// AddHumanOTPEmail adds the OTP Email factor to a user. +// It can only be added if it not already is and the phone has to be verified. func (c *Commands) AddHumanOTPEmail(ctx context.Context, userID, resourceOwner string) (*domain.ObjectDetails, error) { + return c.addHumanOTPEmail(ctx, userID, resourceOwner) +} + +// AddHumanOTPEmailWithCheckSucceeded adds the OTP Email factor to a user. +// It can only be added if it's not already and the email has to be verified. +// An OTPEmailCheckSucceededEvent will be added to the passed AuthRequest, if not nil. +func (c *Commands) AddHumanOTPEmailWithCheckSucceeded(ctx context.Context, userID, resourceOwner string, authRequest *domain.AuthRequest) (*domain.ObjectDetails, error) { + if authRequest == nil { + return c.addHumanOTPEmail(ctx, userID, resourceOwner) + } + event := func(ctx context.Context, userAgg *eventstore.Aggregate) eventstore.Command { + return user.NewHumanOTPEmailCheckSucceededEvent(ctx, userAgg, authRequestDomainToAuthRequestInfo(authRequest)) + } + return c.addHumanOTPEmail(ctx, userID, resourceOwner, event) +} + +func (c *Commands) addHumanOTPEmail(ctx context.Context, userID, resourceOwner string, events ...eventCallback) (*domain.ObjectDetails, error) { if userID == "" { return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-Sg1hz", "Errors.User.UserIDMissing") } @@ -254,7 +349,12 @@ func (c *Commands) AddHumanOTPEmail(ctx context.Context, userID, resourceOwner s return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-KLJ2d", "Errors.User.MFA.OTP.NotReady") } userAgg := UserAggregateFromWriteModel(&otpWriteModel.WriteModel) - if err = c.pushAppendAndReduce(ctx, otpWriteModel, user.NewHumanOTPEmailAddedEvent(ctx, userAgg)); err != nil { + cmds := make([]eventstore.Command, len(events)+1) + cmds[0] = user.NewHumanOTPEmailAddedEvent(ctx, userAgg) + for i, event := range events { + cmds[i+1] = event(ctx, userAgg) + } + if err = c.pushAppendAndReduce(ctx, otpWriteModel, cmds...); err != nil { return nil, err } return writeModelToObjectDetails(&otpWriteModel.WriteModel), nil @@ -270,7 +370,7 @@ func (c *Commands) RemoveHumanOTPEmail(ctx context.Context, userID, resourceOwne return nil, err } if userID != authz.GetCtxData(ctx).UserID { - if err := c.checkPermission(ctx, domain.PermissionUserWrite, existingOTP.ResourceOwner, userID); err != nil { + if err := c.checkPermission(ctx, domain.PermissionUserWrite, existingOTP.WriteModel.ResourceOwner, userID); err != nil { return nil, err } } @@ -284,6 +384,147 @@ func (c *Commands) RemoveHumanOTPEmail(ctx context.Context, userID, resourceOwne return writeModelToObjectDetails(&existingOTP.WriteModel), nil } +func (c *Commands) HumanSendOTPEmail(ctx context.Context, userID, resourceOwner string, authRequest *domain.AuthRequest) error { + smsWriteModel := func(ctx context.Context, userID string, resourceOwner string) (OTPWriteModel, error) { + return c.otpEmailWriteModelByID(ctx, userID, resourceOwner) + } + codeAddedEvent := func(ctx context.Context, aggregate *eventstore.Aggregate, code *crypto.CryptoValue, expiry time.Duration, info *user.AuthRequestInfo) eventstore.Command { + return user.NewHumanOTPEmailCodeAddedEvent(ctx, aggregate, code, expiry, info) + } + return c.sendHumanOTP( + ctx, + userID, + resourceOwner, + authRequest, + smsWriteModel, + domain.SecretGeneratorTypeOTPEmail, + codeAddedEvent, + ) +} + +func (c *Commands) HumanOTPEmailCodeSent(ctx context.Context, userID, resourceOwner string) (err error) { + smsWriteModel := func(ctx context.Context, userID string, resourceOwner string) (OTPWriteModel, error) { + return c.otpEmailWriteModelByID(ctx, userID, resourceOwner) + } + codeSentEvent := func(ctx context.Context, aggregate *eventstore.Aggregate) eventstore.Command { + return user.NewHumanOTPEmailCodeSentEvent(ctx, aggregate) + } + return c.humanOTPSent(ctx, userID, resourceOwner, smsWriteModel, codeSentEvent) +} + +func (c *Commands) HumanCheckOTPEmail(ctx context.Context, userID, code, resourceOwner string, authRequest *domain.AuthRequest) error { + writeModel := func(ctx context.Context, userID string, resourceOwner string) (OTPCodeWriteModel, error) { + return c.otpEmailCodeWriteModelByID(ctx, userID, resourceOwner) + } + succeededEvent := func(ctx context.Context, aggregate *eventstore.Aggregate, info *user.AuthRequestInfo) eventstore.Command { + return user.NewHumanOTPEmailCheckSucceededEvent(ctx, aggregate, authRequestDomainToAuthRequestInfo(authRequest)) + } + failedEvent := func(ctx context.Context, aggregate *eventstore.Aggregate, info *user.AuthRequestInfo) eventstore.Command { + return user.NewHumanOTPEmailCheckFailedEvent(ctx, aggregate, authRequestDomainToAuthRequestInfo(authRequest)) + } + return c.humanCheckOTP( + ctx, + userID, + code, + resourceOwner, + authRequest, + writeModel, + domain.SecretGeneratorTypeOTPEmail, + succeededEvent, + failedEvent, + ) +} + +// sendHumanOTP creates a code for a registered mechanism (sms / email), which is used for a check (during login) +func (c *Commands) sendHumanOTP( + ctx context.Context, + userID, resourceOwner string, + authRequest *domain.AuthRequest, + writeModelByID func(ctx context.Context, userID string, resourceOwner string) (OTPWriteModel, error), + secretGeneratorType domain.SecretGeneratorType, + codeAddedEvent func(ctx context.Context, aggregate *eventstore.Aggregate, code *crypto.CryptoValue, expiry time.Duration, info *user.AuthRequestInfo) eventstore.Command, +) (err error) { + if userID == "" { + return caos_errs.ThrowInvalidArgument(nil, "COMMAND-S3SF1", "Errors.User.UserIDMissing") + } + existingOTP, err := writeModelByID(ctx, userID, resourceOwner) + if err != nil { + return err + } + if !existingOTP.OTPAdded() { + return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-SFD52", "Errors.User.MFA.OTP.NotReady") + } + config, err := secretGeneratorConfig(ctx, c.eventstore.Filter, secretGeneratorType) + if err != nil { + return err + } + gen := crypto.NewEncryptionGenerator(*config, c.userEncryption) + value, _, err := crypto.NewCode(gen) + if err != nil { + return err + } + userAgg := &user.NewAggregate(userID, resourceOwner).Aggregate + _, err = c.eventstore.Push(ctx, codeAddedEvent(ctx, userAgg, value, gen.Expiry(), authRequestDomainToAuthRequestInfo(authRequest))) + return err +} + +func (c *Commands) humanOTPSent( + ctx context.Context, + userID, resourceOwner string, + writeModelByID func(ctx context.Context, userID string, resourceOwner string) (OTPWriteModel, error), + codeSentEvent func(ctx context.Context, aggregate *eventstore.Aggregate) eventstore.Command, +) (err error) { + if userID == "" { + return caos_errs.ThrowInvalidArgument(nil, "COMMAND-AE2h2", "Errors.User.UserIDMissing") + } + existingOTP, err := writeModelByID(ctx, userID, resourceOwner) + if err != nil { + return err + } + if !existingOTP.OTPAdded() { + return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-SD3gh", "Errors.User.MFA.OTP.NotReady") + } + userAgg := &user.NewAggregate(userID, resourceOwner).Aggregate + _, err = c.eventstore.Push(ctx, codeSentEvent(ctx, userAgg)) + return err +} + +func (c *Commands) humanCheckOTP( + ctx context.Context, + userID, code, resourceOwner string, + authRequest *domain.AuthRequest, + writeModelByID func(ctx context.Context, userID string, resourceOwner string) (OTPCodeWriteModel, error), + secretGeneratorType domain.SecretGeneratorType, + checkSucceededEvent func(ctx context.Context, aggregate *eventstore.Aggregate, info *user.AuthRequestInfo) eventstore.Command, + checkFailedEvent func(ctx context.Context, aggregate *eventstore.Aggregate, info *user.AuthRequestInfo) eventstore.Command, +) error { + if userID == "" { + return caos_errs.ThrowInvalidArgument(nil, "COMMAND-S453v", "Errors.User.UserIDMissing") + } + if code == "" { + return caos_errs.ThrowInvalidArgument(nil, "COMMAND-SJl2g", "Errors.User.Code.Empty") + } + existingOTP, err := writeModelByID(ctx, userID, resourceOwner) + if err != nil { + return err + } + if !existingOTP.OTPAdded() { + return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-d2r52", "Errors.User.MFA.OTP.NotReady") + } + if existingOTP.Code() == nil { + return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-S34gh", "Errors.User.Code.NotFound") + } + userAgg := &user.NewAggregate(userID, existingOTP.ResourceOwner()).Aggregate + err = crypto.VerifyCodeWithAlgorithm(existingOTP.CodeCreationDate(), existingOTP.CodeExpiry(), existingOTP.Code(), code, c.userEncryption) + if err == nil { + _, err = c.eventstore.Push(ctx, checkSucceededEvent(ctx, userAgg, authRequestDomainToAuthRequestInfo(authRequest))) + return err + } + _, pushErr := c.eventstore.Push(ctx, checkFailedEvent(ctx, userAgg, authRequestDomainToAuthRequestInfo(authRequest))) + logging.WithFields("userID", userID).OnError(pushErr).Error("otp failure check push failed") + return err +} + func (c *Commands) totpWriteModelByID(ctx context.Context, userID, resourceOwner string) (writeModel *HumanTOTPWriteModel, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() @@ -308,6 +549,18 @@ func (c *Commands) otpSMSWriteModelByID(ctx context.Context, userID, resourceOwn return writeModel, nil } +func (c *Commands) otpSMSCodeWriteModelByID(ctx context.Context, userID, resourceOwner string) (writeModel *HumanOTPSMSCodeWriteModel, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + + writeModel = NewHumanOTPSMSCodeWriteModel(userID, resourceOwner) + err = c.eventstore.FilterToQueryReducer(ctx, writeModel) + if err != nil { + return nil, err + } + return writeModel, nil +} + func (c *Commands) otpEmailWriteModelByID(ctx context.Context, userID, resourceOwner string) (writeModel *HumanOTPEmailWriteModel, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() @@ -319,3 +572,15 @@ func (c *Commands) otpEmailWriteModelByID(ctx context.Context, userID, resourceO } return writeModel, nil } + +func (c *Commands) otpEmailCodeWriteModelByID(ctx context.Context, userID, resourceOwner string) (writeModel *HumanOTPEmailCodeWriteModel, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + + writeModel = NewHumanOTPEmailCodeWriteModel(userID, resourceOwner) + err = c.eventstore.FilterToQueryReducer(ctx, writeModel) + if err != nil { + return nil, err + } + return writeModel, nil +} diff --git a/internal/command/user_human_otp_model.go b/internal/command/user_human_otp_model.go index 9c9b8d2c49..25bd4c9ef5 100644 --- a/internal/command/user_human_otp_model.go +++ b/internal/command/user_human_otp_model.go @@ -1,6 +1,8 @@ package command import ( + "time" + "github.com/zitadel/zitadel/internal/crypto" "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/eventstore" @@ -60,6 +62,18 @@ func (wm *HumanTOTPWriteModel) Query() *eventstore.SearchQueryBuilder { return query } +type OTPWriteModel interface { + OTPAdded() bool + ResourceOwner() string +} + +type OTPCodeWriteModel interface { + OTPWriteModel + CodeCreationDate() time.Time + CodeExpiry() time.Duration + Code() *crypto.CryptoValue +} + type HumanOTPSMSWriteModel struct { eventstore.WriteModel @@ -67,6 +81,14 @@ type HumanOTPSMSWriteModel struct { otpAdded bool } +func (wm *HumanOTPSMSWriteModel) OTPAdded() bool { + return wm.otpAdded +} + +func (wm *HumanOTPSMSWriteModel) ResourceOwner() string { + return wm.WriteModel.ResourceOwner +} + func NewHumanOTPSMSWriteModel(userID, resourceOwner string) *HumanOTPSMSWriteModel { return &HumanOTPSMSWriteModel{ WriteModel: eventstore.WriteModel{ @@ -107,8 +129,66 @@ func (wm *HumanOTPSMSWriteModel) Query() *eventstore.SearchQueryBuilder { ). Builder() - if wm.ResourceOwner != "" { - query.ResourceOwner(wm.ResourceOwner) + if wm.WriteModel.ResourceOwner != "" { + query.ResourceOwner(wm.WriteModel.ResourceOwner) + } + return query +} + +type HumanOTPSMSCodeWriteModel struct { + *HumanOTPSMSWriteModel + + code *crypto.CryptoValue + codeCreationDate time.Time + codeExpiry time.Duration +} + +func (wm *HumanOTPSMSCodeWriteModel) CodeCreationDate() time.Time { + return wm.codeCreationDate +} + +func (wm *HumanOTPSMSCodeWriteModel) CodeExpiry() time.Duration { + return wm.codeExpiry +} + +func (wm *HumanOTPSMSCodeWriteModel) Code() *crypto.CryptoValue { + return wm.code +} + +func NewHumanOTPSMSCodeWriteModel(userID, resourceOwner string) *HumanOTPSMSCodeWriteModel { + return &HumanOTPSMSCodeWriteModel{ + HumanOTPSMSWriteModel: NewHumanOTPSMSWriteModel(userID, resourceOwner), + } +} + +func (wm *HumanOTPSMSCodeWriteModel) Reduce() error { + for _, event := range wm.Events { + if e, ok := event.(*user.HumanOTPSMSCodeAddedEvent); ok { + wm.code = e.Code + wm.codeCreationDate = e.CreationDate() + wm.codeExpiry = e.Expiry + } + } + return wm.HumanOTPSMSWriteModel.Reduce() +} + +func (wm *HumanOTPSMSCodeWriteModel) Query() *eventstore.SearchQueryBuilder { + query := eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent). + AddQuery(). + AggregateTypes(user.AggregateType). + AggregateIDs(wm.AggregateID). + EventTypes( + user.HumanOTPSMSCodeAddedType, + user.HumanPhoneVerifiedType, + user.HumanOTPSMSAddedType, + user.HumanOTPSMSRemovedType, + user.HumanPhoneRemovedType, + user.UserRemovedType, + ). + Builder() + + if wm.WriteModel.ResourceOwner != "" { + query.ResourceOwner(wm.WriteModel.ResourceOwner) } return query } @@ -120,6 +200,14 @@ type HumanOTPEmailWriteModel struct { otpAdded bool } +func (wm *HumanOTPEmailWriteModel) OTPAdded() bool { + return wm.otpAdded +} + +func (wm *HumanOTPEmailWriteModel) ResourceOwner() string { + return wm.WriteModel.ResourceOwner +} + func NewHumanOTPEmailWriteModel(userID, resourceOwner string) *HumanOTPEmailWriteModel { return &HumanOTPEmailWriteModel{ WriteModel: eventstore.WriteModel{ @@ -151,15 +239,73 @@ func (wm *HumanOTPEmailWriteModel) Query() *eventstore.SearchQueryBuilder { AddQuery(). AggregateTypes(user.AggregateType). AggregateIDs(wm.AggregateID). - EventTypes(user.HumanEmailVerifiedType, + EventTypes( + user.HumanEmailVerifiedType, user.HumanOTPEmailAddedType, user.HumanOTPEmailRemovedType, user.UserRemovedType, ). Builder() - if wm.ResourceOwner != "" { - query.ResourceOwner(wm.ResourceOwner) + if wm.WriteModel.ResourceOwner != "" { + query.ResourceOwner(wm.WriteModel.ResourceOwner) + } + return query +} + +type HumanOTPEmailCodeWriteModel struct { + *HumanOTPEmailWriteModel + + code *crypto.CryptoValue + codeCreationDate time.Time + codeExpiry time.Duration +} + +func (wm *HumanOTPEmailCodeWriteModel) CodeCreationDate() time.Time { + return wm.codeCreationDate +} + +func (wm *HumanOTPEmailCodeWriteModel) CodeExpiry() time.Duration { + return wm.codeExpiry +} + +func (wm *HumanOTPEmailCodeWriteModel) Code() *crypto.CryptoValue { + return wm.code +} + +func NewHumanOTPEmailCodeWriteModel(userID, resourceOwner string) *HumanOTPEmailCodeWriteModel { + return &HumanOTPEmailCodeWriteModel{ + HumanOTPEmailWriteModel: NewHumanOTPEmailWriteModel(userID, resourceOwner), + } +} + +func (wm *HumanOTPEmailCodeWriteModel) Reduce() error { + for _, event := range wm.Events { + if e, ok := event.(*user.HumanOTPEmailCodeAddedEvent); ok { + wm.code = e.Code + wm.codeCreationDate = e.CreationDate() + wm.codeExpiry = e.Expiry + } + } + return wm.HumanOTPEmailWriteModel.Reduce() +} + +func (wm *HumanOTPEmailCodeWriteModel) Query() *eventstore.SearchQueryBuilder { + query := eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent). + AddQuery(). + AggregateTypes(user.AggregateType). + AggregateIDs(wm.AggregateID). + EventTypes( + user.HumanOTPEmailCodeAddedType, + user.HumanEmailVerifiedType, + user.HumanOTPEmailAddedType, + user.HumanOTPEmailRemovedType, + user.UserRemovedType, + ). + Builder() + + if wm.WriteModel.ResourceOwner != "" { + query.ResourceOwner(wm.WriteModel.ResourceOwner) } return query } diff --git a/internal/command/user_human_otp_test.go b/internal/command/user_human_otp_test.go index 28e825de4b..5ec52582a9 100644 --- a/internal/command/user_human_otp_test.go +++ b/internal/command/user_human_otp_test.go @@ -3,6 +3,7 @@ package command import ( "context" "io" + "net" "testing" "time" @@ -18,6 +19,7 @@ import ( caos_errs "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore/repository" + "github.com/zitadel/zitadel/internal/repository/instance" "github.com/zitadel/zitadel/internal/repository/org" "github.com/zitadel/zitadel/internal/repository/user" ) @@ -989,6 +991,143 @@ func TestCommandSide_AddHumanOTPSMS(t *testing.T) { } } +func TestCommandSide_AddHumanOTPSMSWithCheckSucceeded(t *testing.T) { + ctx := authz.NewMockContext("inst1", "org1", "user1") + type fields struct { + eventstore func(*testing.T) *eventstore.Eventstore + } + type ( + args struct { + ctx context.Context + userID string + resourceOwner string + authRequest *domain.AuthRequest + } + ) + type res struct { + want *domain.ObjectDetails + err error + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + name: "successful add", + fields: fields{ + eventstore: expectEventstore( + expectFilter( + eventFromEventPusher( + user.NewHumanPhoneChangedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + "+4179654321", + ), + ), + eventFromEventPusher( + user.NewHumanPhoneVerifiedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + ), + expectPush( + []*repository.Event{ + eventFromEventPusherWithInstanceID("inst1", + user.NewHumanOTPSMSAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + }, + ), + ), + }, + args: args{ + ctx: ctx, + userID: "user1", + resourceOwner: "org1", + }, + res: res{ + want: &domain.ObjectDetails{ + ResourceOwner: "org1", + }, + }, + }, + { + name: "successful add with auth request", + fields: fields{ + eventstore: expectEventstore( + expectFilter( + eventFromEventPusher( + user.NewHumanPhoneChangedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + "+4179654321", + ), + ), + eventFromEventPusher( + user.NewHumanPhoneVerifiedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + ), + expectPush( + []*repository.Event{ + eventFromEventPusherWithInstanceID("inst1", + user.NewHumanOTPSMSAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + eventFromEventPusherWithInstanceID("inst1", + user.NewHumanOTPSMSCheckSucceededEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + &user.AuthRequestInfo{ + ID: "authRequestID", + UserAgentID: "userAgentID", + BrowserInfo: &user.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + ), + ), + }, + ), + ), + }, + args: args{ + ctx: ctx, + userID: "user1", + resourceOwner: "org1", + authRequest: &domain.AuthRequest{ + ID: "authRequestID", + AgentID: "userAgentID", + BrowserInfo: &domain.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + }, + res: res{ + want: &domain.ObjectDetails{ + ResourceOwner: "org1", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := &Commands{ + eventstore: tt.fields.eventstore(t), + } + got, err := r.AddHumanOTPSMSWithCheckSucceeded(tt.args.ctx, tt.args.userID, tt.args.resourceOwner, tt.args.authRequest) + assert.ErrorIs(t, err, tt.res.err) + assert.Equal(t, tt.res.want, got) + }) + } +} + func TestCommandSide_RemoveHumanOTPSMS(t *testing.T) { ctx := authz.NewMockContext("inst1", "org1", "user1") type fields struct { @@ -1108,6 +1247,551 @@ func TestCommandSide_RemoveHumanOTPSMS(t *testing.T) { } } +func TestCommandSide_HumanSendOTPSMS(t *testing.T) { + ctx := authz.NewMockContext("inst1", "org1", "user1") + type fields struct { + eventstore func(*testing.T) *eventstore.Eventstore + userEncryption crypto.EncryptionAlgorithm + } + type ( + args struct { + ctx context.Context + userID string + resourceOwner string + authRequest *domain.AuthRequest + } + ) + type res struct { + want *domain.ObjectDetails + err error + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + name: "userid missing, invalid argument error", + fields: fields{ + eventstore: expectEventstore(), + }, + args: args{ + ctx: ctx, + userID: "", + resourceOwner: "org1", + }, + res: res{ + err: caos_errs.ThrowInvalidArgument(nil, "COMMAND-S3SF1", "Errors.User.UserIDMissing"), + }, + }, + { + name: "otp sms not added, not found error", + fields: fields{ + eventstore: expectEventstore( + expectFilter(), + ), + }, + args: args{ + ctx: ctx, + userID: "user1", + resourceOwner: "org1", + }, + res: res{ + err: caos_errs.ThrowPreconditionFailed(nil, "COMMAND-SFD52", "Errors.User.MFA.OTP.NotReady"), + }, + }, + { + name: "successful add", + fields: fields{ + eventstore: expectEventstore( + expectFilter( + eventFromEventPusher( + user.NewHumanOTPSMSAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + ), + expectFilter( + eventFromEventPusher( + instance.NewSecretGeneratorAddedEvent(context.Background(), + &instance.NewAggregate("instanceID").Aggregate, + domain.SecretGeneratorTypeOTPSMS, + 8, + time.Hour, + true, + true, + true, + true, + )), + ), + expectPush( + []*repository.Event{ + eventFromEventPusherWithInstanceID("inst1", + user.NewHumanOTPSMSCodeAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + &crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("12345678"), + }, + time.Hour, + nil, + ), + ), + }, + ), + ), + userEncryption: crypto.CreateMockEncryptionAlgWithCode(gomock.NewController(t), "12345678"), + }, + args: args{ + ctx: ctx, + userID: "user1", + resourceOwner: "org1", + }, + res: res{ + want: &domain.ObjectDetails{ + ResourceOwner: "org1", + }, + }, + }, + { + name: "successful add with auth request", + fields: fields{ + eventstore: expectEventstore( + expectFilter( + eventFromEventPusher( + user.NewHumanOTPSMSAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + ), + expectFilter( + eventFromEventPusher( + instance.NewSecretGeneratorAddedEvent(context.Background(), + &instance.NewAggregate("instanceID").Aggregate, + domain.SecretGeneratorTypeOTPSMS, + 8, + time.Hour, + true, + true, + true, + true, + )), + ), + expectPush( + []*repository.Event{ + eventFromEventPusherWithInstanceID("inst1", + user.NewHumanOTPSMSCodeAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + &crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("12345678"), + }, + time.Hour, + &user.AuthRequestInfo{ + ID: "authRequestID", + UserAgentID: "userAgentID", + BrowserInfo: &user.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + ), + ), + }, + ), + ), + userEncryption: crypto.CreateMockEncryptionAlgWithCode(gomock.NewController(t), "12345678"), + }, + args: args{ + ctx: ctx, + userID: "user1", + resourceOwner: "org1", + authRequest: &domain.AuthRequest{ + ID: "authRequestID", + AgentID: "userAgentID", + BrowserInfo: &domain.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + }, + res: res{ + want: &domain.ObjectDetails{ + ResourceOwner: "org1", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := &Commands{ + eventstore: tt.fields.eventstore(t), + userEncryption: tt.fields.userEncryption, + } + err := r.HumanSendOTPSMS(tt.args.ctx, tt.args.userID, tt.args.resourceOwner, tt.args.authRequest) + assert.ErrorIs(t, err, tt.res.err) + }) + } +} + +func TestCommandSide_HumanOTPSMSCodeSent(t *testing.T) { + ctx := authz.NewMockContext("inst1", "org1", "user1") + type fields struct { + eventstore func(*testing.T) *eventstore.Eventstore + } + type ( + args struct { + ctx context.Context + userID string + resourceOwner string + } + ) + type res struct { + want *domain.ObjectDetails + err error + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + name: "userid missing, invalid argument error", + fields: fields{ + eventstore: expectEventstore(), + }, + args: args{ + ctx: ctx, + userID: "", + resourceOwner: "org1", + }, + res: res{ + err: caos_errs.ThrowInvalidArgument(nil, "COMMAND-AE2h2", "Errors.User.UserIDMissing"), + }, + }, + { + name: "otp sms not added, not found error", + fields: fields{ + eventstore: expectEventstore( + expectFilter(), + ), + }, + args: args{ + ctx: ctx, + userID: "user1", + resourceOwner: "org1", + }, + res: res{ + err: caos_errs.ThrowPreconditionFailed(nil, "COMMAND-SD3gh", "Errors.User.MFA.OTP.NotReady"), + }, + }, + { + name: "successful add", + fields: fields{ + eventstore: expectEventstore( + expectFilter( + eventFromEventPusher( + user.NewHumanOTPSMSAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + ), + expectPush( + []*repository.Event{ + eventFromEventPusherWithInstanceID("inst1", + user.NewHumanOTPSMSCodeSentEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + }, + ), + ), + }, + args: args{ + ctx: ctx, + userID: "user1", + resourceOwner: "org1", + }, + res: res{ + want: &domain.ObjectDetails{ + ResourceOwner: "org1", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := &Commands{ + eventstore: tt.fields.eventstore(t), + } + err := r.HumanOTPSMSCodeSent(tt.args.ctx, tt.args.userID, tt.args.resourceOwner) + assert.ErrorIs(t, err, tt.res.err) + }) + } +} + +func TestCommandSide_HumanCheckOTPSMS(t *testing.T) { + ctx := authz.NewMockContext("inst1", "org1", "user1") + type fields struct { + eventstore func(*testing.T) *eventstore.Eventstore + userEncryption crypto.EncryptionAlgorithm + } + type ( + args struct { + ctx context.Context + userID string + code string + resourceOwner string + authRequest *domain.AuthRequest + } + ) + type res struct { + want *domain.ObjectDetails + err error + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + name: "userid missing, invalid argument error", + fields: fields{ + eventstore: expectEventstore(), + }, + args: args{ + ctx: ctx, + userID: "", + code: "", + resourceOwner: "org1", + }, + res: res{ + err: caos_errs.ThrowInvalidArgument(nil, "COMMAND-S453v", "Errors.User.UserIDMissing"), + }, + }, + { + name: "code missing, invalid argument error", + fields: fields{ + eventstore: expectEventstore(), + }, + args: args{ + ctx: ctx, + userID: "user1", + code: "", + resourceOwner: "org1", + }, + res: res{ + err: caos_errs.ThrowInvalidArgument(nil, "COMMAND-SJl2g", "Errors.User.Code.Empty"), + }, + }, + { + name: "otp sms not added, precondition failed error", + fields: fields{ + eventstore: expectEventstore( + expectFilter(), + ), + }, + args: args{ + ctx: ctx, + userID: "user1", + code: "code", + resourceOwner: "org1", + }, + res: res{ + err: caos_errs.ThrowPreconditionFailed(nil, "COMMAND-d2r52", "Errors.User.MFA.OTP.NotReady"), + }, + }, + { + name: "otp sms code not added, precondition failed error", + fields: fields{ + eventstore: expectEventstore( + expectFilter( + eventFromEventPusher( + user.NewHumanOTPSMSAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + ), + ), + }, + args: args{ + ctx: ctx, + userID: "user1", + code: "code", + resourceOwner: "org1", + }, + res: res{ + err: caos_errs.ThrowPreconditionFailed(nil, "COMMAND-S34gh", "Errors.User.Code.NotFound"), + }, + }, + { + name: "invalid code, error", + fields: fields{ + eventstore: expectEventstore( + expectFilter( + eventFromEventPusher( + user.NewHumanOTPSMSAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + eventFromEventPusherWithCreationDateNow( + user.NewHumanOTPSMSCodeAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + &crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("other-code"), + }, + time.Hour, + &user.AuthRequestInfo{ + ID: "authRequestID", + UserAgentID: "userAgentID", + BrowserInfo: &user.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + ), + ), + ), + expectPush( + []*repository.Event{ + eventFromEventPusherWithInstanceID("inst1", + user.NewHumanOTPSMSCheckFailedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + &user.AuthRequestInfo{ + ID: "authRequestID", + UserAgentID: "userAgentID", + BrowserInfo: &user.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + ), + ), + }, + ), + ), + userEncryption: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args: args{ + ctx: ctx, + userID: "user1", + code: "code", + resourceOwner: "org1", + authRequest: &domain.AuthRequest{ + ID: "authRequestID", + AgentID: "userAgentID", + BrowserInfo: &domain.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + }, + res: res{ + err: caos_errs.ThrowInvalidArgument(nil, "CODE-woT0xc", "Errors.User.Code.Invalid"), + }, + }, + { + name: "code ok", + fields: fields{ + eventstore: expectEventstore( + expectFilter( + eventFromEventPusher( + user.NewHumanOTPSMSAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + eventFromEventPusherWithCreationDateNow( + user.NewHumanOTPSMSCodeAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + &crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("code"), + }, + time.Hour, + &user.AuthRequestInfo{ + ID: "authRequestID", + UserAgentID: "userAgentID", + BrowserInfo: &user.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + ), + ), + ), + expectPush( + []*repository.Event{ + eventFromEventPusherWithInstanceID("inst1", + user.NewHumanOTPSMSCheckSucceededEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + &user.AuthRequestInfo{ + ID: "authRequestID", + UserAgentID: "userAgentID", + BrowserInfo: &user.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + ), + ), + }, + ), + ), + userEncryption: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args: args{ + ctx: ctx, + userID: "user1", + code: "code", + resourceOwner: "org1", + authRequest: &domain.AuthRequest{ + ID: "authRequestID", + AgentID: "userAgentID", + BrowserInfo: &domain.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + }, + res: res{ + want: &domain.ObjectDetails{ + ResourceOwner: "org1", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := &Commands{ + eventstore: tt.fields.eventstore(t), + userEncryption: tt.fields.userEncryption, + } + err := r.HumanCheckOTPSMS(tt.args.ctx, tt.args.userID, tt.args.code, tt.args.resourceOwner, tt.args.authRequest) + assert.ErrorIs(t, err, tt.res.err) + }) + } +} + func TestCommandSide_AddHumanOTPEmail(t *testing.T) { ctx := authz.NewMockContext("inst1", "org1", "user1") type fields struct { @@ -1234,6 +1918,143 @@ func TestCommandSide_AddHumanOTPEmail(t *testing.T) { } } +func TestCommandSide_AddHumanOTPEmailWithCheckSucceeded(t *testing.T) { + ctx := authz.NewMockContext("inst1", "org1", "user1") + type fields struct { + eventstore func(*testing.T) *eventstore.Eventstore + } + type ( + args struct { + ctx context.Context + userID string + resourceOwner string + authRequest *domain.AuthRequest + } + ) + type res struct { + want *domain.ObjectDetails + err error + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + name: "successful add", + fields: fields{ + eventstore: expectEventstore( + expectFilter( + eventFromEventPusher( + user.NewHumanEmailChangedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + "email@test.ch", + ), + ), + eventFromEventPusher( + user.NewHumanEmailVerifiedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + ), + expectPush( + []*repository.Event{ + eventFromEventPusherWithInstanceID("inst1", + user.NewHumanOTPEmailAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + }, + ), + ), + }, + args: args{ + ctx: ctx, + userID: "user1", + resourceOwner: "org1", + }, + res: res{ + want: &domain.ObjectDetails{ + ResourceOwner: "org1", + }, + }, + }, + { + name: "successful add with auth request", + fields: fields{ + eventstore: expectEventstore( + expectFilter( + eventFromEventPusher( + user.NewHumanEmailChangedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + "email@test.ch", + ), + ), + eventFromEventPusher( + user.NewHumanEmailVerifiedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + ), + expectPush( + []*repository.Event{ + eventFromEventPusherWithInstanceID("inst1", + user.NewHumanOTPEmailAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + eventFromEventPusherWithInstanceID("inst1", + user.NewHumanOTPEmailCheckSucceededEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + &user.AuthRequestInfo{ + ID: "authRequestID", + UserAgentID: "userAgentID", + BrowserInfo: &user.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + ), + ), + }, + ), + ), + }, + args: args{ + ctx: ctx, + userID: "user1", + resourceOwner: "org1", + authRequest: &domain.AuthRequest{ + ID: "authRequestID", + AgentID: "userAgentID", + BrowserInfo: &domain.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + }, + res: res{ + want: &domain.ObjectDetails{ + ResourceOwner: "org1", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := &Commands{ + eventstore: tt.fields.eventstore(t), + } + got, err := r.AddHumanOTPEmailWithCheckSucceeded(tt.args.ctx, tt.args.userID, tt.args.resourceOwner, tt.args.authRequest) + assert.ErrorIs(t, err, tt.res.err) + assert.Equal(t, tt.res.want, got) + }) + } +} + func TestCommandSide_RemoveHumanOTPEmail(t *testing.T) { ctx := authz.NewMockContext("inst1", "org1", "user1") type fields struct { @@ -1352,3 +2173,548 @@ func TestCommandSide_RemoveHumanOTPEmail(t *testing.T) { }) } } + +func TestCommandSide_HumanSendOTPEmail(t *testing.T) { + ctx := authz.NewMockContext("inst1", "org1", "user1") + type fields struct { + eventstore func(*testing.T) *eventstore.Eventstore + userEncryption crypto.EncryptionAlgorithm + } + type ( + args struct { + ctx context.Context + userID string + resourceOwner string + authRequest *domain.AuthRequest + } + ) + type res struct { + want *domain.ObjectDetails + err error + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + name: "userid missing, invalid argument error", + fields: fields{ + eventstore: expectEventstore(), + }, + args: args{ + ctx: ctx, + userID: "", + resourceOwner: "org1", + }, + res: res{ + err: caos_errs.ThrowInvalidArgument(nil, "COMMAND-S3SF1", "Errors.User.UserIDMissing"), + }, + }, + { + name: "otp email not added, not found error", + fields: fields{ + eventstore: expectEventstore( + expectFilter(), + ), + }, + args: args{ + ctx: ctx, + userID: "user1", + resourceOwner: "org1", + }, + res: res{ + err: caos_errs.ThrowPreconditionFailed(nil, "COMMAND-SFD52", "Errors.User.MFA.OTP.NotReady"), + }, + }, + { + name: "successful add", + fields: fields{ + eventstore: expectEventstore( + expectFilter( + eventFromEventPusher( + user.NewHumanOTPEmailAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + ), + expectFilter( + eventFromEventPusher( + instance.NewSecretGeneratorAddedEvent(context.Background(), + &instance.NewAggregate("instanceID").Aggregate, + domain.SecretGeneratorTypeOTPEmail, + 8, + time.Hour, + true, + true, + true, + true, + )), + ), + expectPush( + []*repository.Event{ + eventFromEventPusherWithInstanceID("inst1", + user.NewHumanOTPEmailCodeAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + &crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("12345678"), + }, + time.Hour, + nil, + ), + ), + }, + ), + ), + userEncryption: crypto.CreateMockEncryptionAlgWithCode(gomock.NewController(t), "12345678"), + }, + args: args{ + ctx: ctx, + userID: "user1", + resourceOwner: "org1", + }, + res: res{ + want: &domain.ObjectDetails{ + ResourceOwner: "org1", + }, + }, + }, + { + name: "successful add with auth request", + fields: fields{ + eventstore: expectEventstore( + expectFilter( + eventFromEventPusher( + user.NewHumanOTPEmailAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + ), + expectFilter( + eventFromEventPusher( + instance.NewSecretGeneratorAddedEvent(context.Background(), + &instance.NewAggregate("instanceID").Aggregate, + domain.SecretGeneratorTypeOTPEmail, + 8, + time.Hour, + true, + true, + true, + true, + )), + ), + expectPush( + []*repository.Event{ + eventFromEventPusherWithInstanceID("inst1", + user.NewHumanOTPEmailCodeAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + &crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("12345678"), + }, + time.Hour, + &user.AuthRequestInfo{ + ID: "authRequestID", + UserAgentID: "userAgentID", + BrowserInfo: &user.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + ), + ), + }, + ), + ), + userEncryption: crypto.CreateMockEncryptionAlgWithCode(gomock.NewController(t), "12345678"), + }, + args: args{ + ctx: ctx, + userID: "user1", + resourceOwner: "org1", + authRequest: &domain.AuthRequest{ + ID: "authRequestID", + AgentID: "userAgentID", + BrowserInfo: &domain.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + }, + res: res{ + want: &domain.ObjectDetails{ + ResourceOwner: "org1", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := &Commands{ + eventstore: tt.fields.eventstore(t), + userEncryption: tt.fields.userEncryption, + } + err := r.HumanSendOTPEmail(tt.args.ctx, tt.args.userID, tt.args.resourceOwner, tt.args.authRequest) + assert.ErrorIs(t, err, tt.res.err) + }) + } +} + +func TestCommandSide_HumanOTPEmailCodeSent(t *testing.T) { + ctx := authz.NewMockContext("inst1", "org1", "user1") + type fields struct { + eventstore func(*testing.T) *eventstore.Eventstore + } + type ( + args struct { + ctx context.Context + userID string + resourceOwner string + } + ) + type res struct { + want *domain.ObjectDetails + err error + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + name: "userid missing, invalid argument error", + fields: fields{ + eventstore: expectEventstore(), + }, + args: args{ + ctx: ctx, + userID: "", + resourceOwner: "org1", + }, + res: res{ + err: caos_errs.ThrowInvalidArgument(nil, "COMMAND-AE2h2", "Errors.User.UserIDMissing"), + }, + }, + { + name: "otp email not added, not found error", + fields: fields{ + eventstore: expectEventstore( + expectFilter(), + ), + }, + args: args{ + ctx: ctx, + userID: "user1", + resourceOwner: "org1", + }, + res: res{ + err: caos_errs.ThrowPreconditionFailed(nil, "COMMAND-SD3gh", "Errors.User.MFA.OTP.NotReady"), + }, + }, + { + name: "successful add", + fields: fields{ + eventstore: expectEventstore( + expectFilter( + eventFromEventPusher( + user.NewHumanOTPEmailAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + ), + expectPush( + []*repository.Event{ + eventFromEventPusherWithInstanceID("inst1", + user.NewHumanOTPEmailCodeSentEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + }, + ), + ), + }, + args: args{ + ctx: ctx, + userID: "user1", + resourceOwner: "org1", + }, + res: res{ + want: &domain.ObjectDetails{ + ResourceOwner: "org1", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := &Commands{ + eventstore: tt.fields.eventstore(t), + } + err := r.HumanOTPEmailCodeSent(tt.args.ctx, tt.args.userID, tt.args.resourceOwner) + assert.ErrorIs(t, err, tt.res.err) + }) + } +} + +func TestCommandSide_HumanCheckOTPEmail(t *testing.T) { + ctx := authz.NewMockContext("inst1", "org1", "user1") + type fields struct { + eventstore func(*testing.T) *eventstore.Eventstore + userEncryption crypto.EncryptionAlgorithm + } + type ( + args struct { + ctx context.Context + userID string + code string + resourceOwner string + authRequest *domain.AuthRequest + } + ) + type res struct { + want *domain.ObjectDetails + err error + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + name: "userid missing, invalid argument error", + fields: fields{ + eventstore: expectEventstore(), + }, + args: args{ + ctx: ctx, + userID: "", + code: "", + resourceOwner: "org1", + }, + res: res{ + err: caos_errs.ThrowInvalidArgument(nil, "COMMAND-S453v", "Errors.User.UserIDMissing"), + }, + }, + { + name: "code missing, invalid argument error", + fields: fields{ + eventstore: expectEventstore(), + }, + args: args{ + ctx: ctx, + userID: "user1", + code: "", + resourceOwner: "org1", + }, + res: res{ + err: caos_errs.ThrowInvalidArgument(nil, "COMMAND-SJl2g", "Errors.User.Code.Empty"), + }, + }, + { + name: "otp email not added, precondition failed error", + fields: fields{ + eventstore: expectEventstore( + expectFilter(), + ), + }, + args: args{ + ctx: ctx, + userID: "user1", + code: "code", + resourceOwner: "org1", + }, + res: res{ + err: caos_errs.ThrowPreconditionFailed(nil, "COMMAND-d2r52", "Errors.User.MFA.OTP.NotReady"), + }, + }, + { + name: "otp email code not added, precondition failed error", + fields: fields{ + eventstore: expectEventstore( + expectFilter( + eventFromEventPusher( + user.NewHumanOTPEmailAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + ), + ), + }, + args: args{ + ctx: ctx, + userID: "user1", + code: "code", + resourceOwner: "org1", + }, + res: res{ + err: caos_errs.ThrowPreconditionFailed(nil, "COMMAND-S34gh", "Errors.User.Code.NotFound"), + }, + }, + { + name: "invalid code, error", + fields: fields{ + eventstore: expectEventstore( + expectFilter( + eventFromEventPusher( + user.NewHumanOTPEmailAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + eventFromEventPusherWithCreationDateNow( + user.NewHumanOTPEmailCodeAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + &crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("other-code"), + }, + time.Hour, + &user.AuthRequestInfo{ + ID: "authRequestID", + UserAgentID: "userAgentID", + BrowserInfo: &user.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + ), + ), + ), + expectPush( + []*repository.Event{ + eventFromEventPusherWithInstanceID("inst1", + user.NewHumanOTPEmailCheckFailedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + &user.AuthRequestInfo{ + ID: "authRequestID", + UserAgentID: "userAgentID", + BrowserInfo: &user.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + ), + ), + }, + ), + ), + userEncryption: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args: args{ + ctx: ctx, + userID: "user1", + code: "code", + resourceOwner: "org1", + authRequest: &domain.AuthRequest{ + ID: "authRequestID", + AgentID: "userAgentID", + BrowserInfo: &domain.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + }, + res: res{ + err: caos_errs.ThrowInvalidArgument(nil, "CODE-woT0xc", "Errors.User.Code.Invalid"), + }, + }, + { + name: "code ok", + fields: fields{ + eventstore: expectEventstore( + expectFilter( + eventFromEventPusher( + user.NewHumanOTPEmailAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + eventFromEventPusherWithCreationDateNow( + user.NewHumanOTPEmailCodeAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + &crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("code"), + }, + time.Hour, + &user.AuthRequestInfo{ + ID: "authRequestID", + UserAgentID: "userAgentID", + BrowserInfo: &user.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + ), + ), + ), + expectPush( + []*repository.Event{ + eventFromEventPusherWithInstanceID("inst1", + user.NewHumanOTPEmailCheckSucceededEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + &user.AuthRequestInfo{ + ID: "authRequestID", + UserAgentID: "userAgentID", + BrowserInfo: &user.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + ), + ), + }, + ), + ), + userEncryption: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args: args{ + ctx: ctx, + userID: "user1", + code: "code", + resourceOwner: "org1", + authRequest: &domain.AuthRequest{ + ID: "authRequestID", + AgentID: "userAgentID", + BrowserInfo: &domain.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + }, + res: res{ + want: &domain.ObjectDetails{ + ResourceOwner: "org1", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := &Commands{ + eventstore: tt.fields.eventstore(t), + userEncryption: tt.fields.userEncryption, + } + err := r.HumanCheckOTPEmail(tt.args.ctx, tt.args.userID, tt.args.code, tt.args.resourceOwner, tt.args.authRequest) + assert.ErrorIs(t, err, tt.res.err) + }) + } +} diff --git a/internal/command/user_human_phone.go b/internal/command/user_human_phone.go index 525333957c..43395acd15 100644 --- a/internal/command/user_human_phone.go +++ b/internal/command/user_human_phone.go @@ -97,7 +97,7 @@ func (c *Commands) VerifyHumanPhone(ctx context.Context, userID, code, resourceo return nil, caos_errs.ThrowInvalidArgument(err, "COMMAND-sM0cs", "Errors.User.Code.Invalid") } -func (c *Commands) CreateHumanPhoneVerificationCode(ctx context.Context, userID, resourceowner string, phoneCodeGenerator crypto.Generator) (*domain.ObjectDetails, error) { +func (c *Commands) CreateHumanPhoneVerificationCode(ctx context.Context, userID, resourceowner string) (*domain.ObjectDetails, error) { if userID == "" { return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-4M0ds", "Errors.User.UserIDMissing") } @@ -116,19 +116,17 @@ func (c *Commands) CreateHumanPhoneVerificationCode(ctx context.Context, userID, if existingPhone.IsPhoneVerified { return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-2M9sf", "Errors.User.Phone.AlreadyVerified") } - - phoneCode, err := domain.NewPhoneCode(phoneCodeGenerator) + config, err := secretGeneratorConfig(ctx, c.eventstore.Filter, domain.SecretGeneratorTypeVerifyPhoneCode) + if err != nil { + return nil, err + } + phoneCode, err := domain.NewPhoneCode(crypto.NewEncryptionGenerator(*config, c.userEncryption)) if err != nil { return nil, err } userAgg := UserAggregateFromWriteModel(&existingPhone.WriteModel) - pushedEvents, err := c.eventstore.Push(ctx, user.NewHumanPhoneCodeAddedEvent(ctx, userAgg, phoneCode.Code, phoneCode.Expiry)) - if err != nil { - return nil, err - } - err = AppendAndReduce(existingPhone, pushedEvents...) - if err != nil { + if err = c.pushAppendAndReduce(ctx, existingPhone, user.NewHumanPhoneCodeAddedEvent(ctx, userAgg, phoneCode.Code, phoneCode.Expiry)); err != nil { return nil, err } return writeModelToObjectDetails(&existingPhone.WriteModel), nil diff --git a/internal/command/user_human_phone_test.go b/internal/command/user_human_phone_test.go index 98ee9da7c7..8a2b426cb0 100644 --- a/internal/command/user_human_phone_test.go +++ b/internal/command/user_human_phone_test.go @@ -5,6 +5,7 @@ import ( "testing" "time" + "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "golang.org/x/text/language" @@ -14,6 +15,7 @@ import ( "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore/repository" "github.com/zitadel/zitadel/internal/eventstore/v1/models" + "github.com/zitadel/zitadel/internal/repository/instance" "github.com/zitadel/zitadel/internal/repository/user" ) @@ -584,13 +586,13 @@ func TestCommandSide_VerifyHumanPhone(t *testing.T) { func TestCommandSide_CreateVerificationCodeHumanPhone(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore *eventstore.Eventstore + userEncryption crypto.EncryptionAlgorithm } type args struct { - ctx context.Context - userID string - resourceOwner string - secretGenerator crypto.Generator + ctx context.Context + userID string + resourceOwner string } type res struct { want *domain.ObjectDetails @@ -704,6 +706,19 @@ func TestCommandSide_CreateVerificationCodeHumanPhone(t *testing.T) { ), ), ), + expectFilter( + eventFromEventPusher( + instance.NewSecretGeneratorAddedEvent(context.Background(), + &instance.NewAggregate("instanceID").Aggregate, + domain.SecretGeneratorTypeVerifyPhoneCode, + 8, + time.Hour, + true, + true, + true, + true, + )), + ), expectPush( []*repository.Event{ eventFromEventPusher( @@ -713,7 +728,7 @@ func TestCommandSide_CreateVerificationCodeHumanPhone(t *testing.T) { CryptoType: crypto.TypeEncryption, Algorithm: "enc", KeyID: "id", - Crypted: []byte("a"), + Crypted: []byte("12345678"), }, time.Hour*1, ), @@ -721,12 +736,12 @@ func TestCommandSide_CreateVerificationCodeHumanPhone(t *testing.T) { }, ), ), + userEncryption: crypto.CreateMockEncryptionAlgWithCode(gomock.NewController(t), "12345678"), }, args: args{ - ctx: context.Background(), - userID: "user1", - resourceOwner: "org1", - secretGenerator: GetMockSecretGenerator(t), + ctx: context.Background(), + userID: "user1", + resourceOwner: "org1", }, res: res{ want: &domain.ObjectDetails{ @@ -738,9 +753,10 @@ func TestCommandSide_CreateVerificationCodeHumanPhone(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore, + userEncryption: tt.fields.userEncryption, } - got, err := r.CreateHumanPhoneVerificationCode(tt.args.ctx, tt.args.userID, tt.args.resourceOwner, tt.args.secretGenerator) + got, err := r.CreateHumanPhoneVerificationCode(tt.args.ctx, tt.args.userID, tt.args.resourceOwner) if tt.res.err == nil { assert.NoError(t, err) } diff --git a/internal/crypto/code_mocker.go b/internal/crypto/code_mocker.go index 181ec771d3..b29940181e 100644 --- a/internal/crypto/code_mocker.go +++ b/internal/crypto/code_mocker.go @@ -9,14 +9,37 @@ import ( ) func CreateMockEncryptionAlg(ctrl *gomock.Controller) EncryptionAlgorithm { + return createMockEncryptionAlgorithm( + ctrl, + func(code []byte) ([]byte, error) { + return code, nil + }, + ) +} + +// CreateMockEncryptionAlgWithCode compares the length of the value to be encrypted with the length of the provided code. +// It will return an error if they do not match. +// The provided code will be used to encrypt in favor of the value passed to the encryption. +// This function is intended to be used where the passed value is not in control, but where the returned encryption requires a static value. +func CreateMockEncryptionAlgWithCode(ctrl *gomock.Controller, code string) EncryptionAlgorithm { + return createMockEncryptionAlgorithm( + ctrl, + func(c []byte) ([]byte, error) { + if len(c) != len(code) { + return nil, errors.ThrowInvalidArgumentf(nil, "id", "invalid code length - expected %d, got %d", len(code), len(c)) + } + return []byte(code), nil + }, + ) +} + +func createMockEncryptionAlgorithm(ctrl *gomock.Controller, encryptFunction func(c []byte) ([]byte, error)) *MockEncryptionAlgorithm { mCrypto := NewMockEncryptionAlgorithm(ctrl) mCrypto.EXPECT().Algorithm().AnyTimes().Return("enc") mCrypto.EXPECT().EncryptionKeyID().AnyTimes().Return("id") mCrypto.EXPECT().DecryptionKeyIDs().AnyTimes().Return([]string{"id"}) mCrypto.EXPECT().Encrypt(gomock.Any()).AnyTimes().DoAndReturn( - func(code []byte) ([]byte, error) { - return code, nil - }, + encryptFunction, ) mCrypto.EXPECT().DecryptString(gomock.Any(), gomock.Any()).AnyTimes().DoAndReturn( func(code []byte, keyID string) (string, error) { diff --git a/internal/domain/auth_request.go b/internal/domain/auth_request.go index f7f4da19f5..d5b1bf4fe9 100644 --- a/internal/domain/auth_request.go +++ b/internal/domain/auth_request.go @@ -105,6 +105,8 @@ const ( MFATypeTOTP MFAType = iota MFATypeU2F MFATypeU2FUserVerification + MFATypeOTPSMS + MFATypeOTPEmail ) type MFALevel int diff --git a/internal/notification/handlers/user_notifier.go b/internal/notification/handlers/user_notifier.go index 64661d89bc..d5ad60b464 100644 --- a/internal/notification/handlers/user_notifier.go +++ b/internal/notification/handlers/user_notifier.go @@ -4,6 +4,7 @@ import ( "context" "time" + "github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/crypto" "github.com/zitadel/zitadel/internal/domain" @@ -106,6 +107,14 @@ func (u *userNotifier) reducers() []handler.AggregateReducer { Event: user.HumanPasswordChangedType, Reduce: u.reducePasswordChanged, }, + { + Event: user.HumanOTPSMSCodeAddedType, + Reduce: u.reduceOTPSMSCodeAdded, + }, + { + Event: user.HumanOTPEmailCodeAddedType, + Reduce: u.reduceOTPEmailCodeAdded, + }, }, }, } @@ -332,6 +341,136 @@ func (u *userNotifier) reducePasswordCodeAdded(event eventstore.Event) (*handler return crdb.NewNoOpStatement(e), nil } +func (u *userNotifier) reduceOTPSMSCodeAdded(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*user.HumanOTPSMSCodeAddedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-ASF3g", "reduce.wrong.event.type %s", user.HumanOTPSMSCodeAddedType) + } + ctx := HandlerContext(event.Aggregate()) + alreadyHandled, err := u.checkIfCodeAlreadyHandledOrExpired(ctx, event, e.Expiry, nil, + user.HumanOTPSMSCodeAddedType, user.HumanOTPSMSCodeSentType) + if err != nil { + return nil, err + } + if alreadyHandled { + return crdb.NewNoOpStatement(e), nil + } + code, err := crypto.DecryptString(e.Code, u.queries.UserDataCrypto) + if err != nil { + return nil, err + } + colors, err := u.queries.ActiveLabelPolicyByOrg(ctx, e.Aggregate().ResourceOwner, false) + if err != nil { + return nil, err + } + + notifyUser, err := u.queries.GetNotifyUserByID(ctx, true, e.Aggregate().ID, false) + if err != nil { + return nil, err + } + translator, err := u.queries.GetTranslatorWithOrgTexts(ctx, notifyUser.ResourceOwner, domain.VerifySMSOTPMessageType) + if err != nil { + return nil, err + } + + ctx, origin, err := u.queries.Origin(ctx) + if err != nil { + return nil, err + } + notify := types.SendSMSTwilio( + ctx, + translator, + notifyUser, + u.queries.GetTwilioConfig, + u.queries.GetFileSystemProvider, + u.queries.GetLogProvider, + colors, + u.assetsPrefix(ctx), + e, + u.metricSuccessfulDeliveriesSMS, + u.metricFailedDeliveriesSMS, + ) + err = notify.SendOTPSMSCode(authz.GetInstance(ctx).RequestedDomain(), origin, code, e.Expiry) + if err != nil { + return nil, err + } + err = u.commands.HumanOTPSMSCodeSent(ctx, e.Aggregate().ID, e.Aggregate().ResourceOwner) + if err != nil { + return nil, err + } + return crdb.NewNoOpStatement(e), nil +} + +func (u *userNotifier) reduceOTPEmailCodeAdded(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*user.HumanOTPEmailCodeAddedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-JL3hw", "reduce.wrong.event.type %s", user.HumanOTPEmailCodeAddedType) + } + ctx := HandlerContext(event.Aggregate()) + alreadyHandled, err := u.checkIfCodeAlreadyHandledOrExpired(ctx, event, e.Expiry, nil, + user.HumanOTPEmailCodeAddedType, user.HumanOTPEmailCodeSentType) + if err != nil { + return nil, err + } + if alreadyHandled { + return crdb.NewNoOpStatement(e), nil + } + code, err := crypto.DecryptString(e.Code, u.queries.UserDataCrypto) + if err != nil { + return nil, err + } + colors, err := u.queries.ActiveLabelPolicyByOrg(ctx, e.Aggregate().ResourceOwner, false) + if err != nil { + return nil, err + } + + template, err := u.queries.MailTemplateByOrg(ctx, e.Aggregate().ResourceOwner, false) + if err != nil { + return nil, err + } + + notifyUser, err := u.queries.GetNotifyUserByID(ctx, true, e.Aggregate().ID, false) + if err != nil { + return nil, err + } + translator, err := u.queries.GetTranslatorWithOrgTexts(ctx, notifyUser.ResourceOwner, domain.VerifyEmailOTPMessageType) + if err != nil { + return nil, err + } + + ctx, origin, err := u.queries.Origin(ctx) + if err != nil { + return nil, err + } + var authRequestID string + if e.AuthRequestInfo != nil { + authRequestID = e.AuthRequestInfo.ID + } + notify := types.SendEmail( + ctx, + string(template.Template), + translator, + notifyUser, + u.queries.GetSMTPConfig, + u.queries.GetFileSystemProvider, + u.queries.GetLogProvider, + colors, + u.assetsPrefix(ctx), + e, + u.metricSuccessfulDeliveriesEmail, + u.metricFailedDeliveriesEmail, + ) + err = notify.SendOTPEmailCode(notifyUser, authz.GetInstance(ctx).RequestedDomain(), origin, code, authRequestID, e.Expiry) + if err != nil { + return nil, err + } + err = u.commands.HumanOTPEmailCodeSent(ctx, e.Aggregate().ID, e.Aggregate().ResourceOwner) + if err != nil { + return nil, err + } + return crdb.NewNoOpStatement(e), nil +} + func (u *userNotifier) reduceDomainClaimed(event eventstore.Event) (*handler.Statement, error) { e, ok := event.(*user.DomainClaimedEvent) if !ok { @@ -583,7 +722,7 @@ func (u *userNotifier) reducePhoneCodeAdded(event eventstore.Event) (*handler.St e, u.metricSuccessfulDeliveriesSMS, u.metricFailedDeliveriesSMS, - ).SendPhoneVerificationCode(notifyUser, origin, code) + ).SendPhoneVerificationCode(notifyUser, origin, code, authz.GetInstance(ctx).RequestedDomain()) if err != nil { return nil, err } diff --git a/internal/notification/static/i18n/bg.yaml b/internal/notification/static/i18n/bg.yaml index 127163e381..7f67c24dfb 100644 --- a/internal/notification/static/i18n/bg.yaml +++ b/internal/notification/static/i18n/bg.yaml @@ -40,7 +40,10 @@ VerifyEmailOTP: Text: Моля, използвай бутона 'Удостовери' или копирай временната парола {{.OTP}} и я постави на екрана за удостоверяване, за да се удостовериш в ZITADEL в рамките на следващите пет минути. ButtonText: Удостовери VerifySMSOTP: - Text: Моля, посети {{ .VerifyURL }} или копирай временната парола {{.OTP}} и я постави на екрана за удостоверяване, за да се удостовериш в ZITADEL в рамките на следващите пет минути. + Text: >- + {{.OTP}} е вашата еднократна парола за {{ .Domain }}. Използвайте го в рамките на следващия {{.Expiry}}. + + @{{.Domain}} #{{.OTP}} DomainClaimed: Title: ZITADEL - Домейнът е заявен PreHeader: Промяна на имейл/потребителско име diff --git a/internal/notification/static/i18n/de.yaml b/internal/notification/static/i18n/de.yaml index c882f2b791..bf3fe133cb 100644 --- a/internal/notification/static/i18n/de.yaml +++ b/internal/notification/static/i18n/de.yaml @@ -34,7 +34,10 @@ VerifyEmailOTP: Text: Bitte nutze den 'Authentifizieren'-Button oder kopiere das Einmalpasswort {{.OTP}} und füge es in den Authentifizierungsbildschirm ein, um dich innerhalb der nächsten fünf Minuten bei ZITADEL zu authentifizieren. ButtonText: Authentifizieren VerifySMSOTP: - Text: Bitte besuche {{ .VerifyURL }} oder kopiere das Einmalpasswort {{.OTP}} und füge es in den Authentifizierungsbildschirm ein, um dich innerhalb der nächsten fünf Minuten bei ZITADEL zu authentifizieren. + Text: >- + {{.OTP}} ist Ihr Einmalpasswort für {{ .Domain }}. Verwenden Sie es innerhalb der nächsten {{.Expiry}}. + + @{{.Domain}} #{{.OTP}} DomainClaimed: Title: ZITADEL - Domain wurde beansprucht PreHeader: Email / Username ändern diff --git a/internal/notification/static/i18n/en.yaml b/internal/notification/static/i18n/en.yaml index bb2a841ad2..c6257188e0 100644 --- a/internal/notification/static/i18n/en.yaml +++ b/internal/notification/static/i18n/en.yaml @@ -31,10 +31,13 @@ VerifyEmailOTP: PreHeader: Verify One-Time Password Subject: Verify One-Time Password Greeting: Hello {{.DisplayName}}, - Text: Please use the "Authenticate" button or copy the one-time password {{.OTP}} and paste it to to the authentication screen in order to authenticate at ZITADEL within the next five minutes. + Text: Please use the one-time password {{.OTP}} to authenticate at ZITADEL within the next five minutes or click the "Authenticate" button. ButtonText: Authenticate VerifySMSOTP: - Text: Please visit {{ .VerifyURL }} or copy the one-time password {{.OTP}} and paste it to to the authentication screen in order to authenticate at ZITADEL within the next five minutes. + Text: >- + {{.OTP}} is your one-time-password for {{ .Domain }}. Use it within the next {{.Expiry}}. + + @{{.Domain}} #{{.OTP}} DomainClaimed: Title: ZITADEL - Domain has been claimed PreHeader: Change email / username diff --git a/internal/notification/static/i18n/es.yaml b/internal/notification/static/i18n/es.yaml index 9a14132195..b2534e240d 100644 --- a/internal/notification/static/i18n/es.yaml +++ b/internal/notification/static/i18n/es.yaml @@ -34,7 +34,10 @@ VerifyEmailOTP: Text: Por favor, utiliza el botón 'Autenticar' o copia la contraseña de un solo uso {{.OTP}} y pégala en la pantalla de autenticación para autenticarte en ZITADEL en los próximos cinco minutos. ButtonText: Autenticar VerifySMSOTP: - Text: Por favor, visita {{ .VerifyURL }} o copia la contraseña de un solo uso {{.OTP}} y pégala en la pantalla de autenticación para autenticarte en ZITADEL en los próximos cinco minutos. + Text: >- + {{.OTP}} es su contraseña de un solo uso para {{ .Domain }}. Úselo dentro de los próximos {{.Expiry}}. + + @{{.Dominio}} #{{.OTP}} DomainClaimed: Title: ZITADEL - Se ha reclamado un dominio PreHeader: Cambiar dirección de correo electrónico / nombre de usuario diff --git a/internal/notification/static/i18n/fr.yaml b/internal/notification/static/i18n/fr.yaml index fccaaa61f1..43d03253a7 100644 --- a/internal/notification/static/i18n/fr.yaml +++ b/internal/notification/static/i18n/fr.yaml @@ -34,7 +34,10 @@ VerifyEmailOTP: Text: Utilise le bouton 'Authentifier' ou copie le mot de passe à usage unique {{.OTP}} et colle-le à l'écran d'authentification pour t'authentifier sur ZITADEL dans les cinq prochaines minutes. ButtonText: Authentifier VerifySMSOTP: - Text: Visite {{ .VerifyURL }} ou copie le mot de passe à usage unique {{.OTP}} et colle-le à l'écran d'authentification pour t'authentifier sur ZITADEL dans les cinq prochaines minutes. + Text: >- + {{.OTP}} est votre mot de passe à usage unique pour {{ .Domain }}. Utilisez-le dans le prochain {{.Expiry}}. + + @{{.Domaine}} #{{.OTP}} DomainClaimed: Title: ZITADEL - Le domaine a été réclamé PreHeader: Modifier l'email / le nom d'utilisateur diff --git a/internal/notification/static/i18n/it.yaml b/internal/notification/static/i18n/it.yaml index 352aec4af6..ef6d4c5c87 100644 --- a/internal/notification/static/i18n/it.yaml +++ b/internal/notification/static/i18n/it.yaml @@ -34,7 +34,10 @@ VerifyEmailOTP: Text: Per favore, utilizza il pulsante 'Autentica' o copia la password monouso {{.OTP}} e incollala nella schermata di autenticazione per autenticarti a ZITADEL entro i prossimi cinque minuti. ButtonText: Autentica VerifySMSOTP: - Text: Per favore, visita {{ .VerifyURL }} o copia la password monouso {{.OTP}} e incollala nella schermata di autenticazione per autenticarti a ZITADEL entro i prossimi cinque minuti. + Text: >- + {{.OTP}} è la tua password monouso per {{ .Domain }}. Usalo entro il prossimo {{.Expiry}}. + + @{{.Dominio}} #{{.OTP}} DomainClaimed: Title: ZITADEL - Il dominio è stato rivendicato PreHeader: Cambiare email / nome utente diff --git a/internal/notification/static/i18n/ja.yaml b/internal/notification/static/i18n/ja.yaml index 53c1ac3686..1ff5e1eb5a 100644 --- a/internal/notification/static/i18n/ja.yaml +++ b/internal/notification/static/i18n/ja.yaml @@ -31,10 +31,13 @@ VerifyEmailOTP: PreHeader: ワンタイムパスワードを確認する Subject: ワンタイムパスワードを確認する Greeting: こんにちは、{{.DisplayName}}さん - Text: '認証'ボタンを使用するか、ワンタイムパスワード {{.OTP}} をコピーして認証画面に貼り付け、次の5分以内にZITADELで認証してください。 + Text: 認証ボタンを使用するか、ワンタイムパスワード {{.OTP}} をコピーして認証画面に貼り付け、次の5分以内にZITADELで認証してください。 ButtonText: 認証 VerifySMSOTP: - Text: {{ .VerifyURL }} を訪れるか、ワンタイムパスワード {{.OTP}} をコピーして認証画面に貼り付け、次の5分以内にZITADELで認証してください。 + Text: >- + {{.OTP}} は、{{ .Domain }} のワンタイムパスワードです。次の {{.Expiry}} 以内に使用してください。 + + @{{.ドメイン}} #{{.OTP}} DomainClaimed: Title: ZITADEL - ドメインの登録 PreHeader: メールアドレス・ユーザー名の変更 diff --git a/internal/notification/static/i18n/mk.yaml b/internal/notification/static/i18n/mk.yaml index f68cc4c8b8..0614efde79 100644 --- a/internal/notification/static/i18n/mk.yaml +++ b/internal/notification/static/i18n/mk.yaml @@ -34,7 +34,10 @@ VerifyEmailOTP: Text: Ве молам, користи го копчето 'Автентицирај' или копирај ја еднократната лозинка {{.OTP}} и стави ја на екранот за автентикација за да се автентицираш на ZITADEL во следните пет минути. ButtonText: Автентицирај VerifySMSOTP: - Text: Ве молам, посети го {{ .VerifyURL }} или копирај ја еднократната лозинка {{.OTP}} и стави ја на екранот за автентикација за да се автентицираш на ZITADEL во следните пет минути. + Text: >- + {{.OTP}} е вашата еднократна лозинка за {{ .Домен }}. Користете го во следниот {{.Истек}}. + + @{{.Домен}} #{{.OTP}} DomainClaimed: Title: ZITADEL - Доменот е преземен PreHeader: Промена на е-пошта / корисничко име diff --git a/internal/notification/static/i18n/pl.yaml b/internal/notification/static/i18n/pl.yaml index 723e4d3b3c..3f16dab3e4 100644 --- a/internal/notification/static/i18n/pl.yaml +++ b/internal/notification/static/i18n/pl.yaml @@ -34,7 +34,10 @@ VerifyEmailOTP: Text: Proszę, użyj przycisku 'Uwierzytelnij' lub skopiuj hasło jednorazowe {{.OTP}} i wklej go na ekran uwierzytelniania, aby uwierzytelnić się w ZITADEL w ciągu najbliższych pięciu minut. ButtonText: Uwierzytelnij VerifySMSOTP: - Text: Proszę, odwiedź {{ .VerifyURL }} lub skopiuj hasło jednorazowe {{.OTP}} i wklej go na ekran uwierzytelniania, aby uwierzytelnić się w ZITADEL w ciągu najbliższych pięciu minut. + Text: >- + {{.OTP}} to Twoje jednorazowe hasło do domeny {{ .Domain }}. Użyj go w ciągu najbliższych {{.Expiry}}. + + @{{.Domena}} #{{.OTP}} DomainClaimed: Title: ZITADEL - Domena została zarejestrowana PreHeader: Zmiana adresu e-mail / nazwy użytkownika diff --git a/internal/notification/static/i18n/pt.yaml b/internal/notification/static/i18n/pt.yaml index 95f90fdd31..a7a2480b81 100644 --- a/internal/notification/static/i18n/pt.yaml +++ b/internal/notification/static/i18n/pt.yaml @@ -34,7 +34,10 @@ VerifyEmailOTP: Text: Por favor, usa o botão 'Autenticar' ou copia a senha de uso único {{.OTP}} e cola-a na tela de autenticação para te autenticares no ZITADEL nos próximos cinco minutos. ButtonText: Autenticar VerifySMSOTP: - Text: Por favor, visita {{ .VerifyURL }} ou copia a senha de uso único {{.OTP}} e cola-a na tela de autenticação para te autenticares no ZITADEL nos próximos cinco minutos. + Text: >- + {{.OTP}} é sua senha única para {{ .Domain }}. Use-o nos próximos {{.Expiry}}. + + @{{.Domain}} #{{.OTP}} DomainClaimed: Title: ZITADEL - Domínio foi reivindicado PreHeader: Alterar e-mail / nome de usuário diff --git a/internal/notification/static/i18n/zh.yaml b/internal/notification/static/i18n/zh.yaml index f36b2fdb2e..b0dd21cad3 100644 --- a/internal/notification/static/i18n/zh.yaml +++ b/internal/notification/static/i18n/zh.yaml @@ -34,7 +34,10 @@ VerifyEmailOTP: Text: 请使用 '验证' 按钮,或复制一次性密码 {{.OTP}} 并将其粘贴到验证屏幕中,以在接下来的五分钟内在 ZITADEL 中进行验证。 ButtonText: 验证 VerifySMSOTP: - Text: 请访问 {{ .VerifyURL }} 或复制一次性密码 {{.OTP}} 并将其粘贴到身份验证屏幕,以在接下来的五分钟内在ZITADEL进行身份验证。 + Text: >- + {{.OTP}} 是您的 {{ .Domain }} 的一次性密码。在下一个 {{.Expiry}} 内使用它。 + + @{{.Domain}} #{{.OTP}} DomainClaimed: Title: ZITADEL - 域名所有权验证 PreHeader: 更改电子邮件/用户名 diff --git a/internal/notification/types/otp.go b/internal/notification/types/otp.go new file mode 100644 index 0000000000..aea3a5c124 --- /dev/null +++ b/internal/notification/types/otp.go @@ -0,0 +1,29 @@ +package types + +import ( + "time" + + "github.com/zitadel/zitadel/internal/api/ui/login" + "github.com/zitadel/zitadel/internal/domain" + "github.com/zitadel/zitadel/internal/query" +) + +func (notify Notify) SendOTPSMSCode(requestedDomain, origin, code string, expiry time.Duration) error { + args := otpArgs(code, origin, requestedDomain, expiry) + return notify("", args, domain.VerifySMSOTPMessageType, false) +} + +func (notify Notify) SendOTPEmailCode(user *query.NotifyUser, requestedDomain, origin, code, authRequestID string, expiry time.Duration) error { + url := login.OTPLink(origin, authRequestID, code, domain.MFATypeOTPEmail) + args := otpArgs(code, origin, requestedDomain, expiry) + return notify(url, args, domain.VerifyEmailOTPMessageType, false) +} + +func otpArgs(code, origin, requestedDomain string, expiry time.Duration) map[string]interface{} { + args := make(map[string]interface{}) + args["OTP"] = code + args["Origin"] = origin + args["Domain"] = requestedDomain + args["Expiry"] = expiry + return args +} diff --git a/internal/notification/types/phone_verification_code.go b/internal/notification/types/phone_verification_code.go index 88eb744c4b..f833aeb33d 100644 --- a/internal/notification/types/phone_verification_code.go +++ b/internal/notification/types/phone_verification_code.go @@ -5,8 +5,9 @@ import ( "github.com/zitadel/zitadel/internal/query" ) -func (notify Notify) SendPhoneVerificationCode(user *query.NotifyUser, origin, code string) error { +func (notify Notify) SendPhoneVerificationCode(user *query.NotifyUser, origin, code, requestedDomain string) error { args := make(map[string]interface{}) args["Code"] = code + args["Domain"] = requestedDomain return notify("", args, domain.VerifyPhoneMessageType, true) } diff --git a/internal/query/projection/user_auth_method.go b/internal/query/projection/user_auth_method.go index ddaa53c2bd..13b9c6db79 100644 --- a/internal/query/projection/user_auth_method.go +++ b/internal/query/projection/user_auth_method.go @@ -113,6 +113,14 @@ func (p *userAuthMethodProjection) reducers() []handler.AggregateReducer { Event: user.HumanOTPSMSRemovedType, Reduce: p.reduceRemoveAuthMethod, }, + { + Event: user.HumanPhoneRemovedType, + Reduce: p.reduceRemoveAuthMethod, + }, + { + Event: user.UserV1PhoneRemovedType, + Reduce: p.reduceRemoveAuthMethod, + }, { Event: user.HumanOTPEmailRemovedType, Reduce: p.reduceRemoveAuthMethod, diff --git a/internal/repository/instance/secret_generator.go b/internal/repository/instance/secret_generator.go index 013bd53d9c..d2f25422d5 100644 --- a/internal/repository/instance/secret_generator.go +++ b/internal/repository/instance/secret_generator.go @@ -168,7 +168,7 @@ func ChangeSecretGeneratorIncludeDigits(includeDigits bool) func(event *SecretGe func ChangeSecretGeneratorIncludeSymbols(includeSymbols bool) func(event *SecretGeneratorChangedEvent) { return func(e *SecretGeneratorChangedEvent) { - e.IncludeDigits = &includeSymbols + e.IncludeSymbols = &includeSymbols } } diff --git a/internal/repository/user/eventstore.go b/internal/repository/user/eventstore.go index 8aede0d193..414895d5a2 100644 --- a/internal/repository/user/eventstore.go +++ b/internal/repository/user/eventstore.go @@ -91,10 +91,14 @@ func RegisterEventMappers(es *eventstore.Eventstore) { RegisterFilterEventMapper(AggregateType, HumanMFAOTPCheckFailedType, HumanOTPCheckFailedEventMapper). RegisterFilterEventMapper(AggregateType, HumanOTPSMSAddedType, eventstore.GenericEventMapper[HumanOTPSMSAddedEvent]). RegisterFilterEventMapper(AggregateType, HumanOTPSMSRemovedType, eventstore.GenericEventMapper[HumanOTPSMSRemovedEvent]). + RegisterFilterEventMapper(AggregateType, HumanOTPSMSCodeAddedType, eventstore.GenericEventMapper[HumanOTPSMSCodeAddedEvent]). + RegisterFilterEventMapper(AggregateType, HumanOTPSMSCodeSentType, eventstore.GenericEventMapper[HumanOTPSMSCodeSentEvent]). RegisterFilterEventMapper(AggregateType, HumanOTPSMSCheckSucceededType, eventstore.GenericEventMapper[HumanOTPSMSCheckSucceededEvent]). RegisterFilterEventMapper(AggregateType, HumanOTPSMSCheckFailedType, eventstore.GenericEventMapper[HumanOTPSMSCheckFailedEvent]). RegisterFilterEventMapper(AggregateType, HumanOTPEmailAddedType, eventstore.GenericEventMapper[HumanOTPEmailAddedEvent]). RegisterFilterEventMapper(AggregateType, HumanOTPEmailRemovedType, eventstore.GenericEventMapper[HumanOTPEmailRemovedEvent]). + RegisterFilterEventMapper(AggregateType, HumanOTPEmailCodeAddedType, eventstore.GenericEventMapper[HumanOTPEmailCodeAddedEvent]). + RegisterFilterEventMapper(AggregateType, HumanOTPEmailCodeSentType, eventstore.GenericEventMapper[HumanOTPEmailCodeSentEvent]). RegisterFilterEventMapper(AggregateType, HumanOTPEmailCheckSucceededType, eventstore.GenericEventMapper[HumanOTPEmailCheckSucceededEvent]). RegisterFilterEventMapper(AggregateType, HumanOTPEmailCheckFailedType, eventstore.GenericEventMapper[HumanOTPEmailCheckFailedEvent]). RegisterFilterEventMapper(AggregateType, HumanU2FTokenAddedType, HumanU2FAddedEventMapper). diff --git a/internal/repository/user/human_mfa_otp.go b/internal/repository/user/human_mfa_otp.go index 3427dbbfca..52d5ad7a0c 100644 --- a/internal/repository/user/human_mfa_otp.go +++ b/internal/repository/user/human_mfa_otp.go @@ -3,6 +3,7 @@ package user import ( "context" "encoding/json" + "time" "github.com/zitadel/zitadel/internal/eventstore" @@ -21,11 +22,15 @@ const ( otpSMSEventPrefix = otpEventPrefix + "sms." HumanOTPSMSAddedType = otpSMSEventPrefix + "added" HumanOTPSMSRemovedType = otpSMSEventPrefix + "removed" + HumanOTPSMSCodeAddedType = otpSMSEventPrefix + "code.added" + HumanOTPSMSCodeSentType = otpSMSEventPrefix + "code.sent" HumanOTPSMSCheckSucceededType = otpSMSEventPrefix + "check.succeeded" HumanOTPSMSCheckFailedType = otpSMSEventPrefix + "check.failed" otpEmailEventPrefix = otpEventPrefix + "email." HumanOTPEmailAddedType = otpEmailEventPrefix + "added" HumanOTPEmailRemovedType = otpEmailEventPrefix + "removed" + HumanOTPEmailCodeAddedType = otpEmailEventPrefix + "code.added" + HumanOTPEmailCodeSentType = otpEmailEventPrefix + "code.sent" HumanOTPEmailCheckSucceededType = otpEmailEventPrefix + "check.succeeded" HumanOTPEmailCheckFailedType = otpEmailEventPrefix + "check.failed" ) @@ -271,6 +276,78 @@ func NewHumanOTPSMSRemovedEvent( } } +type HumanOTPSMSCodeAddedEvent struct { + eventstore.BaseEvent `json:"-"` + + Code *crypto.CryptoValue `json:"code,omitempty"` + Expiry time.Duration `json:"expiry,omitempty"` + *AuthRequestInfo +} + +func (e *HumanOTPSMSCodeAddedEvent) Data() interface{} { + return e +} + +func (e *HumanOTPSMSCodeAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + return nil +} + +func (e *HumanOTPSMSCodeAddedEvent) SetBaseEvent(event *eventstore.BaseEvent) { + e.BaseEvent = *event +} + +func NewHumanOTPSMSCodeAddedEvent( + ctx context.Context, + aggregate *eventstore.Aggregate, + code *crypto.CryptoValue, + expiry time.Duration, + info *AuthRequestInfo, +) *HumanOTPSMSCodeAddedEvent { + return &HumanOTPSMSCodeAddedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + HumanOTPSMSCodeAddedType, + ), + Code: code, + Expiry: expiry, + AuthRequestInfo: info, + } +} + +type HumanOTPSMSCodeSentEvent struct { + eventstore.BaseEvent `json:"-"` + + Code *crypto.CryptoValue `json:"code,omitempty"` + Expiry time.Duration `json:"expiry,omitempty"` + *AuthRequestInfo +} + +func (e *HumanOTPSMSCodeSentEvent) Data() interface{} { + return e +} + +func (e *HumanOTPSMSCodeSentEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + return nil +} + +func (e *HumanOTPSMSCodeSentEvent) SetBaseEvent(event *eventstore.BaseEvent) { + e.BaseEvent = *event +} + +func NewHumanOTPSMSCodeSentEvent( + ctx context.Context, + aggregate *eventstore.Aggregate, +) *HumanOTPSMSCodeSentEvent { + return &HumanOTPSMSCodeSentEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + HumanOTPSMSCodeSentType, + ), + } +} + type HumanOTPSMSCheckSucceededEvent struct { eventstore.BaseEvent `json:"-"` *AuthRequestInfo @@ -393,6 +470,78 @@ func NewHumanOTPEmailRemovedEvent( } } +type HumanOTPEmailCodeAddedEvent struct { + eventstore.BaseEvent `json:"-"` + + Code *crypto.CryptoValue `json:"code,omitempty"` + Expiry time.Duration `json:"expiry,omitempty"` + *AuthRequestInfo +} + +func (e *HumanOTPEmailCodeAddedEvent) Data() interface{} { + return e +} + +func (e *HumanOTPEmailCodeAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + return nil +} + +func (e *HumanOTPEmailCodeAddedEvent) SetBaseEvent(event *eventstore.BaseEvent) { + e.BaseEvent = *event +} + +func NewHumanOTPEmailCodeAddedEvent( + ctx context.Context, + aggregate *eventstore.Aggregate, + code *crypto.CryptoValue, + expiry time.Duration, + info *AuthRequestInfo, +) *HumanOTPEmailCodeAddedEvent { + return &HumanOTPEmailCodeAddedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + HumanOTPEmailCodeAddedType, + ), + Code: code, + Expiry: expiry, + AuthRequestInfo: info, + } +} + +type HumanOTPEmailCodeSentEvent struct { + eventstore.BaseEvent `json:"-"` + + Code *crypto.CryptoValue `json:"code,omitempty"` + Expiry time.Duration `json:"expiry,omitempty"` + *AuthRequestInfo +} + +func (e *HumanOTPEmailCodeSentEvent) Data() interface{} { + return e +} + +func (e *HumanOTPEmailCodeSentEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + return nil +} + +func (e *HumanOTPEmailCodeSentEvent) SetBaseEvent(event *eventstore.BaseEvent) { + e.BaseEvent = *event +} + +func NewHumanOTPEmailCodeSentEvent( + ctx context.Context, + aggregate *eventstore.Aggregate, +) *HumanOTPEmailCodeSentEvent { + return &HumanOTPEmailCodeSentEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + HumanOTPEmailCodeSentType, + ), + } +} + type HumanOTPEmailCheckSucceededEvent struct { eventstore.BaseEvent `json:"-"` *AuthRequestInfo diff --git a/internal/static/i18n/bg.yaml b/internal/static/i18n/bg.yaml index b719bf191f..319d4af86f 100644 --- a/internal/static/i18n/bg.yaml +++ b/internal/static/i18n/bg.yaml @@ -630,6 +630,24 @@ EventTypes: check: succeeded: Многофакторната OTP проверка е успешна failed: Многофакторната OTP проверка е неуспешна + sms: + added: Добавен Многофакторната OTP SMS + removed: Премахнато многофакторно OTP SMS + code: + added: Добавен многофакторен OTP SMS код + sent: Многофакторната OTP SMS код е изпратен + check: + succeeded: Успешна многофакторна OTP SMS проверка + failed: Многофакторната OTP проверка на SMS не бе успешна + email: + added: Добавен Многофакторната OTP имейл + removed: Премахнат многофакторен OTP имейл + code: + added: Добавен многофакторен OTP имейл код + sent: Многофакторният OTP имейл код е изпратен + check: + succeeded: Многофакторната еднократна имейл потвърждение е успешна + failed: Многофакторната OTP проверка на имейл не бе успешна u2f: token: added: Добавен е многофакторен U2F токен diff --git a/internal/static/i18n/de.yaml b/internal/static/i18n/de.yaml index ff6c85d6ad..774f87f7dd 100644 --- a/internal/static/i18n/de.yaml +++ b/internal/static/i18n/de.yaml @@ -618,6 +618,24 @@ EventTypes: check: succeeded: Multifaktor OTP Verifikation erfolgreich failed: Multifaktor OTP Verifikation fehlgeschlagen + sms: + added: Multifaktor OTP SMS hinzugefügt + removed: Multifaktor OTP SMS entfernt + code: + added: Multifaktor OTP SMS Code hinzugefügt + sent: Multifaktor OTP SMS Code versendet + check: + succeeded: Multifaktor OTP SMS Verifikation erfolgreich + failed: Multifaktor OTP SMS Verifikation fehlgeschlagen + email: + added: Multifaktor OTP Email hinzugefügt + removed: Multifaktor OTP Email entfernt + code: + added: Multifaktor OTP Email Code hinzugefügt + sent: Multifaktor OTP Email Code versendet + check: + succeeded: Multifaktor OTP Email Verifikation erfolgreich + failed: Multifaktor OTP Email Verifikation fehlgeschlagen u2f: token: added: Multifaktor U2F Token hinzugefügt diff --git a/internal/static/i18n/en.yaml b/internal/static/i18n/en.yaml index 9058c15d97..d6e84e5814 100644 --- a/internal/static/i18n/en.yaml +++ b/internal/static/i18n/en.yaml @@ -618,6 +618,24 @@ EventTypes: check: succeeded: Multifactor OTP check succeeded failed: Multifactor OTP check failed + sms: + added: Multifactor OTP SMS added + removed: Multifactor OTP SMS removed + code: + added: Multifactor OTP SMS code added + sent: Multifactor OTP SMS code sent + check: + succeeded: Multifactor OTP SMS check succeeded + failed: Multifactor OTP SMS check failed + email: + added: Multifactor OTP Email added + removed: Multifactor OTP Email removed + code: + added: Multifactor OTP Email code added + sent: Multifactor OTP Email code sent + check: + succeeded: Multifactor OTP Email check succeeded + failed: Multifactor OTP Email check failed u2f: token: added: Multifactor U2F Token added diff --git a/internal/static/i18n/es.yaml b/internal/static/i18n/es.yaml index 475280504d..95af0e0714 100644 --- a/internal/static/i18n/es.yaml +++ b/internal/static/i18n/es.yaml @@ -618,6 +618,24 @@ EventTypes: check: succeeded: Comprobación exitosa de Multifactor OTP failed: Comprobación fallida de Multifactor OTP + sms: + added: Multifactor OTP SMS añadido + removed: Multifactor OTP SMS elimonado + code: + added: Código Multifactor OTP SMS añadido + sent: Código Multifactor OTP SMS enviado + check: + succeeded: Comprobación Multifactor OTP SMS exitosa + failed: Comprobación Multifactor OTP SMS fallida + email: + added: Multifactor OTP email añadido + removed: Multifactor OTP email elimonado + code: + added: Código Multifactor OTP email añadido + sent: Código Multifactor OTP email enviado + check: + succeeded: Comprobación Multifactor OTP email exitosa + failed: Comprobación Multifactor OTP email fallida u2f: token: added: Multifactor U2F Token añadido diff --git a/internal/static/i18n/fr.yaml b/internal/static/i18n/fr.yaml index 54ad40236b..f0a1b1df45 100644 --- a/internal/static/i18n/fr.yaml +++ b/internal/static/i18n/fr.yaml @@ -616,6 +616,24 @@ EventTypes: check: succeeded: Vérification de l'OTP multifactorielle réussie failed: La vérification de l'OTP multifactorielle a échoué + sms: + added: Ajout de SMS OTP multifactoriels + removed: Suppression des SMS OTP multifactoriels + code: + added: Ajout du code SMS OTP multifactoriel + sent: Code SMS OTP multifacteur envoyé + check: + succeeded: Vérification par SMS OTP multifacteur réussie + failed: Échec de la vérification par SMS OTP multifacteur + email: + added: Ajout d'un e-mail OTP multifactoriel + removed: Suppression de l'e-mail OTP multifacteur + code: + added: Ajout d'un code de messagerie OTP multifactoriel + sent: Code de messagerie OTP multifacteur envoyé + check: + succeeded: Vérification de l'e-mail OTP multifacteur réussie + failed: Échec de la vérification de l'e-mail OTP multifacteur u2f: token: added: Ajout d'un jeton U2F multifacteur diff --git a/internal/static/i18n/it.yaml b/internal/static/i18n/it.yaml index 958eea5b12..3e70d4f6a8 100644 --- a/internal/static/i18n/it.yaml +++ b/internal/static/i18n/it.yaml @@ -616,6 +616,24 @@ EventTypes: check: succeeded: Controllo OTP riuscito failed: Controllo OTP fallito + sms: + added: Aggiunto SMS OTP + removed: OTP SMS rimosso + code: + added: Aggiunto codice OTP SMS + sent: Codice OTP SMS inviato + check: + succeeded: Controllo OTP SMS riuscito + failed: Controllo OTP SMS fallito + email: + added: Aggiunto OTP e-mail + removed: OTP e-mail rimosso + code: + added: Aggiunto codice OTP e-mail + sent: Codice OTP e-mail inviato + check: + succeeded: OTP Controllo e-mail riuscito + failed: OTP Controllo e-mail fallito u2f: token: added: Aggiunto il U2F Token diff --git a/internal/static/i18n/ja.yaml b/internal/static/i18n/ja.yaml index c0a735c1e8..d1e5cdfa47 100644 --- a/internal/static/i18n/ja.yaml +++ b/internal/static/i18n/ja.yaml @@ -603,6 +603,24 @@ EventTypes: check: succeeded: MFA OTPチェックの成功 failed: MFA OTPチェックの失敗 + sms: + added: 多要素 OTP SMS を追加しました + removed: 多要素 OTP SMS を削除しました + code: + added: 多要素 OTP SMS コードを追加しました + sent: 多要素 OTP SMS コードが送信されました + check: + succeeded: 多要素 OTP SMS 検証が成功しました + failed: 多要素 OTP SMS 検証が失敗しました + email: + added: 多要素 OTP 電子メールを追加しました + removed: 多要素 OTP 電子メールを削除しました + code: + added: 多要素 OTP 電子メール コードを追加しました + sent: 多要素 OTP 電子メール コードが送信されました + check: + succeeded: 多要素 OTP 電子メール検証が成功しました + failed: 多要素 OTP 電子メール検証が失敗しました u2f: token: added: MFA U2Fトークンの追加 diff --git a/internal/static/i18n/mk.yaml b/internal/static/i18n/mk.yaml index 36d1b1c748..4d2afce3c6 100644 --- a/internal/static/i18n/mk.yaml +++ b/internal/static/i18n/mk.yaml @@ -614,6 +614,24 @@ EventTypes: check: succeeded: Проверката на мултифактор OTP е успешна failed: Проверката на мултифактор OTP е неуспешна + sms: + added: Додадена е мултифакторна OTP SMS + removed: Отстранета мултифакторна OTP SMS + code: + added: Додаден мултифакторски OTP SMS код + sent: Мултифакторен OTP СМС-код е испратен + check: + succeeded: Мултифакторна OTP СМС-верификација е успешна + failed: Мултифакторна OTP СМС-верификација не успеа + email: + added: Додадена е повеќефакторна OTP е-пошта + removed: Отстранета мултифакторна OTP е-пошта + code: + added: Додаден мултифакторски OTP код за е-пошта + sent: Испратен е-пошта OTP-код со повеќе фактори + check: + succeeded: Успешна е-пошта OTP-верификација на мултифактор + failed: Неуспешна потврда на е-пошта OTP со повеќе фактори u2f: token: added: Додаден мултифактор U2F токен diff --git a/internal/static/i18n/pl.yaml b/internal/static/i18n/pl.yaml index 1e831f6824..adde4501aa 100644 --- a/internal/static/i18n/pl.yaml +++ b/internal/static/i18n/pl.yaml @@ -618,6 +618,24 @@ EventTypes: check: succeeded: Sprawdzenie wielofaktorowego OTP zakończone powodzeniem failed: Sprawdzenie wielofaktorowego OTP nie powiodło się + sms: + added: Dodano wieloskładnikowy SMS OTP + removed: Usunięto wieloskładnikowy SMS OTP + code: + added: Dodano wieloczynnikowy kod SMS OTP + sent: Wysłano kod SMS Multifactor OTP + check: + succeeded: Pomyślna weryfikacja wieloczynnikowego SMS-a OTP + failed: Wieloskładnikowa weryfikacja wiadomości SMS OTP nie powiodła się + email: + added: Dodano wieloskładnikowy e-mail OTP + removed: Usunięto wieloskładnikowy e-mail OTP + code: + added: Dodano wieloskładnikowy kod e-mail OTP + sent: Wysłano kod e-mail Multifactor OTP + check: + succeeded: Pomyślna wieloczynnikowa weryfikacja adresu e-mail OTP + failed: Wieloczynnikowa weryfikacja adresu e-mail OTP nie powiodła się u2f: token: added: Dodano token wielofaktorowego U2F diff --git a/internal/static/i18n/pt.yaml b/internal/static/i18n/pt.yaml index 9b823dbfec..00f3f1a055 100644 --- a/internal/static/i18n/pt.yaml +++ b/internal/static/i18n/pt.yaml @@ -609,6 +609,24 @@ EventTypes: check: succeeded: Verificação de OTP de autenticação multifator bem-sucedida failed: Verificação de OTP de autenticação multifator falhou + sms: + added: Adicionado SMS OTP multifator + removed: SMS OTP multifator removido + code: + added: Adicionado código SMS OTP multifator + sent: Código SMS OTP multifator enviado + check: + succeeded: Verificação multifator OTP SMS bem-sucedida + failed: Falha na verificação multifator OTP SMS + email: + added: Adicionado e-mail OTP multifator + removed: E-mail OTP multifator removido + code: + added: Adicionado código de e-mail OTP multifator + sent: Código de e-mail OTP multifator enviado + check: + succeeded: Verificação de e-mail OTP multifator bem-sucedida + failed: Falha na verificação de e-mail OTP multifator u2f: token: added: Token U2F de autenticação multifator adicionado diff --git a/internal/static/i18n/zh.yaml b/internal/static/i18n/zh.yaml index c1d7229cce..fb1d158c62 100644 --- a/internal/static/i18n/zh.yaml +++ b/internal/static/i18n/zh.yaml @@ -612,6 +612,24 @@ EventTypes: check: succeeded: 验证 MFA OTP 成功 failed: 验证 MFA OTP 失败 + sms: + added: 添加了多因素 OTP 短信 + removed: 删除了多因素 OTP 短信 + code: + added: 添加了多因素 OTP 短信代码 + sent: 已发送多因素 OTP 短信代码 + check: + succeeded: 多因素 OTP 短信验证成功 + failed: 多因素 OTP 短信验证失败 + email: + added: 添加了多因素 OTP 电子邮件 + removed: 删除了多因素 OTP 电子邮件 + code: + added: 添加了多因素 OTP 电子邮件代码 + sent: 已发送多因素 OTP 电子邮件代码 + check: + succeeded: 多因素 OTP 电子邮件验证成功 + failed: 多因素 OTP 电子邮件验证失败 u2f: token: added: 添加 MFA U2F 令牌 diff --git a/internal/user/model/user_view.go b/internal/user/model/user_view.go index 5bc7c9a119..dac8b8a558 100644 --- a/internal/user/model/user_view.go +++ b/internal/user/model/user_view.go @@ -49,6 +49,8 @@ type HumanView struct { Region string StreetAddress string OTPState MFAState + OTPSMSAdded bool + OTPEmailAdded bool U2FTokens []*WebAuthNView PasswordlessTokens []*WebAuthNView MFAMaxSetUp domain.MFALevel @@ -162,10 +164,17 @@ func (u *UserView) MFATypesSetupPossible(level domain.MFALevel, policy *domain.L } case domain.SecondFactorTypeU2F: types = append(types, domain.MFATypeU2F) + case domain.SecondFactorTypeOTPSMS: + if !u.OTPSMSAdded { + types = append(types, domain.MFATypeOTPSMS) + } + case domain.SecondFactorTypeOTPEmail: + if !u.OTPEmailAdded { + types = append(types, domain.MFATypeOTPEmail) + } } } } - //PLANNED: add sms } return types } @@ -189,10 +198,17 @@ func (u *UserView) MFATypesAllowed(level domain.MFALevel, policy *domain.LoginPo if u.IsU2FReady() { types = append(types, domain.MFATypeU2F) } + case domain.SecondFactorTypeOTPSMS: + if u.OTPSMSAdded { + types = append(types, domain.MFATypeOTPSMS) + } + case domain.SecondFactorTypeOTPEmail: + if u.OTPEmailAdded { + types = append(types, domain.MFATypeOTPEmail) + } } } } - //PLANNED: add sms } return types, required } diff --git a/internal/user/repository/view/model/user.go b/internal/user/repository/view/model/user.go index d5d9134782..db9f50371d 100644 --- a/internal/user/repository/view/model/user.go +++ b/internal/user/repository/view/model/user.go @@ -89,6 +89,8 @@ type HumanView struct { Region string `json:"region" gorm:"column:region"` StreetAddress string `json:"streetAddress" gorm:"column:street_address"` OTPState int32 `json:"-" gorm:"column:otp_state"` + OTPSMSAdded bool `json:"-" gorm:"column:otp_sms_added"` + OTPEmailAdded bool `json:"-" gorm:"column:otp_email_added"` U2FTokens WebAuthNTokens `json:"-" gorm:"column:u2f_tokens"` MFAMaxSetUp int32 `json:"-" gorm:"column:mfa_max_set_up"` MFAInitSkipped time.Time `json:"-" gorm:"column:mfa_init_skipped"` @@ -178,6 +180,8 @@ func UserToModel(user *UserView) *model.UserView { Region: user.Region, StreetAddress: user.StreetAddress, OTPState: model.MFAState(user.OTPState), + OTPSMSAdded: user.OTPSMSAdded, + OTPEmailAdded: user.OTPEmailAdded, MFAMaxSetUp: domain.MFALevel(user.MFAMaxSetUp), MFAInitSkipped: user.MFAInitSkipped, InitRequired: user.InitRequired, @@ -301,6 +305,8 @@ func (u *UserView) AppendEvent(event *models.Event) (err error) { user.HumanPhoneRemovedType: u.Phone = "" u.IsPhoneVerified = false + u.OTPSMSAdded = false + u.MFAInitSkipped = time.Time{} case user.UserDeactivatedType: u.State = int32(model.UserStateInactive) case user.UserReactivatedType, @@ -326,6 +332,16 @@ func (u *UserView) AppendEvent(event *models.Event) (err error) { case user.UserV1MFAOTPRemovedType, user.HumanMFAOTPRemovedType: u.OTPState = int32(model.MFAStateUnspecified) + case user.HumanOTPSMSAddedType: + u.OTPSMSAdded = true + case user.HumanOTPSMSRemovedType: + u.OTPSMSAdded = false + u.MFAInitSkipped = time.Time{} + case user.HumanOTPEmailAddedType: + u.OTPEmailAdded = true + case user.HumanOTPEmailRemovedType: + u.OTPEmailAdded = false + u.MFAInitSkipped = time.Time{} case user.HumanU2FTokenAddedType: err = u.addU2FToken(event) case user.HumanU2FTokenVerifiedType: @@ -520,7 +536,8 @@ func (u *UserView) ComputeMFAMaxSetUp() { return } } - if u.OTPState == int32(model.MFAStateReady) { + if u.OTPState == int32(model.MFAStateReady) || + u.OTPSMSAdded || u.OTPEmailAdded { u.MFAMaxSetUp = int32(domain.MFALevelSecondFactor) return } @@ -575,6 +592,10 @@ func (u *UserView) EventTypes() []models.EventType { models.EventType(user.HumanMFAOTPVerifiedType), models.EventType(user.UserV1MFAOTPRemovedType), models.EventType(user.HumanMFAOTPRemovedType), + models.EventType(user.HumanOTPSMSAddedType), + models.EventType(user.HumanOTPSMSRemovedType), + models.EventType(user.HumanOTPEmailAddedType), + models.EventType(user.HumanOTPEmailRemovedType), models.EventType(user.HumanU2FTokenAddedType), models.EventType(user.HumanU2FTokenVerifiedType), models.EventType(user.HumanU2FTokenRemovedType), diff --git a/internal/user/repository/view/model/user_session.go b/internal/user/repository/view/model/user_session.go index ec611c16fa..63eb5e0a76 100644 --- a/internal/user/repository/view/model/user_session.go +++ b/internal/user/repository/view/model/user_session.go @@ -139,12 +139,32 @@ func (v *UserSessionView) AppendEvent(event *models.Event) error { case user.UserV1MFAOTPCheckSucceededType, user.HumanMFAOTPCheckSucceededType: v.setSecondFactorVerification(event.CreationDate, domain.MFATypeTOTP) + case user.HumanOTPSMSCheckSucceededType: + data := new(es_model.OTPVerified) + err := data.SetData(event) + if err != nil { + return err + } + if v.UserAgentID == data.UserAgentID { + v.setSecondFactorVerification(event.CreationDate, domain.MFATypeOTPSMS) + } + case user.HumanOTPEmailCheckSucceededType: + data := new(es_model.OTPVerified) + err := data.SetData(event) + if err != nil { + return err + } + if v.UserAgentID == data.UserAgentID { + v.setSecondFactorVerification(event.CreationDate, domain.MFATypeOTPEmail) + } case user.UserV1MFAOTPCheckFailedType, user.UserV1MFAOTPRemovedType, user.HumanMFAOTPCheckFailedType, user.HumanMFAOTPRemovedType, user.HumanU2FTokenCheckFailedType, - user.HumanU2FTokenRemovedType: + user.HumanU2FTokenRemovedType, + user.HumanOTPSMSCheckFailedType, + user.HumanOTPEmailCheckFailedType: v.SecondFactorVerification = time.Time{} case user.HumanU2FTokenVerifiedType: data := new(es_model.WebAuthNVerify) @@ -218,6 +238,10 @@ func (v *UserSessionView) EventTypes() []models.EventType { models.EventType(user.UserV1MFAOTPRemovedType), models.EventType(user.HumanMFAOTPCheckFailedType), models.EventType(user.HumanMFAOTPRemovedType), + models.EventType(user.HumanOTPSMSCheckSucceededType), + models.EventType(user.HumanOTPSMSCheckFailedType), + models.EventType(user.HumanOTPEmailCheckSucceededType), + models.EventType(user.HumanOTPEmailCheckFailedType), models.EventType(user.HumanU2FTokenCheckFailedType), models.EventType(user.HumanU2FTokenRemovedType), models.EventType(user.HumanU2FTokenVerifiedType), From d83681a928717c1edbec436e910513cbfd0ead88 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Tue, 15 Aug 2023 16:05:00 +0200 Subject: [PATCH 32/38] fix(login): mfa prompt styles (#6366) * feat: login with otp * fix(i18n): japanese translation * add missing files * fix provider change * add event types translations to en * add tests * resourceOwner * remove unused handler * fix: secret generators and add comments * add setup step * rename * linting * fix setup * improve otp handling * fix autocomplete * translations for login and notifications * translations for event types * fix: mfa prompt styles * fix merge * fix merge * fix html * rm unused files --------- Co-authored-by: Livio Spring --- .../static/resources/images/mfa/mfa-otp.svg | 58 --------------- .../static/resources/images/mfa/mfa-u2f.svg | 51 -------------- .../themes/scss/styles/mfa/mfa_base.scss | 53 +++++++------- .../themes/scss/styles/mfa/mfa_theme.scss | 30 ++++---- .../themes/scss/styles/radio/radio_base.scss | 4 +- .../ui/login/static/templates/mfa_prompt.html | 70 +++++++++++++++---- 6 files changed, 100 insertions(+), 166 deletions(-) delete mode 100644 internal/api/ui/login/static/resources/images/mfa/mfa-otp.svg delete mode 100644 internal/api/ui/login/static/resources/images/mfa/mfa-u2f.svg diff --git a/internal/api/ui/login/static/resources/images/mfa/mfa-otp.svg b/internal/api/ui/login/static/resources/images/mfa/mfa-otp.svg deleted file mode 100644 index 2a3a326f6f..0000000000 --- a/internal/api/ui/login/static/resources/images/mfa/mfa-otp.svg +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/internal/api/ui/login/static/resources/images/mfa/mfa-u2f.svg b/internal/api/ui/login/static/resources/images/mfa/mfa-u2f.svg deleted file mode 100644 index 75e4f19202..0000000000 --- a/internal/api/ui/login/static/resources/images/mfa/mfa-u2f.svg +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/internal/api/ui/login/static/resources/themes/scss/styles/mfa/mfa_base.scss b/internal/api/ui/login/static/resources/themes/scss/styles/mfa/mfa_base.scss index baba57416e..b53804641e 100644 --- a/internal/api/ui/login/static/resources/themes/scss/styles/mfa/mfa_base.scss +++ b/internal/api/ui/login/static/resources/themes/scss/styles/mfa/mfa_base.scss @@ -1,43 +1,46 @@ @mixin lgn-mfa-base { display: flex; - flex-direction: row; - flex-wrap: wrap; - justify-content: space-evenly; - margin: 1rem 0; + flex-direction: column; + margin: 2rem 0; .mfa { display: flex; - flex-direction: column; + flex-direction: row; align-items: center; flex: 1; - padding: 1rem 0.5rem; + margin: 0.5rem 0; + position: relative; + + input[type="radio"] { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + } label { display: flex; - flex-direction: column; + flex-direction: row; align-items: center; - position: relative; - - input[type="radio"] { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - } - - span { - text-align: center; - } + border-radius: 0.5rem; + padding: 1rem; + width: 100%; .mfa-img { - border-width: 1px; - border-style: solid; - border-radius: 0.5rem; - padding: 1rem; + height: 40px; + width: 40px; + object-fit: contain; + object-position: center; display: flex; - margin-bottom: 0.5rem; transition: all 0.2s ease; + + &.fingerprint, + &.email, + &.sms { + padding: 0.25rem; + box-sizing: border-box; + } } } } diff --git a/internal/api/ui/login/static/resources/themes/scss/styles/mfa/mfa_theme.scss b/internal/api/ui/login/static/resources/themes/scss/styles/mfa/mfa_theme.scss index 5437c92844..1f671f08a5 100644 --- a/internal/api/ui/login/static/resources/themes/scss/styles/mfa/mfa_theme.scss +++ b/internal/api/ui/login/static/resources/themes/scss/styles/mfa/mfa_theme.scss @@ -4,26 +4,26 @@ @mixin lgn-mfa-theme() { .lgn-mfa-options { .mfa { - label { - input[type="radio"] { - &:hover, - &:focus { - + .mfa-img { - background-color: var(--zitadel-color-card-hover); - border-color: var(--zitadel-color-input-border-hover); - } - } + input[type="radio"] { + &:hover, + &:focus { + background-color: var(--zitadel-color-card-hover); + border-color: var(--zitadel-color-input-border-hover); } + } + + label { + border: 1px solid var(--zitadel-color-input-border); .mfa-img { - border: 1px solid var(--zitadel-color-input-border); + margin-right: 1rem; } + } - input[type="radio"]:checked + .mfa-img { - background-color: var(--zitadel-color-card-hover); - border: 1px solid var(--zitadel-color-input-border-active); - box-shadow: 0 0 0 2px var(--zitadel-color-input-border-active); - } + input[type="radio"]:checked + label { + background-color: var(--zitadel-color-card-hover); + border: 1px solid var(--zitadel-color-input-border-active); + box-shadow: 0 0 0 2px var(--zitadel-color-input-border-active); } } } diff --git a/internal/api/ui/login/static/resources/themes/scss/styles/radio/radio_base.scss b/internal/api/ui/login/static/resources/themes/scss/styles/radio/radio_base.scss index 05329f0476..3c8fd1a626 100644 --- a/internal/api/ui/login/static/resources/themes/scss/styles/radio/radio_base.scss +++ b/internal/api/ui/login/static/resources/themes/scss/styles/radio/radio_base.scss @@ -61,8 +61,8 @@ $lgn-radio-label-padding: 0 0 0 ($lgn-radio-size + 10px); } &::after { - top: $lgn-radio-size / 2 - $lgn-radio-checked-size / 2; - left: $lgn-radio-size / 2 - $lgn-radio-checked-size / 2; + top: calc($lgn-radio-size / 2) - calc($lgn-radio-checked-size / 2); + left: calc($lgn-radio-size / 2) - calc($lgn-radio-checked-size / 2); width: $lgn-radio-checked-size; height: $lgn-radio-checked-size; transform: scale(0); diff --git a/internal/api/ui/login/static/templates/mfa_prompt.html b/internal/api/ui/login/static/templates/mfa_prompt.html index 17170eb0bb..8ee9ed659d 100644 --- a/internal/api/ui/login/static/templates/mfa_prompt.html +++ b/internal/api/ui/login/static/templates/mfa_prompt.html @@ -16,34 +16,74 @@ {{ range $provider := .MFAProviders}} {{ $providerName := (t (printf "InitMFAPrompt.Provider%v" $provider)) }}
-