From 8659ba394dcf3ee805eecc883eaa69371053aa3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Nu=C3=B1ez?= <10672208+mind-ar@users.noreply.github.com> Date: Sat, 2 Apr 2022 19:32:57 -0300 Subject: [PATCH] feat(authentication): password policy (#2723) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement a password policy with visual feedback in the web portal. Co-authored-by: Manuel Nuñez <@mind-ar> Co-authored-by: James Elliott --- docs/configuration/password_policy.md | 110 +++ docs/features/password-policy.md | 36 + docs/images/password-policy-classic-1.png | Bin 0 -> 29148 bytes docs/images/password-policy-zxcvbn-1.png | Bin 0 -> 19746 bytes .../configuration/schema/configuration.go | 14 +- .../configuration/schema/password_policy.go | 40 + .../configuration/validator/configuration.go | 2 + internal/configuration/validator/const.go | 11 + .../validator/password_policy.go | 33 + internal/handlers/const.go | 1 + internal/handlers/errors.go | 5 + .../handlers/handler_reset_password_step1.go | 23 +- .../handlers/handler_reset_password_step2.go | 57 ++ internal/handlers/types.go | 12 + internal/suites/Standalone/configuration.yml | 17 + internal/utils/bools.go | 32 + internal/utils/bools_test.go | 114 +++ web/package.json | 3 +- web/pnpm-lock.yaml | 786 ++++++------------ web/src/components/PasswordMeter.test.tsx | 13 + web/src/components/PasswordMeter.tsx | 138 +++ web/src/i18n/locales/en.json | 9 +- web/src/i18n/locales/es.json | 9 +- .../ResetPassword/ResetPasswordStep2.tsx | 63 +- 24 files changed, 964 insertions(+), 564 deletions(-) create mode 100644 docs/configuration/password_policy.md create mode 100644 docs/features/password-policy.md create mode 100644 docs/images/password-policy-classic-1.png create mode 100644 docs/images/password-policy-zxcvbn-1.png create mode 100644 internal/configuration/schema/password_policy.go create mode 100644 internal/configuration/validator/password_policy.go create mode 100644 internal/handlers/errors.go create mode 100644 internal/utils/bools.go create mode 100644 internal/utils/bools_test.go create mode 100644 web/src/components/PasswordMeter.test.tsx create mode 100644 web/src/components/PasswordMeter.tsx diff --git a/docs/configuration/password_policy.md b/docs/configuration/password_policy.md new file mode 100644 index 000000000..9ce29cce9 --- /dev/null +++ b/docs/configuration/password_policy.md @@ -0,0 +1,110 @@ +--- +layout: default +title: Password Policy +parent: Configuration +nav_order: 17 +--- + +# Password Policy +_Authelia_ allows administrators to configure an enforced password policy. + +## Configuration + +```yaml +password_policy: + standard: + enabled: false + min_length: 8 + max_length: 0 + require_uppercase: true + require_lowercase: true + require_number: true + require_special: true + zxcvbn: + enabled: false +``` + +## Options + +### standard +
+type: list +{: .label .label-config .label-purple } +required: no +{: .label .label-config .label-green } +
+ +This section allows you to enable standard security policies. +#### enabled +type: bool +{: .label .label-config .label-purple } +required: no +{: .label .label-config .label-green } + +Enables standard password policy + +#### min_length +type: integer +{: .label .label-config .label-purple } +required: no +{: .label .label-config .label-green } + +Determines the minimum allowed password length + +#### max_length +type: integer +{: .label .label-config .label-purple } +required: no +{: .label .label-config .label-green } + +Determines the maximum allowed password length + +#### require_uppercase +type: bool +{: .label .label-config .label-purple } +required: no +{: .label .label-config .label-green } + +Indicates that at least one UPPERCASE letter must be provided as part of the password + +#### require_lowercase +type: bool +{: .label .label-config .label-purple } +required: no +{: .label .label-config .label-green } + +Indicates that at least one lowercase letter must be provided as part of the password + +#### require_number +type: bool +{: .label .label-config .label-purple } +required: no +{: .label .label-config .label-green } + +Indicates that at least one number must be provided as part of the password + +#### require_special +type: bool +{: .label .label-config .label-purple } +required: no +{: .label .label-config .label-green } + +Indicates that at least one special character must be provided as part of the password + + +### zxcvbn +This password policy enables advanced password strengh metering, using [Dropbox zxcvbn package](https://github.com/dropbox/zxcvbn). + +Note that this password policy do not restrict the user's entry, just warns the user that if their password is too weak + + +#### enabled +type: bool +{: .label .label-config .label-purple } +required: no +{: .label .label-config .label-green } + +Enables standard password policy + +Note: +* only one password policy can be applied at a time diff --git a/docs/features/password-policy.md b/docs/features/password-policy.md new file mode 100644 index 000000000..4ca1ae1ee --- /dev/null +++ b/docs/features/password-policy.md @@ -0,0 +1,36 @@ +--- +layout: default +title: Password Policy +parent: Features +nav_order: 8 +--- + +# Password Policy +Password policy enforces the security by requering the users to use strong passwords +Currently, two methods are supported: +## classic +* this mode of operation allows administrators to set the rules that user passwords must comply with +* the available options are: + * Minimum password length + * Require Uppercase + * Require Lowercase + * Require Numbers + * Require Special characters +* when changing the password users must meet these rules + + +

+ +

+ + +## zxcvbn +* this mode uses zxcvbn for password strength checking (see: https://github.com/dropbox/zxcvbn) +* in this mode of operation, the user is not forced to follow any rules. the user is notified if their passwords is weak or strong +

+ +

+ + + + diff --git a/docs/images/password-policy-classic-1.png b/docs/images/password-policy-classic-1.png new file mode 100644 index 0000000000000000000000000000000000000000..3f844827d1634e97655239b6d9952783a22f90a6 GIT binary patch literal 29148 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 Fe*+}bHv0eo literal 0 HcmV?d00001 diff --git a/docs/images/password-policy-zxcvbn-1.png b/docs/images/password-policy-zxcvbn-1.png new file mode 100644 index 0000000000000000000000000000000000000000..1aa2d14ee341d90f162aabe64b57c5315afa4c07 GIT binary patch literal 19746 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 literal 0 HcmV?d00001 diff --git a/internal/configuration/schema/configuration.go b/internal/configuration/schema/configuration.go index bf75813d4..fe2803ada 100644 --- a/internal/configuration/schema/configuration.go +++ b/internal/configuration/schema/configuration.go @@ -10,14 +10,16 @@ type Configuration struct { Log LogConfiguration `koanf:"log"` IdentityProviders IdentityProvidersConfiguration `koanf:"identity_providers"` AuthenticationBackend AuthenticationBackendConfiguration `koanf:"authentication_backend"` - Session SessionConfiguration `koanf:"session"` TOTP TOTPConfiguration `koanf:"totp"` + Webauthn WebauthnConfiguration `koanf:"webauthn"` DuoAPI *DuoAPIConfiguration `koanf:"duo_api"` AccessControl AccessControlConfiguration `koanf:"access_control"` - NTP NTPConfiguration `koanf:"ntp"` Regulation RegulationConfiguration `koanf:"regulation"` - Storage StorageConfiguration `koanf:"storage"` - Notifier *NotifierConfiguration `koanf:"notifier"` - Server ServerConfiguration `koanf:"server"` - Webauthn WebauthnConfiguration `koanf:"webauthn"` + + Server ServerConfiguration `koanf:"server"` + Session SessionConfiguration `koanf:"session"` + NTP NTPConfiguration `koanf:"ntp"` + Storage StorageConfiguration `koanf:"storage"` + Notifier *NotifierConfiguration `koanf:"notifier"` + PasswordPolicy PasswordPolicyConfiguration `koanf:"password_policy"` } diff --git a/internal/configuration/schema/password_policy.go b/internal/configuration/schema/password_policy.go new file mode 100644 index 000000000..9c24815e3 --- /dev/null +++ b/internal/configuration/schema/password_policy.go @@ -0,0 +1,40 @@ +package schema + +// PasswordPolicyStandardParams represents the configuration related to standard parameters of password policy. +type PasswordPolicyStandardParams struct { + Enabled bool + MinLength int `koanf:"min_length"` + MaxLength int `koanf:"max_length"` + RequireUppercase bool `koanf:"require_uppercase"` + RequireLowercase bool `koanf:"require_lowercase"` + RequireNumber bool `koanf:"require_number"` + RequireSpecial bool `koanf:"require_special"` +} + +// PasswordPolicyZxcvbnParams represents the configuration related to zxcvbn parameters of password policy. +type PasswordPolicyZxcvbnParams struct { + Enabled bool + MinScore int `koanf:"min_score"` +} + +// PasswordPolicyConfiguration represents the configuration related to password policy. +type PasswordPolicyConfiguration struct { + Standard PasswordPolicyStandardParams `koanf:"standard"` + Zxcvbn PasswordPolicyZxcvbnParams `koanf:"zxcvbn"` +} + +// DefaultPasswordPolicyConfiguration is the default password policy configuration. +var DefaultPasswordPolicyConfiguration = PasswordPolicyConfiguration{ + Standard: PasswordPolicyStandardParams{ + Enabled: false, + MinLength: 8, + MaxLength: 0, + RequireUppercase: true, + RequireLowercase: true, + RequireNumber: true, + RequireSpecial: true, + }, + Zxcvbn: PasswordPolicyZxcvbnParams{ + Enabled: false, + }, +} diff --git a/internal/configuration/validator/configuration.go b/internal/configuration/validator/configuration.go index dd536b28d..ae34d6b74 100644 --- a/internal/configuration/validator/configuration.go +++ b/internal/configuration/validator/configuration.go @@ -60,4 +60,6 @@ func ValidateConfiguration(config *schema.Configuration, validator *schema.Struc ValidateIdentityProviders(&config.IdentityProviders, validator) ValidateNTP(config, validator) + + ValidatePasswordPolicy(&config.PasswordPolicy, validator) } diff --git a/internal/configuration/validator/const.go b/internal/configuration/validator/const.go index f2fe7920c..e5d79eb8b 100644 --- a/internal/configuration/validator/const.go +++ b/internal/configuration/validator/const.go @@ -482,6 +482,17 @@ var ValidKeys = []string{ "ntp.max_desync", "ntp.disable_startup_check", "ntp.disable_failure", + + // Password Policy keys. + "password_policy.standard.enabled", + "password_policy.standard.min_length", + "password_policy.standard.max_length", + "password_policy.standard.require_uppercase", + "password_policy.standard.require_lowercase", + "password_policy.standard.require_number", + "password_policy.standard.require_special", + "password_policy.zxcvbn.enabled", + "password_policy.zxcvbn.min_score", } var replacedKeys = map[string]string{ diff --git a/internal/configuration/validator/password_policy.go b/internal/configuration/validator/password_policy.go new file mode 100644 index 000000000..ba5cf570c --- /dev/null +++ b/internal/configuration/validator/password_policy.go @@ -0,0 +1,33 @@ +package validator + +import ( + "errors" + + "github.com/authelia/authelia/v4/internal/configuration/schema" + "github.com/authelia/authelia/v4/internal/utils" +) + +// ValidatePasswordPolicy validates and update Password Policy configuration. +func ValidatePasswordPolicy(configuration *schema.PasswordPolicyConfiguration, validator *schema.StructValidator) { + if !utils.IsBoolCountLessThanN(1, true, configuration.Standard.Enabled, configuration.Zxcvbn.Enabled) { + validator.Push(errors.New("password_policy:only one password policy can be enabled at a time")) + } + + if configuration.Standard.Enabled { + if configuration.Standard.MinLength == 0 { + configuration.Standard.MinLength = schema.DefaultPasswordPolicyConfiguration.Standard.MinLength + } else if configuration.Standard.MinLength < 0 { + validator.Push(errors.New("password_policy: min_length must be > 0")) + } + + if configuration.Standard.MaxLength == 0 { + configuration.Standard.MaxLength = schema.DefaultPasswordPolicyConfiguration.Standard.MaxLength + } + } else if configuration.Zxcvbn.Enabled { + if configuration.Zxcvbn.MinScore == 0 { + configuration.Zxcvbn.MinScore = schema.DefaultPasswordPolicyConfiguration.Zxcvbn.MinScore + } else if configuration.Zxcvbn.MinScore < 0 || configuration.Zxcvbn.MinScore > 4 { + validator.Push(errors.New("min_score must be between 0 and 4")) + } + } +} diff --git a/internal/handlers/const.go b/internal/handlers/const.go index 1b266f66f..64c174034 100644 --- a/internal/handlers/const.go +++ b/internal/handlers/const.go @@ -44,6 +44,7 @@ const ( messageUnableToRegisterSecurityKey = "Unable to register your security key." messageUnableToResetPassword = "Unable to reset your password." messageMFAValidationFailed = "Authentication failed, please retry later." + messagePasswordWeak = "Your supplied password does not meet the password policy requirements" ) const ( diff --git a/internal/handlers/errors.go b/internal/handlers/errors.go new file mode 100644 index 000000000..5111dc95d --- /dev/null +++ b/internal/handlers/errors.go @@ -0,0 +1,5 @@ +package handlers + +import "errors" + +var errPasswordPolicyNoMet = errors.New("the supplied password does not met the security policy") diff --git a/internal/handlers/handler_reset_password_step1.go b/internal/handlers/handler_reset_password_step1.go index 75cff5f0e..b7cc9a352 100644 --- a/internal/handlers/handler_reset_password_step1.go +++ b/internal/handlers/handler_reset_password_step1.go @@ -53,7 +53,28 @@ func resetPasswordIdentityFinish(ctx *middlewares.AutheliaCtx, username string) ctx.Logger.Errorf("Unable to clear password reset flag in session for user %s: %s", userSession.Username, err) } - ctx.ReplyOK() + mode := "" + if ctx.Configuration.PasswordPolicy.Standard.Enabled { + mode = "standard" + } else if ctx.Configuration.PasswordPolicy.Zxcvbn.Enabled { + mode = "zxcvbn" + } + + policyResponse := PassworPolicyBody{ + Mode: mode, + MinLength: ctx.Configuration.PasswordPolicy.Standard.MinLength, + MaxLength: ctx.Configuration.PasswordPolicy.Standard.MaxLength, + RequireLowercase: ctx.Configuration.PasswordPolicy.Standard.RequireLowercase, + RequireUppercase: ctx.Configuration.PasswordPolicy.Standard.RequireUppercase, + RequireNumber: ctx.Configuration.PasswordPolicy.Standard.RequireNumber, + RequireSpecial: ctx.Configuration.PasswordPolicy.Standard.RequireSpecial, + MinScore: ctx.Configuration.PasswordPolicy.Zxcvbn.MinScore, + } + + err = ctx.SetJSONBody(policyResponse) + if err != nil { + ctx.Logger.Errorf("Unable to send password Policy: %s", err) + } } // ResetPasswordIdentityFinish the handler for finishing the identity validation. diff --git a/internal/handlers/handler_reset_password_step2.go b/internal/handlers/handler_reset_password_step2.go index 45689b29d..c3f9dbb85 100644 --- a/internal/handlers/handler_reset_password_step2.go +++ b/internal/handlers/handler_reset_password_step2.go @@ -2,6 +2,7 @@ package handlers import ( "fmt" + "regexp" "github.com/authelia/authelia/v4/internal/middlewares" "github.com/authelia/authelia/v4/internal/utils" @@ -27,6 +28,11 @@ func ResetPasswordPost(ctx *middlewares.AutheliaCtx) { return } + if err := validatePassword(ctx, requestBody.Password); err != nil { + ctx.Error(err, messagePasswordWeak) + return + } + err = ctx.Providers.UserProvider.UpdatePassword(*userSession.PasswordResetUsername, requestBody.Password) if err != nil { @@ -54,3 +60,54 @@ func ResetPasswordPost(ctx *middlewares.AutheliaCtx) { ctx.ReplyOK() } + +// validatePassword validates if the password met the password policy rules. +func validatePassword(ctx *middlewares.AutheliaCtx, password string) error { + // password validation applies only to standard passwor policy. + if !ctx.Configuration.PasswordPolicy.Standard.Enabled { + return nil + } + + requireLowercase := ctx.Configuration.PasswordPolicy.Standard.RequireLowercase + requireUppercase := ctx.Configuration.PasswordPolicy.Standard.RequireUppercase + requireNumber := ctx.Configuration.PasswordPolicy.Standard.RequireNumber + requireSpecial := ctx.Configuration.PasswordPolicy.Standard.RequireSpecial + minLength := ctx.Configuration.PasswordPolicy.Standard.MinLength + maxlength := ctx.Configuration.PasswordPolicy.Standard.MaxLength + + var patterns []string + + if (minLength > 0 && len(password) < minLength) || (maxlength > 0 && len(password) > maxlength) { + return errPasswordPolicyNoMet + } + + if requireLowercase { + patterns = append(patterns, "[a-z]+") + } + + if requireUppercase { + patterns = append(patterns, "[A-Z]+") + } + + if requireNumber { + patterns = append(patterns, "[0-9]+") + } + + if requireSpecial { + patterns = append(patterns, "[^a-zA-Z0-9]+") + } + + for _, pattern := range patterns { + re, err := regexp.Compile(pattern) + + if err != nil { + return err + } + + if found := re.MatchString(password); !found { + return errPasswordPolicyNoMet + } + } + + return nil +} diff --git a/internal/handlers/types.go b/internal/handlers/types.go index 785d6f0d3..e4670220e 100644 --- a/internal/handlers/types.go +++ b/internal/handlers/types.go @@ -112,3 +112,15 @@ type resetPasswordStep1RequestBody struct { type resetPasswordStep2RequestBody struct { Password string `json:"password"` } + +// PassworPolicyBody represents the response sent by the password reset step 2. +type PassworPolicyBody struct { + Mode string `json:"mode"` + MinLength int `json:"min_length"` + MaxLength int `json:"max_length"` + MinScore int `json:"min_score"` + RequireUppercase bool `json:"require_uppercase"` + RequireLowercase bool `json:"require_lowercase"` + RequireNumber bool `json:"require_number"` + RequireSpecial bool `json:"require_special"` +} diff --git a/internal/suites/Standalone/configuration.yml b/internal/suites/Standalone/configuration.yml index 4f5e71510..cf6723d3d 100644 --- a/internal/suites/Standalone/configuration.yml +++ b/internal/suites/Standalone/configuration.yml @@ -99,4 +99,21 @@ ntp: max_desync: 3s ## You can enable or disable the NTP synchronization check on startup disable_startup_check: false + +password_policy: + standard: + # Enables standard password Policy + enabled: false + min_length: 8 + max_length: 0 + require_uppercase: true + require_lowercase: true + require_number: true + require_special: true + zxcvbn: + ## zxcvbn: uses zxcvbn for password strength checking (see: https://github.com/dropbox/zxcvbn) + ## Note that the zxcvbn option does not prohibit the user from using a weak password, + ## it only offers feedback about the strength of the password they are entering. + ## if you need to enforce password rules, you should use `mode=classic` + enabled: false ... diff --git a/internal/utils/bools.go b/internal/utils/bools.go new file mode 100644 index 000000000..7c8da8f05 --- /dev/null +++ b/internal/utils/bools.go @@ -0,0 +1,32 @@ +package utils + +// IsBoolCountLessThanN takes an int (n), bool (v), and then a variadic slice of bool (vals). If the number of bools in vals with +// the value v is more than n, it returns false, otherwise it returns true. +func IsBoolCountLessThanN(n int, v bool, vals ...bool) bool { + lvals := len(vals) + + // If lvals (len of vals) is less than n it can't possibly have more than n so we can short circuit here. + if lvals < n { + return true + } + + j := 0 + + for i, val := range vals { + if val == v { + j++ + } + + // If lvals (len of vals) minus the current index (the remainder) plus the number of positives + // is less than n we can short circuit here. + if lvals-i+j < n { + return true + } + + if j > n { + return false + } + } + + return true +} diff --git a/internal/utils/bools_test.go b/internal/utils/bools_test.go new file mode 100644 index 000000000..36bb2c017 --- /dev/null +++ b/internal/utils/bools_test.go @@ -0,0 +1,114 @@ +package utils + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestIsBoolCountLessThanN(t *testing.T) { + type h struct { + n int + v bool + vals []bool + } + + testCases := []struct { + have h + want bool + }{ + { + have: h{ + n: 1, + v: true, + vals: []bool{true, false, false}, + }, + want: true, + }, + { + have: h{ + n: 1, + v: true, + vals: []bool{true, true, false}, + }, + want: false, + }, + { + have: h{ + n: 2, + v: true, + vals: []bool{true, true, false}, + }, + want: true, + }, + { + have: h{ + n: 2, + v: true, + vals: []bool{true, true, true}, + }, + want: false, + }, + { + have: h{ + n: 300, + v: true, + vals: []bool{true, true, true}, + }, + want: true, + }, + { + have: h{ + n: 300, + v: false, + vals: []bool{true, true, true}, + }, + want: true, + }, + { + have: h{ + n: 2, + v: false, + vals: []bool{false, false, false}, + }, + want: false, + }, + { + have: h{ + n: 1, + v: false, + vals: []bool{false, true, true}, + }, + want: true, + }, + { + have: h{ + n: 20, + v: false, + vals: []bool{true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, + true, true, true, true, true}, + }, + want: true, + }, + } + + for _, tc := range testCases { + countTrue := 0 + countFalse := 0 + + for _, v := range tc.have.vals { + if v { + countTrue++ + } else { + countFalse++ + } + } + + t.Run(fmt.Sprintf("%d %t true(%d)-false(%d)/should be %t", tc.have.n, tc.have.v, countTrue, countFalse, tc.want), func(t *testing.T) { + assert.Equal(t, tc.want, IsBoolCountLessThanN(tc.have.n, tc.have.v, tc.have.vals...)) + }) + } +} diff --git a/web/package.json b/web/package.json index 3b0efd299..b50d6c59b 100644 --- a/web/package.json +++ b/web/package.json @@ -23,7 +23,8 @@ "react-i18next": "11.16.2", "react-loading": "2.0.3", "react-otp-input": "2.4.0", - "react-router-dom": "6.3.0" + "react-router-dom": "6.3.0", + "zxcvbn": "^4.4.2" }, "scripts": { "prepare": "cd .. && husky install .github", diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index 88ce78e78..ab6037ab4 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -56,6 +56,7 @@ specifiers: vite-plugin-istanbul: 2.5.1 vite-plugin-svgr: 1.1.0 vite-tsconfig-paths: 3.4.1 + zxcvbn: ^4.4.2 dependencies: '@fortawesome/fontawesome-svg-core': 6.1.1 @@ -79,6 +80,7 @@ dependencies: react-loading: 2.0.3_react@18.0.0 react-otp-input: 2.4.0_react-dom@18.0.0+react@18.0.0 react-router-dom: 6.3.0_react-dom@18.0.0+react@18.0.0 + zxcvbn: 4.4.2 devDependencies: '@commitlint/cli': 16.2.3 @@ -138,39 +140,11 @@ packages: '@babel/highlight': 7.16.10 dev: true - /@babel/compat-data/7.17.0: - resolution: {integrity: sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==} - engines: {node: '>=6.9.0'} - dev: true - /@babel/compat-data/7.17.7: resolution: {integrity: sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ==} engines: {node: '>=6.9.0'} dev: true - /@babel/core/7.17.5: - resolution: {integrity: sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA==} - engines: {node: '>=6.9.0'} - dependencies: - '@ampproject/remapping': 2.1.2 - '@babel/code-frame': 7.16.7 - '@babel/generator': 7.17.3 - '@babel/helper-compilation-targets': 7.16.7_@babel+core@7.17.5 - '@babel/helper-module-transforms': 7.17.6 - '@babel/helpers': 7.17.2 - '@babel/parser': 7.17.3 - '@babel/template': 7.16.7 - '@babel/traverse': 7.17.3 - '@babel/types': 7.17.0 - convert-source-map: 1.8.0 - debug: 4.3.4 - gensync: 1.0.0-beta.2 - json5: 2.2.0 - semver: 6.3.0 - transitivePeerDependencies: - - supports-color - dev: true - /@babel/core/7.17.8: resolution: {integrity: sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ==} engines: {node: '>=6.9.0'} @@ -188,34 +162,25 @@ packages: convert-source-map: 1.8.0 debug: 4.3.4 gensync: 1.0.0-beta.2 - json5: 2.2.0 + json5: 2.2.1 semver: 6.3.0 transitivePeerDependencies: - supports-color dev: true - /@babel/eslint-parser/7.17.0_@babel+core@7.17.5: + /@babel/eslint-parser/7.17.0_@babel+core@7.17.8: resolution: {integrity: sha512-PUEJ7ZBXbRkbq3qqM/jZ2nIuakUBqCYc7Qf52Lj7dlZ6zERnqisdHioL0l4wwQZnmskMeasqUNzLBFKs3nylXA==} engines: {node: ^10.13.0 || ^12.13.0 || >=14.0.0} peerDependencies: '@babel/core': '>=7.11.0' eslint: ^7.5.0 || ^8.0.0 dependencies: - '@babel/core': 7.17.5 + '@babel/core': 7.17.8 eslint-scope: 5.1.1 eslint-visitor-keys: 2.1.0 semver: 6.3.0 dev: true - /@babel/generator/7.17.3: - resolution: {integrity: sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.17.0 - jsesc: 2.5.2 - source-map: 0.5.7 - dev: true - /@babel/generator/7.17.7: resolution: {integrity: sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==} engines: {node: '>=6.9.0'} @@ -240,19 +205,6 @@ packages: '@babel/types': 7.17.0 dev: true - /@babel/helper-compilation-targets/7.16.7_@babel+core@7.17.5: - resolution: {integrity: sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/compat-data': 7.17.0 - '@babel/core': 7.17.5 - '@babel/helper-validator-option': 7.16.7 - browserslist: 4.20.0 - semver: 6.3.0 - dev: true - /@babel/helper-compilation-targets/7.17.7_@babel+core@7.17.8: resolution: {integrity: sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w==} engines: {node: '>=6.9.0'} @@ -262,7 +214,7 @@ packages: '@babel/compat-data': 7.17.7 '@babel/core': 7.17.8 '@babel/helper-validator-option': 7.16.7 - browserslist: 4.20.0 + browserslist: 4.20.2 semver: 6.3.0 dev: true @@ -276,7 +228,7 @@ packages: '@babel/helper-annotate-as-pure': 7.16.7 '@babel/helper-environment-visitor': 7.16.7 '@babel/helper-function-name': 7.16.7 - '@babel/helper-member-expression-to-functions': 7.16.7 + '@babel/helper-member-expression-to-functions': 7.17.7 '@babel/helper-optimise-call-expression': 7.16.7 '@babel/helper-replace-supers': 7.16.7 '@babel/helper-split-export-declaration': 7.16.7 @@ -350,8 +302,8 @@ packages: '@babel/types': 7.17.0 dev: true - /@babel/helper-member-expression-to-functions/7.16.7: - resolution: {integrity: sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==} + /@babel/helper-member-expression-to-functions/7.17.7: + resolution: {integrity: sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.17.0 @@ -364,22 +316,6 @@ packages: '@babel/types': 7.17.0 dev: true - /@babel/helper-module-transforms/7.17.6: - resolution: {integrity: sha512-2ULmRdqoOMpdvkbT8jONrZML/XALfzxlb052bldftkicAUy8AxSCkD5trDPQcwHNmolcl7wP6ehNqMlyUw6AaA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-environment-visitor': 7.16.7 - '@babel/helper-module-imports': 7.16.7 - '@babel/helper-simple-access': 7.16.7 - '@babel/helper-split-export-declaration': 7.16.7 - '@babel/helper-validator-identifier': 7.16.7 - '@babel/template': 7.16.7 - '@babel/traverse': 7.17.3 - '@babel/types': 7.17.0 - transitivePeerDependencies: - - supports-color - dev: true - /@babel/helper-module-transforms/7.17.7: resolution: {integrity: sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw==} engines: {node: '>=6.9.0'} @@ -424,7 +360,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/helper-environment-visitor': 7.16.7 - '@babel/helper-member-expression-to-functions': 7.16.7 + '@babel/helper-member-expression-to-functions': 7.17.7 '@babel/helper-optimise-call-expression': 7.16.7 '@babel/traverse': 7.17.3 '@babel/types': 7.17.0 @@ -432,13 +368,6 @@ packages: - supports-color dev: true - /@babel/helper-simple-access/7.16.7: - resolution: {integrity: sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.17.0 - dev: true - /@babel/helper-simple-access/7.17.7: resolution: {integrity: sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA==} engines: {node: '>=6.9.0'} @@ -482,17 +411,6 @@ packages: - supports-color dev: true - /@babel/helpers/7.17.2: - resolution: {integrity: sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.16.7 - '@babel/traverse': 7.17.3 - '@babel/types': 7.17.0 - transitivePeerDependencies: - - supports-color - dev: true - /@babel/helpers/7.17.8: resolution: {integrity: sha512-QcL86FGxpfSJwGtAvv4iG93UL6bmqBdmoVY0CMCU2g+oD2ezQse3PT5Pa+jiD6LJndBQi0EDlpzOWNlLuhz5gw==} engines: {node: '>=6.9.0'} @@ -513,12 +431,6 @@ packages: js-tokens: 4.0.0 dev: true - /@babel/parser/7.17.3: - resolution: {integrity: sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==} - engines: {node: '>=6.0.0'} - hasBin: true - dev: true - /@babel/parser/7.17.8: resolution: {integrity: sha512-BoHhDJrJXqcg+ZL16Xv39H9n+AqJ4pcDrQBGZN+wHxIysrLZ3/ECwCBUch/1zUNhnsXULcONU3Ei5Hmkfk6kiQ==} engines: {node: '>=6.0.0'} @@ -588,8 +500,8 @@ packages: - supports-color dev: true - /@babel/plugin-proposal-decorators/7.17.2_@babel+core@7.17.8: - resolution: {integrity: sha512-WH8Z95CwTq/W8rFbMqb9p3hicpt4RX4f0K659ax2VHxgOyT6qQmUaEVEjIh4WR9Eh9NymkVn5vwsrE68fAQNUw==} + /@babel/plugin-proposal-decorators/7.17.8_@babel+core@7.17.8: + resolution: {integrity: sha512-U69odN4Umyyx1xO1rTII0IDkAEC+RNlcKXtqOblfpzqy1C+aOplb76BQNq0+XdpVkOaPlpEDwd++joY8FNFJKA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -746,15 +658,6 @@ packages: '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-async-generators/7.8.4_@babel+core@7.17.5: - resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.17.5 - '@babel/helper-plugin-utils': 7.16.7 - dev: true - /@babel/plugin-syntax-async-generators/7.8.4_@babel+core@7.17.8: resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} peerDependencies: @@ -764,15 +667,6 @@ packages: '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-bigint/7.8.3_@babel+core@7.17.5: - resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.17.5 - '@babel/helper-plugin-utils': 7.16.7 - dev: true - /@babel/plugin-syntax-bigint/7.8.3_@babel+core@7.17.8: resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} peerDependencies: @@ -782,15 +676,6 @@ packages: '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-class-properties/7.12.13_@babel+core@7.17.5: - resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.17.5 - '@babel/helper-plugin-utils': 7.16.7 - dev: true - /@babel/plugin-syntax-class-properties/7.12.13_@babel+core@7.17.8: resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} peerDependencies: @@ -848,15 +733,6 @@ packages: '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-import-meta/7.10.4_@babel+core@7.17.5: - resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.17.5 - '@babel/helper-plugin-utils': 7.16.7 - dev: true - /@babel/plugin-syntax-import-meta/7.10.4_@babel+core@7.17.8: resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} peerDependencies: @@ -866,15 +742,6 @@ packages: '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-json-strings/7.8.3_@babel+core@7.17.5: - resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.17.5 - '@babel/helper-plugin-utils': 7.16.7 - dev: true - /@babel/plugin-syntax-json-strings/7.8.3_@babel+core@7.17.8: resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} peerDependencies: @@ -894,15 +761,6 @@ packages: '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-logical-assignment-operators/7.10.4_@babel+core@7.17.5: - resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.17.5 - '@babel/helper-plugin-utils': 7.16.7 - dev: true - /@babel/plugin-syntax-logical-assignment-operators/7.10.4_@babel+core@7.17.8: resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} peerDependencies: @@ -912,15 +770,6 @@ packages: '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-nullish-coalescing-operator/7.8.3_@babel+core@7.17.5: - resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.17.5 - '@babel/helper-plugin-utils': 7.16.7 - dev: true - /@babel/plugin-syntax-nullish-coalescing-operator/7.8.3_@babel+core@7.17.8: resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} peerDependencies: @@ -930,15 +779,6 @@ packages: '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-numeric-separator/7.10.4_@babel+core@7.17.5: - resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.17.5 - '@babel/helper-plugin-utils': 7.16.7 - dev: true - /@babel/plugin-syntax-numeric-separator/7.10.4_@babel+core@7.17.8: resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} peerDependencies: @@ -948,15 +788,6 @@ packages: '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-object-rest-spread/7.8.3_@babel+core@7.17.5: - resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.17.5 - '@babel/helper-plugin-utils': 7.16.7 - dev: true - /@babel/plugin-syntax-object-rest-spread/7.8.3_@babel+core@7.17.8: resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} peerDependencies: @@ -966,15 +797,6 @@ packages: '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-optional-catch-binding/7.8.3_@babel+core@7.17.5: - resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.17.5 - '@babel/helper-plugin-utils': 7.16.7 - dev: true - /@babel/plugin-syntax-optional-catch-binding/7.8.3_@babel+core@7.17.8: resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} peerDependencies: @@ -984,15 +806,6 @@ packages: '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-optional-chaining/7.8.3_@babel+core@7.17.5: - resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.17.5 - '@babel/helper-plugin-utils': 7.16.7 - dev: true - /@babel/plugin-syntax-optional-chaining/7.8.3_@babel+core@7.17.8: resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} peerDependencies: @@ -1012,16 +825,6 @@ packages: '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-top-level-await/7.14.5_@babel+core@7.17.5: - resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.17.5 - '@babel/helper-plugin-utils': 7.16.7 - dev: true - /@babel/plugin-syntax-top-level-await/7.14.5_@babel+core@7.17.8: resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} engines: {node: '>=6.9.0'} @@ -1115,8 +918,8 @@ packages: '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-transform-destructuring/7.17.3_@babel+core@7.17.8: - resolution: {integrity: sha512-dDFzegDYKlPqa72xIlbmSkly5MluLoaC1JswABGktyt6NTXSBcUuse/kWE/wvKFWJHPETpi158qJZFS3JmykJg==} + /@babel/plugin-transform-destructuring/7.17.7_@babel+core@7.17.8: + resolution: {integrity: sha512-XVh0r5yq9sLR4vZ6eVZe8FKfIcSgaTBxVBRSYokRj2qksf6QerYnTxz9/GTuKTH/n/HwLP7t6gtlybHetJ/6hQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1224,38 +1027,23 @@ packages: - supports-color dev: true - /@babel/plugin-transform-modules-commonjs/7.16.8_@babel+core@7.17.5: - resolution: {integrity: sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.17.5 - '@babel/helper-module-transforms': 7.17.6 - '@babel/helper-plugin-utils': 7.16.7 - '@babel/helper-simple-access': 7.16.7 - babel-plugin-dynamic-import-node: 2.3.3 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/plugin-transform-modules-commonjs/7.16.8_@babel+core@7.17.8: - resolution: {integrity: sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==} + /@babel/plugin-transform-modules-commonjs/7.17.7_@babel+core@7.17.8: + resolution: {integrity: sha512-ITPmR2V7MqioMJyrxUo2onHNC3e+MvfFiFIR0RP21d3PtlVb6sfzoxNKiphSZUOM9hEIdzCcZe83ieX3yoqjUA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.17.8 - '@babel/helper-module-transforms': 7.17.6 + '@babel/helper-module-transforms': 7.17.7 '@babel/helper-plugin-utils': 7.16.7 - '@babel/helper-simple-access': 7.16.7 + '@babel/helper-simple-access': 7.17.7 babel-plugin-dynamic-import-node: 2.3.3 transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-transform-modules-systemjs/7.16.7_@babel+core@7.17.8: - resolution: {integrity: sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==} + /@babel/plugin-transform-modules-systemjs/7.17.8_@babel+core@7.17.8: + resolution: {integrity: sha512-39reIkMTUVagzgA5x88zDYXPCMT6lcaRKs1+S9K6NKBPErbgO/w/kP8GlNQTC87b412ZTlmNgr3k2JrWgHH+Bw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1572,7 +1360,7 @@ packages: '@babel/plugin-transform-block-scoping': 7.16.7_@babel+core@7.17.8 '@babel/plugin-transform-classes': 7.16.7_@babel+core@7.17.8 '@babel/plugin-transform-computed-properties': 7.16.7_@babel+core@7.17.8 - '@babel/plugin-transform-destructuring': 7.17.3_@babel+core@7.17.8 + '@babel/plugin-transform-destructuring': 7.17.7_@babel+core@7.17.8 '@babel/plugin-transform-dotall-regex': 7.16.7_@babel+core@7.17.8 '@babel/plugin-transform-duplicate-keys': 7.16.7_@babel+core@7.17.8 '@babel/plugin-transform-exponentiation-operator': 7.16.7_@babel+core@7.17.8 @@ -1581,8 +1369,8 @@ packages: '@babel/plugin-transform-literals': 7.16.7_@babel+core@7.17.8 '@babel/plugin-transform-member-expression-literals': 7.16.7_@babel+core@7.17.8 '@babel/plugin-transform-modules-amd': 7.16.7_@babel+core@7.17.8 - '@babel/plugin-transform-modules-commonjs': 7.16.8_@babel+core@7.17.8 - '@babel/plugin-transform-modules-systemjs': 7.16.7_@babel+core@7.17.8 + '@babel/plugin-transform-modules-commonjs': 7.17.7_@babel+core@7.17.8 + '@babel/plugin-transform-modules-systemjs': 7.17.8_@babel+core@7.17.8 '@babel/plugin-transform-modules-umd': 7.16.7_@babel+core@7.17.8 '@babel/plugin-transform-named-capturing-groups-regex': 7.16.8_@babel+core@7.17.8 '@babel/plugin-transform-new-target': 7.16.7_@babel+core@7.17.8 @@ -1651,16 +1439,16 @@ packages: - supports-color dev: true - /@babel/runtime-corejs3/7.17.2: - resolution: {integrity: sha512-NcKtr2epxfIrNM4VOmPKO46TvDMCBhgi2CrSHaEarrz+Plk2K5r9QemmOFTGpZaoKnWoGH5MO+CzeRsih/Fcgg==} + /@babel/runtime-corejs3/7.17.8: + resolution: {integrity: sha512-ZbYSUvoSF6dXZmMl/CYTMOvzIFnbGfv4W3SEHYgMvNsFTeLaF2gkGAF4K2ddmtSK4Emej+0aYcnSC6N5dPCXUQ==} engines: {node: '>=6.9.0'} dependencies: core-js-pure: 3.21.1 regenerator-runtime: 0.13.9 dev: true - /@babel/runtime/7.17.2: - resolution: {integrity: sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==} + /@babel/runtime/7.17.8: + resolution: {integrity: sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA==} engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.13.9 @@ -1670,7 +1458,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.16.7 - '@babel/parser': 7.17.3 + '@babel/parser': 7.17.8 '@babel/types': 7.17.0 dev: true @@ -1679,12 +1467,12 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.16.7 - '@babel/generator': 7.17.3 + '@babel/generator': 7.17.7 '@babel/helper-environment-visitor': 7.16.7 '@babel/helper-function-name': 7.16.7 '@babel/helper-hoist-variables': 7.16.7 '@babel/helper-split-export-declaration': 7.16.7 - '@babel/parser': 7.17.3 + '@babel/parser': 7.17.8 '@babel/types': 7.17.0 debug: 4.3.4 globals: 11.12.0 @@ -1726,7 +1514,7 @@ packages: lodash: 4.17.21 resolve-from: 5.0.0 resolve-global: 1.0.0 - yargs: 17.3.1 + yargs: 17.4.0 transitivePeerDependencies: - '@swc/core' - '@swc/wasm' @@ -1899,7 +1687,7 @@ packages: ajv: 6.12.6 debug: 4.3.4 espree: 7.3.1 - globals: 13.12.1 + globals: 13.13.0 ignore: 4.0.6 import-fresh: 3.3.0 js-yaml: 3.14.1 @@ -2026,7 +1814,7 @@ packages: jest-util: 27.5.1 jest-validate: 27.5.1 jest-watcher: 27.5.1 - micromatch: 4.0.4 + micromatch: 4.0.5 rimraf: 3.0.2 slash: 3.0.0 strip-ansi: 6.0.1 @@ -2152,7 +1940,7 @@ packages: jest-haste-map: 26.6.2 jest-regex-util: 26.0.0 jest-util: 26.6.2 - micromatch: 4.0.4 + micromatch: 4.0.5 pirates: 4.0.5 slash: 3.0.0 source-map: 0.6.1 @@ -2175,7 +1963,7 @@ packages: jest-haste-map: 27.5.1 jest-regex-util: 27.5.1 jest-util: 27.5.1 - micromatch: 4.0.4 + micromatch: 4.0.5 pirates: 4.0.5 slash: 3.0.0 source-map: 0.6.1 @@ -2234,7 +2022,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 '@material-ui/styles': 4.11.4_c13207e15fed56fc7b9b70ab319ad0ff '@material-ui/system': 4.12.1_c13207e15fed56fc7b9b70ab319ad0ff '@material-ui/types': 5.1.0_@types+react@17.0.43 @@ -2264,7 +2052,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 '@material-ui/core': 4.12.3_c13207e15fed56fc7b9b70ab319ad0ff '@types/react': 17.0.43 react: 18.0.0 @@ -2283,7 +2071,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 '@emotion/hash': 0.8.0 '@material-ui/types': 5.1.0_@types+react@17.0.43 '@material-ui/utils': 4.11.2_react-dom@18.0.0+react@18.0.0 @@ -2316,7 +2104,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 '@material-ui/utils': 4.11.2_react-dom@18.0.0+react@18.0.0 '@types/react': 17.0.43 csstype: 2.6.20 @@ -2343,7 +2131,7 @@ packages: react: ^16.8.0 || ^17.0.0 react-dom: ^16.8.0 || ^17.0.0 dependencies: - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 prop-types: 15.8.1 react: 18.0.0 react-dom: 18.0.0_react@18.0.0 @@ -2379,8 +2167,8 @@ packages: picomatch: 2.3.1 dev: true - /@rushstack/eslint-patch/1.1.0: - resolution: {integrity: sha512-JLo+Y592QzIE+q7Dl2pMUtt4q8SKYI5jDrZxrozEQxnGVOyYE+GWK9eLkwTaeN9DDctlaRAQ3TBmzZ1qdLE30A==} + /@rushstack/eslint-patch/1.1.1: + resolution: {integrity: sha512-BUyKJGdDWqvWC5GEhyOiUrGNi9iJUr4CU0O2WxJL6QJhHeeA/NVBalH+FeK0r/x/W0rPymXt5s78TDS7d6lCwg==} dev: true /@sinonjs/commons/1.8.3: @@ -2518,12 +2306,12 @@ packages: - supports-color dev: true - /@testing-library/dom/8.11.3: - resolution: {integrity: sha512-9LId28I+lx70wUiZjLvi1DB/WT2zGOxUh46glrSNMaWVx849kKAluezVzZrXJfTKKoQTmEOutLes/bHg4Bj3aA==} + /@testing-library/dom/8.12.0: + resolution: {integrity: sha512-rBrJk5WjI02X1edtiUcZhgyhgBhiut96r5Jp8J5qktKdcvLcZpKDW8i2hkGMMItxrghjXuQ5AM6aE0imnFawaw==} engines: {node: '>=12'} dependencies: '@babel/code-frame': 7.16.7 - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 '@types/aria-query': 4.2.2 aria-query: 5.0.0 chalk: 4.1.2 @@ -2536,7 +2324,7 @@ packages: resolution: {integrity: sha512-u5DfKj4wfSt6akfndfu1eG06jsdyA/IUrlX2n3pyq5UXgXMhXY+NJb8eNK/7pqPWAhCKsCGWDdDO0zKMKAYkEA==} engines: {node: '>=8', npm: '>=6', yarn: '>=1'} dependencies: - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 '@types/testing-library__jest-dom': 5.14.3 aria-query: 5.0.0 chalk: 3.0.0 @@ -2554,8 +2342,8 @@ packages: react: ^18.0.0 react-dom: ^18.0.0 dependencies: - '@babel/runtime': 7.17.2 - '@testing-library/dom': 8.11.3 + '@babel/runtime': 7.17.8 + '@testing-library/dom': 8.12.0 '@types/react-dom': 17.0.14 react: 18.0.0 react-dom: 18.0.0_react@18.0.0 @@ -2586,8 +2374,8 @@ packages: resolution: {integrity: sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==} dev: true - /@types/babel__core/7.1.18: - resolution: {integrity: sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ==} + /@types/babel__core/7.1.19: + resolution: {integrity: sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==} dependencies: '@babel/parser': 7.17.8 '@babel/types': 7.17.0 @@ -2644,8 +2432,8 @@ packages: pretty-format: 27.5.1 dev: true - /@types/json-schema/7.0.9: - resolution: {integrity: sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==} + /@types/json-schema/7.0.11: + resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} dev: true /@types/json5/0.0.29: @@ -2755,13 +2543,13 @@ packages: - supports-color dev: true - /@typescript-eslint/experimental-utils/5.14.0_typescript@4.6.3: - resolution: {integrity: sha512-ke48La1A/TWAn949cdgQiP3oK0NT7ArhDAOVOmNLVjT/uAXlFyrJY8dM4qqxHrATzIp8glg+G2OZjy2lRKBIUA==} + /@typescript-eslint/experimental-utils/5.17.0_typescript@4.6.3: + resolution: {integrity: sha512-U4sM5z0/ymSYqQT6I7lz8l0ZZ9zrya5VIwrwAP5WOJVabVtVsIpTMxPQe+D3qLyePT+VlETUTO2nA1+PufPx9Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - '@typescript-eslint/utils': 5.14.0_typescript@4.6.3 + '@typescript-eslint/utils': 5.17.0_typescript@4.6.3 transitivePeerDependencies: - supports-color - typescript @@ -2786,14 +2574,6 @@ packages: - supports-color dev: true - /@typescript-eslint/scope-manager/5.14.0: - resolution: {integrity: sha512-LazdcMlGnv+xUc5R4qIlqH0OWARyl2kaP8pVCS39qSL3Pd1F7mI10DbdXeARcE62sVQE4fHNvEqMWsypWO+yEw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - '@typescript-eslint/types': 5.14.0 - '@typescript-eslint/visitor-keys': 5.14.0 - dev: true - /@typescript-eslint/scope-manager/5.17.0: resolution: {integrity: sha512-062iCYQF/doQ9T2WWfJohQKKN1zmmXVfAcS3xaiialiw8ZUGy05Em6QVNYJGO34/sU1a7a+90U3dUNfqUDHr3w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2820,37 +2600,11 @@ packages: - supports-color dev: true - /@typescript-eslint/types/5.14.0: - resolution: {integrity: sha512-BR6Y9eE9360LNnW3eEUqAg6HxS9Q35kSIs4rp4vNHRdfg0s+/PgHgskvu5DFTM7G5VKAVjuyaN476LCPrdA7Mw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true - /@typescript-eslint/types/5.17.0: resolution: {integrity: sha512-AgQ4rWzmCxOZLioFEjlzOI3Ch8giDWx8aUDxyNw9iOeCvD3GEYAB7dxWGQy4T/rPVe8iPmu73jPHuaSqcjKvxw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/typescript-estree/5.14.0_typescript@4.6.3: - resolution: {integrity: sha512-QGnxvROrCVtLQ1724GLTHBTR0lZVu13izOp9njRvMkCBgWX26PKvmMP8k82nmXBRD3DQcFFq2oj3cKDwr0FaUA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/types': 5.14.0 - '@typescript-eslint/visitor-keys': 5.14.0 - debug: 4.3.4 - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.3.5 - tsutils: 3.21.0_typescript@4.6.3 - typescript: 4.6.3 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/typescript-estree/5.17.0_typescript@4.6.3: resolution: {integrity: sha512-X1gtjEcmM7Je+qJRhq7ZAAaNXYhTgqMkR10euC4Si6PIjb+kwEQHSxGazXUQXFyqfEXdkGf6JijUu5R0uceQzg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2872,30 +2626,13 @@ packages: - supports-color dev: true - /@typescript-eslint/utils/5.14.0_typescript@4.6.3: - resolution: {integrity: sha512-EHwlII5mvUA0UsKYnVzySb/5EE/t03duUTweVy8Zqt3UQXBrpEVY144OTceFKaOe4xQXZJrkptCf7PjEBeGK4w==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - dependencies: - '@types/json-schema': 7.0.9 - '@typescript-eslint/scope-manager': 5.14.0 - '@typescript-eslint/types': 5.14.0 - '@typescript-eslint/typescript-estree': 5.14.0_typescript@4.6.3 - eslint-scope: 5.1.1 - eslint-utils: 3.0.0 - transitivePeerDependencies: - - supports-color - - typescript - dev: true - /@typescript-eslint/utils/5.17.0_typescript@4.6.3: resolution: {integrity: sha512-DVvndq1QoxQH+hFv+MUQHrrWZ7gQ5KcJzyjhzcqB1Y2Xes1UQQkTRPUfRpqhS8mhTWsSb2+iyvDW1Lef5DD7vA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - '@types/json-schema': 7.0.9 + '@types/json-schema': 7.0.11 '@typescript-eslint/scope-manager': 5.17.0 '@typescript-eslint/types': 5.17.0 '@typescript-eslint/typescript-estree': 5.17.0_typescript@4.6.3 @@ -2906,14 +2643,6 @@ packages: - typescript dev: true - /@typescript-eslint/visitor-keys/5.14.0: - resolution: {integrity: sha512-yL0XxfzR94UEkjBqyymMLgCBdojzEuy/eim7N9/RIcTNxpJudAcqsU8eRyfzBbcEzGoPWfdM3AGak3cN08WOIw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - '@typescript-eslint/types': 5.14.0 - eslint-visitor-keys: 3.3.0 - dev: true - /@typescript-eslint/visitor-keys/5.17.0: resolution: {integrity: sha512-6K/zlc4OfCagUu7Am/BD5k8PSWQOgh34Nrv9Rxe2tBzlJ7uOeJ/h7ugCGDCeEZHT6k2CJBhbk9IsbkPI0uvUkA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3005,8 +2734,8 @@ packages: uri-js: 4.4.1 dev: true - /ajv/8.10.0: - resolution: {integrity: sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==} + /ajv/8.11.0: + resolution: {integrity: sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==} dependencies: fast-deep-equal: 3.1.3 json-schema-traverse: 1.0.0 @@ -3084,8 +2813,8 @@ packages: resolution: {integrity: sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==} engines: {node: '>=6.0'} dependencies: - '@babel/runtime': 7.17.2 - '@babel/runtime-corejs3': 7.17.2 + '@babel/runtime': 7.17.8 + '@babel/runtime-corejs3': 7.17.8 dev: true /aria-query/5.0.0: @@ -3118,7 +2847,7 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.3 - es-abstract: 1.19.1 + es-abstract: 1.19.2 get-intrinsic: 1.1.1 is-string: 1.0.7 dev: true @@ -3139,7 +2868,7 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.3 - es-abstract: 1.19.1 + es-abstract: 1.19.2 dev: true /array.prototype.flatmap/1.2.5: @@ -3148,7 +2877,7 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.3 - es-abstract: 1.19.1 + es-abstract: 1.19.2 dev: true /arrify/1.0.1: @@ -3197,18 +2926,18 @@ packages: resolution: {integrity: sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==} dev: true - /babel-jest/26.6.3_@babel+core@7.17.5: + /babel-jest/26.6.3_@babel+core@7.17.8: resolution: {integrity: sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==} engines: {node: '>= 10.14.2'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.17.5 + '@babel/core': 7.17.8 '@jest/transform': 26.6.2 '@jest/types': 26.6.2 - '@types/babel__core': 7.1.18 + '@types/babel__core': 7.1.19 babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 26.6.2_@babel+core@7.17.5 + babel-preset-jest: 26.6.2_@babel+core@7.17.8 chalk: 4.1.2 graceful-fs: 4.2.9 slash: 3.0.0 @@ -3225,7 +2954,7 @@ packages: '@babel/core': 7.17.8 '@jest/transform': 27.5.1 '@jest/types': 27.5.1 - '@types/babel__core': 7.1.18 + '@types/babel__core': 7.1.19 babel-plugin-istanbul: 6.1.1 babel-preset-jest: 27.5.1_@babel+core@7.17.8 chalk: 4.1.2 @@ -3260,7 +2989,7 @@ packages: dependencies: '@babel/template': 7.16.7 '@babel/types': 7.17.0 - '@types/babel__core': 7.1.18 + '@types/babel__core': 7.1.19 '@types/babel__traverse': 7.14.2 dev: true @@ -3270,7 +2999,7 @@ packages: dependencies: '@babel/template': 7.16.7 '@babel/types': 7.17.0 - '@types/babel__core': 7.1.18 + '@types/babel__core': 7.1.19 '@types/babel__traverse': 7.14.2 dev: true @@ -3278,7 +3007,7 @@ packages: resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} engines: {node: '>=10', npm: '>=6'} dependencies: - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 cosmiconfig: 7.0.1 resolve: 1.22.0 dev: true @@ -3323,26 +3052,6 @@ packages: resolution: {integrity: sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA==} dev: true - /babel-preset-current-node-syntax/1.0.1_@babel+core@7.17.5: - resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.17.5 - '@babel/plugin-syntax-async-generators': 7.8.4_@babel+core@7.17.5 - '@babel/plugin-syntax-bigint': 7.8.3_@babel+core@7.17.5 - '@babel/plugin-syntax-class-properties': 7.12.13_@babel+core@7.17.5 - '@babel/plugin-syntax-import-meta': 7.10.4_@babel+core@7.17.5 - '@babel/plugin-syntax-json-strings': 7.8.3_@babel+core@7.17.5 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4_@babel+core@7.17.5 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3_@babel+core@7.17.5 - '@babel/plugin-syntax-numeric-separator': 7.10.4_@babel+core@7.17.5 - '@babel/plugin-syntax-object-rest-spread': 7.8.3_@babel+core@7.17.5 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3_@babel+core@7.17.5 - '@babel/plugin-syntax-optional-chaining': 7.8.3_@babel+core@7.17.5 - '@babel/plugin-syntax-top-level-await': 7.14.5_@babel+core@7.17.5 - dev: true - /babel-preset-current-node-syntax/1.0.1_@babel+core@7.17.8: resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} peerDependencies: @@ -3363,15 +3072,15 @@ packages: '@babel/plugin-syntax-top-level-await': 7.14.5_@babel+core@7.17.8 dev: true - /babel-preset-jest/26.6.2_@babel+core@7.17.5: + /babel-preset-jest/26.6.2_@babel+core@7.17.8: resolution: {integrity: sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ==} engines: {node: '>= 10.14.2'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.17.5 + '@babel/core': 7.17.8 babel-plugin-jest-hoist: 26.6.2 - babel-preset-current-node-syntax: 1.0.1_@babel+core@7.17.5 + babel-preset-current-node-syntax: 1.0.1_@babel+core@7.17.8 dev: true /babel-preset-jest/27.5.1_@babel+core@7.17.8: @@ -3390,7 +3099,7 @@ packages: dependencies: '@babel/core': 7.17.8 '@babel/plugin-proposal-class-properties': 7.16.7_@babel+core@7.17.8 - '@babel/plugin-proposal-decorators': 7.17.2_@babel+core@7.17.8 + '@babel/plugin-proposal-decorators': 7.17.8_@babel+core@7.17.8 '@babel/plugin-proposal-nullish-coalescing-operator': 7.16.7_@babel+core@7.17.8 '@babel/plugin-proposal-numeric-separator': 7.16.7_@babel+core@7.17.8 '@babel/plugin-proposal-optional-chaining': 7.16.7_@babel+core@7.17.8 @@ -3401,7 +3110,7 @@ packages: '@babel/preset-env': 7.16.11_@babel+core@7.17.8 '@babel/preset-react': 7.16.7_@babel+core@7.17.8 '@babel/preset-typescript': 7.16.7_@babel+core@7.17.8 - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 babel-plugin-macros: 3.1.0 babel-plugin-transform-react-remove-prop-types: 0.4.24 transitivePeerDependencies: @@ -3459,13 +3168,13 @@ packages: resolution: {integrity: sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==} dev: true - /browserslist/4.20.0: - resolution: {integrity: sha512-bnpOoa+DownbciXj0jVGENf8VYQnE2LNWomhYuCsMmmx9Jd9lwq0WXODuwpSsp8AVdKM2/HorrzxAfbKvWTByQ==} + /browserslist/4.20.2: + resolution: {integrity: sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001314 - electron-to-chromium: 1.4.79 + caniuse-lite: 1.0.30001324 + electron-to-chromium: 1.4.103 escalade: 3.1.1 node-releases: 2.0.2 picocolors: 1.0.0 @@ -3527,8 +3236,8 @@ packages: engines: {node: '>=10'} dev: true - /caniuse-lite/1.0.30001314: - resolution: {integrity: sha512-0zaSO+TnCHtHJIbpLroX7nsD+vYuOVjl3uzFbJO1wMVbuveJA0RK2WcQA9ZUIOiO0/ArMiMgHJLxfEZhQiC0kw==} + /caniuse-lite/1.0.30001324: + resolution: {integrity: sha512-/eYp1J6zYh1alySQB4uzYFkLmxxI8tk0kxldbNHXp8+v+rdMKdUBNjRLz7T7fz6Iox+1lIdYpc7rq6ZcXfTukg==} dev: true /capture-exit/2.0.0: @@ -3725,7 +3434,7 @@ packages: /core-js-compat/3.21.1: resolution: {integrity: sha512-gbgX5AUvMb8gwxC7FLVWYT7Kkgu/y7+h/h1X43yJkNqhlK2fuYyQimqvKGNZFAY6CKii/GFKJ2cp/1/42TN36g==} dependencies: - browserslist: 4.20.0 + browserslist: 4.20.2 semver: 7.0.0 dev: true @@ -3796,7 +3505,7 @@ packages: /css-vendor/2.0.8: resolution: {integrity: sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==} dependencies: - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 is-in-browser: 1.1.3 dev: false @@ -3864,18 +3573,6 @@ packages: ms: 2.1.3 dev: true - /debug/4.3.3: - resolution: {integrity: sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.2 - dev: true - /debug/4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -3999,7 +3696,7 @@ packages: /dom-helpers/5.2.1: resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} dependencies: - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 csstype: 3.0.11 dev: false @@ -4017,8 +3714,8 @@ packages: is-obj: 2.0.0 dev: true - /electron-to-chromium/1.4.79: - resolution: {integrity: sha512-nWfAxof87mGHkbORCwVRPst4FlSVdprOKS6dBMrcwn3sjwf8iHXEhsu1+FU5Psd7Ps3KKeBufAdfsPK5BmbSUg==} + /electron-to-chromium/1.4.103: + resolution: {integrity: sha512-c/uKWR1Z/W30Wy/sx3dkZoj4BijbXX85QKWu9jJfjho3LBAXNEGAEW3oWiGb+dotA6C6BzCTxL2/aLes7jlUeg==} dev: true /emittery/0.8.1: @@ -4058,8 +3755,8 @@ packages: is-arrayish: 0.2.1 dev: true - /es-abstract/1.19.1: - resolution: {integrity: sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==} + /es-abstract/1.19.2: + resolution: {integrity: sha512-gfSBJoZdlL2xRiOCy0g8gLMryhoe1TlimjzU99L/31Z8QEGIhVQI+EWwt5lT+AuU9SnorVupXFqqOGqGfsyO6w==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 @@ -4073,7 +3770,7 @@ packages: is-callable: 1.2.4 is-negative-zero: 2.0.2 is-regex: 1.1.4 - is-shared-array-buffer: 1.0.1 + is-shared-array-buffer: 1.0.2 is-string: 1.0.7 is-weakref: 1.0.2 object-inspect: 1.12.0 @@ -4093,8 +3790,8 @@ packages: is-symbol: 1.0.4 dev: true - /esbuild-android-64/0.14.25: - resolution: {integrity: sha512-L5vCUk7TzFbBnoESNoXjU3x9+/+7TDIE/1mTfy/erAfvZAqC+S3sp/Qa9wkypFMcFvN9FzvESkTlpeQDolREtQ==} + /esbuild-android-64/0.14.30: + resolution: {integrity: sha512-vdJ7t8A8msPfKpYUGUV/KaTQRiZ0vDa2XSTlzXVkGGVHLKPeb85PBUtYJcEgw3htW3IdX5i1t1IMdQCwJJgNAg==} engines: {node: '>=12'} cpu: [x64] os: [android] @@ -4102,8 +3799,8 @@ packages: dev: true optional: true - /esbuild-android-arm64/0.14.25: - resolution: {integrity: sha512-4jv5xPjM/qNm27T5j3ZEck0PvjgQtoMHnz4FzwF5zNP56PvY2CT0WStcAIl6jNlsuDdN63rk2HRBIsO6xFbcFw==} + /esbuild-android-arm64/0.14.30: + resolution: {integrity: sha512-BdgGfxeA5hBQNErLr7BWJUA8xjflEfyaARICy8e0OJYNSAwDbEzOf8LyiKWSrDcgV129mWhi3VpbNQvOIDEHcg==} engines: {node: '>=12'} cpu: [arm64] os: [android] @@ -4111,8 +3808,8 @@ packages: dev: true optional: true - /esbuild-darwin-64/0.14.25: - resolution: {integrity: sha512-TGp8tuudIxOyWd1+8aYPxQmC1ZQyvij/AfNBa35RubixD0zJ1vkKHVAzo0Zao1zcG6pNqiSyzfPto8vmg0s7oA==} + /esbuild-darwin-64/0.14.30: + resolution: {integrity: sha512-VRaOXMMrsG5n53pl4qFZQdXy2+E0NoLP/QH3aDUI0+bQP+ZHDmbINKcDy2IX7GVFI9kqPS18iJNAs5a6/G2LZg==} engines: {node: '>=12'} cpu: [x64] os: [darwin] @@ -4120,8 +3817,8 @@ packages: dev: true optional: true - /esbuild-darwin-arm64/0.14.25: - resolution: {integrity: sha512-oTcDgdm0MDVEmw2DWu8BV68pYuImpFgvWREPErBZmNA4MYKGuBRaCiJqq6jZmBR1x+3y1DWCjez+5uLtuAm6mw==} + /esbuild-darwin-arm64/0.14.30: + resolution: {integrity: sha512-qDez+fHMOrO9Oc9qjt/x+sy09RJVh62kik5tVybKRLmezeV4qczM9/sAYY57YN0aWLdHbcCj2YqJUWYJNsgKnw==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] @@ -4129,8 +3826,8 @@ packages: dev: true optional: true - /esbuild-freebsd-64/0.14.25: - resolution: {integrity: sha512-ueAqbnMZ8arnuLH8tHwTCQYeptnHOUV7vA6px6j4zjjQwDx7TdP7kACPf3TLZLdJQ3CAD1XCvQ2sPhX+8tacvQ==} + /esbuild-freebsd-64/0.14.30: + resolution: {integrity: sha512-mec1jENcImVVagddZlGWsdAUwBnzR5cgnhzCxv+9fSMxKbx1uZYLLUAnLPp8m/i934zrumR1xGjJ5VoWdPlI2w==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] @@ -4138,8 +3835,8 @@ packages: dev: true optional: true - /esbuild-freebsd-arm64/0.14.25: - resolution: {integrity: sha512-+ZVWud2HKh+Ob6k/qiJWjBtUg4KmJGGmbvEXXW1SNKS7hW7HU+Zq2ZCcE1akFxOPkVB+EhOty/sSek30tkCYug==} + /esbuild-freebsd-arm64/0.14.30: + resolution: {integrity: sha512-cpjbTs6Iok/AfeB0JgTzyUJTMStC1SQULmany5nHx6S4GTkSgaAHuJzZO0GcVWqghI4e0YL/bjXAhN5Mn6feNw==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] @@ -4152,15 +3849,15 @@ packages: peerDependencies: esbuild: '>=0.8.50' dependencies: - '@babel/core': 7.17.5 - '@babel/plugin-transform-modules-commonjs': 7.16.8_@babel+core@7.17.5 - babel-jest: 26.6.3_@babel+core@7.17.5 + '@babel/core': 7.17.8 + '@babel/plugin-transform-modules-commonjs': 7.17.7_@babel+core@7.17.8 + babel-jest: 26.6.3_@babel+core@7.17.8 transitivePeerDependencies: - supports-color dev: true - /esbuild-linux-32/0.14.25: - resolution: {integrity: sha512-3OP/lwV3kCzEz45tobH9nj+uE4ubhGsfx+tn0L26WAGtUbmmcRpqy7XRG/qK7h1mClZ+eguIANcQntYMdYklfw==} + /esbuild-linux-32/0.14.30: + resolution: {integrity: sha512-liIONVT4F2kZmOMwtwASqZ8WkIjb5HHBR9HUffdHiuotSTF3CyZO+EJf+Og+SYYuuVIvt0qHNSFjBA/iSESteQ==} engines: {node: '>=12'} cpu: [ia32] os: [linux] @@ -4168,8 +3865,8 @@ packages: dev: true optional: true - /esbuild-linux-64/0.14.25: - resolution: {integrity: sha512-+aKHdHZmX9qwVlQmu5xYXh7GsBFf4TWrePgeJTalhXHOG7NNuUwoHmketGiZEoNsWyyqwH9rE5BC+iwcLY30Ug==} + /esbuild-linux-64/0.14.30: + resolution: {integrity: sha512-LUnpzoMpRqFON5En4qEj6NWiyH6a1K+Y2qYNKrCy5qPTjDoG/EWeqMz69n8Uv7pRuvDKl3FNGJ1dufTrA5i0sw==} engines: {node: '>=12'} cpu: [x64] os: [linux] @@ -4177,8 +3874,8 @@ packages: dev: true optional: true - /esbuild-linux-arm/0.14.25: - resolution: {integrity: sha512-aTLcE2VBoLydL943REcAcgnDi3bHtmULSXWLbjtBdtykRatJVSxKMjK9YlBXUZC4/YcNQfH7AxwVeQr9fNxPhw==} + /esbuild-linux-arm/0.14.30: + resolution: {integrity: sha512-97T+bbXnpqf7mfIG49UR7ZSJFGgvc22byn74qw3Kx2GDCBSQoVFjyWuKOHGXp8nXk3XYrdFF+mQ8yQ7aNsgQvg==} engines: {node: '>=12'} cpu: [arm] os: [linux] @@ -4186,8 +3883,8 @@ packages: dev: true optional: true - /esbuild-linux-arm64/0.14.25: - resolution: {integrity: sha512-UxfenPx/wSZx55gScCImPtXekvZQLI2GW3qe5dtlmU7luiqhp5GWPzGeQEbD3yN3xg/pHc671m5bma5Ns7lBHw==} + /esbuild-linux-arm64/0.14.30: + resolution: {integrity: sha512-DHZHn6FK5q/KL0fpNT/0jE38Nnyk2rXxKE9WENi95EXtqfOLPgE8tzjTZQNgpr61R95QX4ymQU26ni3IZk8buQ==} engines: {node: '>=12'} cpu: [arm64] os: [linux] @@ -4195,8 +3892,8 @@ packages: dev: true optional: true - /esbuild-linux-mips64le/0.14.25: - resolution: {integrity: sha512-wLWYyqVfYx9Ur6eU5RT92yJVsaBGi5RdkoWqRHOqcJ38Kn60QMlcghsKeWfe9jcYut8LangYZ98xO1LxIoSXrQ==} + /esbuild-linux-mips64le/0.14.30: + resolution: {integrity: sha512-fLUzTFZ7uknC0aPTk7/lM7NmaG/9ZqE3SaHEphcaM009SZK/mDOvZugWi1ss6WGNhk13dUrhkfHcc4FSb9hYhg==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] @@ -4204,8 +3901,8 @@ packages: dev: true optional: true - /esbuild-linux-ppc64le/0.14.25: - resolution: {integrity: sha512-0dR6Csl6Zas3g4p9ULckEl8Mo8IInJh33VCJ3eaV1hj9+MHGdmDOakYMN8MZP9/5nl+NU/0ygpd14cWgy8uqRw==} + /esbuild-linux-ppc64le/0.14.30: + resolution: {integrity: sha512-2Oudm2WEfj0dNU9bzIl5L/LrsMEmHWsOsYgJJqu8fDyUDgER+J1d33qz3cUdjsJk7gAENayIxDSpsuCszx0w3A==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] @@ -4213,8 +3910,8 @@ packages: dev: true optional: true - /esbuild-linux-riscv64/0.14.25: - resolution: {integrity: sha512-J4d20HDmTrgvhR0bdkDhvvJGaikH3LzXQnNaseo8rcw9Yqby9A90gKUmWpfwqLVNRILvNnAmKLfBjCKU9ajg8w==} + /esbuild-linux-riscv64/0.14.30: + resolution: {integrity: sha512-RPMucPW47rV4t2jlelaE948iCRtbZf5RhifxSwzlpM1Mqdyu99MMNK0w4jFreGTmLN+oGomxIOxD6n+2E/XqHw==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] @@ -4222,8 +3919,8 @@ packages: dev: true optional: true - /esbuild-linux-s390x/0.14.25: - resolution: {integrity: sha512-YI2d5V6nTE73ZnhEKQD7MtsPs1EtUZJ3obS21oxQxGbbRw1G+PtJKjNyur+3t6nzHP9oTg6GHQ3S3hOLLmbDIQ==} + /esbuild-linux-s390x/0.14.30: + resolution: {integrity: sha512-OZ68r7ok6qO7hdwrwQn2p5jbIRRcUcVaAykB7e0uCA0ODwfeGunILM6phJtq2Oz4dlEEFvd+tSuma3paQKwt+A==} engines: {node: '>=12'} cpu: [s390x] os: [linux] @@ -4231,8 +3928,8 @@ packages: dev: true optional: true - /esbuild-netbsd-64/0.14.25: - resolution: {integrity: sha512-TKIVgNWLUOkr+Exrye70XTEE1lJjdQXdM4tAXRzfHE9iBA7LXWcNtVIuSnphTqpanPzTDFarF0yqq4kpbC6miA==} + /esbuild-netbsd-64/0.14.30: + resolution: {integrity: sha512-iyejQUKn0TzpPkufq8pSCxOg9NheycQbMbPCmjefTe9wYuUlBt1TcHvdoJnYbQzsAhAh1BNq+s0ycRsIJFZzaQ==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] @@ -4240,8 +3937,8 @@ packages: dev: true optional: true - /esbuild-openbsd-64/0.14.25: - resolution: {integrity: sha512-QgFJ37A15D7NIXBTYEqz29+uw3nNBOIyog+3kFidANn6kjw0GHZ0lEYQn+cwjyzu94WobR+fes7cTl/ZYlHb1A==} + /esbuild-openbsd-64/0.14.30: + resolution: {integrity: sha512-UyK1MTMcy4j5fH260fsE1o6MVgWNhb62eCK2yCKCRazZv8Nqdc2WiP9ygjWidmEdCDS+A6MuVp9ozk9uoQtQpA==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] @@ -4249,8 +3946,8 @@ packages: dev: true optional: true - /esbuild-sunos-64/0.14.25: - resolution: {integrity: sha512-rmWfjUItYIVlqr5EnTH1+GCxXiBOC42WBZ3w++qh7n2cS9Xo0lO5pGSG2N+huOU2fX5L+6YUuJ78/vOYvefeFw==} + /esbuild-sunos-64/0.14.30: + resolution: {integrity: sha512-aQRtRTNKHB4YuG+xXATe5AoRTNY48IJg5vjE8ElxfmjO9+KdX7MHFkTLhlKevCD6rNANtB3qOlSIeAiXTwHNqw==} engines: {node: '>=12'} cpu: [x64] os: [sunos] @@ -4258,8 +3955,8 @@ packages: dev: true optional: true - /esbuild-windows-32/0.14.25: - resolution: {integrity: sha512-HGAxVUofl3iUIz9W10Y9XKtD0bNsK9fBXv1D55N/ljNvkrAYcGB8YCm0v7DjlwtyS6ws3dkdQyXadbxkbzaKOA==} + /esbuild-windows-32/0.14.30: + resolution: {integrity: sha512-9/fb1tPtpacMqxAXp3fGHowUDg/l9dVch5hKmCLEZC6PdGljh6h372zMdJwYfH0Bd5CCPT0Wx95uycBLJiqpXA==} engines: {node: '>=12'} cpu: [ia32] os: [win32] @@ -4267,8 +3964,8 @@ packages: dev: true optional: true - /esbuild-windows-64/0.14.25: - resolution: {integrity: sha512-TirEohRkfWU9hXLgoDxzhMQD1g8I2mOqvdQF2RS9E/wbkORTAqJHyh7wqGRCQAwNzdNXdg3JAyhQ9/177AadWA==} + /esbuild-windows-64/0.14.30: + resolution: {integrity: sha512-DHgITeUhPAnN9I5O6QBa1GVyPOhiYCn4S4TtQr7sO4+X0LNyqnlmA1M0qmGkUdDC1QQfjI8uQ4G/whdWb2pWIQ==} engines: {node: '>=12'} cpu: [x64] os: [win32] @@ -4276,8 +3973,8 @@ packages: dev: true optional: true - /esbuild-windows-arm64/0.14.25: - resolution: {integrity: sha512-4ype9ERiI45rSh+R8qUoBtaj6kJvUOI7oVLhKqPEpcF4Pa5PpT3hm/mXAyotJHREkHpM87PAJcA442mLnbtlNA==} + /esbuild-windows-arm64/0.14.30: + resolution: {integrity: sha512-F1kLyQH7zSgjh5eLxogGZN7C9+KNs9m+s7Q6WZoMmCWT/6j998zlaoECHyM8izJRRfsvw2eZlEa1jO6/IOU1AQ==} engines: {node: '>=12'} cpu: [arm64] os: [win32] @@ -4285,32 +3982,32 @@ packages: dev: true optional: true - /esbuild/0.14.25: - resolution: {integrity: sha512-4JHEIOMNFvK09ziiL+iVmldIhLbn49V4NAVo888tcGFKedEZY/Y8YapfStJ6zSE23tzYPKxqKwQBnQoIO0BI/Q==} + /esbuild/0.14.30: + resolution: {integrity: sha512-wCecQSBkIjp2xjuXY+wcXS/PpOQo9rFh4NAKPh4Pm9f3fuLcnxkR0rDzA+mYP88FtXIUcXUyYmaIgfrzRl55jA==} engines: {node: '>=12'} hasBin: true requiresBuild: true optionalDependencies: - esbuild-android-64: 0.14.25 - esbuild-android-arm64: 0.14.25 - esbuild-darwin-64: 0.14.25 - esbuild-darwin-arm64: 0.14.25 - esbuild-freebsd-64: 0.14.25 - esbuild-freebsd-arm64: 0.14.25 - esbuild-linux-32: 0.14.25 - esbuild-linux-64: 0.14.25 - esbuild-linux-arm: 0.14.25 - esbuild-linux-arm64: 0.14.25 - esbuild-linux-mips64le: 0.14.25 - esbuild-linux-ppc64le: 0.14.25 - esbuild-linux-riscv64: 0.14.25 - esbuild-linux-s390x: 0.14.25 - esbuild-netbsd-64: 0.14.25 - esbuild-openbsd-64: 0.14.25 - esbuild-sunos-64: 0.14.25 - esbuild-windows-32: 0.14.25 - esbuild-windows-64: 0.14.25 - esbuild-windows-arm64: 0.14.25 + esbuild-android-64: 0.14.30 + esbuild-android-arm64: 0.14.30 + esbuild-darwin-64: 0.14.30 + esbuild-darwin-arm64: 0.14.30 + esbuild-freebsd-64: 0.14.30 + esbuild-freebsd-arm64: 0.14.30 + esbuild-linux-32: 0.14.30 + esbuild-linux-64: 0.14.30 + esbuild-linux-arm: 0.14.30 + esbuild-linux-arm64: 0.14.30 + esbuild-linux-mips64le: 0.14.30 + esbuild-linux-ppc64le: 0.14.30 + esbuild-linux-riscv64: 0.14.30 + esbuild-linux-s390x: 0.14.30 + esbuild-netbsd-64: 0.14.30 + esbuild-openbsd-64: 0.14.30 + esbuild-sunos-64: 0.14.30 + esbuild-windows-32: 0.14.30 + esbuild-windows-64: 0.14.30 + esbuild-windows-arm64: 0.14.30 dev: true /escalade/3.1.1: @@ -4359,9 +4056,9 @@ packages: peerDependencies: eslint: ^8.0.0 dependencies: - '@babel/core': 7.17.5 - '@babel/eslint-parser': 7.17.0_@babel+core@7.17.5 - '@rushstack/eslint-patch': 1.1.0 + '@babel/core': 7.17.8 + '@babel/eslint-parser': 7.17.0_@babel+core@7.17.8 + '@rushstack/eslint-patch': 1.1.1 '@typescript-eslint/eslint-plugin': 5.17.0_4ad50a0fa85b91f236c35644695e4e45 '@typescript-eslint/parser': 5.17.0_typescript@4.6.3 babel-preset-react-app: 10.0.1 @@ -4372,7 +4069,7 @@ packages: eslint-plugin-jsx-a11y: 6.5.1 eslint-plugin-react: 7.29.4 eslint-plugin-react-hooks: 4.4.0 - eslint-plugin-testing-library: 5.0.6_typescript@4.6.3 + eslint-plugin-testing-library: 5.2.0_typescript@4.6.3 transitivePeerDependencies: - '@babel/plugin-syntax-flow' - '@babel/plugin-transform-react-jsx' @@ -4447,7 +4144,7 @@ packages: minimatch: 3.1.2 object.values: 1.1.5 resolve: 1.22.0 - tsconfig-paths: 3.13.0 + tsconfig-paths: 3.14.1 dev: true /eslint-plugin-jest/25.7.0_4f8effa95756196a8dff211513f1ec41: @@ -4464,7 +4161,7 @@ packages: optional: true dependencies: '@typescript-eslint/eslint-plugin': 5.17.0_4ad50a0fa85b91f236c35644695e4e45 - '@typescript-eslint/experimental-utils': 5.14.0_typescript@4.6.3 + '@typescript-eslint/experimental-utils': 5.17.0_typescript@4.6.3 jest: 27.5.1 transitivePeerDependencies: - supports-color @@ -4477,7 +4174,7 @@ packages: peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 dependencies: - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 aria-query: 4.2.2 array-includes: 3.1.4 ast-types-flow: 0.0.7 @@ -4486,7 +4183,7 @@ packages: damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 has: 1.0.3 - jsx-ast-utils: 3.2.1 + jsx-ast-utils: 3.2.2 language-tags: 1.0.5 minimatch: 3.1.2 dev: true @@ -4524,7 +4221,7 @@ packages: array.prototype.flatmap: 1.2.5 doctrine: 2.1.0 estraverse: 5.3.0 - jsx-ast-utils: 3.2.1 + jsx-ast-utils: 3.2.2 minimatch: 3.1.2 object.entries: 1.1.5 object.fromentries: 2.0.5 @@ -4533,11 +4230,11 @@ packages: prop-types: 15.8.1 resolve: 2.0.0-next.3 semver: 6.3.0 - string.prototype.matchall: 4.0.6 + string.prototype.matchall: 4.0.7 dev: true - /eslint-plugin-testing-library/5.0.6_typescript@4.6.3: - resolution: {integrity: sha512-mMU4+slZsWKHNxtxc5TE2+bs9S//e2uFPlcpTapPhVdnctgn0+G/DaUu6VbT0JLiVMcbBjy3IcfddK+abZawbw==} + /eslint-plugin-testing-library/5.2.0_typescript@4.6.3: + resolution: {integrity: sha512-fYFH8lA1hbc1Epr9laNm/+YIR2d+R7WI8sFz9jIRAUfqCf21Nb5BzZwhNeZlu9wKXwDtuf+hUM5QJxG1PuDsTQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0, npm: '>=6'} peerDependencies: eslint: ^7.5.0 || ^8.0.0 @@ -4612,7 +4309,7 @@ packages: file-entry-cache: 6.0.1 functional-red-black-tree: 1.0.1 glob-parent: 5.1.2 - globals: 13.12.1 + globals: 13.13.0 ignore: 4.0.6 import-fresh: 3.3.0 imurmurhash: 0.1.4 @@ -4789,7 +4486,7 @@ packages: '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.4 + micromatch: 4.0.5 dev: true /fast-json-stable-stringify/2.1.0: @@ -4897,7 +4594,7 @@ packages: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 - mime-types: 2.1.34 + mime-types: 2.1.35 dev: true /fragment-cache/0.2.1: @@ -5030,8 +4727,8 @@ packages: engines: {node: '>=4'} dev: true - /globals/13.12.1: - resolution: {integrity: sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==} + /globals/13.13.0: + resolution: {integrity: sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==} engines: {node: '>=8'} dependencies: type-fest: 0.20.2 @@ -5129,7 +4826,7 @@ packages: /history/5.3.0: resolution: {integrity: sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==} dependencies: - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 dev: false /hoist-non-react-statics/3.3.2: @@ -5204,7 +4901,7 @@ packages: /i18next-browser-languagedetector/6.1.4: resolution: {integrity: sha512-wukWnFeU7rKIWT66VU5i8I+3Zc4wReGcuDK2+kuFhtoxBRGWGdvYI9UQmqNL/yQH1KogWwh+xGEaIPH8V/i2Zg==} dependencies: - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 dev: false /i18next-http-backend/1.4.0: @@ -5218,7 +4915,7 @@ packages: /i18next/21.6.14: resolution: {integrity: sha512-XL6WyD+xlwQwbieXRlXhKWoLb/rkch50/rA+vl6untHnJ+aYnkQ0YDZciTWE78PPhOpbi2gR0LTJCJpiAhA+uQ==} dependencies: - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 dev: false /iconv-lite/0.4.24: @@ -5425,8 +5122,8 @@ packages: engines: {node: '>= 0.4'} dev: true - /is-number-object/1.0.6: - resolution: {integrity: sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==} + /is-number-object/1.0.7: + resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.0 @@ -5473,8 +5170,10 @@ packages: has-tostringtag: 1.0.0 dev: true - /is-shared-array-buffer/1.0.1: - resolution: {integrity: sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==} + /is-shared-array-buffer/1.0.2: + resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} + dependencies: + call-bind: 1.0.2 dev: true /is-stream/1.1.0: @@ -5695,7 +5394,7 @@ packages: jest-runner: 27.5.1 jest-util: 27.5.1 jest-validate: 27.5.1 - micromatch: 4.0.4 + micromatch: 4.0.5 parse-json: 5.2.0 pretty-format: 27.5.1 slash: 3.0.0 @@ -5784,7 +5483,7 @@ packages: jest-serializer: 26.6.2 jest-util: 26.6.2 jest-worker: 26.6.2 - micromatch: 4.0.4 + micromatch: 4.0.5 sane: 4.1.0 walker: 1.0.8 optionalDependencies: @@ -5805,7 +5504,7 @@ packages: jest-serializer: 27.5.1 jest-util: 27.5.1 jest-worker: 27.5.1 - micromatch: 4.0.4 + micromatch: 4.0.5 walker: 1.0.8 optionalDependencies: fsevents: 2.3.2 @@ -5863,7 +5562,7 @@ packages: '@types/stack-utils': 2.0.1 chalk: 4.1.2 graceful-fs: 4.2.9 - micromatch: 4.0.4 + micromatch: 4.0.5 pretty-format: 27.5.1 slash: 3.0.0 stack-utils: 2.0.5 @@ -6047,7 +5746,7 @@ packages: chalk: 4.1.2 graceful-fs: 4.2.9 is-ci: 2.0.0 - micromatch: 4.0.4 + micromatch: 4.0.5 dev: true /jest-util/27.5.1: @@ -6229,12 +5928,10 @@ packages: minimist: 1.2.6 dev: true - /json5/2.2.0: - resolution: {integrity: sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==} + /json5/2.2.1: + resolution: {integrity: sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==} engines: {node: '>=6'} hasBin: true - dependencies: - minimist: 1.2.6 dev: true /jsonfile/6.1.0: @@ -6253,7 +5950,7 @@ packages: /jss-plugin-camel-case/10.9.0: resolution: {integrity: sha512-UH6uPpnDk413/r/2Olmw4+y54yEF2lRIV8XIZyuYpgPYTITLlPOsq6XB9qeqv+75SQSg3KLocq5jUBXW8qWWww==} dependencies: - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 hyphenate-style-name: 1.0.4 jss: 10.9.0 dev: false @@ -6261,21 +5958,21 @@ packages: /jss-plugin-default-unit/10.9.0: resolution: {integrity: sha512-7Ju4Q9wJ/MZPsxfu4T84mzdn7pLHWeqoGd/D8O3eDNNJ93Xc8PxnLmV8s8ZPNRYkLdxZqKtm1nPQ0BM4JRlq2w==} dependencies: - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 jss: 10.9.0 dev: false /jss-plugin-global/10.9.0: resolution: {integrity: sha512-4G8PHNJ0x6nwAFsEzcuVDiBlyMsj2y3VjmFAx/uHk/R/gzJV+yRHICjT4MKGGu1cJq2hfowFWCyrr/Gg37FbgQ==} dependencies: - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 jss: 10.9.0 dev: false /jss-plugin-nested/10.9.0: resolution: {integrity: sha512-2UJnDrfCZpMYcpPYR16oZB7VAC6b/1QLsRiAutOt7wJaaqwCBvNsosLEu/fUyKNQNGdvg2PPJFDO5AX7dwxtoA==} dependencies: - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 jss: 10.9.0 tiny-warning: 1.0.3 dev: false @@ -6283,14 +5980,14 @@ packages: /jss-plugin-props-sort/10.9.0: resolution: {integrity: sha512-7A76HI8bzwqrsMOJTWKx/uD5v+U8piLnp5bvru7g/3ZEQOu1+PjHvv7bFdNO3DwNPC9oM0a//KwIJsIcDCjDzw==} dependencies: - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 jss: 10.9.0 dev: false /jss-plugin-rule-value-function/10.9.0: resolution: {integrity: sha512-IHJv6YrEf8pRzkY207cPmdbBstBaE+z8pazhPShfz0tZSDtRdQua5jjg6NMz3IbTasVx9FdnmptxPqSWL5tyJg==} dependencies: - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 jss: 10.9.0 tiny-warning: 1.0.3 dev: false @@ -6298,7 +5995,7 @@ packages: /jss-plugin-vendor-prefixer/10.9.0: resolution: {integrity: sha512-MbvsaXP7iiVdYVSEoi+blrW+AYnTDvHTW6I6zqi7JcwXdc6I9Kbm234nEblayhF38EftoenbM+5218pidmC5gA==} dependencies: - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 css-vendor: 2.0.8 jss: 10.9.0 dev: false @@ -6306,14 +6003,14 @@ packages: /jss/10.9.0: resolution: {integrity: sha512-YpzpreB6kUunQBbrlArlsMpXYyndt9JATbt95tajx0t4MTJJcCJdd4hdNpHmOIDiUJrF/oX5wtVFrS3uofWfGw==} dependencies: - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 csstype: 3.0.11 is-in-browser: 1.1.3 tiny-warning: 1.0.3 dev: false - /jsx-ast-utils/3.2.1: - resolution: {integrity: sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==} + /jsx-ast-utils/3.2.2: + resolution: {integrity: sha512-HDAyJ4MNQBboGpUnHAVUNJs6X0lh058s6FuixsFGP7MgJYpD6Vasd6nzSG5iIfXu1zAYlHJ/zsOKNlrenTUBnw==} engines: {node: '>=4.0'} dependencies: array-includes: 3.1.4 @@ -6524,24 +6221,24 @@ packages: to-regex: 3.0.2 dev: true - /micromatch/4.0.4: - resolution: {integrity: sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==} + /micromatch/4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} engines: {node: '>=8.6'} dependencies: braces: 3.0.2 picomatch: 2.3.1 dev: true - /mime-db/1.51.0: - resolution: {integrity: sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==} + /mime-db/1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} dev: true - /mime-types/2.1.34: - resolution: {integrity: sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==} + /mime-types/2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} dependencies: - mime-db: 1.51.0 + mime-db: 1.52.0 dev: true /mimic-fn/2.1.0: @@ -6593,8 +6290,8 @@ packages: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} dev: true - /nanoid/3.3.1: - resolution: {integrity: sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==} + /nanoid/3.3.2: + resolution: {integrity: sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true dev: true @@ -6738,7 +6435,7 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.3 - es-abstract: 1.19.1 + es-abstract: 1.19.2 dev: true /object.fromentries/2.0.5: @@ -6747,14 +6444,14 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.3 - es-abstract: 1.19.1 + es-abstract: 1.19.2 dev: true /object.hasown/1.1.0: resolution: {integrity: sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg==} dependencies: define-properties: 1.1.3 - es-abstract: 1.19.1 + es-abstract: 1.19.2 dev: true /object.pick/1.3.0: @@ -6770,7 +6467,7 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.3 - es-abstract: 1.19.1 + es-abstract: 1.19.2 dev: true /once/1.4.0: @@ -6957,11 +6654,11 @@ packages: engines: {node: '>=0.10.0'} dev: true - /postcss/8.4.8: - resolution: {integrity: sha512-2tXEqGxrjvAO6U+CJzDL2Fk2kPHTv1jQsYkSoMeOis2SsYaXRO2COxTdQp99cYvif9JTXaAk9lYGc3VhJt7JPQ==} + /postcss/8.4.12: + resolution: {integrity: sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==} engines: {node: ^10 || ^12 || >=14} dependencies: - nanoid: 3.3.1 + nanoid: 3.3.2 picocolors: 1.0.0 source-map-js: 1.0.2 dev: true @@ -7098,7 +6795,7 @@ packages: react-native: optional: true dependencies: - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 html-escaper: 2.0.2 html-parse-stringify: 3.0.1 i18next: 21.6.14 @@ -7188,7 +6885,7 @@ packages: react: '>=16.6.0' react-dom: '>=16.6.0' dependencies: - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 dom-helpers: 5.2.1 loose-envify: 1.4.0 prop-types: 15.8.1 @@ -7231,8 +6928,8 @@ packages: util-deprecate: 1.0.2 dev: true - /recrawl-sync/2.2.1: - resolution: {integrity: sha512-A2yLDgeXNaduJJMlqyUdIN7fewopnNm/mVeeGytS1d2HLXKpS5EthQ0j8tWeX+as9UXiiwQRwfoslKC+/gjqxg==} + /recrawl-sync/2.2.2: + resolution: {integrity: sha512-E2sI4F25Fu2nrfV+KsnC7/qfk/spQIYXlonfQoS4rwxeNK5BjxnLPbWiRXHVXPwYBOTWtPX5765kTm/zJiL+LQ==} dependencies: '@cush/relative': 1.0.0 glob-regex: 0.3.2 @@ -7265,7 +6962,7 @@ packages: /regenerator-transform/0.14.5: resolution: {integrity: sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==} dependencies: - '@babel/runtime': 7.17.2 + '@babel/runtime': 7.17.8 dev: true /regex-not/1.0.2: @@ -7403,8 +7100,8 @@ packages: glob: 7.2.0 dev: true - /rollup/2.70.0: - resolution: {integrity: sha512-iEzYw+syFxQ0X9RefVwhr8BA2TNJsTaX8L8dhyeyMECDbmiba+8UQzcu+xZdji0+JQ+s7kouQnw+9Oz5M19XKA==} + /rollup/2.70.1: + resolution: {integrity: sha512-CRYsI5EuzLbXdxC6RnYhOuRdtz4bhejPMSWjsFLfVM/7w/85n2szZv6yExqUXsBdz5KT8eoubeyDUDjhLHEslA==} engines: {node: '>=10.0.0'} hasBin: true optionalDependencies: @@ -7735,12 +7432,12 @@ packages: strip-ansi: 6.0.1 dev: true - /string.prototype.matchall/4.0.6: - resolution: {integrity: sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg==} + /string.prototype.matchall/4.0.7: + resolution: {integrity: sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==} dependencies: call-bind: 1.0.2 define-properties: 1.1.3 - es-abstract: 1.19.1 + es-abstract: 1.19.2 get-intrinsic: 1.1.1 has-symbols: 1.0.3 internal-slot: 1.0.3 @@ -7860,7 +7557,7 @@ packages: resolution: {integrity: sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==} engines: {node: '>=10.0.0'} dependencies: - ajv: 8.10.0 + ajv: 8.11.0 lodash.truncate: 4.4.2 slice-ansi: 4.0.0 string-width: 4.2.3 @@ -8008,15 +7705,6 @@ packages: yn: 3.1.1 dev: true - /tsconfig-paths/3.13.0: - resolution: {integrity: sha512-nWuffZppoaYK0vQ1SQmkSsQzJoHA4s6uzdb2waRpD806x9yfq153AdVsWz4je2qZcW+pENrMQXbGQ3sMCkXuhw==} - dependencies: - '@types/json5': 0.0.29 - json5: 1.0.1 - minimist: 1.2.6 - strip-bom: 3.0.0 - dev: true - /tsconfig-paths/3.14.1: resolution: {integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==} dependencies: @@ -8207,7 +7895,7 @@ packages: dependencies: '@rollup/pluginutils': 4.2.0 eslint: 7.32.0 - rollup: 2.70.0 + rollup: 2.70.1 vite: 2.8.6 transitivePeerDependencies: - supports-color @@ -8239,10 +7927,10 @@ packages: peerDependencies: vite: '>2.0.0-0' dependencies: - debug: 4.3.3 + debug: 4.3.4 globrex: 0.1.2 - recrawl-sync: 2.2.1 - tsconfig-paths: 3.13.0 + recrawl-sync: 2.2.2 + tsconfig-paths: 3.14.1 vite: 2.8.6 transitivePeerDependencies: - supports-color @@ -8264,10 +7952,10 @@ packages: stylus: optional: true dependencies: - esbuild: 0.14.25 - postcss: 8.4.8 + esbuild: 0.14.30 + postcss: 8.4.12 resolve: 1.22.0 - rollup: 2.70.0 + rollup: 2.70.1 optionalDependencies: fsevents: 2.3.2 dev: true @@ -8341,7 +8029,7 @@ packages: dependencies: is-bigint: 1.0.4 is-boolean-object: 1.1.2 - is-number-object: 1.0.6 + is-number-object: 1.0.7 is-string: 1.0.7 is-symbol: 1.0.4 dev: true @@ -8446,8 +8134,8 @@ packages: yargs-parser: 20.2.9 dev: true - /yargs/17.3.1: - resolution: {integrity: sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==} + /yargs/17.4.0: + resolution: {integrity: sha512-WJudfrk81yWFSOkZYpAZx4Nt7V4xp7S/uJkX0CnxovMCt1wCE8LNftPpNuF9X/u9gN5nsD7ycYtRcDf2pL3UiA==} engines: {node: '>=12'} dependencies: cliui: 7.0.4 @@ -8468,3 +8156,7 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} dev: true + + /zxcvbn/4.4.2: + resolution: {integrity: sha1-KOwXzwl0PtyrBW3dixsGJizHPDA=} + dev: false diff --git a/web/src/components/PasswordMeter.test.tsx b/web/src/components/PasswordMeter.test.tsx new file mode 100644 index 000000000..e3e3bcba6 --- /dev/null +++ b/web/src/components/PasswordMeter.test.tsx @@ -0,0 +1,13 @@ +import React from "react"; + +import { render } from "@testing-library/react"; + +import PasswordMeter from "@components/PasswordMeter"; + +it("renders without crashing", () => { + render(); +}); + +it("renders adjusted height without crashing", () => { + render(); +}); diff --git a/web/src/components/PasswordMeter.tsx b/web/src/components/PasswordMeter.tsx new file mode 100644 index 000000000..359df648c --- /dev/null +++ b/web/src/components/PasswordMeter.tsx @@ -0,0 +1,138 @@ +import React, { useState, useEffect } from "react"; + +import { makeStyles } from "@material-ui/core"; +import classnames from "classnames"; +import { useTranslation } from "react-i18next"; +import zxcvbn from "zxcvbn"; + +export interface Props { + value: string; + /** + * mode password meter mode + * classic: classic mode (checks lowercase, uppercase, specials and numbers) + * zxcvbn: uses zxcvbn package to get the password strength + **/ + mode: string; + minLength: number; + maxLength: number; + requireLowerCase: boolean; + requireUpperCase: boolean; + requireNumber: boolean; + requireSpecial: boolean; +} + +const PasswordMeter = function (props: Props) { + const [progressColor] = useState(["#D32F2F", "#FF5722", "#FFEB3B", "#AFB42B", "#62D32F"]); + const [passwordScore, setPasswordScore] = useState(0); + const [maxScores, setMaxScores] = useState(0); + const [feedback, setFeedback] = useState(""); + const { t: translate } = useTranslation("Portal"); + const style = makeStyles((theme) => ({ + progressBar: { + height: "5px", + marginTop: "2px", + backgroundColor: "red", + width: "50%", + transition: "width .5s linear", + }, + }))(); + + useEffect(() => { + const password = props.value; + if (props.mode === "standard") { + //use mode mode + setMaxScores(4); + if (password.length < props.minLength) { + setPasswordScore(0); + setFeedback(translate("Must be at least {{len}} characters in length", { len: props.minLength })); + return; + } + if (password.length > props.maxLength) { + setPasswordScore(0); + setFeedback(translate("Must not be more than {{len}} characters in length", { len: props.maxLength })); + return; + } + setFeedback(""); + let score = 1; + let required = 0; + let hits = 0; + let warning = ""; + if (props.requireLowerCase) { + required++; + const hasLowercase = /[a-z]/.test(password); + if (hasLowercase) { + hits++; + } else { + warning += "* " + translate("Must have at least one lowercase letter") + "\n"; + } + } + + if (props.requireUpperCase) { + required++; + const hasUppercase = /[A-Z]/.test(password); + if (hasUppercase) { + hits++; + } else { + warning += "* " + translate("Must have at least one UPPERCASE letter") + "\n"; + } + } + + if (props.requireNumber) { + required++; + const hasNumber = /[0-9]/.test(password); + if (hasNumber) { + hits++; + } else { + warning += "* " + translate("Must have at least one number") + "\n"; + } + } + + if (props.requireSpecial) { + required++; + const hasSpecial = /[^0-9\w]/i.test(password); + if (hasSpecial) { + hits++; + } else { + warning += "* " + translate("Must have at least one special character") + "\n"; + } + } + score += hits > 0 ? 1 : 0; + score += required === hits ? 1 : 0; + if (warning !== "") { + setFeedback(translate("The password does not meet the password policy") + ":\n" + warning); + } + setPasswordScore(score); + } else if (props.mode === "zxcvbn") { + //use zxcvbn mode + setMaxScores(5); + const { score, feedback } = zxcvbn(password); + setFeedback(feedback.warning); + setPasswordScore(score); + } + }, [props, translate]); + + if (props.mode === "" || props.mode === "none") return ; + + return ( +
+
+
+ ); +}; + +PasswordMeter.defaultProps = { + minLength: 0, +}; + +export default PasswordMeter; diff --git a/web/src/i18n/locales/en.json b/web/src/i18n/locales/en.json index 4031dfe7f..b2378a408 100644 --- a/web/src/i18n/locales/en.json +++ b/web/src/i18n/locales/en.json @@ -55,6 +55,13 @@ "Access your email addresses": "Access your email addresses", "Accept": "Accept", "Deny": "Deny", - "The above application is requesting the following permissions": "The above application is requesting the following permissions" + "The above application is requesting the following permissions": "The above application is requesting the following permissions", + "The password does not meet the password policy": "The password does not meet the password policy", + "Must have at least one lowercase letter": "Must have at least one lowercase letter", + "Must have at least one UPPERCASE letter": "Must have at least one UPPERCASE letter", + "Must have at least one number": "Must have at least one number", + "Must have at least one special character": "Must have at least one special character", + "Must be at least {{len}} characters in length": "Must be at least {{len}} characters in length", + "Must not be more than {{len}} characters in length": "Must not be more than {{len}} characters in length" } } diff --git a/web/src/i18n/locales/es.json b/web/src/i18n/locales/es.json index 8e3244680..34b6e1b22 100644 --- a/web/src/i18n/locales/es.json +++ b/web/src/i18n/locales/es.json @@ -55,6 +55,13 @@ "Access your email addresses": "Acceso a su dirección de correo", "Accept": "Aceptar", "Deny": "Denegar", - "The above application is requesting the following permissions": "La aplicación solicita los siguientes permisos" + "The above application is requesting the following permissions": "La aplicación solicita los siguientes permisos", + "The password does not meet the password policy": "La contraseña no cumple con la política de contraseñas", + "Must have at least one lowercase letter": "Debe contener al menos una letra minúscula", + "Must have at least one UPPERCASE letter": "Debe contener al menos una letra MAYUSCULA", + "Must have at least one number": "Debe contener al menos un número", + "Must have at least one special character": "Debe contener al menos un caracter especial", + "Must be at least {{len}} characters in length": "La longitud mínima es de {{len}} caracteres", + "Must not be more than {{len}} characters in length": "La longitud máxima es de {{len}} caracteres" } } diff --git a/web/src/views/ResetPassword/ResetPasswordStep2.tsx b/web/src/views/ResetPassword/ResetPasswordStep2.tsx index b1e1aa0af..12c8cce56 100644 --- a/web/src/views/ResetPassword/ResetPasswordStep2.tsx +++ b/web/src/views/ResetPassword/ResetPasswordStep2.tsx @@ -1,11 +1,13 @@ import React, { useState, useCallback, useEffect } from "react"; -import { Grid, Button, makeStyles } from "@material-ui/core"; +import { Grid, Button, makeStyles, InputAdornment, IconButton } from "@material-ui/core"; +import { Visibility, VisibilityOff } from "@material-ui/icons"; import classnames from "classnames"; import { useTranslation } from "react-i18next"; import { useLocation, useNavigate } from "react-router-dom"; import FixedTextField from "@components/FixedTextField"; +import PasswordMeter from "@components/PasswordMeter"; import { IndexRoute } from "@constants/Routes"; import { useNotifications } from "@hooks/NotificationsContext"; import LoginLayout from "@layouts/LoginLayout"; @@ -23,6 +25,15 @@ const ResetPasswordStep2 = function () { const { createSuccessNotification, createErrorNotification } = useNotifications(); const { t: translate } = useTranslation("Portal"); const navigate = useNavigate(); + const [showPassword, setShowPassword] = useState(false); + const [pPolicyMode, setPPolicyMode] = useState("none"); + const [pPolicyMinLength, setPPolicyMinLength] = useState(0); + const [pPolicyMaxLength, setPPolicyMaxLength] = useState(0); + const [pPolicyRequireUpperCase, setPPolicyRequireUpperCase] = useState(false); + const [pPolicyRequireLowerCase, setPPolicyRequireLowerCase] = useState(false); + const [pPolicyRequireNumber, setPPolicyRequireNumber] = useState(false); + const [pPolicyRequireSpecial, setPPolicyRequireSpecial] = useState(false); + // Get the token from the query param to give it back to the API when requesting // the secret for OTP. const processToken = extractIdentityToken(location.search); @@ -36,7 +47,22 @@ const ResetPasswordStep2 = function () { try { setFormDisabled(true); - await completeResetPasswordProcess(processToken); + const { + mode, + min_length, + max_length, + require_uppercase, + require_lowercase, + require_number, + require_special, + } = await completeResetPasswordProcess(processToken); + setPPolicyMode(mode); + setPPolicyMinLength(min_length); + setPPolicyMaxLength(max_length); + setPPolicyRequireLowerCase(require_lowercase); + setPPolicyRequireUpperCase(require_uppercase); + setPPolicyRequireNumber(require_number); + setPPolicyRequireSpecial(require_special); setFormDisabled(false); } catch (err) { console.error(err); @@ -76,9 +102,9 @@ const ResetPasswordStep2 = function () { } catch (err) { console.error(err); if ((err as Error).message.includes("0000052D.")) { - createErrorNotification( - translate("Your supplied password does not meet the password policy requirements"), - ); + createErrorNotification("Your supplied password does not meet the password policy requirements."); + } else if ((err as Error).message.includes("policy")) { + createErrorNotification("Your supplied password does not meet the password policy requirements."); } else { createErrorNotification(translate("There was an issue resetting the password")); } @@ -97,21 +123,44 @@ const ResetPasswordStep2 = function () { id="password1-textfield" label={translate("New password")} variant="outlined" - type="password" + type={showPassword ? "text" : "password"} value={password1} disabled={formDisabled} onChange={(e) => setPassword1(e.target.value)} error={errorPassword1} className={classnames(style.fullWidth)} autoComplete="new-password" + InputProps={{ + endAdornment: ( + + setShowPassword(!showPassword)} + edge="end" + > + {showPassword ? : } + + + ), + }} /> + setPassword2(e.target.value)}