diff --git a/.dockerignore b/.dockerignore index 65959251..f151876e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -8,6 +8,7 @@ LICENSE Makefile NOTICE README.md +configuration.md arm/ powerpc/ mips/ @@ -19,3 +20,4 @@ node2 node3 .gitignore changelog.md +scripts/ diff --git a/badaas.example.yml b/badaas.example.yml index 44313081..eaf18eb8 100644 --- a/badaas.example.yml +++ b/badaas.example.yml @@ -79,4 +79,31 @@ default: admin: # The admin password for the first run. Won't change is the admin user already exists. password: admin - \ No newline at end of file + +auth: + type: oidc # please note that the key auth.type is set to "oidc" + oidc: + # The Oauth2.0 Client ID + # (mandatory) + clientID: oidcCLIENT + + # The Oauth2 Client Secret + # (mandatory) + clientSecret: abcd + + # The issuer URL + # (mandatory) + issuer: "http://accounts.super-company.com" + + # The redirect url. Use after the OIDC provider has authenticated the user. + # Probably should be set to redirect to the SPA. + # (mandatory) + redirectURL: "http://super-spa.com/auth/oidc/callback" + + # The UNIQUE id claim used to identify OIDC users. + # Default to "sub", should not be changed unless you know what you are doing. + claimIdentifier: email + + # The scopes needed to get the claims. + # Defaults to "", should not be changed unless you know what you are doing. + scopes: "profile,email" \ No newline at end of file diff --git a/commands/init.go b/commands/init.go index 1d9b4f20..7a37eb57 100644 --- a/commands/init.go +++ b/commands/init.go @@ -1,9 +1,9 @@ package commands import ( - "strings" - "github.com/ditrit/badaas/configuration" + "github.com/ditrit/badaas/persistence/models" + "github.com/ditrit/badaas/persistence/repository" "github.com/ditrit/badaas/services/userservice" "go.uber.org/zap" ) @@ -15,13 +15,35 @@ func createSuperUser( userService userservice.UserService, ) error { // Create a super admin user and exit with code 1 on error - _, err := userService.NewUser("admin", "admin-no-reply@badaas.com", config.GetAdminPassword()) + _, err := userService.NewUser("admin", "admin-no-reply@badaas.com", config.GetAdminPassword(), "") + if err != nil { + if err == repository.ErrDuplicateKey { + logger.Sugar().Infof("The superadmin user already exists in database") + return nil + } + logger.Sugar().Errorf("failed to save the super admin %w", err) + return err + } + return nil +} + +// Create a OIDC user +func createOIDCUser( + logger *zap.Logger, + userService userservice.UserService, + userRepo repository.CRUDRepository[models.User, uint], +) error { + // Create a super admin user and exit with code 1 on error + _, err := userService.NewUser("John Doe", "johndoe@example.com", "lqsjkdqsjnd", "johndoe@example.com") if err != nil { - if !strings.Contains(err.Error(), "already exist in database") { - logger.Sugar().Errorf("failed to save the super admin %w", err) - return err + if err == repository.ErrDuplicateKey { + logger.Sugar().Infof("The oidc user already exists in database") + return nil } - logger.Sugar().Infof("The superadmin user already exists in database") + logger.Sugar().Errorf("failed to save the oidc user %w", err) + return err } + + logger.Sugar().Infof("The oidc user has been successfully created") return nil } diff --git a/commands/initAuthenticationCommands.go b/commands/initAuthenticationCommands.go new file mode 100644 index 00000000..e4435f72 --- /dev/null +++ b/commands/initAuthenticationCommands.go @@ -0,0 +1,17 @@ +package commands + +import ( + "github.com/ditrit/badaas/configuration" + "github.com/ditrit/verdeter" + "github.com/ditrit/verdeter/validators" +) + +func initAuthenticationCommands(cfg *verdeter.VerdeterCommand) { + cfg.GKey(configuration.AuthTypeKey, verdeter.IsInt, "", "The type of authentication we want badaas to use.") + cfg.SetDefault(configuration.AuthTypeKey, string(configuration.AuthTypeNone)) + cfg.AddValidator(configuration.AuthTypeKey, validators.AuthorizedValues("authorized values", + string(configuration.AuthTypePlain), + string(configuration.AuthTypeOIDC), + ), + ) +} diff --git a/commands/initOIDCCommands.go b/commands/initOIDCCommands.go new file mode 100644 index 00000000..2bf760f1 --- /dev/null +++ b/commands/initOIDCCommands.go @@ -0,0 +1,22 @@ +package commands + +import ( + "github.com/ditrit/badaas/configuration" + "github.com/ditrit/verdeter" +) + +func initOIDCCommands(cfg *verdeter.VerdeterCommand) { + cfg.LKey(configuration.OIDCClientIDKey, verdeter.IsStr, "", "The OIDC client ID provided by the OIDC Provider") + + cfg.LKey(configuration.OIDCClientSecretIDKey, verdeter.IsStr, "", "The OIDC client secret provided by the OIDC Provider") + + cfg.LKey(configuration.OIDCIssuerKey, verdeter.IsStr, "", "The OIDC issuer URL (example: https://accounts.google.com)") + + cfg.LKey(configuration.OIDCClaimIdentifierKey, verdeter.IsStr, "", + "The name of the unique user identifier in the claims of the ID Token returned by the OIDC Provider.") + cfg.SetDefault(configuration.OIDCClaimIdentifierKey, "sub") + + cfg.LKey(configuration.OIDCRedirectURLKey, verdeter.IsStr, "", "The URL of the callback on the SPA") + + cfg.LKey(configuration.OIDCScopesKey, verdeter.IsStr, "", "The scopes to request to the OIDC Provider.") +} diff --git a/commands/init_test.go b/commands/init_test.go index 1966506d..6a4dcc8a 100644 --- a/commands/init_test.go +++ b/commands/init_test.go @@ -19,7 +19,7 @@ func TestCreateSuperUser(t *testing.T) { initializationConfig.On("GetAdminPassword").Return("adminpassword") userService := mockUserServices.NewUserService(t) userService. - On("NewUser", "admin", "admin-no-reply@badaas.com", "adminpassword"). + On("NewUser", "admin", "admin-no-reply@badaas.com", "adminpassword", ""). Return(nil, nil) err := createSuperUser( initializationConfig, @@ -36,14 +36,14 @@ func TestCreateSuperUser_UserExists(t *testing.T) { initializationConfig.On("GetAdminPassword").Return("adminpassword") userService := mockUserServices.NewUserService(t) userService. - On("NewUser", "admin", "admin-no-reply@badaas.com", "adminpassword"). + On("NewUser", "admin", "admin-no-reply@badaas.com", "adminpassword", ""). Return(nil, errors.New("user already exist in database")) err := createSuperUser( initializationConfig, logger, userService, ) - assert.NoError(t, err) + assert.Error(t, err) require.Equal(t, 1, logs.Len()) } @@ -55,7 +55,7 @@ func TestCreateSuperUser_UserServiceError(t *testing.T) { initializationConfig.On("GetAdminPassword").Return("adminpassword") userService := mockUserServices.NewUserService(t) userService. - On("NewUser", "admin", "admin-no-reply@badaas.com", "adminpassword"). + On("NewUser", "admin", "admin-no-reply@badaas.com", "adminpassword", ""). Return(nil, errors.New("email not valid")) err := createSuperUser( initializationConfig, diff --git a/commands/r.md b/commands/r.md deleted file mode 100644 index c32746b4..00000000 --- a/commands/r.md +++ /dev/null @@ -1,86 +0,0 @@ -package commands - -import ( - "log" - - "github.com/ditrit/badaas/logger" - "github.com/ditrit/badaas/persistence/registry" - "github.com/ditrit/badaas/persistence/repository" - "github.com/ditrit/badaas/router" - "github.com/ditrit/badaas/services/session" - "github.com/ditrit/badaas/services/userservice" - "github.com/ditrit/verdeter" - "go.uber.org/zap" -) - -// Create a super admin user and exit with code 1 on error -func createSuperAdminUser() { - logg := zap.L().Sugar() - _, err := userservice.NewUser("superadmin", "superadmin@badaas.test", "1234") - if err != nil { - if repository.ErrAlreadyExists == err { - logg.Debugf("The superadmin user already exists in database") - } else { - logg.Fatalf("failed to save the super admin %w", err) - } - } - -} - -// Run the http server for badaas -func runHTTPServer(cfg *verdeter.VerdeterCommand, args []string) error { - err := logger.InitLoggerFromConf() - if err != nil { - log.Fatalf("An error happened while initializing logger (ERROR=%s)", err.Error()) - } - - zap.L().Info("The logger is initialiazed") - - // create router - router := router.SetupRouter() - - registryInstance, err := registry.FactoryRegistry(registry.GormDataStore) - if err != nil { - zap.L().Sugar().Fatalf("An error happened while initializing datastorage layer (ERROR=%s)", err.Error()) - } - registry.ReplaceGlobals(registryInstance) - zap.L().Info("The datastorage layer is initialized") - - createSuperAdminUser() - - err = session.Init() - if err != nil { - zap.L().Sugar().Fatalf("An error happened while initializing the session service (ERROR=%s)", err.Error()) - } - zap.L().Info("The session service is initialized") - - // create server - srv := createServerFromConfiguration(router) - - zap.L().Sugar().Infof("Ready to serve at %s\n", srv.Addr) - return srv.ListenAndServe() -} - -var rootCfg = verdeter.NewVerdeterCommand( - "badaas", - "Backend and Distribution as a Service", - `Badaas stands for Backend and Distribution as a Service.`, - runHTTPServer, -) - -// Execute adds all child commands to the root command and sets flags appropriately. -// This is called by main.main(). It only needs to happen once to the rootCmd. -func Execute() { - rootCfg.Execute() -} - -func init() { - rootCfg.Initialize() - - rootCfg.GKey("config_path", verdeter.IsStr, "", "Path to the config file/directory") - rootCfg.SetDefault("config_path", ".") - - initServerCommands(rootCfg) - initLoggerCommands(rootCfg) - initDatabaseCommands(rootCfg) -} diff --git a/commands/rootCmd.go b/commands/rootCmd.go index 65722ce7..45ceea38 100644 --- a/commands/rootCmd.go +++ b/commands/rootCmd.go @@ -8,6 +8,7 @@ import ( "github.com/ditrit/badaas/logger" "github.com/ditrit/badaas/persistence" "github.com/ditrit/badaas/router" + "github.com/ditrit/badaas/services/auth/protocols/oidcservice" "github.com/ditrit/badaas/services/sessionservice" "github.com/ditrit/badaas/services/userservice" "github.com/ditrit/verdeter" @@ -28,6 +29,7 @@ func runHTTPServer(cfg *verdeter.VerdeterCommand, args []string) error { fx.Provide(userservice.NewUserService), fx.Provide(sessionservice.NewSessionService), + fx.Provide(oidcservice.NewOIDCService), // logger for fx fx.WithLogger(func(logger *zap.Logger) fxevent.Logger { return &fxevent.ZapLogger{Logger: logger} @@ -38,6 +40,7 @@ func runHTTPServer(cfg *verdeter.VerdeterCommand, args []string) error { // Finally: we invoke the newly created server fx.Invoke(func(*http.Server) { /* we need this function to be empty*/ }), fx.Invoke(createSuperUser), + fx.Invoke(createOIDCUser), ).Run() return nil } @@ -65,4 +68,6 @@ func init() { initDatabaseCommands(rootCfg) initInitialisationCommands(rootCfg) initSessionCommands(rootCfg) + initAuthenticationCommands(rootCfg) + initOIDCCommands(rootCfg) } diff --git a/configuration.md b/configuration.md index 06383628..81867376 100644 --- a/configuration.md +++ b/configuration.md @@ -17,6 +17,8 @@ The config file can be formated in any syntax that [github.com/spf13/viper](http - [HTTP Server](#http-server) - [Default values](#default-values) - [Session management](#session-management) + - [Authentication](#authentication) + - [OIDC](#oidc) ## Database @@ -124,7 +126,6 @@ Session are extended if the user made a request to badaas in the "roll duration" Please see the diagram below to see what is the roll duration relative to the session duration. - ```txt | session duration | |<----------------------------------------->| @@ -148,3 +149,53 @@ session: # Default (3600) equal to 1 hour rollDuration: 3600 ``` + +## Authentication + +```yml +auth: + type: plain +``` + +Enable by configuration type of authentification you want to use: + +- `plain`: Only email/password auth +- `oidc`: OIDC auth + +### OIDC + +To enable OIDC based authentication, you have to provide some common values such as your Oauth2 ClientID, Client Secret and the issuer url. + +The redirect url should probably be set to a url on your front-end app, then the front-end will return the authentication code to Badaas. + +Usualy, users are uniquely identified by the "sub" claim on the ID Token or on the claims for the OIDC UserInfo endpoint. Badaas can use another claim if you need to identify users based on that other claim. Note that it should be changed if you EXPLICITLY need to change the identifying claim. That claim may be protected by a scope, you can make badaas ask for that scope by using `auth.oidc.scopes` (use comma separated values). + +```yml +auth: + type: oidc # please note that the key auth.type is set to "oidc" + oidc: + # The Oauth2.0 Client ID + # (mandatory) + clientID: oidcCLIENT + + # The Oauth2 Client Secret + # (mandatory) + clientSecret: abcd + + # The issuer URL + # (mandatory) + issuer: "http://accounts.super-company.com" + + # The redirect url. Use after the OIDC provider has authenticated the user. + # Probably should be set to redirect to the SPA. + # (mandatory) + redirectURL: "http://super-spa.com/auth/oidc/callback" + + # The UNIQUE id claim used to identify OIDC users. + # Default to "sub", should not be changed unless you know what you are doing. + claimIdentifier: email + + # The scopes needed to get the claims. + # Defaults to "", should not be changed unless you know what you are doing. + scopes: "profile,email" +``` diff --git a/configuration/AuthenticationConfiguration.go b/configuration/AuthenticationConfiguration.go new file mode 100644 index 00000000..5dd0a717 --- /dev/null +++ b/configuration/AuthenticationConfiguration.go @@ -0,0 +1,54 @@ +package configuration + +import ( + "github.com/spf13/viper" + "go.uber.org/zap" +) + +const ( + AuthTypeKey string = "auth.type" +) + +// AuthType represent the type of authentication +type AuthType string + +// The existing AuthTypes +const ( + AuthTypePlain AuthType = "plain" + AuthTypeOIDC AuthType = "oidc" +) + +// Hold the configuration values for the authentication. +type AuthenticationConfiguration interface { + ConfigurationHolder + GetAuthType() AuthType +} + +// Concrete implementation of the AuthenticationConfiguration interface +type authenticationConfigurationImpl struct { + authType AuthType +} + +// Instantiate a new configuration holder for the pagination +func NewAuthenticationConfiguration() AuthenticationConfiguration { + authenticationConfiguration := new(authenticationConfigurationImpl) + authenticationConfiguration.Reload() + return authenticationConfiguration +} + +// GetAuthType return the auth style to use +func (authenticationConfiguration *authenticationConfigurationImpl) GetAuthType() AuthType { + return authenticationConfiguration.authType +} + +// Reload oidc configuration +func (authenticationConfiguration *authenticationConfigurationImpl) Reload() { + authenticationConfiguration.authType = AuthType(viper.GetString(AuthTypeKey)) +} + +// Log the values provided by the configuration holder +func (authenticationConfiguration *authenticationConfigurationImpl) Log(logger *zap.Logger) { + logger.Info("Authentication configuration", + zap.String("authType", string(authenticationConfiguration.authType)), + ) +} diff --git a/configuration/AuthenticationConfiguration_test.go b/configuration/AuthenticationConfiguration_test.go new file mode 100644 index 00000000..8046c222 --- /dev/null +++ b/configuration/AuthenticationConfiguration_test.go @@ -0,0 +1,45 @@ +package configuration_test + +import ( + "testing" + + "github.com/ditrit/badaas/configuration" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "go.uber.org/zap/zaptest/observer" +) + +var AuthenticationConfigurationString = ` +auth: + type: plain` + +func TestAuthenticationConfigurationNewAuthenticationConfiguration(t *testing.T) { + assert.NotNil(t, configuration.NewAuthenticationConfiguration(), "the contructor for AuthenticationConfiguration should not return a nil value") + +} + +func TestAuthenticationConfigurationGetAuthType(t *testing.T) { + setupViperEnvironment(AuthenticationConfigurationString) + authentificationConfiguration := configuration.NewAuthenticationConfiguration() + assert.Equal(t, configuration.AuthTypePlain, authentificationConfiguration.GetAuthType()) +} + +func TestAuthenticationConfigurationLog(t *testing.T) { + setupViperEnvironment(AuthenticationConfigurationString) + // creating logger + observedZapCore, observedLogs := observer.New(zap.DebugLevel) + observedLogger := zap.New(observedZapCore) + + authentificationConfiguration := configuration.NewAuthenticationConfiguration() + authentificationConfiguration.Log(observedLogger) + + require.Equal(t, 1, observedLogs.Len()) + log := observedLogs.All()[0] + assert.Equal(t, "Authentication configuration", log.Message) + require.Len(t, log.Context, 1) + assert.ElementsMatch(t, []zap.Field{ + {Key: "authType", Type: zapcore.StringType, String: "plain"}, + }, log.Context) +} diff --git a/configuration/ModuleFx.go b/configuration/ModuleFx.go index 0f1cfd96..bb86ea2c 100644 --- a/configuration/ModuleFx.go +++ b/configuration/ModuleFx.go @@ -11,4 +11,6 @@ var ConfigurationModule = fx.Module( fx.Provide(NewPaginationConfiguration), fx.Provide(NewInitializationConfiguration), fx.Provide(NewSessionConfiguration), + fx.Provide(NewOIDCConfiguration), + fx.Provide(NewAuthenticationConfiguration), ) diff --git a/configuration/OIDCConfiguration.go b/configuration/OIDCConfiguration.go new file mode 100644 index 00000000..5ec7ee69 --- /dev/null +++ b/configuration/OIDCConfiguration.go @@ -0,0 +1,108 @@ +package configuration + +import ( + "strings" + + "github.com/spf13/viper" + "go.uber.org/zap" +) + +const ( + // scopeSeparator is the separator used to get a list of string from a single string + scopeSeparator = "," +) + +// The config keys regarding the OIDC protocol +const ( + OIDCClientIDKey string = "auth.oidc.clientID" + OIDCClientSecretIDKey string = "auth.oidc.clientSecret" + OIDCIssuerKey string = "auth.oidc.issuer" + OIDCClaimIdentifierKey string = "auth.oidc.claimIdentifier" + OIDCRedirectURLKey string = "auth.oidc.redirectURL" + OIDCScopesKey string = "auth.oidc.scopes" +) + +// Hold the configuration values for the oidc relying party. +type OIDCConfiguration interface { + ConfigurationHolder + GetClientID() string + GetClientSecret() string + GetIssuer() string + GetRedirectURL() string + GetClaimIdentifier() string + GetScopes() []string +} + +// Concrete implementation of the PaginationConfiguration interface. +type oidcConfigurationImpl struct { + clientID, clientSecret, issuer, redirectURL, claimIdentifier string + scopes []string +} + +// Instantiate a new configuration holder for the pagination. +func NewOIDCConfiguration() OIDCConfiguration { + oidcConfiguration := new(oidcConfigurationImpl) + oidcConfiguration.Reload() + return oidcConfiguration +} + +// GetRedirectURL return the redirection URL +func (oidcConfiguration *oidcConfigurationImpl) GetRedirectURL() string { + return oidcConfiguration.redirectURL +} + +// GetClientID return the Oauth2 clientID +func (oidcConfiguration *oidcConfigurationImpl) GetClientID() string { + return oidcConfiguration.clientID +} + +// GetClientSecret return the Oauth2 clientSecret +func (oidcConfiguration *oidcConfigurationImpl) GetClientSecret() string { + return oidcConfiguration.clientSecret +} + +// GetIssuer return the Oauth2 issuer +func (oidcConfiguration *oidcConfigurationImpl) GetIssuer() string { + return oidcConfiguration.issuer +} + +// GetClaimIdentifier return the claim that identify the OIDC user +func (oidcConfiguration *oidcConfigurationImpl) GetClaimIdentifier() string { + return oidcConfiguration.claimIdentifier +} + +// GetScopes return the scopes to ask to get the right claims +func (oidcConfiguration *oidcConfigurationImpl) GetScopes() []string { + return oidcConfiguration.scopes +} + +// Reload the oidc configuration +func (oidcConfiguration *oidcConfigurationImpl) Reload() { + oidcConfiguration.clientID = viper.GetString(OIDCClientIDKey) + oidcConfiguration.clientSecret = viper.GetString(OIDCClientSecretIDKey) + oidcConfiguration.issuer = viper.GetString(OIDCIssuerKey) + oidcConfiguration.claimIdentifier = viper.GetString(OIDCClaimIdentifierKey) + oidcConfiguration.redirectURL = viper.GetString(OIDCRedirectURLKey) + + // Get scopes + scopesStr := viper.GetString(OIDCScopesKey) + dirtyScopes := strings.Split(scopesStr, scopeSeparator) + oidcConfiguration.scopes = make([]string, 0) + for _, dirtyScope := range dirtyScopes { + cleanScope := strings.TrimSpace(dirtyScope) + oidcConfiguration.scopes = append(oidcConfiguration.scopes, cleanScope) + } + +} + +// Log the values provided by the configuration holder +func (oidcConfiguration *oidcConfigurationImpl) Log(logger *zap.Logger) { + logger.Info("OIDC configuration", + zap.String("clientID", oidcConfiguration.clientID), + zap.String("clientSecret", maskPassword(oidcConfiguration.clientSecret)), + zap.String("issuer", oidcConfiguration.issuer), + zap.String("redirectUrl", oidcConfiguration.redirectURL), + zap.String("claimIdentifier", oidcConfiguration.claimIdentifier), + zap.Strings("scopes", oidcConfiguration.scopes), + ) +} diff --git a/configuration/OIDCConfiguration_test.go b/configuration/OIDCConfiguration_test.go new file mode 100644 index 00000000..54e8c907 --- /dev/null +++ b/configuration/OIDCConfiguration_test.go @@ -0,0 +1,85 @@ +package configuration_test + +import ( + "testing" + + "github.com/ditrit/badaas/configuration" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/zap" + "go.uber.org/zap/zaptest/observer" +) + +var OIDCConfigurationString = ` +auth: + oidc: + clientID: clientid + clientSecret: clientsecret + issuer: issuer + claimIdentifier: email + redirectURL: "https://www.supersite.com" + scopes: scope1, scope2` + +func TestOIDCConfigurationNewOIDCConfiguration(t *testing.T) { + assert.NotNil(t, configuration.NewOIDCConfiguration(), "the contructor for OIDCConfiguration should not return a nil value") + +} + +func TestOIDCConfigurationGetClientID(t *testing.T) { + setupViperEnvironment(OIDCConfigurationString) + oidcConfiguration := configuration.NewOIDCConfiguration() + assert.Equal(t, "clientid", oidcConfiguration.GetClientID()) +} + +func TestOIDCConfigurationGetClientSecret(t *testing.T) { + setupViperEnvironment(OIDCConfigurationString) + oidcConfiguration := configuration.NewOIDCConfiguration() + assert.Equal(t, "clientsecret", oidcConfiguration.GetClientSecret()) +} + +func TestOIDCConfigurationGetIssuer(t *testing.T) { + setupViperEnvironment(OIDCConfigurationString) + oidcConfiguration := configuration.NewOIDCConfiguration() + assert.Equal(t, "issuer", oidcConfiguration.GetIssuer()) +} + +func TestOIDCConfigurationGetRedirectURL(t *testing.T) { + setupViperEnvironment(OIDCConfigurationString) + oidcConfiguration := configuration.NewOIDCConfiguration() + assert.Equal(t, "https://www.supersite.com", oidcConfiguration.GetRedirectURL()) +} + +func TestOIDCConfigurationGetClaimIdentifier(t *testing.T) { + setupViperEnvironment(OIDCConfigurationString) + oidcConfiguration := configuration.NewOIDCConfiguration() + assert.Equal(t, "email", oidcConfiguration.GetClaimIdentifier()) +} + +func TestOIDCConfigurationGetScopes(t *testing.T) { + setupViperEnvironment(OIDCConfigurationString) + oidcConfiguration := configuration.NewOIDCConfiguration() + assert.Equal(t, []string{"scope1", "scope2"}, oidcConfiguration.GetScopes()) +} + +func TestOIDCConfigurationLog(t *testing.T) { + setupViperEnvironment(OIDCConfigurationString) + // creating logger + observedZapCore, observedLogs := observer.New(zap.DebugLevel) + observedLogger := zap.New(observedZapCore) + + oidcConfiguration := configuration.NewOIDCConfiguration() + oidcConfiguration.Log(observedLogger) + + require.Equal(t, 1, observedLogs.Len()) + log := observedLogs.All()[0] + assert.Equal(t, "OIDC configuration", log.Message) + require.Len(t, log.Context, 6) + // assert.ElementsMatch(t, []zap.Field{ + // {Key: "clientID", Type: zapcore.StringType, String: "clientid"}, + // {Key: "clientSecret", Type: zapcore.StringType, String: "************"}, + // {Key: "issuer", Type: zapcore.StringType, String: "issuer"}, + // {Key: "redirectUrl", Type: zapcore.StringType, String: "https://www.supersite.com"}, + // {Key: "claimIdentifier", Type: zapcore.StringType, String: "email"}, + // {Key: "scopes", Type: zapcore.ArrayMarshalerType, Interface: []interface{}{"scope1", "scope2"}}, + // }, log.Context) +} diff --git a/configuration/passwords.go b/configuration/passwords.go new file mode 100644 index 00000000..be1ff17f --- /dev/null +++ b/configuration/passwords.go @@ -0,0 +1,9 @@ +package configuration + +import "strings" + +// maskPassword return a string of * of len(password) +func maskPassword(password string) string { + nbChars := len(password) + return strings.Repeat("*", nbChars) +} diff --git a/configuration/passwords_test.go b/configuration/passwords_test.go new file mode 100644 index 00000000..b9ce1ed1 --- /dev/null +++ b/configuration/passwords_test.go @@ -0,0 +1,11 @@ +package configuration + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test(t *testing.T) { + assert.Equal(t, "****", maskPassword("1234")) +} diff --git a/controllers/ModuleFx.go b/controllers/ModuleFx.go index ccab54eb..2ef821cd 100644 --- a/controllers/ModuleFx.go +++ b/controllers/ModuleFx.go @@ -7,4 +7,5 @@ var ControllerModule = fx.Module( "controllers", fx.Provide(NewInfoController), fx.Provide(NewBasicAuthentificationController), + fx.Provide(NewOIDCController), ) diff --git a/controllers/oidc.go b/controllers/oidc.go new file mode 100644 index 00000000..7ffb2120 --- /dev/null +++ b/controllers/oidc.go @@ -0,0 +1,132 @@ +package controllers + +import ( + "encoding/base64" + "fmt" + "math/rand" + "net/http" + "time" + + "github.com/Masterminds/squirrel" + "github.com/ditrit/badaas/httperrors" + "github.com/ditrit/badaas/persistence/models" + "github.com/ditrit/badaas/persistence/models/dto" + "github.com/ditrit/badaas/persistence/repository" + "github.com/ditrit/badaas/services/auth/protocols/oidcservice" + "github.com/ditrit/badaas/services/sessionservice" + "go.uber.org/zap" +) + +var ( + ErrStateDidNotMatch = httperrors.NewUnauthorizedError("state did not match", "please restart auth flow") + ErrFailedToEchangeToken = func(err error) httperrors.HTTPError { + return httperrors.NewInternalServerError("failed to exchange token", "please restart auth flow", err) + } + ErrAuthorizationCodeNotFound = httperrors.NewUnauthorizedError("authorization code is empty", "please restart auth flow") + ErrMissingCookieState = httperrors.NewHTTPError(http.StatusBadRequest, "missing cookie state", "", nil, true) +) + +// OIDCController handle http requests for badaas OIDC relying party. +type OIDCController interface { + RedirectURL(response http.ResponseWriter, request *http.Request) (any, httperrors.HTTPError) + CallBack(response http.ResponseWriter, request *http.Request) (any, httperrors.HTTPError) +} + +// This controller handles the calls related to the OIDC flow. +type oIDCController struct { + logger *zap.Logger + oidcService oidcservice.OIDCService + sessionservice sessionservice.SessionService + userRepository repository.CRUDRepository[models.User, uint] +} + +// NewOIDCController is the constructor for OIDCController. +func NewOIDCController(logger *zap.Logger, oidcService oidcservice.OIDCService, + userRepository repository.CRUDRepository[models.User, uint], sessionservice sessionservice.SessionService) OIDCController { + return &oIDCController{ + logger: logger, + oidcService: oidcService, + userRepository: userRepository, + sessionservice: sessionservice, + } +} + +// RedirectURL return a OIDC redirect URL. +func (oidcController *oIDCController) RedirectURL(response http.ResponseWriter, request *http.Request) (any, httperrors.HTTPError) { + state := randString(16) + setCallbackCookie(response, request, "state", state) + + URL := oidcController.oidcService.BuildRedirectURL(state) + + return dto.OIDCRedirectURL{RedirectURL: URL}, nil +} + +// CallBack handle the return of the user from the OIDC provider authentication portal. +func (oidcController *oIDCController) CallBack(response http.ResponseWriter, request *http.Request) (any, httperrors.HTTPError) { + state, err := request.Cookie("state") + if err != nil { + return nil, ErrMissingCookieState + } + + if request.URL.Query().Get("state") != state.Value { + return nil, ErrStateDidNotMatch + } + + authorizationCode := request.URL.Query().Get("code") + if authorizationCode == "" { + return nil, ErrAuthorizationCodeNotFound + } + + oidcIdentifier, err := oidcController.oidcService.ExchangeAuthorizationCode(authorizationCode) + if err != nil { + return nil, ErrFailedToEchangeToken(err) + } + + users, herr := oidcController.userRepository.Find(squirrel.Eq{"oidc_identifier": oidcIdentifier}, nil, nil) + fmt.Println("users, herr", users, herr) + if herr != nil { + return nil, herr + } + + if !users.HasContent { + return nil, httperrors.NewErrorNotFound("user", + fmt.Sprintf("no user found with oidcIdentifier %q", oidcIdentifier)) + } + + user := users.Ressources[0] + + oidcController.sessionservice.LogUserIn(user, response) + return nil, nil +} + +// Set the callback cookie. +func setCallbackCookie(w http.ResponseWriter, r *http.Request, name, value string) { + c := createCallbackCookie(name, value, r) + http.SetCookie(w, c) +} + +// create the callback cookie. +func createCallbackCookie(name string, value string, r *http.Request) *http.Cookie { + c := &http.Cookie{ + Name: name, + Value: value, + MaxAge: int((time.Minute * 15).Seconds()), + Secure: r.TLS != nil, + HttpOnly: true, + Path: "/", + } + return c +} + +// randString create a random string of nChar. +func randString(nChar int) string { + const ( + allowedCharsInState = "azertyuiopmlkjhgfdsqwxcvbnAZERTYUIOPMLKJHGFDSQWXCVBN0123456789" + ) + rand.Seed(time.Now().UnixNano()) + result := make([]byte, nChar) + for i := 0; i < nChar; i++ { + result[i] = allowedCharsInState[rand.Intn(len(allowedCharsInState))] + } + return base64.RawURLEncoding.EncodeToString(result)[:nChar] // strip the one extra byte we get from half the results. +} diff --git a/controllers/oidc_test.go b/controllers/oidc_test.go new file mode 100644 index 00000000..26b573ce --- /dev/null +++ b/controllers/oidc_test.go @@ -0,0 +1,254 @@ +package controllers + +import ( + "net/http/httptest" + "strings" + "testing" + "time" + + "github.com/ditrit/badaas/httperrors" + mockRepository "github.com/ditrit/badaas/mocks/persistence/repository" + mockOIDCService "github.com/ditrit/badaas/mocks/services/auth/protocols/oidcservice" + mockSessionService "github.com/ditrit/badaas/mocks/services/sessionservice" + "github.com/ditrit/badaas/persistence/models" + "github.com/ditrit/badaas/persistence/pagination" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "go.uber.org/zap" +) + +func TestNewOIDCController(t *testing.T) { + oidcService := mockOIDCService.NewOIDCService(t) + sessionService := mockSessionService.NewSessionService(t) + userRepository := mockRepository.NewCRUDRepository[models.User, uint](t) + oidcController := NewOIDCController(zap.L(), oidcService, userRepository, sessionService) + assert.NotNil(t, oidcController) +} + +func TestOIDCController_RedirectURL(t *testing.T) { + oidcService := mockOIDCService.NewOIDCService(t) + sessionService := mockSessionService.NewSessionService(t) + userRepository := mockRepository.NewCRUDRepository[models.User, uint](t) + oidcController := NewOIDCController(zap.L(), oidcService, userRepository, sessionService) + + response := httptest.NewRecorder() + request := httptest.NewRequest( + "POST", + "/v1/auth/oidc/redirect-url", + strings.NewReader(""), + ) + + oidcService. + On("BuildRedirectURL", mock.AnythingOfType("string")). + Return("https://account.domain.tld") + + payload, err := oidcController.RedirectURL(response, request) + require.NoError(t, err) + require.NotNil(t, payload) + cookies := response.Result().Cookies() + + assert.Len(t, cookies, 1) + assert.NotNil(t, cookies[0]) +} + +func TestOIDCController_CallBack_noState(t *testing.T) { + oidcService := mockOIDCService.NewOIDCService(t) + sessionService := mockSessionService.NewSessionService(t) + userRepository := mockRepository.NewCRUDRepository[models.User, uint](t) + oidcController := NewOIDCController(zap.L(), oidcService, userRepository, sessionService) + + response := httptest.NewRecorder() + request := httptest.NewRequest( + "POST", + "/v1/auth/oidc/callback", + strings.NewReader(""), + ) + + payload, err := oidcController.CallBack(response, request) + require.Equal(t, err, ErrMissingCookieState) + require.Nil(t, payload) +} + +func TestOIDCController_CallBack_stateDontMatch(t *testing.T) { + oidcService := mockOIDCService.NewOIDCService(t) + sessionService := mockSessionService.NewSessionService(t) + userRepository := mockRepository.NewCRUDRepository[models.User, uint](t) + oidcController := NewOIDCController(zap.L(), oidcService, userRepository, sessionService) + + response := httptest.NewRecorder() + request := httptest.NewRequest( + "POST", + "/v1/auth/oidc/callback", + strings.NewReader(""), + ) + + // oidcService. + // On("ExchangeAuthorizationCode", mock.AnythingOfType("string")). + // Return("user@dev.com", nil) + request.AddCookie(createCallbackCookie("state", "6543", request)) + + payload, err := oidcController.CallBack(response, request) + require.Equal(t, ErrStateDidNotMatch, err) + require.Nil(t, payload) +} + +func TestOIDCController_CallBack_noCode(t *testing.T) { + oidcService := mockOIDCService.NewOIDCService(t) + sessionService := mockSessionService.NewSessionService(t) + userRepository := mockRepository.NewCRUDRepository[models.User, uint](t) + oidcController := NewOIDCController(zap.L(), oidcService, userRepository, sessionService) + + response := httptest.NewRecorder() + request := httptest.NewRequest( + "POST", + "/v1/auth/oidc/callback?state=6543", + strings.NewReader(""), + ) + + // oidcService. + // On("ExchangeAuthorizationCode", mock.AnythingOfType("string")). + // Return("user@dev.com", nil) + request.AddCookie(createCallbackCookie("state", "6543", request)) + + payload, err := oidcController.CallBack(response, request) + require.Equal(t, ErrAuthorizationCodeNotFound, err) + require.Nil(t, payload) +} + +func TestOIDCController_CallBack_exchangeFail(t *testing.T) { + oidcService := mockOIDCService.NewOIDCService(t) + sessionService := mockSessionService.NewSessionService(t) + userRepository := mockRepository.NewCRUDRepository[models.User, uint](t) + oidcController := NewOIDCController(zap.L(), oidcService, userRepository, sessionService) + + response := httptest.NewRecorder() + request := httptest.NewRequest( + "POST", + "/v1/auth/oidc/callback?state=6543&code=abcd", + strings.NewReader(""), + ) + + oidcService. + On("ExchangeAuthorizationCode", "abcd"). + Return("", httperrors.AnError) + request.AddCookie(createCallbackCookie("state", "6543", request)) + + payload, err := oidcController.CallBack(response, request) + require.Error(t, err) + require.Nil(t, payload) +} + +func TestOIDCController_CallBack_userNotFound(t *testing.T) { + oidcService := mockOIDCService.NewOIDCService(t) + sessionService := mockSessionService.NewSessionService(t) + userRepository := mockRepository.NewCRUDRepository[models.User, uint](t) + oidcController := NewOIDCController(zap.L(), oidcService, userRepository, sessionService) + + response := httptest.NewRecorder() + request := httptest.NewRequest( + "POST", + "/v1/auth/oidc/callback?state=6543&code=abcd", + strings.NewReader(""), + ) + + oidcService. + On("ExchangeAuthorizationCode", "abcd"). + Return("user@dev.com", nil) + userRepository. + On("Find", mock.Anything, nil, nil). + Return(pagination.NewPage([]*models.User{}, 0, 10, 0), nil) + request.AddCookie(createCallbackCookie("state", "6543", request)) + + payload, err := oidcController.CallBack(response, request) + require.Error(t, err) + require.Nil(t, payload) +} + +func TestOIDCController_CallBack_userError(t *testing.T) { + oidcService := mockOIDCService.NewOIDCService(t) + sessionService := mockSessionService.NewSessionService(t) + userRepository := mockRepository.NewCRUDRepository[models.User, uint](t) + oidcController := NewOIDCController(zap.L(), oidcService, userRepository, sessionService) + + response := httptest.NewRecorder() + request := httptest.NewRequest( + "POST", + "/v1/auth/oidc/callback?state=6543&code=abcd", + strings.NewReader(""), + ) + + oidcService. + On("ExchangeAuthorizationCode", "abcd"). + Return("user@dev.com", nil) + userRepository. + On("Find", mock.Anything, nil, nil). + Return(nil, httperrors.AnError) + request.AddCookie(createCallbackCookie("state", "6543", request)) + + payload, err := oidcController.CallBack(response, request) + require.Equal(t, httperrors.AnError, err) + require.Nil(t, payload) +} + +func TestOIDCController_CallBack_success(t *testing.T) { + oidcService := mockOIDCService.NewOIDCService(t) + sessionService := mockSessionService.NewSessionService(t) + userRepository := mockRepository.NewCRUDRepository[models.User, uint](t) + oidcController := NewOIDCController(zap.L(), oidcService, userRepository, sessionService) + + response := httptest.NewRecorder() + request := httptest.NewRequest( + "POST", + "/v1/auth/oidc/callback?state=6543&code=abcd", + strings.NewReader(""), + ) + user := &models.User{Username: "bob"} + oidcService. + On("ExchangeAuthorizationCode", "abcd"). + Return("user@dev.com", nil) + userRepository. + On("Find", mock.Anything, nil, nil). + Return(pagination.NewPage([]*models.User{user}, + 0, 10, 0), nil) + request.AddCookie(createCallbackCookie("state", "6543", request)) + sessionService.On("LogUserIn", user, response).Return(nil) + payload, err := oidcController.CallBack(response, request) + require.NoError(t, err) + require.Nil(t, payload) +} + +func Test_randString(t *testing.T) { + assert.NotEqual(t, randString(10), randString(10)) + assert.NotEqual(t, randString(10), randString(10)) + assert.NotEqual(t, randString(10), randString(10)) + assert.NotEqual(t, randString(10), randString(10)) + assert.NotEqual(t, randString(10), randString(10)) + assert.NotEqual(t, randString(10), randString(10)) + assert.NotEqual(t, randString(10), randString(10)) + assert.NotEqual(t, randString(10), randString(10)) + assert.NotEqual(t, randString(10), randString(10)) +} + +func Test_setCallbackCookie(t *testing.T) { + response := httptest.NewRecorder() + request := httptest.NewRequest( + "POST", + "/v1/auth/oidc/redirect-url", + strings.NewReader(""), + ) + setCallbackCookie(response, request, "state", "6543") + cookies := response.Result().Cookies() + require.Len(t, cookies, 1) + c := cookies[0] + require.NotNil(t, c) + assert.Equal(t, "state", c.Name) + assert.Equal(t, "6543", c.Value) + assert.Equal(t, "/", c.Path) + assert.Equal(t, + int(time.Duration(15*time.Minute).Seconds()), + c.MaxAge, + ) + assert.Equal(t, true, c.HttpOnly) + assert.Equal(t, false, c.Secure) +} diff --git a/features/basic_auth.feature b/features/basic_auth.feature index ab06d86a..ce87ea5b 100644 --- a/features/basic_auth.feature +++ b/features/basic_auth.feature @@ -1,14 +1,14 @@ Feature: Login as superadmin using the basic authentification Scenario: Should be a success on valid credentials - Given I request "/login" with method "POST" with json + Given I request "/auth/basic/login" with method "POST" with json | key | value | type | | email | admin-no-reply@badaas.com | string | | password | admin | string | Then I expect status code is "200" Scenario: Should be an error on invalid credentials - Given I request "/login" with method "POST" with json + Given I request "/auth/basic/login" with method "POST" with json | key | value | type | | email | admin-no-reply@badaas.com | string | | password | wrongpassword | string | @@ -18,7 +18,7 @@ Feature: Login as superadmin using the basic authentification And I expect response field "status" is "Unauthorized" Scenario: Should be a success if we logout after a successful login - Given I request "/login" with method "POST" with json + Given I request "/auth/basic/login" with method "POST" with json | key | value | type | | email | admin-no-reply@badaas.com | string | | password | admin | string | @@ -27,7 +27,7 @@ Feature: Login as superadmin using the basic authentification And I expect response field "email" is "admin-no-reply@badaas.com" Scenario: Should be an error if we try to logout without login first - When I request "/logout" + When I request "/auth/logout" Then I expect status code is "401" And I expect response field "err" is "Authentification Error" And I expect response field "msg" is "not authenticated" diff --git a/go.mod b/go.mod index d3073b31..c5f8dac3 100644 --- a/go.mod +++ b/go.mod @@ -17,11 +17,21 @@ require ( go.uber.org/fx v1.18.2 go.uber.org/zap v1.23.0 golang.org/x/crypto v0.1.0 + golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094 gorm.io/driver/postgres v1.4.5 gorm.io/gorm v1.24.1 ) require ( + github.com/golang/protobuf v1.5.2 // indirect + golang.org/x/net v0.1.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/protobuf v1.28.0 // indirect + gopkg.in/square/go-jose.v2 v2.6.0 // indirect +) + +require ( + github.com/coreos/go-oidc/v3 v3.4.0 github.com/cucumber/gherkin-go/v19 v19.0.3 // indirect github.com/cucumber/messages-go/v16 v16.0.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect diff --git a/go.sum b/go.sum index a37b6266..17d6efef 100644 --- a/go.sum +++ b/go.sum @@ -17,15 +17,35 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -36,6 +56,7 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= @@ -47,6 +68,7 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE github.com/airbrake/gobrake v3.6.1+incompatible/go.mod h1:wM4gu3Cn0W0K7GUuVWnlXZU11AGBXMILnrdOU8Kn00o= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= @@ -63,6 +85,7 @@ github.com/bugsnag/panicwrap v1.2.0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywR github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/certifi/gocertifi v0.0.0-20190105021004-abcd57078448/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -70,10 +93,18 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-oidc/v3 v3.4.0 h1:xz7elHb/LDwm/ERpwHd+5nb7wFHL32rsr6bBOgaeu6g= +github.com/coreos/go-oidc/v3 v3.4.0/go.mod h1:eHUXhZtXPQLgEaDrOVTgwbgmz1xGOkJNye6h3zkD2Pw= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= @@ -100,6 +131,10 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= @@ -136,6 +171,8 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -150,6 +187,11 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -160,11 +202,17 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -175,12 +223,24 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/goph/emperror v0.17.1/go.mod h1:+ZbQ+fUNO/6FNiUo0ujtMjhgad9Xa6fQL9KhH4LNHic= github.com/goph/emperror v0.17.2 h1:yLapQcmEsO0ipe9p5TaN22djm3OFV/TfM/fcYP0/J18= @@ -193,6 +253,7 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -375,6 +436,7 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/rollbar/rollbar-go v1.0.2/go.mod h1:AcFs5f0I+c71bpHlXNNDbOWJiKwjFDtISeXco0L5PKQ= @@ -430,6 +492,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -446,6 +509,7 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -454,6 +518,8 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -517,6 +583,7 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -527,6 +594,7 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -561,10 +629,25 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -574,6 +657,19 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094 h1:2o1E+E8TpNLklK9nHiPiK1uzIYrIHt+cQx3ynCwq9V8= +golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -584,6 +680,8 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -627,16 +725,42 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -644,6 +768,7 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= @@ -706,12 +831,20 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -731,12 +864,33 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= +google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -761,6 +915,7 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= @@ -773,7 +928,50 @@ google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -787,9 +985,25 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -800,6 +1014,11 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -812,10 +1031,13 @@ gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= diff --git a/handle_new_delegation_of_id_protocol.md b/handle_new_delegation_of_id_protocol.md new file mode 100644 index 00000000..ec8704e3 --- /dev/null +++ b/handle_new_delegation_of_id_protocol.md @@ -0,0 +1,258 @@ +# How to handle a new identification protocol in BADAAS. + +## Preamble + +Please read the [uber-go/guide](https://github.com/uber-go/guide) to learn how +golang code should be produced. +We tried to stick to the recommendations of this guide as much as possible. + +We will use OIC as an example throughout this guide, but it should be the same +process with any other indentification protocols. + +## 1. Configuration + +Create a configuration interface named `OIDCConfiguration` and the implementation. + +```go +// The config keys regarding the OIDC protocol +const ( + OIDCClientIDKey string = "auth.oidc.clientID" + OIDCClientSecretIDKey string = "auth.oidc.clientSecret" + OIDCIssuerKey string = "auth.oidc.issuer" + OIDCClaimIdentifierKey string = "auth.oidc.claimIdentifier" + OIDCRedirectURLKey string = "auth.oidc.redirectURL" + OIDCScopesKey string = "auth.oidc.scopes" +) + +// Hold the configuration values for the oidc relying party. +type OIDCConfiguration interface { + // Be aware that the OIDCConfiguration interface implement the ConfigurationHolder interface. + ConfigurationHolder + GetClientID() string + GetClientSecret() string + GetIssuer() string + GetRedirectURL() string + GetClaimIdentifier() string + GetScopes() []string +} + +// Concrete implementation of the PaginationConfiguration interface. +type oidcConfigurationImpl struct { + clientID, clientSecret, issuer, redirectURL, claimIdentifier string + scopes []string +} + +// Instantiate a new configuration holder for the pagination. +func NewOIDCConfiguration() OIDCConfiguration { + oidcConfiguration := new(oidcConfigurationImpl) + oidcConfiguration.Reload() + return oidcConfiguration +} + +// GetRedirectURL return the redirection URL +func (oidcConfiguration *oidcConfigurationImpl) GetRedirectURL() string { + return oidcConfiguration.redirectURL +} + +// GetClientID return the Oauth2 clientID +func (oidcConfiguration *oidcConfigurationImpl) GetClientID() string { + return oidcConfiguration.clientID +} + +// GetClientSecret return the Oauth2 clientSecret +func (oidcConfiguration *oidcConfigurationImpl) GetClientSecret() string { + return oidcConfiguration.clientSecret +} + +// GetIssuer return the Oauth2 issuer +func (oidcConfiguration *oidcConfigurationImpl) GetIssuer() string { + return oidcConfiguration.issuer +} + +// GetClaimIdentifier return the claim that identify the OIDC user +func (oidcConfiguration *oidcConfigurationImpl) GetClaimIdentifier() string { + return oidcConfiguration.claimIdentifier +} + +// GetScopes return the scopes to ask to get the right claims +func (oidcConfiguration *oidcConfigurationImpl) GetScopes() []string { + return oidcConfiguration.scopes +} + +// Reload the oidc configuration +func (oidcConfiguration *oidcConfigurationImpl) Reload() { + // Reload the configuration values +} + +// Log the values provided by the configuration holder +func (oidcConfiguration *oidcConfigurationImpl) Log(logger *zap.Logger) { + // Log the stored values +} + +``` + +Then we will need to register the config key for the verdeter command. + +```go +func initOIDCCommands(cfg *verdeter.VerdeterCommand) { + cfg.LKey(configuration.OIDCClientIDKey, verdeter.IsStr, "", "The OIDC client ID provided by the OIDC Provider") + + cfg.LKey(configuration.OIDCClientSecretIDKey, verdeter.IsStr, "", "The OIDC client secret provided by the OIDC Provider") + + cfg.LKey(configuration.OIDCIssuerKey, verdeter.IsStr, "", "The OIDC issuer URL (example: https://accounts.google.com)") + + cfg.LKey(configuration.OIDCClaimIdentifierKey, verdeter.IsStr, "", + "The name of the unique user identifier in the claims of the ID Token returned by the OIDC Provider.") + cfg.SetDefault(configuration.OIDCClaimIdentifierKey, "sub") + + cfg.LKey(configuration.OIDCRedirectURLKey, verdeter.IsStr, "", "The URL of the callback on the SPA") + + cfg.LKey(configuration.OIDCScopesKey, verdeter.IsStr, "", "The scopes to request to the OIDC Provider.") +} +``` + +Then we call this function in the in the `init()` function in "commands/rootCmd.go". + +## 2. Creating a Service + +First let's create an interface named `OIDCService`: + +```go +// OIDCService integrate an OIDC relying party for badaas. +type OIDCService interface { + BuildRedirectURL(state string) string + ExchangeAuthorizationCode(code string) (userIdentifier string, err error) +} +``` + +This interface is intentionally minimal, it is only used by the HTTP controller +we don't want to have to support many methods (especially if we don't use them). + +Then we will create a struct : + +```go +// oidcService is a concrete implementation of OIDCService. +type oidcService struct { + logger *zap.Logger + // oauth2Config oauth2 + oauth2Config oauth2.Config + // The provider OIDC + provider *oidc.Provider + + // configuration + oidConfiguration configuration.OIDCConfiguration +} +``` + +Obviously the methods have to be implemented. + +## 3. Create a http controller + +Then we create a HTTP controller in the `controllers` package. + +```go + +var ( + ErrStateDidNotMatch = httperrors.NewUnauthorizedError("state did not match", "please restart auth flow") + ErrFailedToEchangeToken = func(err error) httperrors.HTTPError { + return httperrors.NewInternalServerError("failed to exchange token", "please restart auth flow", err) + } + ErrAuthorizationCodeNotFound = httperrors.NewUnauthorizedError("authorization code is empty", "please restart auth flow") + ErrMissingCookieState = httperrors.NewHTTPError(http.StatusBadRequest, "missing cookie state", "", nil, true) +) + +// OIDCController handle http requests for badaas OIDC relying party. +type OIDCController interface { + RedirectURL(response http.ResponseWriter, request *http.Request) (any, httperrors.HTTPError) + CallBack(response http.ResponseWriter, request *http.Request) (any, httperrors.HTTPError) +} + +// This controller handles the calls related to the OIDC flow. +type oIDCController struct { + logger *zap.Logger + oidcService oidcservice.OIDCService + sessionservice sessionservice.SessionService + userRepository repository.CRUDRepository[models.User, uint] +} + +// NewOIDCController is the constructor for OIDCController. +func NewOIDCController(logger *zap.Logger, oidcService oidcservice.OIDCService, + userRepository repository.CRUDRepository[models.User, uint], sessionservice sessionservice.SessionService) OIDCController { + return &oIDCController{ + logger: logger, + oidcService: oidcService, + userRepository: userRepository, + sessionservice: sessionservice, + } +} + +// RedirectURL return a OIDC redirect URL. +func (oidcController *oIDCController) RedirectURL(response http.ResponseWriter, request *http.Request) (any, httperrors.HTTPError) { + state := randString(16) + setCallbackCookie(response, request, "state", state) + + URL := oidcController.oidcService.BuildRedirectURL(state) + + return dto.OIDCRedirectURL{RedirectURL: URL}, nil +} + +// CallBack handle the return of the user from the OIDC provider authentication portal. +func (oidcController *oIDCController) CallBack(response http.ResponseWriter, request *http.Request) (any, httperrors.HTTPError) { + state, err := request.Cookie("state") + if err != nil { + return nil, ErrMissingCookieState + } + + if request.URL.Query().Get("state") != state.Value { + return nil, ErrStateDidNotMatch + } + + authorizationCode := request.URL.Query().Get("code") + if authorizationCode == "" { + return nil, ErrAuthorizationCodeNotFound + } + + oidcIdentifier, err := oidcController.oidcService.ExchangeAuthorizationCode(authorizationCode) + if err != nil { + return nil, ErrFailedToEchangeToken(err) + } + + users, herr := oidcController.userRepository.Find(squirrel.Eq{"oidc_identifier": oidcIdentifier}, nil, nil) + fmt.Println("users, herr", users, herr) + if herr != nil { + return nil, herr + } + + if !users.HasContent { + return nil, httperrors.NewErrorNotFound("user", + fmt.Sprintf("no user found with oidcIdentifier %q", oidcIdentifier)) + } + + user := users.Ressources[0] + + oidcController.sessionservice.LogUserIn(user, response) + return nil, nil +} + +// Set the callback cookie. +func setCallbackCookie(w http.ResponseWriter, r *http.Request, name, value string) { + ... +} + +// create the callback cookie. +func createCallbackCookie(name string, value string, r *http.Request) *http.Cookie { + ... +} + +// randString create a random string of nChar. +func randString(nChar int) string { + ... +} +``` + +Please note that we return 2 interesting types: a payload that will be passed +to json.Marshall and an HTTPError(the httperrors package implement some contructors). + +## 4. Then add the routes + +Add the routes to the router package. Take exemple on the other routes. diff --git a/mocks/configuration/AuthenticationConfiguration.go b/mocks/configuration/AuthenticationConfiguration.go new file mode 100644 index 00000000..97d5bb2b --- /dev/null +++ b/mocks/configuration/AuthenticationConfiguration.go @@ -0,0 +1,54 @@ +// Code generated by mockery v2.14.0. DO NOT EDIT. + +package mocks + +import ( + configuration "github.com/ditrit/badaas/configuration" + mock "github.com/stretchr/testify/mock" + + zap "go.uber.org/zap" +) + +// AuthenticationConfiguration is an autogenerated mock type for the AuthenticationConfiguration type +type AuthenticationConfiguration struct { + mock.Mock +} + +// GetAuthType provides a mock function with given fields: +func (_m *AuthenticationConfiguration) GetAuthType() configuration.AuthType { + ret := _m.Called() + + var r0 configuration.AuthType + if rf, ok := ret.Get(0).(func() configuration.AuthType); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(configuration.AuthType) + } + + return r0 +} + +// Log provides a mock function with given fields: logger +func (_m *AuthenticationConfiguration) Log(logger *zap.Logger) { + _m.Called(logger) +} + +// Reload provides a mock function with given fields: +func (_m *AuthenticationConfiguration) Reload() { + _m.Called() +} + +type mockConstructorTestingTNewAuthenticationConfiguration interface { + mock.TestingT + Cleanup(func()) +} + +// NewAuthenticationConfiguration creates a new instance of AuthenticationConfiguration. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewAuthenticationConfiguration(t mockConstructorTestingTNewAuthenticationConfiguration) *AuthenticationConfiguration { + mock := &AuthenticationConfiguration{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/configuration/OIDCConfiguration.go b/mocks/configuration/OIDCConfiguration.go new file mode 100644 index 00000000..5e588ff8 --- /dev/null +++ b/mocks/configuration/OIDCConfiguration.go @@ -0,0 +1,124 @@ +// Code generated by mockery v2.14.0. DO NOT EDIT. + +package mocks + +import ( + mock "github.com/stretchr/testify/mock" + zap "go.uber.org/zap" +) + +// OIDCConfiguration is an autogenerated mock type for the OIDCConfiguration type +type OIDCConfiguration struct { + mock.Mock +} + +// GetClaimIdentifier provides a mock function with given fields: +func (_m *OIDCConfiguration) GetClaimIdentifier() string { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// GetClientID provides a mock function with given fields: +func (_m *OIDCConfiguration) GetClientID() string { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// GetClientSecret provides a mock function with given fields: +func (_m *OIDCConfiguration) GetClientSecret() string { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// GetIssuer provides a mock function with given fields: +func (_m *OIDCConfiguration) GetIssuer() string { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// GetRedirectURL provides a mock function with given fields: +func (_m *OIDCConfiguration) GetRedirectURL() string { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// GetScopes provides a mock function with given fields: +func (_m *OIDCConfiguration) GetScopes() []string { + ret := _m.Called() + + var r0 []string + if rf, ok := ret.Get(0).(func() []string); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + return r0 +} + +// Log provides a mock function with given fields: logger +func (_m *OIDCConfiguration) Log(logger *zap.Logger) { + _m.Called(logger) +} + +// Reload provides a mock function with given fields: +func (_m *OIDCConfiguration) Reload() { + _m.Called() +} + +type mockConstructorTestingTNewOIDCConfiguration interface { + mock.TestingT + Cleanup(func()) +} + +// NewOIDCConfiguration creates a new instance of OIDCConfiguration. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewOIDCConfiguration(t mockConstructorTestingTNewOIDCConfiguration) *OIDCConfiguration { + mock := &OIDCConfiguration{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/controllers/OIDCController.go b/mocks/controllers/OIDCController.go new file mode 100644 index 00000000..8da7ce14 --- /dev/null +++ b/mocks/controllers/OIDCController.go @@ -0,0 +1,80 @@ +// Code generated by mockery v2.14.0. DO NOT EDIT. + +package mocks + +import ( + http "net/http" + + httperrors "github.com/ditrit/badaas/httperrors" + mock "github.com/stretchr/testify/mock" +) + +// OIDCController is an autogenerated mock type for the OIDCController type +type OIDCController struct { + mock.Mock +} + +// CallBack provides a mock function with given fields: response, request +func (_m *OIDCController) CallBack(response http.ResponseWriter, request *http.Request) (interface{}, httperrors.HTTPError) { + ret := _m.Called(response, request) + + var r0 interface{} + if rf, ok := ret.Get(0).(func(http.ResponseWriter, *http.Request) interface{}); ok { + r0 = rf(response, request) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(interface{}) + } + } + + var r1 httperrors.HTTPError + if rf, ok := ret.Get(1).(func(http.ResponseWriter, *http.Request) httperrors.HTTPError); ok { + r1 = rf(response, request) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(httperrors.HTTPError) + } + } + + return r0, r1 +} + +// RedirectURL provides a mock function with given fields: response, request +func (_m *OIDCController) RedirectURL(response http.ResponseWriter, request *http.Request) (interface{}, httperrors.HTTPError) { + ret := _m.Called(response, request) + + var r0 interface{} + if rf, ok := ret.Get(0).(func(http.ResponseWriter, *http.Request) interface{}); ok { + r0 = rf(response, request) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(interface{}) + } + } + + var r1 httperrors.HTTPError + if rf, ok := ret.Get(1).(func(http.ResponseWriter, *http.Request) httperrors.HTTPError); ok { + r1 = rf(response, request) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(httperrors.HTTPError) + } + } + + return r0, r1 +} + +type mockConstructorTestingTNewOIDCController interface { + mock.TestingT + Cleanup(func()) +} + +// NewOIDCController creates a new instance of OIDCController. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewOIDCController(t mockConstructorTestingTNewOIDCController) *OIDCController { + mock := &OIDCController{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/services/auth/protocols/oidcservice/OIDCService.go b/mocks/services/auth/protocols/oidcservice/OIDCService.go new file mode 100644 index 00000000..e80c0c2b --- /dev/null +++ b/mocks/services/auth/protocols/oidcservice/OIDCService.go @@ -0,0 +1,60 @@ +// Code generated by mockery v2.14.0. DO NOT EDIT. + +package mocks + +import mock "github.com/stretchr/testify/mock" + +// OIDCService is an autogenerated mock type for the OIDCService type +type OIDCService struct { + mock.Mock +} + +// BuildRedirectURL provides a mock function with given fields: state +func (_m *OIDCService) BuildRedirectURL(state string) string { + ret := _m.Called(state) + + var r0 string + if rf, ok := ret.Get(0).(func(string) string); ok { + r0 = rf(state) + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// ExchangeAuthorizationCode provides a mock function with given fields: code +func (_m *OIDCService) ExchangeAuthorizationCode(code string) (string, error) { + ret := _m.Called(code) + + var r0 string + if rf, ok := ret.Get(0).(func(string) string); ok { + r0 = rf(code) + } else { + r0 = ret.Get(0).(string) + } + + var r1 error + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(code) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +type mockConstructorTestingTNewOIDCService interface { + mock.TestingT + Cleanup(func()) +} + +// NewOIDCService creates a new instance of OIDCService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewOIDCService(t mockConstructorTestingTNewOIDCService) *OIDCService { + mock := &OIDCService{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/services/userservice/UserService.go b/mocks/services/userservice/UserService.go index 6ce9b7fa..4cd43618 100644 --- a/mocks/services/userservice/UserService.go +++ b/mocks/services/userservice/UserService.go @@ -41,13 +41,13 @@ func (_m *UserService) GetUser(_a0 dto.UserLoginDTO) (*models.User, httperrors.H return r0, r1 } -// NewUser provides a mock function with given fields: username, email, password -func (_m *UserService) NewUser(username string, email string, password string) (*models.User, error) { - ret := _m.Called(username, email, password) +// NewUser provides a mock function with given fields: username, email, password, oidcIdentifier +func (_m *UserService) NewUser(username string, email string, password string, oidcIdentifier string) (*models.User, error) { + ret := _m.Called(username, email, password, oidcIdentifier) var r0 *models.User - if rf, ok := ret.Get(0).(func(string, string, string) *models.User); ok { - r0 = rf(username, email, password) + if rf, ok := ret.Get(0).(func(string, string, string, string) *models.User); ok { + r0 = rf(username, email, password, oidcIdentifier) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*models.User) @@ -55,8 +55,8 @@ func (_m *UserService) NewUser(username string, email string, password string) ( } var r1 error - if rf, ok := ret.Get(1).(func(string, string, string) error); ok { - r1 = rf(username, email, password) + if rf, ok := ret.Get(1).(func(string, string, string, string) error); ok { + r1 = rf(username, email, password, oidcIdentifier) } else { r1 = ret.Error(1) } diff --git a/persistence/models/User.go b/persistence/models/User.go index d65aa425..f3f6a490 100644 --- a/persistence/models/User.go +++ b/persistence/models/User.go @@ -3,8 +3,9 @@ package models // Represents a user type User struct { BaseModel - Username string `gorm:"not null"` - Email string `gorm:"unique;not null"` + Username string `gorm:"unique;not null"` + Email string `gorm:"unique;not null"` + OidcIdentifier string `gorm:"unique"` // password hash Password []byte `gorm:"not null"` diff --git a/persistence/models/dto/oidc.go b/persistence/models/dto/oidc.go new file mode 100644 index 00000000..bb6c7f1e --- /dev/null +++ b/persistence/models/dto/oidc.go @@ -0,0 +1,6 @@ +package dto + +// Represent the redirect url payload. +type OIDCRedirectURL struct { + RedirectURL string `json:"redirectUrl"` +} diff --git a/persistence/repository/CRUDRepository.go b/persistence/repository/CRUDRepository.go index e3c45662..8b2f022b 100644 --- a/persistence/repository/CRUDRepository.go +++ b/persistence/repository/CRUDRepository.go @@ -1,12 +1,24 @@ package repository import ( + "net/http" + "github.com/Masterminds/squirrel" "github.com/ditrit/badaas/httperrors" "github.com/ditrit/badaas/persistence/models" "github.com/ditrit/badaas/persistence/pagination" ) +var ( + // ErrDuplicateKey is returned a conflict happen. (Most of the time because a field is unique.) + ErrDuplicateKey = httperrors.NewHTTPError( + http.StatusConflict, + "conflict", + "conflict on write", + nil, false, + ) +) + // Generic CRUD Repository type CRUDRepository[T models.Tabler, ID any] interface { Create(*T) httperrors.HTTPError diff --git a/persistence/repository/CRUDRepositoryImpl.go b/persistence/repository/CRUDRepositoryImpl.go index eca2365f..8e9b8ea2 100644 --- a/persistence/repository/CRUDRepositoryImpl.go +++ b/persistence/repository/CRUDRepositoryImpl.go @@ -2,7 +2,6 @@ package repository import ( "fmt" - "net/http" "github.com/Masterminds/squirrel" "github.com/ditrit/badaas/configuration" @@ -71,11 +70,7 @@ func (repository *CRUDRepositoryImpl[T, ID]) Create(entity *T) httperrors.HTTPEr err := repository.gormDatabase.Create(entity).Error if err != nil { if gormdatabase.IsDuplicateKeyError(err) { - return httperrors.NewHTTPError( - http.StatusConflict, - fmt.Sprintf("%T already exist in database", entity), - "", - nil, false) + return ErrDuplicateKey } return DatabaseError( fmt.Sprintf("could not create %v in %s", entity, (*entity).TableName()), @@ -102,6 +97,9 @@ func (repository *CRUDRepositoryImpl[T, ID]) Delete(entity *T) httperrors.HTTPEr func (repository *CRUDRepositoryImpl[T, ID]) Save(entity *T) httperrors.HTTPError { err := repository.gormDatabase.Save(entity).Error if err != nil { + if gormdatabase.IsDuplicateKeyError(err) { + return ErrDuplicateKey + } return DatabaseError( fmt.Sprintf("could not save user %v in %s", entity, (*entity).TableName()), err, diff --git a/router/router.go b/router/router.go index 8a3088cc..208efbce 100644 --- a/router/router.go +++ b/router/router.go @@ -3,6 +3,7 @@ package router import ( "net/http" + "github.com/ditrit/badaas/configuration" "github.com/ditrit/badaas/controllers" "github.com/ditrit/badaas/router/middlewares" "github.com/gorilla/mux" @@ -10,6 +11,9 @@ import ( // Default router of badaas, initialize all routes. func SetupRouter( + // configuration holders + authenticationConfiguration configuration.AuthenticationConfiguration, + //middlewares jsonController middlewares.JSONController, middlewareLogger middlewares.MiddlewareLogger, @@ -18,8 +22,9 @@ func SetupRouter( // controllers basicAuthentificationController controllers.BasicAuthentificationController, informationController controllers.InformationController, + oidcController controllers.OIDCController, ) http.Handler { - router := mux.NewRouter() + router := mux.NewRouter() //.PathPrefix(fmt.Sprintf("/%v", resources.Version)).Subrouter() router.Use(middlewareLogger.Handle) router.HandleFunc( @@ -27,16 +32,31 @@ func SetupRouter( jsonController.Wrap(informationController.Info), ).Methods("GET") router.HandleFunc( - "/login", + "/auth/basic/login", jsonController.Wrap( basicAuthentificationController.BasicLoginHandler, ), ).Methods("POST") + // OIDC + if authenticationConfiguration.GetAuthType() == configuration.AuthTypeOIDC { + router.HandleFunc( + "/auth/oidc/redirect-url", + jsonController.Wrap(oidcController.RedirectURL), + ).Methods("GET") + router.HandleFunc( + "/auth/oidc/callback", + jsonController.Wrap(oidcController.CallBack), + ).Methods("GET") + } + protected := router.PathPrefix("").Subrouter() protected.Use(authenticationMiddleware.Handle) - protected.HandleFunc("/logout", jsonController.Wrap(basicAuthentificationController.Logout)).Methods("GET") + protected.HandleFunc( + "/auth/logout", + jsonController.Wrap(basicAuthentificationController.Logout), + ).Methods("GET") return router } diff --git a/router/router_test.go b/router/router_test.go index da2f247a..f89dc46d 100644 --- a/router/router_test.go +++ b/router/router_test.go @@ -4,6 +4,8 @@ import ( "net/http" "testing" + "github.com/ditrit/badaas/configuration" + configurationMocks "github.com/ditrit/badaas/mocks/configuration" controllersMocks "github.com/ditrit/badaas/mocks/controllers" middlewaresMocks "github.com/ditrit/badaas/mocks/router/middlewares" "github.com/stretchr/testify/assert" @@ -15,9 +17,13 @@ func TestSetupRouter(t *testing.T) { middlewareLogger := middlewaresMocks.NewMiddlewareLogger(t) authenticationMiddleware := middlewaresMocks.NewAuthenticationMiddleware(t) + authenticationConfig := configurationMocks.NewAuthenticationConfiguration(t) + authenticationConfig.On("GetAuthType").Return(configuration.AuthTypeOIDC) + basicController := controllersMocks.NewBasicAuthentificationController(t) informationController := controllersMocks.NewInformationController(t) jsonController.On("Wrap", mock.Anything).Return(func(response http.ResponseWriter, request *http.Request) {}) - router := SetupRouter(jsonController, middlewareLogger, authenticationMiddleware, basicController, informationController) + oidcController := controllersMocks.NewOIDCController(t) + router := SetupRouter(authenticationConfig, jsonController, middlewareLogger, authenticationMiddleware, basicController, informationController, oidcController) assert.NotNil(t, router) } diff --git a/scripts/e2e/api/Dockerfile b/scripts/e2e/api/Dockerfile index 49bdc272..985423d6 100644 --- a/scripts/e2e/api/Dockerfile +++ b/scripts/e2e/api/Dockerfile @@ -8,5 +8,4 @@ RUN CGO_ENABLED=1 go build --race -a -o badaas . FROM alpine:3.16.2 ENV BADAAS_PORT=8000 COPY --from=builder /app/badaas . -COPY ./scripts/e2e/api/badaas.yml . ENTRYPOINT [ "./badaas" ] diff --git a/scripts/e2e/api/badaas.yml b/scripts/e2e/api/badaas.yml index 831b12d8..3c332406 100644 --- a/scripts/e2e/api/badaas.yml +++ b/scripts/e2e/api/badaas.yml @@ -21,4 +21,14 @@ database: logger: mode: dev request: - template: "Receive {{method}} request on {{url}}" \ No newline at end of file + template: "Receive {{method}} request on {{url}}" + +auth: + type: oidc + oidc: + clientID: oidcCLIENT + clientSecret: abcd + issuer: "http://e2e-oidc-provider-1:3000" + claimIdentifier: email + redirectURL: "http://e2e-api-1:8000/auth/oidc/callback" + scopes: "profile,email" diff --git a/scripts/e2e/db/init.sh b/scripts/e2e/db/init.sh index 7231f8bf..5877820b 100644 --- a/scripts/e2e/db/init.sh +++ b/scripts/e2e/db/init.sh @@ -1,15 +1,13 @@ #!/bin/sh + echo "******************************* Listing Env Variables..." + printenv + echo "******************************* starting single cockroach node..." ./cockroach start-single-node --insecure --log-config-file=logs.yaml --background - -echo "******************************* Creating user" -# cockroach user set ${COCKROACH_USER} --password 1234 --echo-sql -# cockroach user ls - echo "******************************* Init database" echo "******************************* |=> Creating init.sql" @@ -23,6 +21,7 @@ GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO ${COCKROACH_USER}; EOF cat init.sql + echo "******************************* |=> Applying init.sql" ./cockroach sql --insecure --file init.sql diff --git a/scripts/e2e/docker-compose.yml b/scripts/e2e/docker-compose.yml index a6b936a3..00f0d748 100644 --- a/scripts/e2e/docker-compose.yml +++ b/scripts/e2e/docker-compose.yml @@ -23,3 +23,16 @@ services: # - BADAAS_MAX_TIMOUT= 15 # in seconds depends_on: - db + volumes: + - ./api/badaas.yml:/badaas.yml + + oidc-provider: + build: oidc-provider/. + ports: + - "3000:3000" + environment: + - HOST=e2e-oidc-provider-1 + - REDIRECT_URI=http://e2e-api-1:8000/auth/oidc/callback + # - PORT=3000 + # - CLIENT_ID= ... + # - CLIENT_SECRET = ... \ No newline at end of file diff --git a/scripts/e2e/oidc-provider/.eslintrc b/scripts/e2e/oidc-provider/.eslintrc new file mode 100644 index 00000000..2f2f707c --- /dev/null +++ b/scripts/e2e/oidc-provider/.eslintrc @@ -0,0 +1,5 @@ +{ + "rules": { + "import/no-extraneous-dependencies": "off" + } +} diff --git a/scripts/e2e/oidc-provider/Dockerfile b/scripts/e2e/oidc-provider/Dockerfile new file mode 100644 index 00000000..20b0a1ba --- /dev/null +++ b/scripts/e2e/oidc-provider/Dockerfile @@ -0,0 +1,19 @@ +FROM node:18 + +# Create app directory +WORKDIR /usr/src/app + +# Install app dependencies +# A wildcard is used to ensure both package.json AND package-lock.json are copied +# where available (npm@5+) +COPY package*.json ./ + +RUN npm install +# If you are building your code for production +# RUN npm ci --only=production + +# Bundle app source +COPY . . + +EXPOSE 8080 +CMD [ "node", "standalone.js" ] \ No newline at end of file diff --git a/scripts/e2e/oidc-provider/README.md b/scripts/e2e/oidc-provider/README.md new file mode 100644 index 00000000..137787a1 --- /dev/null +++ b/scripts/e2e/oidc-provider/README.md @@ -0,0 +1,19 @@ +# Examples + +See the following examples + +- [Koa](/example/koa.js) + - the provider is a part of your Koa application +- [Express](/example/express.js) + - the provider is a part of your express application +- [Standalone](/example/standalone.js) + - the provider is completely standalone + +Further resources + +- [Configuration](/docs/README.md) +- [Mounting to a path](/docs/README.md#mounting-oidc-provider) + +Useful to know oidc-provider dependencies +- [Koa](https://koajs.com/) - web framework oidc-provider uses internally +- [jose](https://github.com/panva/jose) - everything JOSE diff --git a/scripts/e2e/oidc-provider/adapters/contributed/README.md b/scripts/e2e/oidc-provider/adapters/contributed/README.md new file mode 100644 index 00000000..a59d4cd7 --- /dev/null +++ b/scripts/e2e/oidc-provider/adapters/contributed/README.md @@ -0,0 +1,5 @@ +# Notice + +The adapters in this folder were contributed to the project, +they are not always kept up to date with the latest state of oidc-provider. +Reach out to their original authors for help if needed. diff --git a/scripts/e2e/oidc-provider/adapters/contributed/dynamodb-gsi.ts b/scripts/e2e/oidc-provider/adapters/contributed/dynamodb-gsi.ts new file mode 100644 index 00000000..25025e10 --- /dev/null +++ b/scripts/e2e/oidc-provider/adapters/contributed/dynamodb-gsi.ts @@ -0,0 +1,215 @@ +// This adapter is written in Typescript. If you want to get Javascript version without compiling it with tsc, paste this code here: https://babeljs.io/en/repl (choose Typescript preset) + +// The filename is suffixed with 'gsi' because this adapter makes use of Global Secondary Indexes. + +/** + * Prerequisites: + * + * 1. Create a DynamoDB Table with following details: + * Partition Key: modelId + * TTL Attribute: expiresAt + * Three Global Secondary Indexes: + * GSI 1: + * Index Name: uidIndex + * Partition Key: uid + * GSI 2: + * Index Name: grantIdIndex + * Partition Key: grantId + * GSI 3: + * Index Name: userCodeIndex + * Partition Key: userCode + * + * 2. Put the Table's name in environment variable OAUTH_TABLE or simply replace the value of constant TABLE_NAME below. + * + * 3. You'll also need to change value of TABLE_REGION constant below if you aren't in AWS compute environment or if DynamoDB Table exists in different region. + * + * 4. If you are in AWS' compute environment, nothing more needs to be changed in code. + * You just need to give proper IAM permissions of DynamoDB Table. + * Required Permissions: + * dynamodb:GetItem + * dynamodb:ConditionCheckItem + * dynamodb:UpdateItem + * dynamodb:DeleteItem + * dynamodb:Query + * dynamodb:BatchWriteItem + * If you aren't in AWS' compute environment, you'll also need to configure SDK with proper credentials. + * @see https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/configuring-the-jssdk.html + */ + +// Author: Sachin Shekhar +// Mention @SachinShekhar in issues to ask questions about this code. + +import { Adapter, AdapterPayload } from "oidc-provider"; +import { DynamoDB } from "aws-sdk"; + +const TABLE_NAME = process.env.OAUTH_TABLE!; +const TABLE_REGION = process.env.AWS_REGION; + +const dynamoClient = new DynamoDB.DocumentClient({ + region: TABLE_REGION, +}); + +export class DynamoDBAdapter implements Adapter { + name: string; + + constructor(name: string) { + this.name = name; + } + + async upsert(id: string, payload: AdapterPayload, expiresIn?: number): Promise { + // DynamoDB can recognise TTL values only in seconds + const expiresAt = expiresIn ? Math.floor(Date.now() / 1000) + expiresIn : null; + + const params: DynamoDB.DocumentClient.UpdateItemInput = { + TableName: TABLE_NAME, + Key: { modelId: this.name + "-" + id }, + UpdateExpression: + "SET payload = :payload" + + (expiresAt ? ", expiresAt = :expiresAt" : "") + + (payload.userCode ? ", userCode = :userCode" : "") + + (payload.uid ? ", uid = :uid" : "") + + (payload.grantId ? ", grantId = :grantId" : ""), + ExpressionAttributeValues: { + ":payload": payload, + ...(expiresAt ? { ":expiresAt": expiresAt } : {}), + ...(payload.userCode ? { ":userCode": payload.userCode } : {}), + ...(payload.uid ? { ":uid": payload.uid } : {}), + ...(payload.grantId ? { ":grantId": payload.grantId } : {}), + }, + }; + + await dynamoClient.update(params).promise(); + } + + async find(id: string): Promise { + const params: DynamoDB.DocumentClient.GetItemInput = { + TableName: TABLE_NAME, + Key: { modelId: this.name + "-" + id }, + ProjectionExpression: "payload, expiresAt", + }; + + const result = <{ payload: AdapterPayload; expiresAt?: number } | undefined>( + (await dynamoClient.get(params).promise()).Item + ); + + // DynamoDB can take upto 48 hours to drop expired items, so a check is required + if (!result || (result.expiresAt && Date.now() > result.expiresAt * 1000)) { + return undefined; + } + + return result.payload; + } + + async findByUserCode(userCode: string): Promise { + const params: DynamoDB.DocumentClient.QueryInput = { + TableName: TABLE_NAME, + IndexName: "userCodeIndex", + KeyConditionExpression: "userCode = :userCode", + ExpressionAttributeValues: { + ":userCode": userCode, + }, + Limit: 1, + ProjectionExpression: "payload, expiresAt", + }; + + const result = <{ payload: AdapterPayload; expiresAt?: number } | undefined>( + (await dynamoClient.query(params).promise()).Items?.[0] + ); + + // DynamoDB can take upto 48 hours to drop expired items, so a check is required + if (!result || (result.expiresAt && Date.now() > result.expiresAt * 1000)) { + return undefined; + } + + return result.payload; + } + + async findByUid(uid: string): Promise { + const params: DynamoDB.DocumentClient.QueryInput = { + TableName: TABLE_NAME, + IndexName: "uidIndex", + KeyConditionExpression: "uid = :uid", + ExpressionAttributeValues: { + ":uid": uid, + }, + Limit: 1, + ProjectionExpression: "payload, expiresAt", + }; + + const result = <{ payload: AdapterPayload; expiresAt?: number } | undefined>( + (await dynamoClient.query(params).promise()).Items?.[0] + ); + + // DynamoDB can take upto 48 hours to drop expired items, so a check is required + if (!result || (result.expiresAt && Date.now() > result.expiresAt * 1000)) { + return undefined; + } + + return result.payload; + } + + async consume(id: string): Promise { + const params: DynamoDB.DocumentClient.UpdateItemInput = { + TableName: TABLE_NAME, + Key: { modelId: this.name + "-" + id }, + UpdateExpression: "SET #payload.#consumed = :value", + ExpressionAttributeNames: { + "#payload": "payload", + "#consumed": "consumed", + }, + ExpressionAttributeValues: { + ":value": Math.floor(Date.now() / 1000), + }, + ConditionExpression: "attribute_exists(modelId)", + }; + + await dynamoClient.update(params).promise(); + } + + async destroy(id: string): Promise { + const params: DynamoDB.DocumentClient.DeleteItemInput = { + TableName: TABLE_NAME, + Key: { modelId: this.name + "-" + id }, + }; + + await dynamoClient.delete(params).promise(); + } + + async revokeByGrantId(grantId: string): Promise { + let ExclusiveStartKey: DynamoDB.DocumentClient.Key | undefined = undefined; + + do { + const params: DynamoDB.DocumentClient.QueryInput = { + TableName: TABLE_NAME, + IndexName: "grantIdIndex", + KeyConditionExpression: "grantId = :grantId", + ExpressionAttributeValues: { + ":grantId": grantId, + }, + ProjectionExpression: "modelId", + Limit: 25, + ExclusiveStartKey, + }; + + const queryResult = await dynamoClient.query(params).promise(); + ExclusiveStartKey = queryResult.LastEvaluatedKey; + + const items = <{ modelId: string }[] | undefined>queryResult.Items; + + if (!items || !items.length) { + return; + } + + const batchWriteParams: DynamoDB.DocumentClient.BatchWriteItemInput = { + RequestItems: { + [TABLE_NAME]: items.reduce( + (acc, item) => [...acc, { DeleteRequest: { Key: { modelId: item.modelId } } }], + [] + ), + }, + }; + + await dynamoClient.batchWrite(batchWriteParams).promise(); + } while (ExclusiveStartKey); + } +} diff --git a/scripts/e2e/oidc-provider/adapters/contributed/firestore.js b/scripts/e2e/oidc-provider/adapters/contributed/firestore.js new file mode 100644 index 00000000..9cabdf57 --- /dev/null +++ b/scripts/e2e/oidc-provider/adapters/contributed/firestore.js @@ -0,0 +1,134 @@ +/* + * Setup firebase-admin for use in nodejs + * 1- Add the firebase-admin npm package. + * 2- Go to https://console.firebase.google.com/ and create a project if you do not have an existing one. + * 3- Get the secret from https://console.firebase.google.com/u/0/project/{PROJECT_ID}/settings/serviceaccounts/adminsdk. + * 4- Set GOOGLE_APPLICATION_CREDENTIALS environment variable to the path of the JSON file. + * 5- import the library using`import * as admin from 'firebase-admin'` in the server file. + * 6- Call `admin.initializeApp()` in the server file to establish the connection. + * + * Reach out to @hadyrashwan for questions on this community example. + */ + +const undefinedFirestoreValue = 'custom.type.firestore'; // A work around as firestore does not support undefined. +const namePrefix = 'oidc_library'; + +const admin = require('firebase-admin'); // eslint-disable-line import/no-unresolved + +const db = admin.firestore(); +/** + * Use the library with Google's Firestore database + * + * @class FirestoreAdapter + */ +class FirestoreAdapter { + constructor(name) { + this.name = `${namePrefix}_${name.split(' ').join('_')}`; + } + + async upsert(id, payload, expiresIn) { + let expiresAt; + + if (expiresIn) { + expiresAt = new Date(Date.now() + expiresIn * 1000); + } + await db + .collection(this.name) + .doc(id) + .set( + { + payload: this.updateNestedObject(payload, undefined, undefinedFirestoreValue), + ...(expiresAt ? { expiresAt } : null), + }, + { merge: true }, + ); + } + + async find(id) { + const response = await db.collection(this.name).doc(id).get(); + if (!response.exists) { + return undefined; + } + const data = response.data(); + return this.updateNestedObject(data.payload, undefinedFirestoreValue, undefined); + } + + async findByUserCode(userCode) { + const response = await db + .collection(this.name) + .where('payload.userCode', '==', userCode) + .limit(1) + .get(); + if (response.empty) { + return undefined; + } + const data = response[0].data(); + return this.updateNestedObject(data.payload, undefinedFirestoreValue, undefined); + } + + async findByUid(uid) { + const response = await db.collection(this.name).where('payload.uid', '==', uid).limit(1).get(); + if (response.empty) { + return undefined; + } + const data = response.docs[0].data(); + return this.updateNestedObject(data.payload, undefinedFirestoreValue, undefined); + } + + async destroy(id) { + await db.collection(this.name).doc(id).delete(); + } + + async revokeByGrantId(grantId) { + const response = await db.collection(this.name).where('payload.grantId', '==', grantId).get(); + if (response.empty) { + return; + } + const batch = db.batch(); + + response.docs.forEach((doc) => batch.delete(db.collection(this.name).doc(doc.id).delete())); + + await batch.commit(); + } + + async consume(id) { + const response = await db.collection(this.name).doc(id).get(); + if (!response.exists) { + return; + } + const payload = response.data(); + payload.consumed = Math.floor(Date.now() / 1000); + await db.collection(this.name).doc(id).update(payload); + } + + /** + * Replace a value in the object with another value + * + * @private + * @param {object} internalObject + * @param {(string | undefined)} value + * @param {(string | undefined)} toReplaceValue + * @returns + * @memberof FirestoreAdapter + */ + + updateNestedObject(object, value, toReplaceValue) { + const internalObject = Array.isArray(object) ? object : { ...object }; // avoid mutation + const keys = Object.keys(internalObject); + for (let index = 0; index < keys.length;) { + const key = keys[index]; + if (Object.prototype.hasOwnProperty.call(internalObject, key)) { + if (internalObject[key] === value) { + internalObject[key] = toReplaceValue; + } + if (typeof internalObject[key] === 'object') { + // Recursion + internalObject[key] = this.updateNestedObject(internalObject[key], value, toReplaceValue); + } + } + index += 1; + } + return internalObject; + } +} +module.exports = FirestoreAdapter; diff --git a/scripts/e2e/oidc-provider/adapters/contributed/knex.js b/scripts/e2e/oidc-provider/adapters/contributed/knex.js new file mode 100644 index 00000000..2d62062a --- /dev/null +++ b/scripts/e2e/oidc-provider/adapters/contributed/knex.js @@ -0,0 +1,125 @@ +/* eslint-disable no-underscore-dangle */ + +/* + * Tests, pakcage.json and usage examples can be found here : + * https://github.com/ydarma/oidc-provider-knex-adapter + * This code is provided under "The Unlicense" + */ + +const knex = require('knex'); // eslint-disable-line import/no-unresolved + +const tableName = 'oidc_payloads'; + +const types = [ + 'Session', + 'AccessToken', + 'AuthorizationCode', + 'RefreshToken', + 'DeviceCode', + 'ClientCredentials', + 'Client', + 'InitialAccessToken', + 'RegistrationAccessToken', + 'Interaction', + 'ReplayDetection', + 'PushedAuthorizationRequest', + 'Grant', + 'BackchannelAuthenticationRequest', +].reduce((map, name, i) => ({ ...map, [name]: i + 1 }), {}); + +function knexAdapter(client) { + let _client; + + function getClient() { + if (typeof _client === 'undefined') _client = typeof client === 'function' ? client : knex(client); + return _client; + } + + function getExpireAt(expiresIn) { + return expiresIn + ? new Date(Date.now() + expiresIn * 1000) + : undefined; + } + + return class DbAdapter { + constructor(name) { + this.name = name; + this.type = types[name]; + } + + async upsert(id, payload, expiresIn) { + const expiresAt = getExpireAt(expiresIn); + await getClient() + .table(tableName) + .insert({ + id, + type: this.type, + payload: JSON.stringify(payload), + grantId: payload.grantId, + userCode: payload.userCode, + uid: payload.uid, + expiresAt, + }) + .onConflict(['id', 'type']) + .merge(); + } + + get _table() { + return getClient() + .table(tableName) + .where('type', this.type); + } + + _rows(obj) { + return this._table.where(obj); + } + + // eslint-disable-next-line class-methods-use-this + _result(r) { + return r.length > 0 + ? { + ...JSON.parse(r[0].payload), + ...(r[0].consumedAt ? { consumed: true } : undefined), + } + : undefined; + } + + _findBy(obj) { + return this._rows(obj).then(this._result); + } + + find(id) { + return this._findBy({ id }); + } + + findByUserCode(userCode) { + return this._findBy({ userCode }); + } + + findByUid(uid) { + return this._findBy({ uid }); + } + + destroy(id) { + return this._rows({ id }).delete(); + } + + revokeByGrantId(grantId) { + return this._rows({ grantId }).delete(); + } + + consume(id) { + return this._rows({ id }).update({ consumedAt: new Date() }); + } + }; +} + +const defaultConfig = { + client: 'pg', + connection: 'postgresql://', +}; + +const defaultAdapter = knexAdapter(defaultConfig); +defaultAdapter.knexAdapter = knexAdapter; + +module.exports = defaultAdapter; diff --git a/scripts/e2e/oidc-provider/adapters/contributed/sequelize.js b/scripts/e2e/oidc-provider/adapters/contributed/sequelize.js new file mode 100644 index 00000000..29c3a76b --- /dev/null +++ b/scripts/e2e/oidc-provider/adapters/contributed/sequelize.js @@ -0,0 +1,116 @@ +/* + * This is a very rough-edged example, the idea is to still work with the fact that oidc-provider + * has a rather "dynamic" schema. This example uses sequelize with postgresql, and all dynamic data + * uses JSON fields. id is set to be the primary key, grantId should be additionaly indexed for + * models where these fields are set (grantId-able models). userCode should be additionaly indexed + * for DeviceCode model. uid should be additionaly indexed for Session model. For sequelize + * migrations @see https://github.com/Rogger794/node-oidc-provider/tree/examples/example/migrations/sequelize +*/ + +// npm i sequelize@^5.21.2 +const Sequelize = require('sequelize'); // eslint-disable-line import/no-unresolved + +const sequelize = new Sequelize('databaseName', 'username', 'password', { + host: 'databaseHost', + dialect: 'postgres', +}); + +const grantable = new Set([ + 'AccessToken', + 'AuthorizationCode', + 'RefreshToken', + 'DeviceCode', + 'BackchannelAuthenticationRequest', +]); + +const models = [ + 'Session', + 'AccessToken', + 'AuthorizationCode', + 'RefreshToken', + 'DeviceCode', + 'ClientCredentials', + 'Client', + 'InitialAccessToken', + 'RegistrationAccessToken', + 'Interaction', + 'ReplayDetection', + 'PushedAuthorizationRequest', + 'Grant', + 'BackchannelAuthenticationRequest', +].reduce((map, name) => { + map.set(name, sequelize.define(name, { + id: { type: Sequelize.STRING, primaryKey: true }, + ...(grantable.has(name) ? { grantId: { type: Sequelize.STRING } } : undefined), + ...(name === 'DeviceCode' ? { userCode: { type: Sequelize.STRING } } : undefined), + ...(name === 'Session' ? { uid: { type: Sequelize.STRING } } : undefined), + data: { type: Sequelize.JSONB }, + expiresAt: { type: Sequelize.DATE }, + consumedAt: { type: Sequelize.DATE }, + })); + + return map; +}, new Map()); + +class SequelizeAdapter { + constructor(name) { + this.model = models.get(name); + this.name = name; + } + + async upsert(id, data, expiresIn) { + await this.model.upsert({ + id, + data, + ...(data.grantId ? { grantId: data.grantId } : undefined), + ...(data.userCode ? { userCode: data.userCode } : undefined), + ...(data.uid ? { uid: data.uid } : undefined), + ...(expiresIn ? { expiresAt: new Date(Date.now() + (expiresIn * 1000)) } : undefined), + }); + } + + async find(id) { + const found = await this.model.findByPk(id); + if (!found) return undefined; + return { + ...found.data, + ...(found.consumedAt ? { consumed: true } : undefined), + }; + } + + async findByUserCode(userCode) { + const found = await this.model.findOne({ where: { userCode } }); + if (!found) return undefined; + return { + ...found.data, + ...(found.consumedAt ? { consumed: true } : undefined), + }; + } + + async findByUid(uid) { + const found = await this.model.findOne({ where: { uid } }); + if (!found) return undefined; + return { + ...found.data, + ...(found.consumedAt ? { consumed: true } : undefined), + }; + } + + async destroy(id) { + await this.model.destroy({ where: { id } }); + } + + async consume(id) { + await this.model.update({ consumedAt: new Date() }, { where: { id } }); + } + + async revokeByGrantId(grantId) { + await this.model.destroy({ where: { grantId } }); + } + + static async connect() { + return sequelize.sync(); + } +} + +module.exports = SequelizeAdapter; diff --git a/scripts/e2e/oidc-provider/adapters/mongodb.js b/scripts/e2e/oidc-provider/adapters/mongodb.js new file mode 100644 index 00000000..79584892 --- /dev/null +++ b/scripts/e2e/oidc-provider/adapters/mongodb.js @@ -0,0 +1,134 @@ +/* eslint-disable max-classes-per-file */ + +// npm i mongodb@^4.3.0 +const { MongoClient } = require('mongodb'); // eslint-disable-line import/no-unresolved +const snakeCase = require('lodash/snakeCase'); + +let DB; + +const grantable = new Set([ + 'access_token', + 'authorization_code', + 'refresh_token', + 'device_code', + 'backchannel_authentication_request', +]); + +class CollectionSet extends Set { + add(name) { + const nu = this.has(name); + super.add(name); + if (!nu) { + DB.collection(name).createIndexes([ + ...(grantable.has(name) + ? [{ + key: { 'payload.grantId': 1 }, + }] : []), + ...(name === 'device_code' + ? [{ + key: { 'payload.userCode': 1 }, + unique: true, + }] : []), + ...(name === 'session' + ? [{ + key: { 'payload.uid': 1 }, + unique: true, + }] : []), + { + key: { expiresAt: 1 }, + expireAfterSeconds: 0, + }, + ]).catch(console.error); // eslint-disable-line no-console + } + } +} + +const collections = new CollectionSet(); + +class MongoAdapter { + constructor(name) { + this.name = snakeCase(name); + + // NOTE: you should never be creating indexes at runtime in production, the following is in + // place just for demonstration purposes of the indexes required + collections.add(this.name); + } + + // NOTE: the payload for Session model may contain client_id as keys, make sure you do not use + // dots (".") in your client_id value charset. + async upsert(_id, payload, expiresIn) { + let expiresAt; + + if (expiresIn) { + expiresAt = new Date(Date.now() + (expiresIn * 1000)); + } + + await this.coll().updateOne( + { _id }, + { $set: { payload, ...(expiresAt ? { expiresAt } : undefined) } }, + { upsert: true }, + ); + } + + async find(_id) { + const result = await this.coll().find( + { _id }, + { payload: 1 }, + ).limit(1).next(); + + if (!result) return undefined; + return result.payload; + } + + async findByUserCode(userCode) { + const result = await this.coll().find( + { 'payload.userCode': userCode }, + { payload: 1 }, + ).limit(1).next(); + + if (!result) return undefined; + return result.payload; + } + + async findByUid(uid) { + const result = await this.coll().find( + { 'payload.uid': uid }, + { payload: 1 }, + ).limit(1).next(); + + if (!result) return undefined; + return result.payload; + } + + async destroy(_id) { + await this.coll().deleteOne({ _id }); + } + + async revokeByGrantId(grantId) { + await this.coll().deleteMany({ 'payload.grantId': grantId }); + } + + async consume(_id) { + await this.coll().findOneAndUpdate( + { _id }, + { $set: { 'payload.consumed': Math.floor(Date.now() / 1000) } }, + ); + } + + coll(name) { + return this.constructor.coll(name || this.name); + } + + static coll(name) { + return DB.collection(name); + } + + // This is not part of the required or supported API, all initialization should happen before + // you pass the adapter to `new Provider` + static async connect() { + const connection = await MongoClient.connect(process.env.MONGODB_URI); + DB = connection.db(connection.s.options.dbName); + } +} + +module.exports = MongoAdapter; diff --git a/scripts/e2e/oidc-provider/adapters/redis.js b/scripts/e2e/oidc-provider/adapters/redis.js new file mode 100644 index 00000000..1465a278 --- /dev/null +++ b/scripts/e2e/oidc-provider/adapters/redis.js @@ -0,0 +1,128 @@ +// npm i ioredis@^4.0.0 +const Redis = require('ioredis'); // eslint-disable-line import/no-unresolved +const isEmpty = require('lodash/isEmpty'); + +const client = new Redis(process.env.REDIS_URL, { keyPrefix: 'oidc:' }); + +const grantable = new Set([ + 'AccessToken', + 'AuthorizationCode', + 'RefreshToken', + 'DeviceCode', + 'BackchannelAuthenticationRequest', +]); + +const consumable = new Set([ + 'AuthorizationCode', + 'RefreshToken', + 'DeviceCode', + 'BackchannelAuthenticationRequest', +]); + +function grantKeyFor(id) { + return `grant:${id}`; +} + +function userCodeKeyFor(userCode) { + return `userCode:${userCode}`; +} + +function uidKeyFor(uid) { + return `uid:${uid}`; +} + +class RedisAdapter { + constructor(name) { + this.name = name; + } + + async upsert(id, payload, expiresIn) { + const key = this.key(id); + const store = consumable.has(this.name) + ? { payload: JSON.stringify(payload) } : JSON.stringify(payload); + + const multi = client.multi(); + multi[consumable.has(this.name) ? 'hmset' : 'set'](key, store); + + if (expiresIn) { + multi.expire(key, expiresIn); + } + + if (grantable.has(this.name) && payload.grantId) { + const grantKey = grantKeyFor(payload.grantId); + multi.rpush(grantKey, key); + // if you're seeing grant key lists growing out of acceptable proportions consider using LTRIM + // here to trim the list to an appropriate length + const ttl = await client.ttl(grantKey); + if (expiresIn > ttl) { + multi.expire(grantKey, expiresIn); + } + } + + if (payload.userCode) { + const userCodeKey = userCodeKeyFor(payload.userCode); + multi.set(userCodeKey, id); + multi.expire(userCodeKey, expiresIn); + } + + if (payload.uid) { + const uidKey = uidKeyFor(payload.uid); + multi.set(uidKey, id); + multi.expire(uidKey, expiresIn); + } + + await multi.exec(); + } + + async find(id) { + const data = consumable.has(this.name) + ? await client.hgetall(this.key(id)) + : await client.get(this.key(id)); + + if (isEmpty(data)) { + return undefined; + } + + if (typeof data === 'string') { + return JSON.parse(data); + } + const { payload, ...rest } = data; + return { + ...rest, + ...JSON.parse(payload), + }; + } + + async findByUid(uid) { + const id = await client.get(uidKeyFor(uid)); + return this.find(id); + } + + async findByUserCode(userCode) { + const id = await client.get(userCodeKeyFor(userCode)); + return this.find(id); + } + + async destroy(id) { + const key = this.key(id); + await client.del(key); + } + + async revokeByGrantId(grantId) { // eslint-disable-line class-methods-use-this + const multi = client.multi(); + const tokens = await client.lrange(grantKeyFor(grantId), 0, -1); + tokens.forEach((token) => multi.del(token)); + multi.del(grantKeyFor(grantId)); + await multi.exec(); + } + + async consume(id) { + await client.hset(this.key(id), 'consumed', Math.floor(Date.now() / 1000)); + } + + key(id) { + return `${this.name}:${id}`; + } +} + +module.exports = RedisAdapter; diff --git a/scripts/e2e/oidc-provider/adapters/redis_rejson.js b/scripts/e2e/oidc-provider/adapters/redis_rejson.js new file mode 100644 index 00000000..ed24a236 --- /dev/null +++ b/scripts/e2e/oidc-provider/adapters/redis_rejson.js @@ -0,0 +1,111 @@ +/* + * requires Redis ReJSON plugin (https://oss.redislabs.com/rejson/) + */ + +// npm i ioredis@^4.0.0 +const Redis = require('ioredis'); // eslint-disable-line import/no-unresolved + +const client = new Redis(process.env.REDIS_URL); + +const grantable = new Set([ + 'AccessToken', + 'AuthorizationCode', + 'RefreshToken', + 'DeviceCode', + 'BackchannelAuthenticationRequest', +]); + +function grantKeyFor(id) { + return `oidc:grant:${id}`; +} + +function userCodeKeyFor(userCode) { + return `oidc:userCode:${userCode}`; +} + +function uidKeyFor(uid) { + return `oidc:uid:${uid}`; +} + +class RedisAdapter { + constructor(name) { + this.name = name; + } + + async upsert(id, payload, expiresIn) { + const key = this.key(id); + + const multi = client.multi(); + + multi.call('JSON.SET', key, '.', JSON.stringify(payload)); + + if (expiresIn) { + multi.expire(key, expiresIn); + } + + if (grantable.has(this.name) && payload.grantId) { + const grantKey = grantKeyFor(payload.grantId); + multi.rpush(grantKey, key); + // if you're seeing grant key lists growing out of acceptable proportions consider using LTRIM + // here to trim the list to an appropriate length + const ttl = await client.ttl(grantKey); + if (expiresIn > ttl) { + multi.expire(grantKey, expiresIn); + } + } + + if (payload.userCode) { + const userCodeKey = userCodeKeyFor(payload.userCode); + multi.set(userCodeKey, id); + multi.expire(userCodeKey, expiresIn); + } + + if (payload.uid) { + const uidKey = uidKeyFor(payload.uid); + multi.set(uidKey, id); + multi.expire(uidKey, expiresIn); + } + + await multi.exec(); + } + + async find(id) { + const key = this.key(id); + const data = await client.call('JSON.GET', key); + if (!data) return undefined; + return JSON.parse(data); + } + + async findByUid(uid) { + const id = await client.get(uidKeyFor(uid)); + return this.find(id); + } + + async findByUserCode(userCode) { + const id = await client.get(userCodeKeyFor(userCode)); + return this.find(id); + } + + async destroy(id) { + const key = this.key(id); + await client.del(key); + } + + async revokeByGrantId(grantId) { // eslint-disable-line class-methods-use-this + const multi = client.multi(); + const tokens = await client.lrange(grantKeyFor(grantId), 0, -1); + tokens.forEach((token) => multi.del(token)); + multi.del(grantKeyFor(grantId)); + await multi.exec(); + } + + async consume(id) { + await client.call('JSON.SET', this.key(id), 'consumed', Math.floor(Date.now() / 1000)); + } + + key(id) { + return `oidc:${this.name}:${id}`; + } +} + +module.exports = RedisAdapter; diff --git a/scripts/e2e/oidc-provider/express.js b/scripts/e2e/oidc-provider/express.js new file mode 100644 index 00000000..98d5826a --- /dev/null +++ b/scripts/e2e/oidc-provider/express.js @@ -0,0 +1,76 @@ +/* eslint-disable no-console */ + +const path = require('path'); +const url = require('url'); + +const express = require('express'); // eslint-disable-line import/no-unresolved +const helmet = require('helmet'); + +const { Provider } = require('../lib'); // require('oidc-provider'); + +const Account = require('./support/account'); +const configuration = require('./support/configuration'); +const routes = require('./routes/express'); + +const { PORT = 3000, ISSUER = `http://oidc-provider:${PORT}` } = process.env; +// const { PORT = 3000, ISSUER = `http://localhost:${PORT}` } = process.env; +configuration.findAccount = Account.findAccount; + +const app = express(); + +const directives = helmet.contentSecurityPolicy.getDefaultDirectives(); +delete directives['form-action']; +app.use(helmet({ + contentSecurityPolicy: { + useDefaults: false, + directives, + }, +})); + +app.set('views', path.join(__dirname, 'views')); +app.set('view engine', 'ejs'); + +let server; +(async () => { + let adapter; + if (process.env.MONGODB_URI) { + adapter = require('./adapters/mongodb'); // eslint-disable-line global-require + await adapter.connect(); + } + + const prod = process.env.NODE_ENV === 'production'; + + const provider = new Provider(ISSUER, { adapter, ...configuration }); + + if (prod) { + app.enable('trust proxy'); + provider.proxy = true; + + app.use((req, res, next) => { + if (req.secure) { + next(); + } else if (req.method === 'GET' || req.method === 'HEAD') { + res.redirect(url.format({ + protocol: 'https', + host: req.get('host'), + pathname: req.originalUrl, + })); + } else { + res.status(400).json({ + error: 'invalid_request', + error_description: 'do yourself a favor and only use https', + }); + } + }); + } + + routes(app, provider); + app.use(provider.callback()); + server = app.listen(PORT, () => { + console.log(`application is listening on port ${PORT}, check its /.well-known/openid-configuration`); + }); +})().catch((err) => { + if (server && server.listening) server.close(); + console.error(err); + process.exitCode = 1; +}); diff --git a/scripts/e2e/oidc-provider/helpers/defaults.js b/scripts/e2e/oidc-provider/helpers/defaults.js new file mode 100644 index 00000000..5676c4d1 --- /dev/null +++ b/scripts/e2e/oidc-provider/helpers/defaults.js @@ -0,0 +1,2788 @@ +/* eslint-disable no-shadow */ +/* eslint-disable no-unused-vars */ +/* eslint-disable max-len */ + +const crypto = require('crypto'); +const util = require('util'); +const os = require('os'); + +const MemoryAdapter = require('../adapters/memory_adapter'); +const { DEV_KEYSTORE } = require('../consts'); + +const base64url = require('./base64url'); +const attention = require('./attention'); +const nanoid = require('./nanoid'); +const { base: defaultPolicy } = require('./interaction_policy'); +const htmlSafe = require('./html_safe'); +const errors = require('./errors'); + +const randomFill = util.promisify(crypto.randomFill); + +const warned = new Set(); +function shouldChange(name, msg) { + if (!warned.has(name)) { + warned.add(name); + attention.info(`default ${name} function called, you SHOULD change it in order to ${msg}.`); + } +} +function mustChange(name, msg) { + if (!warned.has(name)) { + warned.add(name); + attention.warn(`default ${name} function called, you MUST change it in order to ${msg}.`); + } +} + +function clientBasedCORS(ctx, origin, client) { + mustChange('clientBasedCORS', 'control CORS allowed Origins based on the client making a CORS request'); + return false; +} + +function getCertificate(ctx) { + mustChange('features.mTLS.getCertificate', 'retrieve the PEM-formatted client certificate from the request context'); + throw new Error('features.mTLS.getCertificate function not configured'); +} + +function certificateAuthorized(ctx) { + mustChange('features.mTLS.certificateAuthorized', 'determine if the client certificate is verified and comes from a trusted CA'); + throw new Error('features.mTLS.certificateAuthorized function not configured'); +} + +function certificateSubjectMatches(ctx, property, expected) { + mustChange('features.mTLS.certificateSubjectMatches', 'verify that the tls_client_auth_* registered client property value matches the certificate one'); + throw new Error('features.mTLS.certificateSubjectMatches function not configured'); +} + +function deviceInfo(ctx) { + return { + ip: ctx.ip, + ua: ctx.get('user-agent'), + }; +} + +async function userCodeInputSource(ctx, form, out, err) { + // @param ctx - koa request context + // @param form - form source (id="op.deviceInputForm") to be embedded in the page and submitted + // by the End-User. + // @param out - if an error is returned the out object contains details that are fit to be + // rendered, i.e. does not include internal error messages + // @param err - error object with an optional userCode property passed when the form is being + // re-rendered due to code missing/invalid/expired + shouldChange('features.deviceFlow.userCodeInputSource', 'customize the look of the user code input page'); + let msg; + if (err && (err.userCode || err.name === 'NoCodeError')) { + msg = '

The code you entered is incorrect. Try again

'; + } else if (err && err.name === 'AbortedError') { + msg = '

The Sign-in request was interrupted

'; + } else if (err) { + msg = '

There was an error processing your request

'; + } else { + msg = '

Enter the code displayed on your device

'; + } + ctx.body = ` + + + + Sign-in + + + + + +
+

Sign-in

+ ${msg} + ${form} + +
+ + `; +} + +async function userCodeConfirmSource(ctx, form, client, deviceInfo, userCode) { + // @param ctx - koa request context + // @param form - form source (id="op.deviceConfirmForm") to be embedded in the page and + // submitted by the End-User. + // @param deviceInfo - device information from the device_authorization_endpoint call + // @param userCode - formatted user code by the configured mask + shouldChange('features.deviceFlow.userCodeConfirmSource', 'customize the look of the user code confirmation page'); + const { + clientId, clientName, clientUri, logoUri, policyUri, tosUri, + } = ctx.oidc.client; + ctx.body = ` + + + + Device Login Confirmation + + + + +
+

Confirm Device

+

+ ${clientName || clientId} +

+ The following code should be displayed on your device

+ ${userCode} +

+ If you did not initiate this action, the code does not match or are unaware of such device in your possession please close this window or click abort. +

+ ${form} + +
+ +
+
+ + `; +} + +async function successSource(ctx) { + // @param ctx - koa request context + shouldChange('features.deviceFlow.successSource', 'customize the look of the device code success page'); + const { + clientId, clientName, clientUri, initiateLoginUri, logoUri, policyUri, tosUri, + } = ctx.oidc.client; + ctx.body = ` + + + + Sign-in Success + + + + +
+

Sign-in Success

+

Your sign-in ${clientName ? `with ${clientName}` : ''} was successful, you can now close this page.

+
+ + `; +} + +async function introspectionAllowedPolicy(ctx, client, token) { + shouldChange('features.introspection.allowedPolicy', 'to check whether the caller is authorized to receive the introspection response'); + + if (client.introspectionEndpointAuthMethod === 'none' && token.clientId !== ctx.oidc.client.clientId) { + return false; + } + + return true; +} + +function idFactory(ctx) { + return nanoid(); +} + +async function secretFactory(ctx) { + const bytes = Buffer.allocUnsafe(64); + await randomFill(bytes); + return base64url.encodeBuffer(bytes); +} + +async function defaultResource(ctx, client, oneOf) { + // @param ctx - koa request context + // @param client - client making the request + // @param oneOf {string[]} - The OP needs to select **one** of the values provided. + // Default is that the array is provided so that the request will fail. + // This argument is only provided when called during + // Authorization Code / Refresh Token / Device Code exchanges. + + if (oneOf) return oneOf; + return undefined; +} + +async function useGrantedResource(ctx, model) { + // @param ctx - koa request context + // @param model - depending on the request's grant_type this can be either an AuthorizationCode, BackchannelAuthenticationRequest, + // RefreshToken, or DeviceCode model instance. + return false; +} + +async function getResourceServerInfo(ctx, resourceIndicator, client) { + // @param ctx - koa request context + // @param resourceIndicator - resource indicator value either requested or resolved by the defaultResource helper. + // @param client - client making the request + mustChange('features.resourceIndicators.getResourceServerInfo', 'to provide details about the Resource Server identified by the Resource Indicator'); + throw new errors.InvalidTarget(); +} + +async function extraTokenClaims(ctx, token) { + return undefined; +} + +function httpOptions(url) { + return { + timeout: 2500, + agent: undefined, // defaults to node's global agents (https.globalAgent or http.globalAgent) + lookup: undefined, // defaults to CacheableLookup (https://github.com/szmarczak/cacheable-lookup) + }; +} + +async function expiresWithSession(ctx, token) { + return !token.scopes.has('offline_access'); +} + +async function issueRefreshToken(ctx, client, code) { + return client.grantTypeAllowed('refresh_token') && code.scopes.has('offline_access'); +} + +function pkceRequired(ctx, client) { + return true; +} + +async function pairwiseIdentifier(ctx, accountId, client) { + mustChange('pairwiseIdentifier', 'provide an implementation for pairwise identifiers, the default one uses `os.hostname()` as salt and is therefore not fit for anything else than development'); + return crypto.createHash('sha256') + .update(client.sectorIdentifier) + .update(accountId) + .update(os.hostname()) // put your own unique salt here, or implement other mechanism + .digest('hex'); +} + +function AccessTokenFormat(ctx, token) { + if (token.resourceServer) { + return token.resourceServer.accessTokenFormat || 'opaque'; + } + return 'opaque'; +} + +function ClientCredentialsFormat(ctx, token) { + if (token.resourceServer) { + return token.resourceServer.accessTokenFormat || 'opaque'; + } + return 'opaque'; +} + +function AccessTokenTTL(ctx, token, client) { + shouldChange('ttl.AccessToken', 'define the expiration for AccessToken artifacts'); + if (token.resourceServer) { + return token.resourceServer.accessTokenTTL || 60 * 60; // 1 hour in seconds + } + return 60 * 60; // 1 hour in seconds +} + +function AuthorizationCodeTTL(ctx, code, client) { + return 10 * 60; // 10 minutes in seconds +} + +function ClientCredentialsTTL(ctx, token, client) { + shouldChange('ttl.ClientCredentials', 'define the expiration for ClientCredentials artifacts'); + if (token.resourceServer) { + return token.resourceServer.accessTokenTTL || 10 * 60; // 10 minutes in seconds + } + return 10 * 60; // 10 minutes in seconds +} + +function DeviceCodeTTL(ctx, deviceCode, client) { + shouldChange('ttl.DeviceCode', 'define the expiration for DeviceCode artifacts'); + return 10 * 60; // 10 minutes in seconds +} + +function BackchannelAuthenticationRequestTTL(ctx, request, client) { + shouldChange('ttl.BackchannelAuthenticationRequest', 'define the expiration for BackchannelAuthenticationRequest artifacts'); + if (ctx && ctx.oidc && ctx.oidc.params.requested_expiry) { + return Math.min(10 * 60, +ctx.oidc.params.requested_expiry); // 10 minutes in seconds or requested_expiry, whichever is shorter + } + + return 10 * 60; // 10 minutes in seconds +} + +function IdTokenTTL(ctx, token, client) { + shouldChange('ttl.IdToken', 'define the expiration for IdToken artifacts'); + return 60 * 60; // 1 hour in seconds +} + +function RefreshTokenTTL(ctx, token, client) { + shouldChange('ttl.RefreshToken', 'define the expiration for RefreshToken artifacts'); + if ( + ctx && ctx.oidc.entities.RotatedRefreshToken + && client.applicationType === 'web' + && client.tokenEndpointAuthMethod === 'none' + && !token.isSenderConstrained() + ) { + // Non-Sender Constrained SPA RefreshTokens do not have infinite expiration through rotation + return ctx.oidc.entities.RotatedRefreshToken.remainingTTL; + } + + return 14 * 24 * 60 * 60; // 14 days in seconds +} + +function InteractionTTL(ctx, interaction) { + shouldChange('ttl.Interaction', 'define the expiration for Interaction artifacts'); + return 60 * 60; // 1 hour in seconds +} + +function SessionTTL(ctx, session) { + shouldChange('ttl.Session', 'define the expiration for Session artifacts'); + return 14 * 24 * 60 * 60; // 14 days in seconds +} + +function GrantTTL(ctx, grant, client) { + shouldChange('ttl.Grant', 'define the expiration for Grant artifacts'); + return 14 * 24 * 60 * 60; // 14 days in seconds +} + +function extraClientMetadataValidator(ctx, key, value, metadata) { + // @param ctx - koa request context (only provided when a client is being constructed during + // Client Registration Request or Client Update Request + // @param key - the client metadata property name + // @param value - the property value + // @param metadata - the current accumulated client metadata + // @param ctx - koa request context (only provided when a client is being constructed during + // Client Registration Request or Client Update Request + + // validations for key, value, other related metadata + + // throw new Provider.errors.InvalidClientMetadata() to reject the client metadata + + // metadata[key] = value; to (re)assign metadata values + + // return not necessary, metadata is already a reference +} + +async function postLogoutSuccessSource(ctx) { + // @param ctx - koa request context + shouldChange('features.rpInitiatedLogout.postLogoutSuccessSource', 'customize the look of the default post logout success page'); + const { + clientId, clientName, clientUri, initiateLoginUri, logoUri, policyUri, tosUri, + } = ctx.oidc.client || {}; // client is defined if the user chose to stay logged in with the OP + const display = clientName || clientId; + ctx.body = ` + + + + Sign-out Success + + + + +
+

Sign-out Success

+

Your sign-out ${display ? `with ${display}` : ''} was successful.

+
+ + `; +} + +async function logoutSource(ctx, form) { + // @param ctx - koa request context + // @param form - form source (id="op.logoutForm") to be embedded in the page and submitted by + // the End-User + shouldChange('features.rpInitiatedLogout.logoutSource', 'customize the look of the logout page'); + ctx.body = ` + + + + Logout Request + + + + +
+

Do you want to sign-out from ${ctx.host}?

+ ${form} + + +
+ + `; +} + +async function renderError(ctx, out, error) { + shouldChange('renderError', 'customize the look of the error page'); + ctx.type = 'html'; + ctx.body = ` + + + + oops! something went wrong + + + + +
+

oops! something went wrong

+ ${Object.entries(out).map(([key, value]) => `
${key}: ${htmlSafe(value)}
`).join('')} +
+ + `; +} + +async function interactionsUrl(ctx, interaction) { + return `/interaction/${interaction.uid}`; +} + +async function findAccount(ctx, sub, token) { + // @param ctx - koa request context + // @param sub {string} - account identifier (subject) + // @param token - is a reference to the token used for which a given account is being loaded, + // is undefined in scenarios where claims are returned from authorization endpoint + mustChange('findAccount', 'use your own account model'); + return { + accountId: sub, + // @param use {string} - can either be "id_token" or "userinfo", depending on + // where the specific claims are intended to be put in + // @param scope {string} - the intended scope, while oidc-provider will mask + // claims depending on the scope automatically you might want to skip + // loading some claims from external resources or through db projection etc. based on this + // detail or not return them in ID Tokens but only UserInfo and so on + // @param claims {object} - the part of the claims authorization parameter for either + // "id_token" or "userinfo" (depends on the "use" param) + // @param rejected {Array[String]} - claim names that were rejected by the end-user, you might + // want to skip loading some claims from external resources or through db projection + async claims(use, scope, claims, rejected) { + return { sub }; + }, + }; +} + +function rotateRefreshToken(ctx) { + const { RefreshToken: refreshToken, Client: client } = ctx.oidc.entities; + + // cap the maximum amount of time a refresh token can be + // rotated for up to 1 year, afterwards its TTL is final + if (refreshToken.totalLifetime() >= 365.25 * 24 * 60 * 60) { + return false; + } + + // rotate non sender-constrained public client refresh tokens + if (client.tokenEndpointAuthMethod === 'none' && !refreshToken.isSenderConstrained()) { + return true; + } + + // rotate if the token is nearing expiration (it's beyond 70% of its lifetime) + return refreshToken.ttlPercentagePassed() >= 70; +} + +async function loadExistingGrant(ctx) { + const grantId = (ctx.oidc.result + && ctx.oidc.result.consent + && ctx.oidc.result.consent.grantId) || ctx.oidc.session.grantIdFor(ctx.oidc.client.clientId); + + if (grantId) { + return ctx.oidc.provider.Grant.find(grantId); + } + return undefined; +} + +function revokeGrantPolicy(ctx) { + return true; +} + +function sectorIdentifierUriValidate(client) { + // @param client - the Client instance + return true; +} + +async function processLoginHintToken(ctx, loginHintToken) { + // @param ctx - koa request context + // @param loginHintToken - string value of the login_hint_token parameter + mustChange('features.ciba.processLoginHintToken', 'process the login_hint_token parameter and return the accountId value to use for processsing the request'); + throw new Error('features.ciba.processLoginHintToken not implemented'); +} + +async function processLoginHint(ctx, loginHint) { + // @param ctx - koa request context + // @param loginHint - string value of the login_hint parameter + mustChange('features.ciba.processLoginHint', 'process the login_hint parameter and return the accountId value to use for processsing the request'); + throw new Error('features.ciba.processLoginHint not implemented'); +} + +async function verifyUserCode(ctx, account, userCode) { + // @param ctx - koa request context + // @param account - + // @param userCode - string value of the user_code parameter, when not provided it is undefined + mustChange('features.ciba.verifyUserCode', 'verify the user_code parameter is present when required and verify its value'); + throw new Error('features.ciba.verifyUserCode not implemented'); +} + +async function validateBindingMessage(ctx, bindingMessage) { + // @param ctx - koa request context + // @param bindingMessage - string value of the binding_message parameter, when not provided it is undefined + shouldChange('features.ciba.validateBindingMessage', 'verify the binding_message parameter is present when required and verify its value'); + if (bindingMessage && !/^[a-zA-Z0-9-._+/!?#]{1,20}$/.exec(bindingMessage)) { + throw new errors.InvalidBindingMessage('the binding_message value, when provided, needs to be 1 - 20 characters in length and use only a basic set of characters (matching the regex: ^[a-zA-Z0-9-._+/!?#]{1,20}$ )'); + } +} + +async function validateRequestContext(ctx, requestContext) { + // @param ctx - koa request context + // @param requestContext - string value of the request_context parameter, when not provided it is undefined + mustChange('features.ciba.validateRequestContext', 'verify the request_context parameter is present when required and verify its value'); + throw new Error('features.ciba.validateRequestContext not implemented'); +} + +async function triggerAuthenticationDevice(ctx, request, account, client) { + // @param ctx - koa request context + // @param request - the BackchannelAuthenticationRequest instance + // @param account - the account object retrieved by findAccount + // @param client - the Client instance + mustChange('features.ciba.triggerAuthenticationDevice', "to trigger the authentication and authorization process on end-user's Authentication Device"); + throw new Error('features.ciba.triggerAuthenticationDevice not implemented'); +} + +function getDefaults() { + const defaults = { + + /* + * acrValues + * + * description: Array of strings, the Authentication Context Class References that the OP supports. + */ + acrValues: [], + + /* + * adapter + * + * description: The provided example and any new instance of oidc-provider will use the basic + * in-memory adapter for storing issued tokens, codes, user sessions, dynamically registered + * clients, etc. This is fine as long as you develop, configure and generally just play around + * since every time you restart your process all information will be lost. As soon as you cannot + * live with this limitation you will be required to provide your own custom adapter constructor + * for oidc-provider to use. This constructor will be called for every model accessed the first + * time it is needed. + * The API oidc-provider expects is documented [here](/example/my_adapter.js). + * + * example: MongoDB adapter implementation + * + * See [/example/adapters/mongodb.js](/example/adapters/mongodb.js) + * + * example: Redis adapter implementation + * + * See [/example/adapters/redis.js](/example/adapters/redis.js) + * + * example: Redis w/ ReJSON adapter implementation + * + * See [/example/adapters/redis_rejson.js](/example/adapters/redis_rejson.js) + * + * example: Default in-memory adapter implementation + * + * See [/lib/adapters/memory_adapter.js](/lib/adapters/memory_adapter.js) + * + * @nodefault + */ + adapter: MemoryAdapter, + + /* + * claims + * + * description: Describes the claims that the OpenID Provider MAY be able to supply values for. + * + * It is used to achieve two different things related to claims: + * - which additional claims are available to RPs (configure as `{ claimName: null }`) + * - which claims fall under what scope (configure `{ scopeName: ['claim', 'another-claim'] }`) + * + * example: OpenID Connect 1.0 Standard Claims + * + * See [/recipes/claim_configuration.md](/recipes/claim_configuration.md) + * + */ + claims: { + acr: null, sid: null, auth_time: null, iss: null, openid: ['sub'], + }, + + /* + * clientBasedCORS + * + * description: Function used to check whether a given CORS request should be allowed + * based on the request's client. + * + * example: Client Metadata-based CORS Origin allow list + * + * See [/recipes/client_based_origins.md](/recipes/client_based_origins.md) + */ + clientBasedCORS, + + /* + * clients + * + * description: Array of objects representing client metadata. These clients are referred to as + * static, they don't expire, never reload, are always available. In addition to these + * clients the provider will use your adapter's `find` method when a non-static client_id is + * encountered. If you only wish to support statically configured clients and + * no dynamic registration then make it so that your adapter resolves client find calls with a + * falsy value (e.g. `return Promise.resolve()`) and don't take unnecessary DB trips. + * + * Client's metadata is validated as defined by the respective specification they've been defined + * in. + * + * example: Available Metadata + * + * application_type, client_id, client_name, client_secret, client_uri, contacts, + * default_acr_values, default_max_age, grant_types, id_token_signed_response_alg, + * initiate_login_uri, jwks, jwks_uri, logo_uri, policy_uri, post_logout_redirect_uris, + * redirect_uris, require_auth_time, response_types, scope, sector_identifier_uri, subject_type, + * token_endpoint_auth_method, tos_uri, userinfo_signed_response_alg + * + *

The following metadata is available but may not be recognized depending on your + * provider's configuration.

+ * + * authorization_encrypted_response_alg, authorization_encrypted_response_enc, + * authorization_signed_response_alg, backchannel_logout_session_required, backchannel_logout_uri, + * id_token_encrypted_response_alg, + * id_token_encrypted_response_enc, introspection_encrypted_response_alg, + * introspection_encrypted_response_enc, introspection_endpoint_auth_method, + * introspection_endpoint_auth_signing_alg, introspection_signed_response_alg, + * request_object_encryption_alg, request_object_encryption_enc, request_object_signing_alg, + * request_uris, revocation_endpoint_auth_method, revocation_endpoint_auth_signing_alg, + * tls_client_auth_san_dns, tls_client_auth_san_email, tls_client_auth_san_ip, + * tls_client_auth_san_uri, tls_client_auth_subject_dn, + * tls_client_certificate_bound_access_tokens, token_endpoint_auth_signing_alg, + * userinfo_encrypted_response_alg, userinfo_encrypted_response_enc, web_message_uris + * + */ + clients: [], + + /* + * clientDefaults + * + * description: Default client metadata to be assigned when unspecified by the client metadata, + * e.g. during Dynamic Client Registration or for statically configured clients. The default value + * does not represent all default values, but merely copies its subset. You can provide any used + * client metadata property in this object. + * + * example: Changing the default client token_endpoint_auth_method + * + * To change the default client token_endpoint_auth_method configure `clientDefaults` to be an + * object like so: + * + * ```js + * { + * token_endpoint_auth_method: 'client_secret_post' + * } + * ``` + * example: Changing the default client response type to `code id_token` + * + * To change the default client response_types configure `clientDefaults` to be an + * object like so: + * + * ```js + * { + * response_types: ['code id_token'], + * grant_types: ['authorization_code', 'implicit'], + * } + * ``` + * + */ + clientDefaults: { + grant_types: ['authorization_code'], + id_token_signed_response_alg: 'RS256', + response_types: ['code'], + token_endpoint_auth_method: 'client_secret_basic', + }, + + /* + * clockTolerance + * + * description: A `Number` value (in seconds) describing the allowed system clock skew for + * validating client-provided JWTs, e.g. Request Objects, DPoP Proofs and otherwise comparing + * timestamps + * recommendation: Only set this to a reasonable value when needed to cover server-side client and + * oidc-provider server clock skew. + */ + clockTolerance: 0, + + /* + * conformIdTokenClaims + * + * title: ID Token only contains End-User claims when the requested `response_type` is `id_token` + * + * description: [Core 1.0 - Requesting Claims using Scope Values](https://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims) + * defines that claims requested using the `scope` parameter are only returned from the UserInfo + * Endpoint unless the `response_type` is `id_token`. + * + * Despite of this configuration the ID Token always includes claims requested using the `scope` + * parameter when the userinfo endpoint is disabled, or when issuing an Access Token not applicable + * for access to the userinfo endpoint. + * + */ + conformIdTokenClaims: true, + + /* + * loadExistingGrant + * + * description: Helper function used to load existing but also just in time pre-established Grants + * to attempt to resolve an Authorization Request with. Default: loads a grant based on the + * interaction result `consent.grantId` first, falls back to the existing grantId for the client + * in the current session. + */ + loadExistingGrant, + + /* + * allowOmittingSingleRegisteredRedirectUri + * + * title: Allow omitting the redirect_uri parameter when only a single one is registered for a client. + */ + allowOmittingSingleRegisteredRedirectUri: false, + + /* + * acceptQueryParamAccessTokens + * + * description: Several OAuth 2.0 / OIDC profiles prohibit the use of query strings to carry + * access tokens. This setting either allows (true) or prohibits (false) that mechanism to be + * used. + * + */ + acceptQueryParamAccessTokens: true, + + /* + * cookies + * + * description: Options for the [cookie module](https://github.com/pillarjs/cookies#cookiesset-name--value---options--) + * used to keep track of various User-Agent states. The options `maxAge` and `expires` are ignored. Use `ttl.Session` + * and `ttl.Interaction` to configure the ttl and in turn the cookie expiration values for Session and Interaction + * models. + * @nodefault + */ + cookies: { + /* + * cookies.names + * + * description: Cookie names used to store and transfer various states. + */ + names: { + session: '_session', // used for main session reference + interaction: '_interaction', // used by the interactions for interaction session reference + resume: '_interaction_resume', // used when interactions resume authorization for interaction session reference + }, + + /* + * cookies.long + * + * description: Options for long-term cookies + * recommendation: set cookies.keys and cookies.long.signed = true + */ + long: { + httpOnly: true, // cookies are not readable by client-side javascript + overwrite: true, + sameSite: 'none', + }, + + /* + * cookies.short + * + * description: Options for short-term cookies + * recommendation: set cookies.keys and cookies.short.signed = true + */ + short: { + httpOnly: true, // cookies are not readable by client-side javascript + overwrite: true, + sameSite: 'lax', + }, + + /* + * cookies.keys + * + * description: [Keygrip](https://www.npmjs.com/package/keygrip) Signing keys used for cookie + * signing to prevent tampering. + * recommendation: Rotate regularly (by prepending new keys) with a reasonable interval and keep + * a reasonable history of keys to allow for returning user session cookies to still be valid + * and re-signed + */ + keys: [], + }, + + /* + * discovery + * + * description: Pass additional properties to this object to extend the discovery document + */ + discovery: { + claim_types_supported: ['normal'], + claims_locales_supported: undefined, + display_values_supported: undefined, + op_policy_uri: undefined, + op_tos_uri: undefined, + service_documentation: undefined, + ui_locales_supported: undefined, + }, + + /* + * extraParams + * + * description: Pass an iterable object (i.e. array or Set of strings) to extend the parameters + * recognised by the authorization, device authorization, and pushed authorization request + * endpoints. These parameters are then available in `ctx.oidc.params` as well as passed to + * interaction session details. + */ + extraParams: [], + + /* + * features + * description: Enable/disable features. Some features are still either based on draft or + * experimental RFCs. Enabling those will produce a warning in your console and you must + * be aware that breaking changes may occur between draft implementations and that those + * will be published as minor versions of oidc-provider. See the example below on how to + * acknowledge the specification is a draft (this will remove the warning log) and ensure + * the provider instance will fail to instantiate if a new version of oidc-provider bundles + * newer version of the RFC with breaking changes in it. + * + * example: Acknowledging a draft / experimental feature + * + * ```js + * new Provider('http://localhost:3000', { + * features: { + * backchannelLogout: { + * enabled: true, + * }, + * }, + * }); + * + * // The above code produces this NOTICE + * // NOTICE: The following draft features are enabled and their implemented version not acknowledged + * // NOTICE: - OpenID Connect Back-Channel Logout 1.0 - draft 06 (OIDF AB/Connect Working Group draft. URL: https://openid.net/specs/openid-connect-backchannel-1_0-06.html) + * // NOTICE: Breaking changes between draft version updates may occur and these will be published as MINOR semver oidc-provider updates. + * // NOTICE: You may disable this notice and these potentially breaking updates by acknowledging the current draft version. See https://github.com/panva/node-oidc-provider/tree/v7.3.0/docs/README.md#features + * + * new Provider('http://localhost:3000', { + * features: { + * backchannelLogout: { + * enabled: true, + * ack: 'draft-06', // < we're acknowledging draft 06 of the RFC + * }, + * }, + * }); + * // No more NOTICE, at this point if the draft implementation changed to 07 and contained no breaking + * // changes, you're good to go, still no NOTICE, your code is safe to run. + * + * // Now lets assume you upgrade oidc-provider version and it bundles draft 08 and it contains breaking + * // changes + * new Provider('http://localhost:3000', { + * features: { + * backchannelLogout: { + * enabled: true, + * ack: 'draft-06', // < bundled is draft-08, but we're still acknowledging draft-06 + * }, + * }, + * }); + * // Thrown: + * // Error: An unacknowledged version of a draft feature is included in this oidc-provider version. + * ``` + * @nodefault + */ + features: { + /* + * features.devInteractions + * + * description: Development-ONLY out of the box interaction views bundled with the library allow + * you to skip the boring frontend part while experimenting with oidc-provider. Enter any + * username (will be used as sub claim value) and any password to proceed. + * + * Be sure to disable and replace this feature with your actual frontend flows and End-User + * authentication flows as soon as possible. These views are not meant to ever be seen by actual + * users. + */ + devInteractions: { enabled: true }, + + /* + * features.dPoP + * + * title: [draft-ietf-oauth-dpop-03](https://tools.ietf.org/html/draft-ietf-oauth-dpop-03) - OAuth 2.0 Demonstration of Proof-of-Possession at the Application Layer (DPoP) + * + * description: Enables `DPoP` - mechanism for sender-constraining tokens via a + * proof-of-possession mechanism on the application level. Browser DPoP Proof generation + * [here](https://www.npmjs.com/package/dpop). + * + * recommendation: Updates to draft specification versions are released as MINOR library versions, + * if you utilize these specification implementations consider using the tilde `~` operator + * in your package.json since breaking changes may be introduced as part of these version + * updates. Alternatively, [acknowledge](#features) the version and be notified of breaking + * changes as part of your CI. + */ + dPoP: { enabled: false, iatTolerance: 60, ack: undefined }, + + /* + * features.backchannelLogout + * + * title: [Back-Channel Logout 1.0](https://openid.net/specs/openid-connect-backchannel-1_0-final.html) + * + * description: Enables Back-Channel Logout features. + */ + backchannelLogout: { enabled: false }, + + /* + * features.ciba + * + * title: [OpenID Connect Client Initiated Backchannel Authentication Flow - Core 1.0](https://openid.net/specs/openid-client-initiated-backchannel-authentication-core-1_0-final.html) + * + * description: Enables Core CIBA Flow, when combined with `features.fapi` enables [Financial-grade API: Client Initiated Backchannel Authentication Profile - Implementer's Draft 01](https://openid.net/specs/openid-financial-api-ciba-ID1.html) as well. + * + */ + ciba: { + enabled: false, + + /* + * features.ciba.deliveryModes + * + * description: Fine-tune the supported token delivery modes. Supported values are + * - `poll` + * - `ping` + * + */ + deliveryModes: ['poll'], + + /* + * features.ciba.triggerAuthenticationDevice + * + * description: Helper function used to trigger the authentication and authorization on end-user's Authentication Device. It is called after + * accepting the backchannel authentication request but before sending client back the response. + * + * When the end-user authenticates use `provider.backchannelResult()` to finish the Consumption Device login process. + * + * example: `provider.backchannelResult()` method + * + * `backchannelResult` is a method on the Provider prototype, it returns a `Promise` with no fulfillment value. + * + * ```js + * const provider = new Provider(...); + * await provider.backchannelResult(...); + * ``` + * + * `backchannelResult(request, result[, options]);` + * - `request` BackchannelAuthenticationRequest - BackchannelAuthenticationRequest instance. + * - `result` Grant | OIDCProviderError - instance of a persisted Grant model or an OIDCProviderError (all exported by Provider.errors). + * - `options.acr?`: string - Authentication Context Class Reference value that identifies the Authentication Context Class that the authentication performed satisfied. + * - `options.amr?`: string[] - Identifiers for authentication methods used in the authentication. + * - `options.authTime?`: number - Time when the End-User authentication occurred. + * + */ + triggerAuthenticationDevice, + + /* + * features.ciba.validateBindingMessage + * + * description: Helper function used to process the binding_message parameter and throw if its not following the authorization server's policy. + * + * recommendation: Use `throw Provider.errors.InvalidBindingMessage('validation error message')` when the binding_message is invalid. + * recommendation: Use `return undefined` when a binding_message isn't required and wasn't provided. + * + */ + validateBindingMessage, + + /* + * features.ciba.validateRequestContext + * + * description: Helper function used to process the request_context parameter and throw if its not following the authorization server's policy. + * + * recommendation: Use `throw Provider.errors.InvalidRequest('validation error message')` when the request_context is required by policy and missing or + * invalid. + * recommendation: Use `return undefined` when a request_context isn't required and wasn't provided. + * + */ + validateRequestContext, + + /* + * features.ciba.processLoginHintToken + * + * description: Helper function used to process the login_hint_token parameter and return the accountId value to use for processsing the request. + * + * recommendation: Use `throw Provider.errors.ExpiredLoginHintToken('validation error message')` when login_hint_token is expired. + * recommendation: Use `throw Provider.errors.InvalidRequest('validation error message')` when login_hint_token is invalid. + * recommendation: Use `return undefined` or when you can't determine the accountId from the login_hint. + * + */ + processLoginHintToken, + + /* + * features.ciba.processLoginHint + * + * description: Helper function used to process the login_hint parameter and return the accountId value to use for processsing the request. + * + * recommendation: Use `throw Provider.errors.InvalidRequest('validation error message')` when login_hint is invalid. + * recommendation: Use `return undefined` or when you can't determine the accountId from the login_hint. + * + */ + processLoginHint, + + /* + * features.ciba.verifyUserCode + * + * description: Helper function used to verify the user_code parameter value is present when required and verify its value. + * + * recommendation: Use `throw Provider.errors.MissingUserCode('validation error message')` when user_code should have been provided but wasn't. + * recommendation: Use `throw Provider.errors.InvalidUserCode('validation error message')` when the provided user_code is invalid. + * recommendation: Use `return undefined` when no user_code was provided and isn't required. + * + */ + verifyUserCode, + }, + + /* + * features.mTLS + * + * title: [RFC8705](https://www.rfc-editor.org/rfc/rfc8705.html) - OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound Access Tokens (MTLS) + * + * description: Enables specific features from the Mutual TLS specification. The three main + * features have their own specific setting in this feature's configuration object and + * you must provide functions for resolving some of the functions which are deployment-specific. + * + */ + mTLS: { + enabled: false, + + /* + * features.mTLS.certificateBoundAccessTokens + * + * description: Enables section 3 & 4 Mutual TLS Client Certificate-Bound Tokens by exposing + * the client's `tls_client_certificate_bound_access_tokens` metadata property. + */ + certificateBoundAccessTokens: false, + + /* + * features.mTLS.selfSignedTlsClientAuth + * + * description: Enables section 2.2. Self-Signed Certificate Mutual TLS client authentication + * method `self_signed_tls_client_auth` for use in the server's `tokenEndpointAuthMethods` + * configuration. + */ + selfSignedTlsClientAuth: false, + + /* + * features.mTLS.tlsClientAuth + * + * description: Enables section 2.1. PKI Mutual TLS client authentication method + * `tls_client_auth` for use in the server's `tokenEndpointAuthMethods` + * configuration. + */ + tlsClientAuth: false, + + /* + * features.mTLS.getCertificate + * + * description: Function used to retrieve the PEM-formatted client certificate used + * in the request. + * + * example: When behind a TLS terminating proxy (nginx/apache) + * + * When behind a TLS terminating proxy it is common that the certificate be passed + * to the application as a sanitized header. This returns the chosen header value provided + * by nginx's `$ssl_client_cert` or apache's `%{SSL_CLIENT_CERT}s` + * + * ```js + * function getCertificate(ctx) { + * return ctx.get('x-ssl-client-cert'); + * } + * ``` + * + * example: When using node's `https.createServer` + * + * ```js + * function getCertificate(ctx) { + * const peerCertificate = ctx.socket.getPeerCertificate(); + * if (peerCertificate.raw) { + * return `-----BEGIN CERTIFICATE-----\n${peerCertificate.raw.toString('base64')}\n-----END CERTIFICATE-----`; + * } + * } + * ``` + * + * @nodefault + */ + getCertificate, + + /* + * features.mTLS.certificateAuthorized + * + * description: Function used to determine if the client certificate, used in the + * request, is verified and comes from a trusted CA for the client. Should return true/false. + * Only used for `tls_client_auth` client authentication method. + * + * example: When behind a TLS terminating proxy (nginx/apache) + * + * When behind a TLS terminating proxy it is common that this detail be passed + * to the application as a sanitized header. This returns the chosen header value provided + * by nginx's `$ssl_client_verify` or apache's `%{SSL_CLIENT_VERIFY}s` + * + * ```js + * function certificateAuthorized(ctx) { + * return ctx.get('x-ssl-client-verify') === 'SUCCESS'; + * } + * ``` + * + * example: When using node's `https.createServer` + * + * ```js + * function certificateAuthorized(ctx) { + * return ctx.socket.authorized; + * } + * ``` + * + * @nodefault + */ + certificateAuthorized, + + /* + * features.mTLS.certificateSubjectMatches + * + * description: Function used to determine if the client certificate, used in the + * request, subject matches the registered client property. Only used for `tls_client_auth` + * client authentication method. + * + * example: When behind a TLS terminating proxy (nginx/apache) + * + * TLS terminating proxies can pass a header with the Subject DN pretty easily, for Nginx + * this would be `$ssl_client_s_dn`, for apache `%{SSL_CLIENT_S_DN}s`. + * + * ```js + * function certificateSubjectMatches(ctx, property, expected) { + * switch (property) { + * case 'tls_client_auth_subject_dn': + * return ctx.get('x-ssl-client-s-dn') === expected; + * default: + * throw new Error(`${property} certificate subject matching not implemented`); + * } + * } + * ``` + * + * @nodefault + */ + certificateSubjectMatches, + }, + + /* + * features.claimsParameter + * + * title: [Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter) - Requesting Claims using the "claims" Request Parameter + * + * description: Enables the use and validations of `claims` parameter as described in the + * specification. + * + */ + claimsParameter: { enabled: false }, + + /* + * features.clientCredentials + * + * title: [RFC6749](https://www.rfc-editor.org/rfc/rfc6749.html#section-1.3.4) - Client Credentials + * + * description: Enables `grant_type=client_credentials` to be used on the token endpoint. + */ + clientCredentials: { enabled: false }, + + /* + * features.deviceFlow + * + * title: [RFC8628](https://www.rfc-editor.org/rfc/rfc8628.html) - OAuth 2.0 Device Authorization Grant (Device Flow) + * + * description: Enables Device Authorization Grant + */ + deviceFlow: { + enabled: false, + + /* + * features.deviceFlow.charset + * + * description: alias for a character set of the generated user codes. Supported values are + * - `base-20` uses BCDFGHJKLMNPQRSTVWXZ + * - `digits` uses 0123456789 + */ + charset: 'base-20', + + /* + * features.deviceFlow.mask + * + * description: a string used as a template for the generated user codes, `*` characters will + * be replaced by random chars from the charset, `-`(dash) and ` ` (space) characters may be + * included for readability. See the RFC for details about minimal recommended entropy + */ + mask: '****-****', + + /* + * features.deviceFlow.deviceInfo + * + * description: Function used to extract details from the device authorization endpoint + * request. This is then available during the end-user confirm screen and is supposed to + * aid the user confirm that the particular authorization initiated by the user from a + * device in his possession + */ + deviceInfo, + /* + * features.deviceFlow.userCodeInputSource + * + * description: HTML source rendered when device code feature renders an input prompt for the + * User-Agent. + */ + userCodeInputSource, + + /* + * features.deviceFlow.userCodeConfirmSource + * + * description: HTML source rendered when device code feature renders an a confirmation prompt for + * ther User-Agent. + */ + userCodeConfirmSource, + + /* + * features.deviceFlow.successSource + * + * description: HTML source rendered when device code feature renders a success page for the + * User-Agent. + */ + successSource, + }, + + /* + * features.encryption + * + * description: Enables encryption features such as receiving encrypted UserInfo responses, + * encrypted ID Tokens and allow receiving encrypted Request Objects. + */ + encryption: { enabled: false }, + + /* + * features.fapi + * + * title: Financial-grade API Security Profile + * + * description: Enables extra Authorization Server behaviours defined in FAPI that cannot be + * achieved by other configuration options. + * + * example: other configuration needed to reach FAPI conformance + * + * - `clientDefaults` for setting different default client `token_endpoint_auth_method` + * - `clientDefaults` for setting different default client `id_token_signed_response_alg` + * - `clientDefaults` for setting different default client `response_types` + * - `clientDefaults` for setting client `tls_client_certificate_bound_access_tokens` to true + * - `clientDefaults` for setting client `require_signed_request_object` to true + * - `clientDefaults` for setting client `default_acr_values` to whatever values are set by the specific FAPI ecosystem + * - `features.mTLS` and enable `certificateBoundAccessTokens` + * - `features.mTLS` and enable `selfSignedTlsClientAuth` and/or `tlsClientAuth` + * - `features.claimsParameter` + * - `features.requestObjects` and enable `request` and/or `request_uri` + * - `enabledJWA` algorithm allow lists + * - (optional) `features.pushedAuthorizationRequests` + * - (optional) `features.jwtResponseModes` + + */ + fapi: { + enabled: false, + /* + * features.fapi.profile + * + * description: The specific profile of FAPI to enable. Supported values are: + * + * - '1.0 Final' (default) Enables behaviours from [Financial-grade API Security Profile 1.0 - Part 2: Advanced](https://openid.net/specs/openid-financial-api-part-2-1_0.html) + * - '1.0 ID2' Enables behaviours from [Financial-grade API - Part 2: Read and Write API Security Profile - Implementer's Draft 02](https://openid.net/specs/openid-financial-api-part-2-ID2.html) + * - Function returning one of the other supported values, or undefined if FAPI behaviours are to be ignored. The function is invoked with two arguments `(ctx, client)` and serves the purpose of allowing the used profile to be context-specific. + */ + profile: '1.0 Final', + }, + + /* + * features.rpInitiatedLogout + * + * title: [RP-Initiated Logout 1.0](https://openid.net/specs/openid-connect-rpinitiated-1_0-final.html) + * + * description: Enables RP-Initiated Logout features + */ + rpInitiatedLogout: { + enabled: true, + + /* + * features.rpInitiatedLogout.postLogoutSuccessSource + * + * description: HTML source rendered when RP-Initiated Logout concludes a logout but there + * was no `post_logout_redirect_uri` provided by the client. + */ + postLogoutSuccessSource, + + /* + * features.rpInitiatedLogout.logoutSource + * + * description: HTML source rendered when RP-Initiated Logout renders a confirmation + * prompt for the User-Agent. + */ + logoutSource, + }, + + /* + * features.introspection + * + * title: [RFC7662](https://www.rfc-editor.org/rfc/rfc7662.html) - OAuth 2.0 Token Introspection + * + * description: Enables Token Introspection for: + * - opaque access tokens + * - refresh tokens + * + */ + introspection: { + enabled: false, + + /* + * features.introspection.allowedPolicy + * + * description: Helper function used to determine whether the client/RS (client argument) + * is allowed to introspect the given token (token argument). + */ + allowedPolicy: introspectionAllowedPolicy, + }, + + /* + * features.jwtIntrospection + * + * title: [draft-ietf-oauth-jwt-introspection-response-10](https://tools.ietf.org/html/draft-ietf-oauth-jwt-introspection-response-10) - JWT Response for OAuth Token Introspection + * + * description: Enables JWT responses for Token Introspection features + * + * recommendation: Updates to draft specification versions are released as MINOR library versions, + * if you utilize these specification implementations consider using the tilde `~` operator + * in your package.json since breaking changes may be introduced as part of these version + * updates. Alternatively, [acknowledge](#features) the version and be notified of breaking + * changes as part of your CI. + */ + jwtIntrospection: { enabled: false, ack: undefined }, + + /* + * features.jwtResponseModes + * + * title: [JWT Secured Authorization Response Mode (JARM)](https://openid.net/specs/oauth-v2-jarm.html) + * + * description: Enables JWT Secured Authorization Responses + */ + jwtResponseModes: { enabled: false }, + + /* + * features.pushedAuthorizationRequests + * + * title: [RFC9126](https://www.rfc-editor.org/rfc/rfc9126.html) - OAuth 2.0 Pushed Authorization Requests (PAR) + * + * description: Enables the use of `pushed_authorization_request_endpoint` defined by the Pushed + * Authorization Requests RFC. + */ + pushedAuthorizationRequests: { + enabled: false, + + /* + * features.pushedAuthorizationRequests.requirePushedAuthorizationRequests + * + * description: Makes the use of PAR required for all authorization + * requests as an OP policy. + */ + requirePushedAuthorizationRequests: false, + }, + + /* + * features.registration + * + * title: [Dynamic Client Registration 1.0](https://openid.net/specs/openid-connect-registration-1_0.html) + * + * description: Enables Dynamic Client Registration. + */ + registration: { + enabled: false, + + /* + * features.registration.initialAccessToken + * + * description: Enables registration_endpoint to check a valid initial access token is + * provided as a bearer token during the registration call. Supported types are + * - `string` the string value will be checked as a static initial access token + * - `boolean` true/false to enable/disable adapter backed initial access tokens + * + * example: To add an adapter backed initial access token and retrive its value + * + * ```js + * new (provider.InitialAccessToken)({}).save().then(console.log); + * ``` + */ + initialAccessToken: false, + + /* + * features.registration.policies + * + * description: define registration and registration management policies applied to client + * properties. Policies are sync/async functions that are assigned to an Initial Access + * Token that run before the regular client property validations are run. Multiple policies + * may be assigned to an Initial Access Token and by default the same policies will transfer + * over to the Registration Access Token. A policy may throw / reject and it may modify the + * properties object. + * + * example: To define registration and registration management policies + * + * To define policy functions configure `features.registration` to be an object like so: + * ```js + * { + * enabled: true, + * initialAccessToken: true, // to enable adapter-backed initial access tokens + * policies: { + * 'my-policy': function (ctx, properties) { + * // @param ctx - koa request context + * // @param properties - the client properties which are about to be validated + * + * // example of setting a default + * if (!('client_name' in properties)) { + * properties.client_name = generateRandomClientName(); + * } + * + * // example of forcing a value + * properties.userinfo_signed_response_alg = 'RS256'; + * + * // example of throwing a validation error + * if (someCondition(ctx, properties)) { + * throw new Provider.errors.InvalidClientMetadata('validation error message'); + * } + * }, + * 'my-policy-2': async function (ctx, properties) {}, + * }, + * } + * ``` + * + * An Initial Access Token with those policies being executed (one by one in that order) is + * created like so + * ```js + * new (provider.InitialAccessToken)({ policies: ['my-policy', 'my-policy-2'] }).save().then(console.log); + * ``` + * + * recommendation: referenced policies must always be present when encountered on a token, an AssertionError + * will be thrown inside the request context if it is not, resulting in a 500 Server Error. + * + * recommendation: the same policies will be assigned to the Registration Access Token after a successful + * validation. If you wish to assign different policies to the Registration Access Token + * ```js + * // inside your final ran policy + * ctx.oidc.entities.RegistrationAccessToken.policies = ['update-policy']; + * ``` + */ + policies: undefined, + + /* + * features.registration.idFactory + * + * description: Function used to generate random client identifiers during dynamic + * client registration + */ + idFactory, + + /* + * features.registration.secretFactory + * + * description: Function used to generate random client secrets during dynamic + * client registration + */ + secretFactory, + + /* + * features.registration.issueRegistrationAccessToken + * + * description: Boolean or a function used to decide whether a registration access token will be + * issued or not. Supported + * values are + * - `true` registration access tokens is issued + * - `false` registration access tokens is not issued + * - function returning true/false, true when token should be issued, false when it shouldn't + * + * example: To determine if a registration access token should be issued dynamically + * + * ```js + * // @param ctx - koa request context + * async issueRegistrationAccessToken(ctx) { + * return policyImplementation(ctx) + * } + * ``` + */ + issueRegistrationAccessToken: true, + }, + + /* + * features.registrationManagement + * + * title: [OAuth 2.0 Dynamic Client Registration Management Protocol](https://www.rfc-editor.org/rfc/rfc7592.html) + * + * description: Enables Update and Delete features described in the RFC + */ + registrationManagement: { + enabled: false, + + /* + * features.registrationManagement.rotateRegistrationAccessToken + * + * description: Enables registration access token rotation. The provider will discard the + * current Registration Access Token with a successful update and issue a new one, returning + * it to the client with the Registration Update Response. Supported + * values are + * - `false` registration access tokens are not rotated + * - `true` registration access tokens are rotated when used + * - function returning true/false, true when rotation should occur, false when it shouldn't + * example: function use + * ```js + * { + * features: { + * registrationManagement: { + * enabled: true, + * async rotateRegistrationAccessToken(ctx) { + * // return tokenRecentlyRotated(ctx.oidc.entities.RegistrationAccessToken); + * // or + * // return customClientBasedPolicy(ctx.oidc.entities.Client); + * } + * } + * } + * } + * ``` + */ + rotateRegistrationAccessToken: false, + }, + + /* + * features.resourceIndicators + * + * title: [RFC8707](https://www.rfc-editor.org/rfc/rfc8707.html) - Resource Indicators for OAuth 2.0 + * + * description: Enables the use of `resource` parameter for the authorization and token + * endpoints to enable issuing Access Tokens for Resource Servers (APIs). + * + * - Multiple resource parameters may be present during Authorization Code Flow, + * Device Authorization Grant, and Backchannel Authentication Requests, + * but only a single audience for an Access Token is permitted. + * - Authorization and Authentication Requests that result in an Access Token being issued by the + * Authorization Endpoint must only contain a single resource (or one must be resolved using the + * `defaultResource` helper). + * - Client Credentials grant must only contain a single resource parameter. + * - During Authorization Code / Refresh Token / Device Code / Backchannel Authentication Request + * exchanges, if the exchanged code/token does not include the `'openid'` scope and only has a single + * resource then the resource parameter may be omitted - an Access Token for the single resource is + * returned. + * - During Authorization Code / Refresh Token / Device Code / Backchannel Authentication Request + * exchanges, if the exchanged code/token does not include the `'openid'` scope and has multiple + * resources then the resource parameter must be provided (or one must be resolved using the + * `defaultResource` helper). + * An Access Token for the provided/resolved resource is returned. + * - (with userinfo endpoint enabled and useGrantedResource helper returning falsy) + * During Authorization Code / Refresh Token / Device Code + * exchanges, if the exchanged code/token includes the `'openid'` scope and no resource + * parameter is present - an Access Token for the UserInfo Endpoint is returned. + * - (with userinfo endpoint enabled and useGrantedResource helper returning truthy) + * During Authorization Code / Refresh Token / Device Code + * exchanges, even if the exchanged code/token includes the `'openid'` scope and only has a single + * resource then the resource parameter may be omitted - an Access Token for the single resource + * is returned. + * - (with userinfo endpoint disabled) During Authorization Code / Refresh Token / Device Code + * exchanges, if the exchanged code/token includes the `'openid'` scope and only has a single + * resource then the resource parameter may be omitted - an Access Token for the single resource + * is returned. + * - Issued Access Tokens always only contain scopes that are defined on the respective Resource + * Server (returned from `features.resourceIndicators.getResourceServerInfo`). + */ + resourceIndicators: { + enabled: true, + + /* + * features.resourceIndicators.defaultResource + * + * description: Function used to determine the default resource indicator for a request + * when none is provided by the client during the authorization request or when multiple + * are provided/resolved and only a single one is required during an Access Token Request. + */ + defaultResource, + + /* + * features.resourceIndicators.useGrantedResource + * + * description: Function used to determine if an already granted resource indicator + * should be used without being explicitly requested by the client during the Token Endpoint + * request. + * + * recommendation: Use `return true` when it's allowed for a client skip providing the "resource" + * parameter at the Token Endpoint. + * recommendation: Use `return false` (default) when it's required for a client to explitly + * provide a "resource" parameter at the Token Endpoint or when other indication + * dictates an Access Token for the UserInfo Endpoint should returned. + */ + useGrantedResource, + + /* + * features.resourceIndicators.getResourceServerInfo + * + * description: Function used to load information about a Resource Server (API) and check if the + * client is meant to request scopes for that particular resource. + * + * recommendation: Only allow client's pre-registered resource values, to pre-register these + * you shall use the `extraClientMetadata` configuration option to define a custom metadata + * and use that to implement your policy using this function. + * + * example: Resource Server (API) with two scopes, an expected audience value, an Access Token TTL and a JWT Access Token Format. + * ```js + * { + * scope: 'api:read api:write', + * audience: 'resource-server-audience-value', + * accessTokenTTL: 2 * 60 * 60, // 2 hours + * accessTokenFormat: 'jwt', + * jwt: { + * sign: { alg: 'ES256' }, + * }, + * } + * ``` + * + * example: Resource Server (API) with two scopes and a symmetrically encrypted JWT Access Token Format. + * ```js + * { + * scope: 'api:read api:write', + * accessTokenFormat: 'jwt', + * jwt: { + * sign: false, + * encrypt: { + * alg: 'dir', + * enc: 'A128CBC-HS256', + * key: Buffer.from('f40dd9591646bebcb9c32aed02f5e610c2d15e1d38cde0c1fe14a55cf6bfe2d9', 'hex') + * }, + * } + * } + * ``` + * + * example: Resource Server (API) with two scopes and a v1.local PASETO Access Token Format. + * ```js + * { + * scope: 'api:read api:write', + * accessTokenFormat: 'paseto', + * paseto: { + * version: 1, + * purpose: 'local', + * key: Buffer.from('f40dd9591646bebcb9c32aed02f5e610c2d15e1d38cde0c1fe14a55cf6bfe2d9', 'hex') + * } + * } + * ``` + * + * example: Resource Server Definition + * ```js + * { + * // REQUIRED + * // available scope values (space-delimited string) + * scope: string, + * + * // OPTIONAL + * // "aud" (Audience) value to use + * // Default is the resource indicator value will be used as token audience + * audience?: string, + * + * // OPTIONAL + * // Issued Token TTL + * // Default is - see `ttl` configuration + * accessTokenTTL?: number, + * + * // Issued Token Format + * // Default is - opaque + * accessTokenFormat?: 'opaque' | 'jwt' | 'paseto', + * + * // JWT Access Token Format (when accessTokenFormat is 'jwt') + * // Default is `{ sign: { alg: 'RS256' }, encrypt: false }` + * // Tokens may be signed, signed and then encrypted, or just encrypted JWTs. + * jwt?: { + * // Tokens will be signed + * sign?: + * | { + * alg?: string, // 'PS256' | 'PS384' | 'PS512' | 'ES256' | 'ES256K' | 'ES384' | 'ES512' | 'EdDSA' | 'RS256' | 'RS384' | 'RS512' + * kid?: string, // OPTIONAL `kid` to aid in signing key selection + * } + * | { + * alg: string, // 'HS256' | 'HS384' | 'HS512' + * key: crypto.KeyObject | Buffer, // shared symmetric secret to sign the JWT token with + * kid?: string, // OPTIONAL `kid` JOSE Header Parameter to put in the token's JWS Header + * }, + * // Tokens will be encrypted + * encrypt?: { + * alg: string, // 'dir' | 'RSA-OAEP' | 'RSA-OAEP-256' | 'RSA-OAEP-384' | 'RSA-OAEP-512' | 'RSA1_5' | 'ECDH-ES' | 'ECDH-ES+A128KW' | 'ECDH-ES+A192KW' | 'ECDH-ES+A256KW' | 'A128KW' | 'A192KW' | 'A256KW' | 'A128GCMKW' | 'A192GCMKW' | 'A256GCMKW' | 'PBES2-HS256+A128KW' | 'PBES2-HS384+A192KW' | 'PBES2-HS512+A256KW' + * enc: string, // 'A128CBC-HS256' | 'A128GCM' | 'A192CBC-HS384' | 'A192GCM' | 'A256CBC-HS512' | 'A256GCM' + * key: crypto.KeyObject | Buffer, // public key or shared symmetric secret to encrypt the JWT token with + * kid?: string, // OPTIONAL `kid` JOSE Header Parameter to put in the token's JWE Header + * } + * } + * + * // PASETO Access Token Format (when accessTokenFormat is 'paseto') + * // Note: v2.local and v4.local are NOT supported + * paseto?: { + * version: 1 | 2 | 3 | 4, + * purpose: 'local' | 'public', + * key?: crypto.KeyObject, // required when purpose is 'local' + * kid?: string, // OPTIONAL `kid` to aid in signing key selection or to put in the footer for 'local' + * } + * } + * ``` + */ + getResourceServerInfo, + }, + + /* + * features.requestObjects + * + * title: [Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#RequestObject) and [JWT Secured Authorization Request (JAR)](https://www.rfc-editor.org/rfc/rfc9101.html) - Request Object + * + * description: Enables the use and validations of the `request` and/or `request_uri` + * parameters. + */ + requestObjects: { + + /* + * features.requestObjects.request + * + * description: Enables the use and validations of the `request` parameter. + */ + request: false, + + /* + * features.requestObjects.requestUri + * + * description: Enables the use and validations of the `request_uri` parameter. + */ + requestUri: true, + + /* + * features.requestObjects.requireUriRegistration + * + * description: Makes request_uri pre-registration mandatory (true) or optional (false). + */ + requireUriRegistration: true, + + /* + * features.requestObjects.requireSignedRequestObject + * + * description: Makes the use of signed request objects required for all authorization + * requests as an OP policy. + */ + requireSignedRequestObject: false, + + /* + * features.requestObjects.mode + * + * description: defines the provider's strategy when it comes to using regular OAuth 2.0 + * parameters that are present. Parameters inside the Request Object are ALWAYS used, + * this option controls whether to combine those with the regular ones or not. + * + * Supported values are: + * + * - 'lax' (default) This is the behaviour expected by OIDC Core 1.0 - all parameters that + * are not present in the Resource Object are used when resolving the authorization + * request. + * - 'strict' This is the behaviour expected by FAPI or JAR, all parameters outside of the + * Request Object are ignored. For FAPI and FAPI-CIBA this value is enforced. + * + */ + mode: 'lax', + }, + + /* + * features.revocation + * + * title: [RFC7009](https://www.rfc-editor.org/rfc/rfc7009.html) - OAuth 2.0 Token Revocation + * + * description: Enables Token Revocation for: + * - opaque access tokens + * - refresh tokens + * + */ + revocation: { enabled: false }, + + /* + * features.userinfo + * + * title: [Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#UserInfo) - UserInfo Endpoint + * + * description: Enables the userinfo endpoint. Its use requires an opaque Access Token with at least + * `openid` scope that's without a Resource Server audience. + */ + userinfo: { enabled: true }, + + /* + * features.jwtUserinfo + * + * title: [Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#UserInfo) - JWT UserInfo Endpoint Responses + * + * description: Enables the userinfo to optionally return signed and/or encrypted JWTs, also + * enables the relevant client metadata for setting up signing and/or encryption. + */ + jwtUserinfo: { enabled: false }, + + /* + * features.webMessageResponseMode + * + * title: [draft-sakimura-oauth-wmrm-00](https://tools.ietf.org/html/draft-sakimura-oauth-wmrm-00) - OAuth 2.0 Web Message Response Mode + * + * description: Enables `web_message` response mode. + * + * recommendation: Although a general advise to use a `helmet` ([express](https://www.npmjs.com/package/helmet), + * [koa](https://www.npmjs.com/package/koa-helmet)) it is especially advised for your interaction + * views routes if Web Message Response Mode is enabled in your deployment. + * + * recommendation: Updates to draft specification versions are released as MINOR library versions, + * if you utilize these specification implementations consider using the tilde `~` operator + * in your package.json since breaking changes may be introduced as part of these version + * updates. Alternatively, [acknowledge](#features) the version and be notified of breaking + * changes as part of your CI. + * + * @skip + */ + webMessageResponseMode: { enabled: false, ack: undefined }, + }, + + /* + * extraTokenClaims + * + * description: Function used to assign additional claims to an Access Token + * when it is being issued. For `opaque` Access Tokens these claims will be stored + * in your storage under the `extra` property and returned by introspection as top + * level claims. For `jwt` or `paseto` Access Tokens these will be top level claims. + * Returned claims will not overwrite pre-existing top level claims. + * + * example: To push additional claims to an Access Token + * ```js + * { + * extraTokenClaims(ctx, token) { + * return { + * 'urn:oidc-provider:example:foo': 'bar', + * }; + * } + * } + * ``` + */ + extraTokenClaims, + + /* + * formats + * + * description: This option allows to configure the token value format. The different + * values change how a client-facing token value is generated and also if the token + * is stored using the adapter or not. The use of JWT or PASETO formats also requires + * use of Resource Indicators. In earlier version of oidc-provider the formats.AccessToken + * and formats.ClientCredentials configuration might've been used but in v7.x there's no + * need to change their default value because they default to use the `accessTokenFormat` + * from a Resource Server, that's where you should tell the Authorization Server to + * issue a token in a certain format. + * + * Supported formats are: + * - `opaque` (default) tokens are PRNG generated random strings using url safe base64 alphabet. + * See `formats.bitsOfOpaqueRandomness` for influencing the token length. Tokens are stored + * using the adapter. + * - `jwt` tokens are issued as JWTs. Tokens using this format are not stored using the adapter, + * they cannot be introspected at the introspection_endpoint and they cannot be used to access + * the userinfo_endpoint. Tokens issued in this format MUST have an audience/indicated resource. + * - `paseto` tokens are issued as PASETOs. Tokens using this format are not stored using the adapter, + * they cannot be introspected at the introspection_endpoint and they cannot be used to access + * the userinfo_endpoint. Tokens issued in this format MUST have an audience/indicated resource. + * + * @skip + */ + formats: { + /* + * formats.bitsOfOpaqueRandomness + * + * description: The value should be an integer (or a function returning an integer) and the + * resulting opaque token length is equal to `Math.ceil(i / Math.log2(n))` where n is the + * number of symbols in the used alphabet, 64 in our case. + * + * example: To have e.g. Refresh Tokens values longer than Access Tokens. + * ```js + * function bitsOfOpaqueRandomness(ctx, token) { + * if (token.kind === 'RefreshToken') { + * return 384; + * } + * + * return 256; + * } + * ``` + */ + bitsOfOpaqueRandomness: 256, + AccessToken: AccessTokenFormat, + ClientCredentials: ClientCredentialsFormat, + + /* + * formats.customizers + * + * description: Customizer functions used before issuing a structured Access Token. + * + * example: To push additional headers and payload claims to a `jwt` format Access Token + * ```js + * { + * customizers: { + * async jwt(ctx, token, jwt) { + * jwt.header = { foo: 'bar' }; + * jwt.payload.foo = 'bar'; + * } + * } + * } + * ``` + * + * example: To push a payload, a footer, and use an implicit assertion with a PASETO structured access token + * ```js + * { + * customizers: { + * paseto(ctx, token, structuredToken) { + * structuredToken.payload.foo = 'bar'; + * structuredToken.footer = { foo: 'bar' }; + * structuredToken.assertion = 'foo'; // v3 and v4 tokens only + * } + * } + * } + * ``` + */ + customizers: { + jwt: undefined, + paseto: undefined, + }, + }, + + /* + * httpOptions + * + * description: Function called whenever calls to an external HTTP(S) resource are being made. + * You can change the request `timeout` duration, the `agent` used as well as the `lookup` + * resolver function. + * + * example: To change the request's timeout + * + * To change all request's timeout configure the httpOptions as a function like so: + * + * ```js + * { + * httpOptions(url) { + * return { timeout: 5000 }; + * } + * } + * ``` + */ + httpOptions, + + /* + * expiresWithSession + * description: Function used to decide whether the given authorization code/ device code + * or implicit returned access token be bound to the user session. This will be applied to all + * tokens issued from the authorization / device code in the future. When tokens are session-bound + * the session will be loaded by its `uid` every time the token is encountered. Session bound + * tokens will effectively get revoked if the end-user logs out. + */ + expiresWithSession, + + /* + * issueRefreshToken + * + * description: Function used to decide whether a refresh token will be issued or not + * + * example: To always issue a refresh tokens ... + * ... if a client has the grant allowed and scope includes offline_access or the client is a + * public web client doing code flow. Configure `issueRefreshToken` like so + * + * ```js + * async issueRefreshToken(ctx, client, code) { + * if (!client.grantTypeAllowed('refresh_token')) { + * return false; + * } + * + * return code.scopes.has('offline_access') || (client.applicationType === 'web' && client.tokenEndpointAuthMethod === 'none'); + * } + * ``` + */ + issueRefreshToken, + + /* + * jwks + * + * description: JSON Web Key Set used by the provider for signing and decryption. The object must + * be in [JWK Set format](https://www.rfc-editor.org/rfc/rfc7517.html#section-5). All provided keys must + * be private keys. + * + * Supported key types are: + * + * - RSA + * - OKP (Ed25519, Ed448, X25519, X448 sub types) + * - EC (P-256, secp256k1, P-384, and P-521 curves) + * + * recommendation: Be sure to follow best practices for distributing private keying material and secrets + * for your respective target deployment environment. + * + * recommendation: The following action order is recommended when rotating signing keys on a distributed + * deployment with rolling reloads in place. + * + * 1. push new keys at the very end of the "keys" array in your JWKS, this means the keys will become + * available for verification should they be encountered but not yet used for signing + * 2. reload all your processes + * 3. move your new key to the very front of the "keys" array in your JWKS, this means the key will be + * used for signing after reload + * 4. reload all your processes + * + * @nodefault + * + */ + jwks: JSON.parse(JSON.stringify(DEV_KEYSTORE)), + + /* + * responseTypes + * + * description: Array of response_type values that the OP supports. The default omits all response + * types that result in access tokens being issued by the authorization endpoint directly as per + * [OAuth 2.0 Security Best Current Practice](https://tools.ietf.org/html/draft-ietf-oauth-security-topics-13#section-3.1.2) + * You can still enable them if you need to. + * + * example: Supported values list + * These are values defined in [Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#Authentication) + * and [OAuth 2.0 Multiple Response Type Encoding Practices](https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html) + * ```js + * [ + * 'code', + * 'id_token', 'id_token token', + * 'code id_token', 'code token', 'code id_token token', + * 'none', + * ] + * ``` + */ + responseTypes: [ + 'code id_token', + 'code', + 'id_token', + 'none', + ], + + /* + * pkce + * title: [RFC7636 - Proof Key for Code Exchange (PKCE)](https://www.rfc-editor.org/rfc/rfc7636.html) + * description: PKCE configuration such as available methods and policy check on required use of + * PKCE + * @nodefault + */ + pkce: { + /* + * pkce.methods + * + * description: Fine-tune the supported code challenge methods. Supported values are + * - `S256` + * - `plain` + */ + methods: ['S256'], + + /* + * pkce.required + * + * description: Configures if and when the OP requires clients to use PKCE. This helper is called + * whenever an authorization request lacks the code_challenge parameter. + * Return + * - `false` to allow the request to continue without PKCE + * - `true` to abort the request + */ + required: pkceRequired, + }, + + /* + * routes + * + * description: Routing values used by the OP. Only provide routes starting with "/" + */ + routes: { + authorization: '/auth', + backchannel_authentication: '/backchannel', + code_verification: '/device', + device_authorization: '/device/auth', + end_session: '/session/end', + introspection: '/token/introspection', + jwks: '/jwks', + pushed_authorization_request: '/request', + registration: '/reg', + revocation: '/token/revocation', + token: '/token', + userinfo: '/me', + }, + + /* + * scopes + * + * description: Array of additional scope values that the OP signals to support in the discovery + * endpoint. Only add scopes the OP has a corresponding resource for. + * Resource Server scopes don't belong here, see `features.resourceIndicators` for configuring + * those. + */ + scopes: ['openid', 'offline_access'], + + /* + * subjectTypes + * + * description: Array of the Subject Identifier types that this OP supports. When only `pairwise` + * is supported it becomes the default `subject_type` client metadata value. Valid types are + * - `public` + * - `pairwise` + */ + subjectTypes: ['public'], + + /* + * pairwiseIdentifier + * + * description: Function used by the OP when resolving pairwise ID Token and Userinfo sub claim + * values. See [Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#PairwiseAlg) + * recommendation: Since this might be called several times in one request with the same arguments + * consider using memoization or otherwise caching the result based on account and client + * ids. + */ + pairwiseIdentifier, + + /* + * tokenEndpointAuthMethods + * + * description: Array of Client Authentication methods supported by this OP's Token Endpoint + * example: Supported values list + * ```js + * [ + * 'none', + * 'client_secret_basic', 'client_secret_post', + * 'client_secret_jwt', 'private_key_jwt', + * 'tls_client_auth', 'self_signed_tls_client_auth', // these methods are only available when features.mTLS is configured + * ] + * ``` + */ + tokenEndpointAuthMethods: [ + 'client_secret_basic', + 'client_secret_jwt', + 'client_secret_post', + 'private_key_jwt', + 'none', + ], + + /* + * ttl + * + * description: description: Expirations for various token and session types. + * The value can be a number (in seconds) or a synchronous function that dynamically returns + * value based on the context. + * + * recommendation: Do not set token TTLs longer then they absolutely have to be, the shorter + * the TTL, the better. + * + * recommendation: Rather than setting crazy high Refresh Token TTL look into `rotateRefreshToken` + * configuration option which is set up in way that when refresh tokens are regularly used they + * will have their TTL refreshed (via rotation). This is inline with the + * [OAuth 2.0 Security Best Current Practice](https://tools.ietf.org/html/draft-ietf-oauth-security-topics-13) + * + * example: To resolve a ttl on runtime for each new token + * Configure `ttl` for a given token type with a function like so, this must return a value, not a + * Promise. + * + * ```js + * { + * ttl: { + * AccessToken(ctx, token, client) { + * // return a Number (in seconds) for the given token (first argument), the associated client is + * // passed as a second argument + * // Tip: if the values are entirely client based memoize the results + * return resolveTTLfor(token, client); + * }, + * }, + * } + * ``` + */ + ttl: { + AccessToken: AccessTokenTTL, + AuthorizationCode: AuthorizationCodeTTL, + BackchannelAuthenticationRequest: BackchannelAuthenticationRequestTTL, + ClientCredentials: ClientCredentialsTTL, + DeviceCode: DeviceCodeTTL, + Grant: GrantTTL, + IdToken: IdTokenTTL, + Interaction: InteractionTTL, + RefreshToken: RefreshTokenTTL, + Session: SessionTTL, + }, + + /* + * extraClientMetadata + * + * description: Allows for custom client metadata to be defined, validated, manipulated as well as + * for existing property validations to be extended. Existing properties are snakeCased on + * a Client instance (e.g. `client.redirectUris`), new properties (defined by this + * configuration) will be avaialable with their names verbatim (e.g. + * `client['urn:example:client:my-property']`) + * @nodefault + */ + extraClientMetadata: { + /* + * extraClientMetadata.properties + * + * description: Array of property names that clients will be allowed to have defined. + */ + properties: [], + /* + * extraClientMetadata.validator + * + * description: validator function that will be executed in order once for every property + * defined in `extraClientMetadata.properties`, regardless of its value or presence on the + * client metadata passed in. Must be synchronous, async validators or functions returning + * Promise will be rejected during runtime. To modify the current client metadata values (for + * current key or any other) just modify the passed in `metadata` argument. + */ + validator: extraClientMetadataValidator, + }, + + /* + * renderError + * + * description: Function used to present errors to the User-Agent + */ + renderError, + + /* + * revokeGrantPolicy + * + * description: Function called in a number of different context to determine whether + * an underlying Grant entry should also be revoked or not. + * + * contexts: + * - RP-Initiated Logout + * - Refresh Token Revocation + * - Authorization Code re-use + * - Device Code re-use + * - Backchannel Authentication Request re-use + * - Rotated Refresh Token re-use + */ + revokeGrantPolicy, + + /* + * sectorIdentifierUriValidate + * + * description: Function called to make a decision about whether sectorIdentifierUri of + * a client being loaded, registered, or updated should be fetched and its contents + * validated against the client metadata. + */ + sectorIdentifierUriValidate, + + /* + * interactions + * + * description: Holds the configuration for interaction policy and url to send end-users to + * when the policy decides to require interaction. + * + * @nodefault + */ + interactions: { + /* + * interactions.policy + * + * description: structure of Prompts and their checks formed by Prompt and Check class instances. + * The default you can get a fresh instance for and the classes are available under + * `Provider.interactionPolicy`. + * + * example: default interaction policy description + * + * The default interaction policy consists of two available prompts, login and consent + * + *

+ * + * - `login` does the following checks: + * - no_session - checks that there's an established session, an authenticated end-user + * - max_age - processes the max_age parameter (when the session's auth_time is too old it requires login) + * - id_token_hint - processes the id_token_hint parameter (when the end-user sub differs it requires login) + * - claims_id_token_sub_value - processes the claims parameter `sub` (when the `claims` parameter requested sub differs it requires login) + * - essential_acrs - processes the claims parameter `acr` (when the current acr is not amongst the `claims` parameter essential `acr.values` it requires login) + * - essential_acr - processes the claims parameter `acr` (when the current acr is not equal to the `claims` parameter essential `acr.value` it requires login) + * + *

+ * + * - `consent` does the following checks: + * - native_client_prompt - native clients always require re-consent + * - op_scopes_missing - requires consent when the requested scope includes scope values previously not requested + * - op_claims_missing - requires consent when the requested claims parameter includes claims previously not requested + * - rs_scopes_missing - requires consent when the requested resource indicated scope values include scopes previously not requested + * + *

+ * + * These checks are the best practice for various privacy and security reasons. + * + * example: disabling default consent checks + * + * You may be required to skip (silently accept) some of the consent checks, while it is + * discouraged there are valid reasons to do that, for instance in some first-party scenarios or + * going with pre-existing, previously granted, consents. To simply silenty "accept" + * first-party/resource indicated scopes or pre-agreed upon claims use the `loadExistingGrant` + * configuration helper function, in there you may just instantiate (and save!) a grant for the + * current clientId and accountId values. + * + * example: modifying the default interaction policy + * ```js + * const { interactionPolicy: { Prompt, Check, base } } = require('oidc-provider'); + * + * const basePolicy = base() + * + * // basePolicy.get(name) => returns a Prompt instance by its name + * // basePolicy.remove(name) => removes a Prompt instance by its name + * // basePolicy.add(prompt, index) => adds a Prompt instance to a specific index, default is add the prompt as the last one + * + * // prompt.checks.get(reason) => returns a Check instance by its reason + * // prompt.checks.remove(reason) => removes a Check instance by its reason + * // prompt.checks.add(check, index) => adds a Check instance to a specific index, default is add the check as the last one + * ``` + */ + policy: defaultPolicy(), + + /* + * interactions.url + * + * description: Function used to determine where to redirect User-Agent for necessary + * interaction, can return both absolute and relative urls. + */ + url: interactionsUrl, + }, + + /* + * findAccount + * + * description: Function used to load an account and retrieve its available claims. The + * return value should be a Promise and #claims() can return a Promise too + */ + findAccount, + + /* + * rotateRefreshToken + * + * description: Configures if and how the OP rotates refresh tokens after they are used. Supported + * values are + * - `false` refresh tokens are not rotated and their initial expiration date is final + * - `true` refresh tokens are rotated when used, current token is marked as + * consumed and new one is issued with new TTL, when a consumed refresh token is + * encountered an error is returned instead and the whole token chain (grant) is revoked + * - `function` returning true/false, true when rotation should occur, false when it shouldn't + * + *

+ * + * The default configuration value puts forth a sensible refresh token rotation policy + * - only allows refresh tokens to be rotated (have their TTL prolonged by issuing a new one) for one year + * - otherwise always rotate public client tokens that are not sender-constrained + * - otherwise only rotate tokens if they're being used close to their expiration (>= 70% TTL passed) + */ + rotateRefreshToken, + + /* + * enabledJWA + * + * description: Fine-tune the algorithms your provider will support by declaring algorithm + * values for each respective JWA use + * recommendation: Only allow JWA algs that are necessary. The current defaults are based on + * recommendations from the [JWA specification](https://www.rfc-editor.org/rfc/rfc7518.html) + enables + * RSASSA-PSS based on current guidance in FAPI. "none" JWT algs are disabled by default but + * available if you need them. + * @nodefault + */ + enabledJWA: { + + /* + * enabledJWA.tokenEndpointAuthSigningAlgValues + * + * description: JWS "alg" Algorithm values the provider supports for signed JWT Client Authentication + * + * example: Supported values list + * ```js + * [ + * 'RS256', 'RS384', 'RS512', + * 'PS256', 'PS384', 'PS512', + * 'ES256', 'ES256K', 'ES384', 'ES512', + * 'EdDSA', + * 'HS256', 'HS384', 'HS512', + * ] + * ``` + */ + tokenEndpointAuthSigningAlgValues: [ + 'HS256', 'RS256', 'PS256', 'ES256', 'EdDSA', + ], + + /* + * enabledJWA.introspectionEndpointAuthSigningAlgValues + * + * description: JWS "alg" Algorithm values the provider supports for signed JWT Client Authentication on the introspection endpoint + * + * @skip + * + * example: Supported values list + * ```js + * [ + * 'RS256', 'RS384', 'RS512', + * 'PS256', 'PS384', 'PS512', + * 'ES256', 'ES256K', 'ES384', 'ES512', + * 'EdDSA', + * 'HS256', 'HS384', 'HS512', + * ] + * ``` + */ + introspectionEndpointAuthSigningAlgValues: [ + 'HS256', 'RS256', 'PS256', 'ES256', 'EdDSA', + ], + + /* + * enabledJWA.revocationEndpointAuthSigningAlgValues + * + * description: JWS "alg" Algorithm values the provider supports for signed JWT Client Authentication on the revocation endpoint + * + * @skip + * + * example: Supported values list + * ```js + * [ + * 'RS256', 'RS384', 'RS512', + * 'PS256', 'PS384', 'PS512', + * 'ES256', 'ES256K', 'ES384', 'ES512', + * 'EdDSA', + * 'HS256', 'HS384', 'HS512', + * ] + * ``` + */ + revocationEndpointAuthSigningAlgValues: [ + 'HS256', 'RS256', 'PS256', 'ES256', 'EdDSA', + ], + + /* + * enabledJWA.idTokenSigningAlgValues + * + * description: JWS "alg" Algorithm values the provider supports to sign ID Tokens with. + * + * example: Supported values list + * ```js + * [ + * 'RS256', 'RS384', 'RS512', + * 'PS256', 'PS384', 'PS512', + * 'ES256', 'ES256K', 'ES384', 'ES512', + * 'EdDSA', + * 'HS256', 'HS384', 'HS512', + * 'none', + * ] + * ``` + */ + idTokenSigningAlgValues: [ + 'RS256', 'PS256', 'ES256', 'EdDSA', + ], + + /* + * enabledJWA.requestObjectSigningAlgValues + * + * description: JWS "alg" Algorithm values the provider supports to receive signed Request Objects (JAR) with + * + * example: Supported values list + * ```js + * [ + * 'RS256', 'RS384', 'RS512', + * 'PS256', 'PS384', 'PS512', + * 'ES256', 'ES256K', 'ES384', 'ES512', + * 'EdDSA', + * 'HS256', 'HS384', 'HS512', + * 'none', + * ] + * ``` + */ + requestObjectSigningAlgValues: [ + 'HS256', 'RS256', 'PS256', 'ES256', 'EdDSA', + ], + + /* + * enabledJWA.userinfoSigningAlgValues + * + * description: JWS "alg" Algorithm values the provider supports to sign UserInfo responses with + * + * example: Supported values list + * ```js + * [ + * 'RS256', 'RS384', 'RS512', + * 'PS256', 'PS384', 'PS512', + * 'ES256', 'ES256K', 'ES384', 'ES512', + * 'EdDSA', + * 'HS256', 'HS384', 'HS512', + * 'none', + * ] + * ``` + */ + userinfoSigningAlgValues: [ + 'RS256', 'PS256', 'ES256', 'EdDSA', + ], + + /* + * enabledJWA.introspectionSigningAlgValues + * + * description: JWS "alg" Algorithm values the provider supports to sign JWT Introspection responses with + * + * example: Supported values list + * ```js + * [ + * 'RS256', 'RS384', 'RS512', + * 'PS256', 'PS384', 'PS512', + * 'ES256', 'ES256K', 'ES384', 'ES512', + * 'EdDSA', + * 'HS256', 'HS384', 'HS512', + * 'none', + * ] + * ``` + */ + introspectionSigningAlgValues: [ + 'RS256', 'PS256', 'ES256', 'EdDSA', + ], + + /* + * enabledJWA.authorizationSigningAlgValues + * + * description: JWS "alg" Algorithm values the provider supports to sign JWT Authorization Responses (JARM) with + * + * example: Supported values list + * ```js + * [ + * 'RS256', 'RS384', 'RS512', + * 'PS256', 'PS384', 'PS512', + * 'ES256', 'ES256K', 'ES384', 'ES512', + * 'EdDSA', + * 'HS256', 'HS384', 'HS512', + * ] + * ``` + */ + authorizationSigningAlgValues: [ + 'RS256', 'PS256', 'ES256', 'EdDSA', + ], + + /* + * enabledJWA.idTokenEncryptionAlgValues + * + * description: JWE "alg" Algorithm values the provider supports for ID Token encryption + * + * example: Supported values list + * ```js + * [ + * // asymmetric RSAES based + * 'RSA-OAEP', 'RSA-OAEP-256', 'RSA-OAEP-384', 'RSA-OAEP-512', 'RSA1_5', + * // asymmetric ECDH-ES based + * 'ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW', + * // symmetric AES key wrapping + * 'A128KW', 'A192KW', 'A256KW', 'A128GCMKW', 'A192GCMKW', 'A256GCMKW', + * // symmetric PBES2 + AES + * 'PBES2-HS256+A128KW', 'PBES2-HS384+A192KW', 'PBES2-HS512+A256KW', + * // direct encryption + * 'dir', + * ] + * ``` + */ + idTokenEncryptionAlgValues: [ + 'A128KW', 'A256KW', 'ECDH-ES', 'RSA-OAEP', 'dir', + ], + + /* + * enabledJWA.requestObjectEncryptionAlgValues + * + * description: JWE "alg" Algorithm values the provider supports to receive encrypted Request Objects (JAR) with + * + * example: Supported values list + * ```js + * [ + * // asymmetric RSAES based + * 'RSA-OAEP', 'RSA-OAEP-256', 'RSA-OAEP-384', 'RSA-OAEP-512', 'RSA1_5', + * // asymmetric ECDH-ES based + * 'ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW', + * // symmetric AES key wrapping + * 'A128KW', 'A192KW', 'A256KW', 'A128GCMKW', 'A192GCMKW', 'A256GCMKW', + * // symmetric PBES2 + AES + * 'PBES2-HS256+A128KW', 'PBES2-HS384+A192KW', 'PBES2-HS512+A256KW', + * // direct encryption + * 'dir', + * ] + * ``` + */ + requestObjectEncryptionAlgValues: [ + 'A128KW', 'A256KW', 'ECDH-ES', 'RSA-OAEP', 'dir', + ], + + /* + * enabledJWA.userinfoEncryptionAlgValues + * + * description: JWE "alg" Algorithm values the provider supports for UserInfo Response encryption + * + * example: Supported values list + * ```js + * [ + * // asymmetric RSAES based + * 'RSA-OAEP', 'RSA-OAEP-256', 'RSA-OAEP-384', 'RSA-OAEP-512', 'RSA1_5', + * // asymmetric ECDH-ES based + * 'ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW', + * // symmetric AES key wrapping + * 'A128KW', 'A192KW', 'A256KW', 'A128GCMKW', 'A192GCMKW', 'A256GCMKW', + * // symmetric PBES2 + AES + * 'PBES2-HS256+A128KW', 'PBES2-HS384+A192KW', 'PBES2-HS512+A256KW', + * // direct encryption + * 'dir', + * ] + * ``` + */ + userinfoEncryptionAlgValues: [ + 'A128KW', 'A256KW', 'ECDH-ES', 'RSA-OAEP', 'dir', + ], + + /* + * enabledJWA.introspectionEncryptionAlgValues + * + * description: JWE "alg" Algorithm values the provider supports for JWT Introspection response + * encryption + * + * example: Supported values list + * ```js + * [ + * // asymmetric RSAES based + * 'RSA-OAEP', 'RSA-OAEP-256', 'RSA-OAEP-384', 'RSA-OAEP-512', 'RSA1_5', + * // asymmetric ECDH-ES based + * 'ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW', + * // symmetric AES key wrapping + * 'A128KW', 'A192KW', 'A256KW', 'A128GCMKW', 'A192GCMKW', 'A256GCMKW', + * // symmetric PBES2 + AES + * 'PBES2-HS256+A128KW', 'PBES2-HS384+A192KW', 'PBES2-HS512+A256KW', + * // direct encryption + * 'dir', + * ] + * ``` + */ + introspectionEncryptionAlgValues: [ + 'A128KW', 'A256KW', 'ECDH-ES', 'RSA-OAEP', 'dir', + ], + + /* + * enabledJWA.authorizationEncryptionAlgValues + * + * description: JWE "alg" Algorithm values the provider supports for JWT Authorization response (JARM) + * encryption + * + * example: Supported values list + * ```js + * [ + * // asymmetric RSAES based + * 'RSA-OAEP', 'RSA-OAEP-256', 'RSA-OAEP-384', 'RSA-OAEP-512', 'RSA1_5', + * // asymmetric ECDH-ES based + * 'ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW', + * // symmetric AES key wrapping + * 'A128KW', 'A192KW', 'A256KW', 'A128GCMKW', 'A192GCMKW', 'A256GCMKW', + * // symmetric PBES2 + AES + * 'PBES2-HS256+A128KW', 'PBES2-HS384+A192KW', 'PBES2-HS512+A256KW', + * // direct encryption + * 'dir', + * ] + * ``` + */ + authorizationEncryptionAlgValues: [ + 'A128KW', 'A256KW', 'ECDH-ES', 'RSA-OAEP', 'dir', + ], + + /* + * enabledJWA.idTokenEncryptionEncValues + * + * description: JWE "enc" Content Encryption Algorithm values the provider supports to encrypt ID Tokens with + * + * example: Supported values list + * ```js + * [ + * 'A128CBC-HS256', 'A128GCM', 'A192CBC-HS384', 'A192GCM', 'A256CBC-HS512', 'A256GCM', + * ] + * ``` + */ + idTokenEncryptionEncValues: [ + 'A128CBC-HS256', 'A128GCM', 'A256CBC-HS512', 'A256GCM', + ], + + /* + * enabledJWA.requestObjectEncryptionEncValues + * + * description: JWE "enc" Content Encryption Algorithm values the provider supports to decrypt Request Objects (JAR) with + * + * example: Supported values list + * ```js + * [ + * 'A128CBC-HS256', 'A128GCM', 'A192CBC-HS384', 'A192GCM', 'A256CBC-HS512', 'A256GCM', + * ] + * ``` + */ + requestObjectEncryptionEncValues: [ + 'A128CBC-HS256', 'A128GCM', 'A256CBC-HS512', 'A256GCM', + ], + + /* + * enabledJWA.userinfoEncryptionEncValues + * + * description: JWE "enc" Content Encryption Algorithm values the provider supports to encrypt UserInfo responses with + * + * example: Supported values list + * ```js + * [ + * 'A128CBC-HS256', 'A128GCM', 'A192CBC-HS384', 'A192GCM', 'A256CBC-HS512', 'A256GCM', + * ] + * ``` + */ + userinfoEncryptionEncValues: [ + 'A128CBC-HS256', 'A128GCM', 'A256CBC-HS512', 'A256GCM', + ], + + /* + * enabledJWA.introspectionEncryptionEncValues + * + * description: JWE "enc" Content Encryption Algorithm values the provider supports to encrypt JWT Introspection responses with + * + * example: Supported values list + * ```js + * [ + * 'A128CBC-HS256', 'A128GCM', 'A192CBC-HS384', 'A192GCM', 'A256CBC-HS512', 'A256GCM', + * ] + * ``` + */ + introspectionEncryptionEncValues: [ + 'A128CBC-HS256', 'A128GCM', 'A256CBC-HS512', 'A256GCM', + ], + + /* + * enabledJWA.authorizationEncryptionEncValues + * + * description: JWE "enc" Content Encryption Algorithm values the provider supports to encrypt JWT Authorization Responses (JARM) with + * + * example: Supported values list + * ```js + * [ + * 'A128CBC-HS256', 'A128GCM', 'A192CBC-HS384', 'A192GCM', 'A256CBC-HS512', 'A256GCM', + * ] + * ``` + */ + authorizationEncryptionEncValues: [ + 'A128CBC-HS256', 'A128GCM', 'A256CBC-HS512', 'A256GCM', + ], + + /* + * enabledJWA.dPoPSigningAlgValues + * + * description: JWS "alg" Algorithm values the provider supports to verify signed DPoP Proof JWTs with + * + * example: Supported values list + * ```js + * [ + * 'RS256', 'RS384', 'RS512', + * 'PS256', 'PS384', 'PS512', + * 'ES256', 'ES256K', 'ES384', 'ES512', + * 'EdDSA', + * ] + * ``` + */ + dPoPSigningAlgValues: [ + 'RS256', 'PS256', 'ES256', 'EdDSA', + ], + }, + }; + + /* + * introspectionEndpointAuthMethods + * + * description: Array of Client Authentication methods supported by this OP's Introspection Endpoint. + * If no configuration value is provided the same values as for tokenEndpointAuthMethods will be + * used. Supported values list is the same as for tokenEndpointAuthMethods. + * @skip + */ + defaults.introspectionEndpointAuthMethods = defaults.tokenEndpointAuthMethods; + + /* + * revocationEndpointAuthMethods + * + * description: Array of Client Authentication methods supported by this OP's Revocation Endpoint. + * If no configuration value is provided the same values as for tokenEndpointAuthMethods will be + * used. Supported values list is the same as for tokenEndpointAuthMethods. + * @skip + */ + defaults.revocationEndpointAuthMethods = defaults.tokenEndpointAuthMethods; + + return defaults; +} + +module.exports = getDefaults; diff --git a/scripts/e2e/oidc-provider/koa.js b/scripts/e2e/oidc-provider/koa.js new file mode 100644 index 00000000..5e541135 --- /dev/null +++ b/scripts/e2e/oidc-provider/koa.js @@ -0,0 +1,85 @@ +/* eslint-disable no-console */ + +const path = require('path'); +const { promisify } = require('util'); + +const Koa = require('koa'); +const render = require('@koa/ejs'); +const helmet = require('helmet'); +const mount = require('koa-mount'); + +const { Provider } = require('../lib'); // require('oidc-provider'); + +const Account = require('./support/account'); +const configuration = require('./support/configuration'); +const routes = require('./routes/koa'); + +// const { PORT = 3000, ISSUER = `http://localhost:${PORT}` } = process.env; +const { PORT = 3000, ISSUER = `http://oidc-provider:${PORT}` } = process.env; +configuration.findAccount = Account.findAccount; + +const app = new Koa(); + +const directives = helmet.contentSecurityPolicy.getDefaultDirectives(); +delete directives['form-action']; +const pHelmet = promisify(helmet({ + contentSecurityPolicy: { + useDefaults: false, + directives, + }, +})); + +app.use(async (ctx, next) => { + const origSecure = ctx.req.secure; + ctx.req.secure = ctx.request.secure; + await pHelmet(ctx.req, ctx.res); + ctx.req.secure = origSecure; + return next(); +}); + +render(app, { + cache: false, + viewExt: 'ejs', + layout: '_layout', + root: path.join(__dirname, 'views'), +}); + +if (process.env.NODE_ENV === 'production') { + app.proxy = true; + + app.use(async (ctx, next) => { + if (ctx.secure) { + await next(); + } else if (ctx.method === 'GET' || ctx.method === 'HEAD') { + ctx.status = 303; + ctx.redirect(ctx.href.replace(/^http:\/\//i, 'https://')); + } else { + ctx.body = { + error: 'invalid_request', + error_description: 'do yourself a favor and only use https', + }; + ctx.status = 400; + } + }); +} + +let server; +(async () => { + let adapter; + if (process.env.MONGODB_URI) { + adapter = require('./adapters/mongodb'); // eslint-disable-line global-require + await adapter.connect(); + } + + const provider = new Provider(ISSUER, { adapter, ...configuration }); + + app.use(routes(provider).routes()); + app.use(mount(provider.app)); + server = app.listen(PORT, () => { + console.log(`application is listening on port ${PORT}, check its /.well-known/openid-configuration`); + }); +})().catch((err) => { + if (server && server.listening) server.close(); + console.error(err); + process.exitCode = 1; +}); diff --git a/scripts/e2e/oidc-provider/my_adapter.js b/scripts/e2e/oidc-provider/my_adapter.js new file mode 100644 index 00000000..730eedb3 --- /dev/null +++ b/scripts/e2e/oidc-provider/my_adapter.js @@ -0,0 +1,242 @@ +/* eslint-disable */ +'use strict'; + +class MyAdapter { + + /** + * + * Creates an instance of MyAdapter for an oidc-provider model. + * + * @constructor + * @param {string} name Name of the oidc-provider model. One of "Grant, "Session", "AccessToken", + * "AuthorizationCode", "RefreshToken", "ClientCredentials", "Client", "InitialAccessToken", + * "RegistrationAccessToken", "DeviceCode", "Interaction", "ReplayDetection", + * "BackchannelAuthenticationRequest", or "PushedAuthorizationRequest" + * + */ + constructor(name) { + + } + + /** + * + * Update or Create an instance of an oidc-provider model. + * + * @return {Promise} Promise fulfilled when the operation succeeded. Rejected with error when + * encountered. + * @param {string} id Identifier that oidc-provider will use to reference this model instance for + * future operations. + * @param {object} payload Object with all properties intended for storage. + * @param {integer} expiresIn Number of seconds intended for this model to be stored. + * + */ + async upsert(id, payload, expiresIn) { + + /** + * + * When this is one of AccessToken, AuthorizationCode, RefreshToken, ClientCredentials, + * InitialAccessToken, RegistrationAccessToken or DeviceCode the payload will contain the + * following properties: + * + * Note: This list is not exhaustive and properties may be added in the future, it is highly + * recommended to use a schema that allows for this. + * + * - jti {string} - unique identifier of the token + * - kind {string} - token class name + * - exp {number} - timestamp of the token's expiration + * - iat {number} - timestamp of the token's creation + * - accountId {string} - account identifier the token belongs to + * - clientId {string} - client identifier the token belongs to + * - aud {string} - audience of a token + * - authTime {number} - timestamp of the end-user's authentication + * - claims {object} - claims parameter (see claims in OIDC Core 1.0) + * - extra {object} - extra claims returned by the extraTokenClaims helper + * - codeChallenge {string} - client provided PKCE code_challenge value + * - codeChallengeMethod {string} - client provided PKCE code_challenge_method value + * - sessionUid {string} - uid of a session this token stems from + * - expiresWithSession {boolean} - whether the token is valid when session expires + * - grantId {string} - grant identifier + * - nonce {string} - random nonce from an authorization request + * - redirectUri {string} - redirect_uri value from an authorization request + * - resource {string|string[]} - resource indicator value(s) (auth code, device code, refresh token) + * - rotations {number} - [RefreshToken only] - number of times the refresh token was rotated + * - iiat {number} - [RefreshToken only] - the very first (initial) issued at before rotations + * - acr {string} - authentication context class reference value + * - amr {string[]} - Authentication methods references + * - scope {string} - scope value from an authorization request + * - sid {string} - session identifier the token comes from + * - 'x5t#S256' {string} - X.509 Certificate SHA-256 Thumbprint of a certificate bound access or + * refresh token + * - 'jkt' {string} - JWK SHA-256 Thumbprint (according to [RFC7638]) of a DPoP bound + * access or refresh token + * - gty {string} - [AccessToken, RefreshToken only] space delimited grant values, indicating + * the grant type(s) they originate from (implicit, authorization_code, refresh_token or + * device_code) the original one is always first, second is refresh_token if refreshed + * - params {object} - [DeviceCode and BackchannelAuthenticationRequest only] an object with the + * authorization request parameters as requested by the client with device_authorization_endpoint + * - userCode {string} - [DeviceCode only] user code value + * - deviceInfo {object} - [DeviceCode only] an object with details about the + * device_authorization_endpoint request + * - inFlight {boolean} - [DeviceCode only] + * - error {string} - [DeviceCode and BackchannelAuthenticationRequest only] - error from authnz to be + * returned to the polling client + * - errorDescription {string} - [DeviceCode and BackchannelAuthenticationRequest only] - error_description + * from authnz to be returned to the polling client + * - policies {string[]} - [InitialAccessToken, RegistrationAccessToken only] array of policies + * - request {string} - [PushedAuthorizationRequest only] Pushed Request Object value + * + * Client model will only use this when registered through Dynamic Registration features and + * will contain all client properties. + * + * Grant model payload contains the following properties: + * - jti {string} - Grant's unique identifier + * - kind {string} - "Grant" fixed string value + * - exp {number} - timestamp of the grant's expiration. exp will be missing when expiration + * is not configured on the Grant model. + * - iat {number} - timestamp of the grant's creation + * - accountId {string} - the grant account identifier + * - clientId {string} - client identifier the grant belongs to + * - openid {object} + * - openid.scope {string} - Granted OpenId Scope value + * - openid.claims {string[]} - Granted OpenId Claim names + * - resources {object} + * - resources[resourceIndicator] {string} - Granted Scope value for a Resource Server + * (indicated by its resource indicator value) + * - resources {object} + * - rejected.openid {object} + * - rejected.openid.scope {string} - Rejected OpenId Scope value + * - rejected.openid.claims {string[]} - Rejected OpenId Claim names + * - rejected.resources {object} + * - rejected.resources[resourceIndicator] {string} - Rejected Scope value for a Resource Server + * (indicated by its resource indicator value) + * + * OIDC Session model payload contains the following properties: + * - jti {string} - Session's unique identifier, it changes on some occasions + * - uid {string} - Session's unique fixed internal identifier + * - kind {string} - "Session" fixed string value + * - exp {number} - timestamp of the session's expiration + * - iat {number} - timestamp of the session's creation + * - accountId {string} - the session account identifier + * - authorizations {object} - object with session authorized clients and their session identifiers + * - loginTs {number} - timestamp of user's authentication + * - acr {string} - authentication context class reference value + * - amr {string[]} - Authentication methods references + * - transient {boolean} - whether the session is using a persistant or session cookie + * - state: {object} - temporary objects used for one-time csrf and state persistance between + * form submissions + * + * Short-lived Interaction model payload contains the following properties: + * - jti {string} - unique identifier of the interaction session + * - kind {string} - "Interaction" fixed string value + * - exp {number} - timestamp of the interaction's expiration + * - iat {number} - timestamp of the interaction's creation + * - returnTo {string} - after resolving interactions send the user-agent to this url + * - deviceCode {string} - [DeviceCode user flows only] deviceCode reference + * - params {object} - parsed recognized parameters object + * - lastSubmission {object} - previous interaction result submission + * - trusted {string[]} - parameter names that come from a trusted source + * - result {object} - interaction results object is expected here + * - grantId {string} - grant identifier if there's a preexisting one + * - session {object} + * - session.uid {string} - uid of the session this Interaction belongs to + * - session.cookie {string} - jti of the session this Interaction belongs to + * - session.acr {string} - existing acr of the session Interaction belongs to + * - session.amr {string[]} - existing amr of the session Interaction belongs to + * - session.accountId {string} - existing account id from the seession Interaction belongs to + * + * Replay prevention ReplayDetection model contains the following properties: + * - jti {string} - unique identifier of the replay object + * - kind {string} - "ReplayDetection" fixed string value + * - exp {number} - timestamp of the replay object cache expiration + * - iat {number} - timestamp of the replay object cache's creation + */ + } + + /** + * + * Return previously stored instance of an oidc-provider model. + * + * @return {Promise} Promise fulfilled with what was previously stored for the id (when found and + * not dropped yet due to expiration) or falsy value when not found anymore. Rejected with error + * when encountered. + * @param {string} id Identifier of oidc-provider model + * + */ + async find(id) { + + } + + /** + * + * Return previously stored instance of DeviceCode by the end-user entered user code. You only + * need this method for the deviceFlow feature + * + * @return {Promise} Promise fulfilled with the stored device code object (when found and not + * dropped yet due to expiration) or falsy value when not found anymore. Rejected with error + * when encountered. + * @param {string} userCode the user_code value associated with a DeviceCode instance + * + */ + async findByUserCode(userCode) { + + } + + /** + * + * Return previously stored instance of Session by its uid reference property. + * + * @return {Promise} Promise fulfilled with the stored session object (when found and not + * dropped yet due to expiration) or falsy value when not found anymore. Rejected with error + * when encountered. + * @param {string} uid the uid value associated with a Session instance + * + */ + async findByUid(uid) { + + } + + /** + * + * Mark a stored oidc-provider model as consumed (not yet expired though!). Future finds for this + * id should be fulfilled with an object containing additional property named "consumed" with a + * truthy value (timestamp, date, boolean, etc). + * + * @return {Promise} Promise fulfilled when the operation succeeded. Rejected with error when + * encountered. + * @param {string} id Identifier of oidc-provider model + * + */ + async consume(id) { + + } + + /** + * + * Destroy/Drop/Remove a stored oidc-provider model. Future finds for this id should be fulfilled + * with falsy values. + * + * @return {Promise} Promise fulfilled when the operation succeeded. Rejected with error when + * encountered. + * @param {string} id Identifier of oidc-provider model + * + */ + async destroy(id) { + + } + + /** + * + * Destroy/Drop/Remove a stored oidc-provider model by its grantId property reference. Future + * finds for all tokens having this grantId value should be fulfilled with falsy values. + * + * @return {Promise} Promise fulfilled when the operation succeeded. Rejected with error when + * encountered. + * @param {string} grantId the grantId value associated with a this model's instance + * + */ + async revokeByGrantId(grantId) { + + } +} + +module.exports = MyAdapter; diff --git a/scripts/e2e/oidc-provider/package-lock.json b/scripts/e2e/oidc-provider/package-lock.json new file mode 100644 index 00000000..b2796271 --- /dev/null +++ b/scripts/e2e/oidc-provider/package-lock.json @@ -0,0 +1,10542 @@ +{ + "name": "node-oidc-provider", + "version": "7.14.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "node-oidc-provider", + "version": "7.14.1", + "dependencies": { + "@koa/cors": "^3.3.0", + "cacheable-lookup": "^6.0.4", + "debug": "^4.3.4", + "ejs": "^3.1.8", + "got": "^11.8.5", + "jose": "^4.10.3", + "jsesc": "^3.0.2", + "koa": "^2.13.4", + "koa-compose": "^4.1.0", + "nanoid": "^3.3.4", + "object-hash": "^3.0.0", + "oidc-provider": "^7.14.1", + "oidc-token-hash": "^5.0.1", + "paseto": "^2.1.3", + "quick-lru": "^5.1.1", + "raw-body": "^2.5.1" + }, + "devDependencies": { + "@fastify/middie": "^8.0.0", + "@hapi/hapi": "^20.2.2", + "@koa/ejs": "^5.0.0", + "babel-eslint": "^10.1.0", + "base64url": "^3.0.1", + "chai": "^4.3.6", + "clear-module": "^4.1.2", + "connect": "^3.7.0", + "eslint": "^7.32.0", + "eslint-config-airbnb-base": "^14.2.1", + "eslint-plugin-import": "^2.26.0", + "express": "^4.18.1", + "fastify": "^4.9.2", + "helmet": "^5.1.0", + "jose2": "npm:jose@^2.0.6", + "koa-body": "^4.2.0", + "koa-mount": "^4.0.0", + "koa-router": "^10.1.1", + "lodash": "^4.17.21", + "mocha": "^9.2.2", + "moment": "^2.29.4", + "nock": "^13.2.8", + "selfsigned": "^2.0.1", + "sinon": "^12.0.1", + "supertest": "^6.3.1", + "timekeeper": "^2.2.0" + }, + "engines": { + "node": "12 || 14 || 16 || 18" + }, + "optionalDependencies": { + "paseto3": "npm:paseto@^3.1.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz", + "integrity": "sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.5", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "dev": true, + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", + "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.5.tgz", + "integrity": "sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.5", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.20.5", + "@babel/types": "^7.20.5", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", + "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", + "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@fastify/ajv-compiler": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-3.4.0.tgz", + "integrity": "sha512-69JnK7Cot+ktn7LD5TikP3b7psBPX55tYpQa8WSumt8r117PCa2zwHnImfBtRWYExreJlI48hr0WZaVrTBGj7w==", + "dev": true, + "dependencies": { + "ajv": "^8.11.0", + "ajv-formats": "^2.1.1", + "fast-uri": "^2.0.0" + } + }, + "node_modules/@fastify/ajv-compiler/node_modules/ajv": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", + "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@fastify/ajv-compiler/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/@fastify/deepmerge": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@fastify/deepmerge/-/deepmerge-1.3.0.tgz", + "integrity": "sha512-J8TOSBq3SoZbDhM9+R/u77hP93gz/rajSA+K2kGyijPpORPWUXHUpTaleoj+92As0S9uPRP7Oi8IqMf0u+ro6A==", + "dev": true + }, + "node_modules/@fastify/error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@fastify/error/-/error-3.1.0.tgz", + "integrity": "sha512-jmk3Q822+xi8jVzGsux3mWd+9O4rzVUGCqR2+JlF9LkCeeUmRdxPd2Je6S7IGMk5VTtB0xyB3crRQqklUyQ6dQ==", + "dev": true + }, + "node_modules/@fastify/fast-json-stringify-compiler": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-4.1.0.tgz", + "integrity": "sha512-cTKBV2J9+u6VaKDhX7HepSfPSzw+F+TSd+k0wzifj4rG+4E5PjSFJCk19P8R6tr/72cuzgGd+mbB3jFT6lvAgw==", + "dev": true, + "dependencies": { + "fast-json-stringify": "^5.0.0" + } + }, + "node_modules/@fastify/middie": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@fastify/middie/-/middie-8.1.0.tgz", + "integrity": "sha512-VvUCLfKx2j6KSnh8puT8QW7d5YNzi2fD/4HcFvRQ3a7sHlCo+qtfX2fqzFvNqnMVbNft7GX1JL5if/riUiXsyg==", + "dev": true, + "dependencies": { + "fastify-plugin": "^4.0.0", + "path-to-regexp": "^6.1.0", + "reusify": "^1.0.4" + } + }, + "node_modules/@hapi/accept": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@hapi/accept/-/accept-5.0.2.tgz", + "integrity": "sha512-CmzBx/bXUR8451fnZRuZAJRlzgm0Jgu5dltTX/bszmR2lheb9BpyN47Q1RbaGTsvFzn0PXAEs+lXDKfshccYZw==", + "dev": true, + "dependencies": { + "@hapi/boom": "9.x.x", + "@hapi/hoek": "9.x.x" + } + }, + "node_modules/@hapi/ammo": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@hapi/ammo/-/ammo-5.0.1.tgz", + "integrity": "sha512-FbCNwcTbnQP4VYYhLNGZmA76xb2aHg9AMPiy18NZyWMG310P5KdFGyA9v2rm5ujrIny77dEEIkMOwl0Xv+fSSA==", + "dev": true, + "dependencies": { + "@hapi/hoek": "9.x.x" + } + }, + "node_modules/@hapi/b64": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@hapi/b64/-/b64-5.0.0.tgz", + "integrity": "sha512-ngu0tSEmrezoiIaNGG6rRvKOUkUuDdf4XTPnONHGYfSGRmDqPZX5oJL6HAdKTo1UQHECbdB4OzhWrfgVppjHUw==", + "dev": true, + "dependencies": { + "@hapi/hoek": "9.x.x" + } + }, + "node_modules/@hapi/boom": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-9.1.4.tgz", + "integrity": "sha512-Ls1oH8jaN1vNsqcaHVYJrKmgMcKsC1wcp8bujvXrHaAqD2iDYq3HoOwsxwo09Cuda5R5nC0o0IxlrlTuvPuzSw==", + "dev": true, + "dependencies": { + "@hapi/hoek": "9.x.x" + } + }, + "node_modules/@hapi/bounce": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@hapi/bounce/-/bounce-2.0.0.tgz", + "integrity": "sha512-JesW92uyzOOyuzJKjoLHM1ThiOvHPOLDHw01YV8yh5nCso7sDwJho1h0Ad2N+E62bZyz46TG3xhAi/78Gsct6A==", + "dev": true, + "dependencies": { + "@hapi/boom": "9.x.x", + "@hapi/hoek": "9.x.x" + } + }, + "node_modules/@hapi/bourne": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-2.1.0.tgz", + "integrity": "sha512-i1BpaNDVLJdRBEKeJWkVO6tYX6DMFBuwMhSuWqLsY4ufeTKGVuV5rBsUhxPayXqnnWHgXUAmWK16H/ykO5Wj4Q==", + "dev": true + }, + "node_modules/@hapi/call": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@hapi/call/-/call-8.0.1.tgz", + "integrity": "sha512-bOff6GTdOnoe5b8oXRV3lwkQSb/LAWylvDMae6RgEWWntd0SHtkYbQukDHKlfaYtVnSAgIavJ0kqszF/AIBb6g==", + "dev": true, + "dependencies": { + "@hapi/boom": "9.x.x", + "@hapi/hoek": "9.x.x" + } + }, + "node_modules/@hapi/catbox": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@hapi/catbox/-/catbox-11.1.1.tgz", + "integrity": "sha512-u/8HvB7dD/6X8hsZIpskSDo4yMKpHxFd7NluoylhGrL6cUfYxdQPnvUp9YU2C6F9hsyBVLGulBd9vBN1ebfXOQ==", + "dev": true, + "dependencies": { + "@hapi/boom": "9.x.x", + "@hapi/hoek": "9.x.x", + "@hapi/podium": "4.x.x", + "@hapi/validate": "1.x.x" + } + }, + "node_modules/@hapi/catbox-memory": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@hapi/catbox-memory/-/catbox-memory-5.0.1.tgz", + "integrity": "sha512-QWw9nOYJq5PlvChLWV8i6hQHJYfvdqiXdvTupJFh0eqLZ64Xir7mKNi96d5/ZMUAqXPursfNDIDxjFgoEDUqeQ==", + "dev": true, + "dependencies": { + "@hapi/boom": "9.x.x", + "@hapi/hoek": "9.x.x" + } + }, + "node_modules/@hapi/content": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@hapi/content/-/content-5.0.2.tgz", + "integrity": "sha512-mre4dl1ygd4ZyOH3tiYBrOUBzV7Pu/EOs8VLGf58vtOEECWed8Uuw6B4iR9AN/8uQt42tB04qpVaMyoMQh0oMw==", + "dev": true, + "dependencies": { + "@hapi/boom": "9.x.x" + } + }, + "node_modules/@hapi/cryptiles": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/cryptiles/-/cryptiles-5.1.0.tgz", + "integrity": "sha512-fo9+d1Ba5/FIoMySfMqPBR/7Pa29J2RsiPrl7bkwo5W5o+AN1dAYQRi4SPrPwwVxVGKjgLOEWrsvt1BonJSfLA==", + "dev": true, + "dependencies": { + "@hapi/boom": "9.x.x" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@hapi/file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@hapi/file/-/file-2.0.0.tgz", + "integrity": "sha512-WSrlgpvEqgPWkI18kkGELEZfXr0bYLtr16iIN4Krh9sRnzBZN6nnWxHFxtsnP684wueEySBbXPDg/WfA9xJdBQ==", + "dev": true + }, + "node_modules/@hapi/hapi": { + "version": "20.2.2", + "resolved": "https://registry.npmjs.org/@hapi/hapi/-/hapi-20.2.2.tgz", + "integrity": "sha512-crhU6TIKt7QsksWLYctDBAXogk9PYAm7UzdpETyuBHC2pCa6/+B5NykiOVLG/3FCIgHo/raPVtan8bYtByHORQ==", + "dev": true, + "dependencies": { + "@hapi/accept": "^5.0.1", + "@hapi/ammo": "^5.0.1", + "@hapi/boom": "^9.1.0", + "@hapi/bounce": "^2.0.0", + "@hapi/call": "^8.0.0", + "@hapi/catbox": "^11.1.1", + "@hapi/catbox-memory": "^5.0.0", + "@hapi/heavy": "^7.0.1", + "@hapi/hoek": "^9.0.4", + "@hapi/mimos": "^6.0.0", + "@hapi/podium": "^4.1.1", + "@hapi/shot": "^5.0.5", + "@hapi/somever": "^3.0.0", + "@hapi/statehood": "^7.0.4", + "@hapi/subtext": "^7.0.3", + "@hapi/teamwork": "^5.1.1", + "@hapi/topo": "^5.0.0", + "@hapi/validate": "^1.1.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@hapi/heavy": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@hapi/heavy/-/heavy-7.0.1.tgz", + "integrity": "sha512-vJ/vzRQ13MtRzz6Qd4zRHWS3FaUc/5uivV2TIuExGTM9Qk+7Zzqj0e2G7EpE6KztO9SalTbiIkTh7qFKj/33cA==", + "dev": true, + "dependencies": { + "@hapi/boom": "9.x.x", + "@hapi/hoek": "9.x.x", + "@hapi/validate": "1.x.x" + } + }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "dev": true + }, + "node_modules/@hapi/iron": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/iron/-/iron-6.0.0.tgz", + "integrity": "sha512-zvGvWDufiTGpTJPG1Y/McN8UqWBu0k/xs/7l++HVU535NLHXsHhy54cfEMdW7EjwKfbBfM9Xy25FmTiobb7Hvw==", + "dev": true, + "dependencies": { + "@hapi/b64": "5.x.x", + "@hapi/boom": "9.x.x", + "@hapi/bourne": "2.x.x", + "@hapi/cryptiles": "5.x.x", + "@hapi/hoek": "9.x.x" + } + }, + "node_modules/@hapi/mimos": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/mimos/-/mimos-6.0.0.tgz", + "integrity": "sha512-Op/67tr1I+JafN3R3XN5DucVSxKRT/Tc+tUszDwENoNpolxeXkhrJ2Czt6B6AAqrespHoivhgZBWYSuANN9QXg==", + "dev": true, + "dependencies": { + "@hapi/hoek": "9.x.x", + "mime-db": "1.x.x" + } + }, + "node_modules/@hapi/nigel": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@hapi/nigel/-/nigel-4.0.2.tgz", + "integrity": "sha512-ht2KoEsDW22BxQOEkLEJaqfpoKPXxi7tvabXy7B/77eFtOyG5ZEstfZwxHQcqAiZhp58Ae5vkhEqI03kawkYNw==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.0.4", + "@hapi/vise": "^4.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@hapi/pez": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@hapi/pez/-/pez-5.0.3.tgz", + "integrity": "sha512-mpikYRJjtrbJgdDHG/H9ySqYqwJ+QU/D7FXsYciS9P7NYBXE2ayKDAy3H0ou6CohOCaxPuTV4SZ0D936+VomHA==", + "dev": true, + "dependencies": { + "@hapi/b64": "5.x.x", + "@hapi/boom": "9.x.x", + "@hapi/content": "^5.0.2", + "@hapi/hoek": "9.x.x", + "@hapi/nigel": "4.x.x" + } + }, + "node_modules/@hapi/podium": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@hapi/podium/-/podium-4.1.3.tgz", + "integrity": "sha512-ljsKGQzLkFqnQxE7qeanvgGj4dejnciErYd30dbrYzUOF/FyS/DOF97qcrT3bhoVwCYmxa6PEMhxfCPlnUcD2g==", + "dev": true, + "dependencies": { + "@hapi/hoek": "9.x.x", + "@hapi/teamwork": "5.x.x", + "@hapi/validate": "1.x.x" + } + }, + "node_modules/@hapi/shot": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@hapi/shot/-/shot-5.0.5.tgz", + "integrity": "sha512-x5AMSZ5+j+Paa8KdfCoKh+klB78otxF+vcJR/IoN91Vo2e5ulXIW6HUsFTCU+4W6P/Etaip9nmdAx2zWDimB2A==", + "dev": true, + "dependencies": { + "@hapi/hoek": "9.x.x", + "@hapi/validate": "1.x.x" + } + }, + "node_modules/@hapi/somever": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@hapi/somever/-/somever-3.0.1.tgz", + "integrity": "sha512-4ZTSN3YAHtgpY/M4GOtHUXgi6uZtG9nEZfNI6QrArhK0XN/RDVgijlb9kOmXwCR5VclDSkBul9FBvhSuKXx9+w==", + "dev": true, + "dependencies": { + "@hapi/bounce": "2.x.x", + "@hapi/hoek": "9.x.x" + } + }, + "node_modules/@hapi/statehood": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@hapi/statehood/-/statehood-7.0.4.tgz", + "integrity": "sha512-Fia6atroOVmc5+2bNOxF6Zv9vpbNAjEXNcUbWXavDqhnJDlchwUUwKS5LCi5mGtCTxRhUKKHwuxuBZJkmLZ7fw==", + "dev": true, + "dependencies": { + "@hapi/boom": "9.x.x", + "@hapi/bounce": "2.x.x", + "@hapi/bourne": "2.x.x", + "@hapi/cryptiles": "5.x.x", + "@hapi/hoek": "9.x.x", + "@hapi/iron": "6.x.x", + "@hapi/validate": "1.x.x" + } + }, + "node_modules/@hapi/subtext": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@hapi/subtext/-/subtext-7.0.4.tgz", + "integrity": "sha512-Y72moHhbRuO8kwBHFEnCRw7oOnhNh4Pl+aonxAze18jkyMpE4Gwz4lNID7ei8vd3lpXC2rKdkxXJgtfY+WttRw==", + "dev": true, + "dependencies": { + "@hapi/boom": "9.x.x", + "@hapi/bourne": "2.x.x", + "@hapi/content": "^5.0.2", + "@hapi/file": "2.x.x", + "@hapi/hoek": "9.x.x", + "@hapi/pez": "^5.0.1", + "@hapi/wreck": "17.x.x" + } + }, + "node_modules/@hapi/teamwork": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@hapi/teamwork/-/teamwork-5.1.1.tgz", + "integrity": "sha512-1oPx9AE5TIv+V6Ih54RP9lTZBso3rP8j4Xhb6iSVwPXtAM+sDopl5TFMv5Paw73UnpZJ9gjcrTE1BXrWt9eQrg==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@hapi/validate": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@hapi/validate/-/validate-1.1.3.tgz", + "integrity": "sha512-/XMR0N0wjw0Twzq2pQOzPBZlDzkekGcoCtzO314BpIEsbXdYGthQUbxgkGDf4nhk1+IPDAsXqWjMohRQYO06UA==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0" + } + }, + "node_modules/@hapi/vise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@hapi/vise/-/vise-4.0.0.tgz", + "integrity": "sha512-eYyLkuUiFZTer59h+SGy7hUm+qE9p+UemePTHLlIWppEd+wExn3Df5jO04bFQTm7nleF5V8CtuYQYb+VFpZ6Sg==", + "dev": true, + "dependencies": { + "@hapi/hoek": "9.x.x" + } + }, + "node_modules/@hapi/wreck": { + "version": "17.2.0", + "resolved": "https://registry.npmjs.org/@hapi/wreck/-/wreck-17.2.0.tgz", + "integrity": "sha512-pJ5kjYoRPYDv+eIuiLQqhGon341fr2bNIYZjuotuPJG/3Ilzr/XtI+JAp0A86E2bYfsS3zBPABuS2ICkaXFT8g==", + "dev": true, + "dependencies": { + "@hapi/boom": "9.x.x", + "@hapi/bourne": "2.x.x", + "@hapi/hoek": "9.x.x" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@koa/cors": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@koa/cors/-/cors-3.4.3.tgz", + "integrity": "sha512-WPXQUaAeAMVaLTEFpoq3T2O1C+FstkjJnDQqy95Ck1UdILajsRhu6mhJ8H2f4NFPRBoCNN+qywTJfq/gGki5mw==", + "dependencies": { + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/@koa/ejs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@koa/ejs/-/ejs-5.0.0.tgz", + "integrity": "sha512-luxtlG1SEfAvbuMbsJYwxXXrXtESslbJsukeKnUiaBmtpkdmNV3M7iL6Ygm8oX67rnPd7tNCJpd7rmFSSBsHig==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "ejs": "^3.1.8" + } + }, + "node_modules/@panva/asn1.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@panva/asn1.js/-/asn1.js-1.0.0.tgz", + "integrity": "sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", + "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/@sinonjs/samsam": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-6.1.3.tgz", + "integrity": "sha512-nhOb2dWPeb1sd3IQXL/dVPnKHDOAFfvichtBf4xV00/rU1QbPCQqKMbvIheIjqwVjh7qIgf2AHTHi391yMOMpQ==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "node_modules/@sinonjs/text-encoding": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", + "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", + "dev": true + }, + "node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/formidable": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@types/formidable/-/formidable-1.2.5.tgz", + "integrity": "sha512-zu3mQJa4hDNubEMViSj937602XdDGzK7Q5pJ5QmLUbNxclbo9tZGt5jtwM352ssZ+pqo5V4H14TBvT/ALqQQcA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", + "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "18.11.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.10.tgz", + "integrity": "sha512-juG3RWMBOqcOuXC643OAdSA525V44cVgGV6dUDuiFtss+8Fk5x1hI93Rsld43VeJVIeqlP9I7Fn9/qaVqoEAuQ==" + }, + "node_modules/@types/responselike": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/abstract-logging": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz", + "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", + "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", + "dev": true + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/array-includes": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/avvio": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/avvio/-/avvio-8.2.0.tgz", + "integrity": "sha512-bbCQdg7bpEv6kGH41RO/3B2/GMMmJSo2iBK+X8AWN9mujtfUipMDfIjsgHCfpnKqoGEQrrmCDKSa5OQ19+fDmg==", + "dev": true, + "dependencies": { + "archy": "^1.0.0", + "debug": "^4.0.0", + "fastq": "^1.6.1" + } + }, + "node_modules/babel-eslint": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", + "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", + "deprecated": "babel-eslint is now @babel/eslint-parser. This package will no longer receive updates.", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0", + "eslint-visitor-keys": "^1.0.0", + "resolve": "^1.12.0" + }, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "eslint": ">= 4.12.1" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/base64url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", + "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cache-content-type": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-content-type/-/cache-content-type-1.0.1.tgz", + "integrity": "sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==", + "dependencies": { + "mime-types": "^2.1.18", + "ylru": "^1.2.0" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/cacheable-lookup": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-6.1.0.tgz", + "integrity": "sha512-KJ/Dmo1lDDhmW2XDPMo+9oiy/CeqosPguPCrgcVzKyZrL6pM1gU2GmPY/xo6OQPTUaA/c0kwHuywB4E6nmT9ww==", + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", + "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chai": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/clear-module": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/clear-module/-/clear-module-4.1.2.tgz", + "integrity": "sha512-LWAxzHqdHsAZlPlEyJ2Poz6AIs384mPeqLVCru2p0BrP9G/kVGuhNyZYClLO6cXlnuJjzC8xtsJIuMjKqLXoAw==", + "dev": true, + "dependencies": { + "parent-module": "^2.0.0", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/co-body": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/co-body/-/co-body-5.2.0.tgz", + "integrity": "sha512-sX/LQ7LqUhgyaxzbe7IqwPeTr2yfpfUIQ/dgpKo6ZI4y4lpQA0YxAomWIY+7I7rHWcG02PG+OuPREzMW/5tszQ==", + "dev": true, + "dependencies": { + "inflation": "^2.0.0", + "qs": "^6.4.0", + "raw-body": "^2.2.0", + "type-is": "^1.6.14" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/confusing-browser-globals": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", + "dev": true + }, + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/cookiejar": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.3.tgz", + "integrity": "sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ==", + "dev": true + }, + "node_modules/cookies": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.8.0.tgz", + "integrity": "sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow==", + "dependencies": { + "depd": "~2.0.0", + "keygrip": "~1.1.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw==" + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "engines": { + "node": ">=10" + } + }, + "node_modules/define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dev": true, + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/ejs": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz", + "integrity": "sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/es-abstract": { + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", + "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.3", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.2", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-airbnb-base": { + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz", + "integrity": "sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA==", + "dev": true, + "dependencies": { + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", + "object.entries": "^1.1.2" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "eslint": "^5.16.0 || ^6.8.0 || ^7.2.0", + "eslint-plugin-import": "^2.22.1" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "resolve": "^1.20.0" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", + "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", + "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.3", + "has": "^1.0.3", + "is-core-module": "^2.8.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.5", + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint/node_modules/@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", + "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/express/node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "node_modules/fast-decode-uri-component": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", + "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==", + "dev": true + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-json-stringify": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-5.4.1.tgz", + "integrity": "sha512-P7S9WXEnMqu6seBnzAFmgZ+T3KCD+Do+pNIJsmk/6OlDHZVjl6KzsQB3TFHKQb2Q8N7C9l31WS7/LZGF5hT1FA==", + "dev": true, + "dependencies": { + "@fastify/deepmerge": "^1.0.0", + "ajv": "^8.10.0", + "ajv-formats": "^2.1.1", + "fast-deep-equal": "^3.1.3", + "fast-uri": "^2.1.0", + "rfdc": "^1.2.0" + } + }, + "node_modules/fast-json-stringify/node_modules/ajv": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", + "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/fast-json-stringify/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fast-querystring": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.0.0.tgz", + "integrity": "sha512-3LQi62IhQoDlmt4ULCYmh17vRO2EtS7hTSsG4WwoKWgV7GLMKBOecEh+aiavASnLx8I2y89OD33AGLo0ccRhzA==", + "dev": true, + "dependencies": { + "fast-decode-uri-component": "^1.0.1" + } + }, + "node_modules/fast-redact": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.1.2.tgz", + "integrity": "sha512-+0em+Iya9fKGfEQGcd62Yv6onjBmmhV1uh86XVfOU8VwAe6kaFdQCWI9s0/Nnugx5Vd9tdbZ7e6gE2tR9dzXdw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true + }, + "node_modules/fast-uri": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-2.1.0.tgz", + "integrity": "sha512-qKRta6N7BWEFVlyonVY/V+BMLgFqktCUV0QjT259ekAIlbVrMaFnFLxJ4s/JPl4tou56S1BzPufI60bLe29fHA==", + "dev": true + }, + "node_modules/fastify": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/fastify/-/fastify-4.10.2.tgz", + "integrity": "sha512-0T+4zI6N3S8ex0LCZi3H4FasJR4AzWw834fUkPWvV8r6GBJkLmAOfFxH8f5V29Plef24IK0QSQD/tz1Nx+1UOA==", + "dev": true, + "dependencies": { + "@fastify/ajv-compiler": "^3.3.1", + "@fastify/error": "^3.0.0", + "@fastify/fast-json-stringify-compiler": "^4.1.0", + "abstract-logging": "^2.0.1", + "avvio": "^8.2.0", + "content-type": "^1.0.4", + "find-my-way": "^7.3.0", + "light-my-request": "^5.6.1", + "pino": "^8.5.0", + "process-warning": "^2.0.0", + "proxy-addr": "^2.0.7", + "rfdc": "^1.3.0", + "secure-json-parse": "^2.5.0", + "semver": "^7.3.7", + "tiny-lru": "^10.0.0" + } + }, + "node_modules/fastify-plugin": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-4.4.0.tgz", + "integrity": "sha512-ovwFQG2qNy3jcCROiWpr94Hs0le+c7N/3t7m9aVwbFhkxcR/esp2xu25dP8e617HpQdmeDv+gFX4zagdUhDByw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz", + "integrity": "sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.1.tgz", + "integrity": "sha512-362NP+zlprccbEt/SkxKfRMHnNY85V74mVnpUpNyr3F35covl09Kec7/sEFLt3RA4oXmewtoaanoIf67SE5Y5g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/finalhandler/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/find-my-way": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-7.3.1.tgz", + "integrity": "sha512-kGvM08SOkqvheLcuQ8GW9t/H901Qb9rZEbcNWbXopzy4jDRoaJpJoObPSKf4MnQLZ20ZTp7rL5MpF6rf+pqmyg==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-querystring": "^1.0.0", + "safe-regex2": "^2.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/formidable": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.6.tgz", + "integrity": "sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==", + "deprecated": "Please upgrade to latest, formidable@v2 or formidable@v3! Check these notes: https://bit.ly/2ZEqIau", + "dev": true, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/got": { + "version": "11.8.5", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.5.tgz", + "integrity": "sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==", + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/got/node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true, + "engines": { + "node": ">=4.x" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/helmet": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-5.1.1.tgz", + "integrity": "sha512-/yX0oVZBggA9cLJh8aw3PPCfedBnbd7J2aowjzsaWwZh7/UFY0nccn/aHAggIgWUFfnykX8GKd3a1pSbrmlcVQ==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/hexoid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", + "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/http-assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.5.0.tgz", + "integrity": "sha512-uPpH7OKX4H25hBmU6G1jWNaqJGpTXxey+YOUizJUAgu0AjLUeC8D73hTrhvDS5D+GJN1DN1+hhc/eF/wpxtp0w==", + "dependencies": { + "deep-equal": "~1.0.1", + "http-errors": "~1.8.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-assert/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-assert/node_modules/http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-assert/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflation": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/inflation/-/inflation-2.0.0.tgz", + "integrity": "sha512-m3xv4hJYR2oXw4o4Y5l6P5P16WYmazYof+el6Al3f+YlggGj6qT9kImBAnzDelRALnP5d3h4jGBPKzYCizjZZw==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/jake": { + "version": "10.8.5", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", + "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==", + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.1", + "minimatch": "^3.0.4" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jake/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jake/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jake/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jake/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jake/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jake/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jose": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.11.1.tgz", + "integrity": "sha512-YRv4Tk/Wlug8qicwqFNFVEZSdbROCHRAC6qu/i0dyNKr5JQdoa2pIGoS04lLO/jXQX7Z9omoNewYIVIxqZBd9Q==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/jose2": { + "name": "jose", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/jose/-/jose-2.0.6.tgz", + "integrity": "sha512-FVoPY7SflDodE4lknJmbAHSUjLCzE2H1F6MS0RYKMQ8SR+lNccpMf8R4eqkNYyyUjR5qZReOzZo5C5YiHOCjjg==", + "dev": true, + "dependencies": { + "@panva/asn1.js": "^1.0.0" + }, + "engines": { + "node": ">=10.13.0 < 13 || >=13.7.0" + }, + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true + }, + "node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/just-extend": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", + "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", + "dev": true + }, + "node_modules/keygrip": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", + "integrity": "sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==", + "dependencies": { + "tsscmp": "1.0.6" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/keyv": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", + "integrity": "sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/koa": { + "version": "2.13.4", + "resolved": "https://registry.npmjs.org/koa/-/koa-2.13.4.tgz", + "integrity": "sha512-43zkIKubNbnrULWlHdN5h1g3SEKXOEzoAlRsHOTFpnlDu8JlAOZSMJBLULusuXRequboiwJcj5vtYXKB3k7+2g==", + "dependencies": { + "accepts": "^1.3.5", + "cache-content-type": "^1.0.0", + "content-disposition": "~0.5.2", + "content-type": "^1.0.4", + "cookies": "~0.8.0", + "debug": "^4.3.2", + "delegates": "^1.0.0", + "depd": "^2.0.0", + "destroy": "^1.0.4", + "encodeurl": "^1.0.2", + "escape-html": "^1.0.3", + "fresh": "~0.5.2", + "http-assert": "^1.3.0", + "http-errors": "^1.6.3", + "is-generator-function": "^1.0.7", + "koa-compose": "^4.1.0", + "koa-convert": "^2.0.0", + "on-finished": "^2.3.0", + "only": "~0.0.2", + "parseurl": "^1.3.2", + "statuses": "^1.5.0", + "type-is": "^1.6.16", + "vary": "^1.1.2" + }, + "engines": { + "node": "^4.8.4 || ^6.10.1 || ^7.10.1 || >= 8.1.4" + } + }, + "node_modules/koa-body": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/koa-body/-/koa-body-4.2.0.tgz", + "integrity": "sha512-wdGu7b9amk4Fnk/ytH8GuWwfs4fsB5iNkY8kZPpgQVb04QZSv85T0M8reb+cJmvLE8cjPYvBzRikD3s6qz8OoA==", + "dev": true, + "dependencies": { + "@types/formidable": "^1.0.31", + "co-body": "^5.1.1", + "formidable": "^1.1.1" + } + }, + "node_modules/koa-compose": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-4.1.0.tgz", + "integrity": "sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==" + }, + "node_modules/koa-convert": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/koa-convert/-/koa-convert-2.0.0.tgz", + "integrity": "sha512-asOvN6bFlSnxewce2e/DK3p4tltyfC4VM7ZwuTuepI7dEQVcvpyFuBcEARu1+Hxg8DIwytce2n7jrZtRlPrARA==", + "dependencies": { + "co": "^4.6.0", + "koa-compose": "^4.1.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/koa-mount": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/koa-mount/-/koa-mount-4.0.0.tgz", + "integrity": "sha512-rm71jaA/P+6HeCpoRhmCv8KVBIi0tfGuO/dMKicbQnQW/YJntJ6MnnspkodoA4QstMVEZArsCphmd0bJEtoMjQ==", + "dev": true, + "dependencies": { + "debug": "^4.0.1", + "koa-compose": "^4.1.0" + }, + "engines": { + "node": ">= 7.6.0" + } + }, + "node_modules/koa-router": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/koa-router/-/koa-router-10.1.1.tgz", + "integrity": "sha512-z/OzxVjf5NyuNO3t9nJpx7e1oR3FSBAauiwXtMQu4ppcnuNZzTaQ4p21P8A6r2Es8uJJM339oc4oVW+qX7SqnQ==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "http-errors": "^1.7.3", + "koa-compose": "^4.1.0", + "methods": "^1.1.2", + "path-to-regexp": "^6.1.0" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/koa-router/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/koa-router/node_modules/http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/koa-router/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/koa/node_modules/http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/koa/node_modules/http-errors/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/koa/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/light-my-request": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-5.8.0.tgz", + "integrity": "sha512-4BtD5C+VmyTpzlDPCZbsatZMJVgUIciSOwYhJDCbLffPZ35KoDkDj4zubLeHDEb35b4kkPeEv5imbh+RJxK/Pg==", + "dev": true, + "dependencies": { + "cookie": "^0.5.0", + "process-warning": "^2.0.0", + "set-cookie-parser": "^2.4.1" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/loupe": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.0" + } + }, + "node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mocha": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", + "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", + "dev": true, + "dependencies": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.3", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "4.2.1", + "ms": "2.1.3", + "nanoid": "3.3.1", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "workerpool": "6.2.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mocha/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/mocha/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/mocha/node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/mocha/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", + "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mocha/node_modules/nanoid": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/nise": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.2.tgz", + "integrity": "sha512-+gQjFi8v+tkfCuSCxfURHLhRhniE/+IaYbIphxAN2JRR9SHKhY8hgXpaXiYfHdw+gcGe4buxgbprBQFab9FkhA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0", + "@sinonjs/fake-timers": "^7.0.4", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + } + }, + "node_modules/nise/node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/nise/node_modules/@sinonjs/fake-timers": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-7.1.2.tgz", + "integrity": "sha512-iQADsW4LBMISqZ6Ci1dupJL9pprqwcVFTcOsEmQOEhW+KLCVn/Y4Jrvg2k19fIHCp+iFprriYPTdRcQR8NbUPg==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/nise/node_modules/@sinonjs/fake-timers/node_modules/@sinonjs/commons": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/nise/node_modules/path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "dependencies": { + "isarray": "0.0.1" + } + }, + "node_modules/nock": { + "version": "13.2.9", + "resolved": "https://registry.npmjs.org/nock/-/nock-13.2.9.tgz", + "integrity": "sha512-1+XfJNYF1cjGB+TKMWi29eZ0b82QOvQs2YoLNzbpWGqFMtRQHTa57osqdGj4FrFPgkO4D4AZinzUJR9VvW3QUA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.21", + "propagate": "^2.0.0" + }, + "engines": { + "node": ">= 10.13" + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", + "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/oidc-provider": { + "version": "7.14.3", + "resolved": "https://registry.npmjs.org/oidc-provider/-/oidc-provider-7.14.3.tgz", + "integrity": "sha512-+TB/JSB6jXyr5Ti2bqOSwDKI6ldc23XlHkgQTFUIjFm2P6SuTkmcXpvF3KF8kDWreSxlKwXwh7ubn9+9yR7CGA==", + "dependencies": { + "@koa/cors": "^3.3.0", + "cacheable-lookup": "^6.0.4", + "debug": "^4.3.4", + "ejs": "^3.1.8", + "got": "^11.8.5", + "jose": "^4.10.3", + "jsesc": "^3.0.2", + "koa": "^2.13.4", + "koa-compose": "^4.1.0", + "nanoid": "^3.3.4", + "object-hash": "^3.0.0", + "oidc-token-hash": "^5.0.1", + "paseto": "^2.1.3", + "quick-lru": "^5.1.1", + "raw-body": "^2.5.1" + }, + "engines": { + "node": "12 || 14 || 16 || 18" + }, + "funding": { + "url": "https://github.com/sponsors/panva" + }, + "optionalDependencies": { + "paseto3": "npm:paseto@^3.1.0" + } + }, + "node_modules/oidc-token-hash": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.1.tgz", + "integrity": "sha512-EvoOtz6FIEBzE+9q253HsLCVRiK/0doEJ2HCvvqMQb3dHZrP3WlJKYtJ55CRTw4jmYomzH4wkPuCj/I3ZvpKxQ==", + "engines": { + "node": "^10.13.0 || >=12.0.0" + } + }, + "node_modules/on-exit-leak-free": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.0.tgz", + "integrity": "sha512-VuCaZZAjReZ3vUwgOB8LxAosIurDiAW0s13rI1YwmaP++jvcxP77AWoQvenZebpCA2m8WC1/EosPYPMjnRAp/w==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/only": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/only/-/only-0.0.2.tgz", + "integrity": "sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ==" + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-2.0.0.tgz", + "integrity": "sha512-uo0Z9JJeWzv8BG+tRcapBKNJ0dro9cLyczGzulS6EfeyAdeC9sbojtW6XwvYxJkEne9En+J2XEl4zyglVeIwFg==", + "dev": true, + "dependencies": { + "callsites": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/paseto": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/paseto/-/paseto-2.1.3.tgz", + "integrity": "sha512-BNkbvr0ZFDbh3oV13QzT5jXIu8xpFc9r0o5mvWBhDU1GBkVt1IzHK1N6dcYmN7XImrUmPQ0HCUXmoe2WPo8xsg==", + "engines": { + "node": "^12.19.0 || >=14.15.0" + }, + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/paseto3": { + "name": "paseto", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/paseto/-/paseto-3.1.2.tgz", + "integrity": "sha512-TNmRcQFF7xRnkLnJ07gCD5lRB273V4fU1pCy8G2P9CQjffIzKMYa3e8yo6LlrCCjIdv4jjS85Cfz86hl5SHzng==", + "optional": true, + "engines": { + "node": ">=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-to-regexp": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", + "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==", + "dev": true + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pino": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-8.7.0.tgz", + "integrity": "sha512-l9sA5uPxmZzwydhMWUcm1gI0YxNnYl8MfSr2h8cwLvOAzQLBLewzF247h/vqHe3/tt6fgtXeG9wdjjoetdI/vA==", + "dev": true, + "dependencies": { + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.1.1", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "v1.0.0", + "pino-std-serializers": "^6.0.0", + "process-warning": "^2.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^3.1.0", + "thread-stream": "^2.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.0.0.tgz", + "integrity": "sha512-c7vo5OpW4wIS42hUVcT5REsL8ZljsUfBjqV/e2sFxmFEFZiq1XLUp5EYLtuDH6PEHq9W1egWqRbnLUP5FuZmOA==", + "dev": true, + "dependencies": { + "readable-stream": "^4.0.0", + "split2": "^4.0.0" + } + }, + "node_modules/pino-std-serializers": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.0.0.tgz", + "integrity": "sha512-mMMOwSKrmyl+Y12Ri2xhH1lbzQxwwpuru9VjyJpgFIH4asSj88F2csdMwN6+M5g1Ll4rmsYghHLQJw81tgZ7LQ==", + "dev": true + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-warning": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-2.1.0.tgz", + "integrity": "sha512-9C20RLxrZU/rFnxWncDkuF6O999NdIf3E1ws4B0ZeY3sRVPzWBMsYDE2lxjxhiXxg464cQTgKUGm8/i6y2YGXg==", + "dev": true + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/propagate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", + "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "dev": true + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readable-stream": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.2.0.tgz", + "integrity": "sha512-gJrBHsaI3lgBoGMW/jHZsQ/o/TIWiu5ENCJG1BB7fuCKzpFM8GaS2UoBVt9NO+oI+3FcrBNbUkl3ilDe09aY4A==", + "dev": true, + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "dev": true, + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ret": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz", + "integrity": "sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex2": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-2.0.0.tgz", + "integrity": "sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==", + "dev": true, + "dependencies": { + "ret": "~0.2.0" + } + }, + "node_modules/safe-stable-stringify": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.1.tgz", + "integrity": "sha512-dVHE6bMtS/bnL2mwualjc6IxEv1F+OCUpA46pKUj6F8uDbUM0jCCulPqRNPSnWwGNKx5etqMjZYdXtrm5KJZGA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/secure-json-parse": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.6.0.tgz", + "integrity": "sha512-B9osKohb6L+EZ6Kve3wHKfsAClzOC/iISA2vSuCe5Jx5NAKiwitfxx8ZKYapHXr0sYRj7UZInT7pLb3rp2Yx6A==", + "dev": true + }, + "node_modules/selfsigned": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", + "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", + "dev": true, + "dependencies": { + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.5.1.tgz", + "integrity": "sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==", + "dev": true + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sinon": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-12.0.1.tgz", + "integrity": "sha512-iGu29Xhym33ydkAT+aNQFBINakjq69kKO6ByPvTsm3yyIACfyQttRTP03aBP/I8GfhFmLzrnKwNNkr0ORb1udg==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.8.3", + "@sinonjs/fake-timers": "^8.1.0", + "@sinonjs/samsam": "^6.0.2", + "diff": "^5.0.0", + "nise": "^5.1.0", + "supports-color": "^7.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/sinon" + } + }, + "node_modules/sinon/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/sinon/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/slice-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/sonic-boom": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.2.0.tgz", + "integrity": "sha512-SbbZ+Kqj/XIunvIAgUZRlqd6CGQYq71tRRbXR92Za8J/R3Yh4Av+TWENiSiEgnlwckYLyP0YZQWVfyNC0dzLaA==", + "dev": true, + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "node_modules/split2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", + "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==", + "dev": true, + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/superagent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.5.tgz", + "integrity": "sha512-lQVE0Praz7nHiSaJLKBM/cZyi7J0E4io8tWnGSBdBrqAzhzrjQ/F5iGP9Zr29CJC8N5zYdhG2kKaNcB6dKxp7g==", + "dev": true, + "dependencies": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.3", + "debug": "^4.3.4", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.0", + "formidable": "^2.0.1", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.11.0", + "semver": "^7.3.8" + }, + "engines": { + "node": ">=6.4.0 <13 || >=14" + } + }, + "node_modules/superagent/node_modules/formidable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.1.tgz", + "integrity": "sha512-0EcS9wCFEzLvfiks7omJ+SiYJAiD+TzK4Pcw1UlUoGnhUxDcMKjt0P7x8wEb0u6OHu8Nb98WG3nxtlF5C7bvUQ==", + "dev": true, + "dependencies": { + "dezalgo": "^1.0.4", + "hexoid": "^1.0.0", + "once": "^1.4.0", + "qs": "^6.11.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, + "node_modules/superagent/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/supertest": { + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.2.tgz", + "integrity": "sha512-mSmbW/sPpBU6K8w8189ZiHdc62zMe7dCHpC2ktS9tc0/d2DN0FaxNbDJJNFknZD4jCrGJpxkiFoVyemvKgOdwA==", + "dev": true, + "dependencies": { + "methods": "^1.1.2", + "superagent": "^8.0.3" + }, + "engines": { + "node": ">=6.4.0" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/table": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", + "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", + "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/thread-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-2.2.0.tgz", + "integrity": "sha512-rUkv4/fnb4rqy/gGy7VuqK6wE1+1DOCOWy4RMeaV69ZHMP11tQKZvZSip1yTgrKCMZzEMcCL/bKfHvSfDHx+iQ==", + "dev": true, + "dependencies": { + "real-require": "^0.2.0" + } + }, + "node_modules/timekeeper": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/timekeeper/-/timekeeper-2.2.0.tgz", + "integrity": "sha512-W3AmPTJWZkRwu+iSNxPIsLZ2ByADsOLbbLxe46UJyWj3mlYLlwucKiq+/dPm0l9wTzqoF3/2PH0AGFCebjq23A==", + "dev": true + }, + "node_modules/tiny-lru": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-10.0.1.tgz", + "integrity": "sha512-Vst+6kEsWvb17Zpz14sRJV/f8bUWKhqm6Dc+v08iShmIJ/WxqWytHzCTd6m88pS33rE2zpX34TRmOpAJPloNCA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsscmp": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", + "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==", + "engines": { + "node": ">=0.6.x" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/workerpool": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", + "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ylru": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/ylru/-/ylru-1.3.2.tgz", + "integrity": "sha512-RXRJzMiK6U2ye0BlGGZnmpwJDPgakn6aNQ0A7gHRbD4I0uvK4TW6UqkK1V0pp9jskjJBAXd3dRrbzWkqJ+6cxA==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/generator": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz", + "integrity": "sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==", + "dev": true, + "requires": { + "@babel/types": "^7.20.5", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "dependencies": { + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + } + } + }, + "@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "dev": true + }, + "@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "dev": true, + "requires": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "dev": true + }, + "@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", + "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", + "dev": true + }, + "@babel/template": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + } + }, + "@babel/traverse": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.5.tgz", + "integrity": "sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.5", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.20.5", + "@babel/types": "^7.20.5", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", + "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + } + }, + "@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "globals": { + "version": "13.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", + "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + } + } + }, + "@fastify/ajv-compiler": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-3.4.0.tgz", + "integrity": "sha512-69JnK7Cot+ktn7LD5TikP3b7psBPX55tYpQa8WSumt8r117PCa2zwHnImfBtRWYExreJlI48hr0WZaVrTBGj7w==", + "dev": true, + "requires": { + "ajv": "^8.11.0", + "ajv-formats": "^2.1.1", + "fast-uri": "^2.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", + "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, + "@fastify/deepmerge": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@fastify/deepmerge/-/deepmerge-1.3.0.tgz", + "integrity": "sha512-J8TOSBq3SoZbDhM9+R/u77hP93gz/rajSA+K2kGyijPpORPWUXHUpTaleoj+92As0S9uPRP7Oi8IqMf0u+ro6A==", + "dev": true + }, + "@fastify/error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@fastify/error/-/error-3.1.0.tgz", + "integrity": "sha512-jmk3Q822+xi8jVzGsux3mWd+9O4rzVUGCqR2+JlF9LkCeeUmRdxPd2Je6S7IGMk5VTtB0xyB3crRQqklUyQ6dQ==", + "dev": true + }, + "@fastify/fast-json-stringify-compiler": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-4.1.0.tgz", + "integrity": "sha512-cTKBV2J9+u6VaKDhX7HepSfPSzw+F+TSd+k0wzifj4rG+4E5PjSFJCk19P8R6tr/72cuzgGd+mbB3jFT6lvAgw==", + "dev": true, + "requires": { + "fast-json-stringify": "^5.0.0" + } + }, + "@fastify/middie": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@fastify/middie/-/middie-8.1.0.tgz", + "integrity": "sha512-VvUCLfKx2j6KSnh8puT8QW7d5YNzi2fD/4HcFvRQ3a7sHlCo+qtfX2fqzFvNqnMVbNft7GX1JL5if/riUiXsyg==", + "dev": true, + "requires": { + "fastify-plugin": "^4.0.0", + "path-to-regexp": "^6.1.0", + "reusify": "^1.0.4" + } + }, + "@hapi/accept": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@hapi/accept/-/accept-5.0.2.tgz", + "integrity": "sha512-CmzBx/bXUR8451fnZRuZAJRlzgm0Jgu5dltTX/bszmR2lheb9BpyN47Q1RbaGTsvFzn0PXAEs+lXDKfshccYZw==", + "dev": true, + "requires": { + "@hapi/boom": "9.x.x", + "@hapi/hoek": "9.x.x" + } + }, + "@hapi/ammo": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@hapi/ammo/-/ammo-5.0.1.tgz", + "integrity": "sha512-FbCNwcTbnQP4VYYhLNGZmA76xb2aHg9AMPiy18NZyWMG310P5KdFGyA9v2rm5ujrIny77dEEIkMOwl0Xv+fSSA==", + "dev": true, + "requires": { + "@hapi/hoek": "9.x.x" + } + }, + "@hapi/b64": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@hapi/b64/-/b64-5.0.0.tgz", + "integrity": "sha512-ngu0tSEmrezoiIaNGG6rRvKOUkUuDdf4XTPnONHGYfSGRmDqPZX5oJL6HAdKTo1UQHECbdB4OzhWrfgVppjHUw==", + "dev": true, + "requires": { + "@hapi/hoek": "9.x.x" + } + }, + "@hapi/boom": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-9.1.4.tgz", + "integrity": "sha512-Ls1oH8jaN1vNsqcaHVYJrKmgMcKsC1wcp8bujvXrHaAqD2iDYq3HoOwsxwo09Cuda5R5nC0o0IxlrlTuvPuzSw==", + "dev": true, + "requires": { + "@hapi/hoek": "9.x.x" + } + }, + "@hapi/bounce": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@hapi/bounce/-/bounce-2.0.0.tgz", + "integrity": "sha512-JesW92uyzOOyuzJKjoLHM1ThiOvHPOLDHw01YV8yh5nCso7sDwJho1h0Ad2N+E62bZyz46TG3xhAi/78Gsct6A==", + "dev": true, + "requires": { + "@hapi/boom": "9.x.x", + "@hapi/hoek": "9.x.x" + } + }, + "@hapi/bourne": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-2.1.0.tgz", + "integrity": "sha512-i1BpaNDVLJdRBEKeJWkVO6tYX6DMFBuwMhSuWqLsY4ufeTKGVuV5rBsUhxPayXqnnWHgXUAmWK16H/ykO5Wj4Q==", + "dev": true + }, + "@hapi/call": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@hapi/call/-/call-8.0.1.tgz", + "integrity": "sha512-bOff6GTdOnoe5b8oXRV3lwkQSb/LAWylvDMae6RgEWWntd0SHtkYbQukDHKlfaYtVnSAgIavJ0kqszF/AIBb6g==", + "dev": true, + "requires": { + "@hapi/boom": "9.x.x", + "@hapi/hoek": "9.x.x" + } + }, + "@hapi/catbox": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@hapi/catbox/-/catbox-11.1.1.tgz", + "integrity": "sha512-u/8HvB7dD/6X8hsZIpskSDo4yMKpHxFd7NluoylhGrL6cUfYxdQPnvUp9YU2C6F9hsyBVLGulBd9vBN1ebfXOQ==", + "dev": true, + "requires": { + "@hapi/boom": "9.x.x", + "@hapi/hoek": "9.x.x", + "@hapi/podium": "4.x.x", + "@hapi/validate": "1.x.x" + } + }, + "@hapi/catbox-memory": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@hapi/catbox-memory/-/catbox-memory-5.0.1.tgz", + "integrity": "sha512-QWw9nOYJq5PlvChLWV8i6hQHJYfvdqiXdvTupJFh0eqLZ64Xir7mKNi96d5/ZMUAqXPursfNDIDxjFgoEDUqeQ==", + "dev": true, + "requires": { + "@hapi/boom": "9.x.x", + "@hapi/hoek": "9.x.x" + } + }, + "@hapi/content": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@hapi/content/-/content-5.0.2.tgz", + "integrity": "sha512-mre4dl1ygd4ZyOH3tiYBrOUBzV7Pu/EOs8VLGf58vtOEECWed8Uuw6B4iR9AN/8uQt42tB04qpVaMyoMQh0oMw==", + "dev": true, + "requires": { + "@hapi/boom": "9.x.x" + } + }, + "@hapi/cryptiles": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/cryptiles/-/cryptiles-5.1.0.tgz", + "integrity": "sha512-fo9+d1Ba5/FIoMySfMqPBR/7Pa29J2RsiPrl7bkwo5W5o+AN1dAYQRi4SPrPwwVxVGKjgLOEWrsvt1BonJSfLA==", + "dev": true, + "requires": { + "@hapi/boom": "9.x.x" + } + }, + "@hapi/file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@hapi/file/-/file-2.0.0.tgz", + "integrity": "sha512-WSrlgpvEqgPWkI18kkGELEZfXr0bYLtr16iIN4Krh9sRnzBZN6nnWxHFxtsnP684wueEySBbXPDg/WfA9xJdBQ==", + "dev": true + }, + "@hapi/hapi": { + "version": "20.2.2", + "resolved": "https://registry.npmjs.org/@hapi/hapi/-/hapi-20.2.2.tgz", + "integrity": "sha512-crhU6TIKt7QsksWLYctDBAXogk9PYAm7UzdpETyuBHC2pCa6/+B5NykiOVLG/3FCIgHo/raPVtan8bYtByHORQ==", + "dev": true, + "requires": { + "@hapi/accept": "^5.0.1", + "@hapi/ammo": "^5.0.1", + "@hapi/boom": "^9.1.0", + "@hapi/bounce": "^2.0.0", + "@hapi/call": "^8.0.0", + "@hapi/catbox": "^11.1.1", + "@hapi/catbox-memory": "^5.0.0", + "@hapi/heavy": "^7.0.1", + "@hapi/hoek": "^9.0.4", + "@hapi/mimos": "^6.0.0", + "@hapi/podium": "^4.1.1", + "@hapi/shot": "^5.0.5", + "@hapi/somever": "^3.0.0", + "@hapi/statehood": "^7.0.4", + "@hapi/subtext": "^7.0.3", + "@hapi/teamwork": "^5.1.1", + "@hapi/topo": "^5.0.0", + "@hapi/validate": "^1.1.1" + } + }, + "@hapi/heavy": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@hapi/heavy/-/heavy-7.0.1.tgz", + "integrity": "sha512-vJ/vzRQ13MtRzz6Qd4zRHWS3FaUc/5uivV2TIuExGTM9Qk+7Zzqj0e2G7EpE6KztO9SalTbiIkTh7qFKj/33cA==", + "dev": true, + "requires": { + "@hapi/boom": "9.x.x", + "@hapi/hoek": "9.x.x", + "@hapi/validate": "1.x.x" + } + }, + "@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "dev": true + }, + "@hapi/iron": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/iron/-/iron-6.0.0.tgz", + "integrity": "sha512-zvGvWDufiTGpTJPG1Y/McN8UqWBu0k/xs/7l++HVU535NLHXsHhy54cfEMdW7EjwKfbBfM9Xy25FmTiobb7Hvw==", + "dev": true, + "requires": { + "@hapi/b64": "5.x.x", + "@hapi/boom": "9.x.x", + "@hapi/bourne": "2.x.x", + "@hapi/cryptiles": "5.x.x", + "@hapi/hoek": "9.x.x" + } + }, + "@hapi/mimos": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/mimos/-/mimos-6.0.0.tgz", + "integrity": "sha512-Op/67tr1I+JafN3R3XN5DucVSxKRT/Tc+tUszDwENoNpolxeXkhrJ2Czt6B6AAqrespHoivhgZBWYSuANN9QXg==", + "dev": true, + "requires": { + "@hapi/hoek": "9.x.x", + "mime-db": "1.x.x" + } + }, + "@hapi/nigel": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@hapi/nigel/-/nigel-4.0.2.tgz", + "integrity": "sha512-ht2KoEsDW22BxQOEkLEJaqfpoKPXxi7tvabXy7B/77eFtOyG5ZEstfZwxHQcqAiZhp58Ae5vkhEqI03kawkYNw==", + "dev": true, + "requires": { + "@hapi/hoek": "^9.0.4", + "@hapi/vise": "^4.0.0" + } + }, + "@hapi/pez": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@hapi/pez/-/pez-5.0.3.tgz", + "integrity": "sha512-mpikYRJjtrbJgdDHG/H9ySqYqwJ+QU/D7FXsYciS9P7NYBXE2ayKDAy3H0ou6CohOCaxPuTV4SZ0D936+VomHA==", + "dev": true, + "requires": { + "@hapi/b64": "5.x.x", + "@hapi/boom": "9.x.x", + "@hapi/content": "^5.0.2", + "@hapi/hoek": "9.x.x", + "@hapi/nigel": "4.x.x" + } + }, + "@hapi/podium": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@hapi/podium/-/podium-4.1.3.tgz", + "integrity": "sha512-ljsKGQzLkFqnQxE7qeanvgGj4dejnciErYd30dbrYzUOF/FyS/DOF97qcrT3bhoVwCYmxa6PEMhxfCPlnUcD2g==", + "dev": true, + "requires": { + "@hapi/hoek": "9.x.x", + "@hapi/teamwork": "5.x.x", + "@hapi/validate": "1.x.x" + } + }, + "@hapi/shot": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@hapi/shot/-/shot-5.0.5.tgz", + "integrity": "sha512-x5AMSZ5+j+Paa8KdfCoKh+klB78otxF+vcJR/IoN91Vo2e5ulXIW6HUsFTCU+4W6P/Etaip9nmdAx2zWDimB2A==", + "dev": true, + "requires": { + "@hapi/hoek": "9.x.x", + "@hapi/validate": "1.x.x" + } + }, + "@hapi/somever": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@hapi/somever/-/somever-3.0.1.tgz", + "integrity": "sha512-4ZTSN3YAHtgpY/M4GOtHUXgi6uZtG9nEZfNI6QrArhK0XN/RDVgijlb9kOmXwCR5VclDSkBul9FBvhSuKXx9+w==", + "dev": true, + "requires": { + "@hapi/bounce": "2.x.x", + "@hapi/hoek": "9.x.x" + } + }, + "@hapi/statehood": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@hapi/statehood/-/statehood-7.0.4.tgz", + "integrity": "sha512-Fia6atroOVmc5+2bNOxF6Zv9vpbNAjEXNcUbWXavDqhnJDlchwUUwKS5LCi5mGtCTxRhUKKHwuxuBZJkmLZ7fw==", + "dev": true, + "requires": { + "@hapi/boom": "9.x.x", + "@hapi/bounce": "2.x.x", + "@hapi/bourne": "2.x.x", + "@hapi/cryptiles": "5.x.x", + "@hapi/hoek": "9.x.x", + "@hapi/iron": "6.x.x", + "@hapi/validate": "1.x.x" + } + }, + "@hapi/subtext": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@hapi/subtext/-/subtext-7.0.4.tgz", + "integrity": "sha512-Y72moHhbRuO8kwBHFEnCRw7oOnhNh4Pl+aonxAze18jkyMpE4Gwz4lNID7ei8vd3lpXC2rKdkxXJgtfY+WttRw==", + "dev": true, + "requires": { + "@hapi/boom": "9.x.x", + "@hapi/bourne": "2.x.x", + "@hapi/content": "^5.0.2", + "@hapi/file": "2.x.x", + "@hapi/hoek": "9.x.x", + "@hapi/pez": "^5.0.1", + "@hapi/wreck": "17.x.x" + } + }, + "@hapi/teamwork": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@hapi/teamwork/-/teamwork-5.1.1.tgz", + "integrity": "sha512-1oPx9AE5TIv+V6Ih54RP9lTZBso3rP8j4Xhb6iSVwPXtAM+sDopl5TFMv5Paw73UnpZJ9gjcrTE1BXrWt9eQrg==", + "dev": true + }, + "@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "dev": true, + "requires": { + "@hapi/hoek": "^9.0.0" + } + }, + "@hapi/validate": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@hapi/validate/-/validate-1.1.3.tgz", + "integrity": "sha512-/XMR0N0wjw0Twzq2pQOzPBZlDzkekGcoCtzO314BpIEsbXdYGthQUbxgkGDf4nhk1+IPDAsXqWjMohRQYO06UA==", + "dev": true, + "requires": { + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0" + } + }, + "@hapi/vise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@hapi/vise/-/vise-4.0.0.tgz", + "integrity": "sha512-eYyLkuUiFZTer59h+SGy7hUm+qE9p+UemePTHLlIWppEd+wExn3Df5jO04bFQTm7nleF5V8CtuYQYb+VFpZ6Sg==", + "dev": true, + "requires": { + "@hapi/hoek": "9.x.x" + } + }, + "@hapi/wreck": { + "version": "17.2.0", + "resolved": "https://registry.npmjs.org/@hapi/wreck/-/wreck-17.2.0.tgz", + "integrity": "sha512-pJ5kjYoRPYDv+eIuiLQqhGon341fr2bNIYZjuotuPJG/3Ilzr/XtI+JAp0A86E2bYfsS3zBPABuS2ICkaXFT8g==", + "dev": true, + "requires": { + "@hapi/boom": "9.x.x", + "@hapi/bourne": "2.x.x", + "@hapi/hoek": "9.x.x" + } + }, + "@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "@koa/cors": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@koa/cors/-/cors-3.4.3.tgz", + "integrity": "sha512-WPXQUaAeAMVaLTEFpoq3T2O1C+FstkjJnDQqy95Ck1UdILajsRhu6mhJ8H2f4NFPRBoCNN+qywTJfq/gGki5mw==", + "requires": { + "vary": "^1.1.2" + } + }, + "@koa/ejs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@koa/ejs/-/ejs-5.0.0.tgz", + "integrity": "sha512-luxtlG1SEfAvbuMbsJYwxXXrXtESslbJsukeKnUiaBmtpkdmNV3M7iL6Ygm8oX67rnPd7tNCJpd7rmFSSBsHig==", + "dev": true, + "requires": { + "debug": "^4.3.4", + "ejs": "^3.1.8" + } + }, + "@panva/asn1.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@panva/asn1.js/-/asn1.js-1.0.0.tgz", + "integrity": "sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw==", + "dev": true + }, + "@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==" + }, + "@sinonjs/commons": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", + "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@sinonjs/samsam": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-6.1.3.tgz", + "integrity": "sha512-nhOb2dWPeb1sd3IQXL/dVPnKHDOAFfvichtBf4xV00/rU1QbPCQqKMbvIheIjqwVjh7qIgf2AHTHi391yMOMpQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", + "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", + "dev": true + }, + "@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "requires": { + "defer-to-connect": "^2.0.0" + } + }, + "@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "requires": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "@types/formidable": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@types/formidable/-/formidable-1.2.5.tgz", + "integrity": "sha512-zu3mQJa4hDNubEMViSj937602XdDGzK7Q5pJ5QmLUbNxclbo9tZGt5jtwM352ssZ+pqo5V4H14TBvT/ALqQQcA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/http-cache-semantics": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", + "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==" + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "requires": { + "@types/node": "*" + } + }, + "@types/node": { + "version": "18.11.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.10.tgz", + "integrity": "sha512-juG3RWMBOqcOuXC643OAdSA525V44cVgGV6dUDuiFtss+8Fk5x1hI93Rsld43VeJVIeqlP9I7Fn9/qaVqoEAuQ==" + }, + "@types/responselike": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "requires": { + "@types/node": "*" + } + }, + "@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "abstract-logging": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz", + "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==", + "dev": true + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "requires": { + "ajv": "^8.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", + "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, + "ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "array-includes": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + } + }, + "array.prototype.flat": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + } + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "dev": true + }, + "avvio": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/avvio/-/avvio-8.2.0.tgz", + "integrity": "sha512-bbCQdg7bpEv6kGH41RO/3B2/GMMmJSo2iBK+X8AWN9mujtfUipMDfIjsgHCfpnKqoGEQrrmCDKSa5OQ19+fDmg==", + "dev": true, + "requires": { + "archy": "^1.0.0", + "debug": "^4.0.0", + "fastq": "^1.6.1" + } + }, + "babel-eslint": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", + "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0", + "eslint-visitor-keys": "^1.0.0", + "resolve": "^1.12.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "base64url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", + "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==", + "dev": true + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "cache-content-type": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-content-type/-/cache-content-type-1.0.1.tgz", + "integrity": "sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==", + "requires": { + "mime-types": "^2.1.18", + "ylru": "^1.2.0" + } + }, + "cacheable-lookup": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-6.1.0.tgz", + "integrity": "sha512-KJ/Dmo1lDDhmW2XDPMo+9oiy/CeqosPguPCrgcVzKyZrL6pM1gU2GmPY/xo6OQPTUaA/c0kwHuywB4E6nmT9ww==" + }, + "cacheable-request": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", + "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "chai": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "dev": true + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "clear-module": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/clear-module/-/clear-module-4.1.2.tgz", + "integrity": "sha512-LWAxzHqdHsAZlPlEyJ2Poz6AIs384mPeqLVCru2p0BrP9G/kVGuhNyZYClLO6cXlnuJjzC8xtsJIuMjKqLXoAw==", + "dev": true, + "requires": { + "parent-module": "^2.0.0", + "resolve-from": "^5.0.0" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "requires": { + "mimic-response": "^1.0.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==" + }, + "co-body": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/co-body/-/co-body-5.2.0.tgz", + "integrity": "sha512-sX/LQ7LqUhgyaxzbe7IqwPeTr2yfpfUIQ/dgpKo6ZI4y4lpQA0YxAomWIY+7I7rHWcG02PG+OuPREzMW/5tszQ==", + "dev": true, + "requires": { + "inflation": "^2.0.0", + "qs": "^6.4.0", + "raw-body": "^2.2.0", + "type-is": "^1.6.14" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "confusing-browser-globals": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", + "dev": true + }, + "connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "requires": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "cookiejar": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.3.tgz", + "integrity": "sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ==", + "dev": true + }, + "cookies": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.8.0.tgz", + "integrity": "sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow==", + "requires": { + "depd": "~2.0.0", + "keygrip": "~1.1.0" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + }, + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "requires": { + "mimic-response": "^3.1.0" + }, + "dependencies": { + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" + } + } + }, + "deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw==" + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==" + }, + "define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dev": true, + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" + }, + "dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "requires": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "ejs": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz", + "integrity": "sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==", + "requires": { + "jake": "^10.8.5" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "es-abstract": { + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", + "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.3", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.2", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" + } + }, + "es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "eslint": { + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "dev": true, + "requires": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + }, + "globals": { + "version": "13.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", + "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "eslint-config-airbnb-base": { + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz", + "integrity": "sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA==", + "dev": true, + "requires": { + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", + "object.entries": "^1.1.2" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "resolve": "^1.20.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-module-utils": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", + "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", + "dev": true, + "requires": { + "debug": "^3.2.7" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-plugin-import": { + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", + "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "dev": true, + "requires": { + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.3", + "has": "^1.0.3", + "is-core-module": "^2.8.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.5", + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true + }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, + "express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dev": true, + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + } + } + }, + "fast-decode-uri-component": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", + "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-json-stringify": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-5.4.1.tgz", + "integrity": "sha512-P7S9WXEnMqu6seBnzAFmgZ+T3KCD+Do+pNIJsmk/6OlDHZVjl6KzsQB3TFHKQb2Q8N7C9l31WS7/LZGF5hT1FA==", + "dev": true, + "requires": { + "@fastify/deepmerge": "^1.0.0", + "ajv": "^8.10.0", + "ajv-formats": "^2.1.1", + "fast-deep-equal": "^3.1.3", + "fast-uri": "^2.1.0", + "rfdc": "^1.2.0" + }, + "dependencies": { + "ajv": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", + "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fast-querystring": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.0.0.tgz", + "integrity": "sha512-3LQi62IhQoDlmt4ULCYmh17vRO2EtS7hTSsG4WwoKWgV7GLMKBOecEh+aiavASnLx8I2y89OD33AGLo0ccRhzA==", + "dev": true, + "requires": { + "fast-decode-uri-component": "^1.0.1" + } + }, + "fast-redact": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.1.2.tgz", + "integrity": "sha512-+0em+Iya9fKGfEQGcd62Yv6onjBmmhV1uh86XVfOU8VwAe6kaFdQCWI9s0/Nnugx5Vd9tdbZ7e6gE2tR9dzXdw==", + "dev": true + }, + "fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true + }, + "fast-uri": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-2.1.0.tgz", + "integrity": "sha512-qKRta6N7BWEFVlyonVY/V+BMLgFqktCUV0QjT259ekAIlbVrMaFnFLxJ4s/JPl4tou56S1BzPufI60bLe29fHA==", + "dev": true + }, + "fastify": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/fastify/-/fastify-4.10.2.tgz", + "integrity": "sha512-0T+4zI6N3S8ex0LCZi3H4FasJR4AzWw834fUkPWvV8r6GBJkLmAOfFxH8f5V29Plef24IK0QSQD/tz1Nx+1UOA==", + "dev": true, + "requires": { + "@fastify/ajv-compiler": "^3.3.1", + "@fastify/error": "^3.0.0", + "@fastify/fast-json-stringify-compiler": "^4.1.0", + "abstract-logging": "^2.0.1", + "avvio": "^8.2.0", + "content-type": "^1.0.4", + "find-my-way": "^7.3.0", + "light-my-request": "^5.6.1", + "pino": "^8.5.0", + "process-warning": "^2.0.0", + "proxy-addr": "^2.0.7", + "rfdc": "^1.3.0", + "secure-json-parse": "^2.5.0", + "semver": "^7.3.7", + "tiny-lru": "^10.0.0" + } + }, + "fastify-plugin": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-4.4.0.tgz", + "integrity": "sha512-ovwFQG2qNy3jcCROiWpr94Hs0le+c7N/3t7m9aVwbFhkxcR/esp2xu25dP8e617HpQdmeDv+gFX4zagdUhDByw==", + "dev": true + }, + "fastq": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz", + "integrity": "sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "requires": { + "minimatch": "^5.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.1.tgz", + "integrity": "sha512-362NP+zlprccbEt/SkxKfRMHnNY85V74mVnpUpNyr3F35covl09Kec7/sEFLt3RA4oXmewtoaanoIf67SE5Y5g==", + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true + } + } + }, + "find-my-way": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-7.3.1.tgz", + "integrity": "sha512-kGvM08SOkqvheLcuQ8GW9t/H901Qb9rZEbcNWbXopzy4jDRoaJpJoObPSKf4MnQLZ20ZTp7rL5MpF6rf+pqmyg==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3", + "fast-querystring": "^1.0.0", + "safe-regex2": "^2.0.0" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "formidable": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.6.tgz", + "integrity": "sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==", + "dev": true + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "dev": true + }, + "get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "requires": { + "pump": "^3.0.0" + } + }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "got": { + "version": "11.8.5", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.5.tgz", + "integrity": "sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==", + "requires": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "dependencies": { + "cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==" + } + } + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "requires": { + "has-symbols": "^1.0.2" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "helmet": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-5.1.1.tgz", + "integrity": "sha512-/yX0oVZBggA9cLJh8aw3PPCfedBnbd7J2aowjzsaWwZh7/UFY0nccn/aHAggIgWUFfnykX8GKd3a1pSbrmlcVQ==", + "dev": true + }, + "hexoid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", + "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==", + "dev": true + }, + "http-assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.5.0.tgz", + "integrity": "sha512-uPpH7OKX4H25hBmU6G1jWNaqJGpTXxey+YOUizJUAgu0AjLUeC8D73hTrhvDS5D+GJN1DN1+hhc/eF/wpxtp0w==", + "requires": { + "deep-equal": "~1.0.1", + "http-errors": "~1.8.0" + }, + "dependencies": { + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==" + }, + "http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==" + } + } + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "requires": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "inflation": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/inflation/-/inflation-2.0.0.tgz", + "integrity": "sha512-m3xv4hJYR2oXw4o4Y5l6P5P16WYmazYof+el6Al3f+YlggGj6qT9kImBAnzDelRALnP5d3h4jGBPKzYCizjZZw==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true + }, + "is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "jake": { + "version": "10.8.5", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", + "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==", + "requires": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.1", + "minimatch": "^3.0.4" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jose": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.11.1.tgz", + "integrity": "sha512-YRv4Tk/Wlug8qicwqFNFVEZSdbROCHRAC6qu/i0dyNKr5JQdoa2pIGoS04lLO/jXQX7Z9omoNewYIVIxqZBd9Q==" + }, + "jose2": { + "version": "npm:jose@2.0.6", + "resolved": "https://registry.npmjs.org/jose/-/jose-2.0.6.tgz", + "integrity": "sha512-FVoPY7SflDodE4lknJmbAHSUjLCzE2H1F6MS0RYKMQ8SR+lNccpMf8R4eqkNYyyUjR5qZReOzZo5C5YiHOCjjg==", + "dev": true, + "requires": { + "@panva/asn1.js": "^1.0.0" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==" + }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "just-extend": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", + "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", + "dev": true + }, + "keygrip": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", + "integrity": "sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==", + "requires": { + "tsscmp": "1.0.6" + } + }, + "keyv": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", + "integrity": "sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==", + "requires": { + "json-buffer": "3.0.1" + } + }, + "koa": { + "version": "2.13.4", + "resolved": "https://registry.npmjs.org/koa/-/koa-2.13.4.tgz", + "integrity": "sha512-43zkIKubNbnrULWlHdN5h1g3SEKXOEzoAlRsHOTFpnlDu8JlAOZSMJBLULusuXRequboiwJcj5vtYXKB3k7+2g==", + "requires": { + "accepts": "^1.3.5", + "cache-content-type": "^1.0.0", + "content-disposition": "~0.5.2", + "content-type": "^1.0.4", + "cookies": "~0.8.0", + "debug": "^4.3.2", + "delegates": "^1.0.0", + "depd": "^2.0.0", + "destroy": "^1.0.4", + "encodeurl": "^1.0.2", + "escape-html": "^1.0.3", + "fresh": "~0.5.2", + "http-assert": "^1.3.0", + "http-errors": "^1.6.3", + "is-generator-function": "^1.0.7", + "koa-compose": "^4.1.0", + "koa-convert": "^2.0.0", + "on-finished": "^2.3.0", + "only": "~0.0.2", + "parseurl": "^1.3.2", + "statuses": "^1.5.0", + "type-is": "^1.6.16", + "vary": "^1.1.2" + }, + "dependencies": { + "http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + }, + "dependencies": { + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==" + } + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==" + } + } + }, + "koa-body": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/koa-body/-/koa-body-4.2.0.tgz", + "integrity": "sha512-wdGu7b9amk4Fnk/ytH8GuWwfs4fsB5iNkY8kZPpgQVb04QZSv85T0M8reb+cJmvLE8cjPYvBzRikD3s6qz8OoA==", + "dev": true, + "requires": { + "@types/formidable": "^1.0.31", + "co-body": "^5.1.1", + "formidable": "^1.1.1" + } + }, + "koa-compose": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-4.1.0.tgz", + "integrity": "sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==" + }, + "koa-convert": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/koa-convert/-/koa-convert-2.0.0.tgz", + "integrity": "sha512-asOvN6bFlSnxewce2e/DK3p4tltyfC4VM7ZwuTuepI7dEQVcvpyFuBcEARu1+Hxg8DIwytce2n7jrZtRlPrARA==", + "requires": { + "co": "^4.6.0", + "koa-compose": "^4.1.0" + } + }, + "koa-mount": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/koa-mount/-/koa-mount-4.0.0.tgz", + "integrity": "sha512-rm71jaA/P+6HeCpoRhmCv8KVBIi0tfGuO/dMKicbQnQW/YJntJ6MnnspkodoA4QstMVEZArsCphmd0bJEtoMjQ==", + "dev": true, + "requires": { + "debug": "^4.0.1", + "koa-compose": "^4.1.0" + } + }, + "koa-router": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/koa-router/-/koa-router-10.1.1.tgz", + "integrity": "sha512-z/OzxVjf5NyuNO3t9nJpx7e1oR3FSBAauiwXtMQu4ppcnuNZzTaQ4p21P8A6r2Es8uJJM339oc4oVW+qX7SqnQ==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "http-errors": "^1.7.3", + "koa-compose": "^4.1.0", + "methods": "^1.1.2", + "path-to-regexp": "^6.1.0" + }, + "dependencies": { + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true + }, + "http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true + } + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "light-my-request": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-5.8.0.tgz", + "integrity": "sha512-4BtD5C+VmyTpzlDPCZbsatZMJVgUIciSOwYhJDCbLffPZ35KoDkDj4zubLeHDEb35b4kkPeEv5imbh+RJxK/Pg==", + "dev": true, + "requires": { + "cookie": "^0.5.0", + "process-warning": "^2.0.0", + "set-cookie-parser": "^2.4.1" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "loupe": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "dev": true, + "requires": { + "get-func-name": "^2.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true + }, + "mocha": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", + "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", + "dev": true, + "requires": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.3", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "4.2.1", + "ms": "2.1.3", + "nanoid": "3.3.1", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "workerpool": "6.2.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "dependencies": { + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "requires": { + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "minimatch": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", + "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "nanoid": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, + "nise": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.2.tgz", + "integrity": "sha512-+gQjFi8v+tkfCuSCxfURHLhRhniE/+IaYbIphxAN2JRR9SHKhY8hgXpaXiYfHdw+gcGe4buxgbprBQFab9FkhA==", + "dev": true, + "requires": { + "@sinonjs/commons": "^2.0.0", + "@sinonjs/fake-timers": "^7.0.4", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + }, + "dependencies": { + "@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-7.1.2.tgz", + "integrity": "sha512-iQADsW4LBMISqZ6Ci1dupJL9pprqwcVFTcOsEmQOEhW+KLCVn/Y4Jrvg2k19fIHCp+iFprriYPTdRcQR8NbUPg==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + }, + "dependencies": { + "@sinonjs/commons": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + } + } + }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "requires": { + "isarray": "0.0.1" + } + } + } + }, + "nock": { + "version": "13.2.9", + "resolved": "https://registry.npmjs.org/nock/-/nock-13.2.9.tgz", + "integrity": "sha512-1+XfJNYF1cjGB+TKMWi29eZ0b82QOvQs2YoLNzbpWGqFMtRQHTa57osqdGj4FrFPgkO4D4AZinzUJR9VvW3QUA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.21", + "propagate": "^2.0.0" + } + }, + "node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==" + }, + "object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==" + }, + "object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + } + }, + "object.entries": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", + "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "object.values": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "oidc-provider": { + "version": "7.14.3", + "resolved": "https://registry.npmjs.org/oidc-provider/-/oidc-provider-7.14.3.tgz", + "integrity": "sha512-+TB/JSB6jXyr5Ti2bqOSwDKI6ldc23XlHkgQTFUIjFm2P6SuTkmcXpvF3KF8kDWreSxlKwXwh7ubn9+9yR7CGA==", + "requires": { + "@koa/cors": "^3.3.0", + "cacheable-lookup": "^6.0.4", + "debug": "^4.3.4", + "ejs": "^3.1.8", + "got": "^11.8.5", + "jose": "^4.10.3", + "jsesc": "^3.0.2", + "koa": "^2.13.4", + "koa-compose": "^4.1.0", + "nanoid": "^3.3.4", + "object-hash": "^3.0.0", + "oidc-token-hash": "^5.0.1", + "paseto": "^2.1.3", + "paseto3": "npm:paseto@^3.1.0", + "quick-lru": "^5.1.1", + "raw-body": "^2.5.1" + } + }, + "oidc-token-hash": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.1.tgz", + "integrity": "sha512-EvoOtz6FIEBzE+9q253HsLCVRiK/0doEJ2HCvvqMQb3dHZrP3WlJKYtJ55CRTw4jmYomzH4wkPuCj/I3ZvpKxQ==" + }, + "on-exit-leak-free": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.0.tgz", + "integrity": "sha512-VuCaZZAjReZ3vUwgOB8LxAosIurDiAW0s13rI1YwmaP++jvcxP77AWoQvenZebpCA2m8WC1/EosPYPMjnRAp/w==", + "dev": true + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "requires": { + "wrappy": "1" + } + }, + "only": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/only/-/only-0.0.2.tgz", + "integrity": "sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ==" + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==" + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "parent-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-2.0.0.tgz", + "integrity": "sha512-uo0Z9JJeWzv8BG+tRcapBKNJ0dro9cLyczGzulS6EfeyAdeC9sbojtW6XwvYxJkEne9En+J2XEl4zyglVeIwFg==", + "dev": true, + "requires": { + "callsites": "^3.1.0" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "paseto": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/paseto/-/paseto-2.1.3.tgz", + "integrity": "sha512-BNkbvr0ZFDbh3oV13QzT5jXIu8xpFc9r0o5mvWBhDU1GBkVt1IzHK1N6dcYmN7XImrUmPQ0HCUXmoe2WPo8xsg==" + }, + "paseto3": { + "version": "npm:paseto@3.1.2", + "resolved": "https://registry.npmjs.org/paseto/-/paseto-3.1.2.tgz", + "integrity": "sha512-TNmRcQFF7xRnkLnJ07gCD5lRB273V4fU1pCy8G2P9CQjffIzKMYa3e8yo6LlrCCjIdv4jjS85Cfz86hl5SHzng==", + "optional": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-to-regexp": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", + "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==", + "dev": true + }, + "pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pino": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-8.7.0.tgz", + "integrity": "sha512-l9sA5uPxmZzwydhMWUcm1gI0YxNnYl8MfSr2h8cwLvOAzQLBLewzF247h/vqHe3/tt6fgtXeG9wdjjoetdI/vA==", + "dev": true, + "requires": { + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.1.1", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "v1.0.0", + "pino-std-serializers": "^6.0.0", + "process-warning": "^2.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^3.1.0", + "thread-stream": "^2.0.0" + } + }, + "pino-abstract-transport": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.0.0.tgz", + "integrity": "sha512-c7vo5OpW4wIS42hUVcT5REsL8ZljsUfBjqV/e2sFxmFEFZiq1XLUp5EYLtuDH6PEHq9W1egWqRbnLUP5FuZmOA==", + "dev": true, + "requires": { + "readable-stream": "^4.0.0", + "split2": "^4.0.0" + } + }, + "pino-std-serializers": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.0.0.tgz", + "integrity": "sha512-mMMOwSKrmyl+Y12Ri2xhH1lbzQxwwpuru9VjyJpgFIH4asSj88F2csdMwN6+M5g1Ll4rmsYghHLQJw81tgZ7LQ==", + "dev": true + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true + }, + "process-warning": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-2.1.0.tgz", + "integrity": "sha512-9C20RLxrZU/rFnxWncDkuF6O999NdIf3E1ws4B0ZeY3sRVPzWBMsYDE2lxjxhiXxg464cQTgKUGm8/i6y2YGXg==", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "propagate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", + "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", + "dev": true + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, + "quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "dev": true + }, + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==" + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true + }, + "raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "readable-stream": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.2.0.tgz", + "integrity": "sha512-gJrBHsaI3lgBoGMW/jHZsQ/o/TIWiu5ENCJG1BB7fuCKzpFM8GaS2UoBVt9NO+oI+3FcrBNbUkl3ilDe09aY4A==", + "dev": true, + "requires": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "dev": true + }, + "regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "requires": { + "lowercase-keys": "^2.0.0" + } + }, + "ret": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz", + "integrity": "sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + } + }, + "safe-regex2": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-2.0.0.tgz", + "integrity": "sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==", + "dev": true, + "requires": { + "ret": "~0.2.0" + } + }, + "safe-stable-stringify": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.1.tgz", + "integrity": "sha512-dVHE6bMtS/bnL2mwualjc6IxEv1F+OCUpA46pKUj6F8uDbUM0jCCulPqRNPSnWwGNKx5etqMjZYdXtrm5KJZGA==", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "secure-json-parse": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.6.0.tgz", + "integrity": "sha512-B9osKohb6L+EZ6Kve3wHKfsAClzOC/iISA2vSuCe5Jx5NAKiwitfxx8ZKYapHXr0sYRj7UZInT7pLb3rp2Yx6A==", + "dev": true + }, + "selfsigned": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", + "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", + "dev": true, + "requires": { + "node-forge": "^1" + } + }, + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + } + } + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "set-cookie-parser": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.5.1.tgz", + "integrity": "sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==", + "dev": true + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "sinon": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-12.0.1.tgz", + "integrity": "sha512-iGu29Xhym33ydkAT+aNQFBINakjq69kKO6ByPvTsm3yyIACfyQttRTP03aBP/I8GfhFmLzrnKwNNkr0ORb1udg==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.8.3", + "@sinonjs/fake-timers": "^8.1.0", + "@sinonjs/samsam": "^6.0.2", + "diff": "^5.0.0", + "nise": "^5.1.0", + "supports-color": "^7.2.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } + } + }, + "sonic-boom": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.2.0.tgz", + "integrity": "sha512-SbbZ+Kqj/XIunvIAgUZRlqd6CGQYq71tRRbXR92Za8J/R3Yh4Av+TWENiSiEgnlwckYLyP0YZQWVfyNC0dzLaA==", + "dev": true, + "requires": { + "atomic-sleep": "^1.0.0" + } + }, + "split2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", + "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "superagent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.5.tgz", + "integrity": "sha512-lQVE0Praz7nHiSaJLKBM/cZyi7J0E4io8tWnGSBdBrqAzhzrjQ/F5iGP9Zr29CJC8N5zYdhG2kKaNcB6dKxp7g==", + "dev": true, + "requires": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.3", + "debug": "^4.3.4", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.0", + "formidable": "^2.0.1", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.11.0", + "semver": "^7.3.8" + }, + "dependencies": { + "formidable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.1.tgz", + "integrity": "sha512-0EcS9wCFEzLvfiks7omJ+SiYJAiD+TzK4Pcw1UlUoGnhUxDcMKjt0P7x8wEb0u6OHu8Nb98WG3nxtlF5C7bvUQ==", + "dev": true, + "requires": { + "dezalgo": "^1.0.4", + "hexoid": "^1.0.0", + "once": "^1.4.0", + "qs": "^6.11.0" + } + }, + "mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true + } + } + }, + "supertest": { + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.2.tgz", + "integrity": "sha512-mSmbW/sPpBU6K8w8189ZiHdc62zMe7dCHpC2ktS9tc0/d2DN0FaxNbDJJNFknZD4jCrGJpxkiFoVyemvKgOdwA==", + "dev": true, + "requires": { + "methods": "^1.1.2", + "superagent": "^8.0.3" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "table": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", + "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", + "dev": true, + "requires": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "ajv": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", + "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "thread-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-2.2.0.tgz", + "integrity": "sha512-rUkv4/fnb4rqy/gGy7VuqK6wE1+1DOCOWy4RMeaV69ZHMP11tQKZvZSip1yTgrKCMZzEMcCL/bKfHvSfDHx+iQ==", + "dev": true, + "requires": { + "real-require": "^0.2.0" + } + }, + "timekeeper": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/timekeeper/-/timekeeper-2.2.0.tgz", + "integrity": "sha512-W3AmPTJWZkRwu+iSNxPIsLZ2ByADsOLbbLxe46UJyWj3mlYLlwucKiq+/dPm0l9wTzqoF3/2PH0AGFCebjq23A==", + "dev": true + }, + "tiny-lru": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-10.0.1.tgz", + "integrity": "sha512-Vst+6kEsWvb17Zpz14sRJV/f8bUWKhqm6Dc+v08iShmIJ/WxqWytHzCTd6m88pS33rE2zpX34TRmOpAJPloNCA==", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "tsconfig-paths": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "tsscmp": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", + "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==" + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "workerpool": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", + "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + } + }, + "ylru": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/ylru/-/ylru-1.3.2.tgz", + "integrity": "sha512-RXRJzMiK6U2ye0BlGGZnmpwJDPgakn6aNQ0A7gHRbD4I0uvK4TW6UqkK1V0pp9jskjJBAXd3dRrbzWkqJ+6cxA==" + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } + } +} diff --git a/scripts/e2e/oidc-provider/package.json b/scripts/e2e/oidc-provider/package.json new file mode 100644 index 00000000..80b69d76 --- /dev/null +++ b/scripts/e2e/oidc-provider/package.json @@ -0,0 +1,60 @@ +{ + "name": "node-oidc-provider", + "version": "7.14.1", + "description": "OAuth 2.0 Authorization Server implementation for Node.js with OpenID Connect", + "scripts": { + "s": "node standalone.js" + }, + "dependencies": { + "@koa/cors": "^3.3.0", + "cacheable-lookup": "^6.0.4", + "debug": "^4.3.4", + "ejs": "^3.1.8", + "got": "^11.8.5", + "jose": "^4.10.3", + "jsesc": "^3.0.2", + "koa": "^2.13.4", + "koa-compose": "^4.1.0", + "nanoid": "^3.3.4", + "object-hash": "^3.0.0", + "oidc-provider": "^7.14.1", + "oidc-token-hash": "^5.0.1", + "paseto": "^2.1.3", + "quick-lru": "^5.1.1", + "raw-body": "^2.5.1" + }, + "optionalDependencies": { + "paseto3": "npm:paseto@^3.1.0" + }, + "devDependencies": { + "@fastify/middie": "^8.0.0", + "@hapi/hapi": "^20.2.2", + "@koa/ejs": "^5.0.0", + "babel-eslint": "^10.1.0", + "base64url": "^3.0.1", + "chai": "^4.3.6", + "clear-module": "^4.1.2", + "connect": "^3.7.0", + "eslint": "^7.32.0", + "eslint-config-airbnb-base": "^14.2.1", + "eslint-plugin-import": "^2.26.0", + "express": "^4.18.1", + "fastify": "^4.9.2", + "helmet": "^5.1.0", + "jose2": "npm:jose@^2.0.6", + "koa-body": "^4.2.0", + "koa-mount": "^4.0.0", + "koa-router": "^10.1.1", + "lodash": "^4.17.21", + "mocha": "^9.2.2", + "moment": "^2.29.4", + "nock": "^13.2.8", + "selfsigned": "^2.0.1", + "sinon": "^12.0.1", + "supertest": "^6.3.1", + "timekeeper": "^2.2.0" + }, + "engines": { + "node": "12 || 14 || 16 || 18" + } +} \ No newline at end of file diff --git a/scripts/e2e/oidc-provider/routes/express.js b/scripts/e2e/oidc-provider/routes/express.js new file mode 100644 index 00000000..0ca9ab14 --- /dev/null +++ b/scripts/e2e/oidc-provider/routes/express.js @@ -0,0 +1,175 @@ +/* eslint-disable no-console, max-len, camelcase, no-unused-vars */ +const { strict: assert } = require('assert'); +const querystring = require('querystring'); +const { inspect } = require('util'); + +const isEmpty = require('lodash/isEmpty'); +const { urlencoded } = require('express'); // eslint-disable-line import/no-unresolved + +const Account = require('../support/account'); + +const body = urlencoded({ extended: false }); + +const keys = new Set(); +const debug = (obj) => querystring.stringify(Object.entries(obj).reduce((acc, [key, value]) => { + keys.add(key); + if (isEmpty(value)) return acc; + acc[key] = inspect(value, { depth: null }); + return acc; +}, {}), '
', ': ', { + encodeURIComponent(value) { return keys.has(value) ? `${value}` : value; }, +}); + +module.exports = (app, provider) => { + const { constructor: { errors: { SessionNotFound } } } = provider; + + app.use((req, res, next) => { + const orig = res.render; + // you'll probably want to use a full blown render engine capable of layouts + res.render = (view, locals) => { + app.render(view, locals, (err, html) => { + if (err) throw err; + orig.call(res, '_layout', { + ...locals, + body: html, + }); + }); + }; + next(); + }); + + function setNoCache(req, res, next) { + res.set('cache-control', 'no-store'); + next(); + } + + app.get('/interaction/:uid', setNoCache, async (req, res, next) => { + try { + const { + uid, prompt, params, session, + } = await provider.interactionDetails(req, res); + + const client = await provider.Client.find(params.client_id); + + switch (prompt.name) { + case 'login': { + return res.render('login', { + client, + uid, + details: prompt.details, + params, + title: 'Sign-in', + session: session ? debug(session) : undefined, + dbg: { + params: debug(params), + prompt: debug(prompt), + }, + }); + } + case 'consent': { + return res.render('interaction', { + client, + uid, + details: prompt.details, + params, + title: 'Authorize', + session: session ? debug(session) : undefined, + dbg: { + params: debug(params), + prompt: debug(prompt), + }, + }); + } + default: + return undefined; + } + } catch (err) { + return next(err); + } + }); + + app.post('/interaction/:uid/login', setNoCache, body, async (req, res, next) => { + try { + const { prompt: { name } } = await provider.interactionDetails(req, res); + assert.equal(name, 'login'); + const account = await Account.findByLogin(req.body.login); + + const result = { + login: { + accountId: account.accountId, + }, + }; + + await provider.interactionFinished(req, res, result, { mergeWithLastSubmission: false }); + } catch (err) { + next(err); + } + }); + + app.post('/interaction/:uid/confirm', setNoCache, body, async (req, res, next) => { + try { + const interactionDetails = await provider.interactionDetails(req, res); + const { prompt: { name, details }, params, session: { accountId } } = interactionDetails; + assert.equal(name, 'consent'); + + let { grantId } = interactionDetails; + let grant; + + if (grantId) { + // we'll be modifying existing grant in existing session + grant = await provider.Grant.find(grantId); + } else { + // we're establishing a new grant + grant = new provider.Grant({ + accountId, + clientId: params.client_id, + }); + } + + if (details.missingOIDCScope) { + grant.addOIDCScope(details.missingOIDCScope.join(' ')); + } + if (details.missingOIDCClaims) { + grant.addOIDCClaims(details.missingOIDCClaims); + } + if (details.missingResourceScopes) { + // eslint-disable-next-line no-restricted-syntax + for (const [indicator, scopes] of Object.entries(details.missingResourceScopes)) { + grant.addResourceScope(indicator, scopes.join(' ')); + } + } + + grantId = await grant.save(); + + const consent = {}; + if (!interactionDetails.grantId) { + // we don't have to pass grantId to consent, we're just modifying existing one + consent.grantId = grantId; + } + + const result = { consent }; + await provider.interactionFinished(req, res, result, { mergeWithLastSubmission: true }); + } catch (err) { + next(err); + } + }); + + app.get('/interaction/:uid/abort', setNoCache, async (req, res, next) => { + try { + const result = { + error: 'access_denied', + error_description: 'End-User aborted interaction', + }; + await provider.interactionFinished(req, res, result, { mergeWithLastSubmission: false }); + } catch (err) { + next(err); + } + }); + + app.use((err, req, res, next) => { + if (err instanceof SessionNotFound) { + // handle interaction expired / session not found error + } + next(err); + }); +}; diff --git a/scripts/e2e/oidc-provider/routes/koa.js b/scripts/e2e/oidc-provider/routes/koa.js new file mode 100644 index 00000000..0648a754 --- /dev/null +++ b/scripts/e2e/oidc-provider/routes/koa.js @@ -0,0 +1,215 @@ +/* eslint-disable no-console, max-len, camelcase, no-unused-vars */ +const { strict: assert } = require('assert'); +const querystring = require('querystring'); +const crypto = require('crypto'); +const { inspect } = require('util'); + +const isEmpty = require('lodash/isEmpty'); +const bodyParser = require('koa-body'); +const Router = require('koa-router'); + +const { renderError } = require('../node_modules/oidc-provider/lib/helpers/defaults')(); // make your own, you'll need it anyway +const Account = require('../support/account'); + +const keys = new Set(); +const debug = (obj) => querystring.stringify(Object.entries(obj).reduce((acc, [key, value]) => { + keys.add(key); + if (isEmpty(value)) return acc; + acc[key] = inspect(value, { depth: null }); + return acc; +}, {}), '
', ': ', { + encodeURIComponent(value) { return keys.has(value) ? `${value}` : value; }, +}); + +module.exports = (provider) => { + const router = new Router(); + const { constructor: { errors: { SessionNotFound } } } = provider; + + router.use(async (ctx, next) => { + ctx.set('cache-control', 'no-store'); + try { + await next(); + } catch (err) { + if (err instanceof SessionNotFound) { + ctx.status = err.status; + const { message: error, error_description } = err; + renderError(ctx, { error, error_description }, err); + } else { + throw err; + } + } + }); + + router.get('/interaction/:uid', async (ctx, next) => { + const { + uid, prompt, params, session, + } = await provider.interactionDetails(ctx.req, ctx.res); + const client = await provider.Client.find(params.client_id); + + switch (prompt.name) { + case 'login': { + return ctx.render('login', { + client, + uid, + details: prompt.details, + params, + title: 'Sign-in', + google: ctx.google, + session: session ? debug(session) : undefined, + dbg: { + params: debug(params), + prompt: debug(prompt), + }, + }); + } + case 'consent': { + return ctx.render('interaction', { + client, + uid, + details: prompt.details, + params, + title: 'Authorize', + session: session ? debug(session) : undefined, + dbg: { + params: debug(params), + prompt: debug(prompt), + }, + }); + } + default: + return next(); + } + }); + + const body = bodyParser({ + text: false, json: false, patchNode: true, patchKoa: true, + }); + + router.get('/interaction/callback/google', (ctx) => { + const nonce = ctx.res.locals.cspNonce; + return ctx.render('repost', { layout: false, upstream: 'google', nonce }); + }); + + router.post('/interaction/:uid/login', body, async (ctx) => { + const { prompt: { name } } = await provider.interactionDetails(ctx.req, ctx.res); + assert.equal(name, 'login'); + + const account = await Account.findByLogin(ctx.request.body.login); + + const result = { + login: { + accountId: account.accountId, + }, + }; + + return provider.interactionFinished(ctx.req, ctx.res, result, { + mergeWithLastSubmission: false, + }); + }); + + router.post('/interaction/:uid/federated', body, async (ctx) => { + const { prompt: { name } } = await provider.interactionDetails(ctx.req, ctx.res); + assert.equal(name, 'login'); + + const path = `/interaction/${ctx.params.uid}/federated`; + + switch (ctx.request.body.upstream) { + case 'google': { + const callbackParams = ctx.google.callbackParams(ctx.req); + + // init + if (!Object.keys(callbackParams).length) { + const state = `${ctx.params.uid}|${crypto.randomBytes(32).toString('hex')}`; + const nonce = crypto.randomBytes(32).toString('hex'); + + ctx.cookies.set('google.state', state, { path, sameSite: 'strict' }); + ctx.cookies.set('google.nonce', nonce, { path, sameSite: 'strict' }); + + ctx.status = 303; + return ctx.redirect(ctx.google.authorizationUrl({ + state, nonce, scope: 'openid email profile', + })); + } + + // callback + const state = ctx.cookies.get('google.state'); + ctx.cookies.set('google.state', null, { path }); + const nonce = ctx.cookies.get('google.nonce'); + ctx.cookies.set('google.nonce', null, { path }); + + const tokenset = await ctx.google.callback(undefined, callbackParams, { state, nonce, response_type: 'id_token' }); + const account = await Account.findByFederated('google', tokenset.claims()); + + const result = { + login: { + accountId: account.accountId, + }, + }; + return provider.interactionFinished(ctx.req, ctx.res, result, { + mergeWithLastSubmission: false, + }); + } + default: + return undefined; + } + }); + + router.post('/interaction/:uid/confirm', body, async (ctx) => { + const interactionDetails = await provider.interactionDetails(ctx.req, ctx.res); + const { prompt: { name, details }, params, session: { accountId } } = interactionDetails; + assert.equal(name, 'consent'); + + let { grantId } = interactionDetails; + let grant; + + if (grantId) { + // we'll be modifying existing grant in existing session + grant = await provider.Grant.find(grantId); + } else { + // we're establishing a new grant + grant = new provider.Grant({ + accountId, + clientId: params.client_id, + }); + } + + if (details.missingOIDCScope) { + grant.addOIDCScope(details.missingOIDCScope.join(' ')); + } + if (details.missingOIDCClaims) { + grant.addOIDCClaims(details.missingOIDCClaims); + } + if (details.missingResourceScopes) { + // eslint-disable-next-line no-restricted-syntax + for (const [indicator, scope] of Object.entries(details.missingResourceScopes)) { + grant.addResourceScope(indicator, scope.join(' ')); + } + } + + grantId = await grant.save(); + + const consent = {}; + if (!interactionDetails.grantId) { + // we don't have to pass grantId to consent, we're just modifying existing one + consent.grantId = grantId; + } + + const result = { consent }; + return provider.interactionFinished(ctx.req, ctx.res, result, { + mergeWithLastSubmission: true, + }); + }); + + router.get('/interaction/:uid/abort', async (ctx) => { + const result = { + error: 'access_denied', + error_description: 'End-User aborted interaction', + }; + + return provider.interactionFinished(ctx.req, ctx.res, result, { + mergeWithLastSubmission: false, + }); + }); + + return router; +}; diff --git a/scripts/e2e/oidc-provider/shell.nix b/scripts/e2e/oidc-provider/shell.nix new file mode 100644 index 00000000..3ed0b698 --- /dev/null +++ b/scripts/e2e/oidc-provider/shell.nix @@ -0,0 +1,11 @@ +{ pkgs ? import { } }: + +with pkgs; + +mkShell { + name = "badaas-oidc-shell"; + + buildInputs = [ + nodejs-18_x + ]; +} diff --git a/scripts/e2e/oidc-provider/standalone.js b/scripts/e2e/oidc-provider/standalone.js new file mode 100644 index 00000000..45658f51 --- /dev/null +++ b/scripts/e2e/oidc-provider/standalone.js @@ -0,0 +1,93 @@ +/* eslint-disable no-console */ + +const path = require('path'); +const { promisify } = require('util'); + +const render = require('@koa/ejs'); +const helmet = require('helmet'); + +const { Provider } = require('oidc-provider'); + +const configuration = require('./support/configuration'); +const routes = require('./routes/koa'); + +const PORT = process.env.PORT || 3000; +const ISSUER = `http://${process.env.HOST || "localhost"}:${PORT}`; +const Account = require('./support/account'); +const { Console } = require('console'); +configuration.findAccount = Account.findAccount; +configuration.pkce = { + required: function pkceRequired(ctx, client) { + return false; + } +} + +let server; + +console.log(`oidc-provider conf`); +console.log(`PORT: ${PORT}`); +console.log(`ISSUER: ${ISSUER}`); +console.log(`CLIENT_ID: ${process.env.CLIENT_ID || 'oidcCLIENT'}`); +console.log(`CLIENT_SECRET: ${process.env.CLIENT_SECRET ||'abcd'}`); +console.log(`REDIRECT_URI: ${process.env.REDIRECT_URI ||'http://localhost:8002/auth/oidc/callback'}`); + +(async () => { + let adapter; + if (process.env.MONGODB_URI) { + adapter = require('./adapters/mongodb'); // eslint-disable-line global-require + await adapter.connect(); + } + + const prod = process.env.NODE_ENV === 'production'; + + const provider = new Provider(ISSUER, { adapter, ...configuration }); + + const directives = helmet.contentSecurityPolicy.getDefaultDirectives(); + delete directives['form-action']; + const pHelmet = promisify(helmet({ + contentSecurityPolicy: { + useDefaults: false, + directives, + }, + })); + + provider.use(async (ctx, next) => { + const origSecure = ctx.req.secure; + ctx.req.secure = ctx.request.secure; + await pHelmet(ctx.req, ctx.res); + ctx.req.secure = origSecure; + return next(); + }); + + if (prod) { + provider.proxy = true; + provider.use(async (ctx, next) => { + if (ctx.secure) { + await next(); + } else if (ctx.method === 'GET' || ctx.method === 'HEAD') { + ctx.status = 303; + ctx.redirect(ctx.href.replace(/^http:\/\//i, 'https://')); + } else { + ctx.body = { + error: 'invalid_request', + error_description: 'do yourself a favor and only use https', + }; + ctx.status = 400; + } + }); + } + render(provider.app, { + cache: false, + viewExt: 'ejs', + layout: '_layout', + root: path.join(__dirname, 'views'), + }); + provider.use(routes(provider).routes()); + server = provider.listen(PORT, () => { + console.log(`application is listening on port ${PORT}, check its /.well-known/openid-configuration`); + }); +})().catch((err) => { + if (server && server.listening) server.close(); + console.error(err); + process.exitCode = 1; +}); diff --git a/scripts/e2e/oidc-provider/support/account.js b/scripts/e2e/oidc-provider/support/account.js new file mode 100644 index 00000000..f469b50d --- /dev/null +++ b/scripts/e2e/oidc-provider/support/account.js @@ -0,0 +1,90 @@ +const store = new Map(); +const logins = new Map(); +const { nanoid } = require('nanoid'); + +class Account { + constructor(id, profile) { + this.accountId = id || nanoid(); + this.profile = profile; + store.set(this.accountId, this); + } + + /** + * @param use - can either be "id_token" or "userinfo", depending on + * where the specific claims are intended to be put in. + * @param scope - the intended scope, while oidc-provider will mask + * claims depending on the scope automatically you might want to skip + * loading some claims from external resources etc. based on this detail + * or not return them in id tokens but only userinfo and so on. + */ + async claims(use, scope) { // eslint-disable-line no-unused-vars + if (this.profile) { + return { + sub: this.accountId, // it is essential to always return a sub claim + email: this.profile.email, + email_verified: this.profile.email_verified, + family_name: this.profile.family_name, + given_name: this.profile.given_name, + locale: this.profile.locale, + name: this.profile.name, + }; + } + + return { + sub: this.accountId, // it is essential to always return a sub claim + + address: { + country: '000', + formatted: '000', + locality: '000', + postal_code: '000', + region: '000', + street_address: '000', + }, + birthdate: '1987-10-16', + email: 'johndoe@example.com', + email_verified: false, + family_name: 'Doe', + gender: 'male', + given_name: 'John', + locale: 'en-US', + middle_name: 'Middle', + name: 'John Doe', + nickname: 'Johny', + phone_number: '+49 000 000000', + phone_number_verified: false, + picture: 'https://lorempixel.com/400/200/', + preferred_username: 'johnny', + profile: 'https://johnswebsite.com', + updated_at: 1454704946, + website: 'http://example.com', + zoneinfo: 'Europe/Berlin', + }; + } + + static async findByFederated(provider, claims) { + const id = `${provider}.${claims.sub}`; + if (!logins.get(id)) { + logins.set(id, new Account(id, claims)); + } + return logins.get(id); + } + + static async findByLogin(login) { + if (!logins.get(login)) { + logins.set(login, new Account(login)); + } + + return logins.get(login); + } + + static async findAccount(ctx, id, token) { // eslint-disable-line no-unused-vars + // token is a reference to the token used for which a given account is being loaded, + // it is undefined in scenarios where account claims are returned from authorization endpoint + // ctx is the koa request context + if (!store.get(id)) new Account(id); // eslint-disable-line no-new + return store.get(id); + } +} + +module.exports = Account; diff --git a/scripts/e2e/oidc-provider/support/configuration.js b/scripts/e2e/oidc-provider/support/configuration.js new file mode 100644 index 00000000..0436db5b --- /dev/null +++ b/scripts/e2e/oidc-provider/support/configuration.js @@ -0,0 +1,54 @@ +module.exports = { + clients: [ + { + client_id: process.env.CLIENT_ID || 'oidcCLIENT', + client_secret: process.env.CLIENT_SECRET ||'abcd', + grant_types: ['refresh_token', 'authorization_code'], + redirect_uris: [process.env.REDIRECT_URI ||'http://localhost:8002/auth/oidc/callback','http://e2e-api-1:8000/auth/oidc/callback'], + } + ], + interactions: { + url(ctx, interaction) { // eslint-disable-line no-unused-vars + return `/interaction/${interaction.uid}`; + }, + }, + cookies: { + keys: ['some secret key', 'and also the old rotated away some time ago', 'and one more'], + }, + claims: { + address: ['address'], + email: ['email', 'email_verified'], + phone: ['phone_number', 'phone_number_verified'], + profile: ['birthdate', 'family_name', 'gender', 'given_name', 'locale', 'middle_name', 'name', + 'nickname', 'picture', 'preferred_username', 'profile', 'updated_at', 'website', 'zoneinfo'], + }, + features: { + devInteractions: { enabled: false }, // defaults to true + + deviceFlow: { enabled: true }, // defaults to false + revocation: { enabled: true }, // defaults to false + }, + jwks: { + keys: [ + { + d: 'VEZOsY07JTFzGTqv6cC2Y32vsfChind2I_TTuvV225_-0zrSej3XLRg8iE_u0-3GSgiGi4WImmTwmEgLo4Qp3uEcxCYbt4NMJC7fwT2i3dfRZjtZ4yJwFl0SIj8TgfQ8ptwZbFZUlcHGXZIr4nL8GXyQT0CK8wy4COfmymHrrUoyfZA154ql_OsoiupSUCRcKVvZj2JHL2KILsq_sh_l7g2dqAN8D7jYfJ58MkqlknBMa2-zi5I0-1JUOwztVNml_zGrp27UbEU60RqV3GHjoqwI6m01U7K0a8Q_SQAKYGqgepbAYOA-P4_TLl5KC4-WWBZu_rVfwgSENwWNEhw8oQ', + dp: 'E1Y-SN4bQqX7kP-bNgZ_gEv-pixJ5F_EGocHKfS56jtzRqQdTurrk4jIVpI-ZITA88lWAHxjD-OaoJUh9Jupd_lwD5Si80PyVxOMI2xaGQiF0lbKJfD38Sh8frRpgelZVaK_gm834B6SLfxKdNsP04DsJqGKktODF_fZeaGFPH0', + dq: 'F90JPxevQYOlAgEH0TUt1-3_hyxY6cfPRU2HQBaahyWrtCWpaOzenKZnvGFZdg-BuLVKjCchq3G_70OLE-XDP_ol0UTJmDTT-WyuJQdEMpt_WFF9yJGoeIu8yohfeLatU-67ukjghJ0s9CBzNE_LrGEV6Cup3FXywpSYZAV3iqc', + e: 'AQAB', + kty: 'RSA', + n: 'xwQ72P9z9OYshiQ-ntDYaPnnfwG6u9JAdLMZ5o0dmjlcyrvwQRdoFIKPnO65Q8mh6F_LDSxjxa2Yzo_wdjhbPZLjfUJXgCzm54cClXzT5twzo7lzoAfaJlkTsoZc2HFWqmcri0BuzmTFLZx2Q7wYBm0pXHmQKF0V-C1O6NWfd4mfBhbM-I1tHYSpAMgarSm22WDMDx-WWI7TEzy2QhaBVaENW9BKaKkJklocAZCxk18WhR0fckIGiWiSM5FcU1PY2jfGsTmX505Ub7P5Dz75Ygqrutd5tFrcqyPAtPTFDk8X1InxkkUwpP3nFU5o50DGhwQolGYKPGtQ-ZtmbOfcWQ', + p: '5wC6nY6Ev5FqcLPCqn9fC6R9KUuBej6NaAVOKW7GXiOJAq2WrileGKfMc9kIny20zW3uWkRLm-O-3Yzze1zFpxmqvsvCxZ5ERVZ6leiNXSu3tez71ZZwp0O9gys4knjrI-9w46l_vFuRtjL6XEeFfHEZFaNJpz-lcnb3w0okrbM', + q: '3I1qeEDslZFB8iNfpKAdWtz_Wzm6-jayT_V6aIvhvMj5mnU-Xpj75zLPQSGa9wunMlOoZW9w1wDO1FVuDhwzeOJaTm-Ds0MezeC4U6nVGyyDHb4CUA3ml2tzt4yLrqGYMT7XbADSvuWYADHw79OFjEi4T3s3tJymhaBvy1ulv8M', + qi: 'wSbXte9PcPtr788e713KHQ4waE26CzoXx-JNOgN0iqJMN6C4_XJEX-cSvCZDf4rh7xpXN6SGLVd5ibIyDJi7bbi5EQ5AXjazPbLBjRthcGXsIuZ3AtQyR0CEWNSdM7EyM5TRdyZQ9kftfz9nI03guW3iKKASETqX2vh0Z8XRjyU', + use: 'sig', + }, { + crv: 'P-256', + d: 'K9xfPv773dZR22TVUB80xouzdF7qCg5cWjPjkHyv7Ws', + kty: 'EC', + use: 'sig', + x: 'FWZ9rSkLt6Dx9E3pxLybhdM6xgR5obGsj5_pqmnz5J4', + y: '_n8G69C-A2Xl4xUW2lF0i8ZGZnk_KPYrhv4GbTGu5G4', + }, + ], + }, +}; diff --git a/scripts/e2e/oidc-provider/views/_layout.ejs b/scripts/e2e/oidc-provider/views/_layout.ejs new file mode 100644 index 00000000..cc88be96 --- /dev/null +++ b/scripts/e2e/oidc-provider/views/_layout.ejs @@ -0,0 +1,229 @@ + + + + + + + Sign-in + + + + +
+
+ (Click to expand) DEBUG information +
+ uid: <%= uid %> +
+ + <% if (session) { %> +
+ SESSION
+ =========
+ <%- session %> +
+ <% } %> + +
+ PARAMS
+ ========
+ <%- dbg.params %> +
+ +
+ PROMPT
+ ========
+ <%- dbg.prompt %> +
+
+
+ + diff --git a/scripts/e2e/oidc-provider/views/interaction.ejs b/scripts/e2e/oidc-provider/views/interaction.ejs new file mode 100644 index 00000000..32b0d6d2 --- /dev/null +++ b/scripts/e2e/oidc-provider/views/interaction.ejs @@ -0,0 +1,55 @@ + + +
    +<% if ([details.missingOIDCScope, details.missingOIDCClaims, details.missingResourceScopes].filter(Boolean).length === 0) { %> +
  • the client is asking you to confirm previously given authorization
  • +<% } %> + +<% missingOIDCScope = new Set(details.missingOIDCScope); missingOIDCScope.delete('openid'); missingOIDCScope.delete('offline_access') %> +<% if (missingOIDCScope.size) { %> +
  • scopes:
  • +
      + <% missingOIDCScope.forEach((scope) => { %> +
    • <%= scope %>
    • + <% }) %> +
    +<% } %> + +<% missingOIDCClaims = new Set(details.missingOIDCClaims); ['sub', 'sid', 'auth_time', 'acr', 'amr', 'iss'].forEach(Set.prototype.delete.bind(missingOIDCClaims)) %> +<% if (missingOIDCClaims.size) { %> +
  • claims:
  • +
      + <% missingOIDCClaims.forEach((claim) => { %> +
    • <%= claim %>
    • + <% }) %> +
    +<% } %> + +<% missingResourceScopes = details.missingResourceScopes %> +<% if (missingResourceScopes) { %> + <% for (const [indicator, scopes] of Object.entries(details.missingResourceScopes)) { %> +
  • <%= indicator %>:
  • +
      + <% scopes.forEach((scope) => { %> +
    • <%= scope %>
    • + <% }) %> +
    + <% } %> +<% } %> + +<% if (params.scope && params.scope.includes('offline_access')) { %> +
  • + the client is asking to have offline access to this authorization + <% if ((!details.missingOIDCScope) || !details.missingOIDCScope.includes('offline_access')) { %> + (which you've previously granted) + <% } %> +
  • +<% } %> + +
+ +
+ +
diff --git a/scripts/e2e/oidc-provider/views/login.ejs b/scripts/e2e/oidc-provider/views/login.ejs new file mode 100644 index 00000000..7db6acba --- /dev/null +++ b/scripts/e2e/oidc-provider/views/login.ejs @@ -0,0 +1,20 @@ +<% if (locals.google) { %> +
+ + +
+ +<% } %> +
+ autofocus="on"<% } else { %> value="<%= params.login_hint %>" <% } %>> + autofocus="on"<% } %>> + + +
diff --git a/scripts/e2e/oidc-provider/views/repost.ejs b/scripts/e2e/oidc-provider/views/repost.ejs new file mode 100644 index 00000000..96767dde --- /dev/null +++ b/scripts/e2e/oidc-provider/views/repost.ejs @@ -0,0 +1,45 @@ + + + Fragment Federated Callback Repost Form + + + + + diff --git a/services/auth/protocols/oidcservice/OIDCService.go b/services/auth/protocols/oidcservice/OIDCService.go new file mode 100644 index 00000000..07752618 --- /dev/null +++ b/services/auth/protocols/oidcservice/OIDCService.go @@ -0,0 +1,91 @@ +package oidcservice + +import ( + "context" + "errors" + "fmt" + + "github.com/coreos/go-oidc/v3/oidc" + "github.com/ditrit/badaas/configuration" + "go.uber.org/zap" + "golang.org/x/oauth2" +) + +var ( + // ErrFailedToExchangeAuthorizationCode is returned when the oauth2Config + // fail to exchange the tokens against the authorization code. + ErrFailedToExchangeAuthorizationCode = errors.New("failed to exchange authorization code") + + // ErrClaimIdentifierNotFoundInIDTokenBody is returned when the OIDC claim is not found in the ID token. + ErrClaimIdentifierNotFoundInIDTokenBody = errors.New("claim identifier not found in ID Token body") +) + +// OIDCService integrate an OIDC relying party for badaas. +type OIDCService interface { + BuildRedirectURL(state string) string + ExchangeAuthorizationCode(code string) (userIdentifier string, err error) +} + +// Check interface compliance. +var _ OIDCService = (*oidcService)(nil) + +// oidcService is a concrete implementation of OIDCService. +type oidcService struct { + logger *zap.Logger + // oauth2Config oauth2 + oauth2Config oauth2.Config + // The provider OIDC + provider *oidc.Provider + + // configuration + oidConfiguration configuration.OIDCConfiguration +} + +// BuildRedirectURL return an authentication url using the provided state +func (oidcService *oidcService) BuildRedirectURL(state string) string { + // access_type=offline in order to get the refresh_token + return oidcService.oauth2Config.AuthCodeURL(state) +} + +// ExchangeAuthorizationCode return the identifying claim value. +func (oidcService *oidcService) ExchangeAuthorizationCode(code string) (string, error) { + ctx := context.Background() + oauth2Token, err := oidcService.oauth2Config.Exchange(ctx, code) + + if err != nil { + return "", ErrFailedToExchangeAuthorizationCode + } + + userInfo, err := oidcService.provider.UserInfo(ctx, oauth2.StaticTokenSource(oauth2Token)) + if err != nil { + return "", fmt.Errorf("the UserInfo endpoint return an error: %s", err.Error()) + } + + IDTokenBody := map[string]string{} + userInfo.Claims(&IDTokenBody) + userIdentifier, ok := IDTokenBody[oidcService.oidConfiguration.GetClaimIdentifier()] + if !ok { + return "", ErrClaimIdentifierNotFoundInIDTokenBody + } + return userIdentifier, nil +} + +// NewOIDCService is the constructor for the OIDC Service +func NewOIDCService(logger *zap.Logger, oidConfiguration configuration.OIDCConfiguration) (OIDCService, error) { + ctx := context.Background() + + provider, err := oidc.NewProvider(ctx, oidConfiguration.GetIssuer()) + if err != nil { + return nil, fmt.Errorf("failed to initialize oidc provider with issuer %q, error=%q", + oidConfiguration.GetIssuer(), err.Error()) + } + + config := oauth2.Config{ + ClientID: oidConfiguration.GetClientID(), + ClientSecret: oidConfiguration.GetClientSecret(), + Endpoint: provider.Endpoint(), + RedirectURL: oidConfiguration.GetRedirectURL(), + Scopes: append(oidConfiguration.GetScopes(), oidc.ScopeOpenID), + } + return &oidcService{logger, config, provider, oidConfiguration}, nil +} diff --git a/services/userservice/userservice.go b/services/userservice/userservice.go index 3f3da399..3dd27c74 100644 --- a/services/userservice/userservice.go +++ b/services/userservice/userservice.go @@ -16,7 +16,7 @@ import ( // UserService provide functions related to Users type UserService interface { - NewUser(username, email, password string) (*models.User, error) + NewUser(username, email, password, oidcIdentifier string) (*models.User, error) GetUser(dto.UserLoginDTO) (*models.User, httperrors.HTTPError) } @@ -41,15 +41,19 @@ func NewUserService( } // Create a new user -func (userService *userServiceImpl) NewUser(username, email, password string) (*models.User, error) { +func (userService *userServiceImpl) NewUser(username, email, password, oidcIdentifier string) (*models.User, error) { sanitizedEmail, err := validator.ValidEmail(email) if err != nil { return nil, fmt.Errorf("the provided email is not valid") } + if oidcIdentifier == "" { + oidcIdentifier = sanitizedEmail + } u := &models.User{ - Username: username, - Email: sanitizedEmail, - Password: basicauth.SaltAndHashPassword(password), + Username: username, + Email: sanitizedEmail, + Password: basicauth.SaltAndHashPassword(password), + OidcIdentifier: oidcIdentifier, } httpError := userService.userRepository.Create(u) if httpError != nil { diff --git a/services/userservice/userservice_test.go b/services/userservice/userservice_test.go index df435ed8..942b3ed0 100644 --- a/services/userservice/userservice_test.go +++ b/services/userservice/userservice_test.go @@ -26,12 +26,13 @@ func TestNewUserService(t *testing.T) { userRespositoryMock := repositorymocks.NewCRUDRepository[models.User, uuid.UUID](t) userRespositoryMock.On("Create", mock.Anything).Return(nil) userService := userservice.NewUserService(observedLogger, userRespositoryMock) - user, err := userService.NewUser("bob", "bob@email.com", "1234") + user, err := userService.NewUser("bob", "bob@email.com", "1234", "bobOIDCIdentifier") assert.NoError(t, err) assert.NotNil(t, user) assert.Equal(t, "bob", user.Username) assert.Equal(t, "bob@email.com", user.Email) assert.NotEqual(t, "1234", user.Password) + assert.Equal(t, "bobOIDCIdentifier", user.OidcIdentifier) // Checking logs require.Equal(t, 1, observedLogs.Len()) @@ -56,7 +57,7 @@ func TestNewUserServiceDatabaseError(t *testing.T) { httperrors.NewInternalServerError("database error", "test error", nil), ) userService := userservice.NewUserService(observedLogger, userRespositoryMock) - user, err := userService.NewUser("bob", "bob@email.com", "1234") + user, err := userService.NewUser("bob", "bob@email.com", "1234", "") assert.Error(t, err) assert.Nil(t, user) @@ -72,7 +73,7 @@ func TestNewUserServiceEmailNotValid(t *testing.T) { userRespositoryMock := repositorymocks.NewCRUDRepository[models.User, uuid.UUID](t) userService := userservice.NewUserService(observedLogger, userRespositoryMock) - user, err := userService.NewUser("bob", "bob@", "1234") + user, err := userService.NewUser("bob", "bob@", "1234", "") assert.Error(t, err) assert.Nil(t, user) @@ -92,7 +93,7 @@ func TestGetUser(t *testing.T) { ).Return( nil, ) - user, err := userService.NewUser("bob", "bob@email.com", "1234") + user, err := userService.NewUser("bob", "bob@email.com", "1234", "") require.NoError(t, err) userRespositoryMock.On( @@ -148,7 +149,7 @@ func TestGetUserNotCorrect(t *testing.T) { nil, ) userService := userservice.NewUserService(observedLogger, userRespositoryMock) - user, err := userService.NewUser("bob", "bob@email.com", "1234") + user, err := userService.NewUser("bob", "bob@email.com", "1234", "") require.NoError(t, err) userRespositoryMock.On( @@ -176,7 +177,7 @@ func TestGetUserEmpty(t *testing.T) { nil, ) userService := userservice.NewUserService(observedLogger, userRespositoryMock) - _, err := userService.NewUser("bob", "bob@email.com", "1234") + _, err := userService.NewUser("bob", "bob@email.com", "1234", "") require.NoError(t, err) userRespositoryMock.On( diff --git a/sonar-project.properties b/sonar-project.properties index f0158b76..bed1328f 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -3,7 +3,7 @@ sonar.organization=ditrit sonar.projectName=badaas sonar.host.url=https://sonarcloud.io sonar.sources=. -sonar.exclusions=**/*_test.go,mocks/***,vendor/*** +sonar.exclusions=**/*_test.go,mocks/***,vendor/***,scripts/e2e/oidc-provider/*** sonar.tests=. sonar.test.inclusions=**/*_test.go sonar.go.coverage.reportPaths=./coverage.out/coverage.out