diff --git a/.gitignore b/.gitignore index bed7331f2..9db836bce 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,8 @@ users_database.test.yml .suite .kube .idea + +# Go binary +authelia + +.authelia-interrupt diff --git a/.npmignore b/.npmignore deleted file mode 100644 index 9513d38de..000000000 --- a/.npmignore +++ /dev/null @@ -1,17 +0,0 @@ -client/ -server/ -test/ -docs/ -scripts/ -images/ -example/ - -.travis.yml -CONTRIBUTORS.md -Dockerfile -docker-compose.* -Gruntfile.js -tslint.json -tsconfig.json - -*.tgz diff --git a/.travis.yml b/.travis.yml index 549d25d45..1ad015b2f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ -language: node_js +language: go required: sudo -node_js: -- '9' +go: +- '1.13' services: - docker - ntp @@ -12,9 +12,11 @@ addons: sources: - google-chrome packages: - - xvfb - libgif-dev - google-chrome-stable +before_script: +- curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash +- nvm install v9 && nvm use v9 && npm i script: - "./scripts/authelia-scripts travis" after_success: diff --git a/BREAKING.md b/BREAKING.md index bfcb86bfa..6dee0e79a 100644 --- a/BREAKING.md +++ b/BREAKING.md @@ -4,6 +4,18 @@ Breaking changes Since Authelia is still under active development, it is subject to breaking changes. We then recommend you don't blindly use the latest Docker image but pick a version instead and check this file before upgrading. This is where you will get information about breaking changes and about what you should do to overcome those changes. +## Breaking in v4.0.0 + +Authelia has been rewritten in Go for better performance and reliability. + +### Model of U2F devices in MongoDB + +The model of U2F devices stored in MongoDB has been updated to better fit with the Go library handling U2F keys. + +### Removal of flag secure for SMTP notifier + +The go library for sending e-mails automatically switch to TLS if possible according to https://golang.org/pkg/net/smtp/#SendMail. + ## Breaking in v3.14.0 ### Headers in nginx configuration diff --git a/Dockerfile b/Dockerfile index 0532b69e0..724decdda 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,19 +1,20 @@ -FROM node:8.7.0-alpine +FROM alpine:3.9.4 -WORKDIR /usr/src +WORKDIR /usr/app -COPY package.json /usr/src/package.json +RUN apk --no-cache add ca-certificates wget -RUN apk --update add --no-cache --virtual \ - .build-deps make g++ python && \ - npm install --production && \ - apk del .build-deps +# Install the libc required by the password hashing compiled with CGO. +RUN wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub +RUN wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.30-r0/glibc-2.30-r0.apk +RUN apk --no-cache add glibc-2.30-r0.apk -COPY dist/server /usr/src/server +ADD dist/authelia authelia +ADD dist/public_html public_html EXPOSE 9091 VOLUME /etc/authelia VOLUME /var/lib/authelia -CMD ["node", "server/src/index.js", "/etc/authelia/config.yml"] +CMD ["./authelia", "-config", "/etc/authelia/config.yml"] diff --git a/authentication/const.go b/authentication/const.go new file mode 100644 index 000000000..49dd6237c --- /dev/null +++ b/authentication/const.go @@ -0,0 +1,25 @@ +package authentication + +// Level is the type representing a level of authentication +type Level int + +const ( + // NotAuthenticated if the user is not authenticated yet. + NotAuthenticated Level = iota + // OneFactor if the user has passed first factor only. + OneFactor Level = iota + // TwoFactor if the user has passed two factors. + TwoFactor Level = iota +) + +const ( + // TOTP Method using Time-Based One-Time Password applications like Google Authenticator + TOTP = "totp" + // U2F Method using U2F devices like Yubikeys + U2F = "u2f" + // DuoPush Method using Duo application to receive push notifications. + DuoPush = "duo_push" +) + +// PossibleMethods is the set of all possible 2FA methods. +var PossibleMethods = []string{TOTP, U2F, DuoPush} diff --git a/authentication/file_user_provider.go b/authentication/file_user_provider.go new file mode 100644 index 000000000..13f0ab071 --- /dev/null +++ b/authentication/file_user_provider.go @@ -0,0 +1,113 @@ +package authentication + +import ( + "fmt" + "io/ioutil" + "sync" + + "github.com/asaskevich/govalidator" + + "gopkg.in/yaml.v2" +) + +// FileUserProvider is a provider reading details from a file. +type FileUserProvider struct { + path *string + database *DatabaseModel + lock *sync.Mutex +} + +// UserDetailsModel is the model of user details in the file database. +type UserDetailsModel struct { + HashedPassword string `yaml:"password" valid:"required"` + Email string `yaml:"email"` + Groups []string `yaml:"groups"` +} + +// DatabaseModel is the model of users file database. +type DatabaseModel struct { + Users map[string]UserDetailsModel `yaml:"users" valid:"required"` +} + +// NewFileUserProvider creates a new instance of FileUserProvider. +func NewFileUserProvider(filepath string) *FileUserProvider { + database, err := readDatabase(filepath) + if err != nil { + // Panic since the file does not exist when Authelia is starting. + panic(err) + } + return &FileUserProvider{ + path: &filepath, + database: database, + lock: &sync.Mutex{}, + } +} + +func readDatabase(path string) (*DatabaseModel, error) { + content, err := ioutil.ReadFile(path) + if err != nil { + return nil, err + } + db := DatabaseModel{} + err = yaml.Unmarshal(content, &db) + if err != nil { + return nil, err + } + + ok, err := govalidator.ValidateStruct(db) + if err != nil { + return nil, err + } + + if !ok { + return nil, fmt.Errorf("The database format is invalid: %s", err.Error()) + } + return &db, nil +} + +// CheckUserPassword checks if provided password matches for the given user. +func (p *FileUserProvider) CheckUserPassword(username string, password string) (bool, error) { + if details, ok := p.database.Users[username]; ok { + hashedPassword := details.HashedPassword[7:] // Remove {CRYPT} + ok, err := CheckPassword(password, hashedPassword) + if err != nil { + return false, err + } + return ok, nil + } + return false, fmt.Errorf("User '%s' does not exist in database", username) +} + +// GetDetails retrieve the groups a user belongs to. +func (p *FileUserProvider) GetDetails(username string) (*UserDetails, error) { + if details, ok := p.database.Users[username]; ok { + return &UserDetails{ + Groups: details.Groups, + Emails: []string{details.Email}, + }, nil + } + return nil, fmt.Errorf("User '%s' does not exist in database", username) +} + +// UpdatePassword update the password of the given user. +func (p *FileUserProvider) UpdatePassword(username string, newPassword string) error { + details, ok := p.database.Users[username] + if !ok { + return fmt.Errorf("User '%s' does not exist in database", username) + } + + hash := HashPassword(newPassword, nil) + details.HashedPassword = fmt.Sprintf("{CRYPT}%s", hash) + + p.lock.Lock() + p.database.Users[username] = details + + b, err := yaml.Marshal(p.database) + if err != nil { + p.lock.Unlock() + return err + } + err = ioutil.WriteFile(*p.path, b, 0644) + p.lock.Unlock() + return err +} diff --git a/authentication/file_user_provider_test.go b/authentication/file_user_provider_test.go new file mode 100644 index 000000000..704d456b0 --- /dev/null +++ b/authentication/file_user_provider_test.go @@ -0,0 +1,144 @@ +package authentication + +import ( + "io/ioutil" + "log" + "os" + "testing" + + "github.com/stretchr/testify/assert" +) + +func WithDatabase(content []byte, f func(path string)) { + tmpfile, err := ioutil.TempFile("", "users_database.*.yaml") + if err != nil { + log.Fatal(err) + } + + defer os.Remove(tmpfile.Name()) // clean up + + if _, err := tmpfile.Write(content); err != nil { + tmpfile.Close() + log.Fatal(err) + } + + f(tmpfile.Name()) + + if err := tmpfile.Close(); err != nil { + log.Fatal(err) + } +} + +func TestShouldCheckUserPasswordIsCorrect(t *testing.T) { + WithDatabase(UserDatabaseContent, func(path string) { + provider := NewFileUserProvider(path) + ok, err := provider.CheckUserPassword("john", "password") + + assert.NoError(t, err) + assert.True(t, ok) + }) +} + +func TestShouldCheckUserPasswordIsWrong(t *testing.T) { + WithDatabase(UserDatabaseContent, func(path string) { + provider := NewFileUserProvider(path) + ok, err := provider.CheckUserPassword("john", "wrong_password") + + assert.NoError(t, err) + assert.False(t, ok) + }) +} + +func TestShouldCheckUserPasswordOfUnexistingUser(t *testing.T) { + WithDatabase(UserDatabaseContent, func(path string) { + provider := NewFileUserProvider(path) + _, err := provider.CheckUserPassword("fake", "password") + assert.Error(t, err) + assert.Equal(t, "User 'fake' does not exist in database", err.Error()) + }) +} + +func TestShouldRetrieveUserDetails(t *testing.T) { + WithDatabase(UserDatabaseContent, func(path string) { + provider := NewFileUserProvider(path) + details, err := provider.GetDetails("john") + assert.NoError(t, err) + assert.Equal(t, details.Emails, []string{"john.doe@authelia.com"}) + assert.Equal(t, details.Groups, []string{"admins", "dev"}) + }) +} + +func TestShouldUpdatePassword(t *testing.T) { + WithDatabase(UserDatabaseContent, func(path string) { + provider := NewFileUserProvider(path) + err := provider.UpdatePassword("john", "newpassword") + assert.NoError(t, err) + + // Reset the provider to force a read from disk. + provider = NewFileUserProvider(path) + ok, err := provider.CheckUserPassword("john", "newpassword") + assert.NoError(t, err) + assert.True(t, ok) + }) +} + +func TestShouldRaiseWhenLoadingMalformedDatabaseForFirstTime(t *testing.T) { + WithDatabase(MalformedUserDatabaseContent, func(path string) { + assert.Panics(t, func() { + NewFileUserProvider(path) + }) + }) +} + +func TestShouldRaiseWhenLoadingDatabaseWithBadSchemaForFirstTime(t *testing.T) { + WithDatabase(BadSchemaUserDatabaseContent, func(path string) { + assert.Panics(t, func() { + NewFileUserProvider(path) + }) + }) +} + +var UserDatabaseContent = []byte(` +users: + john: + password: "{CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/" + email: john.doe@authelia.com + groups: + - admins + - dev + + harry: + password: "{CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/" + email: harry.potter@authelia.com + groups: [] + + bob: + password: "{CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/" + email: bob.dylan@authelia.com + groups: + - dev + + james: + password: "{CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/" + email: james.dean@authelia.com +`) + +var MalformedUserDatabaseContent = []byte(` +users +john +email: john.doe@authelia.com +groups: +- admin +- dev +`) + +// The YAML is valid but the root key is user instead of users +var BadSchemaUserDatabaseContent = []byte(` +user: + john: + password: "{CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/" + email: john.doe@authelia.com + groups: + - admins + - dev +`) diff --git a/authentication/ldap_user_provider.go b/authentication/ldap_user_provider.go new file mode 100644 index 000000000..b139a803b --- /dev/null +++ b/authentication/ldap_user_provider.go @@ -0,0 +1,225 @@ +package authentication + +import ( + "fmt" + "strings" + + "github.com/clems4ever/authelia/configuration/schema" + "gopkg.in/ldap.v3" +) + +// LDAPUserProvider is a provider using a LDAP or AD as a user database. +type LDAPUserProvider struct { + configuration schema.LDAPAuthenticationBackendConfiguration +} + +func (p *LDAPUserProvider) connect(userDN string, password string) (*ldap.Conn, error) { + conn, err := ldap.Dial("tcp", p.configuration.URL) + if err != nil { + return nil, err + } + + err = conn.Bind(userDN, password) + + if err != nil { + return nil, err + } + return conn, nil +} + +// NewLDAPUserProvider creates a new instance of LDAPUserProvider. +func NewLDAPUserProvider(configuration schema.LDAPAuthenticationBackendConfiguration) *LDAPUserProvider { + return &LDAPUserProvider{configuration} +} + +// CheckUserPassword checks if provided password matches for the given user. +func (p *LDAPUserProvider) CheckUserPassword(username string, password string) (bool, error) { + adminClient, err := p.connect(p.configuration.User, p.configuration.Password) + if err != nil { + return false, err + } + defer adminClient.Close() + + userDN, err := p.getUserDN(adminClient, username) + if err != nil { + return false, err + } + + conn, err := p.connect(userDN, password) + if err != nil { + return false, fmt.Errorf("Authentication of user %s failed. Cause: %s", username, err) + } + defer conn.Close() + + return true, nil +} + +func (p *LDAPUserProvider) getUserAttribute(conn *ldap.Conn, username string, attribute string) ([]string, error) { + client, err := p.connect(p.configuration.User, p.configuration.Password) + if err != nil { + return nil, err + } + defer client.Close() + + userFilter := strings.Replace(p.configuration.UsersFilter, "{0}", username, -1) + baseDN := p.configuration.AdditionalUsersDN + "," + p.configuration.BaseDN + + // Search for the given username + searchRequest := ldap.NewSearchRequest( + baseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, + 1, 0, false, userFilter, []string{attribute}, nil, + ) + + sr, err := client.Search(searchRequest) + if err != nil { + return nil, fmt.Errorf("Cannot find user DN of user %s. Cause: %s", username, err) + } + + if len(sr.Entries) != 1 { + return nil, fmt.Errorf("No %s found for user %s", attribute, username) + } + + if attribute == "dn" { + return []string{sr.Entries[0].DN}, nil + } + + return sr.Entries[0].Attributes[0].Values, nil +} + +func (p *LDAPUserProvider) getUserDN(conn *ldap.Conn, username string) (string, error) { + values, err := p.getUserAttribute(conn, username, "dn") + + if err != nil { + return "", err + } + + if len(values) != 1 { + return "", fmt.Errorf("DN attribute of user %s must be set", username) + } + + return values[0], nil +} + +func (p *LDAPUserProvider) getUserUID(conn *ldap.Conn, username string) (string, error) { + values, err := p.getUserAttribute(conn, username, "uid") + + if err != nil { + return "", err + } + + if len(values) != 1 { + return "", fmt.Errorf("UID attribute of user %s must be set", username) + } + + return values[0], nil +} + +func (p *LDAPUserProvider) createGroupsFilter(conn *ldap.Conn, username string) (string, error) { + if strings.Index(p.configuration.GroupsFilter, "{0}") >= 0 { + return strings.Replace(p.configuration.GroupsFilter, "{0}", username, -1), nil + } else if strings.Index(p.configuration.GroupsFilter, "{dn}") >= 0 { + userDN, err := p.getUserDN(conn, username) + if err != nil { + return "", err + } + return strings.Replace(p.configuration.GroupsFilter, "{dn}", userDN, -1), nil + } else if strings.Index(p.configuration.GroupsFilter, "{uid}") >= 0 { + userUID, err := p.getUserUID(conn, username) + if err != nil { + return "", err + } + return strings.Replace(p.configuration.GroupsFilter, "{uid}", userUID, -1), nil + } + return p.configuration.GroupsFilter, nil +} + +// GetDetails retrieve the groups a user belongs to. +func (p *LDAPUserProvider) GetDetails(username string) (*UserDetails, error) { + conn, err := p.connect(p.configuration.User, p.configuration.Password) + if err != nil { + return nil, err + } + defer conn.Close() + + groupsFilter, err := p.createGroupsFilter(conn, username) + if err != nil { + return nil, fmt.Errorf("Unable to create group filter for user %s. Cause: %s", username, err) + } + + groupBaseDN := fmt.Sprintf("%s,%s", p.configuration.AdditionalGroupsDN, p.configuration.BaseDN) + + // Search for the given username + searchGroupRequest := ldap.NewSearchRequest( + groupBaseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, + 0, 0, false, groupsFilter, []string{p.configuration.GroupNameAttribute}, nil, + ) + + sr, err := conn.Search(searchGroupRequest) + + if err != nil { + return nil, fmt.Errorf("Unable to retrieve groups of user %s. Cause: %s", username, err) + } + + groups := make([]string, 0) + + for _, res := range sr.Entries { + // append all values of the document. Normally there should be only one per document. + groups = append(groups, res.Attributes[0].Values...) + } + + userDN, err := p.getUserDN(conn, username) + + if err != nil { + return nil, err + } + + searchEmailRequest := ldap.NewSearchRequest( + userDN, ldap.ScopeBaseObject, ldap.NeverDerefAliases, + 0, 0, false, "(cn=*)", []string{p.configuration.MailAttribute}, nil, + ) + + sr, err = conn.Search(searchEmailRequest) + + if err != nil { + return nil, fmt.Errorf("Unable to retrieve email of user %s. Cause: %s", username, err) + } + + emails := make([]string, 0) + + for _, res := range sr.Entries { + // append all values of the document. Normally there should be only one per document. + emails = append(emails, res.Attributes[0].Values...) + } + + return &UserDetails{ + Emails: emails, + Groups: groups, + }, nil +} + +// UpdatePassword update the password of the given user. +func (p *LDAPUserProvider) UpdatePassword(username string, newPassword string) error { + client, err := p.connect(p.configuration.User, p.configuration.Password) + + if err != nil { + return fmt.Errorf("Unable to update password. Cause: %s", err) + } + + userDN, err := p.getUserDN(client, username) + + if err != nil { + return fmt.Errorf("Unable to update password. Cause: %s", err) + } + + modifyRequest := ldap.NewModifyRequest(userDN, nil) + + modifyRequest.Replace("userPassword", []string{newPassword}) + + err = client.Modify(modifyRequest) + + if err != nil { + return fmt.Errorf("Unable to update password. Cause: %s", err) + } + + return nil +} diff --git a/authentication/password_hash.go b/authentication/password_hash.go new file mode 100644 index 000000000..c4195d002 --- /dev/null +++ b/authentication/password_hash.go @@ -0,0 +1,101 @@ +package authentication + +// #cgo LDFLAGS: -lcrypt +// #define _GNU_SOURCE +// #include +// #include +import "C" +import ( + "errors" + "fmt" + "math/rand" + "strconv" + "strings" + "unsafe" +) + +// Crypt wraps C library crypt_r +func crypt(key string, salt string) string { + data := C.struct_crypt_data{} + ckey := C.CString(key) + csalt := C.CString(salt) + out := C.GoString(C.crypt_r(ckey, csalt, &data)) + C.free(unsafe.Pointer(ckey)) + C.free(unsafe.Pointer(csalt)) + return out +} + +// PasswordHash represents all characteristics of a password hash. +// Authelia only supports salted SHA512 method, i.e., $6$ mode. +type PasswordHash struct { + // The number of rounds. + Rounds int + // The salt with a max size of 16 characters for SHA512. + Salt string + // The password hash. + Hash string +} + +// passwordHashFromString extracts all characteristics of a hash given its string representation. +func passwordHashFromString(hash string) (*PasswordHash, error) { + // Only supports salted sha 512. + if hash[:3] != "$6$" { + return nil, errors.New("Authelia only supports salted SHA512 hashing") + } + parts := strings.Split(hash, "$") + + if len(parts) != 5 { + return nil, errors.New("Cannot parse the hash") + } + + roundsKV := strings.Split(parts[2], "=") + if len(roundsKV) != 2 { + return nil, errors.New("Cannot find the number of rounds") + } + + rounds, err := strconv.ParseInt(roundsKV[1], 10, 0) + if err != nil { + return nil, fmt.Errorf("Cannot find the number of rounds in the hash: %s", err.Error()) + } + + return &PasswordHash{ + Rounds: int(rounds), + Salt: parts[3], + Hash: parts[4], + }, nil +} + +// The set of letters RandomString can pick in. +var possibleLetters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") + +// RandomString generate a random string of n characters. +func RandomString(n int) string { + b := make([]rune, n) + for i := range b { + b[i] = possibleLetters[rand.Intn(len(possibleLetters))] + } + return string(b) +} + +// HashPassword generate a salt and hash the password with the salt and a constant +// number of rounds. +func HashPassword(password string, salt *string) string { + var generatedSalt string + if salt == nil { + generatedSalt = fmt.Sprintf("$6$rounds=5000$%s$", RandomString(16)) + } else { + generatedSalt = *salt + } + return crypt(password, generatedSalt) +} + +// CheckPassword check a password against a hash. +func CheckPassword(password string, hash string) (bool, error) { + passwordHash, err := passwordHashFromString(hash) + if err != nil { + return false, err + } + salt := fmt.Sprintf("$6$rounds=%d$%s$", passwordHash.Rounds, passwordHash.Salt) + pHash := HashPassword(password, &salt) + return pHash == hash, nil +} diff --git a/authentication/password_hash_test.go b/authentication/password_hash_test.go new file mode 100644 index 000000000..3d4745fc8 --- /dev/null +++ b/authentication/password_hash_test.go @@ -0,0 +1,20 @@ +package authentication + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestShouldHashPassword(t *testing.T) { + salt := "$6$rounds=5000$aFr56HjK3DrB8t3S$" + hash := HashPassword("password", &salt) + assert.Equal(t, "$6$rounds=5000$aFr56HjK3DrB8t3S$3yTiN5991WnlmhE8qlMmayIiUiT5ppq68CIuHBrGgQHJ4RWSCb0AykB0E6Ij761ZTzLaCZKuXpurcBiqDR1hu.", hash) +} + +func TestShouldCheckPassword(t *testing.T) { + ok, err := CheckPassword("password", "$6$rounds=5000$aFr56HjK3DrB8t3S$3yTiN5991WnlmhE8qlMmayIiUiT5ppq68CIuHBrGgQHJ4RWSCb0AykB0E6Ij761ZTzLaCZKuXpurcBiqDR1hu.") + + assert.NoError(t, err) + assert.True(t, ok) +} diff --git a/authentication/types.go b/authentication/types.go new file mode 100644 index 000000000..b4277cf1d --- /dev/null +++ b/authentication/types.go @@ -0,0 +1,7 @@ +package authentication + +// UserDetails represent the details retrieved for a given user. +type UserDetails struct { + Emails []string + Groups []string +} diff --git a/authentication/user_provider.go b/authentication/user_provider.go new file mode 100644 index 000000000..9f721ce40 --- /dev/null +++ b/authentication/user_provider.go @@ -0,0 +1,9 @@ +package authentication + +// UserProvider is the interface for checking user password and +// gathering user details. +type UserProvider interface { + CheckUserPassword(username string, password string) (bool, error) + GetDetails(username string) (*UserDetails, error) + UpdatePassword(username string, newPassword string) error +} diff --git a/authorization/authorizer.go b/authorization/authorizer.go new file mode 100644 index 000000000..d6c01d50a --- /dev/null +++ b/authorization/authorizer.go @@ -0,0 +1,189 @@ +package authorization + +import ( + "net" + "net/url" + "regexp" + "strings" + + "github.com/clems4ever/authelia/configuration/schema" +) + +const userPrefix = "user:" +const groupPrefix = "group:" + +// Authorizer the component in charge of checking whether a user can access a given resource. +type Authorizer struct { + configuration schema.AccessControlConfiguration +} + +// NewAuthorizer create an instance of authorizer with a given access control configuration. +func NewAuthorizer(configuration schema.AccessControlConfiguration) *Authorizer { + return &Authorizer{ + configuration: configuration, + } +} + +// Subject subject who to check access control for. +type Subject struct { + Username string + Groups []string + IP net.IP +} + +// Object object to check access control for +type Object struct { + Domain string + Path string +} + +func isDomainMatching(domain string, domainRule string) bool { + if domain == domainRule { // if domain matches exactly + return true + } else if strings.HasPrefix(domainRule, "*") && strings.HasSuffix(domain, domainRule[1:]) { + // If domain pattern starts with *, it's a multi domain pattern. + return true + } + return false +} + +func isPathMatching(path string, pathRegexps []string) bool { + // If there is no regexp patterns, it means that we match any path. + if len(pathRegexps) == 0 { + return true + } + + for _, pathRegexp := range pathRegexps { + match, err := regexp.MatchString(pathRegexp, path) + if err != nil { + // TODO(c.michaud): make sure this is safe in advance to + // avoid checking this case here. + continue + } + + if match { + return true + } + } + return false +} + +func isSubjectMatching(subject Subject, subjectRule string) bool { + // If no subject is provided in the rule, we match any user. + if subjectRule == "" { + return true + } + + if strings.HasPrefix(subjectRule, userPrefix) { + user := strings.Trim(subjectRule[len(userPrefix):], " ") + if user == subject.Username { + return true + } + } + + if strings.HasPrefix(subjectRule, groupPrefix) { + group := strings.Trim(subjectRule[len(groupPrefix):], " ") + if isStringInSlice(group, subject.Groups) { + return true + } + } + return false +} + +// isIPMatching check whether user's IP is in one of the network ranges. +func isIPMatching(ip net.IP, networks []string) bool { + // If no network is provided in the rule, we match any network + if len(networks) == 0 { + return true + } + + for _, network := range networks { + if !strings.Contains(network, "/") { + if ip.String() == network { + return true + } + continue + } + _, ipNet, err := net.ParseCIDR(network) + if err != nil { + // TODO(c.michaud): make sure the rule is valid at startup to + // to such a case here. + continue + } + + if ipNet.Contains(ip) { + return true + } + } + return false +} + +func isStringInSlice(a string, list []string) bool { + for _, b := range list { + if b == a { + return true + } + } + return false +} + +// selectMatchingSubjectRules take a set of rules and select only the rules matching the subject constraints. +func selectMatchingSubjectRules(rules []schema.ACLRule, subject Subject) []schema.ACLRule { + selectedRules := []schema.ACLRule{} + + for _, rule := range rules { + if isSubjectMatching(subject, rule.Subject) && + isIPMatching(subject.IP, rule.Networks) { + + selectedRules = append(selectedRules, rule) + } + } + + return selectedRules +} + +func selectMatchingObjectRules(rules []schema.ACLRule, object Object) []schema.ACLRule { + selectedRules := []schema.ACLRule{} + + for _, rule := range rules { + if isDomainMatching(object.Domain, rule.Domain) && + isPathMatching(object.Path, rule.Resources) { + + selectedRules = append(selectedRules, rule) + } + } + return selectedRules +} + +func selectMatchingRules(rules []schema.ACLRule, subject Subject, object Object) []schema.ACLRule { + matchingRules := selectMatchingSubjectRules(rules, subject) + return selectMatchingObjectRules(matchingRules, object) +} + +func policyToLevel(policy string) Level { + switch policy { + case "bypass": + return Bypass + case "one_factor": + return OneFactor + case "two_factor": + return TwoFactor + case "deny": + return Denied + } + // By default the deny policy applies. + return Denied +} + +// GetRequiredLevel retrieve the required level of authorization to access the object. +func (p *Authorizer) GetRequiredLevel(subject Subject, requestURL url.URL) Level { + matchingRules := selectMatchingRules(p.configuration.Rules, subject, Object{ + Domain: requestURL.Hostname(), + Path: requestURL.Path, + }) + + if len(matchingRules) > 0 { + return policyToLevel(matchingRules[0].Policy) + } + return policyToLevel(p.configuration.DefaultPolicy) +} diff --git a/authorization/authorizer_test.go b/authorization/authorizer_test.go new file mode 100644 index 000000000..82611a0ab --- /dev/null +++ b/authorization/authorizer_test.go @@ -0,0 +1,261 @@ +package authorization + +import ( + "net" + "net/url" + "testing" + + "github.com/stretchr/testify/suite" + + "github.com/clems4ever/authelia/configuration/schema" + + "github.com/stretchr/testify/assert" +) + +var NoNet = []string{} +var LocalNet = []string{"127.0.0.1"} +var PrivateNet = []string{"192.168.1.0/24"} +var MultipleNet = []string{"192.168.1.0/24", "10.0.0.0/8"} +var MixedNetIP = []string{"192.168.1.0/24", "192.168.2.4"} + +type AuthorizerSuite struct { + suite.Suite +} + +type AuthorizerTester struct { + *Authorizer +} + +func NewAuthorizerTester(config schema.AccessControlConfiguration) *AuthorizerTester { + return &AuthorizerTester{ + NewAuthorizer(config), + } +} + +func (s *AuthorizerTester) CheckAuthorizations(t *testing.T, subject Subject, requestURI string, expectedLevel Level) { + url, _ := url.ParseRequestURI(requestURI) + level := s.GetRequiredLevel(Subject{ + Groups: subject.Groups, + Username: subject.Username, + IP: subject.IP, + }, *url) + + assert.Equal(t, expectedLevel, level) +} + +type AuthorizerTesterBuilder struct { + config schema.AccessControlConfiguration +} + +func NewAuthorizerBuilder() *AuthorizerTesterBuilder { + return &AuthorizerTesterBuilder{} +} + +func (b *AuthorizerTesterBuilder) WithDefaultPolicy(policy string) *AuthorizerTesterBuilder { + b.config.DefaultPolicy = policy + return b +} + +func (b *AuthorizerTesterBuilder) WithRule(rule schema.ACLRule) *AuthorizerTesterBuilder { + b.config.Rules = append(b.config.Rules, rule) + return b +} + +func (b *AuthorizerTesterBuilder) Build() *AuthorizerTester { + return NewAuthorizerTester(b.config) +} + +type Request struct { + subject Subject + object Object +} + +var AnonymousUser = Subject{ + Username: "", + Groups: []string{}, + IP: net.ParseIP("127.0.0.1"), +} + +var UserWithGroups = Subject{ + Username: "john", + Groups: []string{"dev", "admins"}, + IP: net.ParseIP("10.0.0.8"), +} + +var John = UserWithGroups + +var UserWithoutGroups = Subject{ + Username: "bob", + Groups: []string{}, + IP: net.ParseIP("10.0.0.7"), +} + +var Bob = UserWithoutGroups + +func (s *AuthorizerSuite) TestShouldCheckDefaultBypassConfig() { + tester := NewAuthorizerBuilder(). + WithDefaultPolicy("bypass").Build() + + tester.CheckAuthorizations(s.T(), AnonymousUser, "https://public.example.com/", Bypass) + tester.CheckAuthorizations(s.T(), UserWithGroups, "https://public.example.com/", Bypass) + tester.CheckAuthorizations(s.T(), UserWithoutGroups, "https://public.example.com/", Bypass) + tester.CheckAuthorizations(s.T(), UserWithoutGroups, "https://public.example.com/elsewhere", Bypass) +} + +func (s *AuthorizerSuite) TestShouldCheckDefaultDeniedConfig() { + tester := NewAuthorizerBuilder(). + WithDefaultPolicy("deny").Build() + + tester.CheckAuthorizations(s.T(), AnonymousUser, "https://public.example.com/", Denied) + tester.CheckAuthorizations(s.T(), UserWithGroups, "https://public.example.com/", Denied) + tester.CheckAuthorizations(s.T(), UserWithoutGroups, "https://public.example.com/", Denied) + tester.CheckAuthorizations(s.T(), UserWithoutGroups, "https://public.example.com/elsewhere", Denied) +} + +func (s *AuthorizerSuite) TestShouldCheckMultiDomainRule() { + tester := NewAuthorizerBuilder(). + WithDefaultPolicy("deny"). + WithRule(schema.ACLRule{ + Domain: "*.example.com", + Policy: "bypass", + }). + Build() + + tester.CheckAuthorizations(s.T(), UserWithGroups, "https://public.example.com/", Bypass) + tester.CheckAuthorizations(s.T(), UserWithGroups, "https://private.example.com/", Bypass) + tester.CheckAuthorizations(s.T(), UserWithGroups, "https://public.example.com/elsewhere", Bypass) + tester.CheckAuthorizations(s.T(), UserWithGroups, "https://example.com/", Denied) + tester.CheckAuthorizations(s.T(), UserWithGroups, "https://public.example.com.c/", Denied) + tester.CheckAuthorizations(s.T(), UserWithGroups, "https://public.example.co/", Denied) +} + +func (s *AuthorizerSuite) TestShouldCheckFactorsPolicy() { + tester := NewAuthorizerBuilder(). + WithDefaultPolicy("deny"). + WithRule(schema.ACLRule{ + Domain: "single.example.com", + Policy: "one_factor", + }). + WithRule(schema.ACLRule{ + Domain: "protected.example.com", + Policy: "two_factor", + }). + WithRule(schema.ACLRule{ + Domain: "public.example.com", + Policy: "bypass", + }). + Build() + + tester.CheckAuthorizations(s.T(), UserWithGroups, "https://public.example.com/", Bypass) + tester.CheckAuthorizations(s.T(), UserWithGroups, "https://protected.example.com/", TwoFactor) + tester.CheckAuthorizations(s.T(), UserWithGroups, "https://single.example.com/", OneFactor) + tester.CheckAuthorizations(s.T(), UserWithGroups, "https://example.com/", Denied) +} + +func (s *AuthorizerSuite) TestShouldCheckRulePrecedence() { + tester := NewAuthorizerBuilder(). + WithDefaultPolicy("deny"). + WithRule(schema.ACLRule{ + Domain: "protected.example.com", + Policy: "bypass", + Subject: "user:john", + }). + WithRule(schema.ACLRule{ + Domain: "protected.example.com", + Policy: "one_factor", + }). + WithRule(schema.ACLRule{ + Domain: "*.example.com", + Policy: "two_factor", + }). + Build() + + tester.CheckAuthorizations(s.T(), John, "https://protected.example.com/", Bypass) + tester.CheckAuthorizations(s.T(), Bob, "https://protected.example.com/", OneFactor) + tester.CheckAuthorizations(s.T(), John, "https://public.example.com/", TwoFactor) +} + +func (s *AuthorizerSuite) TestShouldCheckUserMatching() { + tester := NewAuthorizerBuilder(). + WithDefaultPolicy("deny"). + WithRule(schema.ACLRule{ + Domain: "protected.example.com", + Policy: "bypass", + Subject: "user:john", + }). + Build() + + tester.CheckAuthorizations(s.T(), John, "https://protected.example.com/", Bypass) + tester.CheckAuthorizations(s.T(), Bob, "https://protected.example.com/", Denied) +} + +func (s *AuthorizerSuite) TestShouldCheckGroupMatching() { + tester := NewAuthorizerBuilder(). + WithDefaultPolicy("deny"). + WithRule(schema.ACLRule{ + Domain: "protected.example.com", + Policy: "bypass", + Subject: "group:admins", + }). + Build() + + tester.CheckAuthorizations(s.T(), John, "https://protected.example.com/", Bypass) + tester.CheckAuthorizations(s.T(), Bob, "https://protected.example.com/", Denied) +} + +func (s *AuthorizerSuite) TestShouldCheckIPMatching() { + tester := NewAuthorizerBuilder(). + WithDefaultPolicy("deny"). + WithRule(schema.ACLRule{ + Domain: "protected.example.com", + Policy: "bypass", + Networks: []string{"192.168.1.8", "10.0.0.8"}, + }). + WithRule(schema.ACLRule{ + Domain: "protected.example.com", + Policy: "one_factor", + Networks: []string{"10.0.0.7"}, + }). + WithRule(schema.ACLRule{ + Domain: "net.example.com", + Policy: "two_factor", + Networks: []string{"10.0.0.0/8"}, + }). + Build() + + tester.CheckAuthorizations(s.T(), John, "https://protected.example.com/", Bypass) + tester.CheckAuthorizations(s.T(), Bob, "https://protected.example.com/", OneFactor) + tester.CheckAuthorizations(s.T(), AnonymousUser, "https://protected.example.com/", Denied) + + tester.CheckAuthorizations(s.T(), John, "https://net.example.com/", TwoFactor) + tester.CheckAuthorizations(s.T(), Bob, "https://net.example.com/", TwoFactor) + tester.CheckAuthorizations(s.T(), AnonymousUser, "https://net.example.com/", Denied) +} + +func (s *AuthorizerSuite) TestShouldCheckResourceMatching() { + tester := NewAuthorizerBuilder(). + WithDefaultPolicy("deny"). + WithRule(schema.ACLRule{ + Domain: "resource.example.com", + Policy: "bypass", + Resources: []string{"^/bypass/[a-z]+$", "^/$", "embedded"}, + }). + WithRule(schema.ACLRule{ + Domain: "resource.example.com", + Policy: "one_factor", + Resources: []string{"^/one_factor/[a-z]+$"}, + }). + Build() + + tester.CheckAuthorizations(s.T(), John, "https://resource.example.com/", Bypass) + tester.CheckAuthorizations(s.T(), John, "https://resource.example.com/bypass/abc", Bypass) + tester.CheckAuthorizations(s.T(), John, "https://resource.example.com/bypass/", Denied) + tester.CheckAuthorizations(s.T(), John, "https://resource.example.com/bypass/ABC", Denied) + tester.CheckAuthorizations(s.T(), John, "https://resource.example.com/one_factor/abc", OneFactor) + tester.CheckAuthorizations(s.T(), John, "https://resource.example.com/xyz/embedded/abc", Bypass) +} + +func TestRunSuite(t *testing.T) { + s := AuthorizerSuite{} + suite.Run(t, &s) +} diff --git a/authorization/const.go b/authorization/const.go new file mode 100644 index 000000000..99093bd81 --- /dev/null +++ b/authorization/const.go @@ -0,0 +1,15 @@ +package authorization + +// Level is the type representing an authorization level. +type Level int + +const ( + // Bypass bypass level. + Bypass Level = iota + // OneFactor one factor level. + OneFactor Level = iota + // TwoFactor two factor level. + TwoFactor Level = iota + // Denied denied level. + Denied Level = iota +) diff --git a/bootstrap.sh b/bootstrap.sh index 8d5fc04f0..f2618701d 100644 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -3,7 +3,6 @@ export PATH=$(pwd)/scripts:/tmp:$PATH export PS1="(authelia) $PS1" -echo "[BOOTSTRAP] Installing npm packages..." npm i pushd client @@ -27,5 +26,8 @@ fi echo "[BOOTSTRAP] Running additional bootstrap steps..." authelia-scripts bootstrap +# Create temporary directory that will contain the databases used in tests. +mkdir -p /tmp/authelia + echo "[BOOTSTRAP] Run 'authelia-scripts suites start dockerhub' to start Authelia and visit https://home.example.com:8080." echo "[BOOTSTRAP] More details at https://github.com/clems4ever/authelia/blob/master/docs/getting-started.md" diff --git a/client/package-lock.json b/client/package-lock.json index 2a263c814..0f2e18680 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -9,7 +9,7 @@ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", "requires": { - "@babel/highlight": "^7.0.0" + "@babel/highlight": "7.0.0" } }, "@babel/core": { @@ -17,20 +17,20 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.1.6.tgz", "integrity": "sha512-Hz6PJT6e44iUNpAn8AoyAs6B3bl60g7MJQaI0rZEar6ECzh6+srYO1xlIdssio34mPaUtAb1y+XlkkSJzok3yw==", "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.1.6", - "@babel/helpers": "^7.1.5", - "@babel/parser": "^7.1.6", - "@babel/template": "^7.1.2", - "@babel/traverse": "^7.1.6", - "@babel/types": "^7.1.6", - "convert-source-map": "^1.1.0", - "debug": "^4.1.0", - "json5": "^2.1.0", - "lodash": "^4.17.10", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" + "@babel/code-frame": "7.0.0", + "@babel/generator": "7.2.2", + "@babel/helpers": "7.2.0", + "@babel/parser": "7.2.3", + "@babel/template": "7.2.2", + "@babel/traverse": "7.2.3", + "@babel/types": "7.2.2", + "convert-source-map": "1.6.0", + "debug": "4.1.1", + "json5": "2.1.0", + "lodash": "4.17.11", + "resolve": "1.8.1", + "semver": "5.6.0", + "source-map": "0.5.7" } }, "@babel/generator": { @@ -38,11 +38,11 @@ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.2.2.tgz", "integrity": "sha512-I4o675J/iS8k+P38dvJ3IBGqObLXyQLTxtrR4u9cSUJOURvafeEWb/pFMOTwtNrmq73mJzyF6ueTbO1BtN0Zeg==", "requires": { - "@babel/types": "^7.2.2", - "jsesc": "^2.5.1", - "lodash": "^4.17.10", - "source-map": "^0.5.0", - "trim-right": "^1.0.1" + "@babel/types": "7.2.2", + "jsesc": "2.5.2", + "lodash": "4.17.11", + "source-map": "0.5.7", + "trim-right": "1.0.1" } }, "@babel/helper-annotate-as-pure": { @@ -50,7 +50,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz", "integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==", "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "7.2.2" } }, "@babel/helper-builder-binary-assignment-operator-visitor": { @@ -58,8 +58,8 @@ "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz", "integrity": "sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==", "requires": { - "@babel/helper-explode-assignable-expression": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-explode-assignable-expression": "7.1.0", + "@babel/types": "7.2.2" } }, "@babel/helper-builder-react-jsx": { @@ -67,8 +67,8 @@ "resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.0.0.tgz", "integrity": "sha512-ebJ2JM6NAKW0fQEqN8hOLxK84RbRz9OkUhGS/Xd5u56ejMfVbayJ4+LykERZCOUM6faa6Fp3SZNX3fcT16MKHw==", "requires": { - "@babel/types": "^7.0.0", - "esutils": "^2.0.0" + "@babel/types": "7.2.2", + "esutils": "2.0.2" } }, "@babel/helper-call-delegate": { @@ -76,9 +76,9 @@ "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.1.0.tgz", "integrity": "sha512-YEtYZrw3GUK6emQHKthltKNZwszBcHK58Ygcis+gVUrF4/FmTVr5CCqQNSfmvg2y+YDEANyYoaLz/SHsnusCwQ==", "requires": { - "@babel/helper-hoist-variables": "^7.0.0", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-hoist-variables": "7.0.0", + "@babel/traverse": "7.2.3", + "@babel/types": "7.2.2" } }, "@babel/helper-define-map": { @@ -86,9 +86,9 @@ "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.1.0.tgz", "integrity": "sha512-yPPcW8dc3gZLN+U1mhYV91QU3n5uTbx7DUdf8NnPbjS0RMwBuHi9Xt2MUgppmNz7CJxTBWsGczTiEp1CSOTPRg==", "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/types": "^7.0.0", - "lodash": "^4.17.10" + "@babel/helper-function-name": "7.1.0", + "@babel/types": "7.2.2", + "lodash": "4.17.11" } }, "@babel/helper-explode-assignable-expression": { @@ -96,8 +96,8 @@ "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz", "integrity": "sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==", "requires": { - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/traverse": "7.2.3", + "@babel/types": "7.2.2" } }, "@babel/helper-function-name": { @@ -105,9 +105,9 @@ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", "requires": { - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-get-function-arity": "7.0.0", + "@babel/template": "7.2.2", + "@babel/types": "7.2.2" } }, "@babel/helper-get-function-arity": { @@ -115,7 +115,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "7.2.2" } }, "@babel/helper-hoist-variables": { @@ -123,7 +123,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.0.0.tgz", "integrity": "sha512-Ggv5sldXUeSKsuzLkddtyhyHe2YantsxWKNi7A+7LeD12ExRDWTRk29JCXpaHPAbMaIPZSil7n+lq78WY2VY7w==", "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "7.2.2" } }, "@babel/helper-member-expression-to-functions": { @@ -131,7 +131,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz", "integrity": "sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg==", "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "7.2.2" } }, "@babel/helper-module-imports": { @@ -139,7 +139,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz", "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==", "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "7.2.2" } }, "@babel/helper-module-transforms": { @@ -147,12 +147,12 @@ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.2.2.tgz", "integrity": "sha512-YRD7I6Wsv+IHuTPkAmAS4HhY0dkPobgLftHp0cRGZSdrRvmZY8rFvae/GVu3bD00qscuvK3WPHB3YdNpBXUqrA==", "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-simple-access": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/template": "^7.2.2", - "@babel/types": "^7.2.2", - "lodash": "^4.17.10" + "@babel/helper-module-imports": "7.0.0", + "@babel/helper-simple-access": "7.1.0", + "@babel/helper-split-export-declaration": "7.0.0", + "@babel/template": "7.2.2", + "@babel/types": "7.2.2", + "lodash": "4.17.11" } }, "@babel/helper-optimise-call-expression": { @@ -160,7 +160,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz", "integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==", "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "7.2.2" } }, "@babel/helper-plugin-utils": { @@ -173,7 +173,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.0.0.tgz", "integrity": "sha512-TR0/N0NDCcUIUEbqV6dCO+LptmmSQFQ7q70lfcEB4URsjD0E1HzicrwUH+ap6BAQ2jhCX9Q4UqZy4wilujWlkg==", "requires": { - "lodash": "^4.17.10" + "lodash": "4.17.11" } }, "@babel/helper-remap-async-to-generator": { @@ -181,11 +181,11 @@ "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz", "integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==", "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-wrap-function": "^7.1.0", - "@babel/template": "^7.1.0", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-annotate-as-pure": "7.0.0", + "@babel/helper-wrap-function": "7.2.0", + "@babel/template": "7.2.2", + "@babel/traverse": "7.2.3", + "@babel/types": "7.2.2" } }, "@babel/helper-replace-supers": { @@ -193,10 +193,10 @@ "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.2.3.tgz", "integrity": "sha512-GyieIznGUfPXPWu0yLS6U55Mz67AZD9cUk0BfirOWlPrXlBcan9Gz+vHGz+cPfuoweZSnPzPIm67VtQM0OWZbA==", "requires": { - "@babel/helper-member-expression-to-functions": "^7.0.0", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/traverse": "^7.2.3", - "@babel/types": "^7.0.0" + "@babel/helper-member-expression-to-functions": "7.0.0", + "@babel/helper-optimise-call-expression": "7.0.0", + "@babel/traverse": "7.2.3", + "@babel/types": "7.2.2" } }, "@babel/helper-simple-access": { @@ -204,8 +204,8 @@ "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz", "integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==", "requires": { - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/template": "7.2.2", + "@babel/types": "7.2.2" } }, "@babel/helper-split-export-declaration": { @@ -213,7 +213,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz", "integrity": "sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag==", "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "7.2.2" } }, "@babel/helper-wrap-function": { @@ -221,10 +221,10 @@ "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz", "integrity": "sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ==", "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/template": "^7.1.0", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.2.0" + "@babel/helper-function-name": "7.1.0", + "@babel/template": "7.2.2", + "@babel/traverse": "7.2.3", + "@babel/types": "7.2.2" } }, "@babel/helpers": { @@ -232,9 +232,9 @@ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.2.0.tgz", "integrity": "sha512-Fr07N+ea0dMcMN8nFpuK6dUIT7/ivt9yKQdEEnjVS83tG2pHwPi03gYmk/tyuwONnZ+sY+GFFPlWGgCtW1hF9A==", "requires": { - "@babel/template": "^7.1.2", - "@babel/traverse": "^7.1.5", - "@babel/types": "^7.2.0" + "@babel/template": "7.2.2", + "@babel/traverse": "7.2.3", + "@babel/types": "7.2.2" } }, "@babel/highlight": { @@ -242,9 +242,9 @@ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" + "chalk": "2.4.1", + "esutils": "2.0.2", + "js-tokens": "4.0.0" } }, "@babel/parser": { @@ -257,9 +257,9 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz", "integrity": "sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-remap-async-to-generator": "^7.1.0", - "@babel/plugin-syntax-async-generators": "^7.2.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/helper-remap-async-to-generator": "7.1.0", + "@babel/plugin-syntax-async-generators": "7.2.0" } }, "@babel/plugin-proposal-class-properties": { @@ -267,12 +267,12 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.1.0.tgz", "integrity": "sha512-/PCJWN+CKt5v1xcGn4vnuu13QDoV+P7NcICP44BoonAJoPSGwVkgrXihFIQGiEjjPlUDBIw1cM7wYFLARS2/hw==", "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-member-expression-to-functions": "^7.0.0", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.1.0", - "@babel/plugin-syntax-class-properties": "^7.0.0" + "@babel/helper-function-name": "7.1.0", + "@babel/helper-member-expression-to-functions": "7.0.0", + "@babel/helper-optimise-call-expression": "7.0.0", + "@babel/helper-plugin-utils": "7.0.0", + "@babel/helper-replace-supers": "7.2.3", + "@babel/plugin-syntax-class-properties": "7.2.0" } }, "@babel/plugin-proposal-decorators": { @@ -280,10 +280,10 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.1.6.tgz", "integrity": "sha512-U42f8KhUbtlhUDyV/wK4Rq/wWh8vWyttYABckG/v0vVnMPvayOewZC/83CbVdmyP+UhEqI368FEQ7hHMfhBpQA==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/plugin-syntax-decorators": "^7.1.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/helper-replace-supers": "7.2.3", + "@babel/helper-split-export-declaration": "7.0.0", + "@babel/plugin-syntax-decorators": "7.2.0" } }, "@babel/plugin-proposal-json-strings": { @@ -291,8 +291,8 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz", "integrity": "sha512-MAFV1CA/YVmYwZG0fBQyXhmj0BHCB5egZHCKWIFVv/XCxAeVGIHfos3SwDck4LvCllENIAg7xMKOG5kH0dzyUg==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-json-strings": "^7.2.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-json-strings": "7.2.0" } }, "@babel/plugin-proposal-object-rest-spread": { @@ -300,8 +300,8 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.2.0.tgz", "integrity": "sha512-1L5mWLSvR76XYUQJXkd/EEQgjq8HHRP6lQuZTTg0VA4tTGPpGemmCdAfQIz1rzEuWAm+ecP8PyyEm30jC1eQCg==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-object-rest-spread": "^7.2.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-object-rest-spread": "7.2.0" } }, "@babel/plugin-proposal-optional-catch-binding": { @@ -309,8 +309,8 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz", "integrity": "sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.2.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-optional-catch-binding": "7.2.0" } }, "@babel/plugin-proposal-unicode-property-regex": { @@ -318,9 +318,9 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.2.0.tgz", "integrity": "sha512-LvRVYb7kikuOtIoUeWTkOxQEV1kYvL5B6U3iWEGCzPNRus1MzJweFqORTj+0jkxozkTSYNJozPOddxmqdqsRpw==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.0.0", - "regexpu-core": "^4.2.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/helper-regex": "7.0.0", + "regexpu-core": "4.4.0" } }, "@babel/plugin-syntax-async-generators": { @@ -328,7 +328,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz", "integrity": "sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-class-properties": { @@ -336,7 +336,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.2.0.tgz", "integrity": "sha512-UxYaGXYQ7rrKJS/PxIKRkv3exi05oH7rokBAsmCSsCxz1sVPZ7Fu6FzKoGgUvmY+0YgSkYHgUoCh5R5bCNBQlw==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-decorators": { @@ -344,7 +344,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.2.0.tgz", "integrity": "sha512-38QdqVoXdHUQfTpZo3rQwqQdWtCn5tMv4uV6r2RMfTqNBuv4ZBhz79SfaQWKTVmxHjeFv/DnXVC/+agHCklYWA==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-dynamic-import": { @@ -352,7 +352,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.0.0.tgz", "integrity": "sha512-Gt9xNyRrCHCiyX/ZxDGOcBnlJl0I3IWicpZRC4CdC0P5a/I07Ya2OAMEBU+J7GmRFVmIetqEYRko6QYRuKOESw==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-flow": { @@ -360,7 +360,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.2.0.tgz", "integrity": "sha512-r6YMuZDWLtLlu0kqIim5o/3TNRAlWb073HwT3e2nKf9I8IIvOggPrnILYPsrrKilmn/mYEMCf/Z07w3yQJF6dg==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-json-strings": { @@ -368,7 +368,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz", "integrity": "sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-jsx": { @@ -376,7 +376,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.2.0.tgz", "integrity": "sha512-VyN4QANJkRW6lDBmENzRszvZf3/4AXaj9YR7GwrWeeN9tEBPuXbmDYVU9bYBN0D70zCWVwUy0HWq2553VCb6Hw==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-object-rest-spread": { @@ -384,7 +384,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-optional-catch-binding": { @@ -392,7 +392,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz", "integrity": "sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-typescript": { @@ -400,7 +400,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.2.0.tgz", "integrity": "sha512-WhKr6yu6yGpGcNMVgIBuI9MkredpVc7Y3YR4UzEZmDztHoL6wV56YBHLhWnjO1EvId1B32HrD3DRFc+zSoKI1g==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-arrow-functions": { @@ -408,7 +408,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz", "integrity": "sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-async-to-generator": { @@ -416,9 +416,9 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.2.0.tgz", "integrity": "sha512-CEHzg4g5UraReozI9D4fblBYABs7IM6UerAVG7EJVrTLC5keh00aEuLUT+O40+mJCEzaXkYfTCUKIyeDfMOFFQ==", "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-remap-async-to-generator": "^7.1.0" + "@babel/helper-module-imports": "7.0.0", + "@babel/helper-plugin-utils": "7.0.0", + "@babel/helper-remap-async-to-generator": "7.1.0" } }, "@babel/plugin-transform-block-scoped-functions": { @@ -426,7 +426,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz", "integrity": "sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-block-scoping": { @@ -434,8 +434,8 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.2.0.tgz", "integrity": "sha512-vDTgf19ZEV6mx35yiPJe4fS02mPQUUcBNwWQSZFXSzTSbsJFQvHt7DqyS3LK8oOWALFOsJ+8bbqBgkirZteD5Q==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "lodash": "^4.17.10" + "@babel/helper-plugin-utils": "7.0.0", + "lodash": "4.17.11" } }, "@babel/plugin-transform-classes": { @@ -443,14 +443,14 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.2.2.tgz", "integrity": "sha512-gEZvgTy1VtcDOaQty1l10T3jQmJKlNVxLDCs+3rCVPr6nMkODLELxViq5X9l+rfxbie3XrfrMCYYY6eX3aOcOQ==", "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-define-map": "^7.1.0", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.0.0", - "globals": "^11.1.0" + "@babel/helper-annotate-as-pure": "7.0.0", + "@babel/helper-define-map": "7.1.0", + "@babel/helper-function-name": "7.1.0", + "@babel/helper-optimise-call-expression": "7.0.0", + "@babel/helper-plugin-utils": "7.0.0", + "@babel/helper-replace-supers": "7.2.3", + "@babel/helper-split-export-declaration": "7.0.0", + "globals": "11.10.0" } }, "@babel/plugin-transform-computed-properties": { @@ -458,7 +458,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz", "integrity": "sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-destructuring": { @@ -466,7 +466,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.2.0.tgz", "integrity": "sha512-coVO2Ayv7g0qdDbrNiadE4bU7lvCd9H539m2gMknyVjjMdwF/iCOM7R+E8PkntoqLkltO0rk+3axhpp/0v68VQ==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-dotall-regex": { @@ -474,9 +474,9 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.2.0.tgz", "integrity": "sha512-sKxnyHfizweTgKZf7XsXu/CNupKhzijptfTM+bozonIuyVrLWVUvYjE2bhuSBML8VQeMxq4Mm63Q9qvcvUcciQ==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.0.0", - "regexpu-core": "^4.1.3" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/helper-regex": "7.0.0", + "regexpu-core": "4.4.0" } }, "@babel/plugin-transform-duplicate-keys": { @@ -484,7 +484,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.2.0.tgz", "integrity": "sha512-q+yuxW4DsTjNceUiTzK0L+AfQ0zD9rWaTLiUqHA8p0gxx7lu1EylenfzjeIWNkPy6e/0VG/Wjw9uf9LueQwLOw==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-exponentiation-operator": { @@ -492,8 +492,8 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz", "integrity": "sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A==", "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-builder-binary-assignment-operator-visitor": "7.1.0", + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-flow-strip-types": { @@ -501,8 +501,8 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.1.6.tgz", "integrity": "sha512-0tyFAAjJmnRlr8MVJV39ASn1hv+PbdVP71hf7aAseqLfQ0o9QXk9htbMbq7/ZYXnUIp6gDw0lUUP0+PQMbbtmg==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-flow": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-flow": "7.2.0" } }, "@babel/plugin-transform-for-of": { @@ -510,7 +510,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.2.0.tgz", "integrity": "sha512-Kz7Mt0SsV2tQk6jG5bBv5phVbkd0gd27SgYD4hH1aLMJRchM0dzHaXvrWhVZ+WxAlDoAKZ7Uy3jVTW2mKXQ1WQ==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-function-name": { @@ -518,8 +518,8 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.2.0.tgz", "integrity": "sha512-kWgksow9lHdvBC2Z4mxTsvc7YdY7w/V6B2vy9cTIPtLEE9NhwoWivaxdNM/S37elu5bqlLP/qOY906LukO9lkQ==", "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-function-name": "7.1.0", + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-literals": { @@ -527,7 +527,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz", "integrity": "sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-modules-amd": { @@ -535,8 +535,8 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.2.0.tgz", "integrity": "sha512-mK2A8ucqz1qhrdqjS9VMIDfIvvT2thrEsIQzbaTdc5QFzhDjQv2CkJJ5f6BXIkgbmaoax3zBr2RyvV/8zeoUZw==", "requires": { - "@babel/helper-module-transforms": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-module-transforms": "7.2.2", + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-modules-commonjs": { @@ -544,9 +544,9 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.2.0.tgz", "integrity": "sha512-V6y0uaUQrQPXUrmj+hgnks8va2L0zcZymeU7TtWEgdRLNkceafKXEduv7QzgQAE4lT+suwooG9dC7LFhdRAbVQ==", "requires": { - "@babel/helper-module-transforms": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-simple-access": "^7.1.0" + "@babel/helper-module-transforms": "7.2.2", + "@babel/helper-plugin-utils": "7.0.0", + "@babel/helper-simple-access": "7.1.0" } }, "@babel/plugin-transform-modules-systemjs": { @@ -554,8 +554,8 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.2.0.tgz", "integrity": "sha512-aYJwpAhoK9a+1+O625WIjvMY11wkB/ok0WClVwmeo3mCjcNRjt+/8gHWrB5i+00mUju0gWsBkQnPpdvQ7PImmQ==", "requires": { - "@babel/helper-hoist-variables": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-hoist-variables": "7.0.0", + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-modules-umd": { @@ -563,8 +563,8 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz", "integrity": "sha512-BV3bw6MyUH1iIsGhXlOK6sXhmSarZjtJ/vMiD9dNmpY8QXFFQTj+6v92pcfy1iqa8DeAfJFwoxcrS/TUZda6sw==", "requires": { - "@babel/helper-module-transforms": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-module-transforms": "7.2.2", + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-new-target": { @@ -572,7 +572,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.0.0.tgz", "integrity": "sha512-yin069FYjah+LbqfGeTfzIBODex/e++Yfa0rH0fpfam9uTbuEeEOx5GLGr210ggOV77mVRNoeqSYqeuaqSzVSw==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-object-super": { @@ -580,8 +580,8 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.2.0.tgz", "integrity": "sha512-VMyhPYZISFZAqAPVkiYb7dUe2AsVi2/wCT5+wZdsNO31FojQJa9ns40hzZ6U9f50Jlq4w6qwzdBB2uwqZ00ebg==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.1.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/helper-replace-supers": "7.2.3" } }, "@babel/plugin-transform-parameters": { @@ -589,9 +589,9 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.2.0.tgz", "integrity": "sha512-kB9+hhUidIgUoBQ0MsxMewhzr8i60nMa2KgeJKQWYrqQpqcBYtnpR+JgkadZVZoaEZ/eKu9mclFaVwhRpLNSzA==", "requires": { - "@babel/helper-call-delegate": "^7.1.0", - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-call-delegate": "7.1.0", + "@babel/helper-get-function-arity": "7.0.0", + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-react-constant-elements": { @@ -599,8 +599,8 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.2.0.tgz", "integrity": "sha512-YYQFg6giRFMsZPKUM9v+VcHOdfSQdz9jHCx3akAi3UYgyjndmdYGSXylQ/V+HswQt4fL8IklchD9HTsaOCrWQQ==", "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-annotate-as-pure": "7.0.0", + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-react-display-name": { @@ -608,7 +608,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.2.0.tgz", "integrity": "sha512-Htf/tPa5haZvRMiNSQSFifK12gtr/8vwfr+A9y69uF0QcU77AVu4K7MiHEkTxF7lQoHOL0F9ErqgfNEAKgXj7A==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-react-jsx": { @@ -616,9 +616,9 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.2.0.tgz", "integrity": "sha512-h/fZRel5wAfCqcKgq3OhbmYaReo7KkoJBpt8XnvpS7wqaNMqtw5xhxutzcm35iMUWucfAdT/nvGTsWln0JTg2Q==", "requires": { - "@babel/helper-builder-react-jsx": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-jsx": "^7.2.0" + "@babel/helper-builder-react-jsx": "7.0.0", + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-jsx": "7.2.0" } }, "@babel/plugin-transform-react-jsx-self": { @@ -626,8 +626,8 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.2.0.tgz", "integrity": "sha512-v6S5L/myicZEy+jr6ielB0OR8h+EH/1QFx/YJ7c7Ua+7lqsjj/vW6fD5FR9hB/6y7mGbfT4vAURn3xqBxsUcdg==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-jsx": "^7.2.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-jsx": "7.2.0" } }, "@babel/plugin-transform-react-jsx-source": { @@ -635,8 +635,8 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.2.0.tgz", "integrity": "sha512-A32OkKTp4i5U6aE88GwwcuV4HAprUgHcTq0sSafLxjr6AW0QahrCRCjxogkbbcdtpbXkuTOlgpjophCxb6sh5g==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-jsx": "^7.2.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-jsx": "7.2.0" } }, "@babel/plugin-transform-regenerator": { @@ -644,7 +644,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.0.0.tgz", "integrity": "sha512-sj2qzsEx8KDVv1QuJc/dEfilkg3RRPvPYx/VnKLtItVQRWt1Wqf5eVCOLZm29CiGFfYYsA3VPjfizTCV0S0Dlw==", "requires": { - "regenerator-transform": "^0.13.3" + "regenerator-transform": "0.13.3" } }, "@babel/plugin-transform-runtime": { @@ -652,10 +652,10 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.1.0.tgz", "integrity": "sha512-WFLMgzu5DLQEah0lKTJzYb14vd6UiES7PTnXcvrPZ1VrwFeJ+mTbvr65fFAsXYMt2bIoOoC0jk76zY1S7HZjUg==", "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "resolve": "^1.8.1", - "semver": "^5.5.1" + "@babel/helper-module-imports": "7.0.0", + "@babel/helper-plugin-utils": "7.0.0", + "resolve": "1.8.1", + "semver": "5.6.0" } }, "@babel/plugin-transform-shorthand-properties": { @@ -663,7 +663,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz", "integrity": "sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-spread": { @@ -671,7 +671,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.2.2.tgz", "integrity": "sha512-KWfky/58vubwtS0hLqEnrWJjsMGaOeSBn90Ezn5Jeg9Z8KKHmELbP1yGylMlm5N6TPKeY9A2+UaSYLdxahg01w==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-sticky-regex": { @@ -679,8 +679,8 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz", "integrity": "sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/helper-regex": "7.0.0" } }, "@babel/plugin-transform-template-literals": { @@ -688,8 +688,8 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.2.0.tgz", "integrity": "sha512-FkPix00J9A/XWXv4VoKJBMeSkyY9x/TqIh76wzcdfl57RJJcf8CehQ08uwfhCDNtRQYtHQKBTwKZDEyjE13Lwg==", "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-annotate-as-pure": "7.0.0", + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-typeof-symbol": { @@ -697,7 +697,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz", "integrity": "sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-typescript": { @@ -705,8 +705,8 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.2.0.tgz", "integrity": "sha512-EnI7i2/gJ7ZNr2MuyvN2Hu+BHJENlxWte5XygPvfj/MbvtOkWor9zcnHpMMQL2YYaaCcqtIvJUyJ7QVfoGs7ew==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-typescript": "^7.2.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-typescript": "7.2.0" } }, "@babel/plugin-transform-unicode-regex": { @@ -714,9 +714,9 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.2.0.tgz", "integrity": "sha512-m48Y0lMhrbXEJnVUaYly29jRXbQ3ksxPrS1Tg8t+MHqzXhtBYAvI51euOBaoAlZLPHsieY9XPVMf80a5x0cPcA==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.0.0", - "regexpu-core": "^4.1.3" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/helper-regex": "7.0.0", + "regexpu-core": "4.4.0" } }, "@babel/preset-env": { @@ -724,47 +724,47 @@ "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.2.3.tgz", "integrity": "sha512-AuHzW7a9rbv5WXmvGaPX7wADxFkZIqKlbBh1dmZUQp4iwiPpkE/Qnrji6SC4UQCQzvWY/cpHET29eUhXS9cLPw==", "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-async-generator-functions": "^7.2.0", - "@babel/plugin-proposal-json-strings": "^7.2.0", - "@babel/plugin-proposal-object-rest-spread": "^7.2.0", - "@babel/plugin-proposal-optional-catch-binding": "^7.2.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.2.0", - "@babel/plugin-syntax-async-generators": "^7.2.0", - "@babel/plugin-syntax-object-rest-spread": "^7.2.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.2.0", - "@babel/plugin-transform-arrow-functions": "^7.2.0", - "@babel/plugin-transform-async-to-generator": "^7.2.0", - "@babel/plugin-transform-block-scoped-functions": "^7.2.0", - "@babel/plugin-transform-block-scoping": "^7.2.0", - "@babel/plugin-transform-classes": "^7.2.0", - "@babel/plugin-transform-computed-properties": "^7.2.0", - "@babel/plugin-transform-destructuring": "^7.2.0", - "@babel/plugin-transform-dotall-regex": "^7.2.0", - "@babel/plugin-transform-duplicate-keys": "^7.2.0", - "@babel/plugin-transform-exponentiation-operator": "^7.2.0", - "@babel/plugin-transform-for-of": "^7.2.0", - "@babel/plugin-transform-function-name": "^7.2.0", - "@babel/plugin-transform-literals": "^7.2.0", - "@babel/plugin-transform-modules-amd": "^7.2.0", - "@babel/plugin-transform-modules-commonjs": "^7.2.0", - "@babel/plugin-transform-modules-systemjs": "^7.2.0", - "@babel/plugin-transform-modules-umd": "^7.2.0", - "@babel/plugin-transform-new-target": "^7.0.0", - "@babel/plugin-transform-object-super": "^7.2.0", - "@babel/plugin-transform-parameters": "^7.2.0", - "@babel/plugin-transform-regenerator": "^7.0.0", - "@babel/plugin-transform-shorthand-properties": "^7.2.0", - "@babel/plugin-transform-spread": "^7.2.0", - "@babel/plugin-transform-sticky-regex": "^7.2.0", - "@babel/plugin-transform-template-literals": "^7.2.0", - "@babel/plugin-transform-typeof-symbol": "^7.2.0", - "@babel/plugin-transform-unicode-regex": "^7.2.0", - "browserslist": "^4.3.4", - "invariant": "^2.2.2", - "js-levenshtein": "^1.1.3", - "semver": "^5.3.0" + "@babel/helper-module-imports": "7.0.0", + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-proposal-async-generator-functions": "7.2.0", + "@babel/plugin-proposal-json-strings": "7.2.0", + "@babel/plugin-proposal-object-rest-spread": "7.2.0", + "@babel/plugin-proposal-optional-catch-binding": "7.2.0", + "@babel/plugin-proposal-unicode-property-regex": "7.2.0", + "@babel/plugin-syntax-async-generators": "7.2.0", + "@babel/plugin-syntax-object-rest-spread": "7.2.0", + "@babel/plugin-syntax-optional-catch-binding": "7.2.0", + "@babel/plugin-transform-arrow-functions": "7.2.0", + "@babel/plugin-transform-async-to-generator": "7.2.0", + "@babel/plugin-transform-block-scoped-functions": "7.2.0", + "@babel/plugin-transform-block-scoping": "7.2.0", + "@babel/plugin-transform-classes": "7.2.2", + "@babel/plugin-transform-computed-properties": "7.2.0", + "@babel/plugin-transform-destructuring": "7.2.0", + "@babel/plugin-transform-dotall-regex": "7.2.0", + "@babel/plugin-transform-duplicate-keys": "7.2.0", + "@babel/plugin-transform-exponentiation-operator": "7.2.0", + "@babel/plugin-transform-for-of": "7.2.0", + "@babel/plugin-transform-function-name": "7.2.0", + "@babel/plugin-transform-literals": "7.2.0", + "@babel/plugin-transform-modules-amd": "7.2.0", + "@babel/plugin-transform-modules-commonjs": "7.2.0", + "@babel/plugin-transform-modules-systemjs": "7.2.0", + "@babel/plugin-transform-modules-umd": "7.2.0", + "@babel/plugin-transform-new-target": "7.0.0", + "@babel/plugin-transform-object-super": "7.2.0", + "@babel/plugin-transform-parameters": "7.2.0", + "@babel/plugin-transform-regenerator": "7.0.0", + "@babel/plugin-transform-shorthand-properties": "7.2.0", + "@babel/plugin-transform-spread": "7.2.2", + "@babel/plugin-transform-sticky-regex": "7.2.0", + "@babel/plugin-transform-template-literals": "7.2.0", + "@babel/plugin-transform-typeof-symbol": "7.2.0", + "@babel/plugin-transform-unicode-regex": "7.2.0", + "browserslist": "4.3.7", + "invariant": "2.2.4", + "js-levenshtein": "1.1.5", + "semver": "5.6.0" } }, "@babel/preset-react": { @@ -772,11 +772,11 @@ "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.0.0.tgz", "integrity": "sha512-oayxyPS4Zj+hF6Et11BwuBkmpgT/zMxyuZgFrMeZID6Hdh3dGlk4sHCAhdBCpuCKW2ppBfl2uCCetlrUIJRY3w==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-transform-react-display-name": "^7.0.0", - "@babel/plugin-transform-react-jsx": "^7.0.0", - "@babel/plugin-transform-react-jsx-self": "^7.0.0", - "@babel/plugin-transform-react-jsx-source": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-transform-react-display-name": "7.2.0", + "@babel/plugin-transform-react-jsx": "7.2.0", + "@babel/plugin-transform-react-jsx-self": "7.2.0", + "@babel/plugin-transform-react-jsx-source": "7.2.0" } }, "@babel/preset-typescript": { @@ -784,8 +784,8 @@ "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.1.0.tgz", "integrity": "sha512-LYveByuF9AOM8WrsNne5+N79k1YxjNB6gmpCQsnuSBAcV8QUeB+ZUxQzL7Rz7HksPbahymKkq2qBR+o36ggFZA==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-transform-typescript": "^7.1.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-transform-typescript": "7.2.0" } }, "@babel/runtime": { @@ -793,7 +793,7 @@ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.2.0.tgz", "integrity": "sha512-oouEibCbHMVdZSDlJBO6bZmID/zA/G/Qx3H1d3rSNPTD+L8UNKvCat7aKWSJ74zYbm5zWGh0GQN0hKj8zYFTCg==", "requires": { - "regenerator-runtime": "^0.12.0" + "regenerator-runtime": "0.12.1" } }, "@babel/template": { @@ -801,9 +801,9 @@ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.2.2.tgz", "integrity": "sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g==", "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.2.2", - "@babel/types": "^7.2.2" + "@babel/code-frame": "7.0.0", + "@babel/parser": "7.2.3", + "@babel/types": "7.2.2" } }, "@babel/traverse": { @@ -811,15 +811,15 @@ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.2.3.tgz", "integrity": "sha512-Z31oUD/fJvEWVR0lNZtfgvVt512ForCTNKYcJBGbPb1QZfve4WGH8Wsy7+Mev33/45fhP/hwQtvgusNdcCMgSw==", "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.2.2", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/parser": "^7.2.3", - "@babel/types": "^7.2.2", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.10" + "@babel/code-frame": "7.0.0", + "@babel/generator": "7.2.2", + "@babel/helper-function-name": "7.1.0", + "@babel/helper-split-export-declaration": "7.0.0", + "@babel/parser": "7.2.3", + "@babel/types": "7.2.2", + "debug": "4.1.1", + "globals": "11.10.0", + "lodash": "4.17.11" } }, "@babel/types": { @@ -827,9 +827,9 @@ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.2.2.tgz", "integrity": "sha512-fKCuD6UFUMkR541eDWL+2ih/xFZBXPOg/7EQFeTluMDebfqR4jrpaCjLhkWlQS4hT6nRa2PMEgXKbRB5/H2fpg==", "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.10", - "to-fast-properties": "^2.0.0" + "esutils": "2.0.2", + "lodash": "4.17.11", + "to-fast-properties": "2.0.0" } }, "@csstools/convert-colors": { @@ -852,12 +852,12 @@ "resolved": "https://registry.npmjs.org/@material/button/-/button-0.41.0.tgz", "integrity": "sha512-9mA/7P8yD3YPJ8ijwu0oOiT65OCa8Km3M9OF6VAsBE+XJS9Wo5hWDMgkv16raeOFeXj+1ALsjvuTz31JdcSkgQ==", "requires": { - "@material/elevation": "^0.41.0", - "@material/ripple": "^0.41.0", - "@material/rtl": "^0.40.1", - "@material/shape": "^0.41.0", - "@material/theme": "^0.41.0", - "@material/typography": "^0.41.0" + "@material/elevation": "0.41.0", + "@material/ripple": "0.41.0", + "@material/rtl": "0.40.1", + "@material/shape": "0.41.0", + "@material/theme": "0.41.0", + "@material/typography": "0.41.0" } }, "@material/checkbox": { @@ -865,12 +865,12 @@ "resolved": "https://registry.npmjs.org/@material/checkbox/-/checkbox-0.41.0.tgz", "integrity": "sha512-Zz6e5WRpziO7Z+4rbEs8GHNNBf1UuttniLp6/RvwPSQRaD8G04sdg4HcP/aDCY1KGMwivkuDPc2Bsgs6j+rD7Q==", "requires": { - "@material/animation": "^0.41.0", - "@material/base": "^0.41.0", - "@material/ripple": "^0.41.0", - "@material/rtl": "^0.40.1", - "@material/selection-control": "^0.41.0", - "@material/theme": "^0.41.0" + "@material/animation": "0.41.0", + "@material/base": "0.41.0", + "@material/ripple": "0.41.0", + "@material/rtl": "0.40.1", + "@material/selection-control": "0.41.0", + "@material/theme": "0.41.0" } }, "@material/elevation": { @@ -878,8 +878,8 @@ "resolved": "https://registry.npmjs.org/@material/elevation/-/elevation-0.41.0.tgz", "integrity": "sha512-ZtZS8z5ie9c7Cx5PVudgSorGYa0C3lu3dA+Nn6qJdhGUokl01msh54NfNuwk+EZsk65bNRRqw1Td/63TCbKIzg==", "requires": { - "@material/animation": "^0.41.0", - "@material/theme": "^0.41.0" + "@material/animation": "0.41.0", + "@material/theme": "0.41.0" } }, "@material/floating-label": { @@ -887,11 +887,11 @@ "resolved": "https://registry.npmjs.org/@material/floating-label/-/floating-label-0.41.0.tgz", "integrity": "sha512-qI6f1nZU3crXxWAI9fw3U5fHw2qOzEor49EvskbcaV5KSRW5qO+jtfUQ3ib/Vhki7lqhgwNHB/0n7KYhvhjRHQ==", "requires": { - "@material/animation": "^0.41.0", - "@material/base": "^0.41.0", - "@material/rtl": "^0.40.1", - "@material/theme": "^0.41.0", - "@material/typography": "^0.41.0" + "@material/animation": "0.41.0", + "@material/base": "0.41.0", + "@material/rtl": "0.40.1", + "@material/theme": "0.41.0", + "@material/typography": "0.41.0" } }, "@material/line-ripple": { @@ -899,9 +899,9 @@ "resolved": "https://registry.npmjs.org/@material/line-ripple/-/line-ripple-0.41.0.tgz", "integrity": "sha512-5DDIoC3d78fCLhNgle7DRFojT3D2SF+XVpUd3g6yLZmybHB7832p4bgl/qGpbIXwk1wAQA1dkUgKH5foxorjNQ==", "requires": { - "@material/animation": "^0.41.0", - "@material/base": "^0.41.0", - "@material/theme": "^0.41.0" + "@material/animation": "0.41.0", + "@material/base": "0.41.0", + "@material/theme": "0.41.0" } }, "@material/notched-outline": { @@ -909,11 +909,11 @@ "resolved": "https://registry.npmjs.org/@material/notched-outline/-/notched-outline-0.41.0.tgz", "integrity": "sha512-nQBkOXvkd5G9FeJ9UuecZh88WRgTsnGVvfj7UFJZEkvkzZwLBGUiJS6fF9FYraih3ZFgmphdbJxXEd9af3cqyQ==", "requires": { - "@material/animation": "^0.41.0", - "@material/base": "^0.41.0", - "@material/rtl": "^0.40.1", - "@material/shape": "^0.41.0", - "@material/theme": "^0.41.0" + "@material/animation": "0.41.0", + "@material/base": "0.41.0", + "@material/rtl": "0.40.1", + "@material/shape": "0.41.0", + "@material/theme": "0.41.0" } }, "@material/react-button": { @@ -921,10 +921,10 @@ "resolved": "https://registry.npmjs.org/@material/react-button/-/react-button-0.8.0.tgz", "integrity": "sha512-j/wk/HK2A3/mb+yFdYCbkWFi6hYvvq4fc4t1M3aRLgdeddMNn/+FHOu014dyKeFW93RrBn1WAdQTwCc31KivuQ==", "requires": { - "@material/button": "^0.41.0", - "@material/react-ripple": "^0.8.0", - "classnames": "^2.2.5", - "react": "^16.4.2" + "@material/button": "0.41.0", + "@material/react-ripple": "0.8.0", + "classnames": "2.2.6", + "react": "16.10.2" } }, "@material/react-checkbox": { @@ -932,10 +932,10 @@ "resolved": "https://registry.npmjs.org/@material/react-checkbox/-/react-checkbox-0.8.0.tgz", "integrity": "sha512-/7wQcFovUa04/T0MnJOnrbGn21CgxSSWjqkbMPFh/RjET8vya/kqAjhkLw51Mk4q6si+nfHljM6YSFvvXbUBBw==", "requires": { - "@material/checkbox": "^0.41.0", - "@material/react-ripple": "^0.8.0", - "classnames": "^2.2.5", - "react": "^16.3.2" + "@material/checkbox": "0.41.0", + "@material/react-ripple": "0.8.0", + "classnames": "2.2.6", + "react": "16.10.2" } }, "@material/react-floating-label": { @@ -943,9 +943,9 @@ "resolved": "https://registry.npmjs.org/@material/react-floating-label/-/react-floating-label-0.8.0.tgz", "integrity": "sha512-Bfa+/4nLFu6YE0pAB1wG+vxwYiFvHcOKIq7uAB/IY0/N/ONKM2Jh74/KKqLvNJI608YpZqLAqmZu87R3K15rNQ==", "requires": { - "@material/floating-label": "^0.41.0", - "classnames": "^2.2.5", - "react": "^16.4.2" + "@material/floating-label": "0.41.0", + "classnames": "2.2.6", + "react": "16.10.2" } }, "@material/react-line-ripple": { @@ -953,9 +953,9 @@ "resolved": "https://registry.npmjs.org/@material/react-line-ripple/-/react-line-ripple-0.8.0.tgz", "integrity": "sha512-s921awUm8taB/kbETGN/vEEZV1WUwtTcsNkQ//HsK2fJW7lKuyVWrObc8ZhMFWljVEUj54ANmRvCke7M4/LSmA==", "requires": { - "@material/line-ripple": "^0.41.0", - "classnames": "^2.2.5", - "react": "^16.4.2" + "@material/line-ripple": "0.41.0", + "classnames": "2.2.6", + "react": "16.10.2" } }, "@material/react-notched-outline": { @@ -963,9 +963,9 @@ "resolved": "https://registry.npmjs.org/@material/react-notched-outline/-/react-notched-outline-0.8.0.tgz", "integrity": "sha512-fQ8hHGOQ3dpk9AuuQqXbCAN2UTuRr5LCztkDxdCwvaPC+oR5meTd8RW7RkJgx/MeiSLe/1/2EMz+9lP+V0rx2w==", "requires": { - "@material/notched-outline": "^0.41.0", - "classnames": "^2.2.5", - "react": "^16.4.2" + "@material/notched-outline": "0.41.0", + "classnames": "2.2.6", + "react": "16.10.2" } }, "@material/react-ripple": { @@ -973,9 +973,9 @@ "resolved": "https://registry.npmjs.org/@material/react-ripple/-/react-ripple-0.8.0.tgz", "integrity": "sha512-ThH9Px42poicRXgFBTfLjbAsVIUi6wmX4RszDPwiSTVMQYc785n240VAD8MfVCR27ykIxCrys/YibqxvREvjUQ==", "requires": { - "@material/ripple": "^0.41.0", - "classnames": "^2.2.5", - "react": "^16.4.2" + "@material/ripple": "0.41.0", + "classnames": "2.2.6", + "react": "16.10.2" } }, "@material/react-text-field": { @@ -983,12 +983,12 @@ "resolved": "https://registry.npmjs.org/@material/react-text-field/-/react-text-field-0.8.0.tgz", "integrity": "sha512-eISr4YIBmsIarQQU/LhAPfB9M8srY8Tzagqw6E2z5JyHux8eHlsMWSuYD6eh4FiQekdZoIgoJjlFIGhOvNV59Q==", "requires": { - "@material/react-floating-label": "^0.8.0", - "@material/react-line-ripple": "^0.8.0", - "@material/react-notched-outline": "^0.8.0", - "@material/textfield": "^0.41.0", - "classnames": "^2.2.5", - "react": "^16.4.2" + "@material/react-floating-label": "0.8.0", + "@material/react-line-ripple": "0.8.0", + "@material/react-notched-outline": "0.8.0", + "@material/textfield": "0.41.0", + "classnames": "2.2.6", + "react": "16.10.2" } }, "@material/ripple": { @@ -996,9 +996,9 @@ "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-0.41.0.tgz", "integrity": "sha512-rxEUVWM4AByDlTCH0kkthZQmUuY6eeN0X6cOHBoioFN2vUDk0D0Nfzz/N9FF2AlAf8C2lDDLrTuqnJPVIn+NHA==", "requires": { - "@material/animation": "^0.41.0", - "@material/base": "^0.41.0", - "@material/theme": "^0.41.0" + "@material/animation": "0.41.0", + "@material/base": "0.41.0", + "@material/theme": "0.41.0" } }, "@material/rtl": { @@ -1011,7 +1011,7 @@ "resolved": "https://registry.npmjs.org/@material/selection-control/-/selection-control-0.41.0.tgz", "integrity": "sha512-rRHGiZVPoP4nxAAoeqsgTsxz9GwInGs7HIlEhPfMFygmSZVUHHsuOJXSTpOKYi8GCoKHpB0RKZsAtxM0BYAelw==", "requires": { - "@material/ripple": "^0.41.0" + "@material/ripple": "0.41.0" } }, "@material/shape": { @@ -1024,16 +1024,16 @@ "resolved": "https://registry.npmjs.org/@material/textfield/-/textfield-0.41.0.tgz", "integrity": "sha512-kJ52W2gxOS2xfpreVhvHQ1u3UkiDl58duw9HkhEkK5Oi1bSDOtbnlWy0pGTOiAma5ZQgetPNgoa+T0zMBptfnw==", "requires": { - "@material/animation": "^0.41.0", - "@material/base": "^0.41.0", - "@material/floating-label": "^0.41.0", - "@material/line-ripple": "^0.41.0", - "@material/notched-outline": "^0.41.0", - "@material/ripple": "^0.41.0", - "@material/rtl": "^0.40.1", - "@material/shape": "^0.41.0", - "@material/theme": "^0.41.0", - "@material/typography": "^0.41.0" + "@material/animation": "0.41.0", + "@material/base": "0.41.0", + "@material/floating-label": "0.41.0", + "@material/line-ripple": "0.41.0", + "@material/notched-outline": "0.41.0", + "@material/ripple": "0.41.0", + "@material/rtl": "0.40.1", + "@material/shape": "0.41.0", + "@material/theme": "0.41.0", + "@material/typography": "0.41.0" } }, "@material/theme": { @@ -1051,8 +1051,8 @@ "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", "requires": { - "call-me-maybe": "^1.0.1", - "glob-to-regexp": "^0.3.0" + "call-me-maybe": "1.0.1", + "glob-to-regexp": "0.3.0" } }, "@nodelib/fs.stat": { @@ -1065,13 +1065,13 @@ "resolved": "https://registry.npmjs.org/@svgr/core/-/core-2.4.1.tgz", "integrity": "sha512-2i1cUbjpKt1KcIP05e10vkmu9Aedp32EFqVcSQ08onbB8lVxJqMPci3Hr54aI14S9cLg4JdcpO0D35HHUtT8oQ==", "requires": { - "camelcase": "^5.0.0", - "cosmiconfig": "^5.0.6", - "h2x-core": "^1.1.0", - "h2x-plugin-jsx": "^1.1.0", - "merge-deep": "^3.0.2", - "prettier": "^1.14.2", - "svgo": "^1.0.5" + "camelcase": "5.0.0", + "cosmiconfig": "5.0.7", + "h2x-core": "1.1.1", + "h2x-plugin-jsx": "1.2.0", + "merge-deep": "3.0.2", + "prettier": "1.15.3", + "svgo": "1.1.1" } }, "@svgr/webpack": { @@ -1079,12 +1079,12 @@ "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-2.4.1.tgz", "integrity": "sha512-sMHYq0zbMtSHcc9kVfkYI2zrl88u4mKGyQLgKt7r+ul5nITcncm/EPBhzEUrJY5izdlaU6EvyH8zOhZnfaSmOA==", "requires": { - "@babel/core": "^7.0.1", - "@babel/plugin-transform-react-constant-elements": "^7.0.0", - "@babel/preset-env": "^7.0.0", - "@babel/preset-react": "^7.0.0", - "@svgr/core": "^2.4.1", - "loader-utils": "^1.1.0" + "@babel/core": "7.1.6", + "@babel/plugin-transform-react-constant-elements": "7.2.0", + "@babel/preset-env": "7.2.3", + "@babel/preset-react": "7.0.0", + "@svgr/core": "2.4.1", + "loader-utils": "1.2.3" } }, "@types/classnames": { @@ -1102,8 +1102,8 @@ "resolved": "https://registry.npmjs.org/@types/jss/-/jss-9.5.7.tgz", "integrity": "sha512-OZimStu2QdDMtZ0h72JXqvLVbWUjXd5ZLk8vxLmfuC/nM1AabRyyGoxSufnzixrbpEcVcyy/JV5qeQu2JnjVZw==", "requires": { - "csstype": "^2.0.0", - "indefinite-observable": "^1.0.1" + "csstype": "2.6.0", + "indefinite-observable": "1.0.2" } }, "@types/node": { @@ -1116,7 +1116,7 @@ "resolved": "https://registry.npmjs.org/@types/node-sass/-/node-sass-3.10.32.tgz", "integrity": "sha1-spbM5xRP+rd7hAkMqtTx5Lvqjgk=", "requires": { - "@types/node": "*" + "@types/node": "10.12.18" } }, "@types/prop-types": { @@ -1134,7 +1134,7 @@ "resolved": "https://registry.npmjs.org/@types/qrcode.react/-/qrcode.react-0.8.1.tgz", "integrity": "sha512-OpMOBjWIMTnC1sdLcFgif/cXZYiPQGUN2yDaxC2EmZaAmElxehE+toMzPZvUJVXNyFXFdmYSDRWsjKtTTnqqAQ==", "requires": { - "@types/react": "*" + "@types/react": "16.7.18" } }, "@types/query-string": { @@ -1147,8 +1147,8 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-16.7.18.tgz", "integrity": "sha512-Tx4uu3ppK53/iHk6VpamMP3f3ahfDLEVt3ZQc8TFm30a1H3v9lMsCntBREswZIW/SKrvJjkb3Hq8UwO6GREBng==", "requires": { - "@types/prop-types": "*", - "csstype": "^2.2.0" + "@types/prop-types": "15.5.8", + "csstype": "2.6.0" } }, "@types/react-dom": { @@ -1156,7 +1156,7 @@ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.0.11.tgz", "integrity": "sha512-x6zUx9/42B5Kl2Vl9HlopV8JF64wLpX3c+Pst9kc1HgzrsH+mkehe/zmHMQTplIrR48H2gpU7ZqurQolYu8XBA==", "requires": { - "@types/react": "*" + "@types/react": "16.7.18" } }, "@types/react-redux": { @@ -1164,8 +1164,8 @@ "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-6.0.12.tgz", "integrity": "sha512-fvcpm7cfW/JMflRdZgegCVbSGYt/hyEWQKriesaLZDRDjBGKQsAiui08VCQg5lBpocPmulVGKFhICtOAcMUPOQ==", "requires": { - "@types/react": "*", - "redux": "^4.0.0" + "@types/react": "16.7.18", + "redux": "4.0.1" } }, "@types/react-router": { @@ -1173,8 +1173,8 @@ "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-4.4.3.tgz", "integrity": "sha512-8GmjakEBFNCLJbpg9jtDp1EDvFP0VkIPPKBpVwmB3Q+9whFoHu8rluMUXUE5SoGkEQvVOtgJzWmUsJojNpFMQQ==", "requires": { - "@types/history": "*", - "@types/react": "*" + "@types/history": "4.7.2", + "@types/react": "16.7.18" } }, "@types/react-router-dom": { @@ -1182,9 +1182,9 @@ "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-4.3.1.tgz", "integrity": "sha512-GbztJAScOmQ/7RsQfO4cd55RuH1W4g6V1gDW3j4riLlt+8yxYLqqsiMzmyuXBLzdFmDtX/uU2Bpcm0cmudv44A==", "requires": { - "@types/history": "*", - "@types/react": "*", - "@types/react-router": "*" + "@types/history": "4.7.2", + "@types/react": "16.7.18", + "@types/react-router": "4.4.3" } }, "@types/redux-thunk": { @@ -1192,7 +1192,7 @@ "resolved": "https://registry.npmjs.org/@types/redux-thunk/-/redux-thunk-2.1.0.tgz", "integrity": "sha1-vCtulylhgxr7gqm/TwZybjUflBY=", "requires": { - "redux-thunk": "*" + "redux-thunk": "2.3.0" } }, "@types/tapable": { @@ -1208,7 +1208,7 @@ "@webassemblyjs/helper-module-context": "1.7.6", "@webassemblyjs/helper-wasm-bytecode": "1.7.6", "@webassemblyjs/wast-parser": "1.7.6", - "mamacro": "^0.0.3" + "mamacro": "0.0.3" } }, "@webassemblyjs/floating-point-hex-parser": { @@ -1244,7 +1244,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.6.tgz", "integrity": "sha512-e8/6GbY7OjLM+6OsN7f2krC2qYVNaSr0B0oe4lWdmq5sL++8dYDD1TFbD1TdAdWMRTYNr/Qq7ovXWzia2EbSjw==", "requires": { - "mamacro": "^0.0.3" + "mamacro": "0.0.3" } }, "@webassemblyjs/helper-wasm-bytecode": { @@ -1268,7 +1268,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.7.6.tgz", "integrity": "sha512-V4cIp0ruyw+hawUHwQLn6o2mFEw4t50tk530oKsYXQhEzKR+xNGDxs/SFFuyTO7X3NzEu4usA3w5jzhl2RYyzQ==", "requires": { - "@xtuc/ieee754": "^1.2.0" + "@xtuc/ieee754": "1.2.0" } }, "@webassemblyjs/leb128": { @@ -1346,7 +1346,7 @@ "@webassemblyjs/helper-code-frame": "1.7.6", "@webassemblyjs/helper-fsm": "1.7.6", "@xtuc/long": "4.2.1", - "mamacro": "^0.0.3" + "mamacro": "0.0.3" } }, "@webassemblyjs/wast-printer": { @@ -1384,7 +1384,7 @@ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", "requires": { - "mime-types": "~2.1.18", + "mime-types": "2.1.21", "negotiator": "0.6.1" } }, @@ -1398,7 +1398,7 @@ "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz", "integrity": "sha512-zVWV8Z8lislJoOKKqdNMOB+s6+XV5WERty8MnKBeFgwA+19XJjJHs2RP5dzM57FftIs+jQnRToLiWazKr6sSWg==", "requires": { - "acorn": "^5.0.0" + "acorn": "5.7.3" }, "dependencies": { "acorn": { @@ -1413,8 +1413,8 @@ "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.0.tgz", "integrity": "sha512-hMtHj3s5RnuhvHPowpBYvJVj3rAar82JiDQHvGs1zO0l10ocX/xEdBShNHTJaboucJUsScghp74pH3s7EnHHQw==", "requires": { - "acorn": "^6.0.1", - "acorn-walk": "^6.0.1" + "acorn": "6.0.5", + "acorn-walk": "6.1.1" } }, "acorn-jsx": { @@ -1437,10 +1437,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.6.2.tgz", "integrity": "sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g==", "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "fast-deep-equal": "2.0.1", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.4.1", + "uri-js": "4.2.2" } }, "ajv-errors": { @@ -1488,7 +1488,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "requires": { - "color-convert": "^1.9.0" + "color-convert": "1.9.3" } }, "anymatch": { @@ -1496,8 +1496,8 @@ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" + "micromatch": "3.1.10", + "normalize-path": "2.1.1" }, "dependencies": { "arr-diff": { @@ -1515,16 +1515,16 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" + "arr-flatten": "1.1.0", + "array-unique": "0.3.2", + "extend-shallow": "2.0.1", + "fill-range": "4.0.0", + "isobject": "3.0.1", + "repeat-element": "1.1.3", + "snapdragon": "0.8.2", + "snapdragon-node": "2.1.1", + "split-string": "3.1.0", + "to-regex": "3.0.2" }, "dependencies": { "extend-shallow": { @@ -1532,7 +1532,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -1550,13 +1550,13 @@ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "posix-character-classes": "0.1.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -1564,7 +1564,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "extend-shallow": { @@ -1572,7 +1572,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } }, "is-accessor-descriptor": { @@ -1580,7 +1580,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -1588,7 +1588,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -1598,7 +1598,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -1606,7 +1606,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -1616,9 +1616,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" } }, "kind-of": { @@ -1633,14 +1633,14 @@ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "array-unique": "0.3.2", + "define-property": "1.0.0", + "expand-brackets": "2.1.4", + "extend-shallow": "2.0.1", + "fragment-cache": "0.2.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -1648,7 +1648,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "extend-shallow": { @@ -1656,7 +1656,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -1666,10 +1666,10 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" + "extend-shallow": "2.0.1", + "is-number": "3.0.0", + "repeat-string": "1.6.1", + "to-regex-range": "2.1.1" }, "dependencies": { "extend-shallow": { @@ -1677,7 +1677,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -1687,7 +1687,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { @@ -1695,7 +1695,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { @@ -1703,9 +1703,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } }, "is-number": { @@ -1713,7 +1713,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -1721,7 +1721,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -1736,19 +1736,19 @@ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "braces": "2.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "extglob": "2.0.4", + "fragment-cache": "0.2.1", + "kind-of": "6.0.2", + "nanomatch": "1.2.13", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" } }, "ms": { @@ -1763,7 +1763,7 @@ "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz", "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", "requires": { - "default-require-extensions": "^1.0.0" + "default-require-extensions": "1.0.0" } }, "aproba": { @@ -1776,8 +1776,8 @@ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" + "delegates": "1.0.0", + "readable-stream": "2.3.6" } }, "argparse": { @@ -1785,7 +1785,7 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "requires": { - "sprintf-js": "~1.0.2" + "sprintf-js": "1.0.3" } }, "aria-query": { @@ -1794,7 +1794,7 @@ "integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=", "requires": { "ast-types-flow": "0.0.7", - "commander": "^2.11.0" + "commander": "2.19.0" } }, "arr-diff": { @@ -1802,7 +1802,7 @@ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", "requires": { - "arr-flatten": "^1.0.1" + "arr-flatten": "1.1.0" } }, "arr-flatten": { @@ -1840,8 +1840,8 @@ "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.7.0" + "define-properties": "1.1.3", + "es-abstract": "1.13.0" } }, "array-map": { @@ -1859,7 +1859,7 @@ "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "requires": { - "array-uniq": "^1.0.1" + "array-uniq": "1.0.3" } }, "array-uniq": { @@ -1887,7 +1887,7 @@ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", "requires": { - "safer-buffer": "~2.1.0" + "safer-buffer": "2.1.2" } }, "asn1.js": { @@ -1895,9 +1895,9 @@ "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" + "bn.js": "4.11.8", + "inherits": "2.0.3", + "minimalistic-assert": "1.0.1" } }, "assert": { @@ -1948,7 +1948,7 @@ "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", "requires": { - "lodash": "^4.17.10" + "lodash": "4.17.11" } }, "async-each": { @@ -1981,12 +1981,12 @@ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.4.4.tgz", "integrity": "sha512-7tpjBadJyHKf+gOJEmKhZIksWxdZCSrnKbbTJNsw+/zX9+f//DLELRQPWjjjVoDbbWlCuNRkN7RfmZwDVgWMLw==", "requires": { - "browserslist": "^4.3.7", - "caniuse-lite": "^1.0.30000926", - "normalize-range": "^0.1.2", - "num2fraction": "^1.2.2", - "postcss": "^7.0.7", - "postcss-value-parser": "^3.3.1" + "browserslist": "4.3.7", + "caniuse-lite": "1.0.30000927", + "normalize-range": "0.1.2", + "num2fraction": "1.2.2", + "postcss": "7.0.8", + "postcss-value-parser": "3.3.1" }, "dependencies": { "chalk": { @@ -1994,9 +1994,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -2004,7 +2004,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -2014,9 +2014,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -2029,16 +2029,11 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } }, - "await-to-js": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/await-to-js/-/await-to-js-2.1.1.tgz", - "integrity": "sha512-CHBC6gQGCIzjZ09tJ+XmpQoZOn4GdWePB4qUweCaKNJ0D3f115YdhmYVTZ4rMVpiJ3cFzZcTYK1VMYEICV4YXw==" - }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -2062,9 +2057,9 @@ "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" }, "dependencies": { "ansi-styles": { @@ -2077,11 +2072,11 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" } }, "js-tokens": { @@ -2106,12 +2101,12 @@ "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-9.0.0.tgz", "integrity": "sha512-itv1MwE3TMbY0QtNfeL7wzak1mV47Uy+n6HtSOO4Xd7rvmO+tsGQSgyOEEgo6Y2vHZKZphaoelNeSVj4vkLA1g==", "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.0.0", - "@babel/traverse": "^7.0.0", - "@babel/types": "^7.0.0", + "@babel/code-frame": "7.0.0", + "@babel/parser": "7.2.3", + "@babel/traverse": "7.2.3", + "@babel/types": "7.2.2", "eslint-scope": "3.7.1", - "eslint-visitor-keys": "^1.0.0" + "eslint-visitor-keys": "1.0.0" } }, "babel-extract-comments": { @@ -2119,7 +2114,7 @@ "resolved": "https://registry.npmjs.org/babel-extract-comments/-/babel-extract-comments-1.0.0.tgz", "integrity": "sha512-qWWzi4TlddohA91bFwgt6zO/J0X+io7Qp184Fw0m2JYRSTZnJbFR8+07KmzudHCZgOiKRCrjhylwv9Xd8gfhVQ==", "requires": { - "babylon": "^6.18.0" + "babylon": "6.18.0" } }, "babel-generator": { @@ -2127,14 +2122,14 @@ "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", "requires": { - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "detect-indent": "^4.0.0", - "jsesc": "^1.3.0", - "lodash": "^4.17.4", - "source-map": "^0.5.7", - "trim-right": "^1.0.1" + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "detect-indent": "4.0.0", + "jsesc": "1.3.0", + "lodash": "4.17.11", + "source-map": "0.5.7", + "trim-right": "1.0.1" }, "dependencies": { "jsesc": { @@ -2149,8 +2144,8 @@ "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" } }, "babel-jest": { @@ -2158,8 +2153,8 @@ "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-23.6.0.tgz", "integrity": "sha512-lqKGG6LYXYu+DQh/slrQ8nxXQkEkhugdXsU6St7GmhVS7Ilc/22ArwqXNJrf0QaOBjZB0360qZMwXqDYQHXaew==", "requires": { - "babel-plugin-istanbul": "^4.1.6", - "babel-preset-jest": "^23.2.0" + "babel-plugin-istanbul": "4.1.6", + "babel-preset-jest": "23.2.0" } }, "babel-loader": { @@ -2167,10 +2162,10 @@ "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.4.tgz", "integrity": "sha512-fhBhNkUToJcW9nV46v8w87AJOwAJDz84c1CL57n3Stj73FANM/b9TbCUK4YhdOwEyZ+OxhYpdeZDNzSI29Firw==", "requires": { - "find-cache-dir": "^1.0.0", - "loader-utils": "^1.0.2", - "mkdirp": "^0.5.1", - "util.promisify": "^1.0.0" + "find-cache-dir": "1.0.0", + "loader-utils": "1.2.3", + "mkdirp": "0.5.1", + "util.promisify": "1.0.0" } }, "babel-messages": { @@ -2178,7 +2173,7 @@ "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "6.26.0" } }, "babel-plugin-dynamic-import-node": { @@ -2186,7 +2181,7 @@ "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.2.0.tgz", "integrity": "sha512-fP899ELUnTaBcIzmrW7nniyqqdYWrWuJUyPWHxFa/c7r7hS6KC8FscNfLlBNIoPSc55kYMGEEKjPjJGCLbE1qA==", "requires": { - "object.assign": "^4.1.0" + "object.assign": "4.1.0" } }, "babel-plugin-istanbul": { @@ -2194,10 +2189,10 @@ "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz", "integrity": "sha512-PWP9FQ1AhZhS01T/4qLSKoHGY/xvkZdVBGlKM/HuxxS3+sC66HhTNR7+MpbO/so/cz/wY94MeSWJuP1hXIPfwQ==", "requires": { - "babel-plugin-syntax-object-rest-spread": "^6.13.0", - "find-up": "^2.1.0", - "istanbul-lib-instrument": "^1.10.1", - "test-exclude": "^4.2.1" + "babel-plugin-syntax-object-rest-spread": "6.13.0", + "find-up": "2.1.0", + "istanbul-lib-instrument": "1.10.2", + "test-exclude": "4.2.3" } }, "babel-plugin-jest-hoist": { @@ -2210,8 +2205,8 @@ "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.4.2.tgz", "integrity": "sha512-NBVpEWN4OQ/bHnu1fyDaAaTPAjnhXCEPqr1RwqxrU7b6tZ2hypp+zX4hlNfmVGfClD5c3Sl6Hfj5TJNF5VG5aA==", "requires": { - "cosmiconfig": "^5.0.5", - "resolve": "^1.8.1" + "cosmiconfig": "5.0.7", + "resolve": "1.8.1" } }, "babel-plugin-named-asset-import": { @@ -2229,8 +2224,8 @@ "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz", "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=", "requires": { - "babel-plugin-syntax-object-rest-spread": "^6.8.0", - "babel-runtime": "^6.26.0" + "babel-plugin-syntax-object-rest-spread": "6.13.0", + "babel-runtime": "6.26.0" } }, "babel-plugin-transform-react-remove-prop-types": { @@ -2243,8 +2238,8 @@ "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-23.2.0.tgz", "integrity": "sha1-jsegOhOPABoaj7HoETZSvxpV2kY=", "requires": { - "babel-plugin-jest-hoist": "^23.2.0", - "babel-plugin-syntax-object-rest-spread": "^6.13.0" + "babel-plugin-jest-hoist": "23.2.0", + "babel-plugin-syntax-object-rest-spread": "6.13.0" } }, "babel-preset-react-app": { @@ -2278,8 +2273,8 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.0.0.tgz", "integrity": "sha512-14fhfoPcNu7itSen7Py1iGN0gEm87hX/B+8nZPqkdmANyyYWYMY2pjA3r8WXbWVKMzfnSNS0xY8GVS0IjXi/iw==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-object-rest-spread": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-object-rest-spread": "7.2.0" } }, "@babel/plugin-transform-classes": { @@ -2287,14 +2282,14 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.1.0.tgz", "integrity": "sha512-rNaqoD+4OCBZjM7VaskladgqnZ1LO6o2UxuWSDzljzW21pN1KXkB7BstAVweZdxQkHAujps5QMNOTWesBciKFg==", "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-define-map": "^7.1.0", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.0.0", - "globals": "^11.1.0" + "@babel/helper-annotate-as-pure": "7.0.0", + "@babel/helper-define-map": "7.1.0", + "@babel/helper-function-name": "7.1.0", + "@babel/helper-optimise-call-expression": "7.0.0", + "@babel/helper-plugin-utils": "7.0.0", + "@babel/helper-replace-supers": "7.2.3", + "@babel/helper-split-export-declaration": "7.0.0", + "globals": "11.10.0" } }, "@babel/plugin-transform-destructuring": { @@ -2302,7 +2297,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.1.3.tgz", "integrity": "sha512-Mb9M4DGIOspH1ExHOUnn2UUXFOyVTiX84fXCd+6B5iWrQg/QMeeRmSwpZ9lnjYLSXtZwiw80ytVMr3zue0ucYw==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-react-constant-elements": { @@ -2310,8 +2305,8 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.0.0.tgz", "integrity": "sha512-z8yrW4KCVcqPYr0r9dHXe7fu3daLzn0r6TQEFoGbXahdrzEwT1d1ux+/EnFcqIHv9uPilUlnRnPIUf7GMO0ehg==", "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-annotate-as-pure": "7.0.0", + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-react-display-name": { @@ -2319,7 +2314,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.0.0.tgz", "integrity": "sha512-BX8xKuQTO0HzINxT6j/GiCwoJB0AOMs0HmLbEnAvcte8U8rSkNa/eSCAY+l1OA4JnCVq2jw2p6U8QQryy2fTPg==", "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/preset-env": { @@ -2327,47 +2322,47 @@ "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.1.6.tgz", "integrity": "sha512-YIBfpJNQMBkb6MCkjz/A9J76SNCSuGVamOVBgoUkLzpJD/z8ghHi9I42LQ4pulVX68N/MmImz6ZTixt7Azgexw==", "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-async-generator-functions": "^7.1.0", - "@babel/plugin-proposal-json-strings": "^7.0.0", - "@babel/plugin-proposal-object-rest-spread": "^7.0.0", - "@babel/plugin-proposal-optional-catch-binding": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.0.0", - "@babel/plugin-syntax-async-generators": "^7.0.0", - "@babel/plugin-syntax-object-rest-spread": "^7.0.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.0.0", - "@babel/plugin-transform-arrow-functions": "^7.0.0", - "@babel/plugin-transform-async-to-generator": "^7.1.0", - "@babel/plugin-transform-block-scoped-functions": "^7.0.0", - "@babel/plugin-transform-block-scoping": "^7.1.5", - "@babel/plugin-transform-classes": "^7.1.0", - "@babel/plugin-transform-computed-properties": "^7.0.0", - "@babel/plugin-transform-destructuring": "^7.0.0", - "@babel/plugin-transform-dotall-regex": "^7.0.0", - "@babel/plugin-transform-duplicate-keys": "^7.0.0", - "@babel/plugin-transform-exponentiation-operator": "^7.1.0", - "@babel/plugin-transform-for-of": "^7.0.0", - "@babel/plugin-transform-function-name": "^7.1.0", - "@babel/plugin-transform-literals": "^7.0.0", - "@babel/plugin-transform-modules-amd": "^7.1.0", - "@babel/plugin-transform-modules-commonjs": "^7.1.0", - "@babel/plugin-transform-modules-systemjs": "^7.0.0", - "@babel/plugin-transform-modules-umd": "^7.1.0", - "@babel/plugin-transform-new-target": "^7.0.0", - "@babel/plugin-transform-object-super": "^7.1.0", - "@babel/plugin-transform-parameters": "^7.1.0", - "@babel/plugin-transform-regenerator": "^7.0.0", - "@babel/plugin-transform-shorthand-properties": "^7.0.0", - "@babel/plugin-transform-spread": "^7.0.0", - "@babel/plugin-transform-sticky-regex": "^7.0.0", - "@babel/plugin-transform-template-literals": "^7.0.0", - "@babel/plugin-transform-typeof-symbol": "^7.0.0", - "@babel/plugin-transform-unicode-regex": "^7.0.0", - "browserslist": "^4.1.0", - "invariant": "^2.2.2", - "js-levenshtein": "^1.1.3", - "semver": "^5.3.0" + "@babel/helper-module-imports": "7.0.0", + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-proposal-async-generator-functions": "7.2.0", + "@babel/plugin-proposal-json-strings": "7.2.0", + "@babel/plugin-proposal-object-rest-spread": "7.0.0", + "@babel/plugin-proposal-optional-catch-binding": "7.2.0", + "@babel/plugin-proposal-unicode-property-regex": "7.2.0", + "@babel/plugin-syntax-async-generators": "7.2.0", + "@babel/plugin-syntax-object-rest-spread": "7.2.0", + "@babel/plugin-syntax-optional-catch-binding": "7.2.0", + "@babel/plugin-transform-arrow-functions": "7.2.0", + "@babel/plugin-transform-async-to-generator": "7.2.0", + "@babel/plugin-transform-block-scoped-functions": "7.2.0", + "@babel/plugin-transform-block-scoping": "7.2.0", + "@babel/plugin-transform-classes": "7.1.0", + "@babel/plugin-transform-computed-properties": "7.2.0", + "@babel/plugin-transform-destructuring": "7.1.3", + "@babel/plugin-transform-dotall-regex": "7.2.0", + "@babel/plugin-transform-duplicate-keys": "7.2.0", + "@babel/plugin-transform-exponentiation-operator": "7.2.0", + "@babel/plugin-transform-for-of": "7.2.0", + "@babel/plugin-transform-function-name": "7.2.0", + "@babel/plugin-transform-literals": "7.2.0", + "@babel/plugin-transform-modules-amd": "7.2.0", + "@babel/plugin-transform-modules-commonjs": "7.2.0", + "@babel/plugin-transform-modules-systemjs": "7.2.0", + "@babel/plugin-transform-modules-umd": "7.2.0", + "@babel/plugin-transform-new-target": "7.0.0", + "@babel/plugin-transform-object-super": "7.2.0", + "@babel/plugin-transform-parameters": "7.2.0", + "@babel/plugin-transform-regenerator": "7.0.0", + "@babel/plugin-transform-shorthand-properties": "7.2.0", + "@babel/plugin-transform-spread": "7.2.2", + "@babel/plugin-transform-sticky-regex": "7.2.0", + "@babel/plugin-transform-template-literals": "7.2.0", + "@babel/plugin-transform-typeof-symbol": "7.2.0", + "@babel/plugin-transform-unicode-regex": "7.2.0", + "browserslist": "4.3.7", + "invariant": "2.2.4", + "js-levenshtein": "1.1.5", + "semver": "5.6.0" } }, "@babel/runtime": { @@ -2375,7 +2370,7 @@ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.1.5.tgz", "integrity": "sha512-xKnPpXG/pvK1B90JkwwxSGii90rQGKtzcMt2gI5G6+M0REXaq6rOHsGC2ay6/d0Uje7zzvSzjEzfR3ENhFlrfA==", "requires": { - "regenerator-runtime": "^0.12.0" + "regenerator-runtime": "0.12.1" } } } @@ -2385,13 +2380,13 @@ "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", "requires": { - "babel-core": "^6.26.0", - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "home-or-tmp": "^2.0.0", - "lodash": "^4.17.4", - "mkdirp": "^0.5.1", - "source-map-support": "^0.4.15" + "babel-core": "6.26.3", + "babel-runtime": "6.26.0", + "core-js": "2.6.1", + "home-or-tmp": "2.0.0", + "lodash": "4.17.11", + "mkdirp": "0.5.1", + "source-map-support": "0.4.18" }, "dependencies": { "babel-core": { @@ -2399,25 +2394,25 @@ "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", "requires": { - "babel-code-frame": "^6.26.0", - "babel-generator": "^6.26.0", - "babel-helpers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "convert-source-map": "^1.5.1", - "debug": "^2.6.9", - "json5": "^0.5.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.4", - "path-is-absolute": "^1.0.1", - "private": "^0.1.8", - "slash": "^1.0.0", - "source-map": "^0.5.7" + "babel-code-frame": "6.26.0", + "babel-generator": "6.26.1", + "babel-helpers": "6.24.1", + "babel-messages": "6.23.0", + "babel-register": "6.26.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "convert-source-map": "1.6.0", + "debug": "2.6.9", + "json5": "0.5.1", + "lodash": "4.17.11", + "minimatch": "3.0.4", + "path-is-absolute": "1.0.1", + "private": "0.1.8", + "slash": "1.0.0", + "source-map": "0.5.7" } }, "core-js": { @@ -2450,8 +2445,8 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "core-js": "2.6.1", + "regenerator-runtime": "0.11.1" }, "dependencies": { "core-js": { @@ -2471,11 +2466,11 @@ "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "lodash": "4.17.11" } }, "babel-traverse": { @@ -2483,15 +2478,15 @@ "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" + "babel-code-frame": "6.26.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "debug": "2.6.9", + "globals": "9.18.0", + "invariant": "2.2.4", + "lodash": "4.17.11" }, "dependencies": { "debug": { @@ -2519,10 +2514,10 @@ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.11", + "to-fast-properties": "1.0.3" }, "dependencies": { "to-fast-properties": { @@ -2547,13 +2542,13 @@ "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" + "cache-base": "1.0.1", + "class-utils": "0.3.6", + "component-emitter": "1.2.1", + "define-property": "1.0.0", + "isobject": "3.0.1", + "mixin-deep": "1.3.1", + "pascalcase": "0.1.1" }, "dependencies": { "define-property": { @@ -2561,7 +2556,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "is-accessor-descriptor": { @@ -2569,7 +2564,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { @@ -2577,7 +2572,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { @@ -2585,9 +2580,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } }, "kind-of": { @@ -2612,7 +2607,7 @@ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", "requires": { - "tweetnacl": "^0.14.3" + "tweetnacl": "0.14.5" } }, "bfj": { @@ -2620,10 +2615,10 @@ "resolved": "https://registry.npmjs.org/bfj/-/bfj-6.1.1.tgz", "integrity": "sha512-+GUNvzHR4nRyGybQc2WpNJL4MJazMuvf92ueIyA0bIkPRwhhQu3IfZQ2PSoVPpCBJfmoSdOxu5rnotfFLlvYRQ==", "requires": { - "bluebird": "^3.5.1", - "check-types": "^7.3.0", - "hoopy": "^0.1.2", - "tryer": "^1.0.0" + "bluebird": "3.5.3", + "check-types": "7.4.0", + "hoopy": "0.1.4", + "tryer": "1.0.1" } }, "big.js": { @@ -2641,7 +2636,7 @@ "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", "requires": { - "inherits": "~2.0.0" + "inherits": "2.0.3" } }, "bluebird": { @@ -2660,15 +2655,15 @@ "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", "requires": { "bytes": "3.0.0", - "content-type": "~1.0.4", + "content-type": "1.0.4", "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "~1.6.3", + "depd": "1.1.2", + "http-errors": "1.6.3", "iconv-lite": "0.4.23", - "on-finished": "~2.3.0", + "on-finished": "2.3.0", "qs": "6.5.2", "raw-body": "2.3.3", - "type-is": "~1.6.16" + "type-is": "1.6.16" }, "dependencies": { "debug": { @@ -2684,7 +2679,7 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": "2.1.2" } }, "ms": { @@ -2699,12 +2694,12 @@ "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", "requires": { - "array-flatten": "^2.1.0", - "deep-equal": "^1.0.1", - "dns-equal": "^1.0.0", - "dns-txt": "^2.0.2", - "multicast-dns": "^6.0.1", - "multicast-dns-service-types": "^1.1.0" + "array-flatten": "2.1.2", + "deep-equal": "1.0.1", + "dns-equal": "1.0.0", + "dns-txt": "2.0.2", + "multicast-dns": "6.2.3", + "multicast-dns-service-types": "1.1.0" } }, "boolbase": { @@ -2717,7 +2712,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "requires": { - "balanced-match": "^1.0.0", + "balanced-match": "1.0.0", "concat-map": "0.0.1" } }, @@ -2726,9 +2721,9 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", "requires": { - "expand-range": "^1.8.1", - "preserve": "^0.2.0", - "repeat-element": "^1.1.2" + "expand-range": "1.8.2", + "preserve": "0.2.0", + "repeat-element": "1.1.3" } }, "brorand": { @@ -2761,12 +2756,12 @@ "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "requires": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "buffer-xor": "1.0.3", + "cipher-base": "1.0.4", + "create-hash": "1.2.0", + "evp_bytestokey": "1.0.3", + "inherits": "2.0.3", + "safe-buffer": "5.1.2" } }, "browserify-cipher": { @@ -2774,9 +2769,9 @@ "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "requires": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" + "browserify-aes": "1.2.0", + "browserify-des": "1.0.2", + "evp_bytestokey": "1.0.3" } }, "browserify-des": { @@ -2784,10 +2779,10 @@ "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" + "cipher-base": "1.0.4", + "des.js": "1.0.0", + "inherits": "2.0.3", + "safe-buffer": "5.1.2" } }, "browserify-rsa": { @@ -2795,8 +2790,8 @@ "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "requires": { - "bn.js": "^4.1.0", - "randombytes": "^2.0.1" + "bn.js": "4.11.8", + "randombytes": "2.0.6" } }, "browserify-sign": { @@ -2804,13 +2799,13 @@ "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", "requires": { - "bn.js": "^4.1.1", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.2", - "elliptic": "^6.0.0", - "inherits": "^2.0.1", - "parse-asn1": "^5.0.0" + "bn.js": "4.11.8", + "browserify-rsa": "4.0.1", + "create-hash": "1.2.0", + "create-hmac": "1.1.7", + "elliptic": "6.4.1", + "inherits": "2.0.3", + "parse-asn1": "5.1.1" } }, "browserify-zlib": { @@ -2818,7 +2813,7 @@ "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", "requires": { - "pako": "~1.0.5" + "pako": "1.0.7" } }, "browserslist": { @@ -2826,9 +2821,9 @@ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.3.7.tgz", "integrity": "sha512-pWQv51Ynb0MNk9JGMCZ8VkM785/4MQNXiFYtPqI7EEP0TJO+/d/NqRVn1uiAN0DNbnlUSpL2sh16Kspasv3pUQ==", "requires": { - "caniuse-lite": "^1.0.30000925", - "electron-to-chromium": "^1.3.96", - "node-releases": "^1.1.3" + "caniuse-lite": "1.0.30000927", + "electron-to-chromium": "1.3.100", + "node-releases": "1.1.3" } }, "bser": { @@ -2836,7 +2831,7 @@ "resolved": "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz", "integrity": "sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk=", "requires": { - "node-int64": "^0.4.0" + "node-int64": "0.4.0" } }, "buffer": { @@ -2844,9 +2839,9 @@ "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" + "base64-js": "1.3.0", + "ieee754": "1.1.12", + "isarray": "1.0.0" }, "dependencies": { "isarray": { @@ -2891,20 +2886,20 @@ "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.2.tgz", "integrity": "sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg==", "requires": { - "bluebird": "^3.5.3", - "chownr": "^1.1.1", - "figgy-pudding": "^3.5.1", - "glob": "^7.1.3", - "graceful-fs": "^4.1.15", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.2", - "ssri": "^6.0.1", - "unique-filename": "^1.1.1", - "y18n": "^4.0.0" + "bluebird": "3.5.3", + "chownr": "1.1.1", + "figgy-pudding": "3.5.1", + "glob": "7.1.3", + "graceful-fs": "4.1.15", + "lru-cache": "5.1.1", + "mississippi": "3.0.0", + "mkdirp": "0.5.1", + "move-concurrently": "1.0.1", + "promise-inflight": "1.0.1", + "rimraf": "2.6.3", + "ssri": "6.0.1", + "unique-filename": "1.1.1", + "y18n": "4.0.0" }, "dependencies": { "lru-cache": { @@ -2912,7 +2907,7 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "requires": { - "yallist": "^3.0.2" + "yallist": "3.0.3" } }, "y18n": { @@ -2932,15 +2927,15 @@ "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" + "collection-visit": "1.0.0", + "component-emitter": "1.2.1", + "get-value": "2.0.6", + "has-value": "1.0.0", + "isobject": "3.0.1", + "set-value": "2.0.0", + "to-object-path": "0.3.0", + "union-value": "1.0.0", + "unset-value": "1.0.0" } }, "call-me-maybe": { @@ -2953,7 +2948,7 @@ "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", "requires": { - "callsites": "^2.0.0" + "callsites": "2.0.0" } }, "caller-path": { @@ -2961,7 +2956,7 @@ "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", "requires": { - "caller-callsite": "^2.0.0" + "caller-callsite": "2.0.0" } }, "callsites": { @@ -2974,8 +2969,8 @@ "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", "requires": { - "no-case": "^2.2.0", - "upper-case": "^1.1.1" + "no-case": "2.3.2", + "upper-case": "1.1.3" } }, "camelcase": { @@ -2988,8 +2983,8 @@ "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", "requires": { - "camelcase": "^2.0.0", - "map-obj": "^1.0.0" + "camelcase": "2.1.1", + "map-obj": "1.0.1" }, "dependencies": { "camelcase": { @@ -3004,10 +2999,10 @@ "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", "requires": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" + "browserslist": "4.3.7", + "caniuse-lite": "1.0.30000927", + "lodash.memoize": "4.1.2", + "lodash.uniq": "4.5.0" } }, "caniuse-lite": { @@ -3020,7 +3015,7 @@ "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-1.2.0.tgz", "integrity": "sha1-HF/MSJ/QqwDU8ax64QcuMXP7q28=", "requires": { - "rsvp": "^3.3.3" + "rsvp": "3.6.2" } }, "case-sensitive-paths-webpack-plugin": { @@ -3038,9 +3033,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" } }, "chardet": { @@ -3058,19 +3053,19 @@ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz", "integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==", "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.0", - "braces": "^2.3.0", - "fsevents": "^1.2.2", - "glob-parent": "^3.1.0", - "inherits": "^2.0.1", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "lodash.debounce": "^4.0.8", - "normalize-path": "^2.1.1", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.0.0", - "upath": "^1.0.5" + "anymatch": "2.0.0", + "async-each": "1.0.1", + "braces": "2.3.2", + "fsevents": "1.2.4", + "glob-parent": "3.1.0", + "inherits": "2.0.3", + "is-binary-path": "1.0.1", + "is-glob": "4.0.0", + "lodash.debounce": "4.0.8", + "normalize-path": "2.1.1", + "path-is-absolute": "1.0.1", + "readdirp": "2.2.1", + "upath": "1.1.0" }, "dependencies": { "array-unique": { @@ -3083,16 +3078,16 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" + "arr-flatten": "1.1.0", + "array-unique": "0.3.2", + "extend-shallow": "2.0.1", + "fill-range": "4.0.0", + "isobject": "3.0.1", + "repeat-element": "1.1.3", + "snapdragon": "0.8.2", + "snapdragon-node": "2.1.1", + "split-string": "3.1.0", + "to-regex": "3.0.2" } }, "extend-shallow": { @@ -3100,7 +3095,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } }, "fill-range": { @@ -3108,10 +3103,10 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" + "extend-shallow": "2.0.1", + "is-number": "3.0.0", + "repeat-string": "1.6.1", + "to-regex-range": "2.1.1" } }, "glob-parent": { @@ -3119,8 +3114,8 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" + "is-glob": "3.1.0", + "path-dirname": "1.0.2" }, "dependencies": { "is-glob": { @@ -3128,7 +3123,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "requires": { - "is-extglob": "^2.1.0" + "is-extglob": "2.1.1" } } } @@ -3143,7 +3138,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", "requires": { - "is-extglob": "^2.1.1" + "is-extglob": "2.1.1" } }, "is-number": { @@ -3151,7 +3146,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" } } } @@ -3166,7 +3161,7 @@ "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.0.tgz", "integrity": "sha512-xDbVgyfDTT2piup/h8dK/y4QZfJRSa73bw1WZ8b4XM1o7fsFubUVGYcE+1ANtOzJJELGpYoG2961z0Z6OAld9A==", "requires": { - "tslib": "^1.9.0" + "tslib": "1.9.3" } }, "ci-info": { @@ -3179,8 +3174,8 @@ "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "inherits": "2.0.3", + "safe-buffer": "5.1.2" } }, "circular-json": { @@ -3193,10 +3188,10 @@ "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" + "arr-union": "3.1.0", + "define-property": "0.2.5", + "isobject": "3.0.1", + "static-extend": "0.1.2" }, "dependencies": { "define-property": { @@ -3204,7 +3199,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } } } @@ -3219,7 +3214,7 @@ "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz", "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==", "requires": { - "source-map": "~0.6.0" + "source-map": "0.6.1" }, "dependencies": { "source-map": { @@ -3234,7 +3229,7 @@ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", "requires": { - "restore-cursor": "^2.0.0" + "restore-cursor": "2.0.0" } }, "cli-width": { @@ -3247,9 +3242,9 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "wrap-ansi": "2.1.0" }, "dependencies": { "ansi-regex": { @@ -3262,7 +3257,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "3.0.0" } } } @@ -3272,11 +3267,11 @@ "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-0.2.4.tgz", "integrity": "sha1-TnPdCen7lxzDhnDF3O2cGJZIHMY=", "requires": { - "for-own": "^0.1.3", - "is-plain-object": "^2.0.1", - "kind-of": "^3.0.2", - "lazy-cache": "^1.0.3", - "shallow-clone": "^0.1.2" + "for-own": "0.1.5", + "is-plain-object": "2.0.4", + "kind-of": "3.2.2", + "lazy-cache": "1.0.4", + "shallow-clone": "0.1.2" } }, "co": { @@ -3289,9 +3284,9 @@ "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", "requires": { - "@types/q": "^1.5.1", - "chalk": "^2.4.1", - "q": "^1.1.2" + "@types/q": "1.5.1", + "chalk": "2.4.1", + "q": "1.5.1" } }, "code-point-at": { @@ -3304,8 +3299,8 @@ "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" + "map-visit": "1.0.0", + "object-visit": "1.0.1" } }, "color": { @@ -3313,8 +3308,8 @@ "resolved": "https://registry.npmjs.org/color/-/color-3.1.0.tgz", "integrity": "sha512-CwyopLkuRYO5ei2EpzpIh6LqJMt6Mt+jZhO5VI5f/wJLZriXQE32/SSqzmrh+QB+AZT81Cj8yv+7zwToW8ahZg==", "requires": { - "color-convert": "^1.9.1", - "color-string": "^1.5.2" + "color-convert": "1.9.3", + "color-string": "1.5.3" } }, "color-convert": { @@ -3335,8 +3330,8 @@ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", "requires": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" + "color-name": "1.1.3", + "simple-swizzle": "0.2.2" } }, "colors": { @@ -3349,7 +3344,7 @@ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", "requires": { - "delayed-stream": "~1.0.0" + "delayed-stream": "1.0.0" } }, "commander": { @@ -3377,7 +3372,7 @@ "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.15.tgz", "integrity": "sha512-4aE67DL33dSW9gw4CI2H/yTxqHLNcxp0yS6jB+4h+wr3e43+1z7vm0HU9qXOH8j+qjKuL8+UtkOxYQSMq60Ylw==", "requires": { - "mime-db": ">= 1.36.0 < 2" + "mime-db": "1.37.0" } }, "compression": { @@ -3385,13 +3380,13 @@ "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.3.tgz", "integrity": "sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg==", "requires": { - "accepts": "~1.3.5", + "accepts": "1.3.5", "bytes": "3.0.0", - "compressible": "~2.0.14", + "compressible": "2.0.15", "debug": "2.6.9", - "on-headers": "~1.0.1", + "on-headers": "1.0.1", "safe-buffer": "5.1.2", - "vary": "~1.1.2" + "vary": "1.1.2" }, "dependencies": { "debug": { @@ -3419,10 +3414,10 @@ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" + "buffer-from": "1.1.1", + "inherits": "2.0.3", + "readable-stream": "2.3.6", + "typedarray": "0.0.6" } }, "confusing-browser-globals": { @@ -3440,8 +3435,8 @@ "resolved": "https://registry.npmjs.org/connected-react-router/-/connected-react-router-6.2.1.tgz", "integrity": "sha512-7QFs0wPYvwrzA7NptHx0DgblNA/nVErX0TUjTiOCwXSaqj/1Ng+nEmEczrfdA8gw7kIzFIa08WJGMymdb7bAZA==", "requires": { - "immutable": "^3.8.1", - "seamless-immutable": "^7.1.3" + "immutable": "3.8.2", + "seamless-immutable": "7.1.4" } }, "console-browserify": { @@ -3449,7 +3444,7 @@ "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", "requires": { - "date-now": "^0.1.4" + "date-now": "0.1.4" } }, "console-control-strings": { @@ -3482,7 +3477,7 @@ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", "requires": { - "safe-buffer": "~5.1.1" + "safe-buffer": "5.1.2" } }, "cookie": { @@ -3500,12 +3495,12 @@ "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", "requires": { - "aproba": "^1.1.1", - "fs-write-stream-atomic": "^1.0.8", - "iferr": "^0.1.5", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.0" + "aproba": "1.2.0", + "fs-write-stream-atomic": "1.0.10", + "iferr": "0.1.5", + "mkdirp": "0.5.1", + "rimraf": "2.6.3", + "run-queue": "1.0.3" } }, "copy-descriptor": { @@ -3523,10 +3518,10 @@ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.0.7.tgz", "integrity": "sha512-PcLqxTKiDmNT6pSpy4N6KtuPwb53W+2tzNvwOZw0WH9N6O0vLIBq0x8aj8Oj75ere4YcGi48bDFCL+3fRJdlNA==", "requires": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.9.0", - "parse-json": "^4.0.0" + "import-fresh": "2.0.0", + "is-directory": "0.3.1", + "js-yaml": "3.12.1", + "parse-json": "4.0.0" } }, "create-ecdh": { @@ -3534,8 +3529,8 @@ "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.0.0" + "bn.js": "4.11.8", + "elliptic": "6.4.1" } }, "create-hash": { @@ -3543,11 +3538,11 @@ "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" + "cipher-base": "1.0.4", + "inherits": "2.0.3", + "md5.js": "1.3.5", + "ripemd160": "2.0.2", + "sha.js": "2.4.11" } }, "create-hmac": { @@ -3555,12 +3550,12 @@ "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "requires": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" + "cipher-base": "1.0.4", + "create-hash": "1.2.0", + "inherits": "2.0.3", + "ripemd160": "2.0.2", + "safe-buffer": "5.1.2", + "sha.js": "2.4.11" } }, "cross-spawn": { @@ -3568,11 +3563,11 @@ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "nice-try": "1.0.5", + "path-key": "2.0.1", + "semver": "5.6.0", + "shebang-command": "1.2.0", + "which": "1.3.1" } }, "crypto-browserify": { @@ -3580,17 +3575,17 @@ "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", "requires": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" + "browserify-cipher": "1.0.1", + "browserify-sign": "4.0.4", + "create-ecdh": "4.0.3", + "create-hash": "1.2.0", + "create-hmac": "1.1.7", + "diffie-hellman": "5.0.3", + "inherits": "2.0.3", + "pbkdf2": "3.0.17", + "public-encrypt": "4.0.3", + "randombytes": "2.0.6", + "randomfill": "1.0.4" } }, "css-color-names": { @@ -3603,8 +3598,8 @@ "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", "requires": { - "postcss": "^7.0.1", - "timsort": "^0.3.0" + "postcss": "7.0.8", + "timsort": "0.3.0" }, "dependencies": { "chalk": { @@ -3612,9 +3607,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -3622,7 +3617,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -3632,9 +3627,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -3647,7 +3642,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -3657,18 +3652,18 @@ "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-1.0.0.tgz", "integrity": "sha512-tMXlTYf3mIMt3b0dDCOQFJiVvxbocJ5Ho577WiGPYPZcqVEO218L2iU22pDXzkTZCLDE+9AmGSUkWxeh/nZReA==", "requires": { - "babel-code-frame": "^6.26.0", - "css-selector-tokenizer": "^0.7.0", - "icss-utils": "^2.1.0", - "loader-utils": "^1.0.2", - "lodash.camelcase": "^4.3.0", - "postcss": "^6.0.23", - "postcss-modules-extract-imports": "^1.2.0", - "postcss-modules-local-by-default": "^1.2.0", - "postcss-modules-scope": "^1.1.0", - "postcss-modules-values": "^1.3.0", - "postcss-value-parser": "^3.3.0", - "source-list-map": "^2.0.0" + "babel-code-frame": "6.26.0", + "css-selector-tokenizer": "0.7.1", + "icss-utils": "2.1.0", + "loader-utils": "1.2.3", + "lodash.camelcase": "4.3.0", + "postcss": "6.0.23", + "postcss-modules-extract-imports": "1.2.1", + "postcss-modules-local-by-default": "1.2.0", + "postcss-modules-scope": "1.1.0", + "postcss-modules-values": "1.3.0", + "postcss-value-parser": "3.3.1", + "source-list-map": "2.0.1" } }, "css-select": { @@ -3676,10 +3671,10 @@ "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.0.2.tgz", "integrity": "sha512-dSpYaDVoWaELjvZ3mS6IKZM/y2PMPa/XYoEfYNZePL4U/XgyxZNroHEHReDx/d+VgXh9VbCTtFqLkFbmeqeaRQ==", "requires": { - "boolbase": "^1.0.0", - "css-what": "^2.1.2", - "domutils": "^1.7.0", - "nth-check": "^1.0.2" + "boolbase": "1.0.0", + "css-what": "2.1.2", + "domutils": "1.7.0", + "nth-check": "1.0.2" } }, "css-select-base-adapter": { @@ -3692,9 +3687,9 @@ "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz", "integrity": "sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA==", "requires": { - "cssesc": "^0.1.0", - "fastparse": "^1.1.1", - "regexpu-core": "^1.0.0" + "cssesc": "0.1.0", + "fastparse": "1.1.2", + "regexpu-core": "1.0.0" }, "dependencies": { "jsesc": { @@ -3707,9 +3702,9 @@ "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz", "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=", "requires": { - "regenerate": "^1.2.1", - "regjsgen": "^0.2.0", - "regjsparser": "^0.1.4" + "regenerate": "1.4.0", + "regjsgen": "0.2.0", + "regjsparser": "0.1.5" } }, "regjsgen": { @@ -3722,7 +3717,7 @@ "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", "requires": { - "jsesc": "~0.5.0" + "jsesc": "0.5.0" } } } @@ -3732,8 +3727,8 @@ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.28.tgz", "integrity": "sha512-joNNW1gCp3qFFzj4St6zk+Wh/NBv0vM5YbEreZk0SD4S23S+1xBKb6cLDg2uj4P4k/GUMlIm6cKIDqIG+vdt0w==", "requires": { - "mdn-data": "~1.1.0", - "source-map": "^0.5.3" + "mdn-data": "1.1.4", + "source-map": "0.5.7" } }, "css-unit-converter": { @@ -3766,10 +3761,10 @@ "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.8.tgz", "integrity": "sha512-5GIY0VzAHORpbKiL3rMXp4w4M1Ki+XlXgEXyuWXVd3h6hlASb+9Vo76dNP56/elLMVBBsUfusCo1q56uW0UWig==", "requires": { - "cosmiconfig": "^5.0.0", - "cssnano-preset-default": "^4.0.6", - "is-resolvable": "^1.0.0", - "postcss": "^7.0.0" + "cosmiconfig": "5.0.7", + "cssnano-preset-default": "4.0.6", + "is-resolvable": "1.1.0", + "postcss": "7.0.8" }, "dependencies": { "chalk": { @@ -3777,9 +3772,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -3787,7 +3782,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -3797,9 +3792,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -3812,7 +3807,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -3822,36 +3817,36 @@ "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.6.tgz", "integrity": "sha512-UPboYbFaJFtDUhJ4fqctThWbbyF4q01/7UhsZbLzp35l+nUxtzh1SifoVlEfyLM3n3Z0htd8B1YlCxy9i+bQvg==", "requires": { - "css-declaration-sorter": "^4.0.1", - "cssnano-util-raw-cache": "^4.0.1", - "postcss": "^7.0.0", - "postcss-calc": "^7.0.0", - "postcss-colormin": "^4.0.2", - "postcss-convert-values": "^4.0.1", - "postcss-discard-comments": "^4.0.1", - "postcss-discard-duplicates": "^4.0.2", - "postcss-discard-empty": "^4.0.1", - "postcss-discard-overridden": "^4.0.1", - "postcss-merge-longhand": "^4.0.10", - "postcss-merge-rules": "^4.0.2", - "postcss-minify-font-values": "^4.0.2", - "postcss-minify-gradients": "^4.0.1", - "postcss-minify-params": "^4.0.1", - "postcss-minify-selectors": "^4.0.1", - "postcss-normalize-charset": "^4.0.1", - "postcss-normalize-display-values": "^4.0.1", - "postcss-normalize-positions": "^4.0.1", - "postcss-normalize-repeat-style": "^4.0.1", - "postcss-normalize-string": "^4.0.1", - "postcss-normalize-timing-functions": "^4.0.1", - "postcss-normalize-unicode": "^4.0.1", - "postcss-normalize-url": "^4.0.1", - "postcss-normalize-whitespace": "^4.0.1", - "postcss-ordered-values": "^4.1.1", - "postcss-reduce-initial": "^4.0.2", - "postcss-reduce-transforms": "^4.0.1", - "postcss-svgo": "^4.0.1", - "postcss-unique-selectors": "^4.0.1" + "css-declaration-sorter": "4.0.1", + "cssnano-util-raw-cache": "4.0.1", + "postcss": "7.0.8", + "postcss-calc": "7.0.1", + "postcss-colormin": "4.0.2", + "postcss-convert-values": "4.0.1", + "postcss-discard-comments": "4.0.1", + "postcss-discard-duplicates": "4.0.2", + "postcss-discard-empty": "4.0.1", + "postcss-discard-overridden": "4.0.1", + "postcss-merge-longhand": "4.0.10", + "postcss-merge-rules": "4.0.2", + "postcss-minify-font-values": "4.0.2", + "postcss-minify-gradients": "4.0.1", + "postcss-minify-params": "4.0.1", + "postcss-minify-selectors": "4.0.1", + "postcss-normalize-charset": "4.0.1", + "postcss-normalize-display-values": "4.0.1", + "postcss-normalize-positions": "4.0.1", + "postcss-normalize-repeat-style": "4.0.1", + "postcss-normalize-string": "4.0.1", + "postcss-normalize-timing-functions": "4.0.1", + "postcss-normalize-unicode": "4.0.1", + "postcss-normalize-url": "4.0.1", + "postcss-normalize-whitespace": "4.0.1", + "postcss-ordered-values": "4.1.1", + "postcss-reduce-initial": "4.0.2", + "postcss-reduce-transforms": "4.0.1", + "postcss-svgo": "4.0.1", + "postcss-unique-selectors": "4.0.1" }, "dependencies": { "chalk": { @@ -3859,9 +3854,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -3869,7 +3864,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -3879,9 +3874,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -3894,7 +3889,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -3914,7 +3909,7 @@ "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", "requires": { - "postcss": "^7.0.0" + "postcss": "7.0.8" }, "dependencies": { "chalk": { @@ -3922,9 +3917,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -3932,7 +3927,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -3942,9 +3937,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -3957,7 +3952,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -3980,8 +3975,8 @@ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.29.tgz", "integrity": "sha512-sRNb1XydwkW9IOci6iB2xmy8IGCj6r/fr+JWitvJ2JxQRPzN3T4AGGVWCMlVmVwM1gtgALJRmGIlWv5ppnGGkg==", "requires": { - "mdn-data": "~1.1.0", - "source-map": "^0.5.3" + "mdn-data": "1.1.4", + "source-map": "0.5.7" } } } @@ -3996,7 +3991,7 @@ "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.1.1.tgz", "integrity": "sha512-364AI1l/M5TYcFH83JnOH/pSqgaNnKmYgKrm0didZMGKWjQB60dymwWy1rKUgL3J1ffdq9xVi2yGLHdSjjSNog==", "requires": { - "cssom": "0.3.x" + "cssom": "0.3.4" } }, "csstype": { @@ -4009,7 +4004,7 @@ "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", "requires": { - "array-find-index": "^1.0.1" + "array-find-index": "1.0.2" } }, "cyclist": { @@ -4027,7 +4022,7 @@ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "requires": { - "assert-plus": "^1.0.0" + "assert-plus": "1.0.0" } }, "data-urls": { @@ -4035,9 +4030,9 @@ "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", "requires": { - "abab": "^2.0.0", - "whatwg-mimetype": "^2.2.0", - "whatwg-url": "^7.0.0" + "abab": "2.0.0", + "whatwg-mimetype": "2.3.0", + "whatwg-url": "7.0.0" } }, "date-now": { @@ -4050,7 +4045,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "requires": { - "ms": "^2.1.1" + "ms": "2.1.1" } }, "decamelize": { @@ -4078,8 +4073,8 @@ "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-2.7.2.tgz", "integrity": "sha512-lAc4i9QJR0YHSDFdzeBQKfZ1SRDG3hsJNEkrpcZa8QhBfidLAilT60BDEIVUUGqosFp425KOgB3uYqcnQrWafQ==", "requires": { - "execa": "^0.10.0", - "ip-regex": "^2.1.0" + "execa": "0.10.0", + "ip-regex": "2.1.0" }, "dependencies": { "execa": { @@ -4087,13 +4082,13 @@ "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "cross-spawn": "6.0.5", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" } } } @@ -4103,7 +4098,7 @@ "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-1.0.0.tgz", "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=", "requires": { - "strip-bom": "^2.0.0" + "strip-bom": "2.0.0" } }, "define-properties": { @@ -4111,7 +4106,7 @@ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", "requires": { - "object-keys": "^1.0.12" + "object-keys": "1.0.12" } }, "define-property": { @@ -4119,8 +4114,8 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "is-descriptor": "1.0.2", + "isobject": "3.0.1" }, "dependencies": { "is-accessor-descriptor": { @@ -4128,7 +4123,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { @@ -4136,7 +4131,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { @@ -4144,9 +4139,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } }, "kind-of": { @@ -4161,12 +4156,12 @@ "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz", "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=", "requires": { - "globby": "^6.1.0", - "is-path-cwd": "^1.0.0", - "is-path-in-cwd": "^1.0.0", - "p-map": "^1.1.1", - "pify": "^3.0.0", - "rimraf": "^2.2.8" + "globby": "6.1.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.1", + "p-map": "1.2.0", + "pify": "3.0.0", + "rimraf": "2.6.3" }, "dependencies": { "globby": { @@ -4174,11 +4169,11 @@ "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", "requires": { - "array-union": "^1.0.1", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "array-union": "1.0.2", + "glob": "7.1.3", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" }, "dependencies": { "pify": { @@ -4215,8 +4210,8 @@ "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" + "inherits": "2.0.3", + "minimalistic-assert": "1.0.1" } }, "destroy": { @@ -4229,7 +4224,7 @@ "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", "requires": { - "repeating": "^2.0.0" + "repeating": "2.0.1" } }, "detect-newline": { @@ -4247,8 +4242,8 @@ "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", "requires": { - "address": "^1.0.1", - "debug": "^2.6.0" + "address": "1.0.3", + "debug": "2.6.9" }, "dependencies": { "debug": { @@ -4276,9 +4271,9 @@ "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "requires": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" + "bn.js": "4.11.8", + "miller-rabin": "4.0.1", + "randombytes": "2.0.6" } }, "dir-glob": { @@ -4286,7 +4281,7 @@ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.0.tgz", "integrity": "sha512-YqrO+bduKFqPgspvpjDAaKk0qhmvY+SY7NjIRljCDAy6CX7Ft65irIduHbrYXhy+BxJnYKjWuREw6X42w9/+DQ==", "requires": { - "path-type": "^3.0.0" + "path-type": "3.0.0" }, "dependencies": { "path-type": { @@ -4294,7 +4289,7 @@ "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "requires": { - "pify": "^3.0.0" + "pify": "3.0.0" } }, "pify": { @@ -4314,8 +4309,8 @@ "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", "requires": { - "ip": "^1.1.0", - "safe-buffer": "^5.0.1" + "ip": "1.1.5", + "safe-buffer": "5.1.2" } }, "dns-txt": { @@ -4323,7 +4318,7 @@ "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", "requires": { - "buffer-indexof": "^1.0.0" + "buffer-indexof": "1.1.1" } }, "doctrine": { @@ -4331,7 +4326,7 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "requires": { - "esutils": "^2.0.2" + "esutils": "2.0.2" } }, "dom-converter": { @@ -4339,7 +4334,7 @@ "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", "requires": { - "utila": "~0.4" + "utila": "0.4.0" } }, "dom-serializer": { @@ -4347,8 +4342,8 @@ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", "requires": { - "domelementtype": "~1.1.1", - "entities": "~1.1.1" + "domelementtype": "1.1.3", + "entities": "1.1.2" }, "dependencies": { "domelementtype": { @@ -4373,7 +4368,7 @@ "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", "requires": { - "webidl-conversions": "^4.0.2" + "webidl-conversions": "4.0.2" } }, "domhandler": { @@ -4381,7 +4376,7 @@ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.1.0.tgz", "integrity": "sha1-0mRvXlf2w7qxHPbLBdPArPdBJZQ=", "requires": { - "domelementtype": "1" + "domelementtype": "1.3.1" } }, "domutils": { @@ -4389,8 +4384,8 @@ "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", "requires": { - "dom-serializer": "0", - "domelementtype": "1" + "dom-serializer": "0.1.0", + "domelementtype": "1.3.1" } }, "dot-prop": { @@ -4398,7 +4393,7 @@ "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", "requires": { - "is-obj": "^1.0.0" + "is-obj": "1.0.1" } }, "dotenv": { @@ -4421,10 +4416,10 @@ "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.1.tgz", "integrity": "sha512-vM58DwdnKmty+FSPzT14K9JXb90H+j5emaR4KYbr2KTIz00WHGbWOe5ghQTx233ZCLZtrGDALzKwcjEtSt35mA==", "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" + "end-of-stream": "1.4.1", + "inherits": "2.0.3", + "readable-stream": "2.3.6", + "stream-shift": "1.0.0" } }, "ecc-jsbn": { @@ -4432,8 +4427,8 @@ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" + "jsbn": "0.1.1", + "safer-buffer": "2.1.2" } }, "ee-first": { @@ -4451,13 +4446,13 @@ "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" + "bn.js": "4.11.8", + "brorand": "1.1.0", + "hash.js": "1.1.7", + "hmac-drbg": "1.0.1", + "inherits": "2.0.3", + "minimalistic-assert": "1.0.1", + "minimalistic-crypto-utils": "1.0.1" } }, "emoji-regex": { @@ -4480,7 +4475,7 @@ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", "requires": { - "once": "^1.4.0" + "once": "1.4.0" } }, "enhanced-resolve": { @@ -4488,9 +4483,9 @@ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", "requires": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.4.0", - "tapable": "^1.0.0" + "graceful-fs": "4.1.15", + "memory-fs": "0.4.1", + "tapable": "1.1.1" } }, "entities": { @@ -4503,7 +4498,7 @@ "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", "requires": { - "prr": "~1.0.1" + "prr": "1.0.1" } }, "error-ex": { @@ -4511,7 +4506,7 @@ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "requires": { - "is-arrayish": "^0.2.1" + "is-arrayish": "0.2.1" } }, "es-abstract": { @@ -4519,12 +4514,12 @@ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", "requires": { - "es-to-primitive": "^1.2.0", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "is-callable": "^1.1.4", - "is-regex": "^1.0.4", - "object-keys": "^1.0.12" + "es-to-primitive": "1.2.0", + "function-bind": "1.1.1", + "has": "1.0.3", + "is-callable": "1.1.4", + "is-regex": "1.0.4", + "object-keys": "1.0.12" } }, "es-to-primitive": { @@ -4532,9 +4527,9 @@ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "is-callable": "1.1.4", + "is-date-object": "1.0.1", + "is-symbol": "1.0.2" } }, "escape-html": { @@ -4552,11 +4547,11 @@ "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.0.tgz", "integrity": "sha512-IeMV45ReixHS53K/OmfKAIztN/igDHzTJUhZM3k1jMhIZWjk45SMwAtBsEXiJp3vSPmTcu6CXn7mDvFHRN66fw==", "requires": { - "esprima": "^3.1.3", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" + "esprima": "3.1.3", + "estraverse": "4.2.0", + "esutils": "2.0.2", + "optionator": "0.8.2", + "source-map": "0.6.1" }, "dependencies": { "esprima": { @@ -4577,44 +4572,44 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.6.0.tgz", "integrity": "sha512-/eVYs9VVVboX286mBK7bbKnO1yamUy2UCRjiY6MryhQL2PaaXCExsCQ2aO83OeYRhU2eCU/FMFP+tVMoOrzNrA==", "requires": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.5.3", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^3.1.0", - "doctrine": "^2.1.0", - "eslint-scope": "^4.0.0", - "eslint-utils": "^1.3.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^4.0.0", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^2.0.0", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.7.0", - "ignore": "^4.0.6", - "imurmurhash": "^0.1.4", - "inquirer": "^6.1.0", - "is-resolvable": "^1.1.0", - "js-yaml": "^3.12.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.5", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "pluralize": "^7.0.0", - "progress": "^2.0.0", - "regexpp": "^2.0.0", - "require-uncached": "^1.0.3", - "semver": "^5.5.1", - "strip-ansi": "^4.0.0", - "strip-json-comments": "^2.0.1", - "table": "^4.0.3", - "text-table": "^0.2.0" + "@babel/code-frame": "7.0.0", + "ajv": "6.6.2", + "chalk": "2.4.1", + "cross-spawn": "6.0.5", + "debug": "3.2.6", + "doctrine": "2.1.0", + "eslint-scope": "4.0.0", + "eslint-utils": "1.3.1", + "eslint-visitor-keys": "1.0.0", + "espree": "4.1.0", + "esquery": "1.0.1", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "functional-red-black-tree": "1.0.1", + "glob": "7.1.3", + "globals": "11.10.0", + "ignore": "4.0.6", + "imurmurhash": "0.1.4", + "inquirer": "6.2.1", + "is-resolvable": "1.1.0", + "js-yaml": "3.12.1", + "json-stable-stringify-without-jsonify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.11", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "7.0.0", + "progress": "2.0.3", + "regexpp": "2.0.1", + "require-uncached": "1.0.3", + "semver": "5.6.0", + "strip-ansi": "4.0.0", + "strip-json-comments": "2.0.1", + "table": "4.0.3", + "text-table": "0.2.0" }, "dependencies": { "ansi-regex": { @@ -4627,7 +4622,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "requires": { - "ms": "^2.1.1" + "ms": "2.1.1" } }, "eslint-scope": { @@ -4635,8 +4630,8 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" + "esrecurse": "4.2.1", + "estraverse": "4.2.0" } }, "strip-ansi": { @@ -4644,7 +4639,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "3.0.0" } } } @@ -4654,7 +4649,7 @@ "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-3.0.6.tgz", "integrity": "sha512-VL5rA1EBZv7f9toc9x71or7nr4jRmwCH4V9JKB9DFVaTLOLI9+vjWLgQLjMu3xR9iUT80dty86RbCfNaKyrFFg==", "requires": { - "confusing-browser-globals": "^1.0.5" + "confusing-browser-globals": "1.0.5" } }, "eslint-import-resolver-node": { @@ -4662,8 +4657,8 @@ "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", "requires": { - "debug": "^2.6.9", - "resolve": "^1.5.0" + "debug": "2.6.9", + "resolve": "1.8.1" }, "dependencies": { "debug": { @@ -4686,11 +4681,11 @@ "resolved": "https://registry.npmjs.org/eslint-loader/-/eslint-loader-2.1.1.tgz", "integrity": "sha512-1GrJFfSevQdYpoDzx8mEE2TDWsb/zmFuY09l6hURg1AeFIKQOvZ+vH0UPjzmd1CZIbfTV5HUkMeBmFiDBkgIsQ==", "requires": { - "loader-fs-cache": "^1.0.0", - "loader-utils": "^1.0.2", - "object-assign": "^4.0.1", - "object-hash": "^1.1.4", - "rimraf": "^2.6.1" + "loader-fs-cache": "1.0.1", + "loader-utils": "1.2.3", + "object-assign": "4.1.1", + "object-hash": "1.3.1", + "rimraf": "2.6.3" } }, "eslint-module-utils": { @@ -4698,8 +4693,8 @@ "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz", "integrity": "sha1-snA2LNiLGkitMIl2zn+lTphBF0Y=", "requires": { - "debug": "^2.6.8", - "pkg-dir": "^1.0.0" + "debug": "2.6.9", + "pkg-dir": "1.0.0" }, "dependencies": { "debug": { @@ -4715,8 +4710,8 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" } }, "ms": { @@ -4729,7 +4724,7 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "requires": { - "pinkie-promise": "^2.0.0" + "pinkie-promise": "2.0.1" } }, "pkg-dir": { @@ -4737,7 +4732,7 @@ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", "requires": { - "find-up": "^1.0.0" + "find-up": "1.1.2" } } } @@ -4747,7 +4742,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.50.1.tgz", "integrity": "sha512-9kRxF9hfM/O6WGZcZPszOVPd2W0TLHBtceulLTsGfwMPtiCCLnCW0ssRiOOiXyqrCA20pm1iXdXm7gQeN306zQ==", "requires": { - "lodash": "^4.17.10" + "lodash": "4.17.11" } }, "eslint-plugin-import": { @@ -4755,16 +4750,16 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.14.0.tgz", "integrity": "sha512-FpuRtniD/AY6sXByma2Wr0TXvXJ4nA/2/04VPlfpmUDPOpOY264x+ILiwnrk/k4RINgDAyFZByxqPUbSQ5YE7g==", "requires": { - "contains-path": "^0.1.0", - "debug": "^2.6.8", + "contains-path": "0.1.0", + "debug": "2.6.9", "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.1", - "eslint-module-utils": "^2.2.0", - "has": "^1.0.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.3", - "read-pkg-up": "^2.0.0", - "resolve": "^1.6.0" + "eslint-import-resolver-node": "0.3.2", + "eslint-module-utils": "2.2.0", + "has": "1.0.3", + "lodash": "4.17.11", + "minimatch": "3.0.4", + "read-pkg-up": "2.0.0", + "resolve": "1.8.1" }, "dependencies": { "debug": { @@ -4780,8 +4775,8 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" + "esutils": "2.0.2", + "isarray": "1.0.0" } }, "isarray": { @@ -4794,10 +4789,10 @@ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" + "graceful-fs": "4.1.15", + "parse-json": "2.2.0", + "pify": "2.3.0", + "strip-bom": "3.0.0" } }, "ms": { @@ -4810,7 +4805,7 @@ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "requires": { - "error-ex": "^1.2.0" + "error-ex": "1.3.2" } }, "path-type": { @@ -4818,7 +4813,7 @@ "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", "requires": { - "pify": "^2.0.0" + "pify": "2.3.0" } }, "read-pkg": { @@ -4826,9 +4821,9 @@ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" + "load-json-file": "2.0.0", + "normalize-package-data": "2.4.0", + "path-type": "2.0.0" } }, "read-pkg-up": { @@ -4836,8 +4831,8 @@ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" + "find-up": "2.1.0", + "read-pkg": "2.0.0" } }, "strip-bom": { @@ -4852,14 +4847,14 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.1.2.tgz", "integrity": "sha512-7gSSmwb3A+fQwtw0arguwMdOdzmKUgnUcbSNlo+GjKLAQFuC2EZxWqG9XHRI8VscBJD5a8raz3RuxQNFW+XJbw==", "requires": { - "aria-query": "^3.0.0", - "array-includes": "^3.0.3", - "ast-types-flow": "^0.0.7", - "axobject-query": "^2.0.1", - "damerau-levenshtein": "^1.0.4", - "emoji-regex": "^6.5.1", - "has": "^1.0.3", - "jsx-ast-utils": "^2.0.1" + "aria-query": "3.0.0", + "array-includes": "3.0.3", + "ast-types-flow": "0.0.7", + "axobject-query": "2.0.2", + "damerau-levenshtein": "1.0.4", + "emoji-regex": "6.5.1", + "has": "1.0.3", + "jsx-ast-utils": "2.0.1" } }, "eslint-plugin-react": { @@ -4867,11 +4862,11 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.11.1.tgz", "integrity": "sha512-cVVyMadRyW7qsIUh3FHp3u6QHNhOgVrLQYdQEB1bPWBsgbNCHdFAeNMquBMCcZJu59eNthX053L70l7gRt4SCw==", "requires": { - "array-includes": "^3.0.3", - "doctrine": "^2.1.0", - "has": "^1.0.3", - "jsx-ast-utils": "^2.0.1", - "prop-types": "^15.6.2" + "array-includes": "3.0.3", + "doctrine": "2.1.0", + "has": "1.0.3", + "jsx-ast-utils": "2.0.1", + "prop-types": "15.6.2" } }, "eslint-scope": { @@ -4879,8 +4874,8 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" + "esrecurse": "4.2.1", + "estraverse": "4.2.0" } }, "eslint-utils": { @@ -4898,9 +4893,9 @@ "resolved": "https://registry.npmjs.org/espree/-/espree-4.1.0.tgz", "integrity": "sha512-I5BycZW6FCVIub93TeVY1s7vjhP9CY6cXCznIRfiig7nRviKZYdRnj/sHEWC6A7WE9RDWOFq9+7OsWSYz8qv2w==", "requires": { - "acorn": "^6.0.2", - "acorn-jsx": "^5.0.0", - "eslint-visitor-keys": "^1.0.0" + "acorn": "6.0.5", + "acorn-jsx": "5.0.1", + "eslint-visitor-keys": "1.0.0" } }, "esprima": { @@ -4913,7 +4908,7 @@ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", "requires": { - "estraverse": "^4.0.0" + "estraverse": "4.2.0" } }, "esrecurse": { @@ -4921,7 +4916,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", "requires": { - "estraverse": "^4.1.0" + "estraverse": "4.2.0" } }, "estraverse": { @@ -4954,7 +4949,7 @@ "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-0.1.6.tgz", "integrity": "sha1-Cs7ehJ7X3RzMMsgRuxG5RNTykjI=", "requires": { - "original": ">=0.0.5" + "original": "1.0.2" } }, "evp_bytestokey": { @@ -4962,8 +4957,8 @@ "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "requires": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" + "md5.js": "1.3.5", + "safe-buffer": "5.1.2" } }, "exec-sh": { @@ -4971,7 +4966,7 @@ "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.2.tgz", "integrity": "sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw==", "requires": { - "merge": "^1.2.0" + "merge": "1.2.1" } }, "execa": { @@ -4979,13 +4974,13 @@ "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "cross-spawn": "5.1.0", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" }, "dependencies": { "cross-spawn": { @@ -4993,9 +4988,9 @@ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "lru-cache": "4.1.5", + "shebang-command": "1.2.0", + "which": "1.3.1" } } } @@ -5010,7 +5005,7 @@ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", "requires": { - "is-posix-bracket": "^0.1.0" + "is-posix-bracket": "0.1.1" } }, "expand-range": { @@ -5018,7 +5013,7 @@ "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", "requires": { - "fill-range": "^2.1.0" + "fill-range": "2.2.4" } }, "expand-tilde": { @@ -5026,7 +5021,7 @@ "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", "requires": { - "homedir-polyfill": "^1.0.1" + "homedir-polyfill": "1.0.1" } }, "expect": { @@ -5034,12 +5029,12 @@ "resolved": "https://registry.npmjs.org/expect/-/expect-23.6.0.tgz", "integrity": "sha512-dgSoOHgmtn/aDGRVFWclQyPDKl2CQRq0hmIEoUAuQs/2rn2NcvCWcSCovm6BLeuB/7EZuLGu2QfnR+qRt5OM4w==", "requires": { - "ansi-styles": "^3.2.0", - "jest-diff": "^23.6.0", - "jest-get-type": "^22.1.0", - "jest-matcher-utils": "^23.6.0", - "jest-message-util": "^23.4.0", - "jest-regex-util": "^23.3.0" + "ansi-styles": "3.2.1", + "jest-diff": "23.6.0", + "jest-get-type": "22.4.3", + "jest-matcher-utils": "23.6.0", + "jest-message-util": "23.4.0", + "jest-regex-util": "23.3.0" } }, "express": { @@ -5047,36 +5042,36 @@ "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", "requires": { - "accepts": "~1.3.5", + "accepts": "1.3.5", "array-flatten": "1.1.1", "body-parser": "1.18.3", "content-disposition": "0.5.2", - "content-type": "~1.0.4", + "content-type": "1.0.4", "cookie": "0.3.1", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", + "depd": "1.1.2", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "etag": "1.8.1", "finalhandler": "1.1.1", "fresh": "0.5.2", "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.2", + "methods": "1.1.2", + "on-finished": "2.3.0", + "parseurl": "1.3.2", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.4", + "proxy-addr": "2.0.4", "qs": "6.5.2", - "range-parser": "~1.2.0", + "range-parser": "1.2.0", "safe-buffer": "5.1.2", "send": "0.16.2", "serve-static": "1.13.2", "setprototypeof": "1.1.0", - "statuses": "~1.4.0", - "type-is": "~1.6.16", + "statuses": "1.4.0", + "type-is": "1.6.16", "utils-merge": "1.0.1", - "vary": "~1.1.2" + "vary": "1.1.2" }, "dependencies": { "array-flatten": { @@ -5114,8 +5109,8 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "assign-symbols": "1.0.0", + "is-extendable": "1.0.1" }, "dependencies": { "is-extendable": { @@ -5123,7 +5118,7 @@ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -5133,9 +5128,9 @@ "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz", "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==", "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" + "chardet": "0.7.0", + "iconv-lite": "0.4.24", + "tmp": "0.0.33" } }, "extglob": { @@ -5143,7 +5138,7 @@ "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", "requires": { - "is-extglob": "^1.0.0" + "is-extglob": "1.0.0" } }, "extsprintf": { @@ -5161,12 +5156,12 @@ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.6.tgz", "integrity": "sha512-0BvMaZc1k9F+MeWWMe8pL6YltFzZYcJsYU7D4JyDA6PAczaXvxqQQ/z+mDF7/4Mw01DeUc+i3CTKajnkANkV4w==", "requires": { - "@mrmlnc/readdir-enhanced": "^2.2.1", - "@nodelib/fs.stat": "^1.1.2", - "glob-parent": "^3.1.0", - "is-glob": "^4.0.0", - "merge2": "^1.2.3", - "micromatch": "^3.1.10" + "@mrmlnc/readdir-enhanced": "2.2.1", + "@nodelib/fs.stat": "1.1.3", + "glob-parent": "3.1.0", + "is-glob": "4.0.0", + "merge2": "1.2.3", + "micromatch": "3.1.10" }, "dependencies": { "arr-diff": { @@ -5184,16 +5179,16 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" + "arr-flatten": "1.1.0", + "array-unique": "0.3.2", + "extend-shallow": "2.0.1", + "fill-range": "4.0.0", + "isobject": "3.0.1", + "repeat-element": "1.1.3", + "snapdragon": "0.8.2", + "snapdragon-node": "2.1.1", + "split-string": "3.1.0", + "to-regex": "3.0.2" }, "dependencies": { "extend-shallow": { @@ -5201,7 +5196,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -5219,13 +5214,13 @@ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "posix-character-classes": "0.1.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -5233,7 +5228,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "extend-shallow": { @@ -5241,7 +5236,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } }, "is-accessor-descriptor": { @@ -5249,7 +5244,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -5257,7 +5252,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -5267,7 +5262,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -5275,7 +5270,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -5285,9 +5280,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" } }, "kind-of": { @@ -5302,14 +5297,14 @@ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "array-unique": "0.3.2", + "define-property": "1.0.0", + "expand-brackets": "2.1.4", + "extend-shallow": "2.0.1", + "fragment-cache": "0.2.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -5317,7 +5312,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "extend-shallow": { @@ -5325,7 +5320,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -5335,10 +5330,10 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" + "extend-shallow": "2.0.1", + "is-number": "3.0.0", + "repeat-string": "1.6.1", + "to-regex-range": "2.1.1" }, "dependencies": { "extend-shallow": { @@ -5346,7 +5341,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -5356,8 +5351,8 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" + "is-glob": "3.1.0", + "path-dirname": "1.0.2" }, "dependencies": { "is-glob": { @@ -5365,7 +5360,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "requires": { - "is-extglob": "^2.1.0" + "is-extglob": "2.1.1" } } } @@ -5375,7 +5370,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { @@ -5383,7 +5378,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { @@ -5391,9 +5386,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } }, "is-extglob": { @@ -5406,7 +5401,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", "requires": { - "is-extglob": "^2.1.1" + "is-extglob": "2.1.1" } }, "is-number": { @@ -5414,7 +5409,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -5422,7 +5417,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -5437,19 +5432,19 @@ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "braces": "2.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "extglob": "2.0.4", + "fragment-cache": "0.2.1", + "kind-of": "6.0.2", + "nanomatch": "1.2.13", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" } }, "ms": { @@ -5479,7 +5474,7 @@ "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.1.tgz", "integrity": "sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg=", "requires": { - "websocket-driver": ">=0.5.1" + "websocket-driver": "0.7.0" } }, "fb-watchman": { @@ -5487,7 +5482,7 @@ "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", "requires": { - "bser": "^2.0.0" + "bser": "2.0.0" } }, "figgy-pudding": { @@ -5500,7 +5495,7 @@ "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", "requires": { - "escape-string-regexp": "^1.0.5" + "escape-string-regexp": "1.0.5" } }, "file-entry-cache": { @@ -5508,8 +5503,8 @@ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", "requires": { - "flat-cache": "^1.2.1", - "object-assign": "^4.0.1" + "flat-cache": "1.3.4", + "object-assign": "4.1.1" } }, "file-loader": { @@ -5517,8 +5512,8 @@ "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-2.0.0.tgz", "integrity": "sha512-YCsBfd1ZGCyonOKLxPiKPdu+8ld9HAaMEvJewzz+b2eTF7uL5Zm/HdBF6FjCrpCMRq25Mi0U1gl4pwn2TlH7hQ==", "requires": { - "loader-utils": "^1.0.2", - "schema-utils": "^1.0.0" + "loader-utils": "1.2.3", + "schema-utils": "1.0.0" } }, "filename-regex": { @@ -5531,8 +5526,8 @@ "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", "requires": { - "glob": "^7.0.3", - "minimatch": "^3.0.3" + "glob": "7.1.3", + "minimatch": "3.0.4" } }, "filesize": { @@ -5545,11 +5540,11 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", "requires": { - "is-number": "^2.1.0", - "isobject": "^2.0.0", - "randomatic": "^3.0.0", - "repeat-element": "^1.1.2", - "repeat-string": "^1.5.2" + "is-number": "2.1.0", + "isobject": "2.1.0", + "randomatic": "3.1.1", + "repeat-element": "1.1.3", + "repeat-string": "1.6.1" }, "dependencies": { "isarray": { @@ -5573,12 +5568,12 @@ "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", "requires": { "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.2", - "statuses": "~1.4.0", - "unpipe": "~1.0.0" + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "statuses": "1.4.0", + "unpipe": "1.0.0" }, "dependencies": { "debug": { @@ -5601,9 +5596,9 @@ "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", "requires": { - "commondir": "^1.0.1", - "make-dir": "^1.0.0", - "pkg-dir": "^2.0.0" + "commondir": "1.0.1", + "make-dir": "1.3.0", + "pkg-dir": "2.0.0" } }, "find-up": { @@ -5611,7 +5606,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "requires": { - "locate-path": "^2.0.0" + "locate-path": "2.0.0" } }, "flat-cache": { @@ -5619,10 +5614,10 @@ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", "requires": { - "circular-json": "^0.3.1", - "graceful-fs": "^4.1.2", - "rimraf": "~2.6.2", - "write": "^0.2.1" + "circular-json": "0.3.3", + "graceful-fs": "4.1.15", + "rimraf": "2.6.3", + "write": "0.2.1" } }, "flatten": { @@ -5635,8 +5630,8 @@ "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz", "integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==", "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.4" + "inherits": "2.0.3", + "readable-stream": "2.3.6" } }, "follow-redirects": { @@ -5644,7 +5639,7 @@ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.6.1.tgz", "integrity": "sha512-t2JCjbzxQpWvbhts3l6SH1DKzSrx8a+SsaVf4h6bG4kOXUuPYS/kg2Lr4gQSb7eemaHqJkOThF1BGyjlUkO1GQ==", "requires": { - "debug": "=3.1.0" + "debug": "3.1.0" }, "dependencies": { "debug": { @@ -5672,7 +5667,7 @@ "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", "requires": { - "for-in": "^1.0.1" + "for-in": "1.0.2" } }, "forever-agent": { @@ -5685,14 +5680,14 @@ "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin-alt/-/fork-ts-checker-webpack-plugin-alt-0.4.14.tgz", "integrity": "sha512-s0wjOBuPdylMRBzZ4yO8LSJuzem3g0MYZFxsjRXrFDQyL5KJBVSq30+GoHM/t/r2CRU4tI6zi04sq6OXK0UYnw==", "requires": { - "babel-code-frame": "^6.22.0", - "chalk": "^2.4.1", - "chokidar": "^2.0.4", - "lodash": "^4.17.11", - "micromatch": "^3.1.10", - "minimatch": "^3.0.4", - "resolve": "^1.5.0", - "tapable": "^1.0.0" + "babel-code-frame": "6.26.0", + "chalk": "2.4.1", + "chokidar": "2.0.4", + "lodash": "4.17.11", + "micromatch": "3.1.10", + "minimatch": "3.0.4", + "resolve": "1.8.1", + "tapable": "1.1.1" }, "dependencies": { "arr-diff": { @@ -5710,16 +5705,16 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" + "arr-flatten": "1.1.0", + "array-unique": "0.3.2", + "extend-shallow": "2.0.1", + "fill-range": "4.0.0", + "isobject": "3.0.1", + "repeat-element": "1.1.3", + "snapdragon": "0.8.2", + "snapdragon-node": "2.1.1", + "split-string": "3.1.0", + "to-regex": "3.0.2" }, "dependencies": { "extend-shallow": { @@ -5727,7 +5722,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -5745,13 +5740,13 @@ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "posix-character-classes": "0.1.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -5759,7 +5754,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "extend-shallow": { @@ -5767,7 +5762,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } }, "is-accessor-descriptor": { @@ -5775,7 +5770,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -5783,7 +5778,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -5793,7 +5788,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -5801,7 +5796,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -5811,9 +5806,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" } }, "kind-of": { @@ -5828,14 +5823,14 @@ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "array-unique": "0.3.2", + "define-property": "1.0.0", + "expand-brackets": "2.1.4", + "extend-shallow": "2.0.1", + "fragment-cache": "0.2.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -5843,7 +5838,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "extend-shallow": { @@ -5851,7 +5846,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -5861,10 +5856,10 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" + "extend-shallow": "2.0.1", + "is-number": "3.0.0", + "repeat-string": "1.6.1", + "to-regex-range": "2.1.1" }, "dependencies": { "extend-shallow": { @@ -5872,7 +5867,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -5882,7 +5877,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { @@ -5890,7 +5885,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { @@ -5898,9 +5893,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } }, "is-number": { @@ -5908,7 +5903,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -5916,7 +5911,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -5931,19 +5926,19 @@ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "braces": "2.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "extglob": "2.0.4", + "fragment-cache": "0.2.1", + "kind-of": "6.0.2", + "nanomatch": "1.2.13", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" } }, "ms": { @@ -5958,9 +5953,9 @@ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" + "asynckit": "0.4.0", + "combined-stream": "1.0.7", + "mime-types": "2.1.21" } }, "forwarded": { @@ -5973,7 +5968,7 @@ "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", "requires": { - "map-cache": "^0.2.2" + "map-cache": "0.2.2" } }, "fresh": { @@ -5986,8 +5981,8 @@ "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" + "inherits": "2.0.3", + "readable-stream": "2.3.6" } }, "fs-extra": { @@ -5995,9 +5990,9 @@ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.0.tgz", "integrity": "sha512-EglNDLRpmaTWiD/qraZn6HREAEAHJcJOmxNEYwq6xeMKnVMAy3GUcFB+wXt2C6k4CNvB/mP1y/U3dzvKKj5OtQ==", "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "graceful-fs": "4.1.15", + "jsonfile": "4.0.0", + "universalify": "0.1.2" } }, "fs-write-stream-atomic": { @@ -6005,10 +6000,10 @@ "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", "requires": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" + "graceful-fs": "4.1.15", + "iferr": "0.1.5", + "imurmurhash": "0.1.4", + "readable-stream": "2.3.6" } }, "fs.realpath": { @@ -6022,8 +6017,8 @@ "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", "optional": true, "requires": { - "nan": "^2.9.2", - "node-pre-gyp": "^0.10.0" + "nan": "2.12.1", + "node-pre-gyp": "0.10.0" }, "dependencies": { "abbrev": { @@ -6045,8 +6040,8 @@ "bundled": true, "optional": true, "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" + "delegates": "1.0.0", + "readable-stream": "2.3.6" } }, "balanced-match": { @@ -6057,7 +6052,7 @@ "version": "1.1.11", "bundled": true, "requires": { - "balanced-match": "^1.0.0", + "balanced-match": "1.0.0", "concat-map": "0.0.1" } }, @@ -6111,7 +6106,7 @@ "bundled": true, "optional": true, "requires": { - "minipass": "^2.2.1" + "minipass": "2.2.4" } }, "fs.realpath": { @@ -6124,14 +6119,14 @@ "bundled": true, "optional": true, "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" + "aproba": "1.2.0", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.2" } }, "glob": { @@ -6139,12 +6134,12 @@ "bundled": true, "optional": 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" + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } }, "has-unicode": { @@ -6157,7 +6152,7 @@ "bundled": true, "optional": true, "requires": { - "safer-buffer": "^2.1.0" + "safer-buffer": "2.1.2" } }, "ignore-walk": { @@ -6165,7 +6160,7 @@ "bundled": true, "optional": true, "requires": { - "minimatch": "^3.0.4" + "minimatch": "3.0.4" } }, "inflight": { @@ -6173,8 +6168,8 @@ "bundled": true, "optional": true, "requires": { - "once": "^1.3.0", - "wrappy": "1" + "once": "1.4.0", + "wrappy": "1.0.2" } }, "inherits": { @@ -6190,7 +6185,7 @@ "version": "1.0.0", "bundled": true, "requires": { - "number-is-nan": "^1.0.0" + "number-is-nan": "1.0.1" } }, "isarray": { @@ -6202,7 +6197,7 @@ "version": "3.0.4", "bundled": true, "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "1.1.11" } }, "minimist": { @@ -6213,8 +6208,8 @@ "version": "2.2.4", "bundled": true, "requires": { - "safe-buffer": "^5.1.1", - "yallist": "^3.0.0" + "safe-buffer": "5.1.1", + "yallist": "3.0.2" } }, "minizlib": { @@ -6222,7 +6217,7 @@ "bundled": true, "optional": true, "requires": { - "minipass": "^2.2.1" + "minipass": "2.2.4" } }, "mkdirp": { @@ -6242,9 +6237,9 @@ "bundled": true, "optional": true, "requires": { - "debug": "^2.1.2", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" + "debug": "2.6.9", + "iconv-lite": "0.4.21", + "sax": "1.2.4" } }, "node-pre-gyp": { @@ -6252,16 +6247,16 @@ "bundled": true, "optional": true, "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.0", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.1.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" + "detect-libc": "1.0.3", + "mkdirp": "0.5.1", + "needle": "2.2.0", + "nopt": "4.0.1", + "npm-packlist": "1.1.10", + "npmlog": "4.1.2", + "rc": "1.2.7", + "rimraf": "2.6.2", + "semver": "5.5.0", + "tar": "4.4.1" } }, "nopt": { @@ -6269,8 +6264,8 @@ "bundled": true, "optional": true, "requires": { - "abbrev": "1", - "osenv": "^0.1.4" + "abbrev": "1.1.1", + "osenv": "0.1.5" } }, "npm-bundled": { @@ -6283,8 +6278,8 @@ "bundled": true, "optional": true, "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" + "ignore-walk": "3.0.1", + "npm-bundled": "1.0.3" } }, "npmlog": { @@ -6292,10 +6287,10 @@ "bundled": true, "optional": true, "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" + "are-we-there-yet": "1.1.4", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" } }, "number-is-nan": { @@ -6311,7 +6306,7 @@ "version": "1.4.0", "bundled": true, "requires": { - "wrappy": "1" + "wrappy": "1.0.2" } }, "os-homedir": { @@ -6329,8 +6324,8 @@ "bundled": true, "optional": true, "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" } }, "path-is-absolute": { @@ -6348,10 +6343,10 @@ "bundled": true, "optional": true, "requires": { - "deep-extend": "^0.5.1", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" + "deep-extend": "0.5.1", + "ini": "1.3.5", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" }, "dependencies": { "minimist": { @@ -6366,13 +6361,13 @@ "bundled": true, "optional": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.1", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "rimraf": { @@ -6380,7 +6375,7 @@ "bundled": true, "optional": true, "requires": { - "glob": "^7.0.5" + "glob": "7.1.2" } }, "safe-buffer": { @@ -6416,9 +6411,9 @@ "version": "1.0.2", "bundled": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" } }, "string_decoder": { @@ -6426,14 +6421,14 @@ "bundled": true, "optional": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.1" } }, "strip-ansi": { "version": "3.0.1", "bundled": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "strip-json-comments": { @@ -6446,13 +6441,13 @@ "bundled": true, "optional": true, "requires": { - "chownr": "^1.0.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.2.4", - "minizlib": "^1.1.0", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.1", - "yallist": "^3.0.2" + "chownr": "1.0.1", + "fs-minipass": "1.2.5", + "minipass": "2.2.4", + "minizlib": "1.1.0", + "mkdirp": "0.5.1", + "safe-buffer": "5.1.1", + "yallist": "3.0.2" } }, "util-deprecate": { @@ -6465,7 +6460,7 @@ "bundled": true, "optional": true, "requires": { - "string-width": "^1.0.2" + "string-width": "1.0.2" } }, "wrappy": { @@ -6483,10 +6478,10 @@ "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", "requires": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" + "graceful-fs": "4.1.15", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.6.3" } }, "function-bind": { @@ -6504,14 +6499,14 @@ "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" + "aproba": "1.2.0", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.3" }, "dependencies": { "is-fullwidth-code-point": { @@ -6519,7 +6514,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "requires": { - "number-is-nan": "^1.0.0" + "number-is-nan": "1.0.1" } }, "string-width": { @@ -6527,9 +6522,9 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" } } } @@ -6539,7 +6534,7 @@ "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", "requires": { - "globule": "^1.0.0" + "globule": "1.2.1" } }, "get-caller-file": { @@ -6572,7 +6567,7 @@ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "requires": { - "assert-plus": "^1.0.0" + "assert-plus": "1.0.0" } }, "glob": { @@ -6580,12 +6575,12 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "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" + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } }, "glob-base": { @@ -6593,8 +6588,8 @@ "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", "requires": { - "glob-parent": "^2.0.0", - "is-glob": "^2.0.0" + "glob-parent": "2.0.0", + "is-glob": "2.0.1" } }, "glob-parent": { @@ -6602,7 +6597,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", "requires": { - "is-glob": "^2.0.0" + "is-glob": "2.0.1" } }, "glob-to-regexp": { @@ -6615,9 +6610,9 @@ "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" + "global-prefix": "1.0.2", + "is-windows": "1.0.2", + "resolve-dir": "1.0.1" } }, "global-prefix": { @@ -6625,11 +6620,11 @@ "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", "requires": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" + "expand-tilde": "2.0.2", + "homedir-polyfill": "1.0.1", + "ini": "1.3.5", + "is-windows": "1.0.2", + "which": "1.3.1" } }, "globals": { @@ -6642,13 +6637,13 @@ "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.1.tgz", "integrity": "sha512-oMrYrJERnKBLXNLVTqhm3vPEdJ/b2ZE28xN4YARiix1NOIOBPEpOUnm844K1iu/BkphCaf2WNFwMszv8Soi1pw==", "requires": { - "array-union": "^1.0.1", - "dir-glob": "^2.0.0", - "fast-glob": "^2.0.2", - "glob": "^7.1.2", - "ignore": "^3.3.5", - "pify": "^3.0.0", - "slash": "^1.0.0" + "array-union": "1.0.2", + "dir-glob": "2.2.0", + "fast-glob": "2.2.6", + "glob": "7.1.3", + "ignore": "3.3.10", + "pify": "3.0.0", + "slash": "1.0.0" }, "dependencies": { "ignore": { @@ -6668,9 +6663,9 @@ "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz", "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==", "requires": { - "glob": "~7.1.1", - "lodash": "~4.17.10", - "minimatch": "~3.0.2" + "glob": "7.1.3", + "lodash": "4.17.11", + "minimatch": "3.0.4" } }, "graceful-fs": { @@ -6688,8 +6683,8 @@ "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.0.0.tgz", "integrity": "sha512-5iI7omclyqrnWw4XbXAmGhPsABkSIDQonv2K0h61lybgofWa6iZyvrI3r2zsJH4P8Nb64fFVzlvfhs0g7BBxAA==", "requires": { - "duplexer": "^0.1.1", - "pify": "^3.0.0" + "duplexer": "0.1.1", + "pify": "3.0.0" }, "dependencies": { "pify": { @@ -6704,9 +6699,9 @@ "resolved": "https://registry.npmjs.org/h2x-core/-/h2x-core-1.1.1.tgz", "integrity": "sha512-LdXe4Irs731knLtHgLyFrnJCumfiqXXQwKN1IMUhi37li29PLfLbMDvfK7Rk4wmgHLKP+sIITT1mcJV4QsC3nw==", "requires": { - "h2x-generate": "^1.1.0", - "h2x-parse": "^1.1.1", - "h2x-traverse": "^1.1.0" + "h2x-generate": "1.1.0", + "h2x-parse": "1.1.1", + "h2x-traverse": "1.1.0" } }, "h2x-generate": { @@ -6714,7 +6709,7 @@ "resolved": "https://registry.npmjs.org/h2x-generate/-/h2x-generate-1.1.0.tgz", "integrity": "sha512-L7Hym0yb20QIjvqeULUPOeh/cyvScdOAyJ6oRlh5dF0+w92hf3OiTk1q15KBijde7jGEe+0R4aOmtW8gkPNIzg==", "requires": { - "h2x-traverse": "^1.1.0" + "h2x-traverse": "1.1.0" } }, "h2x-parse": { @@ -6722,8 +6717,8 @@ "resolved": "https://registry.npmjs.org/h2x-parse/-/h2x-parse-1.1.1.tgz", "integrity": "sha512-WRSmPF+tIWuUXVEZaYRhcZx/JGEJx8LjZpDDtrvMr5m/GTR0NerydCik5dRzcKXPWCtfXxuJRLR4v2P4HB2B1A==", "requires": { - "h2x-types": "^1.1.0", - "jsdom": ">=11.0.0" + "h2x-types": "1.1.0", + "jsdom": "13.1.0" } }, "h2x-plugin-jsx": { @@ -6731,7 +6726,7 @@ "resolved": "https://registry.npmjs.org/h2x-plugin-jsx/-/h2x-plugin-jsx-1.2.0.tgz", "integrity": "sha512-a7Vb3BHhJJq0dPDNdqguEyQirENkVsFtvM2YkiaT5h/fmGhmM1nDy3BLeJeSKi2tL2g9v4ykm2Z+GG9QrhDgPA==", "requires": { - "h2x-types": "^1.1.0" + "h2x-types": "1.1.0" } }, "h2x-traverse": { @@ -6739,7 +6734,7 @@ "resolved": "https://registry.npmjs.org/h2x-traverse/-/h2x-traverse-1.1.0.tgz", "integrity": "sha512-1ND8ZbISLSUgpLHYJRvhvElITvs0g44L7RxjeXViz5XP6rooa+FtXTFLByl2Yg01zj2txubifHIuU4pgvj8l+A==", "requires": { - "h2x-types": "^1.1.0" + "h2x-types": "1.1.0" } }, "h2x-types": { @@ -6757,10 +6752,10 @@ "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.12.tgz", "integrity": "sha512-RhmTekP+FZL+XNhwS1Wf+bTTZpdLougwt5pcgA1tuz6Jcx0fpH/7z0qd71RKnZHBCxIRBHfBOnio4gViPemNzA==", "requires": { - "async": "^2.5.0", - "optimist": "^0.6.1", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4" + "async": "2.6.1", + "optimist": "0.6.1", + "source-map": "0.6.1", + "uglify-js": "3.4.9" }, "dependencies": { "source-map": { @@ -6780,8 +6775,8 @@ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" + "ajv": "6.6.2", + "har-schema": "2.0.0" } }, "harmony-reflect": { @@ -6794,7 +6789,7 @@ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "requires": { - "function-bind": "^1.1.1" + "function-bind": "1.1.1" } }, "has-ansi": { @@ -6802,7 +6797,7 @@ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "has-flag": { @@ -6825,9 +6820,9 @@ "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" + "get-value": "2.0.6", + "has-values": "1.0.0", + "isobject": "3.0.1" } }, "has-values": { @@ -6835,8 +6830,8 @@ "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" + "is-number": "3.0.0", + "kind-of": "4.0.0" }, "dependencies": { "is-number": { @@ -6844,7 +6839,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -6852,7 +6847,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -6862,7 +6857,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -6872,8 +6867,8 @@ "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "inherits": "2.0.3", + "safe-buffer": "5.1.2" } }, "hash.js": { @@ -6881,8 +6876,8 @@ "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" + "inherits": "2.0.3", + "minimalistic-assert": "1.0.1" } }, "he": { @@ -6900,11 +6895,11 @@ "resolved": "https://registry.npmjs.org/history/-/history-4.7.2.tgz", "integrity": "sha512-1zkBRWW6XweO0NBcjiphtVJVsIQ+SXF29z9DVkceeaSLVMFXHool+fdCZD4spDCfZJCILPILc3bm7Bc+HRi0nA==", "requires": { - "invariant": "^2.2.1", - "loose-envify": "^1.2.0", - "resolve-pathname": "^2.2.0", - "value-equal": "^0.4.0", - "warning": "^3.0.0" + "invariant": "2.2.4", + "loose-envify": "1.4.0", + "resolve-pathname": "2.2.0", + "value-equal": "0.4.0", + "warning": "3.0.0" }, "dependencies": { "warning": { @@ -6912,7 +6907,7 @@ "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", "requires": { - "loose-envify": "^1.0.0" + "loose-envify": "1.4.0" } } } @@ -6922,9 +6917,9 @@ "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" + "hash.js": "1.1.7", + "minimalistic-assert": "1.0.1", + "minimalistic-crypto-utils": "1.0.1" } }, "hoek": { @@ -6937,7 +6932,7 @@ "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.2.1.tgz", "integrity": "sha512-TFsu3TV3YLY+zFTZDrN8L2DTFanObwmBLpWvJs1qfUuEQ5bTAdFcwfx2T/bsCXfM9QHSLvjfP+nihEl0yvozxw==", "requires": { - "react-is": "^16.3.2" + "react-is": "16.7.0" } }, "home-or-tmp": { @@ -6945,8 +6940,8 @@ "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.1" + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" } }, "homedir-polyfill": { @@ -6954,7 +6949,7 @@ "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz", "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", "requires": { - "parse-passwd": "^1.0.0" + "parse-passwd": "1.0.0" } }, "hoopy": { @@ -6972,10 +6967,10 @@ "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", "requires": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" + "inherits": "2.0.3", + "obuf": "1.1.2", + "readable-stream": "2.3.6", + "wbuf": "1.7.3" } }, "hsl-regex": { @@ -6998,7 +6993,7 @@ "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", "requires": { - "whatwg-encoding": "^1.0.1" + "whatwg-encoding": "1.0.5" } }, "html-entities": { @@ -7011,13 +7006,13 @@ "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", "requires": { - "camel-case": "3.0.x", - "clean-css": "4.2.x", - "commander": "2.17.x", - "he": "1.2.x", - "param-case": "2.1.x", - "relateurl": "0.2.x", - "uglify-js": "3.4.x" + "camel-case": "3.0.0", + "clean-css": "4.2.1", + "commander": "2.17.1", + "he": "1.2.0", + "param-case": "2.1.1", + "relateurl": "0.2.7", + "uglify-js": "3.4.9" }, "dependencies": { "commander": { @@ -7033,11 +7028,11 @@ "integrity": "sha512-tyvhjVpuGqD7QYHi1l1drMQTg5i+qRxpQEGbdnYFREgOKy7aFDf/ocQ/V1fuEDlQx7jV2zMap3Hj2nE9i5eGXw==", "requires": { "@types/tapable": "1.0.2", - "html-minifier": "^3.2.3", - "loader-utils": "^1.1.0", - "lodash": "^4.17.10", - "pretty-error": "^2.0.2", - "tapable": "^1.0.0", + "html-minifier": "3.5.21", + "loader-utils": "1.2.3", + "lodash": "4.17.11", + "pretty-error": "2.1.1", + "tapable": "1.1.1", "util.promisify": "1.0.0" } }, @@ -7046,10 +7041,10 @@ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.3.0.tgz", "integrity": "sha1-zHDQWln2VC5D8OaFyYLhTJJKnv4=", "requires": { - "domelementtype": "1", - "domhandler": "2.1", - "domutils": "1.1", - "readable-stream": "1.0" + "domelementtype": "1.3.1", + "domhandler": "2.1.0", + "domutils": "1.1.6", + "readable-stream": "1.0.34" }, "dependencies": { "domutils": { @@ -7057,7 +7052,7 @@ "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.1.6.tgz", "integrity": "sha1-vdw94Jm5ou+sxRxiPyj0FuzFdIU=", "requires": { - "domelementtype": "1" + "domelementtype": "1.3.1" } }, "readable-stream": { @@ -7065,10 +7060,10 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", + "core-util-is": "1.0.2", + "inherits": "2.0.3", "isarray": "0.0.1", - "string_decoder": "~0.10.x" + "string_decoder": "0.10.31" } }, "string_decoder": { @@ -7088,10 +7083,10 @@ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "requires": { - "depd": "~1.1.2", + "depd": "1.1.2", "inherits": "2.0.3", "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" + "statuses": "1.4.0" } }, "http-parser-js": { @@ -7104,9 +7099,9 @@ "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz", "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", "requires": { - "eventemitter3": "^3.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" + "eventemitter3": "3.1.0", + "follow-redirects": "1.6.1", + "requires-port": "1.0.0" } }, "http-proxy-middleware": { @@ -7114,10 +7109,10 @@ "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.18.0.tgz", "integrity": "sha512-Fs25KVMPAIIcgjMZkVHJoKg9VcXcC1C8yb9JUgeDvVXY0S/zgVIhMb+qVswDIgtJe2DfckMSY2d6TuTEutlk6Q==", "requires": { - "http-proxy": "^1.16.2", - "is-glob": "^4.0.0", - "lodash": "^4.17.5", - "micromatch": "^3.1.9" + "http-proxy": "1.17.0", + "is-glob": "4.0.0", + "lodash": "4.17.11", + "micromatch": "3.1.10" }, "dependencies": { "arr-diff": { @@ -7135,16 +7130,16 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" + "arr-flatten": "1.1.0", + "array-unique": "0.3.2", + "extend-shallow": "2.0.1", + "fill-range": "4.0.0", + "isobject": "3.0.1", + "repeat-element": "1.1.3", + "snapdragon": "0.8.2", + "snapdragon-node": "2.1.1", + "split-string": "3.1.0", + "to-regex": "3.0.2" }, "dependencies": { "extend-shallow": { @@ -7152,7 +7147,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -7170,13 +7165,13 @@ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "posix-character-classes": "0.1.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -7184,7 +7179,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "extend-shallow": { @@ -7192,7 +7187,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } }, "is-accessor-descriptor": { @@ -7200,7 +7195,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -7208,7 +7203,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -7218,7 +7213,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -7226,7 +7221,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -7236,9 +7231,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" } }, "kind-of": { @@ -7253,14 +7248,14 @@ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "array-unique": "0.3.2", + "define-property": "1.0.0", + "expand-brackets": "2.1.4", + "extend-shallow": "2.0.1", + "fragment-cache": "0.2.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -7268,7 +7263,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "extend-shallow": { @@ -7276,7 +7271,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -7286,10 +7281,10 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" + "extend-shallow": "2.0.1", + "is-number": "3.0.0", + "repeat-string": "1.6.1", + "to-regex-range": "2.1.1" }, "dependencies": { "extend-shallow": { @@ -7297,7 +7292,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -7307,7 +7302,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { @@ -7315,7 +7310,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { @@ -7323,9 +7318,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } }, "is-extglob": { @@ -7338,7 +7333,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", "requires": { - "is-extglob": "^2.1.1" + "is-extglob": "2.1.1" } }, "is-number": { @@ -7346,7 +7341,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -7354,7 +7349,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -7369,19 +7364,19 @@ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "braces": "2.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "extglob": "2.0.4", + "fragment-cache": "0.2.1", + "kind-of": "6.0.2", + "nanomatch": "1.2.13", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" } }, "ms": { @@ -7396,9 +7391,9 @@ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "assert-plus": "1.0.0", + "jsprim": "1.4.1", + "sshpk": "1.16.0" } }, "https-browserify": { @@ -7411,7 +7406,7 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": "2.1.2" } }, "icss-replace-symbols": { @@ -7424,7 +7419,7 @@ "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-2.1.0.tgz", "integrity": "sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI=", "requires": { - "postcss": "^6.0.1" + "postcss": "6.0.23" } }, "identity-obj-proxy": { @@ -7432,7 +7427,7 @@ "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", "integrity": "sha1-lNK9qWCERT7zb7xarsN+D3nx/BQ=", "requires": { - "harmony-reflect": "^1.4.6" + "harmony-reflect": "1.6.1" } }, "ieee754": { @@ -7465,7 +7460,7 @@ "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", "requires": { - "import-from": "^2.1.0" + "import-from": "2.1.0" } }, "import-fresh": { @@ -7473,8 +7468,8 @@ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", "requires": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" + "caller-path": "2.0.0", + "resolve-from": "3.0.0" } }, "import-from": { @@ -7482,7 +7477,7 @@ "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", "requires": { - "resolve-from": "^3.0.0" + "resolve-from": "3.0.0" } }, "import-local": { @@ -7490,8 +7485,8 @@ "resolved": "https://registry.npmjs.org/import-local/-/import-local-1.0.0.tgz", "integrity": "sha512-vAaZHieK9qjGo58agRBg+bhHX3hoTZU/Oa3GESWLz7t1U62fk63aHuDJJEteXoDeTCcPmUT+z38gkHPZkkmpmQ==", "requires": { - "pkg-dir": "^2.0.0", - "resolve-cwd": "^2.0.0" + "pkg-dir": "2.0.0", + "resolve-cwd": "2.0.0" } }, "imurmurhash": { @@ -7517,7 +7512,7 @@ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", "requires": { - "repeating": "^2.0.0" + "repeating": "2.0.1" } }, "indexes-of": { @@ -7535,8 +7530,8 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "requires": { - "once": "^1.3.0", - "wrappy": "1" + "once": "1.4.0", + "wrappy": "1.0.2" } }, "inherits": { @@ -7554,19 +7549,19 @@ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.1.tgz", "integrity": "sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg==", "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.0", - "figures": "^2.0.0", - "lodash": "^4.17.10", + "ansi-escapes": "3.1.0", + "chalk": "2.4.1", + "cli-cursor": "2.1.0", + "cli-width": "2.2.0", + "external-editor": "3.0.3", + "figures": "2.0.0", + "lodash": "4.17.11", "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.1.0", - "string-width": "^2.1.0", - "strip-ansi": "^5.0.0", - "through": "^2.3.6" + "run-async": "2.3.0", + "rxjs": "6.3.3", + "string-width": "2.1.1", + "strip-ansi": "5.0.0", + "through": "2.3.8" }, "dependencies": { "ansi-regex": { @@ -7579,7 +7574,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz", "integrity": "sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow==", "requires": { - "ansi-regex": "^4.0.0" + "ansi-regex": "4.0.0" } } } @@ -7589,8 +7584,8 @@ "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-3.0.1.tgz", "integrity": "sha512-NXXgESC2nNVtU+pqmC9e6R8B1GpKxzsAQhffvh5AL79qKnodd+L7tnEQmTiUAVngqLalPbSqRA7XGIEL5nCd0Q==", "requires": { - "default-gateway": "^2.6.0", - "ipaddr.js": "^1.5.2" + "default-gateway": "2.7.2", + "ipaddr.js": "1.8.0" } }, "invariant": { @@ -7598,7 +7593,7 @@ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", "requires": { - "loose-envify": "^1.0.0" + "loose-envify": "1.4.0" } }, "invert-kv": { @@ -7631,7 +7626,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" } }, "is-arrayish": { @@ -7644,7 +7639,7 @@ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", "requires": { - "binary-extensions": "^1.0.0" + "binary-extensions": "1.12.0" } }, "is-buffer": { @@ -7657,7 +7652,7 @@ "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "requires": { - "builtin-modules": "^1.0.0" + "builtin-modules": "1.1.1" } }, "is-callable": { @@ -7670,7 +7665,7 @@ "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", "requires": { - "ci-info": "^1.5.0" + "ci-info": "1.6.0" } }, "is-color-stop": { @@ -7678,12 +7673,12 @@ "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", "requires": { - "css-color-names": "^0.0.4", - "hex-color-regex": "^1.1.0", - "hsl-regex": "^1.0.0", - "hsla-regex": "^1.0.0", - "rgb-regex": "^1.0.1", - "rgba-regex": "^1.0.0" + "css-color-names": "0.0.4", + "hex-color-regex": "1.1.0", + "hsl-regex": "1.0.0", + "hsla-regex": "1.0.0", + "rgb-regex": "1.0.1", + "rgba-regex": "1.0.0" } }, "is-data-descriptor": { @@ -7691,7 +7686,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" } }, "is-date-object": { @@ -7704,9 +7699,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" }, "dependencies": { "kind-of": { @@ -7731,7 +7726,7 @@ "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", "requires": { - "is-primitive": "^2.0.0" + "is-primitive": "2.0.0" } }, "is-extendable": { @@ -7749,7 +7744,7 @@ "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", "requires": { - "number-is-nan": "^1.0.0" + "number-is-nan": "1.0.1" } }, "is-fullwidth-code-point": { @@ -7767,7 +7762,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "requires": { - "is-extglob": "^1.0.0" + "is-extglob": "1.0.0" } }, "is-number": { @@ -7775,7 +7770,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" } }, "is-obj": { @@ -7793,7 +7788,7 @@ "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", "requires": { - "is-path-inside": "^1.0.0" + "is-path-inside": "1.0.1" } }, "is-path-inside": { @@ -7801,7 +7796,7 @@ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", "requires": { - "path-is-inside": "^1.0.1" + "path-is-inside": "1.0.2" } }, "is-plain-object": { @@ -7809,7 +7804,7 @@ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "requires": { - "isobject": "^3.0.1" + "isobject": "3.0.1" } }, "is-posix-bracket": { @@ -7832,7 +7827,7 @@ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", "requires": { - "has": "^1.0.1" + "has": "1.0.3" } }, "is-regexp": { @@ -7860,7 +7855,7 @@ "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz", "integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==", "requires": { - "html-comment-regex": "^1.1.0" + "html-comment-regex": "1.1.2" } }, "is-symbol": { @@ -7868,7 +7863,7 @@ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", "requires": { - "has-symbols": "^1.0.0" + "has-symbols": "1.0.0" } }, "is-typedarray": { @@ -7901,7 +7896,7 @@ "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz", "integrity": "sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==", "requires": { - "punycode": "2.x.x" + "punycode": "2.1.1" } }, "isexe": { @@ -7924,17 +7919,17 @@ "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.3.7.tgz", "integrity": "sha512-4/ApBnMVeEPG3EkSzcw25wDe4N66wxwn+KKn6b47vyek8Xb3NBAcg4xfuQbS7BqcZuTX4wxfD5lVagdggR3gyA==", "requires": { - "async": "^2.1.4", - "fileset": "^2.0.2", - "istanbul-lib-coverage": "^1.2.1", - "istanbul-lib-hook": "^1.2.2", - "istanbul-lib-instrument": "^1.10.2", - "istanbul-lib-report": "^1.1.5", - "istanbul-lib-source-maps": "^1.2.6", - "istanbul-reports": "^1.5.1", - "js-yaml": "^3.7.0", - "mkdirp": "^0.5.1", - "once": "^1.4.0" + "async": "2.6.1", + "fileset": "2.0.3", + "istanbul-lib-coverage": "1.2.1", + "istanbul-lib-hook": "1.2.2", + "istanbul-lib-instrument": "1.10.2", + "istanbul-lib-report": "1.1.5", + "istanbul-lib-source-maps": "1.2.6", + "istanbul-reports": "1.5.1", + "js-yaml": "3.12.1", + "mkdirp": "0.5.1", + "once": "1.4.0" } }, "istanbul-lib-coverage": { @@ -7947,7 +7942,7 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.2.2.tgz", "integrity": "sha512-/Jmq7Y1VeHnZEQ3TL10VHyb564mn6VrQXHchON9Jf/AEcmQ3ZIiyD1BVzNOKTZf/G3gE+kiGK6SmpF9y3qGPLw==", "requires": { - "append-transform": "^0.4.0" + "append-transform": "0.4.0" } }, "istanbul-lib-instrument": { @@ -7955,13 +7950,13 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.2.tgz", "integrity": "sha512-aWHxfxDqvh/ZlxR8BBaEPVSWDPUkGD63VjGQn3jcw8jCp7sHEMKcrj4xfJn/ABzdMEHiQNyvDQhqm5o8+SQg7A==", "requires": { - "babel-generator": "^6.18.0", - "babel-template": "^6.16.0", - "babel-traverse": "^6.18.0", - "babel-types": "^6.18.0", - "babylon": "^6.18.0", - "istanbul-lib-coverage": "^1.2.1", - "semver": "^5.3.0" + "babel-generator": "6.26.1", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "istanbul-lib-coverage": "1.2.1", + "semver": "5.6.0" } }, "istanbul-lib-report": { @@ -7969,10 +7964,10 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.5.tgz", "integrity": "sha512-UsYfRMoi6QO/doUshYNqcKJqVmFe9w51GZz8BS3WB0lYxAllQYklka2wP9+dGZeHYaWIdcXUx8JGdbqaoXRXzw==", "requires": { - "istanbul-lib-coverage": "^1.2.1", - "mkdirp": "^0.5.1", - "path-parse": "^1.0.5", - "supports-color": "^3.1.2" + "istanbul-lib-coverage": "1.2.1", + "mkdirp": "0.5.1", + "path-parse": "1.0.6", + "supports-color": "3.2.3" }, "dependencies": { "has-flag": { @@ -7985,7 +7980,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", "requires": { - "has-flag": "^1.0.0" + "has-flag": "1.0.0" } } } @@ -7995,11 +7990,11 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.6.tgz", "integrity": "sha512-TtbsY5GIHgbMsMiRw35YBHGpZ1DVFEO19vxxeiDMYaeOFOCzfnYVxvl6pOUIZR4dtPhAGpSMup8OyF8ubsaqEg==", "requires": { - "debug": "^3.1.0", - "istanbul-lib-coverage": "^1.2.1", - "mkdirp": "^0.5.1", - "rimraf": "^2.6.1", - "source-map": "^0.5.3" + "debug": "3.2.6", + "istanbul-lib-coverage": "1.2.1", + "mkdirp": "0.5.1", + "rimraf": "2.6.3", + "source-map": "0.5.7" }, "dependencies": { "debug": { @@ -8007,7 +8002,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "requires": { - "ms": "^2.1.1" + "ms": "2.1.1" } } } @@ -8017,7 +8012,7 @@ "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.5.1.tgz", "integrity": "sha512-+cfoZ0UXzWjhAdzosCPP3AN8vvef8XDkWtTfgaN+7L3YTpNYITnCaEkceo5SEYy644VkHka/P1FvkWvrG/rrJw==", "requires": { - "handlebars": "^4.0.3" + "handlebars": "4.0.12" } }, "jest": { @@ -8025,8 +8020,8 @@ "resolved": "https://registry.npmjs.org/jest/-/jest-23.6.0.tgz", "integrity": "sha512-lWzcd+HSiqeuxyhG+EnZds6iO3Y3ZEnMrfZq/OTGvF/C+Z4fPMCdhWTGSAiO2Oym9rbEXfwddHhh6jqrTF3+Lw==", "requires": { - "import-local": "^1.0.0", - "jest-cli": "^23.6.0" + "import-local": "1.0.0", + "jest-cli": "23.6.0" }, "dependencies": { "ansi-regex": { @@ -8039,42 +8034,42 @@ "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-23.6.0.tgz", "integrity": "sha512-hgeD1zRUp1E1zsiyOXjEn4LzRLWdJBV//ukAHGlx6s5mfCNJTbhbHjgxnDUXA8fsKWN/HqFFF6X5XcCwC/IvYQ==", "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.1.11", - "import-local": "^1.0.0", - "is-ci": "^1.0.10", - "istanbul-api": "^1.3.1", - "istanbul-lib-coverage": "^1.2.0", - "istanbul-lib-instrument": "^1.10.1", - "istanbul-lib-source-maps": "^1.2.4", - "jest-changed-files": "^23.4.2", - "jest-config": "^23.6.0", - "jest-environment-jsdom": "^23.4.0", - "jest-get-type": "^22.1.0", - "jest-haste-map": "^23.6.0", - "jest-message-util": "^23.4.0", - "jest-regex-util": "^23.3.0", - "jest-resolve-dependencies": "^23.6.0", - "jest-runner": "^23.6.0", - "jest-runtime": "^23.6.0", - "jest-snapshot": "^23.6.0", - "jest-util": "^23.4.0", - "jest-validate": "^23.6.0", - "jest-watcher": "^23.4.0", - "jest-worker": "^23.2.0", - "micromatch": "^2.3.11", - "node-notifier": "^5.2.1", - "prompts": "^0.1.9", - "realpath-native": "^1.0.0", - "rimraf": "^2.5.4", - "slash": "^1.0.0", - "string-length": "^2.0.0", - "strip-ansi": "^4.0.0", - "which": "^1.2.12", - "yargs": "^11.0.0" + "ansi-escapes": "3.1.0", + "chalk": "2.4.1", + "exit": "0.1.2", + "glob": "7.1.3", + "graceful-fs": "4.1.15", + "import-local": "1.0.0", + "is-ci": "1.2.1", + "istanbul-api": "1.3.7", + "istanbul-lib-coverage": "1.2.1", + "istanbul-lib-instrument": "1.10.2", + "istanbul-lib-source-maps": "1.2.6", + "jest-changed-files": "23.4.2", + "jest-config": "23.6.0", + "jest-environment-jsdom": "23.4.0", + "jest-get-type": "22.4.3", + "jest-haste-map": "23.6.0", + "jest-message-util": "23.4.0", + "jest-regex-util": "23.3.0", + "jest-resolve-dependencies": "23.6.0", + "jest-runner": "23.6.0", + "jest-runtime": "23.6.0", + "jest-snapshot": "23.6.0", + "jest-util": "23.4.0", + "jest-validate": "23.6.0", + "jest-watcher": "23.4.0", + "jest-worker": "23.2.0", + "micromatch": "2.3.11", + "node-notifier": "5.3.0", + "prompts": "0.1.14", + "realpath-native": "1.0.2", + "rimraf": "2.6.3", + "slash": "1.0.0", + "string-length": "2.0.0", + "strip-ansi": "4.0.0", + "which": "1.3.1", + "yargs": "11.1.0" } }, "strip-ansi": { @@ -8082,7 +8077,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "3.0.0" } } } @@ -8092,7 +8087,7 @@ "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-23.4.2.tgz", "integrity": "sha512-EyNhTAUWEfwnK0Is/09LxoqNDOn7mU7S3EHskG52djOFS/z+IT0jT3h3Ql61+dklcG7bJJitIWEMB4Sp1piHmA==", "requires": { - "throat": "^4.0.0" + "throat": "4.1.0" } }, "jest-config": { @@ -8100,20 +8095,20 @@ "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-23.6.0.tgz", "integrity": "sha512-i8V7z9BeDXab1+VNo78WM0AtWpBRXJLnkT+lyT+Slx/cbP5sZJ0+NDuLcmBE5hXAoK0aUp7vI+MOxR+R4d8SRQ==", "requires": { - "babel-core": "^6.0.0", - "babel-jest": "^23.6.0", - "chalk": "^2.0.1", - "glob": "^7.1.1", - "jest-environment-jsdom": "^23.4.0", - "jest-environment-node": "^23.4.0", - "jest-get-type": "^22.1.0", - "jest-jasmine2": "^23.6.0", - "jest-regex-util": "^23.3.0", - "jest-resolve": "^23.6.0", - "jest-util": "^23.4.0", - "jest-validate": "^23.6.0", - "micromatch": "^2.3.11", - "pretty-format": "^23.6.0" + "babel-core": "6.26.3", + "babel-jest": "23.6.0", + "chalk": "2.4.1", + "glob": "7.1.3", + "jest-environment-jsdom": "23.4.0", + "jest-environment-node": "23.4.0", + "jest-get-type": "22.4.3", + "jest-jasmine2": "23.6.0", + "jest-regex-util": "23.3.0", + "jest-resolve": "23.6.0", + "jest-util": "23.4.0", + "jest-validate": "23.6.0", + "micromatch": "2.3.11", + "pretty-format": "23.6.0" }, "dependencies": { "babel-core": { @@ -8121,25 +8116,25 @@ "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", "requires": { - "babel-code-frame": "^6.26.0", - "babel-generator": "^6.26.0", - "babel-helpers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "convert-source-map": "^1.5.1", - "debug": "^2.6.9", - "json5": "^0.5.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.4", - "path-is-absolute": "^1.0.1", - "private": "^0.1.8", - "slash": "^1.0.0", - "source-map": "^0.5.7" + "babel-code-frame": "6.26.0", + "babel-generator": "6.26.1", + "babel-helpers": "6.24.1", + "babel-messages": "6.23.0", + "babel-register": "6.26.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "convert-source-map": "1.6.0", + "debug": "2.6.9", + "json5": "0.5.1", + "lodash": "4.17.11", + "minimatch": "3.0.4", + "path-is-absolute": "1.0.1", + "private": "0.1.8", + "slash": "1.0.0", + "source-map": "0.5.7" } }, "debug": { @@ -8167,10 +8162,10 @@ "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-23.6.0.tgz", "integrity": "sha512-Gz9l5Ov+X3aL5L37IT+8hoCUsof1CVYBb2QEkOupK64XyRR3h+uRpYIm97K7sY8diFxowR8pIGEdyfMKTixo3g==", "requires": { - "chalk": "^2.0.1", - "diff": "^3.2.0", - "jest-get-type": "^22.1.0", - "pretty-format": "^23.6.0" + "chalk": "2.4.1", + "diff": "3.5.0", + "jest-get-type": "22.4.3", + "pretty-format": "23.6.0" } }, "jest-docblock": { @@ -8178,7 +8173,7 @@ "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-23.2.0.tgz", "integrity": "sha1-8IXh8YVI2Z/dabICB+b9VdkTg6c=", "requires": { - "detect-newline": "^2.1.0" + "detect-newline": "2.1.0" } }, "jest-each": { @@ -8186,8 +8181,8 @@ "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-23.6.0.tgz", "integrity": "sha512-x7V6M/WGJo6/kLoissORuvLIeAoyo2YqLOoCDkohgJ4XOXSqOtyvr8FbInlAWS77ojBsZrafbozWoKVRdtxFCg==", "requires": { - "chalk": "^2.0.1", - "pretty-format": "^23.6.0" + "chalk": "2.4.1", + "pretty-format": "23.6.0" } }, "jest-environment-jsdom": { @@ -8195,9 +8190,9 @@ "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-23.4.0.tgz", "integrity": "sha1-BWp5UrP+pROsYqFAosNox52eYCM=", "requires": { - "jest-mock": "^23.2.0", - "jest-util": "^23.4.0", - "jsdom": "^11.5.1" + "jest-mock": "23.2.0", + "jest-util": "23.4.0", + "jsdom": "11.12.0" }, "dependencies": { "acorn": { @@ -8210,32 +8205,32 @@ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", "requires": { - "abab": "^2.0.0", - "acorn": "^5.5.3", - "acorn-globals": "^4.1.0", - "array-equal": "^1.0.0", - "cssom": ">= 0.3.2 < 0.4.0", - "cssstyle": "^1.0.0", - "data-urls": "^1.0.0", - "domexception": "^1.0.1", - "escodegen": "^1.9.1", - "html-encoding-sniffer": "^1.0.2", - "left-pad": "^1.3.0", - "nwsapi": "^2.0.7", + "abab": "2.0.0", + "acorn": "5.7.3", + "acorn-globals": "4.3.0", + "array-equal": "1.0.0", + "cssom": "0.3.4", + "cssstyle": "1.1.1", + "data-urls": "1.1.0", + "domexception": "1.0.1", + "escodegen": "1.11.0", + "html-encoding-sniffer": "1.0.2", + "left-pad": "1.3.0", + "nwsapi": "2.0.9", "parse5": "4.0.0", - "pn": "^1.1.0", - "request": "^2.87.0", - "request-promise-native": "^1.0.5", - "sax": "^1.2.4", - "symbol-tree": "^3.2.2", - "tough-cookie": "^2.3.4", - "w3c-hr-time": "^1.0.1", - "webidl-conversions": "^4.0.2", - "whatwg-encoding": "^1.0.3", - "whatwg-mimetype": "^2.1.0", - "whatwg-url": "^6.4.1", - "ws": "^5.2.0", - "xml-name-validator": "^3.0.0" + "pn": "1.1.0", + "request": "2.88.0", + "request-promise-native": "1.0.5", + "sax": "1.2.4", + "symbol-tree": "3.2.2", + "tough-cookie": "2.5.0", + "w3c-hr-time": "1.0.1", + "webidl-conversions": "4.0.2", + "whatwg-encoding": "1.0.5", + "whatwg-mimetype": "2.3.0", + "whatwg-url": "6.5.0", + "ws": "5.2.2", + "xml-name-validator": "3.0.0" } }, "parse5": { @@ -8248,9 +8243,9 @@ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" + "lodash.sortby": "4.7.0", + "tr46": "1.0.1", + "webidl-conversions": "4.0.2" } }, "ws": { @@ -8258,7 +8253,7 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", "requires": { - "async-limiter": "~1.0.0" + "async-limiter": "1.0.0" } } } @@ -8268,8 +8263,8 @@ "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-23.4.0.tgz", "integrity": "sha1-V+gO0IQd6jAxZ8zozXlSHeuv3hA=", "requires": { - "jest-mock": "^23.2.0", - "jest-util": "^23.4.0" + "jest-mock": "23.2.0", + "jest-util": "23.4.0" } }, "jest-get-type": { @@ -8282,14 +8277,14 @@ "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-23.6.0.tgz", "integrity": "sha512-uyNhMyl6dr6HaXGHp8VF7cK6KpC6G9z9LiMNsst+rJIZ8l7wY0tk8qwjPmEghczojZ2/ZhtEdIabZ0OQRJSGGg==", "requires": { - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.1.11", - "invariant": "^2.2.4", - "jest-docblock": "^23.2.0", - "jest-serializer": "^23.0.1", - "jest-worker": "^23.2.0", - "micromatch": "^2.3.11", - "sane": "^2.0.0" + "fb-watchman": "2.0.0", + "graceful-fs": "4.1.15", + "invariant": "2.2.4", + "jest-docblock": "23.2.0", + "jest-serializer": "23.0.1", + "jest-worker": "23.2.0", + "micromatch": "2.3.11", + "sane": "2.5.2" } }, "jest-jasmine2": { @@ -8297,18 +8292,18 @@ "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-23.6.0.tgz", "integrity": "sha512-pe2Ytgs1nyCs8IvsEJRiRTPC0eVYd8L/dXJGU08GFuBwZ4sYH/lmFDdOL3ZmvJR8QKqV9MFuwlsAi/EWkFUbsQ==", "requires": { - "babel-traverse": "^6.0.0", - "chalk": "^2.0.1", - "co": "^4.6.0", - "expect": "^23.6.0", - "is-generator-fn": "^1.0.0", - "jest-diff": "^23.6.0", - "jest-each": "^23.6.0", - "jest-matcher-utils": "^23.6.0", - "jest-message-util": "^23.4.0", - "jest-snapshot": "^23.6.0", - "jest-util": "^23.4.0", - "pretty-format": "^23.6.0" + "babel-traverse": "6.26.0", + "chalk": "2.4.1", + "co": "4.6.0", + "expect": "23.6.0", + "is-generator-fn": "1.0.0", + "jest-diff": "23.6.0", + "jest-each": "23.6.0", + "jest-matcher-utils": "23.6.0", + "jest-message-util": "23.4.0", + "jest-snapshot": "23.6.0", + "jest-util": "23.4.0", + "pretty-format": "23.6.0" } }, "jest-leak-detector": { @@ -8316,7 +8311,7 @@ "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-23.6.0.tgz", "integrity": "sha512-f/8zA04rsl1Nzj10HIyEsXvYlMpMPcy0QkQilVZDFOaPbv2ur71X5u2+C4ZQJGyV/xvVXtCCZ3wQ99IgQxftCg==", "requires": { - "pretty-format": "^23.6.0" + "pretty-format": "23.6.0" } }, "jest-matcher-utils": { @@ -8324,9 +8319,9 @@ "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-23.6.0.tgz", "integrity": "sha512-rosyCHQfBcol4NsckTn01cdelzWLU9Cq7aaigDf8VwwpIRvWE/9zLgX2bON+FkEW69/0UuYslUe22SOdEf2nog==", "requires": { - "chalk": "^2.0.1", - "jest-get-type": "^22.1.0", - "pretty-format": "^23.6.0" + "chalk": "2.4.1", + "jest-get-type": "22.4.3", + "pretty-format": "23.6.0" } }, "jest-message-util": { @@ -8334,11 +8329,11 @@ "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-23.4.0.tgz", "integrity": "sha1-F2EMUJQjSVCNAaPR4L2iwHkIap8=", "requires": { - "@babel/code-frame": "^7.0.0-beta.35", - "chalk": "^2.0.1", - "micromatch": "^2.3.11", - "slash": "^1.0.0", - "stack-utils": "^1.0.1" + "@babel/code-frame": "7.0.0", + "chalk": "2.4.1", + "micromatch": "2.3.11", + "slash": "1.0.0", + "stack-utils": "1.0.2" } }, "jest-mock": { @@ -8361,9 +8356,9 @@ "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-23.6.0.tgz", "integrity": "sha512-XyoRxNtO7YGpQDmtQCmZjum1MljDqUCob7XlZ6jy9gsMugHdN2hY4+Acz9Qvjz2mSsOnPSH7skBmDYCHXVZqkA==", "requires": { - "browser-resolve": "^1.11.3", - "chalk": "^2.0.1", - "realpath-native": "^1.0.0" + "browser-resolve": "1.11.3", + "chalk": "2.4.1", + "realpath-native": "1.0.2" } }, "jest-resolve-dependencies": { @@ -8371,8 +8366,8 @@ "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-23.6.0.tgz", "integrity": "sha512-EkQWkFWjGKwRtRyIwRwI6rtPAEyPWlUC2MpzHissYnzJeHcyCn1Hc8j7Nn1xUVrS5C6W5+ZL37XTem4D4pLZdA==", "requires": { - "jest-regex-util": "^23.3.0", - "jest-snapshot": "^23.6.0" + "jest-regex-util": "23.3.0", + "jest-snapshot": "23.6.0" } }, "jest-runner": { @@ -8380,19 +8375,19 @@ "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-23.6.0.tgz", "integrity": "sha512-kw0+uj710dzSJKU6ygri851CObtCD9cN8aNkg8jWJf4ewFyEa6kwmiH/r/M1Ec5IL/6VFa0wnAk6w+gzUtjJzA==", "requires": { - "exit": "^0.1.2", - "graceful-fs": "^4.1.11", - "jest-config": "^23.6.0", - "jest-docblock": "^23.2.0", - "jest-haste-map": "^23.6.0", - "jest-jasmine2": "^23.6.0", - "jest-leak-detector": "^23.6.0", - "jest-message-util": "^23.4.0", - "jest-runtime": "^23.6.0", - "jest-util": "^23.4.0", - "jest-worker": "^23.2.0", - "source-map-support": "^0.5.6", - "throat": "^4.0.0" + "exit": "0.1.2", + "graceful-fs": "4.1.15", + "jest-config": "23.6.0", + "jest-docblock": "23.2.0", + "jest-haste-map": "23.6.0", + "jest-jasmine2": "23.6.0", + "jest-leak-detector": "23.6.0", + "jest-message-util": "23.4.0", + "jest-runtime": "23.6.0", + "jest-util": "23.4.0", + "jest-worker": "23.2.0", + "source-map-support": "0.5.9", + "throat": "4.1.0" }, "dependencies": { "source-map": { @@ -8405,8 +8400,8 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz", "integrity": "sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==", "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "buffer-from": "1.1.1", + "source-map": "0.6.1" } } } @@ -8416,27 +8411,27 @@ "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-23.6.0.tgz", "integrity": "sha512-ycnLTNPT2Gv+TRhnAYAQ0B3SryEXhhRj1kA6hBPSeZaNQkJ7GbZsxOLUkwg6YmvWGdX3BB3PYKFLDQCAE1zNOw==", "requires": { - "babel-core": "^6.0.0", - "babel-plugin-istanbul": "^4.1.6", - "chalk": "^2.0.1", - "convert-source-map": "^1.4.0", - "exit": "^0.1.2", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.1.11", - "jest-config": "^23.6.0", - "jest-haste-map": "^23.6.0", - "jest-message-util": "^23.4.0", - "jest-regex-util": "^23.3.0", - "jest-resolve": "^23.6.0", - "jest-snapshot": "^23.6.0", - "jest-util": "^23.4.0", - "jest-validate": "^23.6.0", - "micromatch": "^2.3.11", - "realpath-native": "^1.0.0", - "slash": "^1.0.0", + "babel-core": "6.26.3", + "babel-plugin-istanbul": "4.1.6", + "chalk": "2.4.1", + "convert-source-map": "1.6.0", + "exit": "0.1.2", + "fast-json-stable-stringify": "2.0.0", + "graceful-fs": "4.1.15", + "jest-config": "23.6.0", + "jest-haste-map": "23.6.0", + "jest-message-util": "23.4.0", + "jest-regex-util": "23.3.0", + "jest-resolve": "23.6.0", + "jest-snapshot": "23.6.0", + "jest-util": "23.4.0", + "jest-validate": "23.6.0", + "micromatch": "2.3.11", + "realpath-native": "1.0.2", + "slash": "1.0.0", "strip-bom": "3.0.0", - "write-file-atomic": "^2.1.0", - "yargs": "^11.0.0" + "write-file-atomic": "2.3.0", + "yargs": "11.1.0" }, "dependencies": { "babel-core": { @@ -8444,25 +8439,25 @@ "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", "requires": { - "babel-code-frame": "^6.26.0", - "babel-generator": "^6.26.0", - "babel-helpers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "convert-source-map": "^1.5.1", - "debug": "^2.6.9", - "json5": "^0.5.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.4", - "path-is-absolute": "^1.0.1", - "private": "^0.1.8", - "slash": "^1.0.0", - "source-map": "^0.5.7" + "babel-code-frame": "6.26.0", + "babel-generator": "6.26.1", + "babel-helpers": "6.24.1", + "babel-messages": "6.23.0", + "babel-register": "6.26.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "convert-source-map": "1.6.0", + "debug": "2.6.9", + "json5": "0.5.1", + "lodash": "4.17.11", + "minimatch": "3.0.4", + "path-is-absolute": "1.0.1", + "private": "0.1.8", + "slash": "1.0.0", + "source-map": "0.5.7" } }, "debug": { @@ -8500,16 +8495,16 @@ "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-23.6.0.tgz", "integrity": "sha512-tM7/Bprftun6Cvj2Awh/ikS7zV3pVwjRYU2qNYS51VZHgaAMBs5l4o/69AiDHhQrj5+LA2Lq4VIvK7zYk/bswg==", "requires": { - "babel-types": "^6.0.0", - "chalk": "^2.0.1", - "jest-diff": "^23.6.0", - "jest-matcher-utils": "^23.6.0", - "jest-message-util": "^23.4.0", - "jest-resolve": "^23.6.0", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "pretty-format": "^23.6.0", - "semver": "^5.5.0" + "babel-types": "6.26.0", + "chalk": "2.4.1", + "jest-diff": "23.6.0", + "jest-matcher-utils": "23.6.0", + "jest-message-util": "23.4.0", + "jest-resolve": "23.6.0", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "pretty-format": "23.6.0", + "semver": "5.6.0" } }, "jest-util": { @@ -8517,14 +8512,14 @@ "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-23.4.0.tgz", "integrity": "sha1-TQY8uSe68KI4Mf9hvsLLv0l5NWE=", "requires": { - "callsites": "^2.0.0", - "chalk": "^2.0.1", - "graceful-fs": "^4.1.11", - "is-ci": "^1.0.10", - "jest-message-util": "^23.4.0", - "mkdirp": "^0.5.1", - "slash": "^1.0.0", - "source-map": "^0.6.0" + "callsites": "2.0.0", + "chalk": "2.4.1", + "graceful-fs": "4.1.15", + "is-ci": "1.2.1", + "jest-message-util": "23.4.0", + "mkdirp": "0.5.1", + "slash": "1.0.0", + "source-map": "0.6.1" }, "dependencies": { "source-map": { @@ -8539,10 +8534,10 @@ "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-23.6.0.tgz", "integrity": "sha512-OFKapYxe72yz7agrDAWi8v2WL8GIfVqcbKRCLbRG9PAxtzF9b1SEDdTpytNDN12z2fJynoBwpMpvj2R39plI2A==", "requires": { - "chalk": "^2.0.1", - "jest-get-type": "^22.1.0", - "leven": "^2.1.0", - "pretty-format": "^23.6.0" + "chalk": "2.4.1", + "jest-get-type": "22.4.3", + "leven": "2.1.0", + "pretty-format": "23.6.0" } }, "jest-watcher": { @@ -8550,9 +8545,9 @@ "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-23.4.0.tgz", "integrity": "sha1-0uKM50+NrWxq/JIrksq+9u0FyRw=", "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.1", - "string-length": "^2.0.0" + "ansi-escapes": "3.1.0", + "chalk": "2.4.1", + "string-length": "2.0.0" } }, "jest-worker": { @@ -8560,7 +8555,7 @@ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-23.2.0.tgz", "integrity": "sha1-+vcGqNo2+uYOsmlXJX+ntdjqArk=", "requires": { - "merge-stream": "^1.0.1" + "merge-stream": "1.0.1" } }, "joi": { @@ -8568,9 +8563,9 @@ "resolved": "https://registry.npmjs.org/joi/-/joi-11.4.0.tgz", "integrity": "sha512-O7Uw+w/zEWgbL6OcHbyACKSj0PkQeUgmehdoXVSxt92QFCq4+1390Rwh5moI2K/OgC7D8RHRZqHZxT2husMJHA==", "requires": { - "hoek": "4.x.x", - "isemail": "3.x.x", - "topo": "2.x.x" + "hoek": "4.2.1", + "isemail": "3.2.0", + "topo": "2.0.2" } }, "js-base64": { @@ -8593,8 +8588,8 @@ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz", "integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==", "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "1.0.10", + "esprima": "4.0.1" } }, "jsbn": { @@ -8607,32 +8602,32 @@ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-13.1.0.tgz", "integrity": "sha512-C2Kp0qNuopw0smXFaHeayvharqF3kkcNqlcIlSX71+3XrsOFwkEPLt/9f5JksMmaul2JZYIQuY+WTpqHpQQcLg==", "requires": { - "abab": "^2.0.0", - "acorn": "^6.0.4", - "acorn-globals": "^4.3.0", - "array-equal": "^1.0.0", - "cssom": "^0.3.4", - "cssstyle": "^1.1.1", - "data-urls": "^1.1.0", - "domexception": "^1.0.1", - "escodegen": "^1.11.0", - "html-encoding-sniffer": "^1.0.2", - "nwsapi": "^2.0.9", + "abab": "2.0.0", + "acorn": "6.0.5", + "acorn-globals": "4.3.0", + "array-equal": "1.0.0", + "cssom": "0.3.4", + "cssstyle": "1.1.1", + "data-urls": "1.1.0", + "domexception": "1.0.1", + "escodegen": "1.11.0", + "html-encoding-sniffer": "1.0.2", + "nwsapi": "2.0.9", "parse5": "5.1.0", - "pn": "^1.1.0", - "request": "^2.88.0", - "request-promise-native": "^1.0.5", - "saxes": "^3.1.4", - "symbol-tree": "^3.2.2", - "tough-cookie": "^2.5.0", - "w3c-hr-time": "^1.0.1", - "w3c-xmlserializer": "^1.0.1", - "webidl-conversions": "^4.0.2", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^7.0.0", - "ws": "^6.1.2", - "xml-name-validator": "^3.0.0" + "pn": "1.1.0", + "request": "2.88.0", + "request-promise-native": "1.0.5", + "saxes": "3.1.5", + "symbol-tree": "3.2.2", + "tough-cookie": "2.5.0", + "w3c-hr-time": "1.0.1", + "w3c-xmlserializer": "1.0.1", + "webidl-conversions": "4.0.2", + "whatwg-encoding": "1.0.5", + "whatwg-mimetype": "2.3.0", + "whatwg-url": "7.0.0", + "ws": "6.1.2", + "xml-name-validator": "3.0.0" } }, "jsesc": { @@ -8660,7 +8655,7 @@ "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", "requires": { - "jsonify": "~0.0.0" + "jsonify": "0.0.0" } }, "json-stable-stringify-without-jsonify": { @@ -8683,7 +8678,7 @@ "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", "requires": { - "minimist": "^1.2.0" + "minimist": "1.2.0" } }, "jsonfile": { @@ -8691,7 +8686,7 @@ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", "requires": { - "graceful-fs": "^4.1.6" + "graceful-fs": "4.1.15" } }, "jsonify": { @@ -8715,7 +8710,7 @@ "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz", "integrity": "sha1-6AGxs5mF4g//yHtA43SAgOLcrH8=", "requires": { - "array-includes": "^3.0.3" + "array-includes": "3.0.3" } }, "killable": { @@ -8728,7 +8723,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } }, "kleur": { @@ -8741,8 +8736,8 @@ "resolved": "https://registry.npmjs.org/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz", "integrity": "sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w==", "requires": { - "lodash": "^4.17.5", - "webpack-sources": "^1.1.0" + "lodash": "4.17.11", + "webpack-sources": "1.3.0" } }, "lazy-cache": { @@ -8755,7 +8750,7 @@ "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", "requires": { - "invert-kv": "^1.0.0" + "invert-kv": "1.0.0" } }, "left-pad": { @@ -8773,8 +8768,8 @@ "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "prelude-ls": "1.1.2", + "type-check": "0.3.2" } }, "load-json-file": { @@ -8782,11 +8777,11 @@ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" + "graceful-fs": "4.1.15", + "parse-json": "2.2.0", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" }, "dependencies": { "parse-json": { @@ -8794,7 +8789,7 @@ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "requires": { - "error-ex": "^1.2.0" + "error-ex": "1.3.2" } } } @@ -8804,7 +8799,7 @@ "resolved": "https://registry.npmjs.org/loader-fs-cache/-/loader-fs-cache-1.0.1.tgz", "integrity": "sha1-VuC/CL2XCLJqdltoUJhAyN7J/bw=", "requires": { - "find-cache-dir": "^0.1.1", + "find-cache-dir": "0.1.1", "mkdirp": "0.5.1" }, "dependencies": { @@ -8813,9 +8808,9 @@ "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz", "integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=", "requires": { - "commondir": "^1.0.1", - "mkdirp": "^0.5.1", - "pkg-dir": "^1.0.0" + "commondir": "1.0.1", + "mkdirp": "0.5.1", + "pkg-dir": "1.0.0" } }, "find-up": { @@ -8823,8 +8818,8 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" } }, "path-exists": { @@ -8832,7 +8827,7 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "requires": { - "pinkie-promise": "^2.0.0" + "pinkie-promise": "2.0.1" } }, "pkg-dir": { @@ -8840,7 +8835,7 @@ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", "requires": { - "find-up": "^1.0.0" + "find-up": "1.1.2" } } } @@ -8855,9 +8850,9 @@ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", "requires": { - "big.js": "^5.2.2", - "emojis-list": "^2.0.0", - "json5": "^1.0.1" + "big.js": "5.2.2", + "emojis-list": "2.1.0", + "json5": "1.0.1" }, "dependencies": { "json5": { @@ -8865,7 +8860,7 @@ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "requires": { - "minimist": "^1.2.0" + "minimist": "1.2.0" } } } @@ -8875,8 +8870,8 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "p-locate": "2.0.0", + "path-exists": "3.0.0" } }, "lodash": { @@ -8934,8 +8929,8 @@ "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz", "integrity": "sha1-5zoDhcg1VZF0bgILmWecaQ5o+6A=", "requires": { - "lodash._reinterpolate": "~3.0.0", - "lodash.templatesettings": "^4.0.0" + "lodash._reinterpolate": "3.0.0", + "lodash.templatesettings": "4.1.0" } }, "lodash.templatesettings": { @@ -8943,7 +8938,7 @@ "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz", "integrity": "sha1-K01OlbpEDZFf8IvImeRVNmZxMxY=", "requires": { - "lodash._reinterpolate": "~3.0.0" + "lodash._reinterpolate": "3.0.0" } }, "lodash.uniq": { @@ -8961,7 +8956,7 @@ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" + "js-tokens": "4.0.0" } }, "loud-rejection": { @@ -8969,8 +8964,8 @@ "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", "requires": { - "currently-unhandled": "^0.4.1", - "signal-exit": "^3.0.0" + "currently-unhandled": "0.4.1", + "signal-exit": "3.0.2" } }, "lower-case": { @@ -8983,8 +8978,8 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" + "pseudomap": "1.0.2", + "yallist": "2.1.2" } }, "make-dir": { @@ -8992,7 +8987,7 @@ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "requires": { - "pify": "^3.0.0" + "pify": "3.0.0" }, "dependencies": { "pify": { @@ -9007,7 +9002,7 @@ "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", "requires": { - "tmpl": "1.0.x" + "tmpl": "1.0.4" } }, "mamacro": { @@ -9020,7 +9015,7 @@ "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", "requires": { - "p-defer": "^1.0.0" + "p-defer": "1.0.0" } }, "map-cache": { @@ -9038,7 +9033,7 @@ "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", "requires": { - "object-visit": "^1.0.0" + "object-visit": "1.0.1" } }, "math-random": { @@ -9051,9 +9046,9 @@ "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" + "hash-base": "3.0.4", + "inherits": "2.0.3", + "safe-buffer": "5.1.2" } }, "mdn-data": { @@ -9071,7 +9066,7 @@ "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", "requires": { - "mimic-fn": "^1.0.0" + "mimic-fn": "1.2.0" } }, "memory-fs": { @@ -9079,8 +9074,8 @@ "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" + "errno": "0.1.7", + "readable-stream": "2.3.6" } }, "meow": { @@ -9088,16 +9083,16 @@ "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", "requires": { - "camelcase-keys": "^2.0.0", - "decamelize": "^1.1.2", - "loud-rejection": "^1.0.0", - "map-obj": "^1.0.1", - "minimist": "^1.1.3", - "normalize-package-data": "^2.3.4", - "object-assign": "^4.0.1", - "read-pkg-up": "^1.0.1", - "redent": "^1.0.0", - "trim-newlines": "^1.0.0" + "camelcase-keys": "2.1.0", + "decamelize": "1.2.0", + "loud-rejection": "1.6.0", + "map-obj": "1.0.1", + "minimist": "1.2.0", + "normalize-package-data": "2.4.0", + "object-assign": "4.1.1", + "read-pkg-up": "1.0.1", + "redent": "1.0.0", + "trim-newlines": "1.0.0" } }, "merge": { @@ -9110,9 +9105,9 @@ "resolved": "https://registry.npmjs.org/merge-deep/-/merge-deep-3.0.2.tgz", "integrity": "sha512-T7qC8kg4Zoti1cFd8Cr0M+qaZfOwjlPDEdZIIPPB2JZctjaPM4fX+i7HOId69tAti2fvO6X5ldfYUONDODsrkA==", "requires": { - "arr-union": "^3.1.0", - "clone-deep": "^0.2.4", - "kind-of": "^3.0.2" + "arr-union": "3.1.0", + "clone-deep": "0.2.4", + "kind-of": "3.2.2" } }, "merge-descriptors": { @@ -9125,7 +9120,7 @@ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz", "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=", "requires": { - "readable-stream": "^2.0.1" + "readable-stream": "2.3.6" } }, "merge2": { @@ -9143,19 +9138,19 @@ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", "requires": { - "arr-diff": "^2.0.0", - "array-unique": "^0.2.1", - "braces": "^1.8.2", - "expand-brackets": "^0.1.4", - "extglob": "^0.3.1", - "filename-regex": "^2.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.1", - "kind-of": "^3.0.2", - "normalize-path": "^2.0.1", - "object.omit": "^2.0.0", - "parse-glob": "^3.0.4", - "regex-cache": "^0.4.2" + "arr-diff": "2.0.0", + "array-unique": "0.2.1", + "braces": "1.8.5", + "expand-brackets": "0.1.5", + "extglob": "0.3.2", + "filename-regex": "2.0.1", + "is-extglob": "1.0.0", + "is-glob": "2.0.1", + "kind-of": "3.2.2", + "normalize-path": "2.1.1", + "object.omit": "2.0.1", + "parse-glob": "3.0.4", + "regex-cache": "0.4.4" } }, "miller-rabin": { @@ -9163,8 +9158,8 @@ "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", "requires": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" + "bn.js": "4.11.8", + "brorand": "1.1.0" } }, "mime": { @@ -9182,7 +9177,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", "requires": { - "mime-db": "~1.37.0" + "mime-db": "1.37.0" } }, "mimic-fn": { @@ -9195,9 +9190,9 @@ "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.4.3.tgz", "integrity": "sha512-Mxs0nxzF1kxPv4TRi2NimewgXlJqh0rGE30vviCU2WHrpbta6wklnUV9dr9FUtoAHmB3p3LeXEC+ZjgHvB0Dzg==", "requires": { - "loader-utils": "^1.1.0", - "schema-utils": "^1.0.0", - "webpack-sources": "^1.1.0" + "loader-utils": "1.2.3", + "schema-utils": "1.0.0", + "webpack-sources": "1.3.0" } }, "minimalistic-assert": { @@ -9215,7 +9210,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "1.1.11" } }, "minimist": { @@ -9228,16 +9223,16 @@ "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", "requires": { - "concat-stream": "^1.5.0", - "duplexify": "^3.4.2", - "end-of-stream": "^1.1.0", - "flush-write-stream": "^1.0.0", - "from2": "^2.1.0", - "parallel-transform": "^1.1.0", - "pump": "^3.0.0", - "pumpify": "^1.3.3", - "stream-each": "^1.1.0", - "through2": "^2.0.0" + "concat-stream": "1.6.2", + "duplexify": "3.6.1", + "end-of-stream": "1.4.1", + "flush-write-stream": "1.0.3", + "from2": "2.3.0", + "parallel-transform": "1.1.0", + "pump": "3.0.0", + "pumpify": "1.5.1", + "stream-each": "1.2.3", + "through2": "2.0.5" } }, "mixin-deep": { @@ -9245,8 +9240,8 @@ "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" + "for-in": "1.0.2", + "is-extendable": "1.0.1" }, "dependencies": { "is-extendable": { @@ -9254,7 +9249,7 @@ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -9264,8 +9259,8 @@ "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", "integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=", "requires": { - "for-in": "^0.1.3", - "is-extendable": "^0.1.1" + "for-in": "0.1.8", + "is-extendable": "0.1.1" }, "dependencies": { "for-in": { @@ -9295,12 +9290,12 @@ "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", "requires": { - "aproba": "^1.1.1", - "copy-concurrently": "^1.0.0", - "fs-write-stream-atomic": "^1.0.8", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.3" + "aproba": "1.2.0", + "copy-concurrently": "1.0.5", + "fs-write-stream-atomic": "1.0.10", + "mkdirp": "0.5.1", + "rimraf": "2.6.3", + "run-queue": "1.0.3" } }, "ms": { @@ -9313,8 +9308,8 @@ "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", "requires": { - "dns-packet": "^1.3.1", - "thunky": "^1.0.2" + "dns-packet": "1.3.1", + "thunky": "1.0.3" } }, "multicast-dns-service-types": { @@ -9337,17 +9332,17 @@ "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "fragment-cache": "0.2.1", + "is-windows": "1.0.2", + "kind-of": "6.0.2", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "arr-diff": { @@ -9392,7 +9387,7 @@ "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", "requires": { - "lower-case": "^1.1.1" + "lower-case": "1.1.4" } }, "node-forge": { @@ -9405,18 +9400,18 @@ "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz", "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==", "requires": { - "fstream": "^1.0.0", - "glob": "^7.0.3", - "graceful-fs": "^4.1.2", - "mkdirp": "^0.5.0", - "nopt": "2 || 3", - "npmlog": "0 || 1 || 2 || 3 || 4", - "osenv": "0", - "request": "^2.87.0", - "rimraf": "2", - "semver": "~5.3.0", - "tar": "^2.0.0", - "which": "1" + "fstream": "1.0.11", + "glob": "7.1.3", + "graceful-fs": "4.1.15", + "mkdirp": "0.5.1", + "nopt": "3.0.6", + "npmlog": "4.1.2", + "osenv": "0.1.5", + "request": "2.88.0", + "rimraf": "2.6.3", + "semver": "5.3.0", + "tar": "2.2.1", + "which": "1.3.1" }, "dependencies": { "semver": { @@ -9436,28 +9431,28 @@ "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.1.0.tgz", "integrity": "sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg==", "requires": { - "assert": "^1.1.1", - "browserify-zlib": "^0.2.0", - "buffer": "^4.3.0", - "console-browserify": "^1.1.0", - "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.11.0", - "domain-browser": "^1.1.1", - "events": "^1.0.0", - "https-browserify": "^1.0.0", - "os-browserify": "^0.3.0", + "assert": "1.4.1", + "browserify-zlib": "0.2.0", + "buffer": "4.9.1", + "console-browserify": "1.1.0", + "constants-browserify": "1.0.0", + "crypto-browserify": "3.12.0", + "domain-browser": "1.2.0", + "events": "1.1.1", + "https-browserify": "1.0.0", + "os-browserify": "0.3.0", "path-browserify": "0.0.0", - "process": "^0.11.10", - "punycode": "^1.2.4", - "querystring-es3": "^0.2.0", - "readable-stream": "^2.3.3", - "stream-browserify": "^2.0.1", - "stream-http": "^2.7.2", - "string_decoder": "^1.0.0", - "timers-browserify": "^2.0.4", + "process": "0.11.10", + "punycode": "1.4.1", + "querystring-es3": "0.2.1", + "readable-stream": "2.3.6", + "stream-browserify": "2.0.1", + "stream-http": "2.8.3", + "string_decoder": "1.1.1", + "timers-browserify": "2.0.10", "tty-browserify": "0.0.0", - "url": "^0.11.0", - "util": "^0.10.3", + "url": "0.11.0", + "util": "0.10.4", "vm-browserify": "0.0.4" }, "dependencies": { @@ -9473,10 +9468,10 @@ "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.3.0.tgz", "integrity": "sha512-AhENzCSGZnZJgBARsUjnQ7DnZbzyP+HxlVXuD0xqAnvL8q+OqtSX7lGg9e8nHzwXkMMXNdVeqq4E2M3EUAqX6Q==", "requires": { - "growly": "^1.3.0", - "semver": "^5.5.0", - "shellwords": "^0.1.1", - "which": "^1.3.0" + "growly": "1.3.0", + "semver": "5.6.0", + "shellwords": "0.1.1", + "which": "1.3.1" } }, "node-releases": { @@ -9484,7 +9479,7 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.3.tgz", "integrity": "sha512-6VrvH7z6jqqNFY200kdB6HdzkgM96Oaj9v3dqGfgp6mF+cHmU4wyQKZ2/WPDRVoR0Jz9KqbamaBN0ZhdUaysUQ==", "requires": { - "semver": "^5.3.0" + "semver": "5.6.0" } }, "node-sass": { @@ -9492,25 +9487,25 @@ "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.11.0.tgz", "integrity": "sha512-bHUdHTphgQJZaF1LASx0kAviPH7sGlcyNhWade4eVIpFp6tsn7SV8xNMTbsQFpEV9VXpnwTTnNYlfsZXgGgmkA==", "requires": { - "async-foreach": "^0.1.3", - "chalk": "^1.1.1", - "cross-spawn": "^3.0.0", - "gaze": "^1.0.0", - "get-stdin": "^4.0.1", - "glob": "^7.0.3", - "in-publish": "^2.0.0", - "lodash.assign": "^4.2.0", - "lodash.clonedeep": "^4.3.2", - "lodash.mergewith": "^4.6.0", - "meow": "^3.7.0", - "mkdirp": "^0.5.1", - "nan": "^2.10.0", - "node-gyp": "^3.8.0", - "npmlog": "^4.0.0", - "request": "^2.88.0", - "sass-graph": "^2.2.4", - "stdout-stream": "^1.4.0", - "true-case-path": "^1.0.2" + "async-foreach": "0.1.3", + "chalk": "1.1.3", + "cross-spawn": "3.0.1", + "gaze": "1.1.3", + "get-stdin": "4.0.1", + "glob": "7.1.3", + "in-publish": "2.0.0", + "lodash.assign": "4.2.0", + "lodash.clonedeep": "4.5.0", + "lodash.mergewith": "4.6.1", + "meow": "3.7.0", + "mkdirp": "0.5.1", + "nan": "2.12.1", + "node-gyp": "3.8.0", + "npmlog": "4.1.2", + "request": "2.88.0", + "sass-graph": "2.2.4", + "stdout-stream": "1.4.1", + "true-case-path": "1.0.3" }, "dependencies": { "ansi-styles": { @@ -9523,11 +9518,11 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" } }, "cross-spawn": { @@ -9535,8 +9530,8 @@ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", "requires": { - "lru-cache": "^4.0.1", - "which": "^1.2.9" + "lru-cache": "4.1.5", + "which": "1.3.1" } }, "supports-color": { @@ -9551,7 +9546,7 @@ "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", "requires": { - "abbrev": "1" + "abbrev": "1.1.1" } }, "normalize-package-data": { @@ -9559,10 +9554,10 @@ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", "requires": { - "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" + "hosted-git-info": "2.7.1", + "is-builtin-module": "1.0.0", + "semver": "5.6.0", + "validate-npm-package-license": "3.0.4" } }, "normalize-path": { @@ -9570,7 +9565,7 @@ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", "requires": { - "remove-trailing-separator": "^1.0.1" + "remove-trailing-separator": "1.1.0" } }, "normalize-range": { @@ -9588,7 +9583,7 @@ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "requires": { - "path-key": "^2.0.0" + "path-key": "2.0.1" } }, "npmlog": { @@ -9596,10 +9591,10 @@ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" + "are-we-there-yet": "1.1.5", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" } }, "nth-check": { @@ -9607,7 +9602,7 @@ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", "requires": { - "boolbase": "~1.0.0" + "boolbase": "1.0.0" } }, "num2fraction": { @@ -9640,9 +9635,9 @@ "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" + "copy-descriptor": "0.1.1", + "define-property": "0.2.5", + "kind-of": "3.2.2" }, "dependencies": { "define-property": { @@ -9650,7 +9645,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } } } @@ -9670,7 +9665,7 @@ "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", "requires": { - "isobject": "^3.0.0" + "isobject": "3.0.1" } }, "object.assign": { @@ -9678,10 +9673,10 @@ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" + "define-properties": "1.1.3", + "function-bind": "1.1.1", + "has-symbols": "1.0.0", + "object-keys": "1.0.12" } }, "object.getownpropertydescriptors": { @@ -9689,8 +9684,8 @@ "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.1" + "define-properties": "1.1.3", + "es-abstract": "1.13.0" } }, "object.omit": { @@ -9698,8 +9693,8 @@ "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", "requires": { - "for-own": "^0.1.4", - "is-extendable": "^0.1.1" + "for-own": "0.1.5", + "is-extendable": "0.1.1" } }, "object.pick": { @@ -9707,7 +9702,7 @@ "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", "requires": { - "isobject": "^3.0.1" + "isobject": "3.0.1" } }, "object.values": { @@ -9715,10 +9710,10 @@ "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.12.0", - "function-bind": "^1.1.1", - "has": "^1.0.3" + "define-properties": "1.1.3", + "es-abstract": "1.13.0", + "function-bind": "1.1.1", + "has": "1.0.3" } }, "obuf": { @@ -9744,7 +9739,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { - "wrappy": "1" + "wrappy": "1.0.2" } }, "onetime": { @@ -9752,7 +9747,7 @@ "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", "requires": { - "mimic-fn": "^1.0.0" + "mimic-fn": "1.2.0" } }, "opn": { @@ -9760,7 +9755,7 @@ "resolved": "https://registry.npmjs.org/opn/-/opn-5.4.0.tgz", "integrity": "sha512-YF9MNdVy/0qvJvDtunAOzFw9iasOQHpVthTCvGzxt61Il64AYSGdK+rYwld7NAfk9qJ7dt+hymBNSc9LNYS+Sw==", "requires": { - "is-wsl": "^1.1.0" + "is-wsl": "1.1.0" } }, "optimist": { @@ -9768,8 +9763,8 @@ "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" + "minimist": "0.0.10", + "wordwrap": "0.0.3" }, "dependencies": { "minimist": { @@ -9789,8 +9784,8 @@ "resolved": "https://registry.npmjs.org/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.1.tgz", "integrity": "sha512-Rqm6sSjWtx9FchdP0uzTQDc7GXDKnwVEGoSxjezPkzMewx7gEWE9IMUYKmigTRC4U3RaNSwYVnUDLuIdtTpm0A==", "requires": { - "cssnano": "^4.1.0", - "last-call-webpack-plugin": "^3.0.0" + "cssnano": "4.1.8", + "last-call-webpack-plugin": "3.0.0" } }, "optionator": { @@ -9798,12 +9793,12 @@ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "wordwrap": "~1.0.0" + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" } }, "original": { @@ -9811,7 +9806,7 @@ "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", "requires": { - "url-parse": "^1.4.3" + "url-parse": "1.4.4" } }, "os-browserify": { @@ -9829,9 +9824,9 @@ "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", "requires": { - "execa": "^0.7.0", - "lcid": "^1.0.0", - "mem": "^1.1.0" + "execa": "0.7.0", + "lcid": "1.0.0", + "mem": "1.1.0" } }, "os-tmpdir": { @@ -9844,8 +9839,8 @@ "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" } }, "p-defer": { @@ -9868,7 +9863,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", "requires": { - "p-try": "^1.0.0" + "p-try": "1.0.0" } }, "p-locate": { @@ -9876,7 +9871,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "requires": { - "p-limit": "^1.1.0" + "p-limit": "1.3.0" } }, "p-map": { @@ -9899,9 +9894,9 @@ "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz", "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", "requires": { - "cyclist": "~0.2.2", - "inherits": "^2.0.3", - "readable-stream": "^2.1.5" + "cyclist": "0.2.2", + "inherits": "2.0.3", + "readable-stream": "2.3.6" } }, "param-case": { @@ -9909,7 +9904,7 @@ "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", "requires": { - "no-case": "^2.2.0" + "no-case": "2.3.2" } }, "parse-asn1": { @@ -9917,11 +9912,11 @@ "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz", "integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==", "requires": { - "asn1.js": "^4.0.0", - "browserify-aes": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3" + "asn1.js": "4.10.1", + "browserify-aes": "1.2.0", + "create-hash": "1.2.0", + "evp_bytestokey": "1.0.3", + "pbkdf2": "3.0.17" } }, "parse-glob": { @@ -9929,10 +9924,10 @@ "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", "requires": { - "glob-base": "^0.3.0", - "is-dotfile": "^1.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.0" + "glob-base": "0.3.0", + "is-dotfile": "1.0.3", + "is-extglob": "1.0.0", + "is-glob": "2.0.1" } }, "parse-json": { @@ -9940,8 +9935,8 @@ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" + "error-ex": "1.3.2", + "json-parse-better-errors": "1.0.2" } }, "parse-passwd": { @@ -10012,9 +10007,9 @@ "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "graceful-fs": "4.1.15", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" } }, "pbkdf2": { @@ -10022,11 +10017,11 @@ "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" + "create-hash": "1.2.0", + "create-hmac": "1.1.7", + "ripemd160": "2.0.2", + "safe-buffer": "5.1.2", + "sha.js": "2.4.11" } }, "performance-now": { @@ -10049,7 +10044,7 @@ "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "requires": { - "pinkie": "^2.0.0" + "pinkie": "2.0.4" } }, "pkg-dir": { @@ -10057,7 +10052,7 @@ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", "requires": { - "find-up": "^2.1.0" + "find-up": "2.1.0" } }, "pkg-up": { @@ -10065,7 +10060,7 @@ "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", "requires": { - "find-up": "^2.1.0" + "find-up": "2.1.0" } }, "pluralize": { @@ -10088,9 +10083,9 @@ "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.20.tgz", "integrity": "sha512-Yxe4mTyDzTd59PZJY4ojZR8F+E5e97iq2ZOHPz3HDgSvYC5siNad2tLooQ5y5QHyQhc3xVqvyk/eNA3wuoa7Sw==", "requires": { - "async": "^1.5.2", - "debug": "^2.2.0", - "mkdirp": "0.5.x" + "async": "1.5.2", + "debug": "2.6.9", + "mkdirp": "0.5.1" }, "dependencies": { "async": { @@ -10123,9 +10118,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", "requires": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.4.0" + "chalk": "2.4.1", + "source-map": "0.6.1", + "supports-color": "5.5.0" }, "dependencies": { "source-map": { @@ -10140,8 +10135,8 @@ "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.0.tgz", "integrity": "sha512-K/zqdg0/UgUgC8qR0lDuxYzmowPpnvrrNC5YuoqzhHMubR9AuhsPlpVu3jjkLHgDAzR+ohD/m7//iGnN9WxbzQ==", "requires": { - "postcss": "^7.0.2", - "postcss-selector-parser": "^5.0.0-rc.3" + "postcss": "7.0.8", + "postcss-selector-parser": "5.0.0" }, "dependencies": { "chalk": { @@ -10149,9 +10144,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -10159,7 +10154,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10169,9 +10164,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -10184,7 +10179,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10194,10 +10189,10 @@ "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.1.tgz", "integrity": "sha512-oXqx0m6tb4N3JGdmeMSc/i91KppbYsFZKdH0xMOqK8V1rJlzrKlTdokz8ozUXLVejydRN6u2IddxpcijRj2FqQ==", "requires": { - "css-unit-converter": "^1.1.1", - "postcss": "^7.0.5", - "postcss-selector-parser": "^5.0.0-rc.4", - "postcss-value-parser": "^3.3.1" + "css-unit-converter": "1.1.1", + "postcss": "7.0.8", + "postcss-selector-parser": "5.0.0", + "postcss-value-parser": "3.3.1" }, "dependencies": { "chalk": { @@ -10205,9 +10200,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -10215,7 +10210,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10225,9 +10220,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -10240,7 +10235,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10250,8 +10245,8 @@ "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-2.0.1.tgz", "integrity": "sha512-ZBARCypjEDofW4P6IdPVTLhDNXPRn8T2s1zHbZidW6rPaaZvcnCS2soYFIQJrMZSxiePJ2XIYTlcb2ztr/eT2g==", "requires": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" + "postcss": "7.0.8", + "postcss-values-parser": "2.0.0" }, "dependencies": { "chalk": { @@ -10259,9 +10254,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -10269,7 +10264,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10279,9 +10274,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -10294,7 +10289,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10304,9 +10299,9 @@ "resolved": "https://registry.npmjs.org/postcss-color-gray/-/postcss-color-gray-5.0.0.tgz", "integrity": "sha512-q6BuRnAGKM/ZRpfDascZlIZPjvwsRye7UDNalqVz3s7GDxMtqPY6+Q871liNxsonUw8oC61OG+PSaysYpl1bnw==", "requires": { - "@csstools/convert-colors": "^1.4.0", - "postcss": "^7.0.5", - "postcss-values-parser": "^2.0.0" + "@csstools/convert-colors": "1.4.0", + "postcss": "7.0.8", + "postcss-values-parser": "2.0.0" }, "dependencies": { "chalk": { @@ -10314,9 +10309,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -10324,7 +10319,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10334,9 +10329,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -10349,7 +10344,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10359,8 +10354,8 @@ "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-5.0.2.tgz", "integrity": "sha512-8bIOzQMGdZVifoBQUJdw+yIY00omBd2EwkJXepQo9cjp1UOHHHoeRDeSzTP6vakEpaRc6GAIOfvcQR7jBYaG5Q==", "requires": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" + "postcss": "7.0.8", + "postcss-values-parser": "2.0.0" }, "dependencies": { "chalk": { @@ -10368,9 +10363,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -10378,7 +10373,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10388,9 +10383,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -10403,7 +10398,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10413,9 +10408,9 @@ "resolved": "https://registry.npmjs.org/postcss-color-mod-function/-/postcss-color-mod-function-3.0.3.tgz", "integrity": "sha512-YP4VG+xufxaVtzV6ZmhEtc+/aTXH3d0JLpnYfxqTvwZPbJhWqp8bSY3nfNzNRFLgB4XSaBA82OE4VjOOKpCdVQ==", "requires": { - "@csstools/convert-colors": "^1.4.0", - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" + "@csstools/convert-colors": "1.4.0", + "postcss": "7.0.8", + "postcss-values-parser": "2.0.0" }, "dependencies": { "chalk": { @@ -10423,9 +10418,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -10433,7 +10428,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10443,9 +10438,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -10458,7 +10453,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10468,8 +10463,8 @@ "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-4.0.1.tgz", "integrity": "sha512-aAe3OhkS6qJXBbqzvZth2Au4V3KieR5sRQ4ptb2b2O8wgvB3SJBsdG+jsn2BZbbwekDG8nTfcCNKcSfe/lEy8g==", "requires": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" + "postcss": "7.0.8", + "postcss-values-parser": "2.0.0" }, "dependencies": { "chalk": { @@ -10477,9 +10472,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -10487,7 +10482,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10497,9 +10492,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -10512,7 +10507,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10522,11 +10517,11 @@ "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.2.tgz", "integrity": "sha512-1QJc2coIehnVFsz0otges8kQLsryi4lo19WD+U5xCWvXd0uw/Z+KKYnbiNDCnO9GP+PvErPHCG0jNvWTngk9Rw==", "requires": { - "browserslist": "^4.0.0", - "color": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" + "browserslist": "4.3.7", + "color": "3.1.0", + "has": "1.0.3", + "postcss": "7.0.8", + "postcss-value-parser": "3.3.1" }, "dependencies": { "chalk": { @@ -10534,9 +10529,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -10544,7 +10539,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10554,9 +10549,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -10569,7 +10564,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10579,8 +10574,8 @@ "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" + "postcss": "7.0.8", + "postcss-value-parser": "3.3.1" }, "dependencies": { "chalk": { @@ -10588,9 +10583,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -10598,7 +10593,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10608,9 +10603,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -10623,7 +10618,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10633,7 +10628,7 @@ "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-7.0.7.tgz", "integrity": "sha512-bWPCdZKdH60wKOTG4HKEgxWnZVjAIVNOJDvi3lkuTa90xo/K0YHa2ZnlKLC5e2qF8qCcMQXt0yzQITBp8d0OFA==", "requires": { - "postcss": "^7.0.5" + "postcss": "7.0.8" }, "dependencies": { "chalk": { @@ -10641,9 +10636,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -10651,7 +10646,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10661,9 +10656,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -10676,7 +10671,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10686,8 +10681,8 @@ "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-8.0.9.tgz", "integrity": "sha512-/Lbn5GP2JkKhgUO2elMs4NnbUJcvHX4AaF5nuJDaNkd2chYW1KA5qtOGGgdkBEWcXtKSQfHXzT7C6grEVyb13w==", "requires": { - "postcss": "^7.0.5", - "postcss-values-parser": "^2.0.0" + "postcss": "7.0.8", + "postcss-values-parser": "2.0.0" }, "dependencies": { "chalk": { @@ -10695,9 +10690,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -10705,7 +10700,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10715,9 +10710,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -10730,7 +10725,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10740,8 +10735,8 @@ "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-5.1.2.tgz", "integrity": "sha512-DSGDhqinCqXqlS4R7KGxL1OSycd1lydugJ1ky4iRXPHdBRiozyMHrdu0H3o7qNOCiZwySZTUI5MV0T8QhCLu+w==", "requires": { - "postcss": "^7.0.2", - "postcss-selector-parser": "^5.0.0-rc.3" + "postcss": "7.0.8", + "postcss-selector-parser": "5.0.0" }, "dependencies": { "chalk": { @@ -10749,9 +10744,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -10759,7 +10754,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10769,9 +10764,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -10784,7 +10779,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10794,8 +10789,8 @@ "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-5.0.0.tgz", "integrity": "sha512-3pm4oq8HYWMZePJY+5ANriPs3P07q+LW6FAdTlkFH2XqDdP4HeeJYMOzn0HYLhRSjBO3fhiqSwwU9xEULSrPgw==", "requires": { - "postcss": "^7.0.2", - "postcss-selector-parser": "^5.0.0-rc.3" + "postcss": "7.0.8", + "postcss-selector-parser": "5.0.0" }, "dependencies": { "chalk": { @@ -10803,9 +10798,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -10813,7 +10808,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10823,9 +10818,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -10838,7 +10833,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10848,7 +10843,7 @@ "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.1.tgz", "integrity": "sha512-Ay+rZu1Sz6g8IdzRjUgG2NafSNpp2MSMOQUb+9kkzzzP+kh07fP0yNbhtFejURnyVXSX3FYy2nVNW1QTnNjgBQ==", "requires": { - "postcss": "^7.0.0" + "postcss": "7.0.8" }, "dependencies": { "chalk": { @@ -10856,9 +10851,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -10866,7 +10861,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10876,9 +10871,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -10891,7 +10886,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10901,7 +10896,7 @@ "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", "requires": { - "postcss": "^7.0.0" + "postcss": "7.0.8" }, "dependencies": { "chalk": { @@ -10909,9 +10904,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -10919,7 +10914,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10929,9 +10924,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -10944,7 +10939,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10954,7 +10949,7 @@ "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", "requires": { - "postcss": "^7.0.0" + "postcss": "7.0.8" }, "dependencies": { "chalk": { @@ -10962,9 +10957,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -10972,7 +10967,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -10982,9 +10977,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -10997,7 +10992,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11007,7 +11002,7 @@ "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", "requires": { - "postcss": "^7.0.0" + "postcss": "7.0.8" }, "dependencies": { "chalk": { @@ -11015,9 +11010,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -11025,7 +11020,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11035,9 +11030,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -11050,7 +11045,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11060,8 +11055,8 @@ "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-1.0.0.tgz", "integrity": "sha512-G+nV8EnQq25fOI8CH/B6krEohGWnF5+3A6H/+JEpOncu5dCnkS1QQ6+ct3Jkaepw1NGVqqOZH6lqrm244mCftA==", "requires": { - "postcss": "^7.0.5", - "postcss-values-parser": "^2.0.0" + "postcss": "7.0.8", + "postcss-values-parser": "2.0.0" }, "dependencies": { "chalk": { @@ -11069,9 +11064,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -11079,7 +11074,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11089,9 +11084,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -11104,7 +11099,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11114,8 +11109,8 @@ "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-2.0.2.tgz", "integrity": "sha512-rwac4BuZlITeUbiBq60h/xbLzXY43qOsIErngWa4l7Mt+RaSkT7QBjXVGTcBHupykkblHMDrBFh30zchYPaOUw==", "requires": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" + "postcss": "7.0.8", + "postcss-values-parser": "2.0.0" }, "dependencies": { "chalk": { @@ -11123,9 +11118,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -11133,7 +11128,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11143,9 +11138,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -11158,7 +11153,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11168,7 +11163,7 @@ "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-4.1.0.tgz", "integrity": "sha512-jr1LHxQvStNNAHlgco6PzY308zvLklh7SJVYuWUwyUQncofaAlD2l+P/gxKHOdqWKe7xJSkVLFF/2Tp+JqMSZA==", "requires": { - "postcss": "^7.0.0" + "postcss": "7.0.8" }, "dependencies": { "chalk": { @@ -11176,9 +11171,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -11186,7 +11181,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11196,9 +11191,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -11211,7 +11206,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11221,7 +11216,7 @@ "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-4.0.0.tgz", "integrity": "sha512-Z5CkWBw0+idJHSV6+Bgf2peDOFf/x4o+vX/pwcNYrWpXFrSfTkQ3JQ1ojrq9yS+upnAlNRHeg8uEwFTgorjI8g==", "requires": { - "postcss": "^7.0.2" + "postcss": "7.0.8" }, "dependencies": { "chalk": { @@ -11229,9 +11224,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -11239,7 +11234,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11249,9 +11244,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -11264,7 +11259,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11274,7 +11269,7 @@ "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-3.0.0.tgz", "integrity": "sha512-W0APui8jQeBKbCGZudW37EeMCjDeVxKgiYfIIEo8Bdh5SpB9sxds/Iq8SEuzS0Q4YFOlG7EPFulbbxujpkrV2w==", "requires": { - "postcss": "^7.0.2" + "postcss": "7.0.8" }, "dependencies": { "chalk": { @@ -11282,9 +11277,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -11292,7 +11287,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11302,9 +11297,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -11317,7 +11312,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11327,7 +11322,7 @@ "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-4.0.0.tgz", "integrity": "sha512-M8BFYKOvCrI2aITzDad7kWuXXTm0YhGdP9Q8HanmN4EF1Hmcgs1KK5rSHylt/lUJe8yLxiSwWAHdScoEiIxztg==", "requires": { - "postcss": "^7.0.2" + "postcss": "7.0.8" }, "dependencies": { "chalk": { @@ -11335,9 +11330,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -11345,7 +11340,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11355,9 +11350,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -11370,7 +11365,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11380,7 +11375,7 @@ "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-2.0.0.tgz", "integrity": "sha512-QZSqDaMgXCHuHTEzMsS2KfVDOq7ZFiknSpkrPJY6jmxbugUPTuSzs/vuE5I3zv0WAS+3vhrlqhijiprnuQfzmg==", "requires": { - "postcss": "^7.0.2" + "postcss": "7.0.8" }, "dependencies": { "chalk": { @@ -11388,9 +11383,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -11398,7 +11393,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11408,9 +11403,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -11423,7 +11418,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11433,8 +11428,8 @@ "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-3.0.1.tgz", "integrity": "sha512-oPTcFFip5LZy8Y/whto91L9xdRHCWEMs3e1MdJxhgt4jy2WYXfhkng59fH5qLXSCPN8k4n94p1Czrfe5IOkKUw==", "requires": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" + "postcss": "7.0.8", + "postcss-values-parser": "2.0.0" }, "dependencies": { "chalk": { @@ -11442,9 +11437,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -11452,7 +11447,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11462,9 +11457,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -11477,7 +11472,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11487,8 +11482,8 @@ "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-3.0.0.tgz", "integrity": "sha512-WzrqZ5nG9R9fUtrA+we92R4jhVvEB32IIRTzfIG/PLL8UV4CvbF1ugTEHEFX6vWxl41Xt5RTCJPEZkuWzrOM+Q==", "requires": { - "lodash.template": "^4.2.4", - "postcss": "^7.0.2" + "lodash.template": "4.4.0", + "postcss": "7.0.8" }, "dependencies": { "chalk": { @@ -11496,9 +11491,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -11506,7 +11501,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11516,9 +11511,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -11531,7 +11526,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11541,9 +11536,9 @@ "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-2.0.1.tgz", "integrity": "sha512-whLy1IeZKY+3fYdqQFuDBf8Auw+qFuVnChWjmxm/UhHWqNHZx+B99EwxTvGYmUBqe3Fjxs4L1BoZTJmPu6usVg==", "requires": { - "@csstools/convert-colors": "^1.4.0", - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" + "@csstools/convert-colors": "1.4.0", + "postcss": "7.0.8", + "postcss-values-parser": "2.0.0" }, "dependencies": { "chalk": { @@ -11551,9 +11546,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -11561,7 +11556,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11571,9 +11566,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -11586,7 +11581,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11596,8 +11591,8 @@ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.0.0.tgz", "integrity": "sha512-V5JBLzw406BB8UIfsAWSK2KSwIJ5yoEIVFb4gVkXci0QdKgA24jLmHZ/ghe/GgX0lJ0/D1uUK1ejhzEY94MChQ==", "requires": { - "cosmiconfig": "^4.0.0", - "import-cwd": "^2.0.0" + "cosmiconfig": "4.0.0", + "import-cwd": "2.1.0" }, "dependencies": { "cosmiconfig": { @@ -11605,10 +11600,10 @@ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-4.0.0.tgz", "integrity": "sha512-6e5vDdrXZD+t5v0L8CrurPeybg4Fmf+FCSYxXKYVAqLUtyCSbuyqE059d0kDthTNRzKVjL7QMgNpEUlsoYH3iQ==", "requires": { - "is-directory": "^0.3.1", - "js-yaml": "^3.9.0", - "parse-json": "^4.0.0", - "require-from-string": "^2.0.1" + "is-directory": "0.3.1", + "js-yaml": "3.12.1", + "parse-json": "4.0.0", + "require-from-string": "2.0.2" } } } @@ -11618,10 +11613,10 @@ "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz", "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==", "requires": { - "loader-utils": "^1.1.0", - "postcss": "^7.0.0", - "postcss-load-config": "^2.0.0", - "schema-utils": "^1.0.0" + "loader-utils": "1.2.3", + "postcss": "7.0.8", + "postcss-load-config": "2.0.0", + "schema-utils": "1.0.0" }, "dependencies": { "chalk": { @@ -11629,9 +11624,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -11639,7 +11634,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11649,9 +11644,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -11664,7 +11659,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11674,7 +11669,7 @@ "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-3.0.0.tgz", "integrity": "sha512-1SUKdJc2vuMOmeItqGuNaC+N8MzBWFWEkAnRnLpFYj1tGGa7NqyVBujfRtgNa2gXR+6RkGUiB2O5Vmh7E2RmiA==", "requires": { - "postcss": "^7.0.2" + "postcss": "7.0.8" }, "dependencies": { "chalk": { @@ -11682,9 +11677,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -11692,7 +11687,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11702,9 +11697,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -11717,7 +11712,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11727,7 +11722,7 @@ "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-4.0.0.tgz", "integrity": "sha512-fo9moya6qyxsjbFAYl97qKO9gyre3qvbMnkOZeZwlsW6XYFsvs2DMGDlchVLfAd8LHPZDxivu/+qW2SMQeTHBw==", "requires": { - "postcss": "^7.0.2" + "postcss": "7.0.8" }, "dependencies": { "chalk": { @@ -11735,9 +11730,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -11745,7 +11740,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11755,9 +11750,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -11770,7 +11765,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11781,9 +11776,9 @@ "integrity": "sha512-hME10s6CSjm9nlVIcO1ukR7Jr5RisTaaC1y83jWCivpuBtPohA3pZE7cGTIVSYjXvLnXozHTiVOkG4dnnl756g==", "requires": { "css-color-names": "0.0.4", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "stylehacks": "^4.0.0" + "postcss": "7.0.8", + "postcss-value-parser": "3.3.1", + "stylehacks": "4.0.1" }, "dependencies": { "chalk": { @@ -11791,9 +11786,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -11801,7 +11796,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11811,9 +11806,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -11826,7 +11821,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11836,12 +11831,12 @@ "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.2.tgz", "integrity": "sha512-UiuXwCCJtQy9tAIxsnurfF0mrNHKc4NnNx6NxqmzNNjXpQwLSukUxELHTRF0Rg1pAmcoKLih8PwvZbiordchag==", "requires": { - "browserslist": "^4.0.0", - "caniuse-api": "^3.0.0", - "cssnano-util-same-parent": "^4.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0", - "vendors": "^1.0.0" + "browserslist": "4.3.7", + "caniuse-api": "3.0.0", + "cssnano-util-same-parent": "4.0.1", + "postcss": "7.0.8", + "postcss-selector-parser": "3.1.1", + "vendors": "1.0.2" }, "dependencies": { "chalk": { @@ -11849,9 +11844,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -11859,7 +11854,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11869,9 +11864,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "postcss-selector-parser": { @@ -11879,9 +11874,9 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", "requires": { - "dot-prop": "^4.1.1", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" + "dot-prop": "4.2.0", + "indexes-of": "1.0.1", + "uniq": "1.0.1" } }, "source-map": { @@ -11894,7 +11889,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11904,8 +11899,8 @@ "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" + "postcss": "7.0.8", + "postcss-value-parser": "3.3.1" }, "dependencies": { "chalk": { @@ -11913,9 +11908,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -11923,7 +11918,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11933,9 +11928,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -11948,7 +11943,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11958,10 +11953,10 @@ "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.1.tgz", "integrity": "sha512-pySEW3E6Ly5mHm18rekbWiAjVi/Wj8KKt2vwSfVFAWdW6wOIekgqxKxLU7vJfb107o3FDNPkaYFCxGAJBFyogA==", "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "is-color-stop": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" + "cssnano-util-get-arguments": "4.0.0", + "is-color-stop": "1.1.0", + "postcss": "7.0.8", + "postcss-value-parser": "3.3.1" }, "dependencies": { "chalk": { @@ -11969,9 +11964,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -11979,7 +11974,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -11989,9 +11984,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -12004,7 +11999,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12014,12 +12009,12 @@ "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.1.tgz", "integrity": "sha512-h4W0FEMEzBLxpxIVelRtMheskOKKp52ND6rJv+nBS33G1twu2tCyurYj/YtgU76+UDCvWeNs0hs8HFAWE2OUFg==", "requires": { - "alphanum-sort": "^1.0.0", - "browserslist": "^4.0.0", - "cssnano-util-get-arguments": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "uniqs": "^2.0.0" + "alphanum-sort": "1.0.2", + "browserslist": "4.3.7", + "cssnano-util-get-arguments": "4.0.0", + "postcss": "7.0.8", + "postcss-value-parser": "3.3.1", + "uniqs": "2.0.0" }, "dependencies": { "chalk": { @@ -12027,9 +12022,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -12037,7 +12032,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12047,9 +12042,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -12062,7 +12057,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12072,10 +12067,10 @@ "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.1.tgz", "integrity": "sha512-8+plQkomve3G+CodLCgbhAKrb5lekAnLYuL1d7Nz+/7RANpBEVdgBkPNwljfSKvZ9xkkZTZITd04KP+zeJTJqg==", "requires": { - "alphanum-sort": "^1.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0" + "alphanum-sort": "1.0.2", + "has": "1.0.3", + "postcss": "7.0.8", + "postcss-selector-parser": "3.1.1" }, "dependencies": { "chalk": { @@ -12083,9 +12078,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -12093,7 +12088,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12103,9 +12098,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "postcss-selector-parser": { @@ -12113,9 +12108,9 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", "requires": { - "dot-prop": "^4.1.1", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" + "dot-prop": "4.2.0", + "indexes-of": "1.0.1", + "uniq": "1.0.1" } }, "source-map": { @@ -12128,7 +12123,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12138,7 +12133,7 @@ "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.1.tgz", "integrity": "sha512-6jt9XZwUhwmRUhb/CkyJY020PYaPJsCyt3UjbaWo6XEbH/94Hmv6MP7fG2C5NDU/BcHzyGYxNtHvM+LTf9HrYw==", "requires": { - "postcss": "^6.0.1" + "postcss": "6.0.23" } }, "postcss-modules-local-by-default": { @@ -12146,8 +12141,8 @@ "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz", "integrity": "sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=", "requires": { - "css-selector-tokenizer": "^0.7.0", - "postcss": "^6.0.1" + "css-selector-tokenizer": "0.7.1", + "postcss": "6.0.23" } }, "postcss-modules-scope": { @@ -12155,8 +12150,8 @@ "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz", "integrity": "sha1-1upkmUx5+XtipytCb75gVqGUu5A=", "requires": { - "css-selector-tokenizer": "^0.7.0", - "postcss": "^6.0.1" + "css-selector-tokenizer": "0.7.1", + "postcss": "6.0.23" } }, "postcss-modules-values": { @@ -12164,8 +12159,8 @@ "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz", "integrity": "sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=", "requires": { - "icss-replace-symbols": "^1.1.0", - "postcss": "^6.0.1" + "icss-replace-symbols": "1.1.0", + "postcss": "6.0.23" } }, "postcss-nesting": { @@ -12173,7 +12168,7 @@ "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-7.0.0.tgz", "integrity": "sha512-WSsbVd5Ampi3Y0nk/SKr5+K34n52PqMqEfswu6RtU4r7wA8vSD+gM8/D9qq4aJkHImwn1+9iEFTbjoWsQeqtaQ==", "requires": { - "postcss": "^7.0.2" + "postcss": "7.0.8" }, "dependencies": { "chalk": { @@ -12181,9 +12176,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -12191,7 +12186,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12201,9 +12196,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -12216,7 +12211,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12226,7 +12221,7 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", "requires": { - "postcss": "^7.0.0" + "postcss": "7.0.8" }, "dependencies": { "chalk": { @@ -12234,9 +12229,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -12244,7 +12239,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12254,9 +12249,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -12269,7 +12264,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12279,9 +12274,9 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.1.tgz", "integrity": "sha512-R5mC4vaDdvsrku96yXP7zak+O3Mm9Y8IslUobk7IMP+u/g+lXvcN4jngmHY5zeJnrQvE13dfAg5ViU05ZFDwdg==", "requires": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" + "cssnano-util-get-match": "4.0.0", + "postcss": "7.0.8", + "postcss-value-parser": "3.3.1" }, "dependencies": { "chalk": { @@ -12289,9 +12284,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -12299,7 +12294,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12309,9 +12304,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -12324,7 +12319,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12334,10 +12329,10 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.1.tgz", "integrity": "sha512-GNoOaLRBM0gvH+ZRb2vKCIujzz4aclli64MBwDuYGU2EY53LwiP7MxOZGE46UGtotrSnmarPPZ69l2S/uxdaWA==", "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" + "cssnano-util-get-arguments": "4.0.0", + "has": "1.0.3", + "postcss": "7.0.8", + "postcss-value-parser": "3.3.1" }, "dependencies": { "chalk": { @@ -12345,9 +12340,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -12355,7 +12350,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12365,9 +12360,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -12380,7 +12375,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12390,10 +12385,10 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.1.tgz", "integrity": "sha512-fFHPGIjBUyUiswY2rd9rsFcC0t3oRta4wxE1h3lpwfQZwFeFjXFSiDtdJ7APCmHQOnUZnqYBADNRPKPwFAONgA==", "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" + "cssnano-util-get-arguments": "4.0.0", + "cssnano-util-get-match": "4.0.0", + "postcss": "7.0.8", + "postcss-value-parser": "3.3.1" }, "dependencies": { "chalk": { @@ -12401,9 +12396,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -12411,7 +12406,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12421,9 +12416,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -12436,7 +12431,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12446,9 +12441,9 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.1.tgz", "integrity": "sha512-IJoexFTkAvAq5UZVxWXAGE0yLoNN/012v7TQh5nDo6imZJl2Fwgbhy3J2qnIoaDBrtUP0H7JrXlX1jjn2YcvCQ==", "requires": { - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" + "has": "1.0.3", + "postcss": "7.0.8", + "postcss-value-parser": "3.3.1" }, "dependencies": { "chalk": { @@ -12456,9 +12451,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -12466,7 +12461,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12476,9 +12471,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -12491,7 +12486,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12501,9 +12496,9 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.1.tgz", "integrity": "sha512-1nOtk7ze36+63ONWD8RCaRDYsnzorrj+Q6fxkQV+mlY5+471Qx9kspqv0O/qQNMeApg8KNrRf496zHwJ3tBZ7w==", "requires": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" + "cssnano-util-get-match": "4.0.0", + "postcss": "7.0.8", + "postcss-value-parser": "3.3.1" }, "dependencies": { "chalk": { @@ -12511,9 +12506,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -12521,7 +12516,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12531,9 +12526,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -12546,7 +12541,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12556,9 +12551,9 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", "requires": { - "browserslist": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" + "browserslist": "4.3.7", + "postcss": "7.0.8", + "postcss-value-parser": "3.3.1" }, "dependencies": { "chalk": { @@ -12566,9 +12561,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -12576,7 +12571,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12586,9 +12581,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -12601,7 +12596,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12611,10 +12606,10 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", "requires": { - "is-absolute-url": "^2.0.0", - "normalize-url": "^3.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" + "is-absolute-url": "2.1.0", + "normalize-url": "3.3.0", + "postcss": "7.0.8", + "postcss-value-parser": "3.3.1" }, "dependencies": { "chalk": { @@ -12622,9 +12617,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -12632,7 +12627,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12642,9 +12637,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -12657,7 +12652,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12667,8 +12662,8 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.1.tgz", "integrity": "sha512-U8MBODMB2L+nStzOk6VvWWjZgi5kQNShCyjRhMT3s+W9Jw93yIjOnrEkKYD3Ul7ChWbEcjDWmXq0qOL9MIAnAw==", "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" + "postcss": "7.0.8", + "postcss-value-parser": "3.3.1" }, "dependencies": { "chalk": { @@ -12676,9 +12671,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -12686,7 +12681,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12696,9 +12691,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -12711,7 +12706,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12721,9 +12716,9 @@ "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.1.tgz", "integrity": "sha512-PeJiLgJWPzkVF8JuKSBcylaU+hDJ/TX3zqAMIjlghgn1JBi6QwQaDZoDIlqWRcCAI8SxKrt3FCPSRmOgKRB97Q==", "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" + "cssnano-util-get-arguments": "4.0.0", + "postcss": "7.0.8", + "postcss-value-parser": "3.3.1" }, "dependencies": { "chalk": { @@ -12731,9 +12726,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -12741,7 +12736,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12751,9 +12746,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -12766,7 +12761,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12776,7 +12771,7 @@ "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-2.0.0.tgz", "integrity": "sha512-aK0fHc9CBNx8jbzMYhshZcEv8LtYnBIRYQD5i7w/K/wS9c2+0NSR6B3OVMu5y0hBHYLcMGjfU+dmWYNKH0I85g==", "requires": { - "postcss": "^7.0.2" + "postcss": "7.0.8" }, "dependencies": { "chalk": { @@ -12784,9 +12779,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -12794,7 +12789,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12804,9 +12799,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -12819,7 +12814,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12829,7 +12824,7 @@ "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-2.0.0.tgz", "integrity": "sha512-tkpTSrLpfLfD9HvgOlJuigLuk39wVTbbd8RKcy8/ugV2bNBUW3xU+AIqyxhDrQr1VUj1RmyJrBn1YWrqUm9zAQ==", "requires": { - "postcss": "^7.0.2" + "postcss": "7.0.8" }, "dependencies": { "chalk": { @@ -12837,9 +12832,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -12847,7 +12842,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12857,9 +12852,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -12872,7 +12867,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12882,8 +12877,8 @@ "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-4.0.1.tgz", "integrity": "sha512-Zb6byCSLkgRKLODj/5mQugyuj9bvAAw9LqJJjgwz5cYryGeXfFZfSXoP1UfveccFmeq0b/2xxwcTEVScnqGxBg==", "requires": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" + "postcss": "7.0.8", + "postcss-values-parser": "2.0.0" }, "dependencies": { "chalk": { @@ -12891,9 +12886,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -12901,7 +12896,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12911,9 +12906,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -12926,7 +12921,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12936,40 +12931,40 @@ "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-6.3.1.tgz", "integrity": "sha512-erl+OcCTr1+jsfJNQjBweyb8Y1s6KngUBwoqJnRXO197PmEE6u9HxZfnpKkTQqasxZljxNHzXR5hMb7MdD0Zdw==", "requires": { - "autoprefixer": "^9.3.1", - "browserslist": "^4.3.4", - "caniuse-lite": "^1.0.30000905", - "cssdb": "^4.1.0", - "postcss": "^7.0.5", - "postcss-attribute-case-insensitive": "^4.0.0", - "postcss-color-functional-notation": "^2.0.1", - "postcss-color-gray": "^5.0.0", - "postcss-color-hex-alpha": "^5.0.2", - "postcss-color-mod-function": "^3.0.3", - "postcss-color-rebeccapurple": "^4.0.1", - "postcss-custom-media": "^7.0.7", - "postcss-custom-properties": "^8.0.9", - "postcss-custom-selectors": "^5.1.2", - "postcss-dir-pseudo-class": "^5.0.0", - "postcss-double-position-gradients": "^1.0.0", - "postcss-env-function": "^2.0.2", - "postcss-focus-visible": "^4.0.0", - "postcss-focus-within": "^3.0.0", - "postcss-font-variant": "^4.0.0", - "postcss-gap-properties": "^2.0.0", - "postcss-image-set-function": "^3.0.1", - "postcss-initial": "^3.0.0", - "postcss-lab-function": "^2.0.1", - "postcss-logical": "^3.0.0", - "postcss-media-minmax": "^4.0.0", - "postcss-nesting": "^7.0.0", - "postcss-overflow-shorthand": "^2.0.0", - "postcss-page-break": "^2.0.0", - "postcss-place": "^4.0.1", - "postcss-pseudo-class-any-link": "^6.0.0", - "postcss-replace-overflow-wrap": "^3.0.0", - "postcss-selector-matches": "^4.0.0", - "postcss-selector-not": "^4.0.0" + "autoprefixer": "9.4.4", + "browserslist": "4.3.7", + "caniuse-lite": "1.0.30000927", + "cssdb": "4.3.0", + "postcss": "7.0.8", + "postcss-attribute-case-insensitive": "4.0.0", + "postcss-color-functional-notation": "2.0.1", + "postcss-color-gray": "5.0.0", + "postcss-color-hex-alpha": "5.0.2", + "postcss-color-mod-function": "3.0.3", + "postcss-color-rebeccapurple": "4.0.1", + "postcss-custom-media": "7.0.7", + "postcss-custom-properties": "8.0.9", + "postcss-custom-selectors": "5.1.2", + "postcss-dir-pseudo-class": "5.0.0", + "postcss-double-position-gradients": "1.0.0", + "postcss-env-function": "2.0.2", + "postcss-focus-visible": "4.0.0", + "postcss-focus-within": "3.0.0", + "postcss-font-variant": "4.0.0", + "postcss-gap-properties": "2.0.0", + "postcss-image-set-function": "3.0.1", + "postcss-initial": "3.0.0", + "postcss-lab-function": "2.0.1", + "postcss-logical": "3.0.0", + "postcss-media-minmax": "4.0.0", + "postcss-nesting": "7.0.0", + "postcss-overflow-shorthand": "2.0.0", + "postcss-page-break": "2.0.0", + "postcss-place": "4.0.1", + "postcss-pseudo-class-any-link": "6.0.0", + "postcss-replace-overflow-wrap": "3.0.0", + "postcss-selector-matches": "4.0.0", + "postcss-selector-not": "4.0.0" }, "dependencies": { "chalk": { @@ -12977,9 +12972,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -12987,7 +12982,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -12997,9 +12992,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -13012,7 +13007,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -13022,8 +13017,8 @@ "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-6.0.0.tgz", "integrity": "sha512-lgXW9sYJdLqtmw23otOzrtbDXofUdfYzNm4PIpNE322/swES3VU9XlXHeJS46zT2onFO7V1QFdD4Q9LiZj8mew==", "requires": { - "postcss": "^7.0.2", - "postcss-selector-parser": "^5.0.0-rc.3" + "postcss": "7.0.8", + "postcss-selector-parser": "5.0.0" }, "dependencies": { "chalk": { @@ -13031,9 +13026,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -13041,7 +13036,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -13051,9 +13046,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -13066,7 +13061,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -13076,10 +13071,10 @@ "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.2.tgz", "integrity": "sha512-epUiC39NonKUKG+P3eAOKKZtm5OtAtQJL7Ye0CBN1f+UQTHzqotudp+hki7zxXm7tT0ZAKDMBj1uihpPjP25ug==", "requires": { - "browserslist": "^4.0.0", - "caniuse-api": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0" + "browserslist": "4.3.7", + "caniuse-api": "3.0.0", + "has": "1.0.3", + "postcss": "7.0.8" }, "dependencies": { "chalk": { @@ -13087,9 +13082,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -13097,7 +13092,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -13107,9 +13102,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -13122,7 +13117,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -13132,10 +13127,10 @@ "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.1.tgz", "integrity": "sha512-sZVr3QlGs0pjh6JAIe6DzWvBaqYw05V1t3d9Tp+VnFRT5j+rsqoWsysh/iSD7YNsULjq9IAylCznIwVd5oU/zA==", "requires": { - "cssnano-util-get-match": "^4.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" + "cssnano-util-get-match": "4.0.0", + "has": "1.0.3", + "postcss": "7.0.8", + "postcss-value-parser": "3.3.1" }, "dependencies": { "chalk": { @@ -13143,9 +13138,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -13153,7 +13148,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -13163,9 +13158,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -13178,7 +13173,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -13188,7 +13183,7 @@ "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-3.0.0.tgz", "integrity": "sha512-2T5hcEHArDT6X9+9dVSPQdo7QHzG4XKclFT8rU5TzJPDN7RIRTbO9c4drUISOVemLj03aezStHCR2AIcr8XLpw==", "requires": { - "postcss": "^7.0.2" + "postcss": "7.0.8" }, "dependencies": { "chalk": { @@ -13196,9 +13191,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -13206,7 +13201,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -13216,9 +13211,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -13231,7 +13226,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -13241,7 +13236,7 @@ "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-4.0.1.tgz", "integrity": "sha512-xZsFA3uX8MO3yAda03QrG3/Eg1LN3EPfjjf07vke/46HERLZyHrTsQ9E1r1w1W//fWEhtYNndo2hQplN2cVpCQ==", "requires": { - "postcss": "^7.0.0" + "postcss": "7.0.8" }, "dependencies": { "chalk": { @@ -13249,9 +13244,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -13259,7 +13254,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -13269,9 +13264,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -13284,7 +13279,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -13294,8 +13289,8 @@ "resolved": "https://registry.npmjs.org/postcss-selector-matches/-/postcss-selector-matches-4.0.0.tgz", "integrity": "sha512-LgsHwQR/EsRYSqlwdGzeaPKVT0Ml7LAT6E75T8W8xLJY62CE4S/l03BWIt3jT8Taq22kXP08s2SfTSzaraoPww==", "requires": { - "balanced-match": "^1.0.0", - "postcss": "^7.0.2" + "balanced-match": "1.0.0", + "postcss": "7.0.8" }, "dependencies": { "chalk": { @@ -13303,9 +13298,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -13313,7 +13308,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -13323,9 +13318,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -13338,7 +13333,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -13348,8 +13343,8 @@ "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-4.0.0.tgz", "integrity": "sha512-W+bkBZRhqJaYN8XAnbbZPLWMvZD1wKTu0UxtFKdhtGjWYmxhkUneoeOhRJKdAE5V7ZTlnbHfCR+6bNwK9e1dTQ==", "requires": { - "balanced-match": "^1.0.0", - "postcss": "^7.0.2" + "balanced-match": "1.0.0", + "postcss": "7.0.8" }, "dependencies": { "chalk": { @@ -13357,9 +13352,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -13367,7 +13362,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -13377,9 +13372,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -13392,7 +13387,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -13402,9 +13397,9 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", "requires": { - "cssesc": "^2.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" + "cssesc": "2.0.0", + "indexes-of": "1.0.1", + "uniq": "1.0.1" }, "dependencies": { "cssesc": { @@ -13419,10 +13414,10 @@ "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.1.tgz", "integrity": "sha512-YD5uIk5NDRySy0hcI+ZJHwqemv2WiqqzDgtvgMzO8EGSkK5aONyX8HMVFRFJSdO8wUWTuisUFn/d7yRRbBr5Qw==", "requires": { - "is-svg": "^3.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "svgo": "^1.0.0" + "is-svg": "3.0.0", + "postcss": "7.0.8", + "postcss-value-parser": "3.3.1", + "svgo": "1.1.1" }, "dependencies": { "chalk": { @@ -13430,9 +13425,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -13440,7 +13435,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -13450,9 +13445,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -13465,7 +13460,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -13475,9 +13470,9 @@ "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", "requires": { - "alphanum-sort": "^1.0.0", - "postcss": "^7.0.0", - "uniqs": "^2.0.0" + "alphanum-sort": "1.0.2", + "postcss": "7.0.8", + "uniqs": "2.0.0" }, "dependencies": { "chalk": { @@ -13485,9 +13480,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -13495,7 +13490,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -13505,9 +13500,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "source-map": { @@ -13520,7 +13515,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -13535,9 +13530,9 @@ "resolved": "https://registry.npmjs.org/postcss-values-parser/-/postcss-values-parser-2.0.0.tgz", "integrity": "sha512-cyRdkgbRRefu91ByAlJow4y9w/hnBmmWgLpWmlFQ2bpIy2eKrqowt3VeYcaHQ08otVXmC9V2JtYW1Z/RpvYR8A==", "requires": { - "flatten": "^1.0.2", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" + "flatten": "1.0.2", + "indexes-of": "1.0.1", + "uniq": "1.0.1" } }, "prelude-ls": { @@ -13565,8 +13560,8 @@ "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz", "integrity": "sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM=", "requires": { - "renderkid": "^2.0.1", - "utila": "~0.4" + "renderkid": "2.0.2", + "utila": "0.4.0" } }, "pretty-format": { @@ -13574,8 +13569,8 @@ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", "requires": { - "ansi-regex": "^3.0.0", - "ansi-styles": "^3.2.0" + "ansi-regex": "3.0.0", + "ansi-styles": "3.2.1" }, "dependencies": { "ansi-regex": { @@ -13615,8 +13610,8 @@ "resolved": "https://registry.npmjs.org/prompts/-/prompts-0.1.14.tgz", "integrity": "sha512-rxkyiE9YH6zAz/rZpywySLKkpaj0NMVyNw1qhsubdbjjSgcayjTShDreZGlFMcGSu5sab3bAKPfFk78PB90+8w==", "requires": { - "kleur": "^2.0.1", - "sisteransi": "^0.1.1" + "kleur": "2.0.2", + "sisteransi": "0.1.1" } }, "prop-types": { @@ -13624,8 +13619,8 @@ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz", "integrity": "sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==", "requires": { - "loose-envify": "^1.3.1", - "object-assign": "^4.1.1" + "loose-envify": "1.4.0", + "object-assign": "4.1.1" } }, "proxy-addr": { @@ -13633,7 +13628,7 @@ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", "requires": { - "forwarded": "~0.1.2", + "forwarded": "0.1.2", "ipaddr.js": "1.8.0" } }, @@ -13657,12 +13652,12 @@ "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", "requires": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" + "bn.js": "4.11.8", + "browserify-rsa": "4.0.1", + "create-hash": "1.2.0", + "parse-asn1": "5.1.1", + "randombytes": "2.0.6", + "safe-buffer": "5.1.2" } }, "pump": { @@ -13670,8 +13665,8 @@ "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" + "end-of-stream": "1.4.1", + "once": "1.4.0" } }, "pumpify": { @@ -13679,9 +13674,9 @@ "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", "requires": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" + "duplexify": "3.6.1", + "inherits": "2.0.3", + "pump": "2.0.1" }, "dependencies": { "pump": { @@ -13689,8 +13684,8 @@ "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "end-of-stream": "1.4.1", + "once": "1.4.0" } } } @@ -13715,7 +13710,7 @@ "resolved": "https://registry.npmjs.org/qrcode.react/-/qrcode.react-0.9.2.tgz", "integrity": "sha512-opV0IA4w84qMaZg3hhgmktDs1xjfx3K7RAOzdvmKgkLdhmtv95AYGZmlG0s3NIAZ1qXCK4AyPJayLd3sa6p/RA==", "requires": { - "prop-types": "^15.6.0", + "prop-types": "15.6.2", "qr.js": "0.0.0" } }, @@ -13729,8 +13724,8 @@ "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.2.0.tgz", "integrity": "sha512-5wupExkIt8RYL4h/FE+WTg3JHk62e6fFPWtAZA9J5IWK1PfTfKkMS93HBUHcFpeYi9KsY5pFbh+ldvEyaz5MyA==", "requires": { - "decode-uri-component": "^0.2.0", - "strict-uri-encode": "^2.0.0" + "decode-uri-component": "0.2.0", + "strict-uri-encode": "2.0.0" } }, "querystring": { @@ -13753,7 +13748,7 @@ "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.0.tgz", "integrity": "sha512-pDP/NMRAXoTfrhCfyfSEwJAKLaxBU9eApMeBPB1TkDouZmvPerIClV8lTAd+uF8ZiTaVl69e1FCxQrAd/VTjGw==", "requires": { - "performance-now": "^2.1.0" + "performance-now": "2.1.0" } }, "randomatic": { @@ -13761,9 +13756,9 @@ "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", "requires": { - "is-number": "^4.0.0", - "kind-of": "^6.0.0", - "math-random": "^1.0.1" + "is-number": "4.0.0", + "kind-of": "6.0.2", + "math-random": "1.0.1" }, "dependencies": { "is-number": { @@ -13783,7 +13778,7 @@ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", "requires": { - "safe-buffer": "^5.1.0" + "safe-buffer": "5.1.2" } }, "randomfill": { @@ -13791,8 +13786,8 @@ "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", "requires": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" + "randombytes": "2.0.6", + "safe-buffer": "5.1.2" } }, "range-parser": { @@ -13816,20 +13811,19 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": "2.1.2" } } } }, "react": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/react/-/react-16.7.0.tgz", - "integrity": "sha512-StCz3QY8lxTb5cl2HJxjwLFOXPIFQp+p+hxQfc8WE0QiLfCtIlKj8/+5tjjKm8uSTlAW+fCPaavGFS06V9Ar3A==", + "version": "16.10.2", + "resolved": "https://registry.npmjs.org/react/-/react-16.10.2.tgz", + "integrity": "sha512-MFVIq0DpIhrHFyqLU0S3+4dIcBhhOvBE8bJ/5kHPVOVaGdo0KuiQzpcjCPsf585WvhypqtrMILyoE2th6dT+Lw==", "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.12.0" + "loose-envify": "1.4.0", + "object-assign": "4.1.1", + "prop-types": "15.6.2" } }, "react-app-polyfill": { @@ -13854,7 +13848,7 @@ "resolved": "https://registry.npmjs.org/promise/-/promise-8.0.2.tgz", "integrity": "sha512-EIyzM39FpVOMbqgzEHhxdrEhtOSDOtjMZQ0M6iVfCE+kWNgCkAyOdnuCWqfmflylftfadU6FkiMgHZA2kUzwRw==", "requires": { - "asap": "~2.0.6" + "asap": "2.0.6" } } } @@ -13882,7 +13876,7 @@ "loader-utils": "1.1.0", "opn": "5.4.0", "pkg-up": "2.0.0", - "react-error-overlay": "^5.1.2", + "react-error-overlay": "5.1.2", "recursive-readdir": "2.2.2", "shell-quote": "1.6.1", "sockjs-client": "1.1.5", @@ -13905,9 +13899,9 @@ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.1.1.tgz", "integrity": "sha512-VBorw+tgpOtZ1BYhrVSVTzTt/3+vSE3eFUh0N2GCFK1HffceOaf32YS/bs6WiFhjDAblAFrx85jMy3BG9fBK2Q==", "requires": { - "caniuse-lite": "^1.0.30000884", - "electron-to-chromium": "^1.3.62", - "node-releases": "^1.0.0-alpha.11" + "caniuse-lite": "1.0.30000927", + "electron-to-chromium": "1.3.100", + "node-releases": "1.1.3" } }, "find-up": { @@ -13915,7 +13909,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "requires": { - "locate-path": "^3.0.0" + "locate-path": "3.0.0" } }, "inquirer": { @@ -13923,19 +13917,19 @@ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.0.tgz", "integrity": "sha512-QIEQG4YyQ2UYZGDC4srMZ7BjHOmNk1lR2JQj5UknBapklm6WHA+VVH7N+sUdX3A7NeCfGF8o4X1S3Ao7nAcIeg==", "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.0", - "figures": "^2.0.0", - "lodash": "^4.17.10", + "ansi-escapes": "3.1.0", + "chalk": "2.4.1", + "cli-cursor": "2.1.0", + "cli-width": "2.2.0", + "external-editor": "3.0.3", + "figures": "2.0.0", + "lodash": "4.17.11", "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.1.0", - "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", - "through": "^2.3.6" + "run-async": "2.3.0", + "rxjs": "6.3.3", + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "through": "2.3.8" } }, "json5": { @@ -13948,9 +13942,9 @@ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", "requires": { - "big.js": "^3.1.3", - "emojis-list": "^2.0.0", - "json5": "^0.5.0" + "big.js": "3.2.0", + "emojis-list": "2.1.0", + "json5": "0.5.1" } }, "locate-path": { @@ -13958,8 +13952,8 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "p-locate": "3.0.0", + "path-exists": "3.0.0" } }, "p-limit": { @@ -13967,7 +13961,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", "requires": { - "p-try": "^2.0.0" + "p-try": "2.0.0" } }, "p-locate": { @@ -13975,7 +13969,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "requires": { - "p-limit": "^2.0.0" + "p-limit": "2.1.0" } }, "p-try": { @@ -13988,7 +13982,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "3.0.0" } } } @@ -13998,10 +13992,10 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.7.0.tgz", "integrity": "sha512-D0Ufv1ExCAmF38P2Uh1lwpminZFRXEINJe53zRAbm4KPwSyd6DY/uDoS0Blj9jvPpn1+wivKpZYc8aAAN/nAkg==", "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.12.0" + "loose-envify": "1.4.0", + "object-assign": "4.1.1", + "prop-types": "15.6.2", + "scheduler": "0.12.0" } }, "react-error-overlay": { @@ -14019,12 +14013,12 @@ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-6.0.0.tgz", "integrity": "sha512-EmbC3uLl60pw2VqSSkj6HpZ6jTk12RMrwXMBdYtM6niq0MdEaRq9KYCwpJflkOZj349BLGQm1MI/JO1W96kLWQ==", "requires": { - "@babel/runtime": "^7.2.0", - "hoist-non-react-statics": "^3.2.1", - "invariant": "^2.2.4", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2", - "react-is": "^16.6.3" + "@babel/runtime": "7.2.0", + "hoist-non-react-statics": "3.2.1", + "invariant": "2.2.4", + "loose-envify": "1.4.0", + "prop-types": "15.6.2", + "react-is": "16.7.0" } }, "react-router": { @@ -14032,13 +14026,13 @@ "resolved": "https://registry.npmjs.org/react-router/-/react-router-4.3.1.tgz", "integrity": "sha512-yrvL8AogDh2X42Dt9iknk4wF4V8bWREPirFfS9gLU1huk6qK41sg7Z/1S81jjTrGHxa3B8R3J6xIkDAA6CVarg==", "requires": { - "history": "^4.7.2", - "hoist-non-react-statics": "^2.5.0", - "invariant": "^2.2.4", - "loose-envify": "^1.3.1", - "path-to-regexp": "^1.7.0", - "prop-types": "^15.6.1", - "warning": "^4.0.1" + "history": "4.7.2", + "hoist-non-react-statics": "2.5.5", + "invariant": "2.2.4", + "loose-envify": "1.4.0", + "path-to-regexp": "1.7.0", + "prop-types": "15.6.2", + "warning": "4.0.2" }, "dependencies": { "hoist-non-react-statics": { @@ -14053,12 +14047,12 @@ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-4.3.1.tgz", "integrity": "sha512-c/MlywfxDdCp7EnB7YfPMOfMD3tOtIjrQlj/CKfNMBxdmpJP8xcz5P/UAFn3JbnQCNUxsHyVVqllF9LhgVyFCA==", "requires": { - "history": "^4.7.2", - "invariant": "^2.2.4", - "loose-envify": "^1.3.1", - "prop-types": "^15.6.1", - "react-router": "^4.3.1", - "warning": "^4.0.1" + "history": "4.7.2", + "invariant": "2.2.4", + "loose-envify": "1.4.0", + "prop-types": "15.6.2", + "react-router": "4.3.1", + "warning": "4.0.2" } }, "react-scripts": { @@ -14072,8 +14066,8 @@ "babel-eslint": "9.0.0", "babel-jest": "23.6.0", "babel-loader": "8.0.4", - "babel-plugin-named-asset-import": "^0.3.0", - "babel-preset-react-app": "^7.0.0", + "babel-plugin-named-asset-import": "0.3.0", + "babel-preset-react-app": "7.0.0", "bfj": "6.1.1", "case-sensitive-paths-webpack-plugin": "2.1.2", "chalk": "2.4.1", @@ -14081,7 +14075,7 @@ "dotenv": "6.0.0", "dotenv-expand": "4.2.0", "eslint": "5.6.0", - "eslint-config-react-app": "^3.0.6", + "eslint-config-react-app": "3.0.6", "eslint-loader": "2.1.1", "eslint-plugin-flowtype": "2.50.1", "eslint-plugin-import": "2.14.0", @@ -14103,8 +14097,8 @@ "postcss-loader": "3.0.0", "postcss-preset-env": "6.3.1", "postcss-safe-parser": "4.0.1", - "react-app-polyfill": "^0.2.0", - "react-dev-utils": "^7.0.1", + "react-app-polyfill": "0.2.0", + "react-dev-utils": "7.0.1", "resolve": "1.8.1", "sass-loader": "7.1.0", "style-loader": "0.23.0", @@ -14121,9 +14115,9 @@ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" + "load-json-file": "1.1.0", + "normalize-package-data": "2.4.0", + "path-type": "1.1.0" } }, "read-pkg-up": { @@ -14131,8 +14125,8 @@ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" + "find-up": "1.1.2", + "read-pkg": "1.1.0" }, "dependencies": { "find-up": { @@ -14140,8 +14134,8 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" } }, "path-exists": { @@ -14149,7 +14143,7 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "requires": { - "pinkie-promise": "^2.0.0" + "pinkie-promise": "2.0.1" } } } @@ -14159,13 +14153,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" }, "dependencies": { "isarray": { @@ -14180,9 +14174,9 @@ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" + "graceful-fs": "4.1.15", + "micromatch": "3.1.10", + "readable-stream": "2.3.6" }, "dependencies": { "arr-diff": { @@ -14200,16 +14194,16 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" + "arr-flatten": "1.1.0", + "array-unique": "0.3.2", + "extend-shallow": "2.0.1", + "fill-range": "4.0.0", + "isobject": "3.0.1", + "repeat-element": "1.1.3", + "snapdragon": "0.8.2", + "snapdragon-node": "2.1.1", + "split-string": "3.1.0", + "to-regex": "3.0.2" }, "dependencies": { "extend-shallow": { @@ -14217,7 +14211,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -14235,13 +14229,13 @@ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "posix-character-classes": "0.1.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -14249,7 +14243,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "extend-shallow": { @@ -14257,7 +14251,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } }, "is-accessor-descriptor": { @@ -14265,7 +14259,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -14273,7 +14267,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -14283,7 +14277,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -14291,7 +14285,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -14301,9 +14295,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" } }, "kind-of": { @@ -14318,14 +14312,14 @@ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "array-unique": "0.3.2", + "define-property": "1.0.0", + "expand-brackets": "2.1.4", + "extend-shallow": "2.0.1", + "fragment-cache": "0.2.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -14333,7 +14327,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "extend-shallow": { @@ -14341,7 +14335,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -14351,10 +14345,10 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" + "extend-shallow": "2.0.1", + "is-number": "3.0.0", + "repeat-string": "1.6.1", + "to-regex-range": "2.1.1" }, "dependencies": { "extend-shallow": { @@ -14362,7 +14356,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -14372,7 +14366,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { @@ -14380,7 +14374,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { @@ -14388,9 +14382,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } }, "is-number": { @@ -14398,7 +14392,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -14406,7 +14400,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -14421,19 +14415,19 @@ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "braces": "2.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "extglob": "2.0.4", + "fragment-cache": "0.2.1", + "kind-of": "6.0.2", + "nanomatch": "1.2.13", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" } }, "ms": { @@ -14448,7 +14442,7 @@ "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.0.2.tgz", "integrity": "sha512-+S3zTvVt9yTntFrBpm7TQmQ3tzpCrnA1a/y+3cUHAc9ZR6aIjG0WNLR+Rj79QpJktY+VeW/TQtFlQ1bzsehI8g==", "requires": { - "util.promisify": "^1.0.0" + "util.promisify": "1.0.0" } }, "recursive-readdir": { @@ -14464,8 +14458,8 @@ "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", "requires": { - "indent-string": "^2.1.0", - "strip-indent": "^1.0.1" + "indent-string": "2.1.0", + "strip-indent": "1.0.1" } }, "redux": { @@ -14473,8 +14467,8 @@ "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.1.tgz", "integrity": "sha512-R7bAtSkk7nY6O/OYMVR9RiBI+XghjF9rlbl5806HJbQph0LJVHZrU5oaO4q70eUKiqMRqm4y07KLTlMZ2BlVmg==", "requires": { - "loose-envify": "^1.4.0", - "symbol-observable": "^1.2.0" + "loose-envify": "1.4.0", + "symbol-observable": "1.2.0" } }, "redux-thunk": { @@ -14492,7 +14486,7 @@ "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-7.0.0.tgz", "integrity": "sha512-s5NGghCE4itSlUS+0WUj88G6cfMVMmH8boTPNvABf8od+2dhT9WDlWu8n01raQAJZMOK8Ch6jSexaRO7swd6aw==", "requires": { - "regenerate": "^1.4.0" + "regenerate": "1.4.0" } }, "regenerator-runtime": { @@ -14505,7 +14499,7 @@ "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.13.3.tgz", "integrity": "sha512-5ipTrZFSq5vU2YoGoww4uaRVAK4wyYC4TSICibbfEPOruUu8FFP7ErV0BjmbIOEpn3O/k9na9UEdYR/3m7N6uA==", "requires": { - "private": "^0.1.6" + "private": "0.1.8" } }, "regex-cache": { @@ -14513,7 +14507,7 @@ "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", "requires": { - "is-equal-shallow": "^0.1.3" + "is-equal-shallow": "0.1.3" } }, "regex-not": { @@ -14521,8 +14515,8 @@ "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" + "extend-shallow": "3.0.2", + "safe-regex": "1.1.0" } }, "regexpp": { @@ -14535,12 +14529,12 @@ "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.4.0.tgz", "integrity": "sha512-eDDWElbwwI3K0Lo6CqbQbA6FwgtCz4kYTarrri1okfkRLZAqstU+B3voZBCjg8Fl6iq0gXrJG6MvRgLthfvgOA==", "requires": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^7.0.0", - "regjsgen": "^0.5.0", - "regjsparser": "^0.6.0", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.0.2" + "regenerate": "1.4.0", + "regenerate-unicode-properties": "7.0.0", + "regjsgen": "0.5.0", + "regjsparser": "0.6.0", + "unicode-match-property-ecmascript": "1.0.4", + "unicode-match-property-value-ecmascript": "1.0.2" } }, "regjsgen": { @@ -14553,7 +14547,7 @@ "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", "requires": { - "jsesc": "~0.5.0" + "jsesc": "0.5.0" }, "dependencies": { "jsesc": { @@ -14578,11 +14572,11 @@ "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.2.tgz", "integrity": "sha512-FsygIxevi1jSiPY9h7vZmBFUbAOcbYm9UwyiLNdVsLRs/5We9Ob5NMPbGYUTWiLq5L+ezlVdE0A8bbME5CWTpg==", "requires": { - "css-select": "^1.1.0", - "dom-converter": "~0.2", - "htmlparser2": "~3.3.0", - "strip-ansi": "^3.0.0", - "utila": "^0.4.0" + "css-select": "1.2.0", + "dom-converter": "0.2.0", + "htmlparser2": "3.3.0", + "strip-ansi": "3.0.1", + "utila": "0.4.0" }, "dependencies": { "css-select": { @@ -14590,10 +14584,10 @@ "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", "requires": { - "boolbase": "~1.0.0", - "css-what": "2.1", + "boolbase": "1.0.0", + "css-what": "2.1.2", "domutils": "1.5.1", - "nth-check": "~1.0.1" + "nth-check": "1.0.2" } }, "domutils": { @@ -14601,8 +14595,8 @@ "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", "requires": { - "dom-serializer": "0", - "domelementtype": "1" + "dom-serializer": "0.1.0", + "domelementtype": "1.3.1" } } } @@ -14622,7 +14616,7 @@ "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", "requires": { - "is-finite": "^1.0.0" + "is-finite": "1.0.2" } }, "request": { @@ -14630,26 +14624,26 @@ "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" + "aws-sign2": "0.7.0", + "aws4": "1.8.0", + "caseless": "0.12.0", + "combined-stream": "1.0.7", + "extend": "3.0.2", + "forever-agent": "0.6.1", + "form-data": "2.3.3", + "har-validator": "5.1.3", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.21", + "oauth-sign": "0.9.0", + "performance-now": "2.1.0", + "qs": "6.5.2", + "safe-buffer": "5.1.2", + "tough-cookie": "2.4.3", + "tunnel-agent": "0.6.0", + "uuid": "3.3.2" }, "dependencies": { "punycode": { @@ -14662,8 +14656,8 @@ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" + "psl": "1.1.31", + "punycode": "1.4.1" } } } @@ -14673,7 +14667,7 @@ "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", "requires": { - "lodash": "^4.13.1" + "lodash": "4.17.11" } }, "request-promise-native": { @@ -14682,8 +14676,8 @@ "integrity": "sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU=", "requires": { "request-promise-core": "1.1.1", - "stealthy-require": "^1.1.0", - "tough-cookie": ">=2.3.3" + "stealthy-require": "1.1.1", + "tough-cookie": "2.5.0" } }, "require-directory": { @@ -14706,8 +14700,8 @@ "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", "requires": { - "caller-path": "^0.1.0", - "resolve-from": "^1.0.0" + "caller-path": "0.1.0", + "resolve-from": "1.0.1" }, "dependencies": { "caller-path": { @@ -14715,7 +14709,7 @@ "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", "requires": { - "callsites": "^0.2.0" + "callsites": "0.2.0" } }, "callsites": { @@ -14740,7 +14734,7 @@ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", "requires": { - "path-parse": "^1.0.5" + "path-parse": "1.0.6" } }, "resolve-cwd": { @@ -14748,7 +14742,7 @@ "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", "requires": { - "resolve-from": "^3.0.0" + "resolve-from": "3.0.0" } }, "resolve-dir": { @@ -14756,8 +14750,8 @@ "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", "requires": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" + "expand-tilde": "2.0.2", + "global-modules": "1.0.0" } }, "resolve-from": { @@ -14780,8 +14774,8 @@ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" + "onetime": "2.0.1", + "signal-exit": "3.0.2" } }, "ret": { @@ -14804,7 +14798,7 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "requires": { - "glob": "^7.1.3" + "glob": "7.1.3" } }, "ripemd160": { @@ -14812,8 +14806,8 @@ "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" + "hash-base": "3.0.4", + "inherits": "2.0.3" } }, "rsvp": { @@ -14826,7 +14820,7 @@ "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", "requires": { - "is-promise": "^2.1.0" + "is-promise": "2.1.0" } }, "run-queue": { @@ -14834,7 +14828,7 @@ "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", "requires": { - "aproba": "^1.1.1" + "aproba": "1.2.0" } }, "rxjs": { @@ -14842,7 +14836,7 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz", "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==", "requires": { - "tslib": "^1.9.0" + "tslib": "1.9.3" } }, "safe-buffer": { @@ -14855,7 +14849,7 @@ "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "requires": { - "ret": "~0.1.10" + "ret": "0.1.15" } }, "safer-buffer": { @@ -14868,15 +14862,15 @@ "resolved": "https://registry.npmjs.org/sane/-/sane-2.5.2.tgz", "integrity": "sha1-tNwYYcIbQn6SlQej51HiosuKs/o=", "requires": { - "anymatch": "^2.0.0", - "capture-exit": "^1.2.0", - "exec-sh": "^0.2.0", - "fb-watchman": "^2.0.0", - "fsevents": "^1.2.3", - "micromatch": "^3.1.4", - "minimist": "^1.1.1", - "walker": "~1.0.5", - "watch": "~0.18.0" + "anymatch": "2.0.0", + "capture-exit": "1.2.0", + "exec-sh": "0.2.2", + "fb-watchman": "2.0.0", + "fsevents": "1.2.4", + "micromatch": "3.1.10", + "minimist": "1.2.0", + "walker": "1.0.7", + "watch": "0.18.0" }, "dependencies": { "arr-diff": { @@ -14894,16 +14888,16 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" + "arr-flatten": "1.1.0", + "array-unique": "0.3.2", + "extend-shallow": "2.0.1", + "fill-range": "4.0.0", + "isobject": "3.0.1", + "repeat-element": "1.1.3", + "snapdragon": "0.8.2", + "snapdragon-node": "2.1.1", + "split-string": "3.1.0", + "to-regex": "3.0.2" }, "dependencies": { "extend-shallow": { @@ -14911,7 +14905,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -14929,13 +14923,13 @@ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "posix-character-classes": "0.1.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -14943,7 +14937,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "extend-shallow": { @@ -14951,7 +14945,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } }, "is-accessor-descriptor": { @@ -14959,7 +14953,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -14967,7 +14961,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -14977,7 +14971,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -14985,7 +14979,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -14995,9 +14989,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" } }, "kind-of": { @@ -15012,14 +15006,14 @@ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "array-unique": "0.3.2", + "define-property": "1.0.0", + "expand-brackets": "2.1.4", + "extend-shallow": "2.0.1", + "fragment-cache": "0.2.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -15027,7 +15021,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "extend-shallow": { @@ -15035,7 +15029,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -15045,10 +15039,10 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" + "extend-shallow": "2.0.1", + "is-number": "3.0.0", + "repeat-string": "1.6.1", + "to-regex-range": "2.1.1" }, "dependencies": { "extend-shallow": { @@ -15056,7 +15050,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -15066,7 +15060,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { @@ -15074,7 +15068,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { @@ -15082,9 +15076,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } }, "is-number": { @@ -15092,7 +15086,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -15100,7 +15094,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -15115,19 +15109,19 @@ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "braces": "2.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "extglob": "2.0.4", + "fragment-cache": "0.2.1", + "kind-of": "6.0.2", + "nanomatch": "1.2.13", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" } }, "ms": { @@ -15142,10 +15136,10 @@ "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz", "integrity": "sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=", "requires": { - "glob": "^7.0.0", - "lodash": "^4.0.0", - "scss-tokenizer": "^0.2.3", - "yargs": "^7.0.0" + "glob": "7.1.3", + "lodash": "4.17.11", + "scss-tokenizer": "0.2.3", + "yargs": "7.1.0" }, "dependencies": { "camelcase": { @@ -15158,9 +15152,9 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wrap-ansi": "^2.0.0" + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.1.0" } }, "is-fullwidth-code-point": { @@ -15168,7 +15162,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "requires": { - "number-is-nan": "^1.0.0" + "number-is-nan": "1.0.1" } }, "os-locale": { @@ -15176,7 +15170,7 @@ "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", "requires": { - "lcid": "^1.0.0" + "lcid": "1.0.0" } }, "string-width": { @@ -15184,9 +15178,9 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" } }, "which-module": { @@ -15199,19 +15193,19 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", "requires": { - "camelcase": "^3.0.0", - "cliui": "^3.2.0", - "decamelize": "^1.1.1", - "get-caller-file": "^1.0.1", - "os-locale": "^1.4.0", - "read-pkg-up": "^1.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^1.0.2", - "which-module": "^1.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^5.0.0" + "camelcase": "3.0.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.3", + "os-locale": "1.4.0", + "read-pkg-up": "1.0.1", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "1.0.2", + "which-module": "1.0.0", + "y18n": "3.2.1", + "yargs-parser": "5.0.0" } }, "yargs-parser": { @@ -15219,7 +15213,7 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", "requires": { - "camelcase": "^3.0.0" + "camelcase": "3.0.0" } } } @@ -15229,12 +15223,12 @@ "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.1.0.tgz", "integrity": "sha512-+G+BKGglmZM2GUSfT9TLuEp6tzehHPjAMoRRItOojWIqIGPloVCMhNIQuG639eJ+y033PaGTSjLaTHts8Kw79w==", "requires": { - "clone-deep": "^2.0.1", - "loader-utils": "^1.0.1", - "lodash.tail": "^4.1.1", - "neo-async": "^2.5.0", - "pify": "^3.0.0", - "semver": "^5.5.0" + "clone-deep": "2.0.2", + "loader-utils": "1.2.3", + "lodash.tail": "4.1.1", + "neo-async": "2.6.0", + "pify": "3.0.0", + "semver": "5.6.0" }, "dependencies": { "clone-deep": { @@ -15242,10 +15236,10 @@ "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-2.0.2.tgz", "integrity": "sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ==", "requires": { - "for-own": "^1.0.0", - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.0", - "shallow-clone": "^1.0.0" + "for-own": "1.0.0", + "is-plain-object": "2.0.4", + "kind-of": "6.0.2", + "shallow-clone": "1.0.0" } }, "for-own": { @@ -15253,7 +15247,7 @@ "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", "requires": { - "for-in": "^1.0.1" + "for-in": "1.0.2" } }, "kind-of": { @@ -15271,9 +15265,9 @@ "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-1.0.0.tgz", "integrity": "sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==", "requires": { - "is-extendable": "^0.1.1", - "kind-of": "^5.0.0", - "mixin-object": "^2.0.1" + "is-extendable": "0.1.1", + "kind-of": "5.1.0", + "mixin-object": "2.0.1" }, "dependencies": { "kind-of": { @@ -15295,7 +15289,7 @@ "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.5.tgz", "integrity": "sha512-2mgiX2VOarcQv8G40WdJ5QJniYdsPr0yGedkd98PqApodsS9DG29qyHl/X65OILm7Bapd1/zUUvTHVZwNLhXvQ==", "requires": { - "xmlchars": "^1.3.1" + "xmlchars": "1.3.1" } }, "scheduler": { @@ -15303,8 +15297,8 @@ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.12.0.tgz", "integrity": "sha512-t7MBR28Akcp4Jm+QoR63XgAi9YgCUmgvDHqf5otgAj4QvdoBE4ImCX0ffehefePPG+aitiYHp0g/mW6s4Tp+dw==", "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "loose-envify": "1.4.0", + "object-assign": "4.1.1" } }, "schema-utils": { @@ -15312,9 +15306,9 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" + "ajv": "6.6.2", + "ajv-errors": "1.0.1", + "ajv-keywords": "3.2.0" } }, "scss-tokenizer": { @@ -15322,8 +15316,8 @@ "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", "requires": { - "js-base64": "^2.1.8", - "source-map": "^0.4.2" + "js-base64": "2.5.0", + "source-map": "0.4.4" }, "dependencies": { "source-map": { @@ -15331,7 +15325,7 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "requires": { - "amdefine": ">=0.0.4" + "amdefine": "1.0.1" } } } @@ -15365,18 +15359,18 @@ "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", "requires": { "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", + "depd": "1.1.2", + "destroy": "1.0.4", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "etag": "1.8.1", "fresh": "0.5.2", - "http-errors": "~1.6.2", + "http-errors": "1.6.3", "mime": "1.4.1", "ms": "2.0.0", - "on-finished": "~2.3.0", - "range-parser": "~1.2.0", - "statuses": "~1.4.0" + "on-finished": "2.3.0", + "range-parser": "1.2.0", + "statuses": "1.4.0" }, "dependencies": { "debug": { @@ -15409,13 +15403,13 @@ "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", "requires": { - "accepts": "~1.3.4", + "accepts": "1.3.5", "batch": "0.6.1", "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" + "escape-html": "1.0.3", + "http-errors": "1.6.3", + "mime-types": "2.1.21", + "parseurl": "1.3.2" }, "dependencies": { "debug": { @@ -15438,9 +15432,9 @@ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.2", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "parseurl": "1.3.2", "send": "0.16.2" } }, @@ -15454,10 +15448,10 @@ "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "2.0.4", + "split-string": "3.1.0" }, "dependencies": { "extend-shallow": { @@ -15465,7 +15459,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -15485,8 +15479,8 @@ "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "inherits": "2.0.3", + "safe-buffer": "5.1.2" } }, "shallow-clone": { @@ -15494,10 +15488,10 @@ "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-0.1.2.tgz", "integrity": "sha1-WQnodLp3EG1zrEFM/sH/yofZcGA=", "requires": { - "is-extendable": "^0.1.1", - "kind-of": "^2.0.1", - "lazy-cache": "^0.2.3", - "mixin-object": "^2.0.1" + "is-extendable": "0.1.1", + "kind-of": "2.0.1", + "lazy-cache": "0.2.7", + "mixin-object": "2.0.1" }, "dependencies": { "kind-of": { @@ -15505,7 +15499,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz", "integrity": "sha1-AY7HpM5+OobLkUG+UZ0kyPqpgbU=", "requires": { - "is-buffer": "^1.0.2" + "is-buffer": "1.1.6" } }, "lazy-cache": { @@ -15520,7 +15514,7 @@ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "requires": { - "shebang-regex": "^1.0.0" + "shebang-regex": "1.0.0" } }, "shebang-regex": { @@ -15533,10 +15527,10 @@ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", "requires": { - "array-filter": "~0.0.0", - "array-map": "~0.0.0", - "array-reduce": "~0.0.0", - "jsonify": "~0.0.0" + "array-filter": "0.0.1", + "array-map": "0.0.0", + "array-reduce": "0.0.0", + "jsonify": "0.0.0" } }, "shellwords": { @@ -15554,7 +15548,7 @@ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", "requires": { - "is-arrayish": "^0.3.1" + "is-arrayish": "0.3.2" }, "dependencies": { "is-arrayish": { @@ -15579,7 +15573,7 @@ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", "requires": { - "is-fullwidth-code-point": "^2.0.0" + "is-fullwidth-code-point": "2.0.0" } }, "snapdragon": { @@ -15587,14 +15581,14 @@ "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" + "base": "0.11.2", + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "map-cache": "0.2.2", + "source-map": "0.5.7", + "source-map-resolve": "0.5.2", + "use": "3.1.1" }, "dependencies": { "debug": { @@ -15610,7 +15604,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "extend-shallow": { @@ -15618,7 +15612,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } }, "ms": { @@ -15633,9 +15627,9 @@ "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" + "define-property": "1.0.0", + "isobject": "3.0.1", + "snapdragon-util": "3.0.1" }, "dependencies": { "define-property": { @@ -15643,7 +15637,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "is-accessor-descriptor": { @@ -15651,7 +15645,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { @@ -15659,7 +15653,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { @@ -15667,9 +15661,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } }, "kind-of": { @@ -15684,7 +15678,7 @@ "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "requires": { - "kind-of": "^3.2.0" + "kind-of": "3.2.2" } }, "sockjs": { @@ -15692,8 +15686,8 @@ "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz", "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==", "requires": { - "faye-websocket": "^0.10.0", - "uuid": "^3.0.1" + "faye-websocket": "0.10.0", + "uuid": "3.3.2" }, "dependencies": { "faye-websocket": { @@ -15701,7 +15695,7 @@ "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", "requires": { - "websocket-driver": ">=0.5.1" + "websocket-driver": "0.7.0" } } } @@ -15711,12 +15705,12 @@ "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.1.5.tgz", "integrity": "sha1-G7fA9yIsQPQq3xT0RCy9Eml3GoM=", "requires": { - "debug": "^2.6.6", + "debug": "2.6.9", "eventsource": "0.1.6", - "faye-websocket": "~0.11.0", - "inherits": "^2.0.1", - "json3": "^3.3.2", - "url-parse": "^1.1.8" + "faye-websocket": "0.11.1", + "inherits": "2.0.3", + "json3": "3.3.2", + "url-parse": "1.4.4" }, "dependencies": { "debug": { @@ -15749,11 +15743,11 @@ "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", "requires": { - "atob": "^2.1.1", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" + "atob": "2.1.2", + "decode-uri-component": "0.2.0", + "resolve-url": "0.2.1", + "source-map-url": "0.4.0", + "urix": "0.1.0" } }, "source-map-support": { @@ -15761,7 +15755,7 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", "requires": { - "source-map": "^0.5.6" + "source-map": "0.5.7" } }, "source-map-url": { @@ -15774,8 +15768,8 @@ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" + "spdx-expression-parse": "3.0.0", + "spdx-license-ids": "3.0.3" } }, "spdx-exceptions": { @@ -15788,8 +15782,8 @@ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "spdx-exceptions": "2.2.0", + "spdx-license-ids": "3.0.3" } }, "spdx-license-ids": { @@ -15802,11 +15796,11 @@ "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.0.tgz", "integrity": "sha512-ot0oEGT/PGUpzf/6uk4AWLqkq+irlqHXkrdbk51oWONh3bxQmBuljxPNl66zlRRcIJStWq0QkLUCPOPjgjvU0Q==", "requires": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" + "debug": "4.1.1", + "handle-thing": "2.0.0", + "http-deceiver": "1.2.7", + "select-hose": "2.0.0", + "spdy-transport": "3.0.0" } }, "spdy-transport": { @@ -15814,12 +15808,12 @@ "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", "requires": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" + "debug": "4.1.1", + "detect-node": "2.0.4", + "hpack.js": "2.1.6", + "obuf": "1.1.2", + "readable-stream": "3.1.1", + "wbuf": "1.7.3" }, "dependencies": { "readable-stream": { @@ -15827,9 +15821,9 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.1.1.tgz", "integrity": "sha512-DkN66hPyqDhnIQ6Jcsvx9bFjhw214O4poMBcIMgPVpQvNy9a0e0Uhg5SqySyDKAmUlwt8LonTBz1ezOnM8pUdA==", "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "inherits": "2.0.3", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } } } @@ -15839,7 +15833,7 @@ "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", "requires": { - "extend-shallow": "^3.0.0" + "extend-shallow": "3.0.2" } }, "sprintf-js": { @@ -15852,15 +15846,15 @@ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.0.tgz", "integrity": "sha512-Zhev35/y7hRMcID/upReIvRse+I9SVhyVre/KTJSJQWMz3C3+G+HpO7m1wK/yckEtujKZ7dS4hkVxAnmHaIGVQ==", "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" + "asn1": "0.2.4", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.2", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.2", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "safer-buffer": "2.1.2", + "tweetnacl": "0.14.5" } }, "ssri": { @@ -15868,7 +15862,7 @@ "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", "requires": { - "figgy-pudding": "^3.5.1" + "figgy-pudding": "3.5.1" } }, "stable": { @@ -15886,8 +15880,8 @@ "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" + "define-property": "0.2.5", + "object-copy": "0.1.0" }, "dependencies": { "define-property": { @@ -15895,7 +15889,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } } } @@ -15910,7 +15904,7 @@ "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==", "requires": { - "readable-stream": "^2.0.1" + "readable-stream": "2.3.6" } }, "stealthy-require": { @@ -15923,8 +15917,8 @@ "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", "requires": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" + "inherits": "2.0.3", + "readable-stream": "2.3.6" } }, "stream-each": { @@ -15932,8 +15926,8 @@ "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", "requires": { - "end-of-stream": "^1.1.0", - "stream-shift": "^1.0.0" + "end-of-stream": "1.4.1", + "stream-shift": "1.0.0" } }, "stream-http": { @@ -15941,11 +15935,11 @@ "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", "requires": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.3.6", - "to-arraybuffer": "^1.0.0", - "xtend": "^4.0.0" + "builtin-status-codes": "3.0.0", + "inherits": "2.0.3", + "readable-stream": "2.3.6", + "to-arraybuffer": "1.0.1", + "xtend": "4.0.1" } }, "stream-shift": { @@ -15963,8 +15957,8 @@ "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", "requires": { - "astral-regex": "^1.0.0", - "strip-ansi": "^4.0.0" + "astral-regex": "1.0.0", + "strip-ansi": "4.0.0" }, "dependencies": { "ansi-regex": { @@ -15977,7 +15971,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "3.0.0" } } } @@ -15987,8 +15981,8 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" }, "dependencies": { "ansi-regex": { @@ -16001,7 +15995,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "3.0.0" } } } @@ -16011,7 +16005,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } }, "stringify-object": { @@ -16019,9 +16013,9 @@ "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", "requires": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" + "get-own-enumerable-property-symbols": "3.0.0", + "is-obj": "1.0.1", + "is-regexp": "1.0.0" } }, "strip-ansi": { @@ -16029,7 +16023,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "strip-bom": { @@ -16037,7 +16031,7 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "requires": { - "is-utf8": "^0.2.0" + "is-utf8": "0.2.1" } }, "strip-comments": { @@ -16045,8 +16039,8 @@ "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-1.0.2.tgz", "integrity": "sha512-kL97alc47hoyIQSV165tTt9rG5dn4w1dNnBhOQ3bOU1Nc1hel09jnXANaHJ7vzHLd4Ju8kseDGzlev96pghLFw==", "requires": { - "babel-extract-comments": "^1.0.0", - "babel-plugin-transform-object-rest-spread": "^6.26.0" + "babel-extract-comments": "1.0.0", + "babel-plugin-transform-object-rest-spread": "6.26.0" } }, "strip-eof": { @@ -16059,7 +16053,7 @@ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", "requires": { - "get-stdin": "^4.0.1" + "get-stdin": "4.0.1" } }, "strip-json-comments": { @@ -16072,8 +16066,8 @@ "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.0.tgz", "integrity": "sha512-uCcN7XWHkqwGVt7skpInW6IGO1tG6ReyFQ1Cseh0VcN6VdcFQi62aG/2F3Y9ueA8x4IVlfaSUxpmQXQD9QrEuQ==", "requires": { - "loader-utils": "^1.1.0", - "schema-utils": "^0.4.5" + "loader-utils": "1.2.3", + "schema-utils": "0.4.7" }, "dependencies": { "schema-utils": { @@ -16081,8 +16075,8 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz", "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==", "requires": { - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0" + "ajv": "6.6.2", + "ajv-keywords": "3.2.0" } } } @@ -16092,9 +16086,9 @@ "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.1.tgz", "integrity": "sha512-TK5zEPeD9NyC1uPIdjikzsgWxdQQN/ry1X3d1iOz1UkYDCmcr928gWD1KHgyC27F50UnE0xCTrBOO1l6KR8M4w==", "requires": { - "browserslist": "^4.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0" + "browserslist": "4.3.7", + "postcss": "7.0.8", + "postcss-selector-parser": "3.1.1" }, "dependencies": { "chalk": { @@ -16102,9 +16096,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -16112,7 +16106,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -16122,9 +16116,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.8.tgz", "integrity": "sha512-WudsIzuTKRw9IInRTPBgVXJ7DKR26HT09Rxp0g3w0Fqh3TUtYICcUmvC0xURj04o3vdcDtnjCAUCECg/p341iQ==", "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.0.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "6.0.0" } }, "postcss-selector-parser": { @@ -16132,9 +16126,9 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", "requires": { - "dot-prop": "^4.1.1", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" + "dot-prop": "4.2.0", + "indexes-of": "1.0.1", + "uniq": "1.0.1" } }, "source-map": { @@ -16147,7 +16141,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -16157,7 +16151,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } }, "svgo": { @@ -16165,20 +16159,20 @@ "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.1.1.tgz", "integrity": "sha512-GBkJbnTuFpM4jFbiERHDWhZc/S/kpHToqmZag3aEBjPYK44JAN2QBjvrGIxLOoCyMZjuFQIfTO2eJd8uwLY/9g==", "requires": { - "coa": "~2.0.1", - "colors": "~1.1.2", - "css-select": "^2.0.0", - "css-select-base-adapter": "~0.1.0", + "coa": "2.0.2", + "colors": "1.1.2", + "css-select": "2.0.2", + "css-select-base-adapter": "0.1.1", "css-tree": "1.0.0-alpha.28", - "css-url-regex": "^1.1.0", - "csso": "^3.5.0", - "js-yaml": "^3.12.0", - "mkdirp": "~0.5.1", - "object.values": "^1.0.4", - "sax": "~1.2.4", - "stable": "~0.1.6", - "unquote": "~1.1.1", - "util.promisify": "~1.0.0" + "css-url-regex": "1.1.0", + "csso": "3.5.1", + "js-yaml": "3.12.1", + "mkdirp": "0.5.1", + "object.values": "1.1.0", + "sax": "1.2.4", + "stable": "0.1.8", + "unquote": "1.1.1", + "util.promisify": "1.0.0" } }, "symbol-observable": { @@ -16196,12 +16190,12 @@ "resolved": "https://registry.npmjs.org/table/-/table-4.0.3.tgz", "integrity": "sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg==", "requires": { - "ajv": "^6.0.1", - "ajv-keywords": "^3.0.0", - "chalk": "^2.1.0", - "lodash": "^4.17.4", + "ajv": "6.6.2", + "ajv-keywords": "3.2.0", + "chalk": "2.4.1", + "lodash": "4.17.11", "slice-ansi": "1.0.0", - "string-width": "^2.1.1" + "string-width": "2.1.1" } }, "tapable": { @@ -16214,9 +16208,9 @@ "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", "requires": { - "block-stream": "*", - "fstream": "^1.0.2", - "inherits": "2" + "block-stream": "0.0.9", + "fstream": "1.0.11", + "inherits": "2.0.3" } }, "terser": { @@ -16224,9 +16218,9 @@ "resolved": "https://registry.npmjs.org/terser/-/terser-3.14.1.tgz", "integrity": "sha512-NSo3E99QDbYSMeJaEk9YW2lTg3qS9V0aKGlb+PlOrei1X02r1wSBHCNX/O+yeTRFSWPKPIGj6MqvvdqV4rnVGw==", "requires": { - "commander": "~2.17.1", - "source-map": "~0.6.1", - "source-map-support": "~0.5.6" + "commander": "2.17.1", + "source-map": "0.6.1", + "source-map-support": "0.5.9" }, "dependencies": { "commander": { @@ -16244,8 +16238,8 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz", "integrity": "sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==", "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "buffer-from": "1.1.1", + "source-map": "0.6.1" } } } @@ -16255,14 +16249,14 @@ "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.1.0.tgz", "integrity": "sha512-61lV0DSxMAZ8AyZG7/A4a3UPlrbOBo8NIQ4tJzLPAdGOQ+yoNC7l5ijEow27lBAL2humer01KLS6bGIMYQxKoA==", "requires": { - "cacache": "^11.0.2", - "find-cache-dir": "^2.0.0", - "schema-utils": "^1.0.0", - "serialize-javascript": "^1.4.0", - "source-map": "^0.6.1", - "terser": "^3.8.1", - "webpack-sources": "^1.1.0", - "worker-farm": "^1.5.2" + "cacache": "11.3.2", + "find-cache-dir": "2.0.0", + "schema-utils": "1.0.0", + "serialize-javascript": "1.6.1", + "source-map": "0.6.1", + "terser": "3.14.1", + "webpack-sources": "1.3.0", + "worker-farm": "1.6.0" }, "dependencies": { "find-cache-dir": { @@ -16270,9 +16264,9 @@ "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.0.0.tgz", "integrity": "sha512-LDUY6V1Xs5eFskUVYtIwatojt6+9xC9Chnlk/jYOOvn3FAFfSaWddxahDGyNHh0b2dMXa6YW2m0tk8TdVaXHlA==", "requires": { - "commondir": "^1.0.1", - "make-dir": "^1.0.0", - "pkg-dir": "^3.0.0" + "commondir": "1.0.1", + "make-dir": "1.3.0", + "pkg-dir": "3.0.0" } }, "find-up": { @@ -16280,7 +16274,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "requires": { - "locate-path": "^3.0.0" + "locate-path": "3.0.0" } }, "locate-path": { @@ -16288,8 +16282,8 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "p-locate": "3.0.0", + "path-exists": "3.0.0" } }, "p-limit": { @@ -16297,7 +16291,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", "requires": { - "p-try": "^2.0.0" + "p-try": "2.0.0" } }, "p-locate": { @@ -16305,7 +16299,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "requires": { - "p-limit": "^2.0.0" + "p-limit": "2.1.0" } }, "p-try": { @@ -16318,7 +16312,7 @@ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", "requires": { - "find-up": "^3.0.0" + "find-up": "3.0.0" } }, "source-map": { @@ -16333,11 +16327,11 @@ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.2.3.tgz", "integrity": "sha512-SYbXgY64PT+4GAL2ocI3HwPa4Q4TBKm0cwAVeKOt/Aoc0gSpNRjJX8w0pA1LMKZ3LBmd8pYBqApFNQLII9kavA==", "requires": { - "arrify": "^1.0.1", - "micromatch": "^2.3.11", - "object-assign": "^4.1.0", - "read-pkg-up": "^1.0.1", - "require-main-filename": "^1.0.1" + "arrify": "1.0.1", + "micromatch": "2.3.11", + "object-assign": "4.1.1", + "read-pkg-up": "1.0.1", + "require-main-filename": "1.0.1" } }, "text-table": { @@ -16360,8 +16354,8 @@ "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" + "readable-stream": "2.3.6", + "xtend": "4.0.1" } }, "thunky": { @@ -16374,7 +16368,7 @@ "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz", "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==", "requires": { - "setimmediate": "^1.0.4" + "setimmediate": "1.0.5" } }, "timsort": { @@ -16387,7 +16381,7 @@ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "requires": { - "os-tmpdir": "~1.0.2" + "os-tmpdir": "1.0.2" } }, "tmpl": { @@ -16410,7 +16404,7 @@ "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" } }, "to-regex": { @@ -16418,10 +16412,10 @@ "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "regex-not": "1.0.2", + "safe-regex": "1.1.0" } }, "to-regex-range": { @@ -16429,8 +16423,8 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "is-number": "3.0.0", + "repeat-string": "1.6.1" }, "dependencies": { "is-number": { @@ -16438,7 +16432,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" } } } @@ -16448,7 +16442,7 @@ "resolved": "https://registry.npmjs.org/topo/-/topo-2.0.2.tgz", "integrity": "sha1-zVYVdSU5BXwNwEkaYhw7xvvh0YI=", "requires": { - "hoek": "4.x.x" + "hoek": "4.2.1" } }, "tough-cookie": { @@ -16456,8 +16450,8 @@ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" + "psl": "1.1.31", + "punycode": "2.1.1" } }, "tr46": { @@ -16465,7 +16459,7 @@ "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", "requires": { - "punycode": "^2.1.0" + "punycode": "2.1.1" } }, "trim-newlines": { @@ -16483,7 +16477,7 @@ "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz", "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==", "requires": { - "glob": "^7.1.2" + "glob": "7.1.3" } }, "tryer": { @@ -16506,7 +16500,7 @@ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "requires": { - "safe-buffer": "^5.0.1" + "safe-buffer": "5.1.2" } }, "tweetnacl": { @@ -16519,7 +16513,7 @@ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "requires": { - "prelude-ls": "~1.1.2" + "prelude-ls": "1.1.2" } }, "type-is": { @@ -16528,7 +16522,7 @@ "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", "requires": { "media-typer": "0.3.0", - "mime-types": "~2.1.18" + "mime-types": "2.1.21" } }, "typedarray": { @@ -16556,8 +16550,8 @@ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==", "requires": { - "commander": "~2.17.1", - "source-map": "~0.6.1" + "commander": "2.17.1", + "source-map": "0.6.1" }, "dependencies": { "commander": { @@ -16577,14 +16571,14 @@ "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.3.0.tgz", "integrity": "sha512-ovHIch0AMlxjD/97j9AYovZxG5wnHOPkL7T1GKochBADp/Zwc44pEWNqpKl1Loupp1WhFg7SlYmHZRUfdAacgw==", "requires": { - "cacache": "^10.0.4", - "find-cache-dir": "^1.0.0", - "schema-utils": "^0.4.5", - "serialize-javascript": "^1.4.0", - "source-map": "^0.6.1", - "uglify-es": "^3.3.4", - "webpack-sources": "^1.1.0", - "worker-farm": "^1.5.2" + "cacache": "10.0.4", + "find-cache-dir": "1.0.0", + "schema-utils": "0.4.7", + "serialize-javascript": "1.6.1", + "source-map": "0.6.1", + "uglify-es": "3.3.9", + "webpack-sources": "1.3.0", + "worker-farm": "1.6.0" }, "dependencies": { "cacache": { @@ -16592,19 +16586,19 @@ "resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz", "integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==", "requires": { - "bluebird": "^3.5.1", - "chownr": "^1.0.1", - "glob": "^7.1.2", - "graceful-fs": "^4.1.11", - "lru-cache": "^4.1.1", - "mississippi": "^2.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.2", - "ssri": "^5.2.4", - "unique-filename": "^1.1.0", - "y18n": "^4.0.0" + "bluebird": "3.5.3", + "chownr": "1.1.1", + "glob": "7.1.3", + "graceful-fs": "4.1.15", + "lru-cache": "4.1.5", + "mississippi": "2.0.0", + "mkdirp": "0.5.1", + "move-concurrently": "1.0.1", + "promise-inflight": "1.0.1", + "rimraf": "2.6.3", + "ssri": "5.3.0", + "unique-filename": "1.1.1", + "y18n": "4.0.0" } }, "commander": { @@ -16617,16 +16611,16 @@ "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-2.0.0.tgz", "integrity": "sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==", "requires": { - "concat-stream": "^1.5.0", - "duplexify": "^3.4.2", - "end-of-stream": "^1.1.0", - "flush-write-stream": "^1.0.0", - "from2": "^2.1.0", - "parallel-transform": "^1.1.0", - "pump": "^2.0.1", - "pumpify": "^1.3.3", - "stream-each": "^1.1.0", - "through2": "^2.0.0" + "concat-stream": "1.6.2", + "duplexify": "3.6.1", + "end-of-stream": "1.4.1", + "flush-write-stream": "1.0.3", + "from2": "2.3.0", + "parallel-transform": "1.1.0", + "pump": "2.0.1", + "pumpify": "1.5.1", + "stream-each": "1.2.3", + "through2": "2.0.5" } }, "pump": { @@ -16634,8 +16628,8 @@ "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "end-of-stream": "1.4.1", + "once": "1.4.0" } }, "schema-utils": { @@ -16643,8 +16637,8 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz", "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==", "requires": { - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0" + "ajv": "6.6.2", + "ajv-keywords": "3.2.0" } }, "source-map": { @@ -16657,7 +16651,7 @@ "resolved": "https://registry.npmjs.org/ssri/-/ssri-5.3.0.tgz", "integrity": "sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==", "requires": { - "safe-buffer": "^5.1.1" + "safe-buffer": "5.1.2" } }, "uglify-es": { @@ -16665,8 +16659,8 @@ "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz", "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==", "requires": { - "commander": "~2.13.0", - "source-map": "~0.6.1" + "commander": "2.13.0", + "source-map": "0.6.1" } }, "y18n": { @@ -16686,8 +16680,8 @@ "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", "requires": { - "unicode-canonical-property-names-ecmascript": "^1.0.4", - "unicode-property-aliases-ecmascript": "^1.0.4" + "unicode-canonical-property-names-ecmascript": "1.0.4", + "unicode-property-aliases-ecmascript": "1.0.4" } }, "unicode-match-property-value-ecmascript": { @@ -16705,10 +16699,10 @@ "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^0.4.3" + "arr-union": "3.1.0", + "get-value": "2.0.6", + "is-extendable": "0.1.1", + "set-value": "0.4.3" }, "dependencies": { "extend-shallow": { @@ -16716,7 +16710,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } }, "set-value": { @@ -16724,10 +16718,10 @@ "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "2.0.4", + "to-object-path": "0.3.0" } } } @@ -16747,7 +16741,7 @@ "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", "requires": { - "unique-slug": "^2.0.0" + "unique-slug": "2.0.1" } }, "unique-slug": { @@ -16755,7 +16749,7 @@ "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.1.tgz", "integrity": "sha512-n9cU6+gITaVu7VGj1Z8feKMmfAjEAQGhwD9fE3zvpRRa0wEIx8ODYkVGfSc94M2OX00tUFV8wH3zYbm1I8mxFg==", "requires": { - "imurmurhash": "^0.1.4" + "imurmurhash": "0.1.4" } }, "universalify": { @@ -16778,8 +16772,8 @@ "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" + "has-value": "0.3.1", + "isobject": "3.0.1" }, "dependencies": { "has-value": { @@ -16787,9 +16781,9 @@ "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" + "get-value": "2.0.6", + "has-values": "0.1.4", + "isobject": "2.1.0" }, "dependencies": { "isobject": { @@ -16829,7 +16823,7 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", "requires": { - "punycode": "^2.1.0" + "punycode": "2.1.1" } }, "urix": { @@ -16858,9 +16852,9 @@ "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-1.1.1.tgz", "integrity": "sha512-vugEeXjyYFBCUOpX+ZuaunbK3QXMKaQ3zUnRfIpRBlGkY7QizCnzyyn2ASfcxsvyU3ef+CJppVywnl3Kgf13Gg==", "requires": { - "loader-utils": "^1.1.0", - "mime": "^2.0.3", - "schema-utils": "^1.0.0" + "loader-utils": "1.2.3", + "mime": "2.4.0", + "schema-utils": "1.0.0" } }, "url-parse": { @@ -16868,8 +16862,8 @@ "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.4.tgz", "integrity": "sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg==", "requires": { - "querystringify": "^2.0.0", - "requires-port": "^1.0.0" + "querystringify": "2.1.0", + "requires-port": "1.0.0" } }, "use": { @@ -16895,8 +16889,8 @@ "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", "requires": { - "define-properties": "^1.1.2", - "object.getownpropertydescriptors": "^2.0.3" + "define-properties": "1.1.3", + "object.getownpropertydescriptors": "2.0.3" } }, "utila": { @@ -16924,8 +16918,8 @@ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" + "spdx-correct": "3.1.0", + "spdx-expression-parse": "3.0.0" } }, "value-equal": { @@ -16948,9 +16942,9 @@ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "requires": { - "assert-plus": "^1.0.0", + "assert-plus": "1.0.0", "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" + "extsprintf": "1.3.0" } }, "vm-browserify": { @@ -16966,7 +16960,7 @@ "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", "requires": { - "browser-process-hrtime": "^0.1.2" + "browser-process-hrtime": "0.1.3" } }, "w3c-xmlserializer": { @@ -16974,9 +16968,9 @@ "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-1.0.1.tgz", "integrity": "sha512-XZGI1OH/OLQr/NaJhhPmzhngwcAnZDLytsvXnRmlYeRkmbb0I7sqFFA22erq4WQR0sUu17ZSQOAV9mFwCqKRNg==", "requires": { - "domexception": "^1.0.1", - "webidl-conversions": "^4.0.2", - "xml-name-validator": "^3.0.0" + "domexception": "1.0.1", + "webidl-conversions": "4.0.2", + "xml-name-validator": "3.0.0" } }, "walker": { @@ -16984,7 +16978,7 @@ "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", "requires": { - "makeerror": "1.0.x" + "makeerror": "1.0.11" } }, "warning": { @@ -16992,7 +16986,7 @@ "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.2.tgz", "integrity": "sha512-wbTp09q/9C+jJn4KKJfJfoS6VleK/Dti0yqWSm6KMvJ4MRCXFQNapHuJXutJIrWV0Cf4AhTdeIe4qdKHR1+Hug==", "requires": { - "loose-envify": "^1.0.0" + "loose-envify": "1.4.0" } }, "watch": { @@ -17000,8 +16994,8 @@ "resolved": "https://registry.npmjs.org/watch/-/watch-0.18.0.tgz", "integrity": "sha1-KAlUdsbffJDJYxOJkMClQj60uYY=", "requires": { - "exec-sh": "^0.2.0", - "minimist": "^1.2.0" + "exec-sh": "0.2.2", + "minimist": "1.2.0" } }, "watchpack": { @@ -17009,9 +17003,9 @@ "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==", "requires": { - "chokidar": "^2.0.2", - "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0" + "chokidar": "2.0.4", + "graceful-fs": "4.1.15", + "neo-async": "2.6.0" } }, "wbuf": { @@ -17019,7 +17013,7 @@ "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "requires": { - "minimalistic-assert": "^1.0.0" + "minimalistic-assert": "1.0.1" } }, "webidl-conversions": { @@ -17036,26 +17030,26 @@ "@webassemblyjs/helper-module-context": "1.7.6", "@webassemblyjs/wasm-edit": "1.7.6", "@webassemblyjs/wasm-parser": "1.7.6", - "acorn": "^5.6.2", - "acorn-dynamic-import": "^3.0.0", - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0", - "chrome-trace-event": "^1.0.0", - "enhanced-resolve": "^4.1.0", - "eslint-scope": "^4.0.0", - "json-parse-better-errors": "^1.0.2", - "loader-runner": "^2.3.0", - "loader-utils": "^1.1.0", - "memory-fs": "~0.4.1", - "micromatch": "^3.1.8", - "mkdirp": "~0.5.0", - "neo-async": "^2.5.0", - "node-libs-browser": "^2.0.0", - "schema-utils": "^0.4.4", - "tapable": "^1.1.0", - "uglifyjs-webpack-plugin": "^1.2.4", - "watchpack": "^1.5.0", - "webpack-sources": "^1.2.0" + "acorn": "5.7.3", + "acorn-dynamic-import": "3.0.0", + "ajv": "6.6.2", + "ajv-keywords": "3.2.0", + "chrome-trace-event": "1.0.0", + "enhanced-resolve": "4.1.0", + "eslint-scope": "4.0.0", + "json-parse-better-errors": "1.0.2", + "loader-runner": "2.3.1", + "loader-utils": "1.2.3", + "memory-fs": "0.4.1", + "micromatch": "3.1.10", + "mkdirp": "0.5.1", + "neo-async": "2.6.0", + "node-libs-browser": "2.1.0", + "schema-utils": "0.4.7", + "tapable": "1.1.1", + "uglifyjs-webpack-plugin": "1.3.0", + "watchpack": "1.6.0", + "webpack-sources": "1.3.0" }, "dependencies": { "acorn": { @@ -17078,16 +17072,16 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" + "arr-flatten": "1.1.0", + "array-unique": "0.3.2", + "extend-shallow": "2.0.1", + "fill-range": "4.0.0", + "isobject": "3.0.1", + "repeat-element": "1.1.3", + "snapdragon": "0.8.2", + "snapdragon-node": "2.1.1", + "split-string": "3.1.0", + "to-regex": "3.0.2" }, "dependencies": { "extend-shallow": { @@ -17095,7 +17089,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -17113,8 +17107,8 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" + "esrecurse": "4.2.1", + "estraverse": "4.2.0" } }, "expand-brackets": { @@ -17122,13 +17116,13 @@ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "posix-character-classes": "0.1.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -17136,7 +17130,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "extend-shallow": { @@ -17144,7 +17138,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } }, "is-accessor-descriptor": { @@ -17152,7 +17146,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -17160,7 +17154,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -17170,7 +17164,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -17178,7 +17172,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -17188,9 +17182,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" } }, "kind-of": { @@ -17205,14 +17199,14 @@ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "array-unique": "0.3.2", + "define-property": "1.0.0", + "expand-brackets": "2.1.4", + "extend-shallow": "2.0.1", + "fragment-cache": "0.2.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -17220,7 +17214,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "extend-shallow": { @@ -17228,7 +17222,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -17238,10 +17232,10 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" + "extend-shallow": "2.0.1", + "is-number": "3.0.0", + "repeat-string": "1.6.1", + "to-regex-range": "2.1.1" }, "dependencies": { "extend-shallow": { @@ -17249,7 +17243,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -17259,7 +17253,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { @@ -17267,7 +17261,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { @@ -17275,9 +17269,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } }, "is-number": { @@ -17285,7 +17279,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -17293,7 +17287,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -17308,19 +17302,19 @@ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "braces": "2.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "extglob": "2.0.4", + "fragment-cache": "0.2.1", + "kind-of": "6.0.2", + "nanomatch": "1.2.13", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" } }, "ms": { @@ -17333,8 +17327,8 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz", "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==", "requires": { - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0" + "ajv": "6.6.2", + "ajv-keywords": "3.2.0" } } } @@ -17344,10 +17338,10 @@ "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.4.0.tgz", "integrity": "sha512-Q9Iyc0X9dP9bAsYskAVJ/hmIZZQwf/3Sy4xCAZgL5cUkjZmUZLt4l5HpbST/Pdgjn3u6pE7u5OdGd1apgzRujA==", "requires": { - "memory-fs": "~0.4.1", - "mime": "^2.3.1", - "range-parser": "^1.0.3", - "webpack-log": "^2.0.0" + "memory-fs": "0.4.1", + "mime": "2.4.0", + "range-parser": "1.2.0", + "webpack-log": "2.0.0" } }, "webpack-dev-server": { @@ -17356,34 +17350,34 @@ "integrity": "sha512-mGXDgz5SlTxcF3hUpfC8hrQ11yhAttuUQWf1Wmb+6zo3x6rb7b9mIfuQvAPLdfDRCGRGvakBWHdHOa0I9p/EVQ==", "requires": { "ansi-html": "0.0.7", - "bonjour": "^3.5.0", - "chokidar": "^2.0.0", - "compression": "^1.5.2", - "connect-history-api-fallback": "^1.3.0", - "debug": "^3.1.0", - "del": "^3.0.0", - "express": "^4.16.2", - "html-entities": "^1.2.0", - "http-proxy-middleware": "~0.18.0", - "import-local": "^2.0.0", - "internal-ip": "^3.0.1", - "ip": "^1.1.5", - "killable": "^1.0.0", - "loglevel": "^1.4.1", - "opn": "^5.1.0", - "portfinder": "^1.0.9", - "schema-utils": "^1.0.0", - "selfsigned": "^1.9.1", - "semver": "^5.6.0", - "serve-index": "^1.7.2", + "bonjour": "3.5.0", + "chokidar": "2.0.4", + "compression": "1.7.3", + "connect-history-api-fallback": "1.6.0", + "debug": "3.2.6", + "del": "3.0.0", + "express": "4.16.4", + "html-entities": "1.2.1", + "http-proxy-middleware": "0.18.0", + "import-local": "2.0.0", + "internal-ip": "3.0.1", + "ip": "1.1.5", + "killable": "1.0.1", + "loglevel": "1.6.1", + "opn": "5.4.0", + "portfinder": "1.0.20", + "schema-utils": "1.0.0", + "selfsigned": "1.10.4", + "semver": "5.6.0", + "serve-index": "1.9.1", "sockjs": "0.3.19", "sockjs-client": "1.3.0", - "spdy": "^4.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^5.1.0", - "url": "^0.11.0", + "spdy": "4.0.0", + "strip-ansi": "3.0.1", + "supports-color": "5.5.0", + "url": "0.11.0", "webpack-dev-middleware": "3.4.0", - "webpack-log": "^2.0.0", + "webpack-log": "2.0.0", "yargs": "12.0.2" }, "dependencies": { @@ -17397,7 +17391,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "requires": { - "ms": "^2.1.1" + "ms": "2.1.1" } }, "decamelize": { @@ -17413,7 +17407,7 @@ "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.0.7.tgz", "integrity": "sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ==", "requires": { - "original": "^1.0.0" + "original": "1.0.2" } }, "execa": { @@ -17421,13 +17415,13 @@ "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "cross-spawn": "6.0.5", + "get-stream": "4.1.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" } }, "find-up": { @@ -17435,7 +17429,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "requires": { - "locate-path": "^3.0.0" + "locate-path": "3.0.0" } }, "get-stream": { @@ -17443,7 +17437,7 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", "requires": { - "pump": "^3.0.0" + "pump": "3.0.0" } }, "import-local": { @@ -17451,8 +17445,8 @@ "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", "requires": { - "pkg-dir": "^3.0.0", - "resolve-cwd": "^2.0.0" + "pkg-dir": "3.0.0", + "resolve-cwd": "2.0.0" } }, "invert-kv": { @@ -17465,7 +17459,7 @@ "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", "requires": { - "invert-kv": "^2.0.0" + "invert-kv": "2.0.0" } }, "locate-path": { @@ -17473,8 +17467,8 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "p-locate": "3.0.0", + "path-exists": "3.0.0" } }, "mem": { @@ -17482,9 +17476,9 @@ "resolved": "https://registry.npmjs.org/mem/-/mem-4.0.0.tgz", "integrity": "sha512-WQxG/5xYc3tMbYLXoXPm81ET2WDULiU5FxbuIoNbJqLOOI8zehXFdZuiUEgfdrU2mVB1pxBZUGlYORSrpuJreA==", "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^1.0.0", - "p-is-promise": "^1.1.0" + "map-age-cleaner": "0.1.3", + "mimic-fn": "1.2.0", + "p-is-promise": "1.1.0" } }, "os-locale": { @@ -17492,9 +17486,9 @@ "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", "requires": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" + "execa": "1.0.0", + "lcid": "2.0.0", + "mem": "4.0.0" } }, "p-limit": { @@ -17502,7 +17496,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", "requires": { - "p-try": "^2.0.0" + "p-try": "2.0.0" } }, "p-locate": { @@ -17510,7 +17504,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "requires": { - "p-limit": "^2.0.0" + "p-limit": "2.1.0" } }, "p-try": { @@ -17523,7 +17517,7 @@ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", "requires": { - "find-up": "^3.0.0" + "find-up": "3.0.0" } }, "sockjs-client": { @@ -17531,12 +17525,12 @@ "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.3.0.tgz", "integrity": "sha512-R9jxEzhnnrdxLCNln0xg5uGHqMnkhPSTzUZH2eXcR03S/On9Yvoq2wyUZILRUhZCNVu2PmwWVoyuiPz8th8zbg==", "requires": { - "debug": "^3.2.5", - "eventsource": "^1.0.7", - "faye-websocket": "~0.11.1", - "inherits": "^2.0.3", - "json3": "^3.3.2", - "url-parse": "^1.4.3" + "debug": "3.2.6", + "eventsource": "1.0.7", + "faye-websocket": "0.11.1", + "inherits": "2.0.3", + "json3": "3.3.2", + "url-parse": "1.4.4" } }, "yargs": { @@ -17544,18 +17538,18 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.2.tgz", "integrity": "sha512-e7SkEx6N6SIZ5c5H22RTZae61qtn3PYUE8JYbBFlK9sYmh3DMQ6E5ygtaG/2BW0JZi4WGgTR2IV5ChqlqrDGVQ==", "requires": { - "cliui": "^4.0.0", - "decamelize": "^2.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1 || ^4.0.0", - "yargs-parser": "^10.1.0" + "cliui": "4.1.0", + "decamelize": "2.0.0", + "find-up": "3.0.0", + "get-caller-file": "1.0.3", + "os-locale": "3.1.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "10.1.0" } }, "yargs-parser": { @@ -17563,7 +17557,7 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", "requires": { - "camelcase": "^4.1.0" + "camelcase": "4.1.0" } } } @@ -17573,8 +17567,8 @@ "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", "requires": { - "ansi-colors": "^3.0.0", - "uuid": "^3.3.2" + "ansi-colors": "3.2.3", + "uuid": "3.3.2" } }, "webpack-manifest-plugin": { @@ -17582,9 +17576,9 @@ "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-2.0.4.tgz", "integrity": "sha512-nejhOHexXDBKQOj/5v5IZSfCeTO3x1Dt1RZEcGfBSul891X/eLIcIVH31gwxPDdsi2Z8LKKFGpM4w9+oTBOSCg==", "requires": { - "fs-extra": "^7.0.0", - "lodash": ">=3.5 <5", - "tapable": "^1.0.0" + "fs-extra": "7.0.0", + "lodash": "4.17.11", + "tapable": "1.1.1" } }, "webpack-sources": { @@ -17592,8 +17586,8 @@ "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.3.0.tgz", "integrity": "sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA==", "requires": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" + "source-list-map": "2.0.1", + "source-map": "0.6.1" }, "dependencies": { "source-map": { @@ -17608,8 +17602,8 @@ "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz", "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", "requires": { - "http-parser-js": ">=0.4.0", - "websocket-extensions": ">=0.1.1" + "http-parser-js": "0.5.0", + "websocket-extensions": "0.1.3" } }, "websocket-extensions": { @@ -17640,9 +17634,9 @@ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz", "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==", "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" + "lodash.sortby": "4.7.0", + "tr46": "1.0.1", + "webidl-conversions": "4.0.2" } }, "which": { @@ -17650,7 +17644,7 @@ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "requires": { - "isexe": "^2.0.0" + "isexe": "2.0.0" } }, "which-module": { @@ -17663,7 +17657,7 @@ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "requires": { - "string-width": "^1.0.2 || 2" + "string-width": "2.1.1" } }, "wordwrap": { @@ -17676,7 +17670,7 @@ "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-3.6.3.tgz", "integrity": "sha512-ypLo0B6dces4gSpaslmDg5wuoUWrHHVJfFWwl1udvSylLdXvnrfhFfriCS42SNEe5lsZtcNZF27W/SMzBlva7Q==", "requires": { - "workbox-core": "^3.6.3" + "workbox-core": "3.6.3" } }, "workbox-broadcast-cache-update": { @@ -17684,7 +17678,7 @@ "resolved": "https://registry.npmjs.org/workbox-broadcast-cache-update/-/workbox-broadcast-cache-update-3.6.3.tgz", "integrity": "sha512-pJl4lbClQcvp0SyTiEw0zLSsVYE1RDlCPtpKnpMjxFtu8lCFTAEuVyzxp9w7GF4/b3P4h5nyQ+q7V9mIR7YzGg==", "requires": { - "workbox-core": "^3.6.3" + "workbox-core": "3.6.3" } }, "workbox-build": { @@ -17692,28 +17686,28 @@ "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-3.6.3.tgz", "integrity": "sha512-w0clZ/pVjL8VXy6GfthefxpEXs0T8uiRuopZSFVQ8ovfbH6c6kUpEh6DcYwm/Y6dyWPiCucdyAZotgjz+nRz8g==", "requires": { - "babel-runtime": "^6.26.0", - "common-tags": "^1.4.0", - "fs-extra": "^4.0.2", - "glob": "^7.1.2", - "joi": "^11.1.1", - "lodash.template": "^4.4.0", - "pretty-bytes": "^4.0.2", - "stringify-object": "^3.2.2", - "strip-comments": "^1.0.2", - "workbox-background-sync": "^3.6.3", - "workbox-broadcast-cache-update": "^3.6.3", - "workbox-cache-expiration": "^3.6.3", - "workbox-cacheable-response": "^3.6.3", - "workbox-core": "^3.6.3", - "workbox-google-analytics": "^3.6.3", - "workbox-navigation-preload": "^3.6.3", - "workbox-precaching": "^3.6.3", - "workbox-range-requests": "^3.6.3", - "workbox-routing": "^3.6.3", - "workbox-strategies": "^3.6.3", - "workbox-streams": "^3.6.3", - "workbox-sw": "^3.6.3" + "babel-runtime": "6.26.0", + "common-tags": "1.8.0", + "fs-extra": "4.0.3", + "glob": "7.1.3", + "joi": "11.4.0", + "lodash.template": "4.4.0", + "pretty-bytes": "4.0.2", + "stringify-object": "3.3.0", + "strip-comments": "1.0.2", + "workbox-background-sync": "3.6.3", + "workbox-broadcast-cache-update": "3.6.3", + "workbox-cache-expiration": "3.6.3", + "workbox-cacheable-response": "3.6.3", + "workbox-core": "3.6.3", + "workbox-google-analytics": "3.6.3", + "workbox-navigation-preload": "3.6.3", + "workbox-precaching": "3.6.3", + "workbox-range-requests": "3.6.3", + "workbox-routing": "3.6.3", + "workbox-strategies": "3.6.3", + "workbox-streams": "3.6.3", + "workbox-sw": "3.6.3" }, "dependencies": { "fs-extra": { @@ -17721,9 +17715,9 @@ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "graceful-fs": "4.1.15", + "jsonfile": "4.0.0", + "universalify": "0.1.2" } } } @@ -17733,7 +17727,7 @@ "resolved": "https://registry.npmjs.org/workbox-cache-expiration/-/workbox-cache-expiration-3.6.3.tgz", "integrity": "sha512-+ECNph/6doYx89oopO/UolYdDmQtGUgo8KCgluwBF/RieyA1ZOFKfrSiNjztxOrGJoyBB7raTIOlEEwZ1LaHoA==", "requires": { - "workbox-core": "^3.6.3" + "workbox-core": "3.6.3" } }, "workbox-cacheable-response": { @@ -17741,7 +17735,7 @@ "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-3.6.3.tgz", "integrity": "sha512-QpmbGA9SLcA7fklBLm06C4zFg577Dt8u3QgLM0eMnnbaVv3rhm4vbmDpBkyTqvgK/Ly8MBDQzlXDtUCswQwqqg==", "requires": { - "workbox-core": "^3.6.3" + "workbox-core": "3.6.3" } }, "workbox-core": { @@ -17754,10 +17748,10 @@ "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-3.6.3.tgz", "integrity": "sha512-RQBUo/6SXtIaQTRFj4RQZ9e1gAl7D8oS5S+Hi173Kk70/BgJjzPwXpC5A249Jv5YfkCOLMQCeF9A27BiD0b0ig==", "requires": { - "workbox-background-sync": "^3.6.3", - "workbox-core": "^3.6.3", - "workbox-routing": "^3.6.3", - "workbox-strategies": "^3.6.3" + "workbox-background-sync": "3.6.3", + "workbox-core": "3.6.3", + "workbox-routing": "3.6.3", + "workbox-strategies": "3.6.3" } }, "workbox-navigation-preload": { @@ -17765,7 +17759,7 @@ "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-3.6.3.tgz", "integrity": "sha512-dd26xTX16DUu0i+MhqZK/jQXgfIitu0yATM4jhRXEmpMqQ4MxEeNvl2CgjDMOHBnCVMax+CFZQWwxMx/X/PqCw==", "requires": { - "workbox-core": "^3.6.3" + "workbox-core": "3.6.3" } }, "workbox-precaching": { @@ -17773,7 +17767,7 @@ "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-3.6.3.tgz", "integrity": "sha512-aBqT66BuMFviPTW6IpccZZHzpA8xzvZU2OM1AdhmSlYDXOJyb1+Z6blVD7z2Q8VNtV1UVwQIdImIX+hH3C3PIw==", "requires": { - "workbox-core": "^3.6.3" + "workbox-core": "3.6.3" } }, "workbox-range-requests": { @@ -17781,7 +17775,7 @@ "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-3.6.3.tgz", "integrity": "sha512-R+yLWQy7D9aRF9yJ3QzwYnGFnGDhMUij4jVBUVtkl67oaVoP1ymZ81AfCmfZro2kpPRI+vmNMfxxW531cqdx8A==", "requires": { - "workbox-core": "^3.6.3" + "workbox-core": "3.6.3" } }, "workbox-routing": { @@ -17789,7 +17783,7 @@ "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-3.6.3.tgz", "integrity": "sha512-bX20i95OKXXQovXhFOViOK63HYmXvsIwZXKWbSpVeKToxMrp0G/6LZXnhg82ijj/S5yhKNRf9LeGDzaqxzAwMQ==", "requires": { - "workbox-core": "^3.6.3" + "workbox-core": "3.6.3" } }, "workbox-strategies": { @@ -17797,7 +17791,7 @@ "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-3.6.3.tgz", "integrity": "sha512-Pg5eulqeKet2y8j73Yw6xTgLdElktcWExGkzDVCGqfV9JCvnGuEpz5eVsCIK70+k4oJcBCin9qEg3g3CwEIH3g==", "requires": { - "workbox-core": "^3.6.3" + "workbox-core": "3.6.3" } }, "workbox-streams": { @@ -17805,7 +17799,7 @@ "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-3.6.3.tgz", "integrity": "sha512-rqDuS4duj+3aZUYI1LsrD2t9hHOjwPqnUIfrXSOxSVjVn83W2MisDF2Bj+dFUZv4GalL9xqErcFW++9gH+Z27w==", "requires": { - "workbox-core": "^3.6.3" + "workbox-core": "3.6.3" } }, "workbox-sw": { @@ -17818,9 +17812,9 @@ "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-3.6.3.tgz", "integrity": "sha512-RwmKjc7HFHUFHoOlKoZUq9349u0QN3F8W5tZZU0vc1qsBZDINWXRiIBCAKvo/Njgay5sWz7z4I2adnyTo97qIQ==", "requires": { - "babel-runtime": "^6.26.0", - "json-stable-stringify": "^1.0.1", - "workbox-build": "^3.6.3" + "babel-runtime": "6.26.0", + "json-stable-stringify": "1.0.1", + "workbox-build": "3.6.3" } }, "worker-farm": { @@ -17828,7 +17822,7 @@ "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.6.0.tgz", "integrity": "sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ==", "requires": { - "errno": "~0.1.7" + "errno": "0.1.7" } }, "wrap-ansi": { @@ -17836,8 +17830,8 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" + "string-width": "1.0.2", + "strip-ansi": "3.0.1" }, "dependencies": { "is-fullwidth-code-point": { @@ -17845,7 +17839,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "requires": { - "number-is-nan": "^1.0.0" + "number-is-nan": "1.0.1" } }, "string-width": { @@ -17853,9 +17847,9 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" } } } @@ -17870,7 +17864,7 @@ "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", "requires": { - "mkdirp": "^0.5.1" + "mkdirp": "0.5.1" } }, "write-file-atomic": { @@ -17878,9 +17872,9 @@ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz", "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==", "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" + "graceful-fs": "4.1.15", + "imurmurhash": "0.1.4", + "signal-exit": "3.0.2" } }, "ws": { @@ -17888,7 +17882,7 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.2.tgz", "integrity": "sha512-rfUqzvz0WxmSXtJpPMX2EeASXabOrSMk1ruMOV3JBTBjo4ac2lDjGGsbQSyxj8Odhw5fBib8ZKEjDNvgouNKYw==", "requires": { - "async-limiter": "~1.0.0" + "async-limiter": "1.0.0" } }, "xml-name-validator": { @@ -17926,18 +17920,18 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz", "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.1.1", - "find-up": "^2.1.0", - "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^9.0.2" + "cliui": "4.1.0", + "decamelize": "1.2.0", + "find-up": "2.1.0", + "get-caller-file": "1.0.3", + "os-locale": "2.1.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "9.0.2" } }, "yargs-parser": { @@ -17945,7 +17939,7 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", "requires": { - "camelcase": "^4.1.0" + "camelcase": "4.1.0" }, "dependencies": { "camelcase": { diff --git a/client/package.json b/client/package.json index 33afc7a92..c0002df5e 100644 --- a/client/package.json +++ b/client/package.json @@ -17,13 +17,12 @@ "@types/react-redux": "^6.0.12", "@types/react-router-dom": "^4.3.1", "@types/redux-thunk": "^2.1.0", - "await-to-js": "^2.1.1", "classnames": "^2.2.6", "connected-react-router": "^6.2.1", "node-sass": "^4.11.0", "qrcode.react": "^0.9.2", "query-string": "^6.2.0", - "react": "^16.6.0", + "react": "^16.10.2", "react-dom": "^16.6.0", "react-redux": "^6.0.0", "react-router-dom": "^4.3.1", diff --git a/client/src/behaviors/FetchPrefered2faMethod.ts b/client/src/behaviors/FetchPrefered2faMethod.ts index ada449f3e..9ea5ca48c 100644 --- a/client/src/behaviors/FetchPrefered2faMethod.ts +++ b/client/src/behaviors/FetchPrefered2faMethod.ts @@ -6,6 +6,7 @@ export default async function(dispatch: Dispatch) { dispatch(getPreferedMethod()); try { const method = await AutheliaService.fetchPrefered2faMethod(); + console.log(method); dispatch(getPreferedMethodSuccess(method)); } catch (err) { dispatch(getPreferedMethodFailure(err.message)) diff --git a/client/src/behaviors/FetchStateBehavior.ts b/client/src/behaviors/FetchStateBehavior.ts index 2da2e9eab..8ee99f01a 100644 --- a/client/src/behaviors/FetchStateBehavior.ts +++ b/client/src/behaviors/FetchStateBehavior.ts @@ -1,19 +1,12 @@ import { Dispatch } from "redux"; import { fetchStateFailure, fetchStateSuccess } from "../reducers/Portal/Authentication/actions"; -import to from "await-to-js"; import AutheliaService from "../services/AutheliaService"; export default async function(dispatch: Dispatch) { - let err, res; - [err, res] = await to(AutheliaService.fetchState()); - if (err) { - await dispatch(fetchStateFailure(err.message)); - return; + try { + const state = await AutheliaService.fetchState(); + dispatch(fetchStateSuccess(state)); + } catch (err) { + dispatch(fetchStateFailure(err.message)); } - if (!res) { - await dispatch(fetchStateFailure('No response')); - return - } - await dispatch(fetchStateSuccess(res)); - return res; } \ No newline at end of file diff --git a/client/src/behaviors/LogoutBehavior.ts b/client/src/behaviors/LogoutBehavior.ts index 082bba6b5..db647d819 100644 --- a/client/src/behaviors/LogoutBehavior.ts +++ b/client/src/behaviors/LogoutBehavior.ts @@ -1,18 +1,15 @@ import { Dispatch } from "redux"; import { logout, logoutFailure, logoutSuccess } from "../reducers/Portal/SecondFactor/actions"; -import to from "await-to-js"; import fetchState from "./FetchStateBehavior"; import AutheliaService from "../services/AutheliaService"; export default async function(dispatch: Dispatch) { - await dispatch(logout()); - let err, res; - [err, res] = await to(AutheliaService.postLogout()); - - if (err) { - await dispatch(logoutFailure(err.message)); - return; + try { + dispatch(logout()); + await AutheliaService.postLogout(); + dispatch(logoutSuccess()); + await fetchState(dispatch); + } catch (err) { + dispatch(logoutFailure(err.message)); } - await dispatch(logoutSuccess()); - await fetchState(dispatch); } \ No newline at end of file diff --git a/client/src/components/FirstFactorForm/FirstFactorForm.tsx b/client/src/components/FirstFactorForm/FirstFactorForm.tsx index 1f000c336..0f4a8385a 100644 --- a/client/src/components/FirstFactorForm/FirstFactorForm.tsx +++ b/client/src/components/FirstFactorForm/FirstFactorForm.tsx @@ -17,17 +17,19 @@ export interface OwnProps { export interface StateProps { formDisabled: boolean; error: string | null; + username: string; + password: string; } export interface DispatchProps { - onAuthenticationRequested(username: string, password: string, rememberMe: boolean): Promise; + onUsernameChanged(username: string): void; + onPasswordChanged(password: string): void; + onAuthenticationRequested(username: string, password: string, rememberMe: boolean): void; } export type Props = OwnProps & StateProps & DispatchProps; interface State { - username: string; - password: string; rememberMe: boolean; } @@ -35,8 +37,6 @@ class FirstFactorForm extends Component { constructor(props: Props) { super(props) this.state = { - username: '', - password: '', rememberMe: false, } } @@ -49,12 +49,12 @@ class FirstFactorForm extends Component { onUsernameChanged = (e: FormEvent) => { const val = (e.target as HTMLInputElement).value; - this.setState({username: val}); + this.props.onUsernameChanged(val); } onPasswordChanged = (e: FormEvent) => { const val = (e.target as HTMLInputElement).value; - this.setState({password: val}); + this.props.onPasswordChanged(val); } onLoginClicked = () => { @@ -83,9 +83,10 @@ class FirstFactorForm extends Component { outlined={true}> + value={this.props.username}/>
@@ -95,11 +96,12 @@ class FirstFactorForm extends Component { outlined={true}> + value={this.props.password} />
@@ -134,13 +136,9 @@ class FirstFactorForm extends Component { private authenticate() { this.props.onAuthenticationRequested( - this.state.username, - this.state.password, + this.props.username, + this.props.password, this.state.rememberMe) - .catch((err: Error) => console.error(err)) - .finally(() => { - this.setState({username: '', password: ''}); - }) } } diff --git a/client/src/containers/components/FirstFactorForm/FirstFactorForm.ts b/client/src/containers/components/FirstFactorForm/FirstFactorForm.ts index e63b934e9..4a861786d 100644 --- a/client/src/containers/components/FirstFactorForm/FirstFactorForm.ts +++ b/client/src/containers/components/FirstFactorForm/FirstFactorForm.ts @@ -1,9 +1,14 @@ import { connect } from 'react-redux'; import { Dispatch } from 'redux'; -import { authenticateFailure, authenticateSuccess, authenticate } from '../../../reducers/Portal/FirstFactor/actions'; +import { + authenticateFailure, + authenticateSuccess, + authenticate, + setUsername, + setPassword +} from '../../../reducers/Portal/FirstFactor/actions'; import FirstFactorForm, { StateProps, OwnProps } from '../../../components/FirstFactorForm/FirstFactorForm'; import { RootState } from '../../../reducers'; -import to from 'await-to-js'; import FetchStateBehavior from '../../../behaviors/FetchStateBehavior'; import AutheliaService from '../../../services/AutheliaService'; @@ -11,57 +16,42 @@ const mapStateToProps = (state: RootState): StateProps => { return { error: state.firstFactor.error, formDisabled: state.firstFactor.loading, + username: state.firstFactor.username, + password: state.firstFactor.password, }; } function onAuthenticationRequested(dispatch: Dispatch, redirectionUrl: string | null) { - return async (username: string, password: string, rememberMe: boolean): Promise => { - let err, res; - + return async (username: string, password: string, rememberMe: boolean): Promise => { // Validate first factor dispatch(authenticate()); - [err, res] = await to(AutheliaService.postFirstFactorAuth( - username, password, rememberMe, redirectionUrl)); - - if (err) { - await dispatch(authenticateFailure(err.message)); - throw new Error(err.message); - } - - if (!res) { - await dispatch(authenticateFailure('No response')); - throw new Error('No response'); - } - - if (res.status === 200) { - const json = await res.json(); - if ('error' in json) { - await dispatch(authenticateFailure(json['error'])); - throw new Error(json['error']); - } - - dispatch(authenticateSuccess()); - if ('redirect' in json) { - window.location.href = json['redirect']; + try { + const redirectOrUndefined = await AutheliaService.postFirstFactorAuth( + username, password, rememberMe, redirectionUrl); + if (redirectOrUndefined) { + window.location.href = redirectOrUndefined.redirect; return; } - + dispatch(authenticateSuccess()); + dispatch(setUsername('')); + dispatch(setPassword('')); // fetch state to move to next stage in case redirect is not possible await FetchStateBehavior(dispatch); - } else if (res.status === 204) { - dispatch(authenticateSuccess()); - - // fetch state to move to next stage - await FetchStateBehavior(dispatch); - } else { - dispatch(authenticateFailure('Unknown error')); - throw new Error('Unknown error... (' + res.status + ')'); + } catch (err) { + dispatch(setPassword('')); + dispatch(authenticateFailure(err.message)); } } } const mapDispatchToProps = (dispatch: Dispatch, ownProps: OwnProps) => { return { + onUsernameChanged: function(username: string) { + dispatch(setUsername(username)); + }, + onPasswordChanged: function(password: string) { + dispatch(setPassword(password)); + }, onAuthenticationRequested: onAuthenticationRequested(dispatch, ownProps.redirectionUrl), } } diff --git a/client/src/containers/components/SecondFactorDuoPush/SecondFactorDuoPush.ts b/client/src/containers/components/SecondFactorDuoPush/SecondFactorDuoPush.ts index c6cfb086a..58ec1c360 100644 --- a/client/src/containers/components/SecondFactorDuoPush/SecondFactorDuoPush.ts +++ b/client/src/containers/components/SecondFactorDuoPush/SecondFactorDuoPush.ts @@ -4,7 +4,6 @@ import { Dispatch } from 'redux'; import SecondFactorDuoPush, { StateProps, OwnProps, DispatchProps } from '../../../components/SecondFactorDuoPush/SecondFactorDuoPush'; import FetchStateBehavior from '../../../behaviors/FetchStateBehavior'; import TriggerDuoPushAuth from '../../../behaviors/TriggerDuoPushAuth'; -import RedirectionResponse from '../../../services/RedirectResponse'; const mapStateToProps = (state: RootState): StateProps => ({ @@ -20,7 +19,7 @@ async function redirectIfPossible(body: any) { return false; } -async function handleSuccess(dispatch: Dispatch, body: RedirectionResponse | undefined, duration?: number) { +async function handleSuccess(dispatch: Dispatch, body: {redirect: string} | undefined, duration?: number) { async function handle() { const redirected = await redirectIfPossible(body); if (!redirected) { diff --git a/client/src/containers/components/SecondFactorTOTP/SecondFactorTOTP.ts b/client/src/containers/components/SecondFactorTOTP/SecondFactorTOTP.ts index 1f4a04041..688a70d17 100644 --- a/client/src/containers/components/SecondFactorTOTP/SecondFactorTOTP.ts +++ b/client/src/containers/components/SecondFactorTOTP/SecondFactorTOTP.ts @@ -7,7 +7,6 @@ import { oneTimePasswordVerificationFailure, oneTimePasswordVerificationSuccess } from '../../../reducers/Portal/SecondFactor/actions'; -import to from 'await-to-js'; import AutheliaService from '../../../services/AutheliaService'; import { push } from 'connected-react-router'; import FetchStateBehavior from '../../../behaviors/FetchStateBehavior'; @@ -18,21 +17,6 @@ const mapStateToProps = (state: RootState): StateProps => ({ oneTimePasswordVerificationError: state.secondFactor.oneTimePasswordVerificationError, }); -async function redirectIfPossible(dispatch: Dispatch, res: Response) { - if (res.status === 204) return; - - const body = await res.json(); - if ('error' in body) { - throw new Error(body['error']); - } - - if ('redirect' in body) { - window.location.href = body['redirect']; - return; - } - return; -} - async function handleSuccess(dispatch: Dispatch, duration?: number) { async function handle() { await FetchStateBehavior(dispatch); @@ -48,23 +32,17 @@ async function handleSuccess(dispatch: Dispatch, duration?: number) { const mapDispatchToProps = (dispatch: Dispatch, ownProps: OwnProps) => { return { onOneTimePasswordValidationRequested: async (token: string) => { - let err, res; - dispatch(oneTimePasswordVerification()); - [err, res] = await to(AutheliaService.verifyTotpToken(token, ownProps.redirectionUrl)); - if (err) { - dispatch(oneTimePasswordVerificationFailure(err.message)); - throw err; - } - if (!res) { - dispatch(oneTimePasswordVerificationFailure('No response')); - throw 'No response'; - } - try { - await redirectIfPossible(dispatch, res); + dispatch(oneTimePasswordVerification()); + const response = await AutheliaService.verifyTotpToken(token, ownProps.redirectionUrl); dispatch(oneTimePasswordVerificationSuccess()); + if (response) { + window.location.href = response.redirect; + return; + } await handleSuccess(dispatch); } catch (err) { + console.error(err); dispatch(oneTimePasswordVerificationFailure(err.message)); } }, diff --git a/client/src/containers/components/SecondFactorU2F/SecondFactorU2F.ts b/client/src/containers/components/SecondFactorU2F/SecondFactorU2F.ts index fa4ecd9d4..fc1b932a5 100644 --- a/client/src/containers/components/SecondFactorU2F/SecondFactorU2F.ts +++ b/client/src/containers/components/SecondFactorU2F/SecondFactorU2F.ts @@ -5,7 +5,6 @@ import SecondFactorU2F, { StateProps, OwnProps } from '../../../components/Secon import AutheliaService from '../../../services/AutheliaService'; import { push } from 'connected-react-router'; import u2fApi from 'u2f-api'; -import to from 'await-to-js'; import { securityKeySignSuccess, securityKeySign, @@ -20,58 +19,27 @@ const mapStateToProps = (state: RootState): StateProps => ({ }); async function triggerSecurityKeySigning(dispatch: Dispatch, redirectionUrl: string | null) { - let err, result; dispatch(securityKeySign()); - [err, result] = await to(AutheliaService.requestSigning()); - if (err) { - await dispatch(securityKeySignFailure(err.message)); - throw err; + const signRequest = await AutheliaService.requestSigning(); + const signRequests: u2fApi.SignRequest[] = []; + for (var i in signRequest.registeredKeys) { + const r = signRequest.registeredKeys[i]; + signRequests.push({ + appId: signRequest.appId, + challenge: signRequest.challenge, + keyHandle: r.keyHandle, + version: r.version, + }) } + const signResponse = await u2fApi.sign(signRequests, 60); + const response = await AutheliaService.completeSecurityKeySigning(signResponse, redirectionUrl); + dispatch(securityKeySignSuccess()); - if (!result) { - await dispatch(securityKeySignFailure('No response')); - throw 'No response'; - } - - [err, result] = await to(u2fApi.sign(result, 60)); - if (err) { - await dispatch(securityKeySignFailure(err.message)); - throw err; - } - - if (!result) { - await dispatch(securityKeySignFailure('No response')); - throw 'No response'; - } - - [err, result] = await to(AutheliaService.completeSecurityKeySigning(result, redirectionUrl)); - if (err) { - await dispatch(securityKeySignFailure(err.message)); - throw err; - } - - try { - await redirectIfPossible(result as Response); - dispatch(securityKeySignSuccess()); - await handleSuccess(dispatch, 1000); - } catch (err) { - dispatch(securityKeySignFailure(err.message)); - } -} - -async function redirectIfPossible(res: Response) { - if (res.status === 204) return; - - const body = await res.json(); - if ('error' in body) { - throw new Error(body['error']); - } - - if ('redirect' in body) { - window.location.href = body['redirect']; + if (response) { + window.location.href = response.redirect; return; } - return; + await handleSuccess(dispatch, 1000); } async function handleSuccess(dispatch: Dispatch, duration?: number) { @@ -93,7 +61,12 @@ const mapDispatchToProps = (dispatch: Dispatch, ownProps: OwnProps) => { await dispatch(push('/confirmation-sent')); }, onInit: async () => { - await triggerSecurityKeySigning(dispatch, ownProps.redirectionUrl); + try { + await triggerSecurityKeySigning(dispatch, ownProps.redirectionUrl); + } catch (err) { + console.error(err); + await dispatch(securityKeySignFailure(err.message)); + } }, } } diff --git a/client/src/containers/views/AuthenticationView/AuthenticationView.ts b/client/src/containers/views/AuthenticationView/AuthenticationView.ts index 46921865c..4fed5a898 100644 --- a/client/src/containers/views/AuthenticationView/AuthenticationView.ts +++ b/client/src/containers/views/AuthenticationView/AuthenticationView.ts @@ -27,6 +27,8 @@ const mapStateToProps = (state: RootState, ownProps: OwnProps): StateProps => { const params = QueryString.parse(ownProps.location.search); if ('rd' in params) { url = params['rd'] as string; + } else if (state.authentication.remoteState && state.authentication.remoteState.default_redirection_url) { + url = state.authentication.remoteState.default_redirection_url; } } diff --git a/client/src/containers/views/OneTimePasswordRegistrationView/OneTimePasswordRegistrationView.ts b/client/src/containers/views/OneTimePasswordRegistrationView/OneTimePasswordRegistrationView.ts index f724b3458..c10fff51e 100644 --- a/client/src/containers/views/OneTimePasswordRegistrationView/OneTimePasswordRegistrationView.ts +++ b/client/src/containers/views/OneTimePasswordRegistrationView/OneTimePasswordRegistrationView.ts @@ -2,48 +2,23 @@ import { connect } from 'react-redux'; import OneTimePasswordRegistrationView from '../../../views/OneTimePasswordRegistrationView/OneTimePasswordRegistrationView'; import { RootState } from '../../../reducers'; import { Dispatch } from 'redux'; -import {to} from 'await-to-js'; import { generateTotpSecret, generateTotpSecretSuccess, generateTotpSecretFailure } from '../../../reducers/Portal/OneTimePasswordRegistration/actions'; import { push } from 'connected-react-router'; +import AutheliaService from '../../../services/AutheliaService'; const mapStateToProps = (state: RootState) => ({ error: state.oneTimePasswordRegistration.error, secret: state.oneTimePasswordRegistration.secret, }); -async function checkIdentity(token: string) { - return fetch(`/api/secondfactor/totp/identity/finish?token=${token}`, { - method: 'POST', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json', - }, - }) - .then(async (res) => { - if (res.status !== 200) { - throw new Error('Status code ' + res.status); - } - - const body = await res.json(); - if ('error' in body) { - throw new Error(body['error']); - } - return body; - }); -} - async function tryGenerateTotpSecret(dispatch: Dispatch, token: string) { - let err, result; - dispatch(generateTotpSecret()); - [err, result] = await to(checkIdentity(token)); - if (err) { - const e = err; - setTimeout(() => { - dispatch(generateTotpSecretFailure(e.message)); - }, 2000); - return; + try { + dispatch(generateTotpSecret()); + const res = await AutheliaService.completeOneTimePasswordRegistrationIdentityValidation(token); + dispatch(generateTotpSecretSuccess(res)); + } catch (err) { + dispatch(generateTotpSecretFailure(err.message)); } - dispatch(generateTotpSecretSuccess(result)); } const mapDispatchToProps = (dispatch: Dispatch) => { diff --git a/client/src/containers/views/ResetPasswordView/ResetPasswordView.ts b/client/src/containers/views/ResetPasswordView/ResetPasswordView.ts index 4053ebbbc..ceaf6d2cd 100644 --- a/client/src/containers/views/ResetPasswordView/ResetPasswordView.ts +++ b/client/src/containers/views/ResetPasswordView/ResetPasswordView.ts @@ -12,11 +12,19 @@ const mapStateToProps = (state: RootState): StateProps => ({ const mapDispatchToProps = (dispatch: Dispatch) => { return { onInit: async (token: string) => { - await AutheliaService.completePasswordResetIdentityValidation(token); + try { + await AutheliaService.completePasswordResetIdentityValidation(token); + } catch (err) { + console.error(err); + } }, onPasswordResetRequested: async (newPassword: string) => { - await AutheliaService.resetPassword(newPassword); - await dispatch(push('/')); + try { + await AutheliaService.resetPassword(newPassword); + await dispatch(push('/')); + } catch (err) { + console.error(err); + } }, onCancelClicked: async () => { await dispatch(push('/')); diff --git a/client/src/containers/views/SecurityKeyRegistrationView/SecurityKeyRegistrationView.ts b/client/src/containers/views/SecurityKeyRegistrationView/SecurityKeyRegistrationView.ts index 800424c08..39cb3cf96 100644 --- a/client/src/containers/views/SecurityKeyRegistrationView/SecurityKeyRegistrationView.ts +++ b/client/src/containers/views/SecurityKeyRegistrationView/SecurityKeyRegistrationView.ts @@ -12,26 +12,30 @@ const mapStateToProps = (state: RootState) => ({ error: state.securityKeyRegistration.error, }); -function fail(dispatch: Dispatch, err: Error) { - console.error(err); - dispatch(registerSecurityKeyFailure(err.message)); -} - const mapDispatchToProps = (dispatch: Dispatch, ownProps: Props) => { return { onInit: async (token: string) => { try { dispatch(registerSecurityKey()); - await AutheliaService.completeSecurityKeyRegistrationIdentityValidation(token); - const registerRequest = await AutheliaService.requestSecurityKeyRegistration(); - const registerResponse = await U2fApi.register([registerRequest], [], 60); + const registerRequest = await AutheliaService.completeSecurityKeyRegistrationIdentityValidation(token); + const registerRequests: U2fApi.RegisterRequest[] = []; + for(var i in registerRequest.registerRequests) { + const r = registerRequest.registerRequests[i]; + registerRequests.push({ + appId: registerRequest.appId, + challenge: r.challenge, + version: r.version, + }) + } + const registerResponse = await U2fApi.register(registerRequests, [], 60); await AutheliaService.completeSecurityKeyRegistration(registerResponse); dispatch(registerSecurityKeySuccess()); setTimeout(() => { ownProps.history.push('/'); }, 2000); } catch(err) { - fail(dispatch, err); + console.error(err); + dispatch(registerSecurityKeyFailure(err.message)); } }, onBackClicked: () => { diff --git a/client/src/reducers/Portal/FirstFactor/actions.ts b/client/src/reducers/Portal/FirstFactor/actions.ts index cbbf2cdd2..a93991490 100644 --- a/client/src/reducers/Portal/FirstFactor/actions.ts +++ b/client/src/reducers/Portal/FirstFactor/actions.ts @@ -2,7 +2,9 @@ import { createAction } from 'typesafe-actions'; import { AUTHENTICATE_REQUEST, AUTHENTICATE_SUCCESS, - AUTHENTICATE_FAILURE + AUTHENTICATE_FAILURE, + FIRST_FACTOR_SET_USERNAME, + FIRST_FACTOR_SET_PASSWORD } from "../../constants"; /* AUTHENTICATE_REQUEST */ @@ -11,3 +13,11 @@ export const authenticateSuccess = createAction(AUTHENTICATE_SUCCESS); export const authenticateFailure = createAction(AUTHENTICATE_FAILURE, resolve => { return (error: string) => resolve(error); }); + + +export const setUsername = createAction(FIRST_FACTOR_SET_USERNAME, resolve => { + return (username: string) => resolve(username); +}); +export const setPassword = createAction(FIRST_FACTOR_SET_PASSWORD, resolve => { + return (password: string) => resolve(password); +}); \ No newline at end of file diff --git a/client/src/reducers/Portal/FirstFactor/reducer.ts b/client/src/reducers/Portal/FirstFactor/reducer.ts index f7aa685db..c3e00c742 100644 --- a/client/src/reducers/Portal/FirstFactor/reducer.ts +++ b/client/src/reducers/Portal/FirstFactor/reducer.ts @@ -14,12 +14,16 @@ interface FirstFactorState { lastResult: Result; loading: boolean; error: string | null; + username: string; + password: string; } const firstFactorInitialState: FirstFactorState = { lastResult: Result.NONE, loading: false, error: null, + username: '', + password: '', } export default (state = firstFactorInitialState, action: FirstFactorAction): FirstFactorState => { @@ -44,6 +48,16 @@ export default (state = firstFactorInitialState, action: FirstFactorAction): Fir loading: false, error: action.payload, }; + case getType(Actions.setUsername): + return { + ...state, + username: action.payload, + } + case getType(Actions.setPassword): + return { + ...state, + password: action.payload, + } } return state; } \ No newline at end of file diff --git a/client/src/reducers/constants.ts b/client/src/reducers/constants.ts index 7e37d3e30..6922ce8b9 100644 --- a/client/src/reducers/constants.ts +++ b/client/src/reducers/constants.ts @@ -4,9 +4,12 @@ export const FETCH_STATE_SUCCESS = '@portal/fetch_state_success'; export const FETCH_STATE_FAILURE = '@portal/fetch_state_failure'; // AUTHENTICATION PROCESS -export const AUTHENTICATE_REQUEST = '@portal/authenticate_request'; -export const AUTHENTICATE_SUCCESS = '@portal/authenticate_success'; -export const AUTHENTICATE_FAILURE = '@portal/authenticate_failure'; +export const FIRST_FACTOR_SET_USERNAME = "@portal/first_factor/set_username"; +export const FIRST_FACTOR_SET_PASSWORD = "@portal/first_factor/set_password"; + +export const AUTHENTICATE_REQUEST = '@portal/first_factor/authenticate_request'; +export const AUTHENTICATE_SUCCESS = '@portal/first_factor/authenticate_success'; +export const AUTHENTICATE_FAILURE = '@portal/first_factor/authenticate_failure'; // SECOND FACTOR PAGE export const SET_SECURITY_KEY_SUPPORTED = '@portal/second_factor/set_security_key_supported'; diff --git a/client/src/routes/routes.ts b/client/src/routes/routes.ts index 7fe058ac3..40208e4a7 100644 --- a/client/src/routes/routes.ts +++ b/client/src/routes/routes.ts @@ -4,6 +4,7 @@ import SecurityKeyRegistrationView from "../containers/views/SecurityKeyRegistra import ForgotPasswordView from "../containers/views/ForgotPasswordView/ForgotPasswordView"; import ResetPasswordView from "../containers/views/ResetPasswordView/ResetPasswordView"; import AuthenticationView from "../containers/views/AuthenticationView/AuthenticationView"; +import LogoutView from "../views/LogoutView/LogoutView"; export const routes = [{ path: '/', @@ -29,4 +30,8 @@ export const routes = [{ path: '/reset-password', title: 'Reset password', component: ResetPasswordView, +}, { + path: '/logout', + title: 'Logout', + component: LogoutView, }] \ No newline at end of file diff --git a/client/src/services/AutheliaService.ts b/client/src/services/AutheliaService.ts index eb154f7cf..f2f801ada 100644 --- a/client/src/services/AutheliaService.ts +++ b/client/src/services/AutheliaService.ts @@ -1,58 +1,73 @@ import RemoteState from "../views/AuthenticationView/RemoteState"; -import U2fApi, { SignRequest } from "u2f-api"; +import U2fApi from "u2f-api"; import Method2FA from "../types/Method2FA"; -import RedirectResponse from "./RedirectResponse"; -import PreferedMethodResponse from "./PreferedMethodResponse"; +import { string } from "prop-types"; + +interface DataResponse { + status: "OK"; + data: T; +} + +interface ErrorResponse { + status: "KO"; + message: string; +} + +type ServiceResponse = DataResponse | ErrorResponse; class AutheliaService { - static async fetchSafe(url: string, options?: RequestInit): Promise { - const res = await fetch(url, options); - if (res.status !== 200 && res.status !== 204) { - throw new Error('Status code ' + res.status); - } - return res; - } - static async fetchSafeJson(url: string, options?: RequestInit): Promise { const res = await fetch(url, options); if (res.status !== 200) { throw new Error('Status code ' + res.status); } - return await res.json(); + const response: ServiceResponse = await res.json(); + if (response.status == "OK") { + return response.data; + } else { + throw new Error(response.message) + } } /** * Fetch current authentication state. */ static async fetchState(): Promise { - return await this.fetchSafeJson('/api/state') + return await this.fetchSafeJson('/api/state') } static async postFirstFactorAuth(username: string, password: string, - rememberMe: boolean, redirectionUrl: string | null) { + rememberMe: boolean, targetURL: string | null) { const headers: Record = { 'Accept': 'application/json', 'Content-Type': 'application/json', } - if (redirectionUrl) { - headers['X-Target-Url'] = redirectionUrl; + const requestBody: { + username: string, + password: string, + keepMeLoggedIn: boolean, + targetURL?: string + } = { + username: username, + password: password, + keepMeLoggedIn: rememberMe, } - return this.fetchSafe('/api/firstfactor', { + if (targetURL) { + requestBody.targetURL = targetURL; + } + + return this.fetchSafeJson<{redirect: string}|undefined>('/api/firstfactor', { method: 'POST', headers: headers, - body: JSON.stringify({ - username: username, - password: password, - keepMeLoggedIn: rememberMe, - }) + body: JSON.stringify(requestBody) }); } static async postLogout() { - return this.fetchSafe('/api/logout', { + return this.fetchSafeJson('/api/logout', { method: 'POST', headers: { 'Accept': 'application/json', @@ -62,81 +77,81 @@ class AutheliaService { } static async startU2FRegistrationIdentityProcess() { - return this.fetchSafe('/api/secondfactor/u2f/identity/start', { + return this.fetchSafeJson('/api/secondfactor/u2f/identity/start', { method: 'POST', }); } static async startTOTPRegistrationIdentityProcess() { - return this.fetchSafe('/api/secondfactor/totp/identity/start', { + return this.fetchSafeJson('/api/secondfactor/totp/identity/start', { method: 'POST', }); } static async requestSigning() { - return this.fetchSafeJson('/api/u2f/sign_request'); + return this.fetchSafeJson<{ + appId: string, + challenge: string, + registeredKeys: { + appId: string, + keyHandle: string, + version: string, + }[] + }>('/api/secondfactor/u2f/sign_request', { + method: 'POST' + }); } static async completeSecurityKeySigning( - response: U2fApi.SignResponse, redirectionUrl: string | null) { + response: U2fApi.SignResponse, targetURL: string | null) { - const headers: Record = { - 'Accept': 'application/json', - 'Content-Type': 'application/json', + const headers: Record = {'Content-Type': 'application/json',} + const requestBody: {signResponse: U2fApi.SignResponse, targetURL?: string} = { + signResponse: response, + }; + if (targetURL) { + requestBody.targetURL = targetURL; } - if (redirectionUrl) { - headers['X-Target-Url'] = redirectionUrl; - } - return this.fetchSafe('/api/u2f/sign', { + return this.fetchSafeJson<{redirect: string}|undefined>('/api/secondfactor/u2f/sign', { method: 'POST', headers: headers, - body: JSON.stringify(response), + body: JSON.stringify(requestBody), }); } static async verifyTotpToken( - token: string, redirectionUrl: string | null) { - - const headers: Record = { - 'Accept': 'application/json', + token: string, targetURL: string | null) { + const headers: Record = { 'Content-Type': 'application/json', } - if (redirectionUrl) { - headers['X-Target-Url'] = redirectionUrl; + var requestBody: {token: string, targetURL?: string} = {token}; + if (targetURL) { + requestBody.targetURL = targetURL; } - return this.fetchSafe('/api/totp', { + return this.fetchSafeJson<{redirect: string}|undefined>('/api/secondfactor/totp', { method: 'POST', headers: headers, - body: JSON.stringify({token}), + body: JSON.stringify(requestBody), }) } - static async triggerDuoPush(redirectionUrl: string | null): Promise { + static async triggerDuoPush(targetURL: string | null): Promise<{redirect: string}|undefined> { const headers: Record = { - 'Accept': 'application/json', 'Content-Type': 'application/json', } - if (redirectionUrl) { - headers['X-Target-Url'] = redirectionUrl; + const requestBody: {targetURL?: string} = {} + if (targetURL) { + requestBody.targetURL = targetURL; } - const res = await this.fetchSafe('/api/duo-push', { + return this.fetchSafeJson<{redirect: string}|undefined>('/api/secondfactor/duo', { method: 'POST', headers: headers, + body: JSON.stringify(requestBody), }); - - if (res.status === 204) { - return; - } - - const body = await res.json(); - if ('error' in body) { - throw new Error(body['error']); - } - return body; } static async initiatePasswordResetIdentityValidation(username: string) { - return this.fetchSafe('/api/password-reset/identity/start', { + return this.fetchSafeJson('/api/reset-password/identity/start', { method: 'POST', headers: { 'Accept': 'application/json', @@ -147,13 +162,17 @@ class AutheliaService { } static async completePasswordResetIdentityValidation(token: string) { - return fetch(`/api/password-reset/identity/finish?token=${token}`, { + return this.fetchSafeJson(`/api/reset-password/identity/finish`, { method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({token}) }); } static async resetPassword(newPassword: string) { - return this.fetchSafe('/api/password-reset', { + return this.fetchSafeJson('/api/reset-password', { method: 'POST', headers: { 'Accept': 'application/json', @@ -164,27 +183,14 @@ class AutheliaService { } static async fetchPrefered2faMethod(): Promise { - const doc = await this.fetchSafeJson('/api/secondfactor/preferences'); - if (!doc) { - throw new Error("No response."); - } - - if (doc.error) { - throw new Error(doc.error); - } - - if (!doc.method) { - throw new Error("No method."); - } - - return doc.method; + const res = await this.fetchSafeJson<{method: Method2FA}>('/api/secondfactor/preferences'); + return res.method; } static async setPrefered2faMethod(method: Method2FA): Promise { - await this.fetchSafe('/api/secondfactor/preferences', { + return this.fetchSafeJson('/api/secondfactor/preferences', { method: 'POST', headers: { - 'Accept': 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify({method}) @@ -192,11 +198,12 @@ class AutheliaService { } static async getAvailable2faMethods(): Promise { - return await this.fetchSafeJson('/api/secondfactor/available'); + return this.fetchSafeJson('/api/secondfactor/available'); } - static async completeSecurityKeyRegistration(response: U2fApi.RegisterResponse): Promise { - return await this.fetchSafe('/api/u2f/register', { + static async completeSecurityKeyRegistration( + response: U2fApi.RegisterResponse): Promise { + return this.fetchSafeJson('/api/secondfactor/u2f/register', { method: 'POST', headers: { 'Accept': 'application/json', @@ -206,19 +213,30 @@ class AutheliaService { }); } - static async requestSecurityKeyRegistration() { - return this.fetchSafeJson('/api/u2f/register_request') + static async completeSecurityKeyRegistrationIdentityValidation(token: string) { + return this.fetchSafeJson<{ + appId: string, + registerRequests: [{ + version: string, + challenge: string, + }] + }>(`/api/secondfactor/u2f/identity/finish`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({token}) + }); } - static async completeSecurityKeyRegistrationIdentityValidation(token: string) { - const res = await this.fetchSafeJson(`/api/secondfactor/u2f/identity/finish?token=${token}`, { + static async completeOneTimePasswordRegistrationIdentityValidation(token: string) { + return this.fetchSafeJson<{base32_secret: string, otpauth_url: string}>(`/api/secondfactor/totp/identity/finish`, { method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({token}) }); - - if ('error' in res) { - throw new Error(res['error']); - } - return res; } } diff --git a/client/src/services/RedirectResponse.ts b/client/src/services/RedirectResponse.ts deleted file mode 100644 index b3b16c461..000000000 --- a/client/src/services/RedirectResponse.ts +++ /dev/null @@ -1,6 +0,0 @@ - - -export default interface RedirectResponse { - redirect?: string; - error?: string; -} \ No newline at end of file diff --git a/client/src/views/LogoutView/LogoutView.tsx b/client/src/views/LogoutView/LogoutView.tsx new file mode 100644 index 000000000..f0bfc3394 --- /dev/null +++ b/client/src/views/LogoutView/LogoutView.tsx @@ -0,0 +1,16 @@ +import React from "react" +import { Redirect } from "react-router"; + +async function logout() { + return fetch("/api/logout", {method: "POST"}) +} + +export default class LogoutView extends React.Component { + componentDidMount() { + logout().catch(console.error); + } + + render() { + return ; + } +} \ No newline at end of file diff --git a/config.template.yml b/config.template.yml index a18712039..e2c9b5c24 100644 --- a/config.template.yml +++ b/config.template.yml @@ -10,6 +10,10 @@ port: 9091 # Level of verbosity for logs logs_level: debug +# The secret used to generate JWT tokens when validating user identity by +# email confirmation. +jwt_secret: a_very_important_secret + # Default redirection URL # # If user tries to authenticate without any referer, Authelia @@ -263,19 +267,20 @@ notifier: ## filesystem: ## filename: /tmp/authelia/notification.txt - # Use your email account to send the notifications. You can use an app password. - # List of valid services can be found here: https://nodemailer.com/smtp/well-known/ - ## email: - ## username: user@example.com - ## password: yourpassword - ## sender: admin@example.com - ## service: gmail - - # Use a SMTP server for sending notifications + # Use a SMTP server for sending notifications. Authelia uses PLAIN method to authenticate. + # [Security] Make sure the connection is made over TLS otherwise your password will transit in plain text. smtp: username: test password: password - secure: false host: 127.0.0.1 port: 1025 sender: admin@example.com + + # Sending an email using a Gmail account is as simple as the next section. + # You need to create an app password by following: https://support.google.com/accounts/answer/185833?hl=en + ## smtp: + ## username: myaccount@gmail.com + ## password: yourapppassword + ## sender: admin@example.com + ## host: smtp.gmail.com + ## port: 587 diff --git a/configuration/reader.go b/configuration/reader.go new file mode 100644 index 000000000..972776229 --- /dev/null +++ b/configuration/reader.go @@ -0,0 +1,39 @@ +package configuration + +import ( + "io/ioutil" + + "gopkg.in/yaml.v2" + + "github.com/clems4ever/authelia/configuration/schema" + "github.com/clems4ever/authelia/configuration/validator" +) + +func check(e error) { + if e != nil { + panic(e) + } +} + +// Read a YAML configuration and create a Configuration object out of it. +func Read(configPath string) (*schema.Configuration, []error) { + config := schema.Configuration{} + + data, err := ioutil.ReadFile(configPath) + check(err) + + err = yaml.Unmarshal([]byte(data), &config) + + if err != nil { + return nil, []error{err} + } + + val := schema.NewStructValidator() + validator.Validate(&config, val) + + if val.HasErrors() { + return nil, val.Errors() + } + + return &config, nil +} diff --git a/configuration/reader_test.go b/configuration/reader_test.go new file mode 100644 index 000000000..2e51a2caf --- /dev/null +++ b/configuration/reader_test.go @@ -0,0 +1,22 @@ +package configuration + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestShouldParseConfigFile(t *testing.T) { + config, errors := Read("../test-resources/config.yml") + + assert.Len(t, errors, 0) + + assert.Equal(t, 9091, config.Port) + assert.Equal(t, "debug", config.LogsLevel) + assert.Equal(t, "https://home.example.com:8080/", config.DefaultRedirectionURL) + assert.Equal(t, "authelia.com", config.TOTP.Issuer) + + assert.Equal(t, "api-123456789.example.com", config.DuoAPI.Hostname) + assert.Equal(t, "ABCDEF", config.DuoAPI.IntegrationKey) + assert.Equal(t, "1234567890abcdefghifjkl", config.DuoAPI.SecretKey) +} diff --git a/configuration/schema/access_control.go b/configuration/schema/access_control.go new file mode 100644 index 000000000..d493208d2 --- /dev/null +++ b/configuration/schema/access_control.go @@ -0,0 +1,70 @@ +package schema + +import ( + "fmt" + "net" + "strings" +) + +// ACLRule represent one ACL rule +type ACLRule struct { + Domain string `yaml:"domain"` + Policy string `yaml:"policy"` + Subject string `yaml:"subject"` + Networks []string `yaml:"networks"` + Resources []string `yaml:"resources"` +} + +// IsPolicyValid check if policy is valid +func IsPolicyValid(policy string) bool { + return policy == "deny" || policy == "one_factor" || policy == "two_factor" || policy == "bypass" +} + +// IsSubjectValid check if a subject is valid +func IsSubjectValid(subject string) bool { + return subject == "" || strings.HasPrefix(subject, "user:") || strings.HasPrefix(subject, "group:") +} + +// IsNetworkValid check if a network is valid +func IsNetworkValid(network string) bool { + _, _, err := net.ParseCIDR(network) + return err == nil +} + +// Validate validate an ACL Rule +func (r *ACLRule) Validate(validator *StructValidator) { + if r.Domain == "" { + validator.Push(fmt.Errorf("Domain must be provided")) + } + + if !IsPolicyValid(r.Policy) { + validator.Push(fmt.Errorf("A policy must either be 'deny', 'two_factor', 'one_factor' or 'bypass'")) + } + + if !IsSubjectValid(r.Subject) { + validator.Push(fmt.Errorf("A subject must start with 'user:' or 'group:'")) + } + + for i, network := range r.Networks { + if !IsNetworkValid(network) { + validator.Push(fmt.Errorf("Network %d must be a valid CIDR", i)) + } + } +} + +// AccessControlConfiguration represents the configuration related to ACLs. +type AccessControlConfiguration struct { + DefaultPolicy string `yaml:"default_policy"` + Rules []ACLRule `yaml:"rules"` +} + +// Validate validate the access control configuration +func (acc *AccessControlConfiguration) Validate(validator *StructValidator) { + if acc.DefaultPolicy == "" { + acc.DefaultPolicy = "deny" + } + + if !IsPolicyValid(acc.DefaultPolicy) { + validator.Push(fmt.Errorf("'default_policy' must either be 'deny', 'two_factor', 'one_factor' or 'bypass'")) + } +} diff --git a/configuration/schema/authentication.go b/configuration/schema/authentication.go new file mode 100644 index 000000000..d9ee8dfed --- /dev/null +++ b/configuration/schema/authentication.go @@ -0,0 +1,26 @@ +package schema + +// LDAPAuthenticationBackendConfiguration represents the configuration related to LDAP server. +type LDAPAuthenticationBackendConfiguration struct { + URL string `yaml:"url"` + BaseDN string `yaml:"base_dn"` + AdditionalUsersDN string `yaml:"additional_users_dn"` + UsersFilter string `yaml:"users_filter"` + AdditionalGroupsDN string `yaml:"additional_groups_dn"` + GroupsFilter string `yaml:"groups_filter"` + GroupNameAttribute string `yaml:"group_name_attribute"` + MailAttribute string `yaml:"mail_attribute"` + User string `yaml:"user"` + Password string `yaml:"password"` +} + +// FileAuthenticationBackendConfiguration represents the configuration related to file-based backend +type FileAuthenticationBackendConfiguration struct { + Path string `yaml:"path"` +} + +// AuthenticationBackendConfiguration represents the configuration related to the authentication backend. +type AuthenticationBackendConfiguration struct { + Ldap *LDAPAuthenticationBackendConfiguration `yaml:"ldap"` + File *FileAuthenticationBackendConfiguration `yaml:"file"` +} diff --git a/configuration/schema/configuration.go b/configuration/schema/configuration.go new file mode 100644 index 000000000..3035fcc20 --- /dev/null +++ b/configuration/schema/configuration.go @@ -0,0 +1,18 @@ +package schema + +// Configuration object extracted from YAML configuration file. +type Configuration struct { + Port int `yaml:"port"` + LogsLevel string `yaml:"logs_level"` + JWTSecret string `yaml:"jwt_secret"` + DefaultRedirectionURL string `yaml:"default_redirection_url"` + AuthenticationBackend AuthenticationBackendConfiguration `yaml:"authentication_backend"` + Session SessionConfiguration `yaml:"session"` + + TOTP *TOTPConfiguration `yaml:"totp"` + DuoAPI *DuoAPIConfiguration `yaml:"duo_api"` + AccessControl *AccessControlConfiguration `yaml:"access_control"` + Regulation *RegulationConfiguration `yaml:"regulation"` + Storage *StorageConfiguration `yaml:"storage"` + Notifier *NotifierConfiguration `yaml:"notifier"` +} diff --git a/configuration/schema/duo.go b/configuration/schema/duo.go new file mode 100644 index 000000000..0715463ad --- /dev/null +++ b/configuration/schema/duo.go @@ -0,0 +1,8 @@ +package schema + +// DuoAPIConfiguration represents the configuration related to Duo API. +type DuoAPIConfiguration struct { + Hostname string `yaml:"hostname"` + IntegrationKey string `yaml:"integration_key"` + SecretKey string `yaml:"secret_key"` +} diff --git a/configuration/schema/notifier.go b/configuration/schema/notifier.go new file mode 100644 index 000000000..6a3a7694a --- /dev/null +++ b/configuration/schema/notifier.go @@ -0,0 +1,31 @@ +package schema + +// FileSystemNotifierConfiguration represents the configuration of the notifier writing emails in a file. +type FileSystemNotifierConfiguration struct { + Filename string `yaml:"filename"` +} + +// EmailNotifierConfiguration represents the configuration of the email service notifier (like GMAIL API). +type EmailNotifierConfiguration struct { + Username string `yaml:"username"` + Password string `yaml:"password"` + Sender string `yaml:"sender"` + Service string `yaml:"service"` +} + +// SMTPNotifierConfiguration represents the configuration of the SMTP server to send emails with. +type SMTPNotifierConfiguration struct { + Username string `yaml:"username"` + Password string `yaml:"password"` + Secure string `yaml:"secure"` + Host string `yaml:"host"` + Port int `yaml:"port"` + Sender string `yaml:"sender"` +} + +// NotifierConfiguration representes the configuration of the notifier to use when sending notifications to users. +type NotifierConfiguration struct { + FileSystem *FileSystemNotifierConfiguration `yaml:"filesystem"` + Email *EmailNotifierConfiguration `yaml:"email"` + SMTP *SMTPNotifierConfiguration `yaml:"smtp"` +} diff --git a/configuration/schema/regulation.go b/configuration/schema/regulation.go new file mode 100644 index 000000000..ef5b3a8b6 --- /dev/null +++ b/configuration/schema/regulation.go @@ -0,0 +1,8 @@ +package schema + +// RegulationConfiguration represents the configuration related to regulation. +type RegulationConfiguration struct { + MaxRetries int `yaml:"max_retries"` + FindTime int64 `yaml:"find_time"` + BanTime int64 `yaml:"ban_time"` +} diff --git a/configuration/schema/session.go b/configuration/schema/session.go new file mode 100644 index 000000000..7e66ca42f --- /dev/null +++ b/configuration/schema/session.go @@ -0,0 +1,26 @@ +package schema + +// RedisSessionConfiguration represents the configuration related to redis session store. +type RedisSessionConfiguration struct { + Host string `yaml:"host"` + Port int64 `yaml:"port"` + Password string `yaml:"password"` +} + +// SessionConfiguration represents the configuration related to user sessions. +type SessionConfiguration struct { + Name string `yaml:"name"` + Secret string `yaml:"secret"` + // Expiration in seconds + Expiration int64 `yaml:"expiration"` + // Inactivity in seconds + Inactivity int64 `yaml:"inactivity"` + Domain string `yaml:"domain"` + Redis *RedisSessionConfiguration `yaml:"redis"` +} + +// DefaultSessionConfiguration is the default session configuration +var DefaultSessionConfiguration = SessionConfiguration{ + Name: "authelia_session", + Expiration: 3600, +} diff --git a/configuration/schema/storage.go b/configuration/schema/storage.go new file mode 100644 index 000000000..74c31fb53 --- /dev/null +++ b/configuration/schema/storage.go @@ -0,0 +1,22 @@ +package schema + +// MongoStorageConfiguration represents the configuration related to mongo connection. +type MongoStorageConfiguration struct { + URL string `yaml:"url"` + Database string `yaml:"database"` + Auth struct { + Username string `yaml:"username"` + Password string `yaml:"password"` + } `yaml:"auth"` +} + +// LocalStorageConfiguration represents the configuration when using local storage. +type LocalStorageConfiguration struct { + Path string `yaml:"path"` +} + +// StorageConfiguration represents the configuration of the storage backend. +type StorageConfiguration struct { + Mongo *MongoStorageConfiguration `yaml:"mongo"` + Local *LocalStorageConfiguration `yaml:"local"` +} diff --git a/configuration/schema/totp.go b/configuration/schema/totp.go new file mode 100644 index 000000000..a8b45d9a5 --- /dev/null +++ b/configuration/schema/totp.go @@ -0,0 +1,6 @@ +package schema + +// TOTPConfiguration represents the configuration related to TOTP options. +type TOTPConfiguration struct { + Issuer string +} diff --git a/configuration/schema/validator.go b/configuration/schema/validator.go new file mode 100644 index 000000000..8ad09131e --- /dev/null +++ b/configuration/schema/validator.go @@ -0,0 +1,129 @@ +package schema + +import ( + "fmt" + "reflect" + + "github.com/Workiva/go-datastructures/queue" +) + +// ErrorContainer represents a container where we can add errors and retrieve them +type ErrorContainer interface { + Push(err error) + HasErrors() bool + Errors() []error +} + +// Validator represents the validator interface +type Validator struct { + errors map[string][]error +} + +// NewValidator create a validator +func NewValidator() *Validator { + validator := new(Validator) + validator.errors = make(map[string][]error) + return validator +} + +// QueueItem an item representing a struct field and its path. +type QueueItem struct { + value reflect.Value + path string +} + +func (v *Validator) validateOne(item QueueItem, q *queue.Queue) error { + if item.value.Type().Kind() == reflect.Ptr { + if item.value.IsNil() { + return nil + } + + elem := item.value.Elem() + q.Put(QueueItem{ + value: elem, + path: item.path, + }) + } else if item.value.Kind() == reflect.Struct { + numFields := item.value.Type().NumField() + + validateFn := item.value.Addr().MethodByName("Validate") + + if validateFn.IsValid() { + structValidator := NewStructValidator() + validateFn.Call([]reflect.Value{reflect.ValueOf(structValidator)}) + v.errors[item.path] = structValidator.Errors() + } + + for i := 0; i < numFields; i++ { + field := item.value.Type().Field(i) + value := item.value.Field(i) + + q.Put(QueueItem{ + value: value, + path: item.path + "." + field.Name, + }) + } + } + return nil +} + +// Validate validate a struct +func (v *Validator) Validate(s interface{}) error { + q := queue.New(40) + q.Put(QueueItem{value: reflect.ValueOf(s), path: "root"}) + + for !q.Empty() { + val, err := q.Get(1) + if err != nil { + return err + } + item, ok := val[0].(QueueItem) + if !ok { + return fmt.Errorf("Cannot convert item into QueueItem") + } + v.validateOne(item, q) + } + return nil +} + +// PrintErrors display the errors thrown during validation +func (v *Validator) PrintErrors() { + for path, errs := range v.errors { + fmt.Printf("Errors at %s:\n", path) + for _, err := range errs { + fmt.Printf("--> %s\n", err) + } + } +} + +// Errors return the errors thrown during validation +func (v *Validator) Errors() map[string][]error { + return v.errors +} + +// StructValidator is a validator for structs +type StructValidator struct { + errors []error +} + +// NewStructValidator is a constructor of struct validator +func NewStructValidator() *StructValidator { + val := new(StructValidator) + val.errors = make([]error, 0) + return val +} + +// Push an error in the validator. +func (v *StructValidator) Push(err error) { + v.errors = append(v.errors, err) +} + +// HasErrors checks whether the validator contains errors. +func (v *StructValidator) HasErrors() bool { + return len(v.errors) > 0 +} + +// Errors returns the errors. +func (v *StructValidator) Errors() []error { + return v.errors +} diff --git a/configuration/schema/validator_test.go b/configuration/schema/validator_test.go new file mode 100644 index 000000000..20dc08300 --- /dev/null +++ b/configuration/schema/validator_test.go @@ -0,0 +1,81 @@ +package schema_test + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/clems4ever/authelia/configuration/schema" +) + +type TestNestedStruct struct { + MustBe5 int +} + +func (tns *TestNestedStruct) Validate(validator *schema.StructValidator) { + if tns.MustBe5 != 5 { + validator.Push(fmt.Errorf("MustBe5 must be 5")) + } +} + +type TestStruct struct { + MustBe10 int + NotEmpty string + SetDefault string + Nested TestNestedStruct + Nested2 TestNestedStruct + NilPtr *int + NestedPtr *TestNestedStruct +} + +func (ts *TestStruct) Validate(validator *schema.StructValidator) { + if ts.MustBe10 != 10 { + validator.Push(fmt.Errorf("MustBe10 must be 10")) + } + + if ts.NotEmpty == "" { + validator.Push(fmt.Errorf("NotEmpty must not be empty")) + } + + if ts.SetDefault == "" { + ts.SetDefault = "xyz" + } +} + +func TestValidator(t *testing.T) { + validator := schema.NewValidator() + + s := TestStruct{ + MustBe10: 5, + NotEmpty: "", + NestedPtr: &TestNestedStruct{}, + } + + err := validator.Validate(&s) + if err != nil { + panic(err) + } + + errs := validator.Errors() + assert.Equal(t, 4, len(errs)) + + assert.Equal(t, 2, len(errs["root"])) + assert.ElementsMatch(t, []error{ + fmt.Errorf("MustBe10 must be 10"), + fmt.Errorf("NotEmpty must not be empty")}, errs["root"]) + + assert.Equal(t, 1, len(errs["root.Nested"])) + assert.ElementsMatch(t, []error{ + fmt.Errorf("MustBe5 must be 5")}, errs["root.Nested"]) + + assert.Equal(t, 1, len(errs["root.Nested2"])) + assert.ElementsMatch(t, []error{ + fmt.Errorf("MustBe5 must be 5")}, errs["root.Nested2"]) + + assert.Equal(t, 1, len(errs["root.NestedPtr"])) + assert.ElementsMatch(t, []error{ + fmt.Errorf("MustBe5 must be 5")}, errs["root.NestedPtr"]) + + assert.Equal(t, "xyz", s.SetDefault) +} diff --git a/configuration/validator/authentication.go b/configuration/validator/authentication.go new file mode 100644 index 000000000..b3a8a8c21 --- /dev/null +++ b/configuration/validator/authentication.go @@ -0,0 +1,64 @@ +package validator + +import ( + "errors" + + "github.com/clems4ever/authelia/configuration/schema" +) + +func validateFileAuthenticationBackend(configuration *schema.FileAuthenticationBackendConfiguration, validator *schema.StructValidator) { + if configuration.Path == "" { + validator.Push(errors.New("Please provide a `path` for the users database in `authentication_backend`")) + } +} + +func validateLdapAuthenticationBackend(configuration *schema.LDAPAuthenticationBackendConfiguration, validator *schema.StructValidator) { + if configuration.URL == "" { + validator.Push(errors.New("Please provide a URL to the LDAP server")) + } + + if configuration.User == "" { + validator.Push(errors.New("Please provide a user name to connect to the LDAP server")) + } + + if configuration.Password == "" { + validator.Push(errors.New("Please provide a password to connect to the LDAP server")) + } + + if configuration.BaseDN == "" { + validator.Push(errors.New("Please provide a base DN to connect to the LDAP server")) + } + + if configuration.UsersFilter == "" { + configuration.UsersFilter = "cn={0}" + } + + if configuration.GroupsFilter == "" { + configuration.GroupsFilter = "member={dn}" + } + + if configuration.GroupNameAttribute == "" { + configuration.GroupNameAttribute = "cn" + } + + if configuration.MailAttribute == "" { + configuration.MailAttribute = "mail" + } +} + +// ValidateAuthenticationBackend validates and update authentication backend configuration. +func ValidateAuthenticationBackend(configuration *schema.AuthenticationBackendConfiguration, validator *schema.StructValidator) { + if configuration.Ldap == nil && configuration.File == nil { + validator.Push(errors.New("Please provide `ldap` or `file` object in `authentication_backend`")) + } + + if configuration.Ldap != nil && configuration.File != nil { + validator.Push(errors.New("You cannot provide both `ldap` and `file` objects in `authentication_backend`")) + } + + if configuration.File != nil { + validateFileAuthenticationBackend(configuration.File, validator) + } else if configuration.Ldap != nil { + validateLdapAuthenticationBackend(configuration.Ldap, validator) + } +} diff --git a/configuration/validator/authentication_test.go b/configuration/validator/authentication_test.go new file mode 100644 index 000000000..75ede3a92 --- /dev/null +++ b/configuration/validator/authentication_test.go @@ -0,0 +1,124 @@ +package validator + +import ( + "testing" + + "github.com/clems4ever/authelia/configuration/schema" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +func TestShouldRaiseErrorsWhenNoBackendProvided(t *testing.T) { + validator := schema.NewStructValidator() + backendConfig := schema.AuthenticationBackendConfiguration{} + + ValidateAuthenticationBackend(&backendConfig, validator) + + assert.Len(t, validator.Errors(), 1) + assert.EqualError(t, validator.Errors()[0], "Please provide `ldap` or `file` object in `authentication_backend`") +} + +type FileBasedAuthenticationBackend struct { + suite.Suite + configuration schema.AuthenticationBackendConfiguration + validator *schema.StructValidator +} + +func (suite *FileBasedAuthenticationBackend) SetupTest() { + suite.validator = schema.NewStructValidator() + suite.configuration = schema.AuthenticationBackendConfiguration{} + suite.configuration.File = &schema.FileAuthenticationBackendConfiguration{Path: "/a/path"} +} + +func (suite *FileBasedAuthenticationBackend) TestShouldValidateCompleteConfiguration() { + ValidateAuthenticationBackend(&suite.configuration, suite.validator) + assert.Len(suite.T(), suite.validator.Errors(), 0) +} + +func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenNoPathProvided() { + suite.configuration.File.Path = "" + ValidateAuthenticationBackend(&suite.configuration, suite.validator) + assert.Len(suite.T(), suite.validator.Errors(), 1) + assert.EqualError(suite.T(), suite.validator.Errors()[0], "Please provide a `path` for the users database in `authentication_backend`") +} + +func TestFileBasedAuthenticationBackend(t *testing.T) { + suite.Run(t, new(FileBasedAuthenticationBackend)) +} + +type LdapAuthenticationBackendSuite struct { + suite.Suite + configuration schema.AuthenticationBackendConfiguration + validator *schema.StructValidator +} + +func (suite *LdapAuthenticationBackendSuite) SetupTest() { + suite.validator = schema.NewStructValidator() + suite.configuration = schema.AuthenticationBackendConfiguration{} + suite.configuration.Ldap = &schema.LDAPAuthenticationBackendConfiguration{} + suite.configuration.Ldap.URL = "ldap://ldap" + suite.configuration.Ldap.User = "user" + suite.configuration.Ldap.Password = "password" + suite.configuration.Ldap.BaseDN = "base_dn" +} + +func (suite *LdapAuthenticationBackendSuite) TestShouldValidateCompleteConfiguration() { + ValidateAuthenticationBackend(&suite.configuration, suite.validator) + assert.Len(suite.T(), suite.validator.Errors(), 0) +} + +func (suite *LdapAuthenticationBackendSuite) TestShouldRaiseErrorWhenURLNotProvided() { + suite.configuration.Ldap.URL = "" + ValidateAuthenticationBackend(&suite.configuration, suite.validator) + assert.Len(suite.T(), suite.validator.Errors(), 1) + assert.EqualError(suite.T(), suite.validator.Errors()[0], "Please provide a URL to the LDAP server") +} + +func (suite *LdapAuthenticationBackendSuite) TestShouldRaiseErrorWhenUserNotProvided() { + suite.configuration.Ldap.User = "" + ValidateAuthenticationBackend(&suite.configuration, suite.validator) + assert.Len(suite.T(), suite.validator.Errors(), 1) + assert.EqualError(suite.T(), suite.validator.Errors()[0], "Please provide a user name to connect to the LDAP server") +} + +func (suite *LdapAuthenticationBackendSuite) TestShouldRaiseErrorWhenPasswordNotProvided() { + suite.configuration.Ldap.Password = "" + ValidateAuthenticationBackend(&suite.configuration, suite.validator) + assert.Len(suite.T(), suite.validator.Errors(), 1) + assert.EqualError(suite.T(), suite.validator.Errors()[0], "Please provide a password to connect to the LDAP server") +} + +func (suite *LdapAuthenticationBackendSuite) TestShouldRaiseErrorWhenBaseDNNotProvided() { + suite.configuration.Ldap.BaseDN = "" + ValidateAuthenticationBackend(&suite.configuration, suite.validator) + assert.Len(suite.T(), suite.validator.Errors(), 1) + assert.EqualError(suite.T(), suite.validator.Errors()[0], "Please provide a base DN to connect to the LDAP server") +} + +func (suite *LdapAuthenticationBackendSuite) TestShouldSetDefaultUsersFilter() { + ValidateAuthenticationBackend(&suite.configuration, suite.validator) + assert.Len(suite.T(), suite.validator.Errors(), 0) + assert.Equal(suite.T(), "cn={0}", suite.configuration.Ldap.UsersFilter) +} + +func (suite *LdapAuthenticationBackendSuite) TestShouldSetDefaultGroupsFilter() { + ValidateAuthenticationBackend(&suite.configuration, suite.validator) + assert.Len(suite.T(), suite.validator.Errors(), 0) + assert.Equal(suite.T(), "member={dn}", suite.configuration.Ldap.GroupsFilter) +} + +func (suite *LdapAuthenticationBackendSuite) TestShouldSetDefaultGroupNameAttribute() { + ValidateAuthenticationBackend(&suite.configuration, suite.validator) + assert.Len(suite.T(), suite.validator.Errors(), 0) + assert.Equal(suite.T(), "cn", suite.configuration.Ldap.GroupNameAttribute) +} + +func (suite *LdapAuthenticationBackendSuite) TestShouldSetDefaultMailAttribute() { + ValidateAuthenticationBackend(&suite.configuration, suite.validator) + assert.Len(suite.T(), suite.validator.Errors(), 0) + assert.Equal(suite.T(), "mail", suite.configuration.Ldap.MailAttribute) +} + +func TestLdapAuthenticationBackend(t *testing.T) { + suite.Run(t, new(LdapAuthenticationBackendSuite)) +} diff --git a/configuration/validator/configuration.go b/configuration/validator/configuration.go new file mode 100644 index 000000000..c4837cc14 --- /dev/null +++ b/configuration/validator/configuration.go @@ -0,0 +1,33 @@ +package validator + +import ( + "fmt" + + "github.com/clems4ever/authelia/configuration/schema" +) + +var defaultPort = 8080 +var defaultLogsLevel = "info" + +// Validate and adapt the configuration read from file. +func Validate(configuration *schema.Configuration, validator *schema.StructValidator) { + if configuration.Port == 0 { + configuration.Port = defaultPort + } + + if configuration.LogsLevel == "" { + configuration.LogsLevel = defaultLogsLevel + } + + if configuration.JWTSecret == "" { + validator.Push(fmt.Errorf("Provide a JWT secret using `jwt_secret` key")) + } + + ValidateAuthenticationBackend(&configuration.AuthenticationBackend, validator) + ValidateSession(&configuration.Session, validator) + + if configuration.TOTP == nil { + configuration.TOTP = &schema.TOTPConfiguration{} + ValidateTOTP(configuration.TOTP, validator) + } +} diff --git a/configuration/validator/configuration_test.go b/configuration/validator/configuration_test.go new file mode 100644 index 000000000..c29feee0b --- /dev/null +++ b/configuration/validator/configuration_test.go @@ -0,0 +1,56 @@ +package validator + +import ( + "testing" + + "github.com/clems4ever/authelia/configuration/schema" + "github.com/stretchr/testify/assert" +) + +func newDefaultConfig() schema.Configuration { + config := schema.Configuration{} + config.Port = 9090 + config.LogsLevel = "info" + config.JWTSecret = "a_secret" + config.AuthenticationBackend.File = new(schema.FileAuthenticationBackendConfiguration) + config.AuthenticationBackend.File.Path = "/a/path" + config.Session = schema.SessionConfiguration{ + Domain: "example.com", + Name: "authelia_session", + Secret: "secret", + } + return config +} + +func TestShouldNotUpdateConfig(t *testing.T) { + validator := schema.NewStructValidator() + config := newDefaultConfig() + + Validate(&config, validator) + + assert.Len(t, validator.Errors(), 0) + assert.Equal(t, 9090, config.Port) + assert.Equal(t, "info", config.LogsLevel) +} + +func TestShouldValidateAndUpdatePort(t *testing.T) { + validator := schema.NewStructValidator() + config := newDefaultConfig() + config.Port = 0 + + Validate(&config, validator) + + assert.Len(t, validator.Errors(), 0) + assert.Equal(t, 8080, config.Port) +} + +func TestShouldValidateAndUpdateLogsLevel(t *testing.T) { + validator := schema.NewStructValidator() + config := newDefaultConfig() + config.LogsLevel = "" + + Validate(&config, validator) + + assert.Len(t, validator.Errors(), 0) + assert.Equal(t, "info", config.LogsLevel) +} diff --git a/configuration/validator/session.go b/configuration/validator/session.go new file mode 100644 index 000000000..1ca870c13 --- /dev/null +++ b/configuration/validator/session.go @@ -0,0 +1,26 @@ +package validator + +import ( + "errors" + + "github.com/clems4ever/authelia/configuration/schema" +) + +// ValidateSession validates and update session configuration. +func ValidateSession(configuration *schema.SessionConfiguration, validator *schema.StructValidator) { + if configuration.Name == "" { + configuration.Name = schema.DefaultSessionConfiguration.Name + } + + if configuration.Secret == "" { + validator.Push(errors.New("Set secret of the session object")) + } + + if configuration.Expiration == 0 { + configuration.Expiration = schema.DefaultSessionConfiguration.Expiration // 1 hour + } + + if configuration.Domain == "" { + validator.Push(errors.New("Set domain of the session object")) + } +} diff --git a/configuration/validator/session_test.go b/configuration/validator/session_test.go new file mode 100644 index 000000000..a9c62b0db --- /dev/null +++ b/configuration/validator/session_test.go @@ -0,0 +1,47 @@ +package validator + +import ( + "testing" + + "github.com/clems4ever/authelia/configuration/schema" + "github.com/stretchr/testify/assert" +) + +func newDefaultSessionConfig() schema.SessionConfiguration { + config := schema.SessionConfiguration{} + config.Secret = "a_secret" + config.Domain = "example.com" + return config +} + +func TestShouldSetDefaultSessionName(t *testing.T) { + validator := schema.NewStructValidator() + config := newDefaultSessionConfig() + + ValidateSession(&config, validator) + + assert.Len(t, validator.Errors(), 0) + assert.Equal(t, "authelia_session", config.Name) +} + +func TestShouldRaiseErrorWhenPasswordNotSet(t *testing.T) { + validator := schema.NewStructValidator() + config := newDefaultSessionConfig() + config.Secret = "" + + ValidateSession(&config, validator) + + assert.Len(t, validator.Errors(), 1) + assert.EqualError(t, validator.Errors()[0], "Set secret of the session object") +} + +func TestShouldRaiseErrorWhenDomainNotSet(t *testing.T) { + validator := schema.NewStructValidator() + config := newDefaultSessionConfig() + config.Domain = "" + + ValidateSession(&config, validator) + + assert.Len(t, validator.Errors(), 1) + assert.EqualError(t, validator.Errors()[0], "Set domain of the session object") +} diff --git a/configuration/validator/totp.go b/configuration/validator/totp.go new file mode 100644 index 000000000..e2cda5b02 --- /dev/null +++ b/configuration/validator/totp.go @@ -0,0 +1,14 @@ +package validator + +import ( + "github.com/clems4ever/authelia/configuration/schema" +) + +const defaultTOTPIssuer = "Authelia" + +// ValidateTOTP validates and update TOTP configuration. +func ValidateTOTP(configuration *schema.TOTPConfiguration, validator *schema.StructValidator) { + if configuration.Issuer == "" { + configuration.Issuer = defaultTOTPIssuer + } +} diff --git a/docs/proxies/nginx.md b/docs/proxies/nginx.md index 58f869b67..cfc932fa2 100644 --- a/docs/proxies/nginx.md +++ b/docs/proxies/nginx.md @@ -14,7 +14,7 @@ Here is a commented example of configuration set $upstream_verify https://authelia.example.com/api/verify; set $upstream_endpoint http://nginx-backend; - ssl_certificate /etc/ssl/server.crt; + ssl_certificate /etc/ssl/server.cert; ssl_certificate_key /etc/ssl/server.key; # Use HSTS, please beware of what you're doing if you set it. diff --git a/duo/duo.go b/duo/duo.go new file mode 100644 index 000000000..13f924b54 --- /dev/null +++ b/duo/duo.go @@ -0,0 +1,32 @@ +package duo + +import ( + "encoding/json" + "net/url" + + "github.com/duosecurity/duo_api_golang" +) + +// NewDuoAPI create duo API instance +func NewDuoAPI(duoAPI *duoapi.DuoApi) *APIImpl { + api := new(APIImpl) + api.DuoApi = duoAPI + return api +} + +// Call call to the DuoAPI +func (d *APIImpl) Call(values url.Values) (*Response, error) { + _, responseBytes, err := d.DuoApi.SignedCall("POST", "/auth/v2/auth", values) + + if err != nil { + return nil, err + } + + var response Response + err = json.Unmarshal(responseBytes, &response) + if err != nil { + return nil, err + } + + return &response, nil +} diff --git a/duo/types.go b/duo/types.go new file mode 100644 index 000000000..8f529c986 --- /dev/null +++ b/duo/types.go @@ -0,0 +1,24 @@ +package duo + +import "net/url" +import "github.com/duosecurity/duo_api_golang" + +// API interface wrapping duo api library for testing purpose +type API interface { + Call(values url.Values) (*Response, error) +} + +// APIImpl implementation of DuoAPI interface +type APIImpl struct { + *duoapi.DuoApi +} + +// Response response coming from Duo API +type Response struct { + Response struct { + Result string `json:"result"` + Status string `json:"status"` + StatusMessage string `json:"status_msg"` + } `json:"response"` + Stat string `json:"stat"` +} diff --git a/example/compose/nginx/kubernetes/nginx.conf b/example/compose/nginx/kubernetes/nginx.conf index 6efca6976..d14b56f1e 100644 --- a/example/compose/nginx/kubernetes/nginx.conf +++ b/example/compose/nginx/kubernetes/nginx.conf @@ -15,7 +15,7 @@ http { resolver 127.0.0.11 ipv6=off; - ssl_certificate /etc/ssl/server.crt; + ssl_certificate /etc/ssl/server.cert; ssl_certificate_key /etc/ssl/server.key; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; diff --git a/example/compose/nginx/kubernetes/ssl/server.cert b/example/compose/nginx/kubernetes/ssl/server.cert new file mode 100644 index 000000000..0fd2ff140 --- /dev/null +++ b/example/compose/nginx/kubernetes/ssl/server.cert @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDEzCCAfugAwIBAgIUJZXxXExVQPJhc8TnlD+uAAYHlvwwDQYJKoZIhvcNAQEL +BQAwGDEWMBQGA1UEAwwNKi5leGFtcGxlLmNvbTAgFw0xOTA5MjYyMDAwMTBaGA8y +MTE5MDkwMjIwMDAxMFowGDEWMBQGA1UEAwwNKi5leGFtcGxlLmNvbTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3DFTAdrxG6iOj5UjSeB5lMjMQQyeYm +OxUvswwwBzmQYPUt0inAJ9QmXJ8i9Fbye8HHYUeqE5zsEfeHir81MiWfhi9oUzJt +u3bmxGLDXYaApejd18hBKITX6MYogmK2lWrl/F9zPYxc2xM/fqWnGg2xwdrMmida +hZjDUfh0rtoz8zqOzJaiiDoFMwNO+NTGmDbeOwBFYOF1OTkS3aJWwJCLZmINUG8h +Z3YPR+SL8CpGGl0xhJYAwXD1AtMlYwAteTILqrqvo2XkGsvuj0mx0w/D0DDpC48g +oSNsRIVTW3Ql3uu+kXDFtkf4I63Ctt85rZk1kX3QtYmS0pRzvmyY/b0CAwEAAaNT +MFEwHQYDVR0OBBYEFMTozK79Kp813+8TstjXRFw1MTE5MB8GA1UdIwQYMBaAFMTo +zK79Kp813+8TstjXRFw1MTE5MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBALf1bJf3qF3m54+q98E6lSE+34yi/rVdzB9reAW1QzvvqdJRtsfjt39R +SznsbmrvCfK4SLyOj9Uhd8Z6bASPPNsUux1XAGN4AqaGmlYI8b7j3LhKCdRBZQ0I +zWgPhocyWwp5VkFe68zR06NHme/2B6eBRFsdd/69DIOv9YnEGUHk3A/9v1zvolt9 +krW57Oz63zWGYXmtPPTD8of/Ya6NKqwonVx1MUQ5QzqH3WySYhRsIYqwUEXm9jt5 +GEM3Nx0phEltaOLXa71nqS/Rhg/5Kod0cFaNoSKb6N93I8bqKKTK0m5wMJ5Fisrm +Pw5+AIar7RT5gHU2DD2/OTb9bXXww8I= +-----END CERTIFICATE----- diff --git a/example/compose/nginx/kubernetes/ssl/server.crt b/example/compose/nginx/kubernetes/ssl/server.crt deleted file mode 100644 index abe89b561..000000000 --- a/example/compose/nginx/kubernetes/ssl/server.crt +++ /dev/null @@ -1,13 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICATCCAWoCCQCvH2RvyOshNzANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB -VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 -cyBQdHkgTHRkMB4XDTE3MDExNzIzMTc0M1oXDTE4MDExNzIzMTc0M1owRTELMAkG -A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 -IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAzZaE -4XE1QyFNbrHBHRhSA53anAsJ5mBeG7Om6SdQcZAYahlDWEbtdoY4hy0gPNGcITcW -eE+WA+PvNRr7PczKEhneIyUUgV+nrz010fM5JnECPxLTe1oFzl4U8dyYiBpTziNz -hiUfq733PRYjcd9BQtcKcN4LdmQvjUHnnQ73TysCAwEAATANBgkqhkiG9w0BAQsF -AAOBgQAUFICtbuqXgL4HBRAg7yGbwokoH8Ar1QKZGe+F2WTR8vaDLOYUL7VsltLE -EJIGrcfs31nItHOBcLJuflrS8y0CQqes5puRw33LL2usSvO8z2q7JhCx+DSBi6yN -RbhcrGOllIdjsrbmd/zAMBVTUyxSisq3Nmk1cZayDvKg+GSAEA== ------END CERTIFICATE----- diff --git a/example/compose/nginx/kubernetes/ssl/server.csr b/example/compose/nginx/kubernetes/ssl/server.csr deleted file mode 100644 index 80b307a91..000000000 --- a/example/compose/nginx/kubernetes/ssl/server.csr +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIIBhDCB7gIBADBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEh -MB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEB -AQUAA4GNADCBiQKBgQDNloThcTVDIU1uscEdGFIDndqcCwnmYF4bs6bpJ1BxkBhq -GUNYRu12hjiHLSA80ZwhNxZ4T5YD4+81Gvs9zMoSGd4jJRSBX6evPTXR8zkmcQI/ -EtN7WgXOXhTx3JiIGlPOI3OGJR+rvfc9FiNx30FC1wpw3gt2ZC+NQeedDvdPKwID -AQABoAAwDQYJKoZIhvcNAQELBQADgYEAmCX60kspIw1Zfb79AQOarFW5Q2K2h5Vx -/cRbDyHlKtbmG77EtICccULyqf76B1gNRw5Zq3lSotSUcLzsWcdesXCFDC7k87Qf -mpQKPj6GdTYJvdWf8aDwt32tAqWuBIRoAbdx5WbFPPWVfDcm7zDJefBrhNUDH0Qd -vcnxjvPMmOM= ------END CERTIFICATE REQUEST----- diff --git a/example/compose/nginx/kubernetes/ssl/server.key b/example/compose/nginx/kubernetes/ssl/server.key index 23a513ce1..268a2a1c3 100644 --- a/example/compose/nginx/kubernetes/ssl/server.key +++ b/example/compose/nginx/kubernetes/ssl/server.key @@ -1,15 +1,27 @@ -----BEGIN RSA PRIVATE KEY----- -MIICXQIBAAKBgQDNloThcTVDIU1uscEdGFIDndqcCwnmYF4bs6bpJ1BxkBhqGUNY -Ru12hjiHLSA80ZwhNxZ4T5YD4+81Gvs9zMoSGd4jJRSBX6evPTXR8zkmcQI/EtN7 -WgXOXhTx3JiIGlPOI3OGJR+rvfc9FiNx30FC1wpw3gt2ZC+NQeedDvdPKwIDAQAB -AoGBAIwGcfkO30UawJ+daDeF4g5ejI/toM+NYWuiwBNbWJoQl+Bj1o+gt4obvxKq -tKNX7OxelepZ4oZB0CIuf2LHQfU6cVGdu//or7nfS2FLBYStopZyL6KorZbkqsj1 -ikQN4GosJQqaYkexnwjItMFaHaRRX6YnIXp42Jl1glitO3+5AkEA+thn/vwFo24I -fC+7ORpmLi+BVAkTuhMm+C6TIV6s64B+A5oQ82OBCYK9YCOWmS6JHHFDrxJla+3M -2U9KXky63wJBANHQCFCirfuT6esSjbqpCeqtmZG5LWHtL12V9DF7yjHPjmHL9uRu -e9W+Uz33IJbqd82gtZ/ARfpYEjD0JEieQTUCQFo872xzDTQ1qSfDo/5u2MNUo5mv -ikEuEp7FYnhmrp4poyt4iRCFgy4Ask+bfdmtO/XXaRnZ7FJfQYoLVB2ITNECQQCN -gOiauZztl4yj5heAVJFDnWF9To61BOp1C7VtyjdL8NfuTUluNrV+KqapnAp2vhue -q0zTOTH47X0XVxFBiLohAkBuQzPey5I3Ui8inE4sDt/fqX8r/GMhBTxIb9KlV/H6 -jKZNs/83n5/ohaX36er8svW9PB4pcqENZ+kBpvDtKVwS +MIIEpAIBAAKCAQEAvcMVMB2vEbqI6PlSNJ4HmUyMxBDJ5iY7FS+zDDAHOZBg9S3S +KcAn1CZcnyL0VvJ7wcdhR6oTnOwR94eKvzUyJZ+GL2hTMm27dubEYsNdhoCl6N3X +yEEohNfoxiiCYraVauX8X3M9jFzbEz9+pacaDbHB2syaJ1qFmMNR+HSu2jPzOo7M +lqKIOgUzA0741MaYNt47AEVg4XU5ORLdolbAkItmYg1QbyFndg9H5IvwKkYaXTGE +lgDBcPUC0yVjAC15Mguquq+jZeQay+6PSbHTD8PQMOkLjyChI2xEhVNbdCXe676R +cMW2R/gjrcK23zmtmTWRfdC1iZLSlHO+bJj9vQIDAQABAoIBAEZvkP/JJOCJwqPn +V3IcbmmilmV4bdi1vByDFgyiDyx4wOSA24+PubjvfFW9XcCgRPuKjDtTj/AhWBHv +B7stfa2lZuNV7/u562mZArA+IAr62Zp0LdIxDV8x3T8gbjVB3HhPYbv0RJZDKTYd +zV6jhfIrVu9mHpoY6ZnodhapCPYIyk/d49KBIHZuAc25CUjMXgTeaVtf0c996036 +UxW6ef33wAOJAvW0RCvbXAJfmBeEq2qQlkjTIlpYx71fhZWexHifi8Ouv3Zonc+1 +/P2Adq5uzYVBT92f9RKHg9QxxNzVrLjSMaxyvUtWQCAQfW0tFIRdqBGsHYsQrFtI +F4yzv8ECgYEA7ntpyN9HD9Z9lYQzPCR73sFCLM+ID99aVij0wHuxK97bkSyyvkLd +7MyTaym3lg1UEqWNWBCLvFULZx7F0Ah6qCzD4ymm3Bj/ADpWWPgljBI0AFml+HHs +hcATmXUrj5QbLyhiP2gmJjajp1o/rgATx6ED66seSynD6JOH8wUhhZUCgYEAy7OA +06PF8GfseNsTqlDjNF0K7lOqd21S0prdwrsJLiVzUlfMM25MLE0XLDUutCnRheeh +IlcuDoBsVTxz6rkvFGD74N+pgXlN4CicsBq5ofK060PbqCQhSII3fmHobrZ9Cr75 +HmBjAxHx998SKaAAGbBbcYGUAp521i1pH5CEPYkCgYEAkUd1Zf0+2RMdZhwm6hh/ +rW+l1I6IoMK70YkZsLipccRNld7Y9LbfYwYtODcts6di9AkOVfueZJiaXbONZfIE +Zrb+jkAteh9wGL9xIrnohbABJcV3Kiaco84jInUSmGDtPokncOENfHIEuEpuSJ2b +bx1TuhmAVuGWivR0+ULC7RECgYEAgS0cDRpWc9Xzh9Cl7+PLsXEvdWNpPsL9OsEq +0Ep7z9+/+f/jZtoTRCS/BTHUpDvAuwHglT5j3p5iFMt5VuiIiovWLwynGYwrbnNS +qfrIrYKUaH1n1oDS+oBZYLQGCe9/7EifAjxtjYzbvSyg//SPG7tSwfBCREbpZXj2 +qSWkNsECgYA/mCDzCTlrrWPuiepo6kTmN+4TnFA+hJI6NccDVQ+jvbqEdoJ4SW4L +zqfZSZRFJMNpSgIqkQNRPJqMP0jQ5KRtJrjMWBnYxktwKz9fDg2R2MxdFgMF2LH2 +HEMMhFHlv8NDjVOXh1KwRoltNGVWYsSrD9wKU9GhRCEfmNCGrvBcEg== -----END RSA PRIVATE KEY----- diff --git a/example/compose/nginx/portal/nginx.conf.ejs b/example/compose/nginx/portal/nginx.conf.ejs index 41b368882..01ff8a307 100644 --- a/example/compose/nginx/portal/nginx.conf.ejs +++ b/example/compose/nginx/portal/nginx.conf.ejs @@ -18,7 +18,7 @@ http { resolver 127.0.0.11 ipv6=off; set $backend_endpoint <%= authelia_backend %>; - ssl_certificate /etc/ssl/server.crt; + ssl_certificate /etc/ssl/server.cert; ssl_certificate_key /etc/ssl/server.key; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; @@ -26,7 +26,7 @@ http { # Serves the portal application. location / { - proxy_pass $backend_endpoint/index.html; + proxy_pass $backend_endpoint; } location /static { @@ -62,7 +62,7 @@ http { set $frontend_endpoint http://192.168.240.1:3000; set $backend_endpoint <%= authelia_backend %>; - ssl_certificate /etc/ssl/server.crt; + ssl_certificate /etc/ssl/server.cert; ssl_certificate_key /etc/ssl/server.key; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; @@ -108,7 +108,7 @@ http { resolver 127.0.0.11 ipv6=off; set $upstream_endpoint http://nginx-backend; - ssl_certificate /etc/ssl/server.crt; + ssl_certificate /etc/ssl/server.cert; ssl_certificate_key /etc/ssl/server.key; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; @@ -135,7 +135,7 @@ http { set $upstream_endpoint http://nginx-backend; set $upstream_headers http://httpbin:8000/headers; - ssl_certificate /etc/ssl/server.crt; + ssl_certificate /etc/ssl/server.cert; ssl_certificate_key /etc/ssl/server.key; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; @@ -179,7 +179,7 @@ http { proxy_set_header X-Real-IP $remote_addr; # Provide either X-Original-URL and X-Forwarded-Proto or - # X-Forwarded-Proto, X-Forwarded-Host and X-Forwarded-Uri or both. + # X-Forwarded-Proto, X-Forwarded-Host and X-Forwarded-URI or both. # Those headers will be used by Authelia to deduce the target url of the user. # # X-Forwarded-Proto is mandatory since Authelia uses the "trust proxy" option. @@ -188,7 +188,7 @@ http { proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $http_host; - proxy_set_header X-Forwarded-Uri $request_uri; + proxy_set_header X-Forwarded-URI $request_uri; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; @@ -227,7 +227,7 @@ http { resolver 127.0.0.11 ipv6=off; set $upstream_endpoint http://smtp:1080; - ssl_certificate /etc/ssl/server.crt; + ssl_certificate /etc/ssl/server.cert; ssl_certificate_key /etc/ssl/server.key; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; @@ -247,7 +247,7 @@ http { resolver 127.0.0.11 ipv6=off; set $upstream_endpoint http://duo-api:3000; - ssl_certificate /etc/ssl/server.crt; + ssl_certificate /etc/ssl/server.cert; ssl_certificate_key /etc/ssl/server.key; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; @@ -264,7 +264,7 @@ http { listen 8080 ssl; server_name _; - ssl_certificate /etc/ssl/server.crt; + ssl_certificate /etc/ssl/server.cert; ssl_certificate_key /etc/ssl/server.key; return 301 https://home.example.com:8080/; diff --git a/example/compose/nginx/portal/ssl/server.cert b/example/compose/nginx/portal/ssl/server.cert new file mode 100644 index 000000000..0fd2ff140 --- /dev/null +++ b/example/compose/nginx/portal/ssl/server.cert @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDEzCCAfugAwIBAgIUJZXxXExVQPJhc8TnlD+uAAYHlvwwDQYJKoZIhvcNAQEL +BQAwGDEWMBQGA1UEAwwNKi5leGFtcGxlLmNvbTAgFw0xOTA5MjYyMDAwMTBaGA8y +MTE5MDkwMjIwMDAxMFowGDEWMBQGA1UEAwwNKi5leGFtcGxlLmNvbTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3DFTAdrxG6iOj5UjSeB5lMjMQQyeYm +OxUvswwwBzmQYPUt0inAJ9QmXJ8i9Fbye8HHYUeqE5zsEfeHir81MiWfhi9oUzJt +u3bmxGLDXYaApejd18hBKITX6MYogmK2lWrl/F9zPYxc2xM/fqWnGg2xwdrMmida +hZjDUfh0rtoz8zqOzJaiiDoFMwNO+NTGmDbeOwBFYOF1OTkS3aJWwJCLZmINUG8h +Z3YPR+SL8CpGGl0xhJYAwXD1AtMlYwAteTILqrqvo2XkGsvuj0mx0w/D0DDpC48g +oSNsRIVTW3Ql3uu+kXDFtkf4I63Ctt85rZk1kX3QtYmS0pRzvmyY/b0CAwEAAaNT +MFEwHQYDVR0OBBYEFMTozK79Kp813+8TstjXRFw1MTE5MB8GA1UdIwQYMBaAFMTo +zK79Kp813+8TstjXRFw1MTE5MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBALf1bJf3qF3m54+q98E6lSE+34yi/rVdzB9reAW1QzvvqdJRtsfjt39R +SznsbmrvCfK4SLyOj9Uhd8Z6bASPPNsUux1XAGN4AqaGmlYI8b7j3LhKCdRBZQ0I +zWgPhocyWwp5VkFe68zR06NHme/2B6eBRFsdd/69DIOv9YnEGUHk3A/9v1zvolt9 +krW57Oz63zWGYXmtPPTD8of/Ya6NKqwonVx1MUQ5QzqH3WySYhRsIYqwUEXm9jt5 +GEM3Nx0phEltaOLXa71nqS/Rhg/5Kod0cFaNoSKb6N93I8bqKKTK0m5wMJ5Fisrm +Pw5+AIar7RT5gHU2DD2/OTb9bXXww8I= +-----END CERTIFICATE----- diff --git a/example/compose/nginx/portal/ssl/server.crt b/example/compose/nginx/portal/ssl/server.crt deleted file mode 100644 index abe89b561..000000000 --- a/example/compose/nginx/portal/ssl/server.crt +++ /dev/null @@ -1,13 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICATCCAWoCCQCvH2RvyOshNzANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB -VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 -cyBQdHkgTHRkMB4XDTE3MDExNzIzMTc0M1oXDTE4MDExNzIzMTc0M1owRTELMAkG -A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 -IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAzZaE -4XE1QyFNbrHBHRhSA53anAsJ5mBeG7Om6SdQcZAYahlDWEbtdoY4hy0gPNGcITcW -eE+WA+PvNRr7PczKEhneIyUUgV+nrz010fM5JnECPxLTe1oFzl4U8dyYiBpTziNz -hiUfq733PRYjcd9BQtcKcN4LdmQvjUHnnQ73TysCAwEAATANBgkqhkiG9w0BAQsF -AAOBgQAUFICtbuqXgL4HBRAg7yGbwokoH8Ar1QKZGe+F2WTR8vaDLOYUL7VsltLE -EJIGrcfs31nItHOBcLJuflrS8y0CQqes5puRw33LL2usSvO8z2q7JhCx+DSBi6yN -RbhcrGOllIdjsrbmd/zAMBVTUyxSisq3Nmk1cZayDvKg+GSAEA== ------END CERTIFICATE----- diff --git a/example/compose/nginx/portal/ssl/server.csr b/example/compose/nginx/portal/ssl/server.csr deleted file mode 100644 index 80b307a91..000000000 --- a/example/compose/nginx/portal/ssl/server.csr +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIIBhDCB7gIBADBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEh -MB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEB -AQUAA4GNADCBiQKBgQDNloThcTVDIU1uscEdGFIDndqcCwnmYF4bs6bpJ1BxkBhq -GUNYRu12hjiHLSA80ZwhNxZ4T5YD4+81Gvs9zMoSGd4jJRSBX6evPTXR8zkmcQI/ -EtN7WgXOXhTx3JiIGlPOI3OGJR+rvfc9FiNx30FC1wpw3gt2ZC+NQeedDvdPKwID -AQABoAAwDQYJKoZIhvcNAQELBQADgYEAmCX60kspIw1Zfb79AQOarFW5Q2K2h5Vx -/cRbDyHlKtbmG77EtICccULyqf76B1gNRw5Zq3lSotSUcLzsWcdesXCFDC7k87Qf -mpQKPj6GdTYJvdWf8aDwt32tAqWuBIRoAbdx5WbFPPWVfDcm7zDJefBrhNUDH0Qd -vcnxjvPMmOM= ------END CERTIFICATE REQUEST----- diff --git a/example/compose/nginx/portal/ssl/server.key b/example/compose/nginx/portal/ssl/server.key index 23a513ce1..268a2a1c3 100644 --- a/example/compose/nginx/portal/ssl/server.key +++ b/example/compose/nginx/portal/ssl/server.key @@ -1,15 +1,27 @@ -----BEGIN RSA PRIVATE KEY----- -MIICXQIBAAKBgQDNloThcTVDIU1uscEdGFIDndqcCwnmYF4bs6bpJ1BxkBhqGUNY -Ru12hjiHLSA80ZwhNxZ4T5YD4+81Gvs9zMoSGd4jJRSBX6evPTXR8zkmcQI/EtN7 -WgXOXhTx3JiIGlPOI3OGJR+rvfc9FiNx30FC1wpw3gt2ZC+NQeedDvdPKwIDAQAB -AoGBAIwGcfkO30UawJ+daDeF4g5ejI/toM+NYWuiwBNbWJoQl+Bj1o+gt4obvxKq -tKNX7OxelepZ4oZB0CIuf2LHQfU6cVGdu//or7nfS2FLBYStopZyL6KorZbkqsj1 -ikQN4GosJQqaYkexnwjItMFaHaRRX6YnIXp42Jl1glitO3+5AkEA+thn/vwFo24I -fC+7ORpmLi+BVAkTuhMm+C6TIV6s64B+A5oQ82OBCYK9YCOWmS6JHHFDrxJla+3M -2U9KXky63wJBANHQCFCirfuT6esSjbqpCeqtmZG5LWHtL12V9DF7yjHPjmHL9uRu -e9W+Uz33IJbqd82gtZ/ARfpYEjD0JEieQTUCQFo872xzDTQ1qSfDo/5u2MNUo5mv -ikEuEp7FYnhmrp4poyt4iRCFgy4Ask+bfdmtO/XXaRnZ7FJfQYoLVB2ITNECQQCN -gOiauZztl4yj5heAVJFDnWF9To61BOp1C7VtyjdL8NfuTUluNrV+KqapnAp2vhue -q0zTOTH47X0XVxFBiLohAkBuQzPey5I3Ui8inE4sDt/fqX8r/GMhBTxIb9KlV/H6 -jKZNs/83n5/ohaX36er8svW9PB4pcqENZ+kBpvDtKVwS +MIIEpAIBAAKCAQEAvcMVMB2vEbqI6PlSNJ4HmUyMxBDJ5iY7FS+zDDAHOZBg9S3S +KcAn1CZcnyL0VvJ7wcdhR6oTnOwR94eKvzUyJZ+GL2hTMm27dubEYsNdhoCl6N3X +yEEohNfoxiiCYraVauX8X3M9jFzbEz9+pacaDbHB2syaJ1qFmMNR+HSu2jPzOo7M +lqKIOgUzA0741MaYNt47AEVg4XU5ORLdolbAkItmYg1QbyFndg9H5IvwKkYaXTGE +lgDBcPUC0yVjAC15Mguquq+jZeQay+6PSbHTD8PQMOkLjyChI2xEhVNbdCXe676R +cMW2R/gjrcK23zmtmTWRfdC1iZLSlHO+bJj9vQIDAQABAoIBAEZvkP/JJOCJwqPn +V3IcbmmilmV4bdi1vByDFgyiDyx4wOSA24+PubjvfFW9XcCgRPuKjDtTj/AhWBHv +B7stfa2lZuNV7/u562mZArA+IAr62Zp0LdIxDV8x3T8gbjVB3HhPYbv0RJZDKTYd +zV6jhfIrVu9mHpoY6ZnodhapCPYIyk/d49KBIHZuAc25CUjMXgTeaVtf0c996036 +UxW6ef33wAOJAvW0RCvbXAJfmBeEq2qQlkjTIlpYx71fhZWexHifi8Ouv3Zonc+1 +/P2Adq5uzYVBT92f9RKHg9QxxNzVrLjSMaxyvUtWQCAQfW0tFIRdqBGsHYsQrFtI +F4yzv8ECgYEA7ntpyN9HD9Z9lYQzPCR73sFCLM+ID99aVij0wHuxK97bkSyyvkLd +7MyTaym3lg1UEqWNWBCLvFULZx7F0Ah6qCzD4ymm3Bj/ADpWWPgljBI0AFml+HHs +hcATmXUrj5QbLyhiP2gmJjajp1o/rgATx6ED66seSynD6JOH8wUhhZUCgYEAy7OA +06PF8GfseNsTqlDjNF0K7lOqd21S0prdwrsJLiVzUlfMM25MLE0XLDUutCnRheeh +IlcuDoBsVTxz6rkvFGD74N+pgXlN4CicsBq5ofK060PbqCQhSII3fmHobrZ9Cr75 +HmBjAxHx998SKaAAGbBbcYGUAp521i1pH5CEPYkCgYEAkUd1Zf0+2RMdZhwm6hh/ +rW+l1I6IoMK70YkZsLipccRNld7Y9LbfYwYtODcts6di9AkOVfueZJiaXbONZfIE +Zrb+jkAteh9wGL9xIrnohbABJcV3Kiaco84jInUSmGDtPokncOENfHIEuEpuSJ2b +bx1TuhmAVuGWivR0+ULC7RECgYEAgS0cDRpWc9Xzh9Cl7+PLsXEvdWNpPsL9OsEq +0Ep7z9+/+f/jZtoTRCS/BTHUpDvAuwHglT5j3p5iFMt5VuiIiovWLwynGYwrbnNS +qfrIrYKUaH1n1oDS+oBZYLQGCe9/7EifAjxtjYzbvSyg//SPG7tSwfBCREbpZXj2 +qSWkNsECgYA/mCDzCTlrrWPuiepo6kTmN+4TnFA+hJI6NccDVQ+jvbqEdoJ4SW4L +zqfZSZRFJMNpSgIqkQNRPJqMP0jQ5KRtJrjMWBnYxktwKz9fDg2R2MxdFgMF2LH2 +HEMMhFHlv8NDjVOXh1KwRoltNGVWYsSrD9wKU9GhRCEfmNCGrvBcEg== -----END RSA PRIVATE KEY----- diff --git a/example/kube/apps/ssl/server.cert b/example/kube/apps/ssl/server.cert new file mode 100644 index 000000000..0fd2ff140 --- /dev/null +++ b/example/kube/apps/ssl/server.cert @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDEzCCAfugAwIBAgIUJZXxXExVQPJhc8TnlD+uAAYHlvwwDQYJKoZIhvcNAQEL +BQAwGDEWMBQGA1UEAwwNKi5leGFtcGxlLmNvbTAgFw0xOTA5MjYyMDAwMTBaGA8y +MTE5MDkwMjIwMDAxMFowGDEWMBQGA1UEAwwNKi5leGFtcGxlLmNvbTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3DFTAdrxG6iOj5UjSeB5lMjMQQyeYm +OxUvswwwBzmQYPUt0inAJ9QmXJ8i9Fbye8HHYUeqE5zsEfeHir81MiWfhi9oUzJt +u3bmxGLDXYaApejd18hBKITX6MYogmK2lWrl/F9zPYxc2xM/fqWnGg2xwdrMmida +hZjDUfh0rtoz8zqOzJaiiDoFMwNO+NTGmDbeOwBFYOF1OTkS3aJWwJCLZmINUG8h +Z3YPR+SL8CpGGl0xhJYAwXD1AtMlYwAteTILqrqvo2XkGsvuj0mx0w/D0DDpC48g +oSNsRIVTW3Ql3uu+kXDFtkf4I63Ctt85rZk1kX3QtYmS0pRzvmyY/b0CAwEAAaNT +MFEwHQYDVR0OBBYEFMTozK79Kp813+8TstjXRFw1MTE5MB8GA1UdIwQYMBaAFMTo +zK79Kp813+8TstjXRFw1MTE5MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBALf1bJf3qF3m54+q98E6lSE+34yi/rVdzB9reAW1QzvvqdJRtsfjt39R +SznsbmrvCfK4SLyOj9Uhd8Z6bASPPNsUux1XAGN4AqaGmlYI8b7j3LhKCdRBZQ0I +zWgPhocyWwp5VkFe68zR06NHme/2B6eBRFsdd/69DIOv9YnEGUHk3A/9v1zvolt9 +krW57Oz63zWGYXmtPPTD8of/Ya6NKqwonVx1MUQ5QzqH3WySYhRsIYqwUEXm9jt5 +GEM3Nx0phEltaOLXa71nqS/Rhg/5Kod0cFaNoSKb6N93I8bqKKTK0m5wMJ5Fisrm +Pw5+AIar7RT5gHU2DD2/OTb9bXXww8I= +-----END CERTIFICATE----- diff --git a/example/kube/apps/ssl/server.key b/example/kube/apps/ssl/server.key new file mode 100644 index 000000000..268a2a1c3 --- /dev/null +++ b/example/kube/apps/ssl/server.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAvcMVMB2vEbqI6PlSNJ4HmUyMxBDJ5iY7FS+zDDAHOZBg9S3S +KcAn1CZcnyL0VvJ7wcdhR6oTnOwR94eKvzUyJZ+GL2hTMm27dubEYsNdhoCl6N3X +yEEohNfoxiiCYraVauX8X3M9jFzbEz9+pacaDbHB2syaJ1qFmMNR+HSu2jPzOo7M +lqKIOgUzA0741MaYNt47AEVg4XU5ORLdolbAkItmYg1QbyFndg9H5IvwKkYaXTGE +lgDBcPUC0yVjAC15Mguquq+jZeQay+6PSbHTD8PQMOkLjyChI2xEhVNbdCXe676R +cMW2R/gjrcK23zmtmTWRfdC1iZLSlHO+bJj9vQIDAQABAoIBAEZvkP/JJOCJwqPn +V3IcbmmilmV4bdi1vByDFgyiDyx4wOSA24+PubjvfFW9XcCgRPuKjDtTj/AhWBHv +B7stfa2lZuNV7/u562mZArA+IAr62Zp0LdIxDV8x3T8gbjVB3HhPYbv0RJZDKTYd +zV6jhfIrVu9mHpoY6ZnodhapCPYIyk/d49KBIHZuAc25CUjMXgTeaVtf0c996036 +UxW6ef33wAOJAvW0RCvbXAJfmBeEq2qQlkjTIlpYx71fhZWexHifi8Ouv3Zonc+1 +/P2Adq5uzYVBT92f9RKHg9QxxNzVrLjSMaxyvUtWQCAQfW0tFIRdqBGsHYsQrFtI +F4yzv8ECgYEA7ntpyN9HD9Z9lYQzPCR73sFCLM+ID99aVij0wHuxK97bkSyyvkLd +7MyTaym3lg1UEqWNWBCLvFULZx7F0Ah6qCzD4ymm3Bj/ADpWWPgljBI0AFml+HHs +hcATmXUrj5QbLyhiP2gmJjajp1o/rgATx6ED66seSynD6JOH8wUhhZUCgYEAy7OA +06PF8GfseNsTqlDjNF0K7lOqd21S0prdwrsJLiVzUlfMM25MLE0XLDUutCnRheeh +IlcuDoBsVTxz6rkvFGD74N+pgXlN4CicsBq5ofK060PbqCQhSII3fmHobrZ9Cr75 +HmBjAxHx998SKaAAGbBbcYGUAp521i1pH5CEPYkCgYEAkUd1Zf0+2RMdZhwm6hh/ +rW+l1I6IoMK70YkZsLipccRNld7Y9LbfYwYtODcts6di9AkOVfueZJiaXbONZfIE +Zrb+jkAteh9wGL9xIrnohbABJcV3Kiaco84jInUSmGDtPokncOENfHIEuEpuSJ2b +bx1TuhmAVuGWivR0+ULC7RECgYEAgS0cDRpWc9Xzh9Cl7+PLsXEvdWNpPsL9OsEq +0Ep7z9+/+f/jZtoTRCS/BTHUpDvAuwHglT5j3p5iFMt5VuiIiovWLwynGYwrbnNS +qfrIrYKUaH1n1oDS+oBZYLQGCe9/7EifAjxtjYzbvSyg//SPG7tSwfBCREbpZXj2 +qSWkNsECgYA/mCDzCTlrrWPuiepo6kTmN+4TnFA+hJI6NccDVQ+jvbqEdoJ4SW4L +zqfZSZRFJMNpSgIqkQNRPJqMP0jQ5KRtJrjMWBnYxktwKz9fDg2R2MxdFgMF2LH2 +HEMMhFHlv8NDjVOXh1KwRoltNGVWYsSrD9wKU9GhRCEfmNCGrvBcEg== +-----END RSA PRIVATE KEY----- diff --git a/example/kube/apps/ssl/tls.crt b/example/kube/apps/ssl/tls.crt deleted file mode 100644 index abe89b561..000000000 --- a/example/kube/apps/ssl/tls.crt +++ /dev/null @@ -1,13 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICATCCAWoCCQCvH2RvyOshNzANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB -VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 -cyBQdHkgTHRkMB4XDTE3MDExNzIzMTc0M1oXDTE4MDExNzIzMTc0M1owRTELMAkG -A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 -IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAzZaE -4XE1QyFNbrHBHRhSA53anAsJ5mBeG7Om6SdQcZAYahlDWEbtdoY4hy0gPNGcITcW -eE+WA+PvNRr7PczKEhneIyUUgV+nrz010fM5JnECPxLTe1oFzl4U8dyYiBpTziNz -hiUfq733PRYjcd9BQtcKcN4LdmQvjUHnnQ73TysCAwEAATANBgkqhkiG9w0BAQsF -AAOBgQAUFICtbuqXgL4HBRAg7yGbwokoH8Ar1QKZGe+F2WTR8vaDLOYUL7VsltLE -EJIGrcfs31nItHOBcLJuflrS8y0CQqes5puRw33LL2usSvO8z2q7JhCx+DSBi6yN -RbhcrGOllIdjsrbmd/zAMBVTUyxSisq3Nmk1cZayDvKg+GSAEA== ------END CERTIFICATE----- diff --git a/example/kube/apps/ssl/tls.key b/example/kube/apps/ssl/tls.key deleted file mode 100644 index 23a513ce1..000000000 --- a/example/kube/apps/ssl/tls.key +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICXQIBAAKBgQDNloThcTVDIU1uscEdGFIDndqcCwnmYF4bs6bpJ1BxkBhqGUNY -Ru12hjiHLSA80ZwhNxZ4T5YD4+81Gvs9zMoSGd4jJRSBX6evPTXR8zkmcQI/EtN7 -WgXOXhTx3JiIGlPOI3OGJR+rvfc9FiNx30FC1wpw3gt2ZC+NQeedDvdPKwIDAQAB -AoGBAIwGcfkO30UawJ+daDeF4g5ejI/toM+NYWuiwBNbWJoQl+Bj1o+gt4obvxKq -tKNX7OxelepZ4oZB0CIuf2LHQfU6cVGdu//or7nfS2FLBYStopZyL6KorZbkqsj1 -ikQN4GosJQqaYkexnwjItMFaHaRRX6YnIXp42Jl1glitO3+5AkEA+thn/vwFo24I -fC+7ORpmLi+BVAkTuhMm+C6TIV6s64B+A5oQ82OBCYK9YCOWmS6JHHFDrxJla+3M -2U9KXky63wJBANHQCFCirfuT6esSjbqpCeqtmZG5LWHtL12V9DF7yjHPjmHL9uRu -e9W+Uz33IJbqd82gtZ/ARfpYEjD0JEieQTUCQFo872xzDTQ1qSfDo/5u2MNUo5mv -ikEuEp7FYnhmrp4poyt4iRCFgy4Ask+bfdmtO/XXaRnZ7FJfQYoLVB2ITNECQQCN -gOiauZztl4yj5heAVJFDnWF9To61BOp1C7VtyjdL8NfuTUluNrV+KqapnAp2vhue -q0zTOTH47X0XVxFBiLohAkBuQzPey5I3Ui8inE4sDt/fqX8r/GMhBTxIb9KlV/H6 -jKZNs/83n5/ohaX36er8svW9PB4pcqENZ+kBpvDtKVwS ------END RSA PRIVATE KEY----- diff --git a/example/kube/authelia/configs/config.yml b/example/kube/authelia/configs/config.yml index 95762b494..8c67c370c 100644 --- a/example/kube/authelia/configs/config.yml +++ b/example/kube/authelia/configs/config.yml @@ -10,6 +10,8 @@ port: 80 # Level of verbosity for logs logs_level: debug +jwt_secret: an_unsecure_secret + # Default redirection URL # # If user tries to authenticate without any referer, Authelia @@ -35,7 +37,7 @@ authentication_backend: # production. ldap: # The url of the ldap server - url: ldap://ldap-service + url: ldap-service:389 # The base dn for every entries base_dn: dc=example,dc=com @@ -46,7 +48,7 @@ authentication_backend: # The users filter used to find the user DN # {0} is a matcher replaced by username. # 'cn={0}' by default. - users_filter: cn={0} + users_filter: (cn={0}) # An additional dn to define the scope of groups additional_groups_dn: ou=groups @@ -195,20 +197,9 @@ notifier: # For testing purpose, notifications can be sent in a file # filesystem: # filename: /tmp/authelia/notification.txt - - # Use your email account to send the notifications. You can use an app password. - # List of valid services can be found here: https://nodemailer.com/smtp/well-known/ - # email: - # username: authelia@gmail.com - # password: password - # sender: authelia@example.com - # service: gmail # Use a SMTP server for sending notifications smtp: - username: test - password: password - secure: false host: 'mailcatcher-service' port: 1025 sender: admin@example.com diff --git a/example/kube/bootstrap.sh b/example/kube/bootstrap.sh index c372a3d38..38e23c926 100755 --- a/example/kube/bootstrap.sh +++ b/example/kube/bootstrap.sh @@ -2,7 +2,7 @@ start_apps() { # Create TLS certificate and key for HTTPS termination - kubectl create secret generic test-app-tls --namespace=authelia --from-file=apps/ssl/tls.key --from-file=apps/ssl/tls.crt + kubectl create secret generic test-app-tls --namespace=authelia --from-file=apps/ssl/server.key --from-file=apps/ssl/server.cert # Spawn the applications kubectl apply -f apps @@ -13,7 +13,11 @@ start_ingress_controller() { } start_dashboard() { - kubectl apply -f dashboard + kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta4/aio/deploy/recommended.yaml + kubectl apply -f dashboard.yml + + echo "Bearer token for UI user." + kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}') } # Spawn Redis and Mongo as backend for Authelia @@ -28,6 +32,7 @@ start_mail() { } start_ldap() { + kubectl create configmap ldap-config --namespace=authelia --from-file=ldap/base.ldif --from-file=ldap/access.rules kubectl apply -f ldap } diff --git a/example/kube/dashboard.yml b/example/kube/dashboard.yml new file mode 100644 index 000000000..fe4bebcc7 --- /dev/null +++ b/example/kube/dashboard.yml @@ -0,0 +1,20 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: admin-user + namespace: kubernetes-dashboard + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: admin-user +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: +- kind: ServiceAccount + name: admin-user + namespace: kubernetes-dashboard diff --git a/example/kube/dashboard/dashboard.yaml b/example/kube/dashboard/dashboard.yaml deleted file mode 100644 index 059769f1e..000000000 --- a/example/kube/dashboard/dashboard.yaml +++ /dev/null @@ -1,179 +0,0 @@ -# Copyright 2017 The Kubernetes Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# ------------------- Dashboard Secret ------------------- # - -apiVersion: v1 -kind: Secret -metadata: - labels: - k8s-app: kubernetes-dashboard - name: kubernetes-dashboard-certs - namespace: kube-system -type: Opaque - ---- -# ------------------- Dashboard Service Account ------------------- # - -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - k8s-app: kubernetes-dashboard - name: kubernetes-dashboard - namespace: kube-system - ---- -# ------------------- Dashboard Role & Role Binding ------------------- # - -kind: Role -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: kubernetes-dashboard-minimal - namespace: kube-system -rules: - # Allow Dashboard to create 'kubernetes-dashboard-key-holder' secret. -- apiGroups: [""] - resources: ["secrets"] - verbs: ["create"] - # Allow Dashboard to create 'kubernetes-dashboard-settings' config map. -- apiGroups: [""] - resources: ["configmaps"] - verbs: ["create"] - # Allow Dashboard to get, update and delete Dashboard exclusive secrets. -- apiGroups: [""] - resources: ["secrets"] - resourceNames: ["kubernetes-dashboard-key-holder", "kubernetes-dashboard-certs"] - verbs: ["get", "update", "delete"] - # Allow Dashboard to get and update 'kubernetes-dashboard-settings' config map. -- apiGroups: [""] - resources: ["configmaps"] - resourceNames: ["kubernetes-dashboard-settings"] - verbs: ["get", "update"] - # Allow Dashboard to get metrics from heapster. -- apiGroups: [""] - resources: ["services"] - resourceNames: ["heapster"] - verbs: ["proxy"] -- apiGroups: [""] - resources: ["services/proxy"] - resourceNames: ["heapster", "http:heapster:", "https:heapster:"] - verbs: ["get"] - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: kubernetes-dashboard-minimal - namespace: kube-system -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: kubernetes-dashboard-minimal -subjects: -- kind: ServiceAccount - name: kubernetes-dashboard - namespace: kube-system - ---- -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRoleBinding -metadata: - name: kubernetes-dashboard - labels: - k8s-app: kubernetes-dashboard -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cluster-admin -subjects: -- kind: ServiceAccount - name: kubernetes-dashboard - namespace: kube-system - ---- -# ------------------- Dashboard Deployment ------------------- # - -kind: Deployment -apiVersion: apps/v1 -metadata: - labels: - k8s-app: kubernetes-dashboard - name: kubernetes-dashboard - namespace: kube-system -spec: - replicas: 1 - revisionHistoryLimit: 10 - selector: - matchLabels: - k8s-app: kubernetes-dashboard - template: - metadata: - labels: - k8s-app: kubernetes-dashboard - spec: - containers: - - name: kubernetes-dashboard - image: k8s.gcr.io/kubernetes-dashboard-amd64:v1.10.1 - ports: - - containerPort: 8443 - protocol: TCP - args: - - --auto-generate-certificates - - --enable-skip-login - # Uncomment the following line to manually specify Kubernetes API server Host - # If not specified, Dashboard will attempt to auto discover the API server and connect - # to it. Uncomment only if the default does not work. - # - --apiserver-host=http://my-address:port - volumeMounts: - - name: kubernetes-dashboard-certs - mountPath: /certs - # Create on-disk volume to store exec logs - - mountPath: /tmp - name: tmp-volume - livenessProbe: - httpGet: - scheme: HTTPS - path: / - port: 8443 - initialDelaySeconds: 30 - timeoutSeconds: 30 - volumes: - - name: kubernetes-dashboard-certs - secret: - secretName: kubernetes-dashboard-certs - - name: tmp-volume - emptyDir: {} - serviceAccountName: kubernetes-dashboard - # Comment the following tolerations if Dashboard must not be deployed on master - tolerations: - - key: node-role.kubernetes.io/master - effect: NoSchedule - ---- -# ------------------- Dashboard Service ------------------- # - -kind: Service -apiVersion: v1 -metadata: - labels: - k8s-app: kubernetes-dashboard - name: kubernetes-dashboard - namespace: kube-system -spec: - ports: - - port: 443 - targetPort: 8443 - selector: - k8s-app: kubernetes-dashboard diff --git a/example/kube/ldap/Dockerfile b/example/kube/ldap/Dockerfile deleted file mode 100644 index c7e70e0c0..000000000 --- a/example/kube/ldap/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM clems4ever/openldap - -ENV SLAPD_ORGANISATION=MyCompany -ENV SLAPD_DOMAIN=example.com -ENV SLAPD_PASSWORD=password -ENV SLAPD_CONFIG_PASSWORD=password -ENV SLAPD_ADDITIONAL_MODULES=memberof -ENV SLAPD_ADDITIONAL_SCHEMAS=openldap -ENV SLAPD_FORCE_RECONFIGURE=true - -ADD base.ldif /etc/ldap.dist/prepopulate/base.ldif -ADD access.rules /etc/ldap.dist/prepopulate/access.rules diff --git a/example/kube/ldap/access.rules b/example/kube/ldap/access.rules new file mode 100644 index 000000000..8762639e2 --- /dev/null +++ b/example/kube/ldap/access.rules @@ -0,0 +1,7 @@ +olcAccess: {0}to attrs=userPassword,shadowLastChange by self write by anonymou + s auth by * none +# olcAccess: {1}to dn.base="" by * read +# olcAccess: {2}to * by * read + +olcPasswordHash: {CRYPT} +olcPasswordCryptSaltFormat: $6$rounds=50000$%.16s diff --git a/example/kube/ldap/base.ldif b/example/kube/ldap/base.ldif new file mode 100644 index 000000000..3136eb89f --- /dev/null +++ b/example/kube/ldap/base.ldif @@ -0,0 +1,62 @@ +dn: ou=groups,dc=example,dc=com +objectclass: organizationalUnit +objectclass: top +ou: groups + +dn: ou=users,dc=example,dc=com +objectclass: organizationalUnit +objectclass: top +ou: users + +dn: cn=dev,ou=groups,dc=example,dc=com +cn: dev +member: cn=john,ou=users,dc=example,dc=com +member: cn=bob,ou=users,dc=example,dc=com +objectclass: groupOfNames +objectclass: top + +dn: cn=admin,ou=groups,dc=example,dc=com +cn: admin +member: cn=john,ou=users,dc=example,dc=com +objectclass: groupOfNames +objectclass: top + +dn: cn=john,ou=users,dc=example,dc=com +cn: john +objectclass: inetOrgPerson +objectclass: top +mail: john.doe@authelia.com +sn: John Doe +userpassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/ + +dn: cn=harry,ou=users,dc=example,dc=com +cn: harry +objectclass: inetOrgPerson +objectclass: top +mail: harry.potter@authelia.com +sn: Harry Potter +userpassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/ + +dn: cn=bob,ou=users,dc=example,dc=com +cn: bob +objectclass: inetOrgPerson +objectclass: top +mail: bob.dylan@authelia.com +sn: Bob Dylan +userpassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/ + +dn: cn=james,ou=users,dc=example,dc=com +cn: james +objectclass: inetOrgPerson +objectclass: top +mail: james.dean@authelia.com +sn: James Dean +userpassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/ + +dn: cn=blackhat,ou=users,dc=example,dc=com +cn: blackhat +objectclass: inetOrgPerson +objectclass: top +mail: billy.blackhat@authelia.com +sn: Billy BlackHat +userpassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/ diff --git a/example/kube/ldap/deployment.yml b/example/kube/ldap/deployment.yml index fea1cefd2..8c46627ae 100644 --- a/example/kube/ldap/deployment.yml +++ b/example/kube/ldap/deployment.yml @@ -21,3 +21,30 @@ spec: image: clems4ever/authelia-test-ldap ports: - containerPort: 389 + env: + - name: SLAPD_ORGANISATION + value: MyCompany + - name: SLAPD_DOMAIN + value: example.com + - name: SLAPD_PASSWORD + value: password + - name: SLAPD_CONFIG_PASSWORD + value: password + - name: SLAPD_ADDITIONAL_MODULES + value: memberof + - name: SLAPD_ADDITIONAL_SCHEMAS + value: openldap + - name: SLAPD_FORCE_RECONFIGURE + value: "true" + volumeMounts: + - name: config-volume + mountPath: /etc/ldap.dist/prepopulate + volumes: + - name: config-volume + configMap: + name: ldap-config + items: + - key: base.ldif + path: base.ldif + - key: access.rules + path: access.rules diff --git a/handlers/const.go b/handlers/const.go new file mode 100644 index 000000000..844f56ad0 --- /dev/null +++ b/handlers/const.go @@ -0,0 +1,36 @@ +package handlers + +// TOTPRegistrationAction is the string representation of the action for which the token has been produced. +const TOTPRegistrationAction = "RegisterTOTPDevice" + +// U2FRegistrationAction is the string representation of the action for which the token has been produced. +const U2FRegistrationAction = "RegisterU2FDevice" + +// ResetPasswordAction is the string representation of the action for which the token has been produced. +const ResetPasswordAction = "ResetPassword" + +const authPrefix = "Basic " + +const authorizationHeader = "Proxy-Authorization" +const remoteUserHeader = "Remote-User" +const remoteGroupsHeader = "Remote-Groups" + +var protoHostSeparator = []byte("://") + +const ( + // Forbidden means the user is forbidden the access to a resource + Forbidden authorizationMatching = iota + // NotAuthorized means the user can access the resource with more permissions. + NotAuthorized authorizationMatching = iota + // Authorized means the user is authorized given her current permissions. + Authorized authorizationMatching = iota +) + +const operationFailedMessage = "Operation failed." +const authenticationFailedMessage = "Authentication failed. Check your credentials." +const userBannedMessage = "Please retry in a few minutes." +const unableToRegisterOneTimePasswordMessage = "Unable to set up one-time passwords." +const unableToRegisterSecurityKeyMessage = "Unable to register your security key." +const unableToResetPasswordMessage = "Unable to reset your password." +const mfaValidationFailedMessage = "Authentication failed, please retry later." +const badBasicAuthFormatMessage = "Content of Proxy-Authorization header is wrong." diff --git a/handlers/errors.go b/handlers/errors.go new file mode 100644 index 000000000..f9ebdb356 --- /dev/null +++ b/handlers/errors.go @@ -0,0 +1,12 @@ +package handlers + +import "errors" + +// InternalError is the error message sent when there was an internal error but it should +// be hidden to the end user. In that case the error should be in the server logs. +const InternalError = "Internal error." + +// UnauthorizedError is the error message sent when the user is not authorized. +const UnauthorizedError = "You're not authorized." + +var errMissingHeadersForTargetURL = errors.New("Missing headers for detecting target URL") diff --git a/handlers/handler_2fa_available_methods.go b/handlers/handler_2fa_available_methods.go new file mode 100644 index 000000000..c3ba46a73 --- /dev/null +++ b/handlers/handler_2fa_available_methods.go @@ -0,0 +1,19 @@ +package handlers + +import ( + "github.com/clems4ever/authelia/authentication" + "github.com/clems4ever/authelia/middlewares" +) + +// SecondFactorAvailableMethodsGet retrieve available 2FA methods. +// The supported methods are: "totp", "u2f", "duo" +func SecondFactorAvailableMethodsGet(ctx *middlewares.AutheliaCtx) { + availableMethods := MethodList{authentication.TOTP, authentication.U2F} + + if ctx.Configuration.DuoAPI != nil { + availableMethods = append(availableMethods, authentication.DuoPush) + } + + ctx.Logger.Debugf("Available methods are %s", availableMethods) + ctx.SetJSONBody(availableMethods) +} diff --git a/handlers/handler_2fa_available_methods_test.go b/handlers/handler_2fa_available_methods_test.go new file mode 100644 index 000000000..fa7de9fb7 --- /dev/null +++ b/handlers/handler_2fa_available_methods_test.go @@ -0,0 +1,42 @@ +package handlers + +import ( + "testing" + + "github.com/clems4ever/authelia/mocks" + + "github.com/clems4ever/authelia/configuration/schema" + "github.com/stretchr/testify/suite" +) + +type SecondFactorAvailableMethodsFixture struct { + suite.Suite + + mock *mocks.MockAutheliaCtx +} + +func (s *SecondFactorAvailableMethodsFixture) SetupTest() { + s.mock = mocks.NewMockAutheliaCtx(s.T()) +} + +func (s *SecondFactorAvailableMethodsFixture) TearDownTest() { + s.mock.Close() +} + +func (s *SecondFactorAvailableMethodsFixture) TestShouldServeDefaultMethods() { + SecondFactorAvailableMethodsGet(s.mock.Ctx) + s.mock.Assert200OK(s.T(), []string{"totp", "u2f"}) +} + +func (s *SecondFactorAvailableMethodsFixture) TestShouldServeDefaultMethodsAndDuo() { + s.mock.Ctx.Configuration = schema.Configuration{ + DuoAPI: &schema.DuoAPIConfiguration{}, + } + SecondFactorAvailableMethodsGet(s.mock.Ctx) + s.mock.Assert200OK(s.T(), []string{"totp", "u2f", "duo_push"}) +} + +func TestRunSuite(t *testing.T) { + s := new(SecondFactorAvailableMethodsFixture) + suite.Run(t, s) +} diff --git a/handlers/handler_2fa_preferences.go b/handlers/handler_2fa_preferences.go new file mode 100644 index 000000000..c40549a05 --- /dev/null +++ b/handlers/handler_2fa_preferences.go @@ -0,0 +1,68 @@ +package handlers + +import ( + "fmt" + + "github.com/clems4ever/authelia/authentication" + "github.com/clems4ever/authelia/middlewares" +) + +// SecondFactorPreferencesGet get the user preferences regarding 2FA. +func SecondFactorPreferencesGet(ctx *middlewares.AutheliaCtx) { + preferences := preferences{ + Method: "totp", + } + + userSession := ctx.GetSession() + method, err := ctx.Providers.StorageProvider.LoadPrefered2FAMethod(userSession.Username) + ctx.Logger.Debugf("Loaded prefered 2FA method of user %s is %s", userSession.Username, method) + + if err != nil { + ctx.Error(fmt.Errorf("Unable to load prefered 2FA method: %s", err), operationFailedMessage) + return + } + + if method != "" { + // Set the retrieved method. + preferences.Method = method + } + + ctx.SetJSONBody(preferences) +} + +func stringInSlice(a string, list []string) bool { + for _, b := range list { + if b == a { + return true + } + } + return false +} + +// SecondFactorPreferencesPost update the user preferences regarding 2FA. +func SecondFactorPreferencesPost(ctx *middlewares.AutheliaCtx) { + bodyJSON := preferences{} + + err := ctx.ParseBody(&bodyJSON) + if err != nil { + ctx.Error(err, operationFailedMessage) + return + } + + if !stringInSlice(bodyJSON.Method, authentication.PossibleMethods) { + ctx.Error(fmt.Errorf("Unknown method %s, it should be either u2f, totp or duo_push", bodyJSON.Method), operationFailedMessage) + return + } + + userSession := ctx.GetSession() + + ctx.Logger.Debugf("Save new prefered 2FA method of user %s to %s", userSession.Username, bodyJSON.Method) + err = ctx.Providers.StorageProvider.SavePrefered2FAMethod(userSession.Username, bodyJSON.Method) + + if err != nil { + ctx.Error(fmt.Errorf("Unable to save new prefered 2FA method: %s", err), operationFailedMessage) + return + } + + ctx.ReplyOK() +} diff --git a/handlers/handler_2fa_preferences_test.go b/handlers/handler_2fa_preferences_test.go new file mode 100644 index 000000000..2d7ae71db --- /dev/null +++ b/handlers/handler_2fa_preferences_test.go @@ -0,0 +1,129 @@ +package handlers + +import ( + "fmt" + "testing" + + "github.com/clems4ever/authelia/mocks" + + "github.com/golang/mock/gomock" + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +type SecondFactorPreferencesSuite struct { + suite.Suite + + mock *mocks.MockAutheliaCtx +} + +func (s *SecondFactorPreferencesSuite) SetupTest() { + s.mock = mocks.NewMockAutheliaCtx(s.T()) + // Set the intial user session. + userSession := s.mock.Ctx.GetSession() + userSession.Username = "john" + userSession.AuthenticationLevel = 1 + s.mock.Ctx.SaveSession(userSession) +} + +func (s *SecondFactorPreferencesSuite) TearDownTest() { + s.mock.Close() +} + +// GET + +func (s *SecondFactorPreferencesSuite) TestShouldGetPreferenceRetrievedFromStorage() { + s.mock.StorageProviderMock.EXPECT(). + LoadPrefered2FAMethod(gomock.Eq("john")). + Return("u2f", nil) + SecondFactorPreferencesGet(s.mock.Ctx) + + s.mock.Assert200OK(s.T(), preferences{Method: "u2f"}) +} + +func (s *SecondFactorPreferencesSuite) TestShouldGetDefaultPreferenceIfNotInDB() { + s.mock.StorageProviderMock.EXPECT(). + LoadPrefered2FAMethod(gomock.Eq("john")). + Return("", nil) + SecondFactorPreferencesGet(s.mock.Ctx) + + s.mock.Assert200OK(s.T(), preferences{Method: "totp"}) +} + +func (s *SecondFactorPreferencesSuite) TestShouldReturnError500WhenStorageFailsToLoad() { + s.mock.StorageProviderMock.EXPECT(). + LoadPrefered2FAMethod(gomock.Eq("john")). + Return("", fmt.Errorf("Failure")) + SecondFactorPreferencesGet(s.mock.Ctx) + + s.mock.Assert200KO(s.T(), "Operation failed.") + assert.Equal(s.T(), "Unable to load prefered 2FA method: Failure", s.mock.Hook.LastEntry().Message) + assert.Equal(s.T(), logrus.ErrorLevel, s.mock.Hook.LastEntry().Level) +} + +// POST + +func (s *SecondFactorPreferencesSuite) TestShouldReturnError500WhenNoBodyProvided() { + SecondFactorPreferencesPost(s.mock.Ctx) + + s.mock.Assert200KO(s.T(), "Operation failed.") + assert.Equal(s.T(), "Unable to parse body: unexpected end of JSON input", s.mock.Hook.LastEntry().Message) + assert.Equal(s.T(), logrus.ErrorLevel, s.mock.Hook.LastEntry().Level) +} + +func (s *SecondFactorPreferencesSuite) TestShouldReturnError500WhenMalformedBodyProvided() { + s.mock.Ctx.Request.SetBody([]byte("{\"method\":\"abc\"")) + SecondFactorPreferencesPost(s.mock.Ctx) + + s.mock.Assert200KO(s.T(), "Operation failed.") + assert.Equal(s.T(), "Unable to parse body: unexpected end of JSON input", s.mock.Hook.LastEntry().Message) + assert.Equal(s.T(), logrus.ErrorLevel, s.mock.Hook.LastEntry().Level) +} + +func (s *SecondFactorPreferencesSuite) TestShouldReturnError500WhenBadBodyProvided() { + s.mock.Ctx.Request.SetBody([]byte("{\"weird_key\":\"abc\"}")) + SecondFactorPreferencesPost(s.mock.Ctx) + + s.mock.Assert200KO(s.T(), "Operation failed.") + assert.Equal(s.T(), "Unable to validate body: method: non zero value required", s.mock.Hook.LastEntry().Message) + assert.Equal(s.T(), logrus.ErrorLevel, s.mock.Hook.LastEntry().Level) +} + +func (s *SecondFactorPreferencesSuite) TestShouldReturnError500WhenBadMethodProvided() { + s.mock.Ctx.Request.SetBody([]byte("{\"method\":\"abc\"}")) + SecondFactorPreferencesPost(s.mock.Ctx) + + s.mock.Assert200KO(s.T(), "Operation failed.") + assert.Equal(s.T(), "Unknown method abc, it should be either u2f, totp or duo_push", s.mock.Hook.LastEntry().Message) + assert.Equal(s.T(), logrus.ErrorLevel, s.mock.Hook.LastEntry().Level) +} + +func (s *SecondFactorPreferencesSuite) TestShouldReturnError500WhenDatabaseFailsToSave() { + s.mock.Ctx.Request.SetBody([]byte("{\"method\":\"u2f\"}")) + s.mock.StorageProviderMock.EXPECT(). + SavePrefered2FAMethod(gomock.Eq("john"), gomock.Eq("u2f")). + Return(fmt.Errorf("Failure")) + + SecondFactorPreferencesPost(s.mock.Ctx) + + s.mock.Assert200KO(s.T(), "Operation failed.") + assert.Equal(s.T(), "Unable to save new prefered 2FA method: Failure", s.mock.Hook.LastEntry().Message) + assert.Equal(s.T(), logrus.ErrorLevel, s.mock.Hook.LastEntry().Level) +} + +func (s *SecondFactorPreferencesSuite) TestShouldReturn200WhenMethodIsSuccessfullySaved() { + s.mock.Ctx.Request.SetBody([]byte("{\"method\":\"u2f\"}")) + s.mock.StorageProviderMock.EXPECT(). + SavePrefered2FAMethod(gomock.Eq("john"), gomock.Eq("u2f")). + Return(nil) + + SecondFactorPreferencesPost(s.mock.Ctx) + + assert.Equal(s.T(), 200, s.mock.Ctx.Response.StatusCode()) +} + +func TestRunPreferencesSuite(t *testing.T) { + s := new(SecondFactorPreferencesSuite) + suite.Run(t, s) +} diff --git a/handlers/handler_firstfactor.go b/handlers/handler_firstfactor.go new file mode 100644 index 000000000..d4615a825 --- /dev/null +++ b/handlers/handler_firstfactor.go @@ -0,0 +1,133 @@ +package handlers + +import ( + "fmt" + "net/url" + "time" + + "github.com/clems4ever/authelia/regulation" + + "github.com/clems4ever/authelia/session" + + "github.com/clems4ever/authelia/authentication" + "github.com/clems4ever/authelia/authorization" + "github.com/clems4ever/authelia/middlewares" +) + +// FirstFactorPost is the handler performing the first factory. +func FirstFactorPost(ctx *middlewares.AutheliaCtx) { + bodyJSON := firstFactorRequestBody{} + err := ctx.ParseBody(&bodyJSON) + + if err != nil { + ctx.Error(err, authenticationFailedMessage) + return + } + + bannedUntil, err := ctx.Providers.Regulator.Regulate(bodyJSON.Username) + + if err == regulation.ErrUserIsBanned { + ctx.Error(fmt.Errorf("User %s is banned until %s", bodyJSON.Username, bannedUntil), userBannedMessage) + return + } else if err != nil { + ctx.Error(fmt.Errorf("Unable to regulate authentication: %s", err), authenticationFailedMessage) + return + } + + userPasswordOk, err := ctx.Providers.UserProvider.CheckUserPassword(bodyJSON.Username, bodyJSON.Password) + + if err != nil { + ctx.Error(fmt.Errorf("Error while checking password for user %s: %s", bodyJSON.Username, err.Error()), authenticationFailedMessage) + return + } + + ctx.Logger.Debugf("Mark authentication attempt made by user %s", bodyJSON.Username) + // Mark the authentication attempt and whether it was successful. + err = ctx.Providers.Regulator.Mark(bodyJSON.Username, userPasswordOk) + + if err != nil { + ctx.Error(fmt.Errorf("Unable to mark authentication: %s", err), authenticationFailedMessage) + return + } + + if !userPasswordOk { + ctx.Error(fmt.Errorf("Credentials are wrong for user %s", bodyJSON.Username), authenticationFailedMessage) + return + } + + ctx.Logger.Debugf("Credentials validation of user %s is ok", bodyJSON.Username) + + // Reset all values from previous session before regenerating the cookie. + err = ctx.SaveSession(session.NewDefaultUserSession()) + + if err != nil { + ctx.Error(fmt.Errorf("Unable to reset the session for user %s: %s", bodyJSON.Username, err), authenticationFailedMessage) + return + } + + err = ctx.Providers.SessionProvider.RegenerateSession(ctx.RequestCtx) + + if err != nil { + ctx.Error(fmt.Errorf("Unable to regenerate session for user %s: %s", bodyJSON.Username, err), authenticationFailedMessage) + return + } + + // and avoid the cookie to expire if "Remember me" was ticked. + if *bodyJSON.KeepMeLoggedIn { + err = ctx.Providers.SessionProvider.UpdateExpiration(ctx.RequestCtx, time.Duration(0)) + if err != nil { + ctx.Error(fmt.Errorf("Unable to update expiration timer for user %s: %s", bodyJSON.Username, err), authenticationFailedMessage) + return + } + } + + // Get the details of the given user from the user provider. + userDetails, err := ctx.Providers.UserProvider.GetDetails(bodyJSON.Username) + + if err != nil { + ctx.Error(fmt.Errorf("Error while retrieving details from user %s: %s", bodyJSON.Username, err.Error()), authenticationFailedMessage) + return + } + + ctx.Logger.Debugf("Details for user %s => groups: %s, emails %s", bodyJSON.Username, userDetails.Groups, userDetails.Emails) + + // And set those information in the new session. + userSession := ctx.GetSession() + userSession.Username = bodyJSON.Username + userSession.Groups = userDetails.Groups + userSession.Emails = userDetails.Emails + userSession.AuthenticationLevel = authentication.OneFactor + userSession.LastActivity = time.Now().Unix() + err = ctx.SaveSession(userSession) + + if err != nil { + ctx.Error(fmt.Errorf("Unable to save session of user %s", bodyJSON.Username), authenticationFailedMessage) + return + } + + if bodyJSON.TargetURL != "" { + targetURL, err := url.ParseRequestURI(bodyJSON.TargetURL) + if err != nil { + ctx.Error(fmt.Errorf("Unable to parse target URL %s: %s", bodyJSON.TargetURL, err), authenticationFailedMessage) + return + } + requiredLevel := ctx.Providers.Authorizer.GetRequiredLevel(authorization.Subject{ + Username: userSession.Username, + Groups: userSession.Groups, + IP: ctx.RemoteIP(), + }, *targetURL) + + ctx.Logger.Debugf("Required level for the URL %s is %d", targetURL.String(), requiredLevel) + + safeRedirection := isRedirectionSafe(*targetURL, ctx.Configuration.Session.Domain) + + if safeRedirection && requiredLevel <= authorization.OneFactor { + response := redirectResponse{bodyJSON.TargetURL} + ctx.SetJSONBody(response) + } else { + ctx.ReplyOK() + } + } else { + ctx.ReplyOK() + } +} diff --git a/handlers/handler_firstfactor_test.go b/handlers/handler_firstfactor_test.go new file mode 100644 index 000000000..da74aa899 --- /dev/null +++ b/handlers/handler_firstfactor_test.go @@ -0,0 +1,169 @@ +package handlers + +import ( + "fmt" + "testing" + + "github.com/clems4ever/authelia/mocks" + + "github.com/clems4ever/authelia/authentication" + "github.com/golang/mock/gomock" + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +type FirstFactorSuite struct { + suite.Suite + + mock *mocks.MockAutheliaCtx +} + +func (s *FirstFactorSuite) SetupTest() { + s.mock = mocks.NewMockAutheliaCtx(s.T()) +} + +func (s *FirstFactorSuite) TearDownTest() { + s.mock.Close() +} + +func (s *FirstFactorSuite) assertError500(err string) { + assert.Equal(s.T(), 500, s.mock.Ctx.Response.StatusCode()) + assert.Equal(s.T(), []byte(InternalError), s.mock.Ctx.Response.Body()) + assert.Equal(s.T(), err, s.mock.Hook.LastEntry().Message) + assert.Equal(s.T(), logrus.ErrorLevel, s.mock.Hook.LastEntry().Level) +} + +func (s *FirstFactorSuite) TestShouldFailIfBodyIsNil() { + FirstFactorPost(s.mock.Ctx) + + // No body + assert.Equal(s.T(), "Unable to parse body: unexpected end of JSON input", s.mock.Hook.LastEntry().Message) + s.mock.Assert200KO(s.T(), "Authentication failed. Check your credentials.") +} + +func (s *FirstFactorSuite) TestShouldFailIfBodyIsInBadFormat() { + // Missing password + s.mock.Ctx.Request.SetBodyString(`{ + "username": "test" + }`) + FirstFactorPost(s.mock.Ctx) + + assert.Equal(s.T(), "Unable to validate body: password: non zero value required", s.mock.Hook.LastEntry().Message) + s.mock.Assert200KO(s.T(), "Authentication failed. Check your credentials.") +} + +func (s *FirstFactorSuite) TestShouldFailIfUserProviderCheckPasswordFail() { + s.mock.UserProviderMock. + EXPECT(). + CheckUserPassword(gomock.Eq("test"), gomock.Eq("hello")). + Return(false, fmt.Errorf("Failed")) + + s.mock.Ctx.Request.SetBodyString(`{ + "username": "test", + "password": "hello", + "keepMeLoggedIn": true + }`) + FirstFactorPost(s.mock.Ctx) + + assert.Equal(s.T(), "Error while checking password for user test: Failed", s.mock.Hook.LastEntry().Message) + s.mock.Assert200KO(s.T(), "Authentication failed. Check your credentials.") +} + +func (s *FirstFactorSuite) TestShouldFailIfUserProviderGetDetailsFail() { + s.mock.UserProviderMock. + EXPECT(). + CheckUserPassword(gomock.Eq("test"), gomock.Eq("hello")). + Return(true, nil) + + s.mock.UserProviderMock. + EXPECT(). + GetDetails(gomock.Eq("test")). + Return(nil, fmt.Errorf("Failed")) + + s.mock.StorageProviderMock. + EXPECT(). + AppendAuthenticationLog(gomock.Any()). + Return(nil) + + s.mock.Ctx.Request.SetBodyString(`{ + "username": "test", + "password": "hello", + "keepMeLoggedIn": true + }`) + FirstFactorPost(s.mock.Ctx) + + assert.Equal(s.T(), "Error while retrieving details from user test: Failed", s.mock.Hook.LastEntry().Message) + s.mock.Assert200KO(s.T(), "Authentication failed. Check your credentials.") +} + +func (s *FirstFactorSuite) TestShouldFailIfAuthenticationLoggingFail() { + s.mock.UserProviderMock. + EXPECT(). + CheckUserPassword(gomock.Eq("test"), gomock.Eq("hello")). + Return(true, nil) + + s.mock.UserProviderMock. + EXPECT(). + GetDetails(gomock.Eq("test")). + Return(nil, nil) + + s.mock.StorageProviderMock. + EXPECT(). + AppendAuthenticationLog(gomock.Any()). + Return(fmt.Errorf("failed")) + + s.mock.Ctx.Request.SetBodyString(`{ + "username": "test", + "password": "hello", + "keepMeLoggedIn": true + }`) + FirstFactorPost(s.mock.Ctx) + + assert.Equal(s.T(), "Unable to mark authentication: failed", s.mock.Hook.LastEntry().Message) + s.mock.Assert200KO(s.T(), "Authentication failed. Check your credentials.") +} + +func (s *FirstFactorSuite) TestShouldAuthenticateUser() { + s.mock.UserProviderMock. + EXPECT(). + CheckUserPassword(gomock.Eq("test"), gomock.Eq("hello")). + Return(true, nil) + + s.mock.UserProviderMock. + EXPECT(). + GetDetails(gomock.Eq("test")). + Return(&authentication.UserDetails{ + Emails: []string{"test@example.com"}, + Groups: []string{"dev", "admin"}, + }, nil) + + s.mock.StorageProviderMock. + EXPECT(). + AppendAuthenticationLog(gomock.Any()). + Return(nil) + + s.mock.Ctx.Request.SetBodyString(`{ + "username": "test", + "password": "hello", + "keepMeLoggedIn": true + }`) + FirstFactorPost(s.mock.Ctx) + + // Respond with 200. + assert.Equal(s.T(), 200, s.mock.Ctx.Response.StatusCode()) + assert.Equal(s.T(), []byte("{\"status\":\"OK\"}"), s.mock.Ctx.Response.Body()) + + // And store authentication in session. + session := s.mock.Ctx.GetSession() + assert.Equal(s.T(), "test", session.Username) + assert.Equal(s.T(), authentication.OneFactor, session.AuthenticationLevel) + assert.Equal(s.T(), []string{"test@example.com"}, session.Emails) + assert.Equal(s.T(), []string{"dev", "admin"}, session.Groups) + +} + +func TestFirstFactorSuite(t *testing.T) { + firstFactorSuite := new(FirstFactorSuite) + suite.Run(t, firstFactorSuite) +} diff --git a/handlers/handler_logout.go b/handlers/handler_logout.go new file mode 100644 index 000000000..e64cde038 --- /dev/null +++ b/handlers/handler_logout.go @@ -0,0 +1,19 @@ +package handlers + +import ( + "fmt" + + "github.com/clems4ever/authelia/middlewares" +) + +// LogoutPost is the handler logging out the user attached to the given cookie. +func LogoutPost(ctx *middlewares.AutheliaCtx) { + ctx.Logger.Debug("Destroy session") + err := ctx.Providers.SessionProvider.DestroySession(ctx.RequestCtx) + + if err != nil { + ctx.Error(fmt.Errorf("Unable to destroy session during logout: %s", err), operationFailedMessage) + } + + ctx.ReplyOK() +} diff --git a/handlers/handler_logout_test.go b/handlers/handler_logout_test.go new file mode 100644 index 000000000..d6656a0d2 --- /dev/null +++ b/handlers/handler_logout_test.go @@ -0,0 +1,43 @@ +package handlers + +import ( + "strings" + "testing" + + "github.com/clems4ever/authelia/mocks" + + "github.com/stretchr/testify/assert" + + "github.com/stretchr/testify/suite" +) + +type LogoutSuite struct { + suite.Suite + + mock *mocks.MockAutheliaCtx +} + +func (s *LogoutSuite) SetupTest() { + s.mock = mocks.NewMockAutheliaCtx(s.T()) + userSession := s.mock.Ctx.GetSession() + userSession.Username = "john" + s.mock.Ctx.SaveSession(userSession) +} + +func (s *LogoutSuite) TearDownTest() { + s.mock.Close() +} + +func (s *LogoutSuite) TestShouldDestroySession() { + LogoutPost(s.mock.Ctx) + b := s.mock.Ctx.Response.Header.PeekCookie("authelia_session") + + // Reset the cookie, meaning it resets the value and expires the cookie by setting + // date to one minute in the past. + assert.True(s.T(), strings.HasPrefix(string(b), "authelia_session=;")) +} + +func TestRunLogoutSuite(t *testing.T) { + s := new(LogoutSuite) + suite.Run(t, s) +} diff --git a/handlers/handler_register_totp.go b/handlers/handler_register_totp.go new file mode 100644 index 000000000..3ae8fdb6a --- /dev/null +++ b/handlers/handler_register_totp.go @@ -0,0 +1,70 @@ +package handlers + +import ( + "fmt" + + "github.com/clems4ever/authelia/middlewares" + "github.com/clems4ever/authelia/session" + "github.com/pquerna/otp/totp" +) + +// identityRetrieverFromSession retriever computing the identity from the cookie session. +func identityRetrieverFromSession(ctx *middlewares.AutheliaCtx) (*session.Identity, error) { + userSession := ctx.GetSession() + + if len(userSession.Emails) == 0 { + return nil, fmt.Errorf("User %s does not have any email address", userSession.Username) + } + + return &session.Identity{ + Username: userSession.Username, + Email: userSession.Emails[0], + }, nil +} + +func isTokenUserValidFor2FARegistration(ctx *middlewares.AutheliaCtx, username string) bool { + return ctx.GetSession().Username == username +} + +// SecondFactorTOTPIdentityStart the handler for initiating the identity validation. +var SecondFactorTOTPIdentityStart = middlewares.IdentityVerificationStart(middlewares.IdentityVerificationStartArgs{ + MailSubject: "[Authelia] Register your mobile", + MailTitle: "Register your mobile", + MailButtonContent: "Register", + TargetEndpoint: "/one-time-password-registration", + ActionClaim: TOTPRegistrationAction, + IdentityRetrieverFunc: identityRetrieverFromSession, +}) + +func secondFactorTOTPIdentityFinish(ctx *middlewares.AutheliaCtx, username string) { + key, err := totp.Generate(totp.GenerateOpts{ + Issuer: ctx.Configuration.TOTP.Issuer, + AccountName: username, + SecretSize: 32, + }) + + if err != nil { + ctx.Error(fmt.Errorf("Unable to generate TOTP key: %s", err), unableToRegisterOneTimePasswordMessage) + return + } + + err = ctx.Providers.StorageProvider.SaveTOTPSecret(username, key.Secret()) + if err != nil { + ctx.Error(fmt.Errorf("Unable to save TOTP secret in DB: %s", err), unableToRegisterOneTimePasswordMessage) + return + } + + response := TOTPKeyResponse{ + OTPAuthURL: key.URL(), + Base32Secret: key.Secret(), + } + + ctx.SetJSONBody(response) +} + +// SecondFactorTOTPIdentityFinish the handler for finishing the identity validation +var SecondFactorTOTPIdentityFinish = middlewares.IdentityVerificationFinish( + middlewares.IdentityVerificationFinishArgs{ + ActionClaim: TOTPRegistrationAction, + IsTokenUserValidFunc: isTokenUserValidFor2FARegistration, + }, secondFactorTOTPIdentityFinish) diff --git a/handlers/handler_register_u2f_step1.go b/handlers/handler_register_u2f_step1.go new file mode 100644 index 000000000..0dd6c2d31 --- /dev/null +++ b/handlers/handler_register_u2f_step1.go @@ -0,0 +1,63 @@ +package handlers + +import ( + "fmt" + + "github.com/clems4ever/authelia/middlewares" + "github.com/tstranex/u2f" +) + +var u2fConfig = &u2f.Config{ + // Chrome 66+ doesn't return the device's attestation + // certificate by default. + SkipAttestationVerify: true, +} + +// SecondFactorU2FIdentityStart the handler for initiating the identity validation. +var SecondFactorU2FIdentityStart = middlewares.IdentityVerificationStart(middlewares.IdentityVerificationStartArgs{ + MailSubject: "[Authelia] Register your key", + MailTitle: "Register your key", + MailButtonContent: "Register", + TargetEndpoint: "/security-key-registration", + ActionClaim: U2FRegistrationAction, + IdentityRetrieverFunc: identityRetrieverFromSession, +}) + +func secondFactorU2FIdentityFinish(ctx *middlewares.AutheliaCtx, username string) { + appID := fmt.Sprintf("%s://%s", ctx.XForwardedProto(), ctx.XForwardedHost()) + ctx.Logger.Debugf("U2F appID is %s", appID) + var trustedFacets = []string{appID} + + challenge, err := u2f.NewChallenge(appID, trustedFacets) + + if err != nil { + ctx.Error(fmt.Errorf("Unable to generate new U2F challenge for registration: %s", err), operationFailedMessage) + return + } + + // Save the challenge in the user session. + userSession := ctx.GetSession() + userSession.U2FChallenge = challenge + err = ctx.SaveSession(userSession) + + if err != nil { + ctx.Error(fmt.Errorf("Unable to save U2F challenge in session: %s", err), operationFailedMessage) + return + } + + request := u2f.NewWebRegisterRequest(challenge, []u2f.Registration{}) + + if err != nil { + ctx.Error(fmt.Errorf("Unable to generate new U2F request for registration: %s", err), operationFailedMessage) + return + } + + ctx.SetJSONBody(request) +} + +// SecondFactorU2FIdentityFinish the handler for finishing the identity validation +var SecondFactorU2FIdentityFinish = middlewares.IdentityVerificationFinish( + middlewares.IdentityVerificationFinishArgs{ + ActionClaim: U2FRegistrationAction, + IsTokenUserValidFunc: isTokenUserValidFor2FARegistration, + }, secondFactorU2FIdentityFinish) diff --git a/handlers/handler_register_u2f_step2.go b/handlers/handler_register_u2f_step2.go new file mode 100644 index 000000000..83857ac0b --- /dev/null +++ b/handlers/handler_register_u2f_step2.go @@ -0,0 +1,50 @@ +package handlers + +import ( + "fmt" + + "github.com/clems4ever/authelia/middlewares" + "github.com/tstranex/u2f" +) + +// SecondFactorU2FRegister handler validating the client has successfully validated the challenge +// to complete the U2F registration. +func SecondFactorU2FRegister(ctx *middlewares.AutheliaCtx) { + responseBody := u2f.RegisterResponse{} + err := ctx.ParseBody(&responseBody) + + userSession := ctx.GetSession() + + if userSession.U2FChallenge == nil { + ctx.Error(fmt.Errorf("U2F registration has not been initiated yet"), unableToRegisterSecurityKeyMessage) + return + } + // Ensure the challenge is cleared if anything goes wrong. + defer func() { + userSession.U2FChallenge = nil + ctx.SaveSession(userSession) + }() + + registration, err := u2f.Register(responseBody, *userSession.U2FChallenge, u2fConfig) + + if err != nil { + ctx.Error(fmt.Errorf("Unable to verify U2F registration: %v", err), unableToRegisterSecurityKeyMessage) + return + } + + deviceHandle, err := registration.MarshalBinary() + if err != nil { + ctx.Error(fmt.Errorf("Unable to marshal U2F registration data: %v", err), unableToRegisterSecurityKeyMessage) + return + } + + ctx.Logger.Debugf("Register U2F device for user %s", userSession.Username) + err = ctx.Providers.StorageProvider.SaveU2FDeviceHandle(userSession.Username, deviceHandle) + + if err != nil { + ctx.Error(fmt.Errorf("Unable to register U2F device for user %s: %v", userSession.Username, err), unableToRegisterSecurityKeyMessage) + return + } + + ctx.ReplyOK() +} diff --git a/handlers/handler_reset_password_step1.go b/handlers/handler_reset_password_step1.go new file mode 100644 index 000000000..a5c63213d --- /dev/null +++ b/handlers/handler_reset_password_step1.go @@ -0,0 +1,57 @@ +package handlers + +import ( + "encoding/json" + "fmt" + + "github.com/clems4ever/authelia/middlewares" + "github.com/clems4ever/authelia/session" +) + +func identityRetrieverFromStorage(ctx *middlewares.AutheliaCtx) (*session.Identity, error) { + var requestBody resetPasswordStep1RequestBody + err := json.Unmarshal(ctx.PostBody(), &requestBody) + + if err != nil { + return nil, err + } + + details, err := ctx.Providers.UserProvider.GetDetails(requestBody.Username) + + if err != nil { + return nil, err + } + + if len(details.Emails) == 0 { + return nil, fmt.Errorf("User %s has no email address configured", requestBody.Username) + } + + return &session.Identity{ + Username: requestBody.Username, + Email: details.Emails[0], + }, nil +} + +// ResetPasswordIdentityStart the handler for initiating the identity validation for resetting a password. +// We need to ensure the attacker cannot perform user enumeration by alway replying with 200 whatever what happens in backend. +var ResetPasswordIdentityStart = middlewares.IdentityVerificationStart(middlewares.IdentityVerificationStartArgs{ + MailSubject: "[Authelia] Reset your password", + MailTitle: "Reset your password", + MailButtonContent: "Reset", + TargetEndpoint: "/reset-password", + ActionClaim: ResetPasswordAction, + IdentityRetrieverFunc: identityRetrieverFromStorage, +}) + +func resetPasswordIdentityFinish(ctx *middlewares.AutheliaCtx, username string) { + userSession := ctx.GetSession() + // TODO(c.michaud): use JWT tokens to expire the request in only few seconds for better security. + userSession.PasswordResetUsername = &username + ctx.SaveSession(userSession) + + ctx.ReplyOK() +} + +// ResetPasswordIdentityFinish the handler for finishing the identity validation +var ResetPasswordIdentityFinish = middlewares.IdentityVerificationFinish( + middlewares.IdentityVerificationFinishArgs{ActionClaim: ResetPasswordAction}, resetPasswordIdentityFinish) diff --git a/handlers/handler_reset_password_step2.go b/handlers/handler_reset_password_step2.go new file mode 100644 index 000000000..02b638a40 --- /dev/null +++ b/handlers/handler_reset_password_step2.go @@ -0,0 +1,48 @@ +package handlers + +import ( + "fmt" + + "github.com/clems4ever/authelia/middlewares" +) + +// ResetPasswordPost handler for resetting passwords +func ResetPasswordPost(ctx *middlewares.AutheliaCtx) { + userSession := ctx.GetSession() + + // Those checks unsure that the identity verification process has been initiated and completed successfully + // otherwise PasswordReset would not be set to true. We can improve the security of this check by making the + // request expire at some point because here it only expires when the cookie expires... + if userSession.PasswordResetUsername == nil { + ctx.Error(fmt.Errorf("No identity verification process has been initiated"), unableToResetPasswordMessage) + return + } + + var requestBody resetPasswordStep2RequestBody + err := ctx.ParseBody(&requestBody) + + if err != nil { + ctx.Error(err, unableToResetPasswordMessage) + return + } + + err = ctx.Providers.UserProvider.UpdatePassword(*userSession.PasswordResetUsername, requestBody.Password) + + if err != nil { + ctx.Error(fmt.Errorf("Unable to update password: %s", err), unableToResetPasswordMessage) + return + } + + ctx.Logger.Debugf("Password of user %s has been reset", *userSession.PasswordResetUsername) + + // Reset the request. + userSession.PasswordResetUsername = nil + err = ctx.SaveSession(userSession) + + if err != nil { + ctx.Error(fmt.Errorf("Unable to update password reset state: %s", err), operationFailedMessage) + return + } + + ctx.ReplyOK() +} diff --git a/handlers/handler_sign_duo.go b/handlers/handler_sign_duo.go new file mode 100644 index 000000000..b3d51c7ff --- /dev/null +++ b/handlers/handler_sign_duo.go @@ -0,0 +1,71 @@ +package handlers + +import ( + "fmt" + "net/url" + + "github.com/clems4ever/authelia/authentication" + "github.com/clems4ever/authelia/duo" + "github.com/clems4ever/authelia/middlewares" +) + +// SecondFactorDuoPost handler for sending a push notification via duo api. +func SecondFactorDuoPost(duoAPI duo.API) middlewares.RequestHandler { + return func(ctx *middlewares.AutheliaCtx) { + var requestBody signDuoRequestBody + err := ctx.ParseBody(&requestBody) + + if err != nil { + ctx.Error(err, mfaValidationFailedMessage) + return + } + + userSession := ctx.GetSession() + + values := url.Values{} + // { username, ipaddr: clientIP, factor: "push", device: "auto", pushinfo: `target%20url=${targetURL}`} + values.Set("username", userSession.Username) + values.Set("ipaddr", ctx.RemoteIP().String()) + values.Set("factor", "push") + values.Set("device", "auto") + if requestBody.TargetURL != "" { + values.Set("pushinfo", fmt.Sprintf("target%%20url=%s", requestBody.TargetURL)) + } + + duoResponse, err := duoAPI.Call(values) + if err != nil { + ctx.Error(fmt.Errorf("Duo API errored: %s", err), mfaValidationFailedMessage) + return + } + + if duoResponse.Response.Result != "allow" { + ctx.ReplyUnauthorized() + return + } + + userSession.AuthenticationLevel = authentication.TwoFactor + err = ctx.SaveSession(userSession) + + if err != nil { + ctx.Error(fmt.Errorf("Unable to update authentication level with Duo: %s", err), mfaValidationFailedMessage) + return + } + + if requestBody.TargetURL != "" { + targetURL, err := url.ParseRequestURI(requestBody.TargetURL) + + if err != nil { + ctx.Error(fmt.Errorf("Unable to parse target URL: %s", err), mfaValidationFailedMessage) + return + } + + if targetURL != nil && isRedirectionSafe(*targetURL, ctx.Configuration.Session.Domain) { + ctx.SetJSONBody(redirectResponse{Redirect: requestBody.TargetURL}) + } else { + ctx.ReplyOK() + } + } else { + ctx.ReplyOK() + } + } +} diff --git a/handlers/handler_sign_duo_test.go b/handlers/handler_sign_duo_test.go new file mode 100644 index 000000000..3781684a4 --- /dev/null +++ b/handlers/handler_sign_duo_test.go @@ -0,0 +1,98 @@ +package handlers + +import ( + "fmt" + "net/url" + "testing" + + "github.com/clems4ever/authelia/duo" + "github.com/clems4ever/authelia/mocks" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +type SecondFactorDuoPostSuite struct { + suite.Suite + + mock *mocks.MockAutheliaCtx +} + +func (s *SecondFactorDuoPostSuite) SetupTest() { + s.mock = mocks.NewMockAutheliaCtx(s.T()) + userSession := s.mock.Ctx.GetSession() + userSession.Username = "john" + s.mock.Ctx.SaveSession(userSession) +} + +func (s *SecondFactorDuoPostSuite) TearDownTest() { + s.mock.Close() +} + +func (s *SecondFactorDuoPostSuite) TestShouldCallDuoAPIAndAllowAccess() { + duoMock := mocks.NewMockAPI(s.mock.Ctrl) + + values := url.Values{} + values.Set("username", "john") + values.Set("ipaddr", s.mock.Ctx.RemoteIP().String()) + values.Set("factor", "push") + values.Set("device", "auto") + values.Set("pushinfo", "target%20url=https://target.example.com") + + response := duo.Response{} + response.Response.Result = "allow" + + duoMock.EXPECT().Call(gomock.Eq(values)).Return(&response, nil) + + s.mock.Ctx.Request.SetBodyString("{\"targetURL\": \"https://target.example.com\"}") + + SecondFactorDuoPost(duoMock)(s.mock.Ctx) + + assert.Equal(s.T(), s.mock.Ctx.Response.StatusCode(), 200) +} + +func (s *SecondFactorDuoPostSuite) TestShouldCallDuoAPIAndDenyAccess() { + duoMock := mocks.NewMockAPI(s.mock.Ctrl) + + values := url.Values{} + values.Set("username", "john") + values.Set("ipaddr", s.mock.Ctx.RemoteIP().String()) + values.Set("factor", "push") + values.Set("device", "auto") + values.Set("pushinfo", "target%20url=https://target.example.com") + + response := duo.Response{} + response.Response.Result = "deny" + + duoMock.EXPECT().Call(gomock.Eq(values)).Return(&response, nil) + + s.mock.Ctx.Request.SetBodyString("{\"targetURL\": \"https://target.example.com\"}") + + SecondFactorDuoPost(duoMock)(s.mock.Ctx) + + assert.Equal(s.T(), s.mock.Ctx.Response.StatusCode(), 401) +} + +func (s *SecondFactorDuoPostSuite) TestShouldCallDuoAPIAndFail() { + duoMock := mocks.NewMockAPI(s.mock.Ctrl) + + values := url.Values{} + values.Set("username", "john") + values.Set("ipaddr", s.mock.Ctx.RemoteIP().String()) + values.Set("factor", "push") + values.Set("device", "auto") + values.Set("pushinfo", "target%20url=https://target.example.com") + + duoMock.EXPECT().Call(gomock.Eq(values)).Return(nil, fmt.Errorf("Connnection error")) + + s.mock.Ctx.Request.SetBodyString("{\"targetURL\": \"https://target.example.com\"}") + + SecondFactorDuoPost(duoMock)(s.mock.Ctx) + + s.mock.Assert200KO(s.T(), "Authentication failed, please retry later.") +} + +func TestRunSecondeFactorDuoPostSuite(t *testing.T) { + s := new(SecondFactorDuoPostSuite) + suite.Run(t, s) +} diff --git a/handlers/handler_sign_totp.go b/handlers/handler_sign_totp.go new file mode 100644 index 000000000..905ed6954 --- /dev/null +++ b/handlers/handler_sign_totp.go @@ -0,0 +1,59 @@ +package handlers + +import ( + "fmt" + "net/url" + + "github.com/clems4ever/authelia/authentication" + "github.com/clems4ever/authelia/middlewares" + "github.com/pquerna/otp/totp" +) + +// SecondFactorTOTPPost validate the TOTP passcode provided by the user. +func SecondFactorTOTPPost(ctx *middlewares.AutheliaCtx) { + bodyJSON := signTOTPRequestBody{} + err := ctx.ParseBody(&bodyJSON) + + if err != nil { + ctx.Error(err, mfaValidationFailedMessage) + return + } + + userSession := ctx.GetSession() + secret, err := ctx.Providers.StorageProvider.LoadTOTPSecret(userSession.Username) + if err != nil { + ctx.Error(fmt.Errorf("Unable to load TOTP secret: %s", err), mfaValidationFailedMessage) + return + } + + isValid := totp.Validate(bodyJSON.Token, secret) + + if !isValid { + ctx.Error(fmt.Errorf("Wrong passcode during TOTP validation for user %s", userSession.Username), mfaValidationFailedMessage) + return + } + + userSession.AuthenticationLevel = authentication.TwoFactor + err = ctx.SaveSession(userSession) + + if err != nil { + ctx.Error(fmt.Errorf("Unable to update the authentication level with TOTP: %s", err), mfaValidationFailedMessage) + return + } + + if bodyJSON.TargetURL != "" { + targetURL, err := url.ParseRequestURI(bodyJSON.TargetURL) + if err != nil { + ctx.Error(fmt.Errorf("Unable to parse URL with TOTP: %s", err), mfaValidationFailedMessage) + return + } + + if targetURL != nil && isRedirectionSafe(*targetURL, ctx.Configuration.Session.Domain) { + ctx.SetJSONBody(redirectResponse{bodyJSON.TargetURL}) + } else { + ctx.ReplyOK() + } + } else { + ctx.ReplyOK() + } +} diff --git a/handlers/handler_sign_u2f_step1.go b/handlers/handler_sign_u2f_step1.go new file mode 100644 index 000000000..b8198d8b2 --- /dev/null +++ b/handlers/handler_sign_u2f_step1.go @@ -0,0 +1,64 @@ +package handlers + +import ( + "fmt" + + "github.com/clems4ever/authelia/middlewares" + "github.com/clems4ever/authelia/storage" + "github.com/tstranex/u2f" +) + +// SecondFactorU2FSignGet handler for initiating a signing request. +func SecondFactorU2FSignGet(ctx *middlewares.AutheliaCtx) { + userSession := ctx.GetSession() + + appID := fmt.Sprintf("%s://%s", ctx.XForwardedProto(), ctx.XForwardedHost()) + var trustedFacets = []string{appID} + challenge, err := u2f.NewChallenge(appID, trustedFacets) + + if err != nil { + ctx.Error(fmt.Errorf("Unable to create U2F challenge: %s", err), mfaValidationFailedMessage) + return + } + + registrationBin, err := ctx.Providers.StorageProvider.LoadU2FDeviceHandle(userSession.Username) + + if err != nil { + if err == storage.ErrNoU2FDeviceHandle { + ctx.Error(fmt.Errorf("No device handle found for user %s", userSession.Username), mfaValidationFailedMessage) + return + } + ctx.Error(fmt.Errorf("Unable to retrieve U2F device handle: %s", err), mfaValidationFailedMessage) + return + } + + if len(registrationBin) == 0 { + ctx.Error(fmt.Errorf("Wrong format of device handler for user %s", userSession.Username), mfaValidationFailedMessage) + return + } + + var registration u2f.Registration + err = registration.UnmarshalBinary(registrationBin) + if err != nil { + ctx.Error(fmt.Errorf("Unable to unmarshal U2F device handle: %s", err), mfaValidationFailedMessage) + return + } + + // Save the challenge and registration for use in next request + userSession.U2FRegistration = ®istration + userSession.U2FChallenge = challenge + err = ctx.SaveSession(userSession) + + if err != nil { + ctx.Error(fmt.Errorf("Unable to save U2F challenge and registration in session: %s", err), mfaValidationFailedMessage) + return + } + + signRequest := challenge.SignRequest([]u2f.Registration{registration}) + err = ctx.SetJSONBody(signRequest) + + if err != nil { + ctx.Error(fmt.Errorf("Unable to set sign request in body: %s", err), mfaValidationFailedMessage) + return + } +} diff --git a/handlers/handler_sign_u2f_step2.go b/handlers/handler_sign_u2f_step2.go new file mode 100644 index 000000000..4f54a4b3b --- /dev/null +++ b/handlers/handler_sign_u2f_step2.go @@ -0,0 +1,65 @@ +package handlers + +import ( + "fmt" + "net/url" + + "github.com/clems4ever/authelia/authentication" + "github.com/clems4ever/authelia/middlewares" +) + +// SecondFactorU2FSignPost handler for completing a signing request. +func SecondFactorU2FSignPost(ctx *middlewares.AutheliaCtx) { + var requestBody signU2FRequestBody + err := ctx.ParseBody(&requestBody) + + if err != nil { + ctx.Error(err, mfaValidationFailedMessage) + return + } + + userSession := ctx.GetSession() + if userSession.U2FChallenge == nil { + ctx.Error(fmt.Errorf("U2F signing has not been initiated yet (no challenge)"), mfaValidationFailedMessage) + return + } + + if userSession.U2FRegistration == nil { + ctx.Error(fmt.Errorf("U2F signing has not been initiated yet (no registration)"), mfaValidationFailedMessage) + return + } + + // TODO(c.michaud): store the counter to help detecting cloned U2F keys. + _, err = userSession.U2FRegistration.Authenticate( + requestBody.SignResponse, *userSession.U2FChallenge, 0) + + if err != nil { + ctx.Error(err, mfaValidationFailedMessage) + return + } + + userSession.AuthenticationLevel = authentication.TwoFactor + err = ctx.SaveSession(userSession) + + if err != nil { + ctx.Error(fmt.Errorf("Unable to update authentication level with U2F: %s", err), mfaValidationFailedMessage) + return + } + + if requestBody.TargetURL != "" { + targetURL, err := url.ParseRequestURI(requestBody.TargetURL) + + if err != nil { + ctx.Error(fmt.Errorf("Unable to parse target URL with U2F: %s", err), mfaValidationFailedMessage) + return + } + + if targetURL != nil && isRedirectionSafe(*targetURL, ctx.Configuration.Session.Domain) { + ctx.SetJSONBody(redirectResponse{Redirect: requestBody.TargetURL}) + } else { + ctx.ReplyOK() + } + } else { + ctx.ReplyOK() + } +} diff --git a/handlers/handler_state.go b/handlers/handler_state.go new file mode 100644 index 000000000..75eee8848 --- /dev/null +++ b/handlers/handler_state.go @@ -0,0 +1,16 @@ +package handlers + +import ( + "github.com/clems4ever/authelia/middlewares" +) + +// StateGet is the handler serving the user state. +func StateGet(ctx *middlewares.AutheliaCtx) { + userSession := ctx.GetSession() + stateResponse := StateResponse{ + Username: userSession.Username, + AuthenticationLevel: userSession.AuthenticationLevel, + DefaultRedirectionURL: ctx.Configuration.DefaultRedirectionURL, + } + ctx.SetJSONBody(stateResponse) +} diff --git a/handlers/handler_state_test.go b/handlers/handler_state_test.go new file mode 100644 index 000000000..b47c49010 --- /dev/null +++ b/handlers/handler_state_test.go @@ -0,0 +1,87 @@ +package handlers + +import ( + "encoding/json" + "testing" + + "github.com/clems4ever/authelia/mocks" + + "github.com/clems4ever/authelia/authentication" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +type StateGetSuite struct { + suite.Suite + + mock *mocks.MockAutheliaCtx +} + +func (s *StateGetSuite) SetupTest() { + s.mock = mocks.NewMockAutheliaCtx(s.T()) +} + +func (s *StateGetSuite) TearDownTest() { + s.mock.Close() +} + +func (s *StateGetSuite) TestShouldReturnUsernameFromSession() { + userSession := s.mock.Ctx.GetSession() + userSession.Username = "username" + s.mock.Ctx.SaveSession(userSession) + + StateGet(s.mock.Ctx) + + type Response struct { + Status string + Data StateResponse + } + + expectedBody := Response{ + Status: "OK", + Data: StateResponse{ + Username: "username", + DefaultRedirectionURL: "", + AuthenticationLevel: authentication.NotAuthenticated, + }, + } + actualBody := Response{} + + json.Unmarshal(s.mock.Ctx.Response.Body(), &actualBody) + assert.Equal(s.T(), 200, s.mock.Ctx.Response.StatusCode()) + assert.Equal(s.T(), []byte("application/json"), s.mock.Ctx.Response.Header.ContentType()) + assert.Equal(s.T(), expectedBody, actualBody) +} + +func (s *StateGetSuite) TestShouldReturnAuthenticationLevelFromSession() { + userSession := s.mock.Ctx.GetSession() + userSession.AuthenticationLevel = authentication.OneFactor + s.mock.Ctx.SaveSession(userSession) + + StateGet(s.mock.Ctx) + + type Response struct { + Status string + Data StateResponse + } + + expectedBody := Response{ + Status: "OK", + Data: StateResponse{ + Username: "", + DefaultRedirectionURL: "", + AuthenticationLevel: authentication.OneFactor, + }, + } + actualBody := Response{} + + json.Unmarshal(s.mock.Ctx.Response.Body(), &actualBody) + assert.Equal(s.T(), 200, s.mock.Ctx.Response.StatusCode()) + assert.Equal(s.T(), []byte("application/json"), s.mock.Ctx.Response.Header.ContentType()) + assert.Equal(s.T(), expectedBody, actualBody) +} + +func TestRunStateGetSuite(t *testing.T) { + s := new(StateGetSuite) + suite.Run(t, s) +} diff --git a/handlers/handler_verify.go b/handlers/handler_verify.go new file mode 100644 index 000000000..d62ed65a0 --- /dev/null +++ b/handlers/handler_verify.go @@ -0,0 +1,265 @@ +package handlers + +import ( + "encoding/base64" + "fmt" + "net" + "net/url" + "strings" + "time" + + "github.com/clems4ever/authelia/authentication" + "github.com/clems4ever/authelia/authorization" + "github.com/clems4ever/authelia/middlewares" + "github.com/valyala/fasthttp" +) + +// getOriginalURL extract the URL from the request headers (X-Original-URI or X-Forwarded-* headers). +func getOriginalURL(ctx *middlewares.AutheliaCtx) (*url.URL, error) { + originalURL := ctx.XOriginalURL() + if originalURL != nil { + url, err := url.ParseRequestURI(string(originalURL)) + if err != nil { + return nil, err + } + return url, nil + } + + forwardedProto := ctx.XForwardedProto() + forwardedHost := ctx.XForwardedHost() + forwardedURI := ctx.XForwardedURI() + + if forwardedProto == nil || forwardedHost == nil { + return nil, errMissingHeadersForTargetURL + } + + var requestURI string + scheme := append(forwardedProto, protoHostSeparator...) + if forwardedURI == nil { + requestURI = string(append(scheme, forwardedHost...)) + } + + requestURI = string(append(scheme, + append(forwardedHost, forwardedURI...)...)) + + url, err := url.ParseRequestURI(string(requestURI)) + if err != nil { + return nil, err + } + return url, nil +} + +// parseBasicAuth parses an HTTP Basic Authentication string. +// "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" returns ("Aladdin", "open sesame", true). +func parseBasicAuth(auth string) (username, password string, err error) { + if !strings.HasPrefix(auth, authPrefix) { + return "", "", fmt.Errorf("%s prefix not found in authorization header", strings.Trim(authPrefix, " ")) + } + c, err := base64.StdEncoding.DecodeString(auth[len(authPrefix):]) + if err != nil { + return "", "", err + } + cs := string(c) + s := strings.IndexByte(cs, ':') + if s < 0 { + return "", "", fmt.Errorf("Format for basic auth must be user:password") + } + return cs[:s], cs[s+1:], nil +} + +// isTargetURLAuthorized check whether the given user is authorized to access the resource. +func isTargetURLAuthorized(authorizer *authorization.Authorizer, targetURL url.URL, + username string, userGroups []string, clientIP net.IP, authLevel authentication.Level) authorizationMatching { + + level := authorizer.GetRequiredLevel(authorization.Subject{ + Username: username, + Groups: userGroups, + IP: clientIP, + }, targetURL) + + if level == authorization.Bypass { + return Authorized + } else if username != "" && level == authorization.Denied { + // If the user is not anonymous, it means that we went through + // all the rules related to that user and knowing who he is we can + // deduce the access is forbidden. + // For anonymous users though, we cannot be sure that she + // could not be granted the rights to access the resource. Consequently + // for anonymous users we send Unauthorized instead of Forbidden. + return Forbidden + } else { + if level == authorization.OneFactor && + authLevel >= authentication.OneFactor { + return Authorized + } else if level == authorization.TwoFactor && + authLevel >= authentication.TwoFactor { + return Authorized + } + } + return NotAuthorized +} + +// verifyBasicAuth verify that the provided username and password are correct and +// that the user is authorized to target the resource. +func verifyBasicAuth(auth []byte, targetURL url.URL, ctx *middlewares.AutheliaCtx) (username string, groups []string, authLevel authentication.Level, err error) { + username, password, err := parseBasicAuth(string(auth)) + + if err != nil { + return "", nil, authentication.NotAuthenticated, fmt.Errorf("Unable to parse basic auth: %s", err) + } + + authenticated, err := ctx.Providers.UserProvider.CheckUserPassword(username, password) + + if err != nil { + return "", nil, authentication.NotAuthenticated, fmt.Errorf("Unable to check password in basic auth mode: %s", err) + } + + // If the user is not correctly authenticated, send a 401. + if !authenticated { + // Request Basic Authentication otherwise + return "", nil, authentication.NotAuthenticated, fmt.Errorf("User %s is not authenticated", username) + } + + details, err := ctx.Providers.UserProvider.GetDetails(username) + + if err != nil { + return "", nil, authentication.NotAuthenticated, fmt.Errorf("Unable to retrieve user details in basic auth mode: %s", err) + } + + return username, details.Groups, authentication.OneFactor, nil +} + +// setForwardedHeaders set the forwarded User and Groups headers. +func setForwardedHeaders(headers *fasthttp.ResponseHeader, username string, groups []string) { + if username != "" { + headers.Set(remoteUserHeader, username) + headers.Set(remoteGroupsHeader, strings.Join(groups, ",")) + } +} + +// hasUserBeenInactiveLongEnough check whether the user has been inactive for too long. +func hasUserBeenInactiveLongEnough(ctx *middlewares.AutheliaCtx) (bool, error) { + expiration, err := ctx.Providers.SessionProvider.GetExpiration(ctx.RequestCtx) + + if err != nil { + return false, err + } + + // If the cookie has no expiration. + if expiration == 0 { + return false, nil + } + + maxInactivityPeriod := ctx.Configuration.Session.Inactivity + if maxInactivityPeriod == 0 { + return false, nil + } + + lastActivity := ctx.GetSession().LastActivity + inactivityPeriod := time.Now().Unix() - lastActivity + + ctx.Logger.Debugf("Inactivity report: Inactivity=%d, MaxInactivity=%d", + inactivityPeriod, maxInactivityPeriod) + + if inactivityPeriod > maxInactivityPeriod { + return true, nil + } + + return false, nil +} + +// verifyFromSessionCookie verify if a user identified by a cookie is allowed to access target URL. +func verifyFromSessionCookie(targetURL url.URL, ctx *middlewares.AutheliaCtx) (username string, groups []string, authLevel authentication.Level, err error) { + userSession := ctx.GetSession() + // No username in the session means the user is anonymous. + isUserAnonymous := userSession.Username == "" + + if isUserAnonymous && userSession.AuthenticationLevel != authentication.NotAuthenticated { + return "", nil, authentication.NotAuthenticated, fmt.Errorf("An anonymous user cannot be authenticated. That might be the sign of a compromise") + } + + if !isUserAnonymous { + inactiveLongEnough, err := hasUserBeenInactiveLongEnough(ctx) + if err != nil { + return "", nil, authentication.NotAuthenticated, fmt.Errorf("Unable to check if user has been inactive for a long time: %s", err) + } + + if inactiveLongEnough { + // Destroy the session a new one will be regenerated on next request. + err := ctx.Providers.SessionProvider.DestroySession(ctx.RequestCtx) + if err != nil { + return "", nil, authentication.NotAuthenticated, fmt.Errorf("Unable to destroy user session after long inactivity: %s", err) + } + + return "", nil, authentication.NotAuthenticated, fmt.Errorf("User %s has been inactive for too long", userSession.Username) + } + } + return userSession.Username, userSession.Groups, userSession.AuthenticationLevel, nil +} + +// VerifyGet is the handler verifying if a request is allowed to go through. +func VerifyGet(ctx *middlewares.AutheliaCtx) { + ctx.Logger.Tracef("Headers=%s", ctx.Request.Header.String()) + targetURL, err := getOriginalURL(ctx) + + if err != nil { + ctx.Error(fmt.Errorf("Unable to parse target URL: %s", err), operationFailedMessage) + return + } + + var username string + var groups []string + var authLevel authentication.Level + + proxyAuthorization := ctx.Request.Header.Peek(authorizationHeader) + hasBasicAuth := proxyAuthorization != nil + + if hasBasicAuth { + username, groups, authLevel, err = verifyBasicAuth(proxyAuthorization, *targetURL, ctx) + } else { + username, groups, authLevel, err = verifyFromSessionCookie(*targetURL, ctx) + } + + if err != nil { + ctx.Logger.Error(fmt.Sprintf("Error caught when verifying user authorization: %s", err)) + ctx.ReplyUnauthorized() + return + } + + authorization := isTargetURLAuthorized(ctx.Providers.Authorizer, *targetURL, username, + groups, ctx.RemoteIP(), authLevel) + + if authorization == Forbidden { + ctx.ReplyForbidden() + ctx.Logger.Errorf("Access to %s is forbidden to user %s", targetURL.String(), username) + return + } else if authorization == NotAuthorized { + // Kubernetes ingress controller and Traefik use the rd parameter of the verify + // endpoint to provide the URL of the login portal. The target URL of the user + // is computed from X-Fowarded-* headers or X-Original-URL. + rd := string(ctx.QueryArgs().Peek("rd")) + if rd != "" { + redirectionURL := fmt.Sprintf("%s?rd=%s", rd, targetURL.String()) + ctx.Redirect(redirectionURL, 302) + ctx.SetBodyString(fmt.Sprintf("Found. Redirecting to %s", redirectionURL)) + } else { + ctx.ReplyUnauthorized() + ctx.Logger.Errorf("Access to %s is not authorized to user %s", targetURL.String(), username) + } + } else if authorization == Authorized { + setForwardedHeaders(&ctx.Response.Header, username, groups) + } + + // We mark activity of the current user if he comes with a session cookie. + if !hasBasicAuth && username != "" { + // Mark current activity + userSession := ctx.GetSession() + userSession.LastActivity = time.Now().Unix() + err = ctx.SaveSession(userSession) + + if err != nil { + ctx.Error(fmt.Errorf("Unable to update last activity: %s", err), operationFailedMessage) + return + } + } +} diff --git a/handlers/handler_verify_test.go b/handlers/handler_verify_test.go new file mode 100644 index 000000000..65bffa3ae --- /dev/null +++ b/handlers/handler_verify_test.go @@ -0,0 +1,338 @@ +package handlers + +import ( + "fmt" + "net" + "net/url" + "testing" + + "github.com/clems4ever/authelia/authentication" + "github.com/clems4ever/authelia/authorization" + "github.com/clems4ever/authelia/configuration/schema" + "github.com/clems4ever/authelia/mocks" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" +) + +// Test getOriginalURL +func TestShouldGetOriginalURLFromOriginalURLHeader(t *testing.T) { + mock := mocks.NewMockAutheliaCtx(t) + defer mock.Close() + + mock.Ctx.Request.Header.Set("X-Original-URL", "https://home.example.com") + originalURL, err := getOriginalURL(mock.Ctx) + assert.NoError(t, err) + + expectedURL, err := url.ParseRequestURI("https://home.example.com") + assert.NoError(t, err) + assert.Equal(t, expectedURL, originalURL) +} + +func TestShouldGetOriginalURLFromForwardedHeadersWithoutURI(t *testing.T) { + mock := mocks.NewMockAutheliaCtx(t) + defer mock.Close() + mock.Ctx.Request.Header.Set("X-Forwarded-Proto", "https") + mock.Ctx.Request.Header.Set("X-Forwarded-Host", "home.example.com") + originalURL, err := getOriginalURL(mock.Ctx) + assert.NoError(t, err) + + expectedURL, err := url.ParseRequestURI("https://home.example.com") + assert.NoError(t, err) + assert.Equal(t, expectedURL, originalURL) +} + +func TestShouldGetOriginalURLFromForwardedHeadersWithURI(t *testing.T) { + mock := mocks.NewMockAutheliaCtx(t) + defer mock.Close() + mock.Ctx.Request.Header.Set("X-Original-URL", "htt-ps//home?-.example.com") + _, err := getOriginalURL(mock.Ctx) + assert.Error(t, err) + assert.Equal(t, "parse htt-ps//home?-.example.com: invalid URI for request", err.Error()) +} + +func TestShouldRaiseWhenTargetUrlIsMalformed(t *testing.T) { + mock := mocks.NewMockAutheliaCtx(t) + defer mock.Close() + mock.Ctx.Request.Header.Set("X-Forwarded-Proto", "https") + mock.Ctx.Request.Header.Set("X-Forwarded-Host", "home.example.com") + mock.Ctx.Request.Header.Set("X-Forwarded-URI", "/abc") + originalURL, err := getOriginalURL(mock.Ctx) + assert.NoError(t, err) + + expectedURL, err := url.ParseRequestURI("https://home.example.com/abc") + assert.NoError(t, err) + assert.Equal(t, expectedURL, originalURL) +} + +func TestShouldRaiseWhenNoHeaderProvidedToDetectTargetURL(t *testing.T) { + mock := mocks.NewMockAutheliaCtx(t) + defer mock.Close() + _, err := getOriginalURL(mock.Ctx) + assert.Error(t, err) + assert.Equal(t, "Missing headers for detecting target URL", err.Error()) +} + +// Test parseBasicAuth +func TestShouldRaiseWhenHeaderDoesNotContainBasicPrefix(t *testing.T) { + _, _, err := parseBasicAuth("alzefzlfzemjfej==") + assert.Error(t, err) + assert.Equal(t, "Basic prefix not found in authorization header", err.Error()) +} + +func TestShouldRaiseWhenCredentialsAreNotInBase64(t *testing.T) { + _, _, err := parseBasicAuth("Basic alzefzlfzemjfej==") + assert.Error(t, err) + assert.Equal(t, "illegal base64 data at input byte 16", err.Error()) +} + +func TestShouldRaiseWhenCredentialsAreNotInCorrectForm(t *testing.T) { + // the decoded format should be user:password. + _, _, err := parseBasicAuth("Basic am9obiBwYXNzd29yZA==") + assert.Error(t, err) + assert.Equal(t, "Format for basic auth must be user:password", err.Error()) +} + +func TestShouldReturnUsernameAndPassword(t *testing.T) { + // the decoded format should be user:password. + user, password, err := parseBasicAuth("Basic am9objpwYXNzd29yZA==") + assert.NoError(t, err) + assert.Equal(t, "john", user) + assert.Equal(t, "password", password) +} + +// Test isTargetURLAuthorized +func TestShouldCheckAuthorizationMatching(t *testing.T) { + type Rule struct { + Policy string + AuthLevel authentication.Level + ExpectedMatching authorizationMatching + } + rules := []Rule{ + Rule{"bypass", authentication.NotAuthenticated, Authorized}, + Rule{"bypass", authentication.OneFactor, Authorized}, + Rule{"bypass", authentication.TwoFactor, Authorized}, + + Rule{"one_factor", authentication.NotAuthenticated, NotAuthorized}, + Rule{"one_factor", authentication.OneFactor, Authorized}, + Rule{"one_factor", authentication.TwoFactor, Authorized}, + + Rule{"two_factor", authentication.NotAuthenticated, NotAuthorized}, + Rule{"two_factor", authentication.OneFactor, NotAuthorized}, + Rule{"two_factor", authentication.TwoFactor, Authorized}, + + Rule{"deny", authentication.NotAuthenticated, NotAuthorized}, + Rule{"deny", authentication.OneFactor, Forbidden}, + Rule{"deny", authentication.TwoFactor, Forbidden}, + } + + url, _ := url.ParseRequestURI("https://test.example.com") + + for _, rule := range rules { + authorizer := authorization.NewAuthorizer(schema.AccessControlConfiguration{ + DefaultPolicy: "deny", + Rules: []schema.ACLRule{schema.ACLRule{ + Domain: "test.example.com", + Policy: rule.Policy, + }}, + }) + + username := "" + if rule.AuthLevel > authentication.NotAuthenticated { + username = "john" + } + + matching := isTargetURLAuthorized(authorizer, *url, username, []string{}, net.ParseIP("127.0.0.1"), rule.AuthLevel) + assert.Equal(t, rule.ExpectedMatching, matching, "policy=%s, authLevel=%v, expected=%v, actual=%v", + rule.Policy, rule.AuthLevel, rule.ExpectedMatching, matching) + } +} + +// Test verifyBasicAuth +func TestShouldVerifyWrongCredentials(t *testing.T) { + mock := mocks.NewMockAutheliaCtx(t) + defer mock.Close() + + mock.UserProviderMock.EXPECT(). + CheckUserPassword(gomock.Eq("john"), gomock.Eq("password")). + Return(false, nil) + + url, _ := url.ParseRequestURI("https://test.example.com") + _, _, _, err := verifyBasicAuth([]byte("Basic am9objpwYXNzd29yZA=="), *url, mock.Ctx) + + assert.Error(t, err) +} + +type TestCase struct { + URL string + Authorization string + ExpectedStatusCode int +} + +func (tc TestCase) String() string { + return fmt.Sprintf("url=%s, auth=%s, exp_status=%d", tc.URL, tc.Authorization, tc.ExpectedStatusCode) +} + +func TestShouldVerifyAuthorizationsUsingBasicAuth(t *testing.T) { + testCases := []TestCase{ + // Authorization has bad format. + TestCase{"https://bypass.example.com", "Basic am9objpaaaaaaaaaaaaaaaa", 401}, + + // Correct Authorization + TestCase{"https://test.example.com", "Basic am9objpwYXNzd29yZA==", 403}, + TestCase{"https://bypass.example.com", "Basic am9objpwYXNzd29yZA==", 200}, + TestCase{"https://one-factor.example.com", "Basic am9objpwYXNzd29yZA==", 200}, + TestCase{"https://two-factor.example.com", "Basic am9objpwYXNzd29yZA==", 401}, + TestCase{"https://deny.example.com", "Basic am9objpwYXNzd29yZA==", 403}, + } + + for _, testCase := range testCases { + testCase := testCase + t.Run(testCase.String(), func(t *testing.T) { + mock := mocks.NewMockAutheliaCtx(t) + defer mock.Close() + + mock.UserProviderMock.EXPECT(). + CheckUserPassword(gomock.Eq("john"), gomock.Eq("password")). + Return(true, nil) + + details := authentication.UserDetails{ + Emails: []string{"john@example.com"}, + Groups: []string{"dev", "admin"}, + } + mock.UserProviderMock.EXPECT(). + GetDetails(gomock.Eq("john")). + Return(&details, nil) + + mock.Ctx.Request.Header.Set("Proxy-Authorization", testCase.Authorization) + mock.Ctx.Request.Header.Set("X-Original-URL", testCase.URL) + + VerifyGet(mock.Ctx) + expStatus, actualStatus := testCase.ExpectedStatusCode, mock.Ctx.Response.StatusCode() + assert.Equal(t, expStatus, actualStatus, "URL=%s -> StatusCode=%d != ExpectedStatusCode=%d", + testCase.URL, actualStatus, expStatus) + + if testCase.ExpectedStatusCode == 200 { + assert.Equal(t, []byte("john"), mock.Ctx.Response.Header.Peek("Remote-User")) + assert.Equal(t, []byte("dev,admin"), mock.Ctx.Response.Header.Peek("Remote-Groups")) + } else { + assert.Equal(t, []byte(nil), mock.Ctx.Response.Header.Peek("Remote-User")) + assert.Equal(t, []byte(nil), mock.Ctx.Response.Header.Peek("Remote-Groups")) + } + }) + } +} + +func TestShouldVerifyWrongCredentialsInBasicAuth(t *testing.T) { + mock := mocks.NewMockAutheliaCtx(t) + defer mock.Close() + + mock.UserProviderMock.EXPECT(). + CheckUserPassword(gomock.Eq("john"), gomock.Eq("wrongpass")). + Return(false, nil) + + mock.Ctx.Request.Header.Set("Proxy-Authorization", "Basic am9objp3cm9uZ3Bhc3M=") + mock.Ctx.Request.Header.Set("X-Original-URL", "https://test.example.com") + + VerifyGet(mock.Ctx) + expStatus, actualStatus := 401, mock.Ctx.Response.StatusCode() + assert.Equal(t, expStatus, actualStatus, "URL=%s -> StatusCode=%d != ExpectedStatusCode=%d", + "https://test.example.com", actualStatus, expStatus) +} + +func TestShouldVerifyFailingPasswordCheckingInBasicAuth(t *testing.T) { + mock := mocks.NewMockAutheliaCtx(t) + defer mock.Close() + + mock.UserProviderMock.EXPECT(). + CheckUserPassword(gomock.Eq("john"), gomock.Eq("wrongpass")). + Return(false, fmt.Errorf("Failed")) + + mock.Ctx.Request.Header.Set("Proxy-Authorization", "Basic am9objp3cm9uZ3Bhc3M=") + mock.Ctx.Request.Header.Set("X-Original-URL", "https://test.example.com") + + VerifyGet(mock.Ctx) + expStatus, actualStatus := 401, mock.Ctx.Response.StatusCode() + assert.Equal(t, expStatus, actualStatus, "URL=%s -> StatusCode=%d != ExpectedStatusCode=%d", + "https://test.example.com", actualStatus, expStatus) +} + +func TestShouldVerifyFailingDetailsFetchingInBasicAuth(t *testing.T) { + mock := mocks.NewMockAutheliaCtx(t) + defer mock.Close() + + mock.UserProviderMock.EXPECT(). + CheckUserPassword(gomock.Eq("john"), gomock.Eq("password")). + Return(true, nil) + + mock.UserProviderMock.EXPECT(). + GetDetails(gomock.Eq("john")). + Return(nil, fmt.Errorf("Failed")) + + mock.Ctx.Request.Header.Set("Proxy-Authorization", "Basic am9objpwYXNzd29yZA==") + mock.Ctx.Request.Header.Set("X-Original-URL", "https://test.example.com") + + VerifyGet(mock.Ctx) + expStatus, actualStatus := 401, mock.Ctx.Response.StatusCode() + assert.Equal(t, expStatus, actualStatus, "URL=%s -> StatusCode=%d != ExpectedStatusCode=%d", + "https://test.example.com", actualStatus, expStatus) +} + +type Pair struct { + URL string + Username string + AuthenticationLevel authentication.Level + ExpectedStatusCode int +} + +func (p Pair) String() string { + return fmt.Sprintf("url=%s, username=%s, auth_lvl=%d, exp_status=%d", + p.URL, p.Username, p.AuthenticationLevel, p.ExpectedStatusCode) +} + +func TestShouldVerifyAuthorizationsUsingSessionCookie(t *testing.T) { + testCases := []Pair{ + Pair{"https://test.example.com", "", authentication.NotAuthenticated, 401}, + Pair{"https://bypass.example.com", "", authentication.NotAuthenticated, 200}, + Pair{"https://one-factor.example.com", "", authentication.NotAuthenticated, 401}, + Pair{"https://two-factor.example.com", "", authentication.NotAuthenticated, 401}, + Pair{"https://deny.example.com", "", authentication.NotAuthenticated, 401}, + + Pair{"https://test.example.com", "john", authentication.OneFactor, 403}, + Pair{"https://bypass.example.com", "john", authentication.OneFactor, 200}, + Pair{"https://one-factor.example.com", "john", authentication.OneFactor, 200}, + Pair{"https://two-factor.example.com", "john", authentication.OneFactor, 401}, + Pair{"https://deny.example.com", "john", authentication.OneFactor, 403}, + + Pair{"https://test.example.com", "john", authentication.TwoFactor, 403}, + Pair{"https://bypass.example.com", "john", authentication.TwoFactor, 200}, + Pair{"https://one-factor.example.com", "john", authentication.TwoFactor, 200}, + Pair{"https://two-factor.example.com", "john", authentication.TwoFactor, 200}, + Pair{"https://deny.example.com", "john", authentication.TwoFactor, 403}, + } + + for _, testCase := range testCases { + testCase := testCase + t.Run(testCase.String(), func(t *testing.T) { + mock := mocks.NewMockAutheliaCtx(t) + defer mock.Close() + + userSession := mock.Ctx.GetSession() + userSession.Username = testCase.Username + userSession.AuthenticationLevel = testCase.AuthenticationLevel + mock.Ctx.SaveSession(userSession) + + mock.Ctx.Request.Header.Set("X-Original-URL", testCase.URL) + + VerifyGet(mock.Ctx) + expStatus, actualStatus := testCase.ExpectedStatusCode, mock.Ctx.Response.StatusCode() + assert.Equal(t, expStatus, actualStatus, "URL=%s -> AuthLevel=%d, StatusCode=%d != ExpectedStatusCode=%d", + testCase.URL, testCase.AuthenticationLevel, actualStatus, expStatus) + + if testCase.ExpectedStatusCode == 200 && testCase.Username != "" { + assert.Equal(t, []byte(testCase.Username), mock.Ctx.Response.Header.Peek("Remote-User")) + } else { + assert.Equal(t, []byte(nil), mock.Ctx.Response.Header.Peek("Remote-User")) + } + }) + } +} diff --git a/handlers/safe_redirection.go b/handlers/safe_redirection.go new file mode 100644 index 000000000..b03bbf9eb --- /dev/null +++ b/handlers/safe_redirection.go @@ -0,0 +1,17 @@ +package handlers + +import ( + "net/url" + "strings" +) + +func isRedirectionSafe(url url.URL, protectedDomain string) bool { + if url.Scheme != "https" { + return false + } + + if !strings.HasSuffix(url.Hostname(), protectedDomain) { + return false + } + return true +} diff --git a/handlers/safe_redirection_test.go b/handlers/safe_redirection_test.go new file mode 100644 index 000000000..cd4c575da --- /dev/null +++ b/handlers/safe_redirection_test.go @@ -0,0 +1,25 @@ +package handlers + +import ( + "net/url" + "testing" + + "github.com/stretchr/testify/assert" +) + +func isURLSafe(requestURI string, domain string) bool { + url, _ := url.ParseRequestURI(requestURI) + return isRedirectionSafe(*url, domain) +} + +func TestShouldReturnFalseOnBadScheme(t *testing.T) { + assert.False(t, isURLSafe("http://secure.example.com", "example.com")) + assert.False(t, isURLSafe("ftp://secure.example.com", "example.com")) + assert.True(t, isURLSafe("https://secure.example.com", "example.com")) +} + +func TestShouldReturnFalseOnBadDomain(t *testing.T) { + assert.False(t, isURLSafe("https://secure.example.com.c", "example.com")) + assert.False(t, isURLSafe("https://secure.example.comc", "example.com")) + assert.False(t, isURLSafe("https://secure.example.co", "example.com")) +} diff --git a/handlers/types.go b/handlers/types.go new file mode 100644 index 000000000..44c115265 --- /dev/null +++ b/handlers/types.go @@ -0,0 +1,78 @@ +package handlers + +import ( + "github.com/clems4ever/authelia/authentication" + "github.com/tstranex/u2f" +) + +// MethodList is the list of available methods. +type MethodList = []string + +type authorizationMatching int + +// preferences is the model of user second factor preferences +type preferences struct { + // The prefered 2FA method. + Method string `json:"method" valid:"required"` +} + +// signTOTPRequestBody model of the request body received by TOTP authentication endpoint. +type signTOTPRequestBody struct { + Token string `json:"token" valid:"required"` + TargetURL string `json:"targetURL"` +} + +// signU2FRequestBody model of the request body of U2F authentication endpoint. +type signU2FRequestBody struct { + SignResponse u2f.SignResponse `json:"signResponse"` + TargetURL string `json:"targetURL"` +} + +type signDuoRequestBody struct { + TargetURL string `json:"targetURL"` +} + +// firstFactorBody represents the JSON body received by the endpoint. +type firstFactorRequestBody struct { + Username string `json:"username" valid:"required"` + Password string `json:"password" valid:"required"` + TargetURL string `json:"targetURL"` + // Cannot require this field because of https://github.com/asaskevich/govalidator/pull/329 + // TODO(c.michaud): add required validation once the above PR is merged. + KeepMeLoggedIn *bool `json:"keepMeLoggedIn"` +} + +// FirstFactorMessageResponse represents the response sent by the first factor endpoint +// when no redirection URL has been provided by the user. +type firstFactorMessageResponse struct { + Message string `json:"message"` +} + +// redirectResponse represent the response sent by the first factor endpoint +// when a redirection URL has been provided. +type redirectResponse struct { + Redirect string `json:"redirect"` +} + +// TOTPKeyResponse is the model of response that is sent to the client up successful identity verification. +type TOTPKeyResponse struct { + Base32Secret string `json:"base32_secret"` + OTPAuthURL string `json:"otpauth_url"` +} + +// StateResponse represents the response sent by the state endpoint. +type StateResponse struct { + Username string `json:"username"` + AuthenticationLevel authentication.Level `json:"authentication_level"` + DefaultRedirectionURL string `json:"default_redirection_url"` +} + +// resetPasswordStep1RequestBody model of the reset password (step1) request body +type resetPasswordStep1RequestBody struct { + Username string `json:"username"` +} + +// resetPasswordStep2RequestBody model of the reset password (step2) request body +type resetPasswordStep2RequestBody struct { + Password string `json:"password"` +} diff --git a/logging/logger.go b/logging/logger.go new file mode 100644 index 000000000..34eb4b9a9 --- /dev/null +++ b/logging/logger.go @@ -0,0 +1,25 @@ +package logging + +import ( + "github.com/sirupsen/logrus" + "github.com/valyala/fasthttp" +) + +// Logger return the standard logrues logger. +func Logger() *logrus.Logger { + return logrus.StandardLogger() +} + +// NewRequestLogger create a new request logger for the given request. +func NewRequestLogger(ctx *fasthttp.RequestCtx) *logrus.Entry { + return logrus.WithFields(logrus.Fields{ + "method": string(ctx.Method()), + "path": string(ctx.Path()), + "remote_ip": ctx.RemoteIP().String(), + }) +} + +// SetLevel set the level of the logger. +func SetLevel(level logrus.Level) { + logrus.SetLevel(level) +} diff --git a/main.go b/main.go new file mode 100644 index 000000000..22025cdc0 --- /dev/null +++ b/main.go @@ -0,0 +1,103 @@ +package main + +import ( + "errors" + "flag" + "log" + "os" + + "github.com/clems4ever/authelia/regulation" + + "github.com/clems4ever/authelia/session" + + "github.com/clems4ever/authelia/authentication" + "github.com/clems4ever/authelia/authorization" + "github.com/clems4ever/authelia/configuration" + "github.com/clems4ever/authelia/logging" + "github.com/clems4ever/authelia/middlewares" + "github.com/clems4ever/authelia/notification" + "github.com/clems4ever/authelia/server" + "github.com/clems4ever/authelia/storage" + "github.com/sirupsen/logrus" +) + +func tryExtractConfigPath() (string, error) { + configPtr := flag.String("config", "", "The path to a configuration file.") + flag.Parse() + + if *configPtr == "" { + return "", errors.New("No config file path provided") + } + + return *configPtr, nil +} + +func main() { + if os.Getenv("ENVIRONMENT") == "dev" { + logging.Logger().Info("===> Authelia is running in development mode. <===") + } + + configPath, err := tryExtractConfigPath() + if err != nil { + logging.Logger().Error(err) + } + + config, errs := configuration.Read(configPath) + + if len(errs) > 0 { + for _, err = range errs { + logging.Logger().Error(err) + } + panic(errors.New("Some errors have been reported")) + } + + switch config.LogsLevel { + case "info": + logging.SetLevel(logrus.InfoLevel) + break + case "debug": + logging.SetLevel(logrus.TraceLevel) + } + + var userProvider authentication.UserProvider + + if config.AuthenticationBackend.File != nil { + userProvider = authentication.NewFileUserProvider(config.AuthenticationBackend.File.Path) + } else if config.AuthenticationBackend.Ldap != nil { + userProvider = authentication.NewLDAPUserProvider(*config.AuthenticationBackend.Ldap) + } else { + log.Fatalf("Unrecognized authentication backend") + } + + var storageProvider storage.Provider + if config.Storage.Mongo != nil { + storageProvider = storage.NewMongoProvider(*config.Storage.Mongo) + } else if config.Storage.Local != nil { + storageProvider = storage.NewSQLiteProvider(config.Storage.Local.Path) + } else { + log.Fatalf("Unrecognized storage backend") + } + + var notifier notification.Notifier + if config.Notifier.SMTP != nil { + notifier = notification.NewSMTPNotifier(*config.Notifier.SMTP) + } else if config.Notifier.FileSystem != nil { + notifier = notification.NewFileNotifier(*config.Notifier.FileSystem) + } else { + log.Fatalf("Unrecognized notifier") + } + + authorizer := authorization.NewAuthorizer(*config.AccessControl) + sessionProvider := session.NewProvider(config.Session) + regulator := regulation.NewRegulator(config.Regulation, storageProvider) + + providers := middlewares.Providers{ + Authorizer: authorizer, + UserProvider: userProvider, + Regulator: regulator, + StorageProvider: storageProvider, + Notifier: notifier, + SessionProvider: sessionProvider, + } + server.StartServer(*config, providers) +} diff --git a/middlewares/authelia_context.go b/middlewares/authelia_context.go new file mode 100644 index 000000000..50c80ad3c --- /dev/null +++ b/middlewares/authelia_context.go @@ -0,0 +1,146 @@ +package middlewares + +import ( + "encoding/json" + "fmt" + "net" + "strings" + + "github.com/asaskevich/govalidator" + "github.com/clems4ever/authelia/session" + + "github.com/clems4ever/authelia/configuration/schema" + "github.com/clems4ever/authelia/logging" + "github.com/valyala/fasthttp" +) + +// NewAutheliaCtx instantiate an AutheliaCtx out of a RequestCtx. +func NewAutheliaCtx(ctx *fasthttp.RequestCtx, configuration schema.Configuration, providers Providers) (*AutheliaCtx, error) { + autheliaCtx := new(AutheliaCtx) + autheliaCtx.RequestCtx = ctx + autheliaCtx.Providers = providers + autheliaCtx.Configuration = configuration + autheliaCtx.Logger = logging.NewRequestLogger(ctx) + + userSession, err := providers.SessionProvider.GetSession(ctx) + if err != nil { + return nil, fmt.Errorf("Unable to retrieve user session: %s", err.Error()) + } + + autheliaCtx.userSession = userSession + return autheliaCtx, nil +} + +// AutheliaMiddleware is wrapping the RequestCtx into an AutheliaCtx providing Authelia related objects. +func AutheliaMiddleware(configuration schema.Configuration, providers Providers) func(next RequestHandler) fasthttp.RequestHandler { + return func(next RequestHandler) fasthttp.RequestHandler { + return func(ctx *fasthttp.RequestCtx) { + autheliaCtx, err := NewAutheliaCtx(ctx, configuration, providers) + if err != nil { + autheliaCtx.Error(err, operationFailedMessage) + return + } + next(autheliaCtx) + } + } +} + +func (c *AutheliaCtx) Error(err error, message string) { + b, _ := json.Marshal(ErrorResponse{Status: "KO", Message: message}) + c.SetContentType("application/json") + c.SetBody(b) + c.Logger.Error(err) +} + +// ReplyUnauthorized response sent when user is unauthorized +func (c *AutheliaCtx) ReplyUnauthorized() { + c.RequestCtx.Error(fasthttp.StatusMessage(fasthttp.StatusUnauthorized), fasthttp.StatusUnauthorized) + // c.Response.Header.Set("WWW-Authenticate", "Basic realm=Restricted") +} + +// ReplyForbidden response sent when access is forbidden to user +func (c *AutheliaCtx) ReplyForbidden() { + c.RequestCtx.Error(fasthttp.StatusMessage(fasthttp.StatusForbidden), fasthttp.StatusForbidden) +} + +// XForwardedProto return the content of the header X-Forwarded-Proto +func (c *AutheliaCtx) XForwardedProto() []byte { + return c.RequestCtx.Request.Header.Peek(xForwardedProtoHeader) +} + +// XForwardedHost return the content of the header X-Forwarded-Host +func (c *AutheliaCtx) XForwardedHost() []byte { + return c.RequestCtx.Request.Header.Peek(xForwardedHostHeader) +} + +// XForwardedURI return the content of the header X-Forwarded-URI +func (c *AutheliaCtx) XForwardedURI() []byte { + return c.RequestCtx.Request.Header.Peek(xForwardedURIHeader) +} + +// XOriginalURL return the content of the header X-Original-URL +func (c *AutheliaCtx) XOriginalURL() []byte { + return c.RequestCtx.Request.Header.Peek(xOriginalURLHeader) +} + +// GetSession return the user session. Any update will be saved in cache. +func (c *AutheliaCtx) GetSession() session.UserSession { + return c.userSession +} + +// SaveSession save the content of the session. +func (c *AutheliaCtx) SaveSession(userSession session.UserSession) error { + c.userSession = userSession + return c.Providers.SessionProvider.SaveSession(c.RequestCtx, userSession) +} + +// ReplyOK is a helper method to reply ok +func (c *AutheliaCtx) ReplyOK() { + c.SetContentType(applicationJSONContentType) + c.SetBody(okMessageBytes) +} + +// ParseBody parse the request body into the type of value +func (c *AutheliaCtx) ParseBody(value interface{}) error { + err := json.Unmarshal(c.PostBody(), &value) + + if err != nil { + return fmt.Errorf("Unable to parse body: %s", err) + } + + valid, err := govalidator.ValidateStruct(value) + + if err != nil { + return fmt.Errorf("Unable to validate body: %s", err) + } + + if !valid { + return fmt.Errorf("Body is not valid") + } + return nil +} + +// SetJSONBody Set json body +func (c *AutheliaCtx) SetJSONBody(value interface{}) error { + b, err := json.Marshal(OKResponse{Status: "OK", Data: value}) + if err != nil { + return fmt.Errorf("Unable to marshal JSON body") + } + + c.SetContentType("application/json") + c.SetBody(b) + return nil +} + +// RemoteIP return the remote IP taking X-Forwarded-For header into account if provided. +func (c *AutheliaCtx) RemoteIP() net.IP { + XForwardedFor := c.RequestCtx.Request.Header.Peek("X-Forwarded-For") + if XForwardedFor != nil { + ips := strings.Split(string(XForwardedFor), ",") + + if len(ips) > 0 { + return net.ParseIP(strings.Trim(ips[0], " ")) + } + } + return c.RequestCtx.RemoteIP() +} diff --git a/middlewares/authelia_context_test.go b/middlewares/authelia_context_test.go new file mode 100644 index 000000000..e244a6cc1 --- /dev/null +++ b/middlewares/authelia_context_test.go @@ -0,0 +1,35 @@ +package middlewares_test + +import ( + "testing" + + "github.com/clems4ever/authelia/session" + + "github.com/clems4ever/authelia/configuration/schema" + "github.com/clems4ever/authelia/middlewares" + "github.com/clems4ever/authelia/mocks" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + "github.com/valyala/fasthttp" +) + +func TestShouldCallNextWithAutheliaCtx(t *testing.T) { + ctrl := gomock.NewController(t) + ctx := &fasthttp.RequestCtx{} + configuration := schema.Configuration{} + userProvider := mocks.NewMockUserProvider(ctrl) + sessionProvider := session.NewProvider(configuration.Session) + providers := middlewares.Providers{ + UserProvider: userProvider, + SessionProvider: sessionProvider, + } + nextCalled := false + + middlewares.AutheliaMiddleware(configuration, providers)(func(actx *middlewares.AutheliaCtx) { + // Authelia context wraps the request. + assert.Equal(t, ctx, actx.RequestCtx) + nextCalled = true + })(ctx) + + assert.True(t, nextCalled) +} diff --git a/middlewares/const.go b/middlewares/const.go new file mode 100644 index 000000000..3959044fb --- /dev/null +++ b/middlewares/const.go @@ -0,0 +1,18 @@ +package middlewares + +// JWTIssuer is +const jwtIssuer = "Authelia" + +const xForwardedProtoHeader = "X-Forwarded-Proto" +const xForwardedHostHeader = "X-Forwarded-Host" +const xForwardedURIHeader = "X-Forwarded-URI" + +const xOriginalURLHeader = "X-Original-URL" + +const applicationJSONContentType = "application/json" + +var okMessageBytes = []byte("{\"status\":\"OK\"}") + +const operationFailedMessage = "Operation failed" +const identityVerificationTokenAlreadyUsedMessage = "The identity verification token has already been used" +const identityVerificationTokenHasExpiredMessage = "The identity verification token has expired" diff --git a/middlewares/errors.go b/middlewares/errors.go new file mode 100644 index 000000000..1ee2e5bc3 --- /dev/null +++ b/middlewares/errors.go @@ -0,0 +1,8 @@ +package middlewares + +// InternalError is the error message sent when there was an internal error but it should +// be hidden to the end user. In that case the error should be in the server logs. +const InternalError = "Internal error." + +// UnauthorizedError is the error message sent when the user is not authorized. +const UnauthorizedError = "You're not authorized." diff --git a/middlewares/identity_verification.go b/middlewares/identity_verification.go new file mode 100644 index 000000000..8bbe7ccc1 --- /dev/null +++ b/middlewares/identity_verification.go @@ -0,0 +1,161 @@ +package middlewares + +import ( + "bytes" + "encoding/json" + "fmt" + "time" + + "github.com/clems4ever/authelia/templates" + jwt "github.com/dgrijalva/jwt-go" +) + +// IdentityVerificationStart the handler for initiating the identity validation process. +func IdentityVerificationStart(args IdentityVerificationStartArgs) RequestHandler { + if args.IdentityRetrieverFunc == nil { + panic(fmt.Errorf("Identity verification requires an identity retriever")) + } + + return func(ctx *AutheliaCtx) { + identity, err := args.IdentityRetrieverFunc(ctx) + + if err != nil { + // In that case we reply ok to avoid user enumeration. + ctx.Logger.Error(err) + ctx.ReplyOK() + return + } + + // Create the claim with the action to sign it. + claims := &IdentityVerificationClaim{ + jwt.StandardClaims{ + ExpiresAt: time.Now().Add(5 * time.Minute).Unix(), + Issuer: jwtIssuer, + }, + args.ActionClaim, + identity.Username, + } + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + ss, err := token.SignedString([]byte(ctx.Configuration.JWTSecret)) + + if err != nil { + ctx.Error(err, operationFailedMessage) + return + } + + err = ctx.Providers.StorageProvider.SaveIdentityVerificationToken(ss) + if err != nil { + ctx.Error(err, operationFailedMessage) + return + } + + link := fmt.Sprintf("%s://%s/#%s?token=%s", ctx.XForwardedProto(), + ctx.XForwardedHost(), args.TargetEndpoint, ss) + + params := map[string]interface{}{ + "title": args.MailTitle, + "url": link, + "button": args.MailButtonContent, + } + buf := new(bytes.Buffer) + err = templates.EmailTemplate.Execute(buf, params) + + if err != nil { + ctx.Error(err, operationFailedMessage) + return + } + + ctx.Logger.Debugf("Sending an email to user %s (%s) to confirm identity for registering a TOTP device.", + identity.Username, identity.Email) + err = ctx.Providers.Notifier.Send(identity.Email, args.MailSubject, buf.String()) + + if err != nil { + ctx.Error(err, operationFailedMessage) + return + } + + ctx.ReplyOK() + } +} + +// IdentityVerificationFinish the middleware for finishing the identity validation process. +func IdentityVerificationFinish(args IdentityVerificationFinishArgs, next func(ctx *AutheliaCtx, username string)) RequestHandler { + return func(ctx *AutheliaCtx) { + var finishBody IdentityVerificationFinishBody + b := ctx.PostBody() + + err := json.Unmarshal(b, &finishBody) + + if err != nil { + ctx.Error(err, operationFailedMessage) + return + } + + if finishBody.Token == "" { + ctx.Error(fmt.Errorf("No token provided"), operationFailedMessage) + return + } + + found, err := ctx.Providers.StorageProvider.FindIdentityVerificationToken(finishBody.Token) + + if err != nil { + ctx.Error(err, operationFailedMessage) + return + } + + if !found { + ctx.Error(fmt.Errorf("Token is not in DB, it might have already been used"), + identityVerificationTokenAlreadyUsedMessage) + return + } + + token, err := jwt.ParseWithClaims(finishBody.Token, &IdentityVerificationClaim{}, + func(token *jwt.Token) (interface{}, error) { + return []byte(ctx.Configuration.JWTSecret), nil + }) + + if err != nil { + if ve, ok := err.(*jwt.ValidationError); ok { + if ve.Errors&jwt.ValidationErrorMalformed != 0 { + ctx.Error(fmt.Errorf("Cannot parse token"), operationFailedMessage) + return + } else if ve.Errors&(jwt.ValidationErrorExpired|jwt.ValidationErrorNotValidYet) != 0 { + // Token is either expired or not active yet + ctx.Error(fmt.Errorf("Token expired"), identityVerificationTokenHasExpiredMessage) + return + } else { + ctx.Error(fmt.Errorf("Cannot handle this token: %s", ve), operationFailedMessage) + return + } + } + ctx.Error(err, operationFailedMessage) + return + } + + claims, ok := token.Claims.(*IdentityVerificationClaim) + if !ok { + ctx.Error(fmt.Errorf("Wrong type of claims (%T != *middlewares.IdentityVerificationClaim)", claims), operationFailedMessage) + return + } + + // Verify that the action claim in the token is the one expected for the given endpoint. + if claims.Action != args.ActionClaim { + ctx.Error(fmt.Errorf("This token has not been generated for this kind of action"), operationFailedMessage) + return + } + + if args.IsTokenUserValidFunc != nil && !args.IsTokenUserValidFunc(ctx, claims.Username) { + ctx.Error(fmt.Errorf("This token has not been generated for this user"), operationFailedMessage) + return + } + + // TODO(c.michaud): find a way to garbage collect unused tokens. + err = ctx.Providers.StorageProvider.RemoveIdentityVerificationToken(finishBody.Token) + if err != nil { + ctx.Error(err, operationFailedMessage) + return + } + + next(ctx, claims.Username) + } +} diff --git a/middlewares/identity_verification_test.go b/middlewares/identity_verification_test.go new file mode 100644 index 000000000..a21531b53 --- /dev/null +++ b/middlewares/identity_verification_test.go @@ -0,0 +1,280 @@ +package middlewares_test + +import ( + "fmt" + "testing" + "time" + + "github.com/clems4ever/authelia/middlewares" + "github.com/clems4ever/authelia/mocks" + "github.com/clems4ever/authelia/session" + jwt "github.com/dgrijalva/jwt-go" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +func newArgs(retriever func(ctx *middlewares.AutheliaCtx) (*session.Identity, error)) middlewares.IdentityVerificationStartArgs { + return middlewares.IdentityVerificationStartArgs{ + ActionClaim: "Claim", + MailButtonContent: "Register", + MailSubject: "Subject", + MailTitle: "Title", + TargetEndpoint: "/target", + IdentityRetrieverFunc: retriever, + } +} + +func defaultRetriever(ctx *middlewares.AutheliaCtx) (*session.Identity, error) { + return &session.Identity{ + Username: "john", + Email: "john@example.com", + }, nil +} + +func TestShouldFailStartingProcessIfUserHasNoEmailAddress(t *testing.T) { + mock := mocks.NewMockAutheliaCtx(t) + defer mock.Close() + + retriever := func(ctx *middlewares.AutheliaCtx) (*session.Identity, error) { + return nil, fmt.Errorf("User does not have any email") + } + + middlewares.IdentityVerificationStart(newArgs(retriever))(mock.Ctx) + + // Return 200 KO + assert.Equal(t, 200, mock.Ctx.Response.StatusCode()) + assert.Equal(t, "User does not have any email", mock.Hook.LastEntry().Message) +} + +func TestShouldFailIfJWTCannotBeSaved(t *testing.T) { + mock := mocks.NewMockAutheliaCtx(t) + defer mock.Close() + + mock.Ctx.Configuration.JWTSecret = "abc" + + mock.StorageProviderMock.EXPECT(). + SaveIdentityVerificationToken(gomock.Any()). + Return(fmt.Errorf("cannot save")) + + args := newArgs(defaultRetriever) + middlewares.IdentityVerificationStart(args)(mock.Ctx) + + // Return 200 KO + assert.Equal(t, 200, mock.Ctx.Response.StatusCode()) + assert.Equal(t, "cannot save", mock.Hook.LastEntry().Message) +} + +func TestShouldFailSendingAnEmail(t *testing.T) { + mock := mocks.NewMockAutheliaCtx(t) + defer mock.Close() + + mock.Ctx.Configuration.JWTSecret = "abc" + + mock.StorageProviderMock.EXPECT(). + SaveIdentityVerificationToken(gomock.Any()). + Return(nil) + + mock.NotifierMock.EXPECT(). + Send(gomock.Eq("john@example.com"), gomock.Eq("Subject"), gomock.Any()). + Return(fmt.Errorf("no notif")) + + args := newArgs(defaultRetriever) + middlewares.IdentityVerificationStart(args)(mock.Ctx) + + // Return 200 KO + assert.Equal(t, 200, mock.Ctx.Response.StatusCode()) + assert.Equal(t, "no notif", mock.Hook.LastEntry().Message) +} + +func TestShouldSucceedIdentityVerficationStartProcess(t *testing.T) { + mock := mocks.NewMockAutheliaCtx(t) + defer mock.Close() + + mock.Ctx.Configuration.JWTSecret = "abc" + + mock.StorageProviderMock.EXPECT(). + SaveIdentityVerificationToken(gomock.Any()). + Return(nil) + + mock.NotifierMock.EXPECT(). + Send(gomock.Eq("john@example.com"), gomock.Eq("Subject"), gomock.Any()). + Return(nil) + + args := newArgs(defaultRetriever) + middlewares.IdentityVerificationStart(args)(mock.Ctx) + + assert.Equal(t, 200, mock.Ctx.Response.StatusCode()) +} + +// Test Finish process + +type IdentityVerificationFinishProcess struct { + suite.Suite + + mock *mocks.MockAutheliaCtx +} + +func (s *IdentityVerificationFinishProcess) SetupTest() { + s.mock = mocks.NewMockAutheliaCtx(s.T()) + + s.mock.Ctx.Configuration.JWTSecret = "abc" +} + +func (s *IdentityVerificationFinishProcess) TearDownTest() { + s.mock.Close() +} + +func createToken(secret string, username string, action string, expiresAt time.Time) string { + claims := &middlewares.IdentityVerificationClaim{ + jwt.StandardClaims{ + ExpiresAt: expiresAt.Unix(), + Issuer: "Authelia", + }, + action, + username, + } + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + ss, _ := token.SignedString([]byte(secret)) + return ss +} + +func next(ctx *middlewares.AutheliaCtx, username string) {} + +func newFinishArgs() middlewares.IdentityVerificationFinishArgs { + return middlewares.IdentityVerificationFinishArgs{ + ActionClaim: "EXP_ACTION", + IsTokenUserValidFunc: func(ctx *middlewares.AutheliaCtx, username string) bool { return true }, + } +} + +func (s *IdentityVerificationFinishProcess) TestShouldFailIfJSONBodyIsMalformed() { + middlewares.IdentityVerificationFinish(newFinishArgs(), next)(s.mock.Ctx) + + s.mock.Assert200KO(s.T(), "Operation failed") + assert.Equal(s.T(), "unexpected end of JSON input", s.mock.Hook.LastEntry().Message) +} + +func (s *IdentityVerificationFinishProcess) TestShouldFailIfTokenIsNotProvided() { + s.mock.Ctx.Request.SetBodyString("{}") + middlewares.IdentityVerificationFinish(newFinishArgs(), next)(s.mock.Ctx) + + s.mock.Assert200KO(s.T(), "Operation failed") + assert.Equal(s.T(), "No token provided", s.mock.Hook.LastEntry().Message) +} + +func (s *IdentityVerificationFinishProcess) TestShouldFailIfTokenIsNotFoundInDB() { + s.mock.Ctx.Request.SetBodyString("{\"token\":\"abc\"}") + + s.mock.StorageProviderMock.EXPECT(). + FindIdentityVerificationToken(gomock.Eq("abc")). + Return(false, nil) + + middlewares.IdentityVerificationFinish(newFinishArgs(), next)(s.mock.Ctx) + + s.mock.Assert200KO(s.T(), "The identity verification token has already been used") + assert.Equal(s.T(), "Token is not in DB, it might have already been used", s.mock.Hook.LastEntry().Message) +} + +func (s *IdentityVerificationFinishProcess) TestShouldFailIfTokenIsInvalid() { + s.mock.Ctx.Request.SetBodyString("{\"token\":\"abc\"}") + + s.mock.StorageProviderMock.EXPECT(). + FindIdentityVerificationToken(gomock.Eq("abc")). + Return(true, nil) + + middlewares.IdentityVerificationFinish(newFinishArgs(), next)(s.mock.Ctx) + + s.mock.Assert200KO(s.T(), "Operation failed") + assert.Equal(s.T(), "Cannot parse token", s.mock.Hook.LastEntry().Message) +} + +func (s *IdentityVerificationFinishProcess) TestShouldFailIfTokenExpired() { + args := newArgs(defaultRetriever) + token := createToken(s.mock.Ctx.Configuration.JWTSecret, "john", args.ActionClaim, + time.Now().Add(-1*time.Minute)) + s.mock.Ctx.Request.SetBodyString(fmt.Sprintf("{\"token\":\"%s\"}", token)) + + s.mock.StorageProviderMock.EXPECT(). + FindIdentityVerificationToken(gomock.Eq(token)). + Return(true, nil) + + middlewares.IdentityVerificationFinish(newFinishArgs(), next)(s.mock.Ctx) + + s.mock.Assert200KO(s.T(), "The identity verification token has expired") + assert.Equal(s.T(), "Token expired", s.mock.Hook.LastEntry().Message) +} + +func (s *IdentityVerificationFinishProcess) TestShouldFailForWrongAction() { + token := createToken(s.mock.Ctx.Configuration.JWTSecret, "", "", + time.Now().Add(1*time.Minute)) + s.mock.Ctx.Request.SetBodyString(fmt.Sprintf("{\"token\":\"%s\"}", token)) + + s.mock.StorageProviderMock.EXPECT(). + FindIdentityVerificationToken(gomock.Eq(token)). + Return(true, nil) + + middlewares.IdentityVerificationFinish(newFinishArgs(), next)(s.mock.Ctx) + + s.mock.Assert200KO(s.T(), "Operation failed") + assert.Equal(s.T(), "This token has not been generated for this kind of action", s.mock.Hook.LastEntry().Message) +} + +func (s *IdentityVerificationFinishProcess) TestShouldFailForWrongUser() { + token := createToken(s.mock.Ctx.Configuration.JWTSecret, "harry", "EXP_ACTION", + time.Now().Add(1*time.Minute)) + s.mock.Ctx.Request.SetBodyString(fmt.Sprintf("{\"token\":\"%s\"}", token)) + + s.mock.StorageProviderMock.EXPECT(). + FindIdentityVerificationToken(gomock.Eq(token)). + Return(true, nil) + + args := newFinishArgs() + args.IsTokenUserValidFunc = func(ctx *middlewares.AutheliaCtx, username string) bool { return false } + middlewares.IdentityVerificationFinish(args, next)(s.mock.Ctx) + + s.mock.Assert200KO(s.T(), "Operation failed") + assert.Equal(s.T(), "This token has not been generated for this user", s.mock.Hook.LastEntry().Message) +} + +func (s *IdentityVerificationFinishProcess) TestShouldFailIfTokenCannotBeRemovedFromDB() { + token := createToken(s.mock.Ctx.Configuration.JWTSecret, "john", "EXP_ACTION", + time.Now().Add(1*time.Minute)) + s.mock.Ctx.Request.SetBodyString(fmt.Sprintf("{\"token\":\"%s\"}", token)) + + s.mock.StorageProviderMock.EXPECT(). + FindIdentityVerificationToken(gomock.Eq(token)). + Return(true, nil) + + s.mock.StorageProviderMock.EXPECT(). + RemoveIdentityVerificationToken(gomock.Eq(token)). + Return(fmt.Errorf("cannot remove")) + + middlewares.IdentityVerificationFinish(newFinishArgs(), next)(s.mock.Ctx) + + s.mock.Assert200KO(s.T(), "Operation failed") + assert.Equal(s.T(), "cannot remove", s.mock.Hook.LastEntry().Message) +} + +func (s *IdentityVerificationFinishProcess) TestShouldReturn200OnFinishComplete() { + token := createToken(s.mock.Ctx.Configuration.JWTSecret, "john", "EXP_ACTION", + time.Now().Add(1*time.Minute)) + s.mock.Ctx.Request.SetBodyString(fmt.Sprintf("{\"token\":\"%s\"}", token)) + + s.mock.StorageProviderMock.EXPECT(). + FindIdentityVerificationToken(gomock.Eq(token)). + Return(true, nil) + + s.mock.StorageProviderMock.EXPECT(). + RemoveIdentityVerificationToken(gomock.Eq(token)). + Return(nil) + + middlewares.IdentityVerificationFinish(newFinishArgs(), next)(s.mock.Ctx) + + assert.Equal(s.T(), 200, s.mock.Ctx.Response.StatusCode()) +} + +func TestRunIdentityVerificationFinish(t *testing.T) { + s := new(IdentityVerificationFinishProcess) + suite.Run(t, s) +} diff --git a/middlewares/log_request.go b/middlewares/log_request.go new file mode 100644 index 000000000..3a2220988 --- /dev/null +++ b/middlewares/log_request.go @@ -0,0 +1,17 @@ +package middlewares + +import ( + "github.com/clems4ever/authelia/logging" + "github.com/valyala/fasthttp" +) + +// LogRequestMiddleware logs the query that is being treated. +func LogRequestMiddleware(next fasthttp.RequestHandler) fasthttp.RequestHandler { + return func(ctx *fasthttp.RequestCtx) { + logger := logging.NewRequestLogger(ctx) + + logger.Trace("Request hit") + next(ctx) + logger.Tracef("Replied (status=%d)", ctx.Response.StatusCode()) + } +} diff --git a/middlewares/log_request_test.go b/middlewares/log_request_test.go new file mode 100644 index 000000000..4b521efb6 --- /dev/null +++ b/middlewares/log_request_test.go @@ -0,0 +1,18 @@ +package middlewares + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/valyala/fasthttp" +) + +func TestShouldCallNextFunction(t *testing.T) { + var val = false + f := func(ctx *fasthttp.RequestCtx) { val = true } + + context := &fasthttp.RequestCtx{} + LogRequestMiddleware(f)(context) + + assert.Equal(t, true, val) +} diff --git a/middlewares/require_first_factor.go b/middlewares/require_first_factor.go new file mode 100644 index 000000000..73fbd64b6 --- /dev/null +++ b/middlewares/require_first_factor.go @@ -0,0 +1,16 @@ +package middlewares + +import ( + "github.com/clems4ever/authelia/authentication" +) + +// RequireFirstFactor check if user has enough permissions to execute the next handler. +func RequireFirstFactor(next RequestHandler) RequestHandler { + return func(ctx *AutheliaCtx) { + if ctx.GetSession().AuthenticationLevel < authentication.OneFactor { + ctx.ReplyForbidden() + return + } + next(ctx) + } +} diff --git a/middlewares/types.go b/middlewares/types.go new file mode 100644 index 000000000..35db422fd --- /dev/null +++ b/middlewares/types.go @@ -0,0 +1,101 @@ +package middlewares + +import ( + "github.com/clems4ever/authelia/authentication" + "github.com/clems4ever/authelia/authorization" + "github.com/clems4ever/authelia/configuration/schema" + "github.com/clems4ever/authelia/notification" + "github.com/clems4ever/authelia/regulation" + "github.com/clems4ever/authelia/session" + "github.com/clems4ever/authelia/storage" + jwt "github.com/dgrijalva/jwt-go" + "github.com/sirupsen/logrus" + "github.com/valyala/fasthttp" +) + +// AutheliaCtx contains all server variables related to Authelia. +type AutheliaCtx struct { + *fasthttp.RequestCtx + + Logger *logrus.Entry + Providers Providers + Configuration schema.Configuration + userSession session.UserSession +} + +// Providers contain all provider provided to Authelia. +type Providers struct { + Authorizer *authorization.Authorizer + SessionProvider *session.Provider + Regulator *regulation.Regulator + + UserProvider authentication.UserProvider + StorageProvider storage.Provider + Notifier notification.Notifier +} + +// RequestHandler represents an Authelia request handler. +type RequestHandler = func(*AutheliaCtx) + +// Middleware represent an Authelia middleware. +type Middleware = func(RequestHandler) RequestHandler + +// IdentityVerificationStartArgs represent the arguments used to customize the starting phase +// of the identity verification process. +type IdentityVerificationStartArgs struct { + // Email template needs a subject, a title and the content of the button. + MailSubject string + MailTitle string + MailButtonContent string + + // The target endpoint where to redirect the user when verification process + // is completed successfully. + TargetEndpoint string + + // The action claim that will be stored in the JWT token + ActionClaim string + + // The function retrieving the identity to who the email will be sent. + IdentityRetrieverFunc func(ctx *AutheliaCtx) (*session.Identity, error) + + // The function for checking the user in the token is valid for the current action + IsTokenUserValidFunc func(ctx *AutheliaCtx, username string) bool +} + +// IdentityVerificationFinishArgs represent the arguments used to customize the finishing phase +// of the identity verification process. +type IdentityVerificationFinishArgs struct { + // The action claim that should be in the token to consider the action legitimate + ActionClaim string + + // The function for checking the user in the token is valid for the current action + IsTokenUserValidFunc func(ctx *AutheliaCtx, username string) bool +} + +// IdentityVerificationClaim custom claim for specifying the action claim. +// The action can be to register a TOTP device, a U2F device or reset one's password. +type IdentityVerificationClaim struct { + jwt.StandardClaims + + // The action this token has been crafted for. + Action string `json:"action"` + // The user this token has been crafted for. + Username string `json:"username"` +} + +// IdentityVerificationFinishBody type of the body received by the finish endpoint. +type IdentityVerificationFinishBody struct { + Token string `json:"token"` +} + +// OKResponse model of a status OK response +type OKResponse struct { + Status string `json:"status"` + Data interface{} `json:"data"` +} + +// ErrorResponse model of an error response +type ErrorResponse struct { + Status string `json:"status"` + Message string `json:"message"` +} diff --git a/mocks/mock_authelia_ctx.go b/mocks/mock_authelia_ctx.go new file mode 100644 index 000000000..bd0746477 --- /dev/null +++ b/mocks/mock_authelia_ctx.go @@ -0,0 +1,116 @@ +package mocks + +import ( + "encoding/json" + "fmt" + "testing" + + "github.com/clems4ever/authelia/regulation" + "github.com/stretchr/testify/assert" + + "github.com/clems4ever/authelia/authorization" + "github.com/clems4ever/authelia/configuration/schema" + "github.com/clems4ever/authelia/middlewares" + "github.com/clems4ever/authelia/session" + "github.com/golang/mock/gomock" + "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus/hooks/test" + "github.com/valyala/fasthttp" +) + +// MockAutheliaCtx a mock of AutheliaCtx +type MockAutheliaCtx struct { + // Logger hook + Hook *test.Hook + Ctx *middlewares.AutheliaCtx + Ctrl *gomock.Controller + + // Providers + UserProviderMock *MockUserProvider + StorageProviderMock *MockStorageProvider + NotifierMock *MockNotifier + + UserSession *session.UserSession +} + +// NewMockAutheliaCtx create an instance of AutheliaCtx mock +func NewMockAutheliaCtx(t *testing.T) *MockAutheliaCtx { + mockAuthelia := new(MockAutheliaCtx) + + configuration := schema.Configuration{ + AccessControl: new(schema.AccessControlConfiguration), + } + configuration.Session.Name = "authelia_session" + configuration.AccessControl.DefaultPolicy = "deny" + configuration.AccessControl.Rules = []schema.ACLRule{schema.ACLRule{ + Domain: "bypass.example.com", + Policy: "bypass", + }, schema.ACLRule{ + Domain: "one-factor.example.com", + Policy: "one_factor", + }, schema.ACLRule{ + Domain: "two-factor.example.com", + Policy: "two_factor", + }, schema.ACLRule{ + Domain: "deny.example.com", + Policy: "deny", + }} + + providers := middlewares.Providers{} + + mockAuthelia.Ctrl = gomock.NewController(t) + mockAuthelia.UserProviderMock = NewMockUserProvider(mockAuthelia.Ctrl) + providers.UserProvider = mockAuthelia.UserProviderMock + + mockAuthelia.StorageProviderMock = NewMockStorageProvider(mockAuthelia.Ctrl) + providers.StorageProvider = mockAuthelia.StorageProviderMock + + mockAuthelia.NotifierMock = NewMockNotifier(mockAuthelia.Ctrl) + providers.Notifier = mockAuthelia.NotifierMock + + providers.Authorizer = authorization.NewAuthorizer( + *configuration.AccessControl) + + providers.SessionProvider = session.NewProvider( + configuration.Session) + + providers.Regulator = regulation.NewRegulator(configuration.Regulation, providers.StorageProvider) + + request := &fasthttp.RequestCtx{} + // Set a cookie to identify this client throughout the test + // request.Request.Header.SetCookie("authelia_session", "client_cookie") + + autheliaCtx, _ := middlewares.NewAutheliaCtx(request, configuration, providers) + mockAuthelia.Ctx = autheliaCtx + + logger, hook := test.NewNullLogger() + mockAuthelia.Hook = hook + + mockAuthelia.Ctx.Logger = logrus.NewEntry(logger) + return mockAuthelia +} + +// Close close the mock +func (m *MockAutheliaCtx) Close() { + m.Hook.Reset() +} + +// Assert200KO assert an error response from the service. +func (m *MockAutheliaCtx) Assert200KO(t *testing.T, message string) { + assert.Equal(t, 200, m.Ctx.Response.StatusCode()) + assert.Equal(t, fmt.Sprintf("{\"status\":\"KO\",\"message\":\"%s\"}", message), string(m.Ctx.Response.Body())) +} + +// Assert200OK assert a successful response from the service. +func (m *MockAutheliaCtx) Assert200OK(t *testing.T, data interface{}) { + assert.Equal(t, 200, m.Ctx.Response.StatusCode()) + response := middlewares.OKResponse{ + Status: "OK", + Data: data, + } + + b, err := json.Marshal(response) + + assert.NoError(t, err) + assert.Equal(t, string(b), string(m.Ctx.Response.Body())) +} diff --git a/mocks/mock_duo_api.go b/mocks/mock_duo_api.go new file mode 100644 index 000000000..bcbae1595 --- /dev/null +++ b/mocks/mock_duo_api.go @@ -0,0 +1,51 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/clems4ever/authelia/duo (interfaces: API) + +// Package mocks is a generated GoMock package. +package mocks + +import ( + url "net/url" + reflect "reflect" + + duo "github.com/clems4ever/authelia/duo" + gomock "github.com/golang/mock/gomock" +) + +// MockAPI is a mock of API interface +type MockAPI struct { + ctrl *gomock.Controller + recorder *MockAPIMockRecorder +} + +// MockAPIMockRecorder is the mock recorder for MockAPI +type MockAPIMockRecorder struct { + mock *MockAPI +} + +// NewMockAPI creates a new mock instance +func NewMockAPI(ctrl *gomock.Controller) *MockAPI { + mock := &MockAPI{ctrl: ctrl} + mock.recorder = &MockAPIMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockAPI) EXPECT() *MockAPIMockRecorder { + return m.recorder +} + +// Call mocks base method +func (m *MockAPI) Call(arg0 url.Values) (*duo.Response, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Call", arg0) + ret0, _ := ret[0].(*duo.Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Call indicates an expected call of Call +func (mr *MockAPIMockRecorder) Call(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Call", reflect.TypeOf((*MockAPI)(nil).Call), arg0) +} diff --git a/mocks/mock_notifier.go b/mocks/mock_notifier.go new file mode 100644 index 000000000..70ee6dfa3 --- /dev/null +++ b/mocks/mock_notifier.go @@ -0,0 +1,48 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/clems4ever/authelia/notification (interfaces: Notifier) + +// Package mock_notification is a generated GoMock package. +package mocks + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" +) + +// MockNotifier is a mock of Notifier interface +type MockNotifier struct { + ctrl *gomock.Controller + recorder *MockNotifierMockRecorder +} + +// MockNotifierMockRecorder is the mock recorder for MockNotifier +type MockNotifierMockRecorder struct { + mock *MockNotifier +} + +// NewMockNotifier creates a new mock instance +func NewMockNotifier(ctrl *gomock.Controller) *MockNotifier { + mock := &MockNotifier{ctrl: ctrl} + mock.recorder = &MockNotifierMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockNotifier) EXPECT() *MockNotifierMockRecorder { + return m.recorder +} + +// Send mocks base method +func (m *MockNotifier) Send(arg0, arg1, arg2 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Send", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// Send indicates an expected call of Send +func (mr *MockNotifierMockRecorder) Send(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Send", reflect.TypeOf((*MockNotifier)(nil).Send), arg0, arg1, arg2) +} diff --git a/mocks/mock_storage_provider.go b/mocks/mock_storage_provider.go new file mode 100644 index 000000000..3c923630f --- /dev/null +++ b/mocks/mock_storage_provider.go @@ -0,0 +1,195 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: storage/provider.go + +// Package mocks is a generated GoMock package. +package mocks + +import ( + reflect "reflect" + time "time" + + models "github.com/clems4ever/authelia/models" + gomock "github.com/golang/mock/gomock" +) + +// MockStorageProvider is a mock of Provider interface +type MockStorageProvider struct { + ctrl *gomock.Controller + recorder *MockStorageProviderMockRecorder +} + +// MockStorageProviderMockRecorder is the mock recorder for MockStorageProvider +type MockStorageProviderMockRecorder struct { + mock *MockStorageProvider +} + +// NewMockStorageProvider creates a new mock instance +func NewMockStorageProvider(ctrl *gomock.Controller) *MockStorageProvider { + mock := &MockStorageProvider{ctrl: ctrl} + mock.recorder = &MockStorageProviderMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockStorageProvider) EXPECT() *MockStorageProviderMockRecorder { + return m.recorder +} + +// LoadPrefered2FAMethod mocks base method +func (m *MockStorageProvider) LoadPrefered2FAMethod(username string) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LoadPrefered2FAMethod", username) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// LoadPrefered2FAMethod indicates an expected call of LoadPrefered2FAMethod +func (mr *MockStorageProviderMockRecorder) LoadPrefered2FAMethod(username interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadPrefered2FAMethod", reflect.TypeOf((*MockStorageProvider)(nil).LoadPrefered2FAMethod), username) +} + +// SavePrefered2FAMethod mocks base method +func (m *MockStorageProvider) SavePrefered2FAMethod(username, method string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SavePrefered2FAMethod", username, method) + ret0, _ := ret[0].(error) + return ret0 +} + +// SavePrefered2FAMethod indicates an expected call of SavePrefered2FAMethod +func (mr *MockStorageProviderMockRecorder) SavePrefered2FAMethod(username, method interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SavePrefered2FAMethod", reflect.TypeOf((*MockStorageProvider)(nil).SavePrefered2FAMethod), username, method) +} + +// FindIdentityVerificationToken mocks base method +func (m *MockStorageProvider) FindIdentityVerificationToken(token string) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FindIdentityVerificationToken", token) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FindIdentityVerificationToken indicates an expected call of FindIdentityVerificationToken +func (mr *MockStorageProviderMockRecorder) FindIdentityVerificationToken(token interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindIdentityVerificationToken", reflect.TypeOf((*MockStorageProvider)(nil).FindIdentityVerificationToken), token) +} + +// SaveIdentityVerificationToken mocks base method +func (m *MockStorageProvider) SaveIdentityVerificationToken(token string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SaveIdentityVerificationToken", token) + ret0, _ := ret[0].(error) + return ret0 +} + +// SaveIdentityVerificationToken indicates an expected call of SaveIdentityVerificationToken +func (mr *MockStorageProviderMockRecorder) SaveIdentityVerificationToken(token interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveIdentityVerificationToken", reflect.TypeOf((*MockStorageProvider)(nil).SaveIdentityVerificationToken), token) +} + +// RemoveIdentityVerificationToken mocks base method +func (m *MockStorageProvider) RemoveIdentityVerificationToken(token string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RemoveIdentityVerificationToken", token) + ret0, _ := ret[0].(error) + return ret0 +} + +// RemoveIdentityVerificationToken indicates an expected call of RemoveIdentityVerificationToken +func (mr *MockStorageProviderMockRecorder) RemoveIdentityVerificationToken(token interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveIdentityVerificationToken", reflect.TypeOf((*MockStorageProvider)(nil).RemoveIdentityVerificationToken), token) +} + +// SaveTOTPSecret mocks base method +func (m *MockStorageProvider) SaveTOTPSecret(username, secret string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SaveTOTPSecret", username, secret) + ret0, _ := ret[0].(error) + return ret0 +} + +// SaveTOTPSecret indicates an expected call of SaveTOTPSecret +func (mr *MockStorageProviderMockRecorder) SaveTOTPSecret(username, secret interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveTOTPSecret", reflect.TypeOf((*MockStorageProvider)(nil).SaveTOTPSecret), username, secret) +} + +// LoadTOTPSecret mocks base method +func (m *MockStorageProvider) LoadTOTPSecret(username string) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LoadTOTPSecret", username) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// LoadTOTPSecret indicates an expected call of LoadTOTPSecret +func (mr *MockStorageProviderMockRecorder) LoadTOTPSecret(username interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadTOTPSecret", reflect.TypeOf((*MockStorageProvider)(nil).LoadTOTPSecret), username) +} + +// SaveU2FDeviceHandle mocks base method +func (m *MockStorageProvider) SaveU2FDeviceHandle(username string, device []byte) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SaveU2FDeviceHandle", username, device) + ret0, _ := ret[0].(error) + return ret0 +} + +// SaveU2FDeviceHandle indicates an expected call of SaveU2FDeviceHandle +func (mr *MockStorageProviderMockRecorder) SaveU2FDeviceHandle(username, device interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveU2FDeviceHandle", reflect.TypeOf((*MockStorageProvider)(nil).SaveU2FDeviceHandle), username, device) +} + +// LoadU2FDeviceHandle mocks base method +func (m *MockStorageProvider) LoadU2FDeviceHandle(username string) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LoadU2FDeviceHandle", username) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// LoadU2FDeviceHandle indicates an expected call of LoadU2FDeviceHandle +func (mr *MockStorageProviderMockRecorder) LoadU2FDeviceHandle(username interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadU2FDeviceHandle", reflect.TypeOf((*MockStorageProvider)(nil).LoadU2FDeviceHandle), username) +} + +// AppendAuthenticationLog mocks base method +func (m *MockStorageProvider) AppendAuthenticationLog(attempt models.AuthenticationAttempt) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AppendAuthenticationLog", attempt) + ret0, _ := ret[0].(error) + return ret0 +} + +// AppendAuthenticationLog indicates an expected call of AppendAuthenticationLog +func (mr *MockStorageProviderMockRecorder) AppendAuthenticationLog(attempt interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AppendAuthenticationLog", reflect.TypeOf((*MockStorageProvider)(nil).AppendAuthenticationLog), attempt) +} + +// LoadLatestAuthenticationLogs mocks base method +func (m *MockStorageProvider) LoadLatestAuthenticationLogs(username string, fromDate time.Time) ([]models.AuthenticationAttempt, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LoadLatestAuthenticationLogs", username, fromDate) + ret0, _ := ret[0].([]models.AuthenticationAttempt) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// LoadLatestAuthenticationLogs indicates an expected call of LoadLatestAuthenticationLogs +func (mr *MockStorageProviderMockRecorder) LoadLatestAuthenticationLogs(username, fromDate interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadLatestAuthenticationLogs", reflect.TypeOf((*MockStorageProvider)(nil).LoadLatestAuthenticationLogs), username, fromDate) +} diff --git a/mocks/mock_user_provider.go b/mocks/mock_user_provider.go new file mode 100644 index 000000000..7da1a0b79 --- /dev/null +++ b/mocks/mock_user_provider.go @@ -0,0 +1,79 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/clems4ever/authelia/authentication (interfaces: UserProvider) + +// Package mocks is a generated GoMock package. +package mocks + +import ( + reflect "reflect" + + authentication "github.com/clems4ever/authelia/authentication" + gomock "github.com/golang/mock/gomock" +) + +// MockUserProvider is a mock of UserProvider interface +type MockUserProvider struct { + ctrl *gomock.Controller + recorder *MockUserProviderMockRecorder +} + +// MockUserProviderMockRecorder is the mock recorder for MockUserProvider +type MockUserProviderMockRecorder struct { + mock *MockUserProvider +} + +// NewMockUserProvider creates a new mock instance +func NewMockUserProvider(ctrl *gomock.Controller) *MockUserProvider { + mock := &MockUserProvider{ctrl: ctrl} + mock.recorder = &MockUserProviderMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockUserProvider) EXPECT() *MockUserProviderMockRecorder { + return m.recorder +} + +// CheckUserPassword mocks base method +func (m *MockUserProvider) CheckUserPassword(arg0, arg1 string) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CheckUserPassword", arg0, arg1) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CheckUserPassword indicates an expected call of CheckUserPassword +func (mr *MockUserProviderMockRecorder) CheckUserPassword(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckUserPassword", reflect.TypeOf((*MockUserProvider)(nil).CheckUserPassword), arg0, arg1) +} + +// GetDetails mocks base method +func (m *MockUserProvider) GetDetails(arg0 string) (*authentication.UserDetails, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetDetails", arg0) + ret0, _ := ret[0].(*authentication.UserDetails) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetDetails indicates an expected call of GetDetails +func (mr *MockUserProviderMockRecorder) GetDetails(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDetails", reflect.TypeOf((*MockUserProvider)(nil).GetDetails), arg0) +} + +// UpdatePassword mocks base method +func (m *MockUserProvider) UpdatePassword(arg0, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdatePassword", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdatePassword indicates an expected call of UpdatePassword +func (mr *MockUserProviderMockRecorder) UpdatePassword(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdatePassword", reflect.TypeOf((*MockUserProvider)(nil).UpdatePassword), arg0, arg1) +} diff --git a/models/types.go b/models/types.go new file mode 100644 index 000000000..1dfd07b9c --- /dev/null +++ b/models/types.go @@ -0,0 +1,13 @@ +package models + +import "time" + +// Attempt represent an authentication attempt. +type AuthenticationAttempt struct { + // The user who tried to authenticate. + Username string + // Successful true if the attempt was successful. + Successful bool + // The time of the attempt. + Time time.Time +} diff --git a/notification/file_notifier.go b/notification/file_notifier.go new file mode 100644 index 000000000..c38b03a6b --- /dev/null +++ b/notification/file_notifier.go @@ -0,0 +1,33 @@ +package notification + +import ( + "fmt" + "io/ioutil" + "time" + + "github.com/clems4ever/authelia/configuration/schema" +) + +// FileNotifier a notifier to send emails to SMTP servers. +type FileNotifier struct { + path string +} + +// NewFileNotifier create an FileNotifier writing the notification into a file. +func NewFileNotifier(configuration schema.FileSystemNotifierConfiguration) *FileNotifier { + return &FileNotifier{ + path: configuration.Filename, + } +} + +// Send send a identity verification link to a user. +func (n *FileNotifier) Send(recipient string, subject string, body string) error { + content := fmt.Sprintf("Date: %s\nRecipient: %s\nSubject: %s\nBody: %s", time.Now(), recipient, subject, body) + + err := ioutil.WriteFile(n.path, []byte(content), 0755) + + if err != nil { + return err + } + return nil +} diff --git a/notification/notifier.go b/notification/notifier.go new file mode 100644 index 000000000..967418c88 --- /dev/null +++ b/notification/notifier.go @@ -0,0 +1,6 @@ +package notification + +// Notifier interface for sending the identity verification link. +type Notifier interface { + Send(to string, subject string, link string) error +} diff --git a/notification/smtp_notifier.go b/notification/smtp_notifier.go new file mode 100644 index 000000000..3b893052d --- /dev/null +++ b/notification/smtp_notifier.go @@ -0,0 +1,90 @@ +package notification + +import ( + "fmt" + "net/smtp" + + "github.com/clems4ever/authelia/configuration/schema" +) + +// SMTPNotifier a notifier to send emails to SMTP servers. +type SMTPNotifier struct { + address string + sender string + username string + password string + host string + port int +} + +// NewSMTPNotifier create an SMTPNotifier targeting a given address. +func NewSMTPNotifier(configuration schema.SMTPNotifierConfiguration) *SMTPNotifier { + return &SMTPNotifier{ + host: configuration.Host, + port: configuration.Port, + address: fmt.Sprintf("%s:%d", configuration.Host, configuration.Port), + sender: configuration.Sender, + username: configuration.Username, + password: configuration.Password, + } +} + +func (n *SMTPNotifier) authenticatedSend(recipient string, msg string) error { + auth := smtp.PlainAuth("", n.username, n.password, n.host) + err := smtp.SendMail(fmt.Sprintf("%s:%d", n.host, n.port), auth, n.sender, + []string{recipient}, []byte(msg)) + if err != nil { + return err + } + return nil +} + +func (n *SMTPNotifier) unauthenticatedSend(recipient string, msg string) error { + // Connect to the remote SMTP server. + c, err := smtp.Dial(n.address) + + // Set the sender and recipient first + if err := c.Mail(n.sender); err != nil { + return err + } + + if err := c.Rcpt(recipient); err != nil { + return err + } + + // Send the email body. + wc, err := c.Data() + if err != nil { + return err + } + _, err = fmt.Fprintf(wc, msg) + if err != nil { + return err + } + err = wc.Close() + if err != nil { + return err + } + + // Send the QUIT command and close the connection. + err = c.Quit() + if err != nil { + return err + } + return nil +} + +// Send send a identity verification link to a user. +func (n *SMTPNotifier) Send(recipient string, subject string, body string) error { + msg := "From: " + n.sender + "\n" + + "To: " + recipient + "\n" + + "Subject: " + subject + "\n" + + "Content-Type: text/html\n" + + "MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n\n" + + body + + if n.password != "" { + return n.authenticatedSend(recipient, msg) + } + return n.unauthenticatedSend(recipient, msg) +} diff --git a/package-lock.json b/package-lock.json index 7789264b8..721e302d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,48 +13,6 @@ "@babel/highlight": "7.0.0" } }, - "@babel/generator": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.4.0.tgz", - "integrity": "sha512-/v5I+a1jhGSKLgZDcmAUZ4K/VePi43eRkUs3yePW1HB1iANOD5tqJXwGSG4BZhSksP8J9ejSlwGeTiiOFZOrXQ==", - "dev": true, - "requires": { - "@babel/types": "7.4.0", - "jsesc": "2.5.2", - "lodash": "4.17.15", - "source-map": "0.5.7", - "trim-right": "1.0.1" - } - }, - "@babel/helper-function-name": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", - "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "7.0.0", - "@babel/template": "7.4.0", - "@babel/types": "7.4.0" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", - "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", - "dev": true, - "requires": { - "@babel/types": "7.4.0" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.0.tgz", - "integrity": "sha512-7Cuc6JZiYShaZnybDmfwhY4UYHzI6rlqhWjaIqbsJGsIqPimEYy5uh3akSRLMg65LSdSEnJ8a8/bWQN6u2oMGw==", - "dev": true, - "requires": { - "@babel/types": "7.4.0" - } - }, "@babel/highlight": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", @@ -64,125 +22,12 @@ "chalk": "2.4.2", "esutils": "2.0.2", "js-tokens": "4.0.0" - }, - "dependencies": { - "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.1" - } - }, - "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.5.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "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 - }, - "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" - } - } - } - }, - "@babel/parser": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.3.tgz", - "integrity": "sha512-gxpEUhTS1sGA63EGQGuA+WESPR/6tz6ng7tSHFCmaTJK/cGK8y37cBTspX+U2xCAue2IQVvF6Z0oigmjwD8YGQ==", - "dev": true - }, - "@babel/template": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.0.tgz", - "integrity": "sha512-SOWwxxClTTh5NdbbYZ0BmaBVzxzTh2tO/TeLTbF6MO6EzVhHTnff8CdBXx3mEtazFBoysmEM6GU/wF+SuSx4Fw==", - "dev": true, - "requires": { - "@babel/code-frame": "7.0.0", - "@babel/parser": "7.4.3", - "@babel/types": "7.4.0" - } - }, - "@babel/traverse": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.3.tgz", - "integrity": "sha512-HmA01qrtaCwwJWpSKpA948cBvU5BrmviAief/b3AVw936DtcdsTexlbyzNuDnthwhOQ37xshn7hvQaEQk7ISYQ==", - "dev": true, - "requires": { - "@babel/code-frame": "7.0.0", - "@babel/generator": "7.4.0", - "@babel/helper-function-name": "7.1.0", - "@babel/helper-split-export-declaration": "7.4.0", - "@babel/parser": "7.4.3", - "@babel/types": "7.4.0", - "debug": "4.1.1", - "globals": "11.11.0", - "lodash": "4.17.15" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true - } - } - }, - "@babel/types": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.4.0.tgz", - "integrity": "sha512-aPvkXyU2SPOnztlgo8n9cEiXW755mgyvueUPcpStqdzoSPm0fjO0vQBjLkt3JKJW7ufikfcnMTTPsN1xaTsBPA==", - "dev": true, - "requires": { - "esutils": "2.0.2", - "lodash": "4.17.15", - "to-fast-properties": "2.0.0" - } - }, - "@duosecurity/duo_api": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@duosecurity/duo_api/-/duo_api-1.2.0.tgz", - "integrity": "sha512-Jxmeo5VZtaut9hELnBNZyvA7kojwRBAHl0uOk0dZSfBbphjr3QJ+92dnm/I++GPUEhEKjALLeQ9fCABwo5HsPQ==", - "requires": { - "nopt": "3.0.6" } }, "@sinonjs/commons": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.3.0.tgz", - "integrity": "sha512-j4ZwhaHmwsCb4DlDOIWnI5YyKDNMoNThsmwEpfHx6a1EpsGZ9qYLxP++LMlmBRjtGptGHFsGItJ768snllFWpA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.4.0.tgz", + "integrity": "sha512-9jHK3YF/8HtJ9wCAbG+j8cD0i0+ATS9A7gXFqS36TblLPNy6rEEc+SB0imo91eCboGaBYGV/MT1/br/J+EE7Tw==", "dev": true, "requires": { "type-detect": "4.0.8" @@ -198,45 +43,32 @@ } }, "@sinonjs/samsam": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.1.1.tgz", - "integrity": "sha512-ILlwvQUwAiaVBzr3qz8oT1moM7AIUHqUc2UmEjQcH9lLe+E+BZPwUMuc9FFojMswRK4r96x5zDTTrowMLw/vuA==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.2.tgz", + "integrity": "sha512-ILO/rR8LfAb60Y1Yfp9vxfYAASK43NFC2mLzpvLUbCQY/Qu8YwReboseu8aheCEkyElZF2L2T9mHcR2bgdvZyA==", "dev": true, "requires": { - "@sinonjs/commons": "1.3.0", + "@sinonjs/commons": "1.4.0", "array-from": "2.1.1", "lodash": "4.17.15" } }, - "@types/bluebird": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.20.tgz", - "integrity": "sha512-Wk41MVdF+cHBfVXj/ufUHJeO3BlIQr1McbHZANErMykaCWeDSZbH5erGjNBw2/3UlRdSxZbLfSuQTzFmPOYFsA==", + "@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", "dev": true }, - "@types/body-parser": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.17.0.tgz", - "integrity": "sha512-a2+YeUjPkztKJu5aIF2yArYFQQp8d51wZ7DavSHjFuY1mqVgidGyzEQ41JIVNy82fXj8yPgy2vJmfIywgESW6w==", - "dev": true, - "requires": { - "@types/connect": "3.4.32", - "@types/node": "10.0.3" - } - }, - "@types/bson": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/bson/-/bson-1.0.8.tgz", - "integrity": "sha512-PMa4nkRhLaqwsXQDDTzGbTyCIpej0ERznyAP9fyuGnlsmUbcC4Y25mdqjibYjkOPNyK/BWWUKneruaKHcS3Q8g==", - "dev": true, - "requires": { - "@types/node": "10.0.3" - } + "@types/bluebird": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.27.tgz", + "integrity": "sha512-6BmYWSBea18+tSjjSC3QIyV93ZKAeNWGM7R6aYt1ryTZXrlHF+QLV0G2yV0viEGVyRkyQsWfMoJ0k/YghBX5sQ==", + "dev": true }, "@types/caseless": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.1.tgz", - "integrity": "sha512-FhlMa34NHp9K5MY1Uz8yb+ZvuX0pnvn3jScRSNAb75KHGB8d3rEU6hqMs3Z2vjuytcMfRg6c5CHMc3wtYyD2/A==", + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", + "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==", "dev": true }, "@types/chokidar": { @@ -245,8 +77,8 @@ "integrity": "sha512-PDkSRY7KltW3M60hSBlerxI8SFPXsO3AL/aRVsO4Kh9IHRW74Ih75gUuTd/aE4LSSFqypb10UIX3QzOJwBQMGQ==", "dev": true, "requires": { - "@types/events": "1.2.0", - "@types/node": "10.0.3" + "@types/events": "3.0.0", + "@types/node": "12.0.10" } }, "@types/commander": { @@ -255,111 +87,45 @@ "integrity": "sha512-0QEFiR8ljcHp9bAbWxecjVRuAMr16ivPiGOw6KFQBVrVd0RQIcM3xKdRisH2EDWgVWujiYtHwhSkSUoAAGzH7Q==", "dev": true, "requires": { - "commander": "2.19.0" + "commander": "2.20.0" } }, - "@types/connect": { - "version": "3.4.32", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.32.tgz", - "integrity": "sha512-4r8qa0quOvh7lGD0pre62CAb1oni1OO6ecJLGCezTmhQ8Fz50Arx9RUszryR8KlgK6avuSXvviL6yWyViQABOg==", - "dev": true, - "requires": { - "@types/node": "10.0.3" - } - }, - "@types/connect-redis": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/@types/connect-redis/-/connect-redis-0.0.9.tgz", - "integrity": "sha512-LdAbC9EnQkHLMgeV0EKufPbqaRKfsAxgdWaYnDtQOKuJV2U4JpFE2EU4yKJ3G2FjVvNXyzO6rcaBBjPBztGTzg==", - "dev": true, - "requires": { - "@types/express": "4.11.1", - "@types/express-session": "1.15.8", - "@types/redis": "2.8.11" - } - }, - "@types/ejs": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-2.5.1.tgz", - "integrity": "sha512-TcBUX5YwtvXIWyp+B9vqpkIDUiEVA1+ha48FNUMthAWE4bjloQNQfHvBY0t4i/OJ14JG91YUNGJn+gNwNdTE8Q==", - "dev": true - }, "@types/events": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz", - "integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", + "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", "dev": true }, - "@types/express": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.11.1.tgz", - "integrity": "sha512-ttWle8cnPA5rAelauSWeWJimtY2RsUf2aspYZs7xPHiWgOlPn6nnUfBMtrkcnjFJuIHJF4gNOdVvpLK2Zmvh6g==", - "dev": true, - "requires": { - "@types/body-parser": "1.17.0", - "@types/express-serve-static-core": "4.11.1", - "@types/serve-static": "1.13.2" - } - }, - "@types/express-serve-static-core": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.11.1.tgz", - "integrity": "sha512-EehCl3tpuqiM8RUb+0255M8PhhSwTtLfmO7zBBdv0ay/VTd/zmrqDfQdZFsa5z/PVMbH2yCMZPXsnrImpATyIw==", - "dev": true, - "requires": { - "@types/events": "1.2.0", - "@types/node": "10.0.3" - } - }, - "@types/express-session": { - "version": "1.15.8", - "resolved": "https://registry.npmjs.org/@types/express-session/-/express-session-1.15.8.tgz", - "integrity": "sha512-Be5N9zul4C/IH1UjRDaVJ46wkG1jsBgJlihBdWlqJWfCaiqvaVmxcyqcLey7omSFGCTIUDgdHqf0vwNjEZOSVA==", - "dev": true, - "requires": { - "@types/events": "1.2.0", - "@types/express": "4.11.1", - "@types/node": "10.0.3" - } - }, "@types/form-data": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-2.2.1.tgz", "integrity": "sha512-JAMFhOaHIciYVh8fb5/83nmuO/AHwmto+Hq7a9y8FzLDcC1KCU344XDOMEmahnrTFlHjgh4L0WJFczNIX2GxnQ==", "dev": true, "requires": { - "@types/node": "10.0.3" + "@types/node": "12.0.10" } }, - "@types/helmet": { - "version": "0.0.37", - "resolved": "https://registry.npmjs.org/@types/helmet/-/helmet-0.0.37.tgz", - "integrity": "sha512-E45vdnx+7+HIN5jsywhzfd+hUI/2yBFr6RT7tsMVrwp+uTvyVANBf4dyVUNW/+ZqAvcx23t2YtGTndQJR3tXIA==", + "@types/glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", + "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", "dev": true, "requires": { - "@types/express": "4.11.1" + "@types/events": "3.0.0", + "@types/minimatch": "3.0.3", + "@types/node": "12.0.10" } }, - "@types/ldapjs": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@types/ldapjs/-/ldapjs-1.0.3.tgz", - "integrity": "sha512-FSj24s1WsFEfOy8taIKp2DokSZfFkjWYZb88AS5eDj3WTocZ+4DnHjhzrXEs048WQ5mfOLJXMOAnc0kSnHh5Lw==", - "dev": true, - "requires": { - "@types/events": "1.2.0", - "@types/node": "10.0.3" - } - }, - "@types/mime": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.0.tgz", - "integrity": "sha512-A2TAGbTFdBw9azHbpVd+/FkdW2T6msN1uct1O9bH3vTerEHKZhTXJUQXy+hNq1B0RagfU8U+KBdqiZpxjhOUQA==", + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", "dev": true }, "@types/mocha": { - "version": "5.2.6", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.6.tgz", - "integrity": "sha512-1axi39YdtBI7z957vdqXI4Ac25e7YihYQtJa+Clnxg1zTJEaIRbndt71O3sP4GAMgiAm0pY26/b9BrY4MR/PMw==", + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", + "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==", "dev": true }, "@types/mockdate": { @@ -368,198 +134,78 @@ "integrity": "sha1-qvOIoerTsPXtbcFhGVbqe0ClfTw=", "dev": true }, - "@types/mongodb": { - "version": "3.0.17", - "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.0.17.tgz", - "integrity": "sha512-G2cE4c+6+zvbWos+VbEiOdlr6sqbyrvuRmUHGAQGSkLvs+P/omIBV8FvfFTnAQW8/Op1kqXJUnK8mXSm3Dnnjg==", - "dev": true, - "requires": { - "@types/bson": "1.0.8", - "@types/events": "1.2.0", - "@types/node": "10.0.3" - } - }, - "@types/nedb": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@types/nedb/-/nedb-1.8.5.tgz", - "integrity": "sha512-4x3IymcP2xjrDKwH/Q78h4tFdXthXOxc9LuUQJ3dCjD5U0VVauYUoH/Olmz8QqHqECiyEDxgfcVL8oaDqlD/Pw==", - "dev": true - }, "@types/node": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.0.3.tgz", - "integrity": "sha512-J7nx6JzxmtT4zyvfLipYL7jNaxvlCWpyG7JhhCQ4fQyG+AGfovAHoYR55TFx+X8akfkUJYpt5JG6GPeFMjZaCQ==", + "version": "12.0.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.10.tgz", + "integrity": "sha512-LcsGbPomWsad6wmMNv7nBLw7YYYyfdYcz6xryKYQhx89c3XXan+8Q6AJ43G5XDIaklaVkK3mE4fCb0SBvMiPSQ==", "dev": true }, "@types/node-fetch": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.1.4.tgz", - "integrity": "sha512-tR1ekaXUGpmzOcDXWU9BW73YfA2/VW1DF1FH+wlJ82BbCSnWTbdX+JkqWQXWKIGsFPnPsYadbXfNgz28g+ccWg==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.3.7.tgz", + "integrity": "sha512-+bKtuxhj/TYSSP1r4CZhfmyA0vm/aDRQNo7vbAgf6/cZajn0SAniGGST07yvI4Q+q169WTa2/x9gEHfJrkcALw==", "dev": true, "requires": { - "@types/node": "10.0.3" + "@types/node": "12.0.10" } }, - "@types/nodemailer": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-4.6.0.tgz", - "integrity": "sha512-DWG172izmWXfShUm2Lm6nVght5TxDI1cx2cKiGPeu2f66yTnn0QY7WhC9OSybdPoxGu7UbRXNuIkIzB+NE648A==", - "dev": true, - "requires": { - "@types/events": "1.2.0", - "@types/node": "10.0.3" - } - }, - "@types/nodemailer-direct-transport": { - "version": "1.0.31", - "resolved": "https://registry.npmjs.org/@types/nodemailer-direct-transport/-/nodemailer-direct-transport-1.0.31.tgz", - "integrity": "sha512-LDFL7X58v4som2QnodajLgltFpCbF4JAqlg/Iy4SNbrnfBraJVU/ySh7gvd22Wc6V6CSpuG3SjZolJfNf7Z3bA==", - "dev": true, - "requires": { - "@types/nodemailer": "3.1.5" - }, - "dependencies": { - "@types/nodemailer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-3.1.5.tgz", - "integrity": "sha512-d8GSTD/5kEf7fsghVEyU9vqRVGu+Hpmf/z+x+7+vXGvbK7kQoorulvuOX4ozPmGsJCq7oBIdHw5gFIRDvSvdag==", - "dev": true, - "requires": { - "@types/node": "10.0.3", - "@types/nodemailer-direct-transport": "1.0.31", - "@types/nodemailer-ses-transport": "3.1.4", - "@types/nodemailer-smtp-transport": "2.7.4", - "aws-sdk": "2.230.1" - } - } - } - }, - "@types/nodemailer-ses-transport": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@types/nodemailer-ses-transport/-/nodemailer-ses-transport-3.1.4.tgz", - "integrity": "sha512-gWoykP57qYQ60YDD0vFPGDYN/Waq+aKI4k2UBrf5nc87+wlg71eAbb4HwDdZeANLR/wdWkAWdUjz1XgGcpUZNA==", - "dev": true, - "requires": { - "@types/nodemailer": "3.1.5", - "aws-sdk": "2.230.1" - }, - "dependencies": { - "@types/nodemailer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-3.1.5.tgz", - "integrity": "sha512-d8GSTD/5kEf7fsghVEyU9vqRVGu+Hpmf/z+x+7+vXGvbK7kQoorulvuOX4ozPmGsJCq7oBIdHw5gFIRDvSvdag==", - "dev": true, - "requires": { - "@types/node": "10.0.3", - "@types/nodemailer-direct-transport": "1.0.31", - "@types/nodemailer-ses-transport": "3.1.4", - "@types/nodemailer-smtp-transport": "2.7.4", - "aws-sdk": "2.230.1" - } - } - } - }, - "@types/nodemailer-smtp-transport": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/@types/nodemailer-smtp-transport/-/nodemailer-smtp-transport-2.7.4.tgz", - "integrity": "sha512-AXsNWM1gKm3ieD+Ff7FK4mmpkPnpOGVzLSM67T0l8cQGz0G7mFbcq48FhxfbrOtm92gG00k9Cv81+flXhDBuxg==", - "dev": true, - "requires": { - "@types/node": "10.0.3", - "@types/nodemailer": "3.1.5" - }, - "dependencies": { - "@types/nodemailer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-3.1.5.tgz", - "integrity": "sha512-d8GSTD/5kEf7fsghVEyU9vqRVGu+Hpmf/z+x+7+vXGvbK7kQoorulvuOX4ozPmGsJCq7oBIdHw5gFIRDvSvdag==", - "dev": true, - "requires": { - "@types/node": "10.0.3", - "@types/nodemailer-direct-transport": "1.0.31", - "@types/nodemailer-ses-transport": "3.1.4", - "@types/nodemailer-smtp-transport": "2.7.4", - "aws-sdk": "2.230.1" - } - } - } - }, - "@types/object-path": { - "version": "0.9.29", - "resolved": "https://registry.npmjs.org/@types/object-path/-/object-path-0.9.29.tgz", - "integrity": "sha512-txsii9cwD2OUOPukfPu3Jpoi3CnznBAwRX3JF26EC4p5T6IA8AaL6PBilACyY2fJkk+ydDNo4BJrJOo/OmNaZw==", - "dev": true - }, "@types/query-string": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/@types/query-string/-/query-string-5.1.0.tgz", "integrity": "sha512-9/sJK+T04pNq7uwReR0CLxqXj1dhxiTapZ1tIxA0trEsT6FRS0bz09YMcMb7tsVBTm4RJ0NEBYGsAjoEmqoFXg==", "dev": true }, - "@types/randomstring": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@types/randomstring/-/randomstring-1.1.6.tgz", - "integrity": "sha512-XRIZIMTxjcUukqQcYBdpFWGbcRDyNBXrvTEtTYgFMIbBNUVt+9mCKsU+jUUDLeFO/RXopUgR5OLiBqbY18vSHQ==", - "dev": true - }, "@types/redis": { - "version": "2.8.11", - "resolved": "https://registry.npmjs.org/@types/redis/-/redis-2.8.11.tgz", - "integrity": "sha512-i0AqDzjX0FlO+npqkhl1etZw1fGnJc0IeHUHKAf/V7Drk+rDJI634GE9Lwh8aj/2ahuW6jHdWX4ZnyNofWXKrw==", + "version": "2.8.14", + "resolved": "https://registry.npmjs.org/@types/redis/-/redis-2.8.14.tgz", + "integrity": "sha512-255dzsOLJdXFHBio9/aMHGozNkoiBUgc+g2nlNjbTSp5qcAlmpm4Z6Xs3pKOBLNIKdZbA2BkUxWvYSIwKra0Yw==", "dev": true, "requires": { - "@types/node": "10.0.3" + "@types/node": "12.0.10" } }, "@types/request": { - "version": "2.47.0", - "resolved": "https://registry.npmjs.org/@types/request/-/request-2.47.0.tgz", - "integrity": "sha512-/KXM5oev+nNCLIgBjkwbk8VqxmzI56woD4VUxn95O+YeQ8hJzcSmIZ1IN3WexiqBb6srzDo2bdMbsXxgXNkz5Q==", + "version": "2.48.1", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.1.tgz", + "integrity": "sha512-ZgEZ1TiD+KGA9LiAAPPJL68Id2UWfeSO62ijSXZjFJArVV+2pKcsVHmrcu+1oiE3q6eDGiFiSolRc4JHoerBBg==", "dev": true, "requires": { - "@types/caseless": "0.12.1", + "@types/caseless": "0.12.2", "@types/form-data": "2.2.1", - "@types/node": "10.0.3", - "@types/tough-cookie": "2.3.2" + "@types/node": "12.0.10", + "@types/tough-cookie": "2.3.5" } }, "@types/request-promise": { - "version": "4.1.41", - "resolved": "https://registry.npmjs.org/@types/request-promise/-/request-promise-4.1.41.tgz", - "integrity": "sha512-qlx6COxSTdSFHY9oX9v2zL1I05hgz5lwqYiXa2SFL2nDxAiG5KK8rnllLBH7k6OqzS3Ck0bWbxlGVdrZhS6oNw==", + "version": "4.1.44", + "resolved": "https://registry.npmjs.org/@types/request-promise/-/request-promise-4.1.44.tgz", + "integrity": "sha512-RId7eFsUKxfal1LirDDIcOp9u3MM3NXFDBcC3sqIMcmu7f4U6DsCEMD8RbLZtnPrQlN5Jc79di/WPsIEDO4keg==", "dev": true, "requires": { - "@types/bluebird": "3.5.20", - "@types/request": "2.47.0" + "@types/bluebird": "3.5.27", + "@types/request": "2.48.1" } }, "@types/selenium-webdriver": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.8.tgz", - "integrity": "sha512-yrqQvb1EZhH+ONMzUmsEnBjzitortVv0lynRe5US2+FofdoMWUE4wf7v4peCd62fqXq8COCVTbpS1/jIg5EbuQ==", + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.16.tgz", + "integrity": "sha512-lMC2G0ItF2xv4UCiwbJGbnJlIuUixHrioOhNGHSCsYCJ8l4t9hMCUimCytvFv7qy6AfSzRxhRHoGa+UqaqwyeA==", "dev": true }, - "@types/serve-static": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.2.tgz", - "integrity": "sha512-/BZ4QRLpH/bNYgZgwhKEh+5AsboDBcUdlBYgzoLX0fpj3Y2gp6EApyOlM3bK53wQS/OE1SrdSYBAbux2D1528Q==", - "dev": true, - "requires": { - "@types/express-serve-static-core": "4.11.1", - "@types/mime": "2.0.0" - } - }, "@types/sinon": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-4.3.1.tgz", - "integrity": "sha512-DK4YtH30I67k4klURIBS4VAe1aBISfS9lgNlHFkibSmKem2tLQc5VkKoJreT3dCJAd+xRyCS8bx1o97iq3yUVg==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-4.3.3.tgz", + "integrity": "sha512-Tt7w/ylBS/OEAlSCwzB0Db1KbxnkycP/1UkQpbvKFYoUuRn4uYsC3xh5TRPrOjTy0i8TIkSz1JdNL4GPVdf3KQ==", "dev": true }, "@types/speakeasy": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@types/speakeasy/-/speakeasy-2.0.2.tgz", - "integrity": "sha512-h8KW3wSd3/l4oKRGYPxExCaos5VmjcnwDG3RK25tfcoWQR9iLmM9UbwvF1Pd+UT5aY1Z3LdQGt4xU0u9Zk/C2Q==", - "dev": true + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/speakeasy/-/speakeasy-2.0.4.tgz", + "integrity": "sha512-WcZalHN3tlh+StC8cszTuh2SkX+vn5s4K+eMwa2fXM4t3GDeYg6JVrpchHs9InqTkgXXsEtE8KNXaQxfkIdmng==", + "dev": true, + "requires": { + "@types/node": "12.0.10" + } }, "@types/tmp": { "version": "0.0.33", @@ -568,55 +214,27 @@ "dev": true }, "@types/tough-cookie": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.2.tgz", - "integrity": "sha512-vOVmaruQG5EatOU/jM6yU2uCp3Lz6mK1P5Ztu4iJjfM4SVHU9XYktPUQtKlIXuahqXHdEyUarMrBEwg5Cwu+bA==", - "dev": true - }, - "@types/url-parse": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@types/url-parse/-/url-parse-1.4.2.tgz", - "integrity": "sha512-Z25Ef2iI0lkiBAoe8qATRHQWy+BWFWuWasD6HB5prsWx2QjLmB/ngXv8v9dePw2jDwdSvET4/6J5HxmeqhslmQ==", - "dev": true - }, - "@types/winston": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/@types/winston/-/winston-2.3.9.tgz", - "integrity": "sha512-zzruYOEtNgfS3SBjcij1F6HlH6My5n8WrBNhP3fzaRM22ba70QBC2ATs18jGr88Fy43c0z8vFJv5wJankfxv2A==", - "dev": true, - "requires": { - "@types/node": "10.0.3" - } - }, - "@types/yamljs": { - "version": "0.2.30", - "resolved": "https://registry.npmjs.org/@types/yamljs/-/yamljs-0.2.30.tgz", - "integrity": "sha1-0DTh0ynkbo0Pc3yajbl/aPgbU4I=", + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.5.tgz", + "integrity": "sha512-SCcK7mvGi3+ZNz833RRjFIxrn4gI1PPR3NtuIS+6vMkvmsGjosqTJwRt5bAEFLRz+wtJMWv8+uOnZf2hi2QXTg==", "dev": true }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, - "accepts": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", - "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", - "requires": { - "mime-types": "2.1.18", - "negotiator": "0.6.1" - } + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true }, "ajv": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.4.0.tgz", - "integrity": "sha1-06/3jpJ3VJdx2vAWTP9ISCt1T8Y=", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", + "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", + "dev": true, "requires": { - "fast-deep-equal": "1.1.0", + "fast-deep-equal": "2.0.1", "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1", - "uri-js": "3.0.2" + "json-schema-traverse": "0.4.1", + "uri-js": "4.2.2" } }, "amdefine": { @@ -642,16 +260,19 @@ "dev": true }, "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, "ansi-styles": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", - "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=", - "dev": true + "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.3" + } }, "anymatch": { "version": "2.0.0", @@ -661,99 +282,24 @@ "requires": { "micromatch": "3.1.10", "normalize-path": "2.1.1" - } - }, - "apidoc": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/apidoc/-/apidoc-0.17.6.tgz", - "integrity": "sha1-TuisYQ3t3csQBsPij6fdY0tKXOY=", - "dev": true, - "requires": { - "apidoc-core": "0.8.3", - "fs-extra": "3.0.1", - "lodash": "4.17.15", - "markdown-it": "8.4.1", - "nomnom": "1.8.1", - "winston": "2.3.1" }, "dependencies": { - "async": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", - "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=", - "dev": true - }, - "winston": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/winston/-/winston-2.3.1.tgz", - "integrity": "sha1-C0hCDZeMAYBM8CMLZIhhWYIloRk=", + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", "dev": true, "requires": { - "async": "1.0.0", - "colors": "1.0.3", - "cycle": "1.0.3", - "eyes": "0.1.8", - "isstream": "0.1.2", - "stack-trace": "0.0.10" + "remove-trailing-separator": "1.1.0" } } } }, - "apidoc-core": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/apidoc-core/-/apidoc-core-0.8.3.tgz", - "integrity": "sha1-2dY1RYKd8lDSzKBJaDqH53U2S5Y=", - "dev": true, - "requires": { - "fs-extra": "3.0.1", - "glob": "7.1.2", - "iconv-lite": "0.4.19", - "klaw-sync": "2.1.0", - "lodash": "4.17.15", - "semver": "5.3.0" - }, - "dependencies": { - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "semver": { - "version": "5.3.0", - "resolved": "http://registry.npmjs.org/semver/-/semver-5.3.0.tgz", - "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", - "dev": true - } - } - }, - "append-transform": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", - "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", - "dev": true, - "requires": { - "default-require-extensions": "2.0.0" - } - }, - "archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", - "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.3" } @@ -776,11 +322,6 @@ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", "dev": true }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, "array-from": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", @@ -793,13 +334,14 @@ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "dev": true, "requires": { - "array-uniq": "1.0.2" + "array-uniq": "1.0.3" } }, "array-uniq": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.2.tgz", - "integrity": "sha1-X8w3OSB3VyPP1k1lxkvvU7+eum0=" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true }, "array-unique": { "version": "0.3.2", @@ -814,14 +356,19 @@ "dev": true }, "asn1": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "2.1.2" + } }, "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true }, "assign-symbols": { "version": "1.0.0", @@ -830,14 +377,15 @@ "dev": true }, "async": { - "version": "0.2.10", - "resolved": "http://registry.npmjs.org/async/-/async-0.2.10.tgz", - "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=" + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true }, "async-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", - "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", "dev": true }, "asynckit": { @@ -852,32 +400,6 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, - "aws-sdk": { - "version": "2.230.1", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.230.1.tgz", - "integrity": "sha1-SUzvau0uFtse2cEqz0vSpzF/U2U=", - "dev": true, - "requires": { - "buffer": "4.9.1", - "events": "1.1.1", - "ieee754": "1.1.8", - "jmespath": "0.15.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "uuid": "3.1.0", - "xml2js": "0.4.17", - "xmlbuilder": "4.2.1" - }, - "dependencies": { - "uuid": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", - "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", - "dev": true - } - } - }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -890,59 +412,11 @@ "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", "dev": true }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - } - } - }, - "backoff": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/backoff/-/backoff-2.5.0.tgz", - "integrity": "sha1-9hbtqdPktmuMp/ynn2lXIsX44m8=", - "requires": { - "precond": "0.2.3" - } - }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true }, "base": { "version": "0.11.2", @@ -952,7 +426,7 @@ "requires": { "cache-base": "1.0.1", "class-utils": "0.3.6", - "component-emitter": "1.2.1", + "component-emitter": "1.3.0", "define-property": "1.0.0", "isobject": "3.0.1", "mixin-deep": "1.3.2", @@ -996,30 +470,13 @@ "is-data-descriptor": "1.0.0", "kind-of": "6.0.2" } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true } } }, "base32.js": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/base32.js/-/base32.js-0.0.1.tgz", - "integrity": "sha1-0EVzalex9sE58MffQlGKhOkbsro=" - }, - "base64-js": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", + "integrity": "sha1-0EVzalex9sE58MffQlGKhOkbsro=", "dev": true }, "bcrypt-pbkdf": { @@ -1032,45 +489,16 @@ } }, "binary-extensions": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz", - "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", "dev": true }, - "binary-search-tree": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/binary-search-tree/-/binary-search-tree-0.2.5.tgz", - "integrity": "sha1-fbs7IQ/coIJFDa0jNMMErzm9x4Q=", - "requires": { - "underscore": "1.4.4" - } - }, "bluebird": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", - "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=" - }, - "body-parser": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", - "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", - "requires": { - "bytes": "3.0.0", - "content-type": "1.0.4", - "debug": "2.6.9", - "depd": "1.1.2", - "http-errors": "1.6.3", - "iconv-lite": "0.4.19", - "on-finished": "2.3.0", - "qs": "6.5.1", - "raw-body": "2.3.2", - "type-is": "1.6.16" - } - }, - "bowser": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.6.1.tgz", - "integrity": "sha512-hySGUuLhi0KetfxPZpuJOsjM0kRvCiCgPBygBkzGzJNsq/nbJmaO8QJc6xlWfeFFnMvtd/LeKkhDJGVrmVobUA==" + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", + "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==", + "dev": true }, "boxen": { "version": "1.3.0", @@ -1087,46 +515,11 @@ "widest-line": "2.0.1" }, "dependencies": { - "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.1" - } - }, "camelcase": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", "dev": true - }, - "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.5.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "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" - } } } }, @@ -1134,6 +527,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "requires": { "balanced-match": "1.0.0", "concat-map": "0.0.1" @@ -1150,7 +544,7 @@ "extend-shallow": "2.0.1", "fill-range": "4.0.0", "isobject": "3.0.1", - "repeat-element": "1.1.2", + "repeat-element": "1.1.3", "snapdragon": "0.8.2", "snapdragon-node": "2.1.1", "split-string": "3.1.0", @@ -1174,26 +568,10 @@ "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, - "bson": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.1.tgz", - "integrity": "sha512-jCGVYLoYMHDkOsbwJZBCqwMHyH4c+wzgI9hG7Z6SZJRXWr+x58pdIbm2i9a/jFGCkRJqRUr8eoI7lDWa0hTkxg==" - }, - "buffer": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", - "dev": true, - "requires": { - "base64-js": "1.3.0", - "ieee754": "1.1.8", - "isarray": "1.0.0" - } - }, "buffer-from": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.0.0.tgz", - "integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, "builtin-modules": { @@ -1202,22 +580,6 @@ "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", "dev": true }, - "bunyan": { - "version": "1.8.12", - "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.12.tgz", - "integrity": "sha1-8VDw9nSKvdcq6uhPBEA74u8RN5c=", - "requires": { - "dtrace-provider": "0.8.6", - "moment": "2.22.1", - "mv": "2.1.1", - "safe-json-stringify": "1.1.0" - } - }, - "bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" - }, "cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", @@ -1225,7 +587,7 @@ "dev": true, "requires": { "collection-visit": "1.0.0", - "component-emitter": "1.2.1", + "component-emitter": "1.3.0", "get-value": "2.0.6", "has-value": "1.0.0", "isobject": "3.0.1", @@ -1233,67 +595,13 @@ "to-object-path": "0.3.0", "union-value": "1.0.1", "unset-value": "1.0.0" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } } }, - "caching-transform": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-3.0.2.tgz", - "integrity": "sha512-Mtgcv3lh3U0zRii/6qVgQODdPA4G3zhG+jtbCWj39RXuUFTMzH0vcdMtaJS1jPowd+It2Pqr6y3NJMQqOqCE2w==", - "dev": true, - "requires": { - "hasha": "3.0.0", - "make-dir": "2.1.0", - "package-hash": "3.0.0", - "write-file-atomic": "2.4.2" - }, - "dependencies": { - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "requires": { - "pify": "4.0.1", - "semver": "5.7.0" - } - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - }, - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true - }, - "write-file-atomic": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.2.tgz", - "integrity": "sha512-s0b6vB3xIVRLWywa6X9TOMA7k9zio0TMOsl9ZnDkliA/cfJlpHXAscj0gbHVJiTdIuAYpIyqS5GW91fqm6gG5g==", - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "imurmurhash": "0.1.4", - "signal-exit": "3.0.2" - } - } - } - }, - "camelize": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", - "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=" + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true }, "capture-stack-trace": { "version": "1.0.1", @@ -1308,48 +616,58 @@ "dev": true }, "chalk": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", - "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", + "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": "1.0.0", - "has-color": "0.1.7", - "strip-ansi": "0.1.1" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" + }, + "dependencies": { + "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" + } + } } }, "chokidar": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz", - "integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.6.tgz", + "integrity": "sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g==", "dev": true, "requires": { "anymatch": "2.0.0", - "async-each": "1.0.1", + "async-each": "1.0.3", "braces": "2.3.2", - "fsevents": "1.2.8", + "fsevents": "1.2.9", "glob-parent": "3.1.0", - "inherits": "2.0.3", + "inherits": "2.0.4", "is-binary-path": "1.0.1", - "is-glob": "4.0.0", - "lodash.debounce": "4.0.8", - "normalize-path": "2.1.1", + "is-glob": "4.0.1", + "normalize-path": "3.0.0", "path-is-absolute": "1.0.1", - "readdirp": "2.1.0", - "upath": "1.1.0" + "readdirp": "2.2.1", + "upath": "1.1.2" } }, "chromedriver": { - "version": "2.38.2", - "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-2.38.2.tgz", - "integrity": "sha512-gh77kozqCPTtr74RZpnSgBCoClpNznsg2NEKwi8t54UyzrcpMRkG9nH1qhwI+ojLQpsdpsSjGiASSdMsFZT/mw==", + "version": "77.0.0", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-77.0.0.tgz", + "integrity": "sha512-mZa1IVx4HD8rDaItWbnS470mmypgiWsDiu98r0NkiT4uLm3qrANl4vOU6no6vtWtLQiW5kt1POcIbjeNpsLbXA==", "dev": true, "requires": { - "del": "3.0.0", - "extract-zip": "1.6.6", - "kew": "0.7.0", + "del": "4.1.1", + "extract-zip": "1.6.7", "mkdirp": "0.5.1", - "request": "2.88.0" + "request": "2.88.0", + "tcp-port-used": "1.0.1" } }, "ci-info": { @@ -1378,12 +696,6 @@ "requires": { "is-descriptor": "0.1.6" } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true } } }, @@ -1402,31 +714,8 @@ "string-width": "2.1.1", "strip-ansi": "4.0.0", "wrap-ansi": "2.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "3.0.0" - } - } } }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", @@ -1444,9 +733,9 @@ } }, "color-convert": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", + "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" @@ -1458,42 +747,44 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, - "colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=" - }, "combined-stream": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", - "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", + "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" } }, "commander": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", - "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", - "dev": true - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", "dev": true }, "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "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": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "1.1.1", + "inherits": "2.0.4", + "readable-stream": "2.3.6", + "typedarray": "0.0.6" + } }, "configstore": { "version": "3.1.2", @@ -1502,71 +793,13 @@ "dev": true, "requires": { "dot-prop": "4.2.0", - "graceful-fs": "4.1.11", + "graceful-fs": "4.2.0", "make-dir": "1.3.0", "unique-string": "1.0.0", - "write-file-atomic": "2.3.0", + "write-file-atomic": "2.4.3", "xdg-basedir": "3.0.0" } }, - "connect-redis": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/connect-redis/-/connect-redis-3.4.1.tgz", - "integrity": "sha512-oXNcpLg/PJ6G4gbhyGwrQK9mUQTKYa2aEnOH9kWIxbNUjIFPqUmzz75RdLp5JTPSjrBVcz+9ll4sSxfvlW0ZLA==", - "requires": { - "debug": "4.1.1", - "redis": "2.8.0" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - } - } - }, - "content-disposition": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", - "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" - }, - "content-security-policy-builder": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/content-security-policy-builder/-/content-security-policy-builder-2.1.0.tgz", - "integrity": "sha512-/MtLWhJVvJNkA9dVLAp6fg9LxD2gfI6R2Fi1hPmfjYXSahJJzcfvoeDOxSyp4NvxMuwWv3WMssE9o31DoULHrQ==" - }, - "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==" - }, - "convert-source-map": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", - "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", - "dev": true, - "requires": { - "safe-buffer": "5.1.1" - } - }, - "cookie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", - "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, "copy-descriptor": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", @@ -1576,49 +809,8 @@ "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "cp-file": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-6.2.0.tgz", - "integrity": "sha512-fmvV4caBnofhPe8kOcitBwSn2f39QLjnAnGq3gO9dfd75mUytzKNZB1hde6QHunW2Rt+OwuBOMc3i1tNElbszA==", - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "make-dir": "2.1.0", - "nested-error-stacks": "2.1.0", - "pify": "4.0.1", - "safe-buffer": "5.1.1" - }, - "dependencies": { - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "requires": { - "pify": "4.0.1", - "semver": "5.7.0" - } - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - }, - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true - } - } - }, - "crc": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/crc/-/crc-3.4.4.tgz", - "integrity": "sha1-naHpgOO9RPxck79as9ozeNheRms=" + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true }, "create-error-class": { "version": "3.0.2", @@ -1630,23 +822,16 @@ } }, "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "requires": { - "lru-cache": "4.1.2", + "nice-try": "1.0.5", + "path-key": "2.0.1", + "semver": "5.7.0", "shebang-command": "1.2.0", - "which": "1.2.14" - } - }, - "crypt3": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/crypt3/-/crypt3-1.0.0.tgz", - "integrity": "sha1-imWPHRaZm1UFrclszNe8aDIUvv4=", - "requires": { - "nan": "2.10.0", - "q": "1.5.1" + "which": "1.3.1" } }, "crypto-random-string": { @@ -1655,28 +840,20 @@ "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", "dev": true }, - "cycle": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", - "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=" - }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, "requires": { "assert-plus": "1.0.0" } }, - "dasherize": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dasherize/-/dasherize-2.0.0.tgz", - "integrity": "sha1-bYCcnNDPe7iVLYD8hPoT1H3bEwg=" - }, "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" } @@ -1705,23 +882,6 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, - "default-require-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", - "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", - "dev": true, - "requires": { - "strip-bom": "3.0.0" - }, - "dependencies": { - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - } - } - }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -1769,33 +929,30 @@ "is-data-descriptor": "1.0.0", "kind-of": "6.0.2" } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true } } }, "del": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz", - "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", + "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", "dev": true, "requires": { + "@types/glob": "7.1.1", "globby": "6.1.0", - "is-path-cwd": "1.0.0", - "is-path-in-cwd": "1.0.1", - "p-map": "1.2.0", - "pify": "3.0.0", - "rimraf": "2.4.5" + "is-path-cwd": "2.2.0", + "is-path-in-cwd": "2.1.0", + "p-map": "2.1.0", + "pify": "4.0.1", + "rimraf": "2.6.3" + }, + "dependencies": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } } }, "delayed-stream": { @@ -1804,32 +961,12 @@ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "dev": true }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", "dev": true }, - "dns-prefetch-control": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dns-prefetch-control/-/dns-prefetch-control-0.2.0.tgz", - "integrity": "sha512-hvSnros73+qyZXhHFjx2CMLwoj3Fe7eR9EJsFsqmcI1bB2OBWL/+0YzaEaKssCHnj/6crawNnUyw74Gm2EKe+Q==" - }, - "dont-sniff-mimetype": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/dont-sniff-mimetype/-/dont-sniff-mimetype-1.1.0.tgz", - "integrity": "sha512-ZjI4zqTaxveH2/tTlzS1wFp+7ncxNZaIEWYg3lzZRHkKf5zPT/MnEG6WL0BhHMJUabkh8GeU5NL5j+rEUCb7Ug==" - }, "dot-prop": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", @@ -1842,16 +979,8 @@ "double-ended-queue": { "version": "2.1.0-0", "resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz", - "integrity": "sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=" - }, - "dtrace-provider": { - "version": "0.8.6", - "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.6.tgz", - "integrity": "sha1-QooiOv4DQl0s1tY0f99AxmkDVj0=", - "optional": true, - "requires": { - "nan": "2.10.0" - } + "integrity": "sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=", + "dev": true }, "duplexer3": { "version": "0.1.4", @@ -1869,15 +998,11 @@ "safer-buffer": "2.1.2" } }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, "ejs": { - "version": "2.5.9", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.5.9.tgz", - "integrity": "sha512-GJCAeDBKfREgkBtgrYSf9hQy9kTb3helv0zGdzqhM7iAkW8FA/ZF97VQDbwFiwIT8MQLLOe5VlPZOEvZAqtUAQ==" + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.6.2.tgz", + "integrity": "sha512-PcW2a0tyTuPHz3tWyYqtK6r1fZ3gp+3Sop8Ph+ZYN81Ob5rwmbHEzaqs10N3BEsaGTkh/ooniXK+WwszGlc2+Q==", + "dev": true }, "emoji-regex": { "version": "7.0.3", @@ -1885,11 +1010,6 @@ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" - }, "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", @@ -1899,21 +1019,6 @@ "once": "1.4.0" } }, - "entities": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", - "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", - "dev": true - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "0.2.1" - } - }, "es-abstract": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", @@ -1939,23 +1044,6 @@ "is-symbol": "1.0.2" } }, - "es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true - }, - "es6-promise": { - "version": "3.0.2", - "resolved": "http://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz", - "integrity": "sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y=", - "dev": true - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -1975,6 +1063,12 @@ "source-map": "0.2.0" }, "dependencies": { + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true + }, "source-map": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", @@ -1988,9 +1082,9 @@ } }, "esprima": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "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 }, "estraverse": { @@ -2005,25 +1099,14 @@ "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" - }, - "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", - "dev": true - }, "execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "dev": true, "requires": { - "cross-spawn": "5.1.0", - "get-stream": "3.0.0", + "cross-spawn": "6.0.5", + "get-stream": "4.1.0", "is-stream": "1.1.0", "npm-run-path": "2.0.2", "p-finally": "1.0.0", @@ -2066,79 +1149,6 @@ } } }, - "expect-ct": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/expect-ct/-/expect-ct-0.2.0.tgz", - "integrity": "sha512-6SK3MG/Bbhm8MsgyJAylg+ucIOU71/FzyFalcfu5nY19dH8y/z0tBJU0wrNBXD4B27EoQtqPF/9wqH0iYAd04g==" - }, - "express": { - "version": "4.16.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz", - "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", - "requires": { - "accepts": "1.3.5", - "array-flatten": "1.1.1", - "body-parser": "1.18.2", - "content-disposition": "0.5.2", - "content-type": "1.0.4", - "cookie": "0.3.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "1.1.2", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "etag": "1.8.1", - "finalhandler": "1.1.1", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "1.1.2", - "on-finished": "2.3.0", - "parseurl": "1.3.2", - "path-to-regexp": "0.1.7", - "proxy-addr": "2.0.3", - "qs": "6.5.1", - "range-parser": "1.2.0", - "safe-buffer": "5.1.1", - "send": "0.16.2", - "serve-static": "1.13.2", - "setprototypeof": "1.1.0", - "statuses": "1.4.0", - "type-is": "1.6.16", - "utils-merge": "1.0.1", - "vary": "1.1.2" - }, - "dependencies": { - "statuses": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", - "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" - } - } - }, - "express-request-id": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/express-request-id/-/express-request-id-1.4.0.tgz", - "integrity": "sha1-J3ssCUmAPmgQTJ1Fw+aJNPlr9aI=", - "requires": { - "uuid": "3.2.1" - } - }, - "express-session": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.15.6.tgz", - "integrity": "sha512-r0nrHTCYtAMrFwZ0kBzZEXa1vtPVrw0dKvGSrKP4dahwBQ1BJpF2/y1Pp4sCD/0kvxV4zZeclyvfmw0B4RMJQA==", - "requires": { - "cookie": "0.3.1", - "cookie-signature": "1.0.6", - "crc": "3.4.4", - "debug": "2.6.9", - "depd": "1.1.2", - "on-headers": "1.0.1", - "parseurl": "1.3.2", - "uid-safe": "2.1.5", - "utils-merge": "1.0.1" - } - }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -2228,68 +1238,38 @@ "is-data-descriptor": "1.0.0", "kind-of": "6.0.2" } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true } } }, "extract-zip": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.6.tgz", - "integrity": "sha1-EpDt6NINCHK0Kf0/NRyhKOxe+Fw=", + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz", + "integrity": "sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=", "dev": true, "requires": { - "concat-stream": "1.6.0", + "concat-stream": "1.6.2", "debug": "2.6.9", - "mkdirp": "0.5.0", + "mkdirp": "0.5.1", "yauzl": "2.4.1" - }, - "dependencies": { - "concat-stream": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", - "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", - "dev": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.6", - "typedarray": "0.0.6" - } - }, - "mkdirp": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz", - "integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=", - "dev": true, - "requires": { - "minimist": "0.0.8" - } - } } }, "extsprintf": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.2.0.tgz", - "integrity": "sha1-WtlGwi9bMrp/jNdCZxHG6KP8JSk=" - }, - "eyes": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", - "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true }, "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true }, "fast-levenshtein": { "version": "2.0.6", @@ -2306,11 +1286,6 @@ "pend": "1.2.0" } }, - "feature-policy": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/feature-policy/-/feature-policy-0.3.0.tgz", - "integrity": "sha512-ZtijOTFN7TzCujt1fnNhfWPFPSHeZkesff9AXZj+UEjYBynWNUIYpC87Ve4wHzyexQsImicLu7WsC2LHq7/xrQ==" - }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -2334,60 +1309,13 @@ } } }, - "finalhandler": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", - "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", - "requires": { - "debug": "2.6.9", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "on-finished": "2.3.0", - "parseurl": "1.3.2", - "statuses": "1.4.0", - "unpipe": "1.0.0" - }, - "dependencies": { - "statuses": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", - "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" - } - } - }, - "find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { - "commondir": "1.0.1", - "make-dir": "2.1.0", - "pkg-dir": "3.0.0" - }, - "dependencies": { - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "requires": { - "pify": "4.0.1", - "semver": "5.7.0" - } - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - }, - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true - } + "locate-path": "3.0.0" } }, "flat": { @@ -2413,28 +1341,6 @@ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", "dev": true }, - "foreground-child": { - "version": "1.5.6", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", - "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", - "dev": true, - "requires": { - "cross-spawn": "4.0.2", - "signal-exit": "3.0.2" - }, - "dependencies": { - "cross-spawn": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", - "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", - "dev": true, - "requires": { - "lru-cache": "4.1.2", - "which": "1.2.14" - } - } - } - }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -2448,15 +1354,10 @@ "dev": true, "requires": { "asynckit": "0.4.0", - "combined-stream": "1.0.7", - "mime-types": "2.1.18" + "combined-stream": "1.0.8", + "mime-types": "2.1.24" } }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" - }, "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -2466,40 +1367,20 @@ "map-cache": "0.2.2" } }, - "frameguard": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/frameguard/-/frameguard-3.1.0.tgz", - "integrity": "sha512-TxgSKM+7LTA6sidjOiSZK9wxY0ffMPY3Wta//MqwmX0nZuEHc8QrkV8Fh3ZhMJeiH+Uyh/tcaarImRy8u77O7g==" - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" - }, - "fs-extra": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz", - "integrity": "sha1-N5TzeMWLNC6n27sjCVEJxLO2IpE=", - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "jsonfile": "3.0.1", - "universalify": "0.1.1" - } - }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true }, "fsevents": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.8.tgz", - "integrity": "sha512-tPvHgPGB7m40CZ68xqFGkKuzN+RnpGmSV+hgeKxhRpbxdqKXUFJGC3yonBOLzQBcJyGpdZFDfCsdOC2KFsXzeA==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", "dev": true, "optional": true, "requires": { - "nan": "2.13.2", + "nan": "2.14.0", "node-pre-gyp": "0.12.0" }, "dependencies": { @@ -2512,8 +1393,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -2534,16 +1414,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { - "balanced-match": "^1.0.0", + "balanced-match": "1.0.0", "concat-map": "0.0.1" } }, @@ -2556,20 +1434,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -2583,7 +1458,7 @@ "dev": true, "optional": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.1" } }, "deep-extend": { @@ -2670,7 +1545,7 @@ "dev": true, "optional": true, "requires": { - "minimatch": "^3.0.4" + "minimatch": "3.0.4" } }, "inflight": { @@ -2686,8 +1561,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -2699,9 +1573,8 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { - "number-is-nan": "^1.0.0" + "number-is-nan": "1.0.1" } }, "isarray": { @@ -2714,16 +1587,14 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "1.1.11" } }, "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.3.5", @@ -2747,7 +1618,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -2758,13 +1628,6 @@ "dev": true, "optional": true }, - "nan": { - "version": "2.13.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz", - "integrity": "sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==", - "dev": true, - "optional": true - }, "needle": { "version": "2.3.0", "bundled": true, @@ -2800,8 +1663,8 @@ "dev": true, "optional": true, "requires": { - "abbrev": "1", - "osenv": "^0.1.4" + "abbrev": "1.1.1", + "osenv": "0.1.5" } }, "npm-bundled": { @@ -2816,8 +1679,8 @@ "dev": true, "optional": true, "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" + "ignore-walk": "3.0.1", + "npm-bundled": "1.0.6" } }, "npmlog": { @@ -2835,8 +1698,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -2870,8 +1732,8 @@ "dev": true, "optional": true, "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" } }, "path-is-absolute": { @@ -2933,8 +1795,7 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -3048,16 +1909,19 @@ "dev": true }, "get-caller-file": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", - "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", "dev": true }, "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "3.0.0" + } }, "get-value": { "version": "2.0.6", @@ -3075,12 +1939,14 @@ } }, "glob": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", - "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, "requires": { + "fs.realpath": "1.0.0", "inflight": "1.0.6", - "inherits": "2.0.3", + "inherits": "2.0.4", "minimatch": "3.0.4", "once": "1.4.0", "path-is-absolute": "1.0.1" @@ -3116,42 +1982,22 @@ "ini": "1.3.5" } }, - "globals": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", - "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", - "dev": true - }, "globby": { "version": "6.1.0", - "resolved": "http://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", "dev": true, "requires": { "array-union": "1.0.2", - "glob": "7.1.2", + "glob": "7.1.4", "object-assign": "4.1.1", "pify": "2.3.0", "pinkie-promise": "2.0.1" }, "dependencies": { - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -3170,16 +2016,24 @@ "is-retry-allowed": "1.1.0", "is-stream": "1.1.0", "lowercase-keys": "1.0.1", - "safe-buffer": "5.1.1", + "safe-buffer": "5.1.2", "timed-out": "4.0.1", "unzip-response": "2.0.1", "url-parse-lax": "1.0.0" + }, + "dependencies": { + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + } } }, "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz", + "integrity": "sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==", "dev": true }, "growl": { @@ -3189,15 +2043,15 @@ "dev": true }, "handlebars": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.3.1.tgz", - "integrity": "sha512-c0HoNHzDiHpBt4Kqe99N8tdLPKAnGCQ73gYMPWtAYM4PwGnf7xl8PBUHJqh9ijlzt2uQKaSRxbXRt+rZ7M2/kA==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.4.3.tgz", + "integrity": "sha512-B0W4A2U1ww3q7VVthTKfh+epHx+q4mCt6iK+zEAzbMBpWQAwxCeKxEGpj/1oQTpzPXDNSOG7hmG14TsISH50yw==", "dev": true, "requires": { "neo-async": "2.6.1", "optimist": "0.6.1", "source-map": "0.6.1", - "uglify-js": "3.6.0" + "uglify-js": "3.6.3" }, "dependencies": { "source-map": { @@ -3215,27 +2069,13 @@ "dev": true }, "har-validator": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz", - "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", "dev": true, "requires": { - "ajv": "5.5.2", + "ajv": "6.10.0", "har-schema": "2.0.0" - }, - "dependencies": { - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "dev": true, - "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" - } - } } }, "has": { @@ -3247,25 +2087,10 @@ "function-bind": "1.1.1" } }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "has-color": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", - "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=", - "dev": true - }, "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, "has-symbols": { @@ -3283,14 +2108,6 @@ "get-value": "2.0.6", "has-values": "1.0.0", "isobject": "3.0.1" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } } }, "has-values": { @@ -3303,26 +2120,6 @@ "kind-of": "4.0.0" }, "dependencies": { - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, "kind-of": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", @@ -3334,108 +2131,12 @@ } } }, - "hasha": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-3.0.0.tgz", - "integrity": "sha1-UqMvq4Vp1BymmmH/GiFPjrfIvTk=", - "dev": true, - "requires": { - "is-stream": "1.1.0" - } - }, "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": "3.21.1", - "resolved": "https://registry.npmjs.org/helmet/-/helmet-3.21.1.tgz", - "integrity": "sha512-IC/54Lxvvad2YiUdgLmPlNFKLhNuG++waTF5KPYq/Feo3NNhqMFbcLAlbVkai+9q0+4uxjxGPJ9bNykG+3zZNg==", - "requires": { - "depd": "2.0.0", - "dns-prefetch-control": "0.2.0", - "dont-sniff-mimetype": "1.1.0", - "expect-ct": "0.2.0", - "feature-policy": "0.3.0", - "frameguard": "3.1.0", - "helmet-crossdomain": "0.4.0", - "helmet-csp": "2.9.2", - "hide-powered-by": "1.1.0", - "hpkp": "2.0.0", - "hsts": "2.2.0", - "ienoopen": "1.1.0", - "nocache": "2.1.0", - "referrer-policy": "1.2.0", - "x-xss-protection": "1.3.0" - }, - "dependencies": { - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - } - } - }, - "helmet-crossdomain": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/helmet-crossdomain/-/helmet-crossdomain-0.4.0.tgz", - "integrity": "sha512-AB4DTykRw3HCOxovD1nPR16hllrVImeFp5VBV9/twj66lJ2nU75DP8FPL0/Jp4jj79JhTfG+pFI2MD02kWJ+fA==" - }, - "helmet-csp": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/helmet-csp/-/helmet-csp-2.9.2.tgz", - "integrity": "sha512-Lt5WqNfbNjEJ6ysD4UNpVktSyjEKfU9LVJ1LaFmPfYseg/xPealPfgHhtqdAdjPDopp5zbg/VWCyp4cluMIckw==", - "requires": { - "bowser": "2.6.1", - "camelize": "1.0.0", - "content-security-policy-builder": "2.1.0", - "dasherize": "2.0.0" - } - }, - "hide-powered-by": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/hide-powered-by/-/hide-powered-by-1.1.0.tgz", - "integrity": "sha512-Io1zA2yOA1YJslkr+AJlWSf2yWFkKjvkcL9Ni1XSUqnGLr/qRQe2UI3Cn/J9MsJht7yEVCe0SscY1HgVMujbgg==" - }, - "hosted-git-info": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", - "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", - "dev": true - }, - "hpkp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hpkp/-/hpkp-2.0.0.tgz", - "integrity": "sha1-EOFCJk52IVpdMMROxD3mTe5tFnI=" - }, - "hsts": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/hsts/-/hsts-2.2.0.tgz", - "integrity": "sha512-ToaTnQ2TbJkochoVcdXYm4HOCliNozlviNsg+X2XQLQvZNI/kCHR9rZxVYpJB3UPcHz80PgxRyWQ7PdU1r+VBQ==", - "requires": { - "depd": "2.0.0" - }, - "dependencies": { - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - } - } - }, - "http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", - "requires": { - "depd": "1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": "1.5.0" - } - }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -3444,46 +2145,9 @@ "requires": { "assert-plus": "1.0.0", "jsprim": "1.4.1", - "sshpk": "1.15.1" + "sshpk": "1.16.1" } }, - "httpntlm": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.6.1.tgz", - "integrity": "sha1-rQFScUOi6Hc8+uapb1hla7UqNLI=", - "requires": { - "httpreq": "0.4.24", - "underscore": "1.7.0" - }, - "dependencies": { - "underscore": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", - "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=" - } - } - }, - "httpreq": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/httpreq/-/httpreq-0.4.24.tgz", - "integrity": "sha1-QzX/2CzZaWaKOUZckprGHWOTYn8=" - }, - "iconv-lite": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", - "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" - }, - "ieee754": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", - "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=", - "dev": true - }, - "ienoopen": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ienoopen/-/ienoopen-1.1.0.tgz", - "integrity": "sha512-MFs36e/ca6ohEKtinTJ5VvAJ6oDRAYFdYXweUnGY9L9vcoqFOU4n2ZhmJ0C4z/cwGZ3YIQRSB3XZ1+ghZkY5NQ==" - }, "ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", @@ -3493,7 +2157,8 @@ "immediate": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=" + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=", + "dev": true }, "import-lazy": { "version": "2.1.0", @@ -3511,15 +2176,17 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, "requires": { "once": "1.4.0", "wrappy": "1.0.2" } }, "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true }, "ini": { "version": "1.3.5", @@ -3528,23 +2195,16 @@ "dev": true }, "invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", "dev": true }, - "ip-range-check": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/ip-range-check/-/ip-range-check-0.0.2.tgz", - "integrity": "sha1-YFyFloeqTxhGORjUYZDYs2maKTw=", - "requires": { - "ipaddr.js": "1.6.0" - } - }, - "ipaddr.js": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.6.0.tgz", - "integrity": "sha1-4/o1e3c9phnybpXwSdBVxyeW+Gs=" + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "dev": true }, "is-accessor-descriptor": { "version": "0.1.6", @@ -3553,21 +2213,26 @@ "dev": true, "requires": { "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + } } }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, "is-binary-path": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", "dev": true, "requires": { - "binary-extensions": "1.11.0" + "binary-extensions": "1.13.1" } }, "is-buffer": { @@ -3576,15 +2241,6 @@ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "dev": true, - "requires": { - "builtin-modules": "1.1.1" - } - }, "is-callable": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", @@ -3607,6 +2263,17 @@ "dev": true, "requires": { "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + } } }, "is-date-object": { @@ -3653,9 +2320,9 @@ "dev": true }, "is-glob": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", - "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", "dev": true, "requires": { "is-extglob": "2.1.1" @@ -3684,6 +2351,17 @@ "dev": true, "requires": { "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + } } }, "is-obj": { @@ -3693,18 +2371,29 @@ "dev": true }, "is-path-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", "dev": true }, "is-path-in-cwd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", - "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", + "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", "dev": true, "requires": { - "is-path-inside": "1.0.1" + "is-path-inside": "2.1.0" + }, + "dependencies": { + "is-path-inside": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", + "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", + "dev": true, + "requires": { + "path-is-inside": "1.0.2" + } + } } }, "is-path-inside": { @@ -3723,14 +2412,6 @@ "dev": true, "requires": { "isobject": "3.0.1" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } } }, "is-redirect": { @@ -3775,12 +2456,29 @@ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, + "is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", + "dev": true + }, "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true }, + "is2": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is2/-/is2-2.0.1.tgz", + "integrity": "sha512-+WaJvnaA7aJySz2q/8sLjMb2Mw14KTplHmSwcSpZ/fWJPkUmqw3YTzSWbPJ7OAwRvdYTWF2Wg+yYJ1AdP5Z8CA==", + "dev": true, + "requires": { + "deep-is": "0.1.3", + "ip-regex": "2.1.0", + "is-url": "1.2.4" + } + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -3802,7 +2500,8 @@ "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true }, "istanbul": { "version": "0.4.5", @@ -3815,14 +2514,14 @@ "escodegen": "1.8.1", "esprima": "2.7.3", "glob": "5.0.15", - "handlebars": "4.3.1", + "handlebars": "4.4.3", "js-yaml": "3.13.1", "mkdirp": "0.5.1", "nopt": "3.0.6", "once": "1.4.0", "resolve": "1.1.7", "supports-color": "3.2.3", - "which": "1.2.14", + "which": "1.3.1", "wordwrap": "1.0.0" }, "dependencies": { @@ -3832,10 +2531,10 @@ "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", "dev": true }, - "async": { - "version": "1.5.2", - "resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", "dev": true }, "glob": { @@ -3845,12 +2544,27 @@ "dev": true, "requires": { "inflight": "1.0.6", - "inherits": "2.0.3", + "inherits": "2.0.4", "minimatch": "3.0.4", "once": "1.4.0", "path-is-absolute": "1.0.1" } }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "requires": { + "abbrev": "1.0.9" + } + }, "resolve": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", @@ -3865,203 +2579,13 @@ "requires": { "has-flag": "1.0.0" } - }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true } } }, - "istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-LXTBICkMARVgo579kWDm8SqfB6nvSDKNqIOBEjmJRnL04JvoMHCYGWaMddQnseJYtkEuEvO/sIcOxPLk9gERug==", - "dev": true - }, - "istanbul-lib-hook": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.6.tgz", - "integrity": "sha512-829DKONApZ7UCiPXcOYWSgkFXa4+vNYoNOt3F+4uDJLKL1OotAoVwvThoEj1i8jmOj7odbYcR3rnaHu+QroaXg==", - "dev": true, - "requires": { - "append-transform": "1.0.0" - } - }, - "istanbul-lib-instrument": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.2.0.tgz", - "integrity": "sha512-06IM3xShbNW4NgZv5AP4QH0oHqf1/ivFo8eFys0ZjPXHGldHJQWb3riYOKXqmOqfxXBfxu4B+g/iuhOPZH0RJg==", - "dev": true, - "requires": { - "@babel/generator": "7.4.0", - "@babel/parser": "7.4.3", - "@babel/template": "7.4.0", - "@babel/traverse": "7.4.3", - "@babel/types": "7.4.0", - "istanbul-lib-coverage": "2.0.4", - "semver": "6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.0.0.tgz", - "integrity": "sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ==", - "dev": true - } - } - }, - "istanbul-lib-report": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.7.tgz", - "integrity": "sha512-wLH6beJBFbRBLiTlMOBxmb85cnVM1Vyl36N48e4e/aTKSM3WbOx7zbVIH1SQ537fhhsPbX0/C5JB4qsmyRXXyA==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "2.0.4", - "make-dir": "2.1.0", - "supports-color": "6.1.0" - }, - "dependencies": { - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - } - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - }, - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.5.tgz", - "integrity": "sha512-eDhZ7r6r1d1zQPVZehLc3D0K14vRba/eBYkz3rw16DLOrrTzve9RmnkcwrrkWVgO1FL3EK5knujVe5S8QHE9xw==", - "dev": true, - "requires": { - "debug": "4.1.1", - "istanbul-lib-coverage": "2.0.4", - "make-dir": "2.1.0", - "rimraf": "2.6.3", - "source-map": "0.6.1" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "7.1.3" - } - }, - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "istanbul-reports": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.3.tgz", - "integrity": "sha512-T6EbPuc8Cb620LWAYyZ4D8SSn06dY9i1+IgUX2lTH8gbwflMc9Obd33zHTyNX653ybjpamAHS9toKS3E6cGhTw==", - "dev": true, - "requires": { - "handlebars": "4.3.1" - } - }, - "jmespath": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", - "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=", - "dev": true - }, "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "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": { @@ -4072,14 +2596,6 @@ "requires": { "argparse": "1.0.10", "esprima": "4.0.1" - }, - "dependencies": { - "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 - } } }, "jsbn": { @@ -4088,18 +2604,6 @@ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "dev": true }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", @@ -4107,9 +2611,10 @@ "dev": true }, "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + "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-stringify-safe": { "version": "5.0.1", @@ -4117,21 +2622,6 @@ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", "dev": true }, - "jsonfile": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", - "integrity": "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=", - "dev": true, - "requires": { - "graceful-fs": "4.1.11" - } - }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", - "dev": true - }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -4142,86 +2632,31 @@ "extsprintf": "1.3.0", "json-schema": "0.2.3", "verror": "1.10.0" - }, - "dependencies": { - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true - } } }, "jszip": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.1.5.tgz", - "integrity": "sha512-5W8NUaFRFRqTOL7ZDDrx5qWHJyBXy6velVudIzQUSoqAAYqzSh2Z7/m0Rf1QbmQJccegD0r+YZxBjzqoBiEeJQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.2.1.tgz", + "integrity": "sha512-iCMBbo4eE5rb1VCpm5qXOAaUiRKRUKiItn8ah2YQQx9qymmSAY98eyQfioChEYcVQLh0zxJ3wS4A0mh90AVPvw==", "dev": true, "requires": { - "core-js": "2.3.0", - "es6-promise": "3.0.2", - "lie": "3.1.1", - "pako": "1.0.6", - "readable-stream": "2.0.6" - }, - "dependencies": { - "core-js": { - "version": "2.3.0", - "resolved": "http://registry.npmjs.org/core-js/-/core-js-2.3.0.tgz", - "integrity": "sha1-+rg/uwstjchfpjbEudNMdUIMbWU=", - "dev": true - }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", - "dev": true - }, - "readable-stream": { - "version": "2.0.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", - "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", - "dev": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "0.10.31", - "util-deprecate": "1.0.2" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - } + "lie": "3.3.0", + "pako": "1.0.10", + "readable-stream": "2.3.6", + "set-immediate-shim": "1.0.1" } }, - "kew": { - "version": "0.7.0", - "resolved": "http://registry.npmjs.org/kew/-/kew-0.7.0.tgz", - "integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=", + "just-extend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.0.2.tgz", + "integrity": "sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw==", "dev": true }, "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - }, - "klaw-sync": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-2.1.0.tgz", - "integrity": "sha1-PTvNhgDnv971MjHHOf8FOu1WDkQ=", - "dev": true, - "requires": { - "graceful-fs": "4.1.11" - } + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true }, "latest-version": { "version": "3.1.0", @@ -4233,44 +2668,12 @@ } }, "lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", "dev": true, "requires": { - "invert-kv": "1.0.0" - } - }, - "ldap-filter": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/ldap-filter/-/ldap-filter-0.2.2.tgz", - "integrity": "sha1-8rhCvguG2jNSeYUFsx68rlkNd9A=", - "requires": { - "assert-plus": "0.1.5" - }, - "dependencies": { - "assert-plus": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz", - "integrity": "sha1-7nQAlBMALYTOxyGcasgRgS5yMWA=" - } - } - }, - "ldapjs": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/ldapjs/-/ldapjs-1.0.2.tgz", - "integrity": "sha1-VE/3Ayt7g8aPBwEyjZKXqmlDQPk=", - "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "backoff": "2.5.0", - "bunyan": "1.8.12", - "dashdash": "1.14.1", - "dtrace-provider": "0.8.6", - "ldap-filter": "0.2.2", - "once": "1.4.0", - "vasync": "1.6.4", - "verror": "1.10.0" + "invert-kv": "2.0.0" } }, "levn": { @@ -4284,46 +2687,22 @@ } }, "lie": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", - "integrity": "sha1-mkNrLMd0bKWd56QfpGmz77dr2H4=", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, "requires": { "immediate": "3.0.6" } }, - "linkify-it": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.0.3.tgz", - "integrity": "sha1-2UpGSPmxwXnWT6lykSaL22zpQ08=", - "dev": true, - "requires": { - "uc.micro": "1.0.5" - } - }, - "localforage": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/localforage/-/localforage-1.7.1.tgz", - "integrity": "sha1-5JJ+BCMCuGTbMPMhHxO1xvDell0=", - "requires": { - "lie": "3.1.1" - } - }, "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "requires": { - "p-locate": "2.0.0", + "p-locate": "3.0.0", "path-exists": "3.0.0" - }, - "dependencies": { - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - } } }, "lodash": { @@ -4332,18 +2711,6 @@ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", - "dev": true - }, - "lodash.flattendeep": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", - "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", - "dev": true - }, "lodash.get": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", @@ -4357,49 +2724,12 @@ "dev": true, "requires": { "chalk": "2.4.2" - }, - "dependencies": { - "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.1" - } - }, - "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.5.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "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" - } - } } }, "lolex": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.3.2.tgz", - "integrity": "sha512-A5pN2tkFj7H0dGIAM6MFvHKMJcPnjZsOMvR7ujCjfgW5TbV6H9vb1PgxLtHvjqNZTHsUolz+6/WEO0N1xNx2ng==", + "version": "2.7.5", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.5.tgz", + "integrity": "sha512-l9x0+1offnKKIzYVjyXU2SiwhXDLekRzKyhnbyldPHvC7BvLPVpdNUNR2KeMAiCN2D/kLNttZgQD5WjSxuBx3Q==", "dev": true }, "lowercase-keys": { @@ -4409,9 +2739,9 @@ "dev": true }, "lru-cache": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.2.tgz", - "integrity": "sha512-wgeVXhrDwAWnIF/yZARsFnMBtdFXOg1b8RIrhilp+0iDYN4mdQcNZElDZ0e4B64BhaxeQ5zN7PMyvu7we1kPeQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", "dev": true, "requires": { "pseudomap": "1.0.2", @@ -4428,9 +2758,9 @@ } }, "make-error": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.4.tgz", - "integrity": "sha512-0Dab5btKVPhibSalc9QGXb559ED7G7iLjFXBaj9Wq8O3vorueR5K5jaE3hkG6ZQINyhA/JgG6Qk4qdFQjsYV6g==", + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", + "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", "dev": true }, "map-age-cleaner": { @@ -4457,77 +2787,17 @@ "object-visit": "1.0.1" } }, - "markdown-it": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.1.tgz", - "integrity": "sha512-CzzqSSNkFRUf9vlWvhK1awpJreMRqdCrBvZ8DIoDWTOkESMIF741UPAhuAmbyWmdiFPA6WARNhnu2M6Nrhwa+A==", - "dev": true, - "requires": { - "argparse": "1.0.10", - "entities": "1.1.1", - "linkify-it": "2.0.3", - "mdurl": "1.0.1", - "uc.micro": "1.0.5" - } - }, - "math-random": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz", - "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=" - }, - "mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", - "dev": true - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" - }, "mem": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", - "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", + "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", "dev": true, "requires": { - "mimic-fn": "1.2.0" + "map-age-cleaner": "0.1.3", + "mimic-fn": "2.1.0", + "p-is-promise": "2.1.0" } }, - "memory-pager": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", - "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", - "optional": true - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, - "merge-source-map": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", - "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", - "dev": true, - "requires": { - "source-map": "0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" - }, "micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", @@ -4547,52 +2817,43 @@ "regex-not": "1.0.2", "snapdragon": "0.8.2", "to-regex": "3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } } }, - "mime": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" - }, "mime-db": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "dev": true }, "mime-types": { - "version": "2.1.18", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", - "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "dev": true, "requires": { - "mime-db": "1.33.0" + "mime-db": "1.40.0" } }, "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, "requires": { "brace-expansion": "1.1.11" } }, "minimist": { "version": "0.0.8", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true }, "mixin-deep": { "version": "1.3.2", @@ -4619,6 +2880,7 @@ "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, "requires": { "minimist": "0.0.8" } @@ -4654,10 +2916,10 @@ "yargs-unparser": "1.5.0" }, "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, "debug": { @@ -4666,17 +2928,14 @@ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.1" } }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "3.0.0" - } + "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 }, "glob": { "version": "7.1.3", @@ -4684,28 +2943,12 @@ "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "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" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "3.0.0", - "path-exists": "3.0.0" + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.4", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } }, "ms": { @@ -4714,35 +2957,31 @@ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true }, - "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", - "dev": true, - "requires": { - "p-try": "2.2.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "7.0.3", + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "5.2.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "4.1.0" + } }, "supports-color": { "version": "6.0.0", @@ -4750,16 +2989,26 @@ "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "yargs": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.2.tgz", + "integrity": "sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA==", "dev": true, "requires": { - "isexe": "^2.0.0" + "cliui": "4.1.0", + "find-up": "3.0.0", + "get-caller-file": "2.0.5", + "os-locale": "3.1.0", + "require-directory": "2.1.1", + "require-main-filename": "2.0.0", + "set-blocking": "2.0.0", + "string-width": "3.1.0", + "which-module": "2.0.0", + "y18n": "4.0.0", + "yargs-parser": "13.0.0" } }, "yargs-parser": { @@ -4768,78 +3017,30 @@ "integrity": "sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw==", "dev": true, "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" + "camelcase": "5.3.1", + "decamelize": "1.2.0" } } } }, "mockdate": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/mockdate/-/mockdate-2.0.2.tgz", - "integrity": "sha1-WuDA6vj+I+AJzQH5iJtCxPY0rxI=", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/mockdate/-/mockdate-2.0.3.tgz", + "integrity": "sha512-/wRyr3grWk3tyk188qjZpeiiAfkAoDPEGqyerretomeeaH0D+pN9MCcedhAwrkxX3a216gp8CwPeQMHfLvrFpA==", "dev": true }, - "moment": { - "version": "2.22.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.1.tgz", - "integrity": "sha512-shJkRTSebXvsVqk56I+lkb2latjBs8I+pc2TzWc545y2iFnSjm7Wg0QMh+ZWcdSLQyGEau5jI8ocnmkyTgr9YQ==", - "optional": true - }, - "mongodb": { - "version": "3.1.13", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.1.13.tgz", - "integrity": "sha512-sz2dhvBZQWf3LRNDhbd30KHVzdjZx9IKC0L+kSZ/gzYquCF5zPOgGqRz6sSCqYZtKP2ekB4nfLxhGtzGHnIKxA==", - "requires": { - "mongodb-core": "3.1.11", - "safe-buffer": "5.2.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" - } - } - }, - "mongodb-core": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-3.1.11.tgz", - "integrity": "sha512-rD2US2s5qk/ckbiiGFHeu+yKYDXdJ1G87F6CG3YdaZpzdOm5zpoAZd/EKbPmFO6cQZ+XVXBXBJ660sSI0gc6qg==", - "requires": { - "bson": "1.1.1", - "require_optional": "1.0.1", - "safe-buffer": "5.2.0", - "saslprep": "1.0.3" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" - } - } - }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "mv": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", - "integrity": "sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=", - "optional": true, - "requires": { - "mkdirp": "0.5.1", - "ncp": "2.0.0", - "rimraf": "2.4.5" - } + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true }, "nan": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", - "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==" + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "dev": true, + "optional": true }, "nanomatch": { "version": "1.2.13", @@ -4858,63 +3059,14 @@ "regex-not": "1.0.2", "snapdragon": "0.8.2", "to-regex": "3.0.2" - }, - "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } } }, - "ncp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", - "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", - "optional": true - }, - "nedb": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/nedb/-/nedb-1.8.0.tgz", - "integrity": "sha1-DjUCzYLABNU1WkPJ5VV3vXvZHYg=", - "requires": { - "async": "0.2.10", - "binary-search-tree": "0.2.5", - "localforage": "1.7.1", - "mkdirp": "0.5.1", - "underscore": "1.4.4" - } - }, - "negotiator": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", - "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" - }, "neo-async": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", "dev": true }, - "nested-error-stacks": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz", - "integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==", - "dev": true - }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -4922,55 +3074,36 @@ "dev": true }, "nise": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/nise/-/nise-1.4.8.tgz", - "integrity": "sha512-kGASVhuL4tlAV0tvA34yJYZIVihrUt/5bDwpp4tTluigxUr2bBlJeDXmivb6NuEdFkqvdv/Ybb9dm16PSKUhtw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.0.tgz", + "integrity": "sha512-Z3sfYEkLFzFmL8KY6xnSJLRxwQwYBjOXi/24lb62ZnZiGA0JUzGGTI6TBIgfCSMIDl9Jlu8SRmHNACLTemDHww==", "dev": true, "requires": { - "@sinonjs/formatio": "3.1.0", + "@sinonjs/formatio": "3.2.1", + "@sinonjs/text-encoding": "0.7.1", "just-extend": "4.0.2", - "lolex": "2.3.2", - "path-to-regexp": "1.7.0", - "text-encoding": "0.6.4" + "lolex": "4.1.0", + "path-to-regexp": "1.7.0" }, "dependencies": { "@sinonjs/formatio": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.1.0.tgz", - "integrity": "sha512-ZAR2bPHOl4Xg6eklUGpsdiIJ4+J1SNag1DHHrG/73Uz/nVwXqjgUtRPLoS+aVyieN9cSbc0E4LsU984tWcDyNg==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.1.tgz", + "integrity": "sha512-tsHvOB24rvyvV2+zKMmPkZ7dXX6LSLKZ7aOtXY6Edklp0uRcgGpOsQTTGTcWViFyx4uhWc6GV8QdnALbIbIdeQ==", "dev": true, "requires": { - "@sinonjs/samsam": "3.1.1" + "@sinonjs/commons": "1.4.0", + "@sinonjs/samsam": "3.3.2" } }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "lolex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.1.0.tgz", + "integrity": "sha512-BYxIEXiVq5lGIXeVHnsFzqa1TxN5acnKnPCdlZSpzm8viNEOhiigupA4vTQ9HEFQ6nLTQ9wQOgBknJgzUYQ9Aw==", "dev": true - }, - "just-extend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.0.2.tgz", - "integrity": "sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw==", - "dev": true - }, - "path-to-regexp": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", - "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", - "dev": true, - "requires": { - "isarray": "0.0.1" - } } } }, - "nocache": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/nocache/-/nocache-2.1.0.tgz", - "integrity": "sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q==" - }, "node-environment-flags": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", @@ -4979,512 +3112,72 @@ "requires": { "object.getownpropertydescriptors": "2.0.3", "semver": "5.7.0" - }, - "dependencies": { - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true - } } }, "node-fetch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.3.0.tgz", - "integrity": "sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", + "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==", "dev": true }, - "nodemailer": { - "version": "4.6.4", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-4.6.4.tgz", - "integrity": "sha512-SD4uuX7NMzZ5f5m1XHDd13J4UC3SmdJk8DsmU1g6Nrs5h3x9LcXr6EBPZIqXRJ3LrF7RdklzGhZRF/TuylTcLg==" - }, - "nodemailer-direct-transport": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/nodemailer-direct-transport/-/nodemailer-direct-transport-3.3.2.tgz", - "integrity": "sha1-6W+vuQNYVglH5WkBfZfmBzilCoY=", - "requires": { - "nodemailer-shared": "1.1.0", - "smtp-connection": "2.12.0" - } - }, - "nodemailer-fetch": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/nodemailer-fetch/-/nodemailer-fetch-1.6.0.tgz", - "integrity": "sha1-ecSQihwPXzdbc/6IjamCj23JY6Q=" - }, - "nodemailer-shared": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/nodemailer-shared/-/nodemailer-shared-1.1.0.tgz", - "integrity": "sha1-z1mU4v0mjQD1zw+nZ6CBae2wfsA=", - "requires": { - "nodemailer-fetch": "1.6.0" - } - }, - "nodemailer-smtp-transport": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/nodemailer-smtp-transport/-/nodemailer-smtp-transport-2.7.4.tgz", - "integrity": "sha1-DYmvAZoUSkgP2OzJmZfZ+DjxNoU=", - "requires": { - "nodemailer-shared": "1.1.0", - "nodemailer-wellknown": "0.1.10", - "smtp-connection": "2.12.0" - } - }, - "nodemailer-wellknown": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/nodemailer-wellknown/-/nodemailer-wellknown-0.1.10.tgz", - "integrity": "sha1-WG24EB2zDLRDjrVGc3pBqtDPE9U=" - }, "nodemon": { - "version": "1.18.9", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.18.9.tgz", - "integrity": "sha512-oj/eEVTEI47pzYAjGkpcNw0xYwTl4XSTUQv2NPQI6PpN3b75PhpuYk3Vb3U80xHCyM2Jm+1j68ULHXl4OR3Afw==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.19.1.tgz", + "integrity": "sha512-/DXLzd/GhiaDXXbGId5BzxP1GlsqtMGM9zTmkWrgXtSqjKmGSbLicM/oAy4FR0YWm14jCHRwnR31AHS2dYFHrg==", "dev": true, "requires": { - "chokidar": "2.0.4", + "chokidar": "2.1.6", "debug": "3.2.6", "ignore-by-default": "1.0.1", "minimatch": "3.0.4", - "pstree.remy": "1.1.6", - "semver": "5.5.0", + "pstree.remy": "1.1.7", + "semver": "5.7.0", "supports-color": "5.5.0", "touch": "3.1.0", "undefsafe": "2.0.2", "update-notifier": "2.5.0" }, "dependencies": { - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "chokidar": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz", - "integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==", - "dev": true, - "requires": { - "anymatch": "2.0.0", - "async-each": "1.0.1", - "braces": "2.3.2", - "fsevents": "1.2.8", - "glob-parent": "3.1.0", - "inherits": "2.0.3", - "is-binary-path": "1.0.1", - "is-glob": "4.0.0", - "lodash.debounce": "4.0.8", - "normalize-path": "2.1.1", - "path-is-absolute": "1.0.1", - "readdirp": "2.1.0", - "upath": "1.1.0" - } - }, "debug": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, "requires": { - "ms": "^2.1.1" - }, - "dependencies": { - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true - } + "ms": "2.1.2" } }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "posix-character-classes": "0.1.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.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" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "0.1.6" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "0.1.1" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "0.3.2", - "define-property": "1.0.0", - "expand-brackets": "2.1.4", - "extend-shallow": "2.0.1", - "fragment-cache": "0.2.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "1.0.2" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "0.1.1" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "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 }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "6.0.2" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "6.0.2" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-glob": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", - "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", - "dev": true, - "requires": { - "is-extglob": "2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "braces": "2.3.2", - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "extglob": "2.0.4", - "fragment-cache": "0.2.1", - "kind-of": "6.0.2", - "nanomatch": "1.2.13", - "object.pick": "1.3.0", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" - } - }, "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" + "has-flag": "3.0.0" } } } }, - "nomnom": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz", - "integrity": "sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=", - "dev": true, - "requires": { - "chalk": "0.4.0", - "underscore": "1.6.0" - }, - "dependencies": { - "underscore": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", - "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", - "dev": true - } - } - }, "nopt": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "dev": true, "requires": { "abbrev": "1.1.1" } }, - "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", - "dev": true, - "requires": { - "hosted-git-info": "2.7.1", - "is-builtin-module": "1.0.0", - "semver": "5.5.0", - "validate-npm-package-license": "3.0.4" - } - }, "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "1.1.0" - } + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true }, "npm-run-path": { "version": "2.0.2", @@ -5501,162 +3194,6 @@ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, - "nyc": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-14.0.0.tgz", - "integrity": "sha512-R1zC6UZak6pzn5BZQorkSH5GdOGafrwyeja+eimS5Tu+KJ/hCgBc8qA1QWSzxQmT2FDl2lbpqPw7tBDbSvhAHg==", - "dev": true, - "requires": { - "archy": "1.0.0", - "caching-transform": "3.0.2", - "convert-source-map": "1.6.0", - "cp-file": "6.2.0", - "find-cache-dir": "2.1.0", - "find-up": "3.0.0", - "foreground-child": "1.5.6", - "glob": "7.1.3", - "istanbul-lib-coverage": "2.0.4", - "istanbul-lib-hook": "2.0.6", - "istanbul-lib-instrument": "3.2.0", - "istanbul-lib-report": "2.0.7", - "istanbul-lib-source-maps": "3.0.5", - "istanbul-reports": "2.2.3", - "make-dir": "2.1.0", - "merge-source-map": "1.1.0", - "resolve-from": "4.0.0", - "rimraf": "2.6.3", - "signal-exit": "3.0.2", - "spawn-wrap": "1.4.2", - "test-exclude": "5.2.2", - "uuid": "3.3.2", - "yargs": "13.2.2", - "yargs-parser": "13.0.0" - }, - "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "3.0.0" - } - }, - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "3.0.0", - "path-exists": "3.0.0" - } - }, - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - } - }, - "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", - "dev": true, - "requires": { - "p-try": "2.2.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - }, - "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 - }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "7.1.3" - } - }, - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true - }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", - "dev": true - }, - "yargs-parser": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.0.0.tgz", - "integrity": "sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw==", - "dev": true, - "requires": { - "camelcase": "5.3.1", - "decamelize": "1.2.0" - } - } - } - }, "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", @@ -5688,6 +3225,15 @@ "requires": { "is-descriptor": "0.1.6" } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } } } }, @@ -5697,11 +3243,6 @@ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true }, - "object-path": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.4.tgz", - "integrity": "sha1-NwrnUvvzfePqcKhhwju6iRVpGUk=" - }, "object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", @@ -5709,14 +3250,6 @@ "dev": true, "requires": { "isobject": "3.0.1" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } } }, "object.assign": { @@ -5748,33 +3281,13 @@ "dev": true, "requires": { "isobject": "3.0.1" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } } }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "requires": { - "ee-first": "1.1.1" - } - }, - "on-headers": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", - "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=" - }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, "requires": { "wrappy": "1.0.2" } @@ -5787,6 +3300,14 @@ "requires": { "minimist": "0.0.8", "wordwrap": "0.0.3" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + } } }, "optionator": { @@ -5801,31 +3322,17 @@ "prelude-ls": "1.1.2", "type-check": "0.3.2", "wordwrap": "1.0.0" - }, - "dependencies": { - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - } } }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true - }, "os-locale": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", - "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", "dev": true, "requires": { - "execa": "0.7.0", - "lcid": "1.0.0", - "mem": "1.1.0" + "execa": "1.0.0", + "lcid": "2.0.0", + "mem": "4.3.0" } }, "os-tmpdir": { @@ -5846,56 +3353,42 @@ "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true }, + "p-is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", + "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", + "dev": true + }, "p-limit": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", - "integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", "dev": true, "requires": { - "p-try": "1.0.0" + "p-try": "2.2.0" } }, "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "requires": { - "p-limit": "1.2.0" + "p-limit": "2.2.0" } }, "p-map": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", - "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", "dev": true }, "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, - "package-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-3.0.0.tgz", - "integrity": "sha512-lOtmukMDVvtkL84rJHI7dpTYq+0rli8N2wlnqUcBuDWCfVhRUfOmnR9SsoHFMLpACvEV60dX7rd0rFaYDZI+FA==", - "dev": true, - "requires": { - "graceful-fs": "4.1.15", - "hasha": "3.0.0", - "lodash.flattendeep": "4.4.0", - "release-zalgo": "1.0.0" - }, - "dependencies": { - "graceful-fs": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", - "dev": true - } - } - }, "package-json": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", @@ -5903,22 +3396,17 @@ "dev": true, "requires": { "got": "6.7.1", - "registry-auth-token": "3.3.2", + "registry-auth-token": "3.4.0", "registry-url": "3.1.0", - "semver": "5.5.0" + "semver": "5.7.0" } }, "pako": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", - "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", + "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==", "dev": true }, - "parseurl": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", - "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" - }, "pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", @@ -5931,10 +3419,17 @@ "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", "dev": true }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "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": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true }, "path-is-inside": { "version": "1.0.2", @@ -5949,15 +3444,27 @@ "dev": true }, "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "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": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", + "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", + "dev": true, + "requires": { + "isarray": "0.0.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + } + } }, "pend": { "version": "1.2.0", @@ -5992,77 +3499,12 @@ "pinkie": "2.0.4" } }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "requires": { - "find-up": "3.0.0" - }, - "dependencies": { - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "3.0.0", - "path-exists": "3.0.0" - } - }, - "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", - "dev": true, - "requires": { - "p-try": "2.2.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - } - } - }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", "dev": true }, - "precond": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/precond/-/precond-0.2.3.tgz", - "integrity": "sha1-qpWRvKokkj8eD0hJ0kD0fvwQdaw=" - }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -6076,20 +3518,11 @@ "dev": true }, "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, - "proxy-addr": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.3.tgz", - "integrity": "sha512-jQTChiCJteusULxjBp8+jftSQE5Obdl3k4cnmLA6WXtK6XFuWRnvVL7aCiBqaLPM8c4ph0S4tKna8XvmIwEnXQ==", - "requires": { - "forwarded": "0.1.2", - "ipaddr.js": "1.6.0" - } - }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -6097,15 +3530,15 @@ "dev": true }, "psl": { - "version": "1.1.29", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", - "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==", + "version": "1.1.33", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.33.tgz", + "integrity": "sha512-LTDP2uSrsc7XCb5lO7A8BI1qYxRe/8EqlRvMeEl6rsnYAqDOl8xHR+8lSAIVfrNaSAlTPTNOCgNjWcoUL3AZsw==", "dev": true }, "pstree.remy": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.6.tgz", - "integrity": "sha512-NdF35+QsqD7EgNEI5mkI/X+UwaxVEbQaz9f4IooEmMUv6ZPmlTQYGjBPJGgrlzNdjSvIy4MWMg6Q6vCgBO2K+w==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.7.tgz", + "integrity": "sha512-xsMgrUwRpuGskEzBFkH8NmTimbZ5PcPup0LA8JJkHIm2IMUbQcpo3yeLNWVrufEYjh8YwtSVh0xz6UeWc5Oh5A==", "dev": true }, "pump": { @@ -6119,116 +3552,28 @@ } }, "punycode": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", - "integrity": "sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0=" - }, - "q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", - "optional": true + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true }, "qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", - "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true }, "query-string": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.1.0.tgz", - "integrity": "sha512-pNB/Gr8SA8ff8KpUFM36o/WFAlthgaThka5bV19AD9PNTH20Pwq5Zxodif2YyHwrctp6SkL4GqlOot0qR/wGaw==", + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.8.1.tgz", + "integrity": "sha512-g6y0Lbq10a5pPQpjlFuojfMfV1Pd2Jw9h75ypiYPPia3Gcq2rgkKiIwbkS6JxH7c5f5u/B/sB+d13PU+g1eu4Q==", "dev": true, "requires": { "decode-uri-component": "0.2.0", + "split-on-first": "1.1.0", "strict-uri-encode": "2.0.0" } }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "dev": true - }, - "querystringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.0.tgz", - "integrity": "sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg==" - }, - "random-bytes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", - "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=" - }, - "randomatic": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.0.tgz", - "integrity": "sha512-KnGPVE0lo2WoXxIZ7cPR8YBpiol4gsSuOwDSg410oHh80ZMp5EiypNqL2K4Z77vJn6lB5rap7IkAmcUlalcnBQ==", - "requires": { - "is-number": "4.0.0", - "kind-of": "6.0.2", - "math-random": "1.0.1" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==" - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - } - } - }, - "randomstring": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/randomstring/-/randomstring-1.1.5.tgz", - "integrity": "sha1-bfBij3XL1ZMpMNn+OrTpVqGFGMM=", - "requires": { - "array-uniq": "1.0.2" - } - }, - "range-parser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", - "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" - }, - "raw-body": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", - "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", - "requires": { - "bytes": "3.0.0", - "http-errors": "1.6.2", - "iconv-lite": "0.4.19", - "unpipe": "1.0.0" - }, - "dependencies": { - "depd": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", - "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" - }, - "http-errors": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", - "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", - "requires": { - "depd": "1.1.1", - "inherits": "2.0.3", - "setprototypeof": "1.0.3", - "statuses": "1.5.0" - } - }, - "setprototypeof": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", - "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" - } - } - }, "rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -6256,50 +3601,47 @@ "dev": true, "requires": { "core-util-is": "1.0.2", - "inherits": "2.0.3", + "inherits": "2.0.4", "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.1", + "process-nextick-args": "2.0.1", + "safe-buffer": "5.1.2", "string_decoder": "1.1.1", "util-deprecate": "1.0.2" } }, "readdirp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", - "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", "dev": true, "requires": { - "graceful-fs": "4.1.11", - "minimatch": "3.0.4", - "readable-stream": "2.3.6", - "set-immediate-shim": "1.0.1" + "graceful-fs": "4.2.0", + "micromatch": "3.1.10", + "readable-stream": "2.3.6" } }, "redis": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/redis/-/redis-2.8.0.tgz", "integrity": "sha512-M1OkonEQwtRmZv4tEWF2VgpG0JWJ8Fv1PhlgT5+B+uNq2cA3Rt1Yt/ryoR+vQNOQcIEgdCdfH0jr3bDpihAw1A==", + "dev": true, "requires": { "double-ended-queue": "2.1.0-0", - "redis-commands": "1.4.0", + "redis-commands": "1.5.0", "redis-parser": "2.6.0" } }, "redis-commands": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.4.0.tgz", - "integrity": "sha512-cu8EF+MtkwI4DLIT0x9P8qNTLFhQD4jLfxLR0cCNkeGzs87FN6879JOJwNQR/1zD7aSYNbU0hgsV9zGY71Itvw==" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.5.0.tgz", + "integrity": "sha512-6KxamqpZ468MeQC3bkWmCB1fp56XL64D4Kf0zJSwDZbVLLm7KFkoIcHrgRvQ+sk8dnhySs7+yBg94yIkAK7aJg==", + "dev": true }, "redis-parser": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-2.6.0.tgz", - "integrity": "sha1-Uu0J2srBCPGmMcB+m2mUHnoZUEs=" - }, - "referrer-policy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/referrer-policy/-/referrer-policy-1.2.0.tgz", - "integrity": "sha512-LgQJIuS6nAy1Jd88DCQRemyE3mS+ispwlqMk3b0yjZ257fI1v9c+/p6SD5gP5FGyXUIgrNOAfmyioHwZtYv2VA==" + "integrity": "sha1-Uu0J2srBCPGmMcB+m2mUHnoZUEs=", + "dev": true }, "regex-not": { "version": "1.0.2", @@ -6312,13 +3654,13 @@ } }, "registry-auth-token": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz", - "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", + "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==", "dev": true, "requires": { "rc": "1.2.8", - "safe-buffer": "5.1.1" + "safe-buffer": "5.1.2" } }, "registry-url": { @@ -6330,15 +3672,6 @@ "rc": "1.2.8" } }, - "release-zalgo": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", - "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", - "dev": true, - "requires": { - "es6-error": "4.1.1" - } - }, "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -6346,9 +3679,9 @@ "dev": true }, "repeat-element": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", "dev": true }, "repeat-string": { @@ -6366,16 +3699,16 @@ "aws-sign2": "0.7.0", "aws4": "1.8.0", "caseless": "0.12.0", - "combined-stream": "1.0.7", + "combined-stream": "1.0.8", "extend": "3.0.2", "forever-agent": "0.6.1", "form-data": "2.3.3", - "har-validator": "5.1.0", + "har-validator": "5.1.3", "http-signature": "1.2.0", "is-typedarray": "1.0.0", "isstream": "0.1.2", "json-stringify-safe": "5.0.1", - "mime-types": "2.1.21", + "mime-types": "2.1.24", "oauth-sign": "0.9.0", "performance-now": "2.1.0", "qs": "6.5.2", @@ -6383,75 +3716,24 @@ "tough-cookie": "2.4.3", "tunnel-agent": "0.6.0", "uuid": "3.3.2" - }, - "dependencies": { - "mime-db": { - "version": "1.37.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", - "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==", - "dev": true - }, - "mime-types": { - "version": "2.1.21", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", - "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", - "dev": true, - "requires": { - "mime-db": "1.37.0" - } - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "dev": true - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", - "dev": true, - "requires": { - "psl": "1.1.29", - "punycode": "1.4.1" - } - }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", - "dev": true - } } }, "request-promise": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.2.tgz", - "integrity": "sha1-0epG1lSm7k+O5qT+oQGMIpEZBLQ=", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.4.tgz", + "integrity": "sha512-8wgMrvE546PzbR5WbYxUQogUnUDfM0S7QIFZMID+J73vdFARkFy+HElj4T+MWYhpXwlLp0EQ8Zoj8xUA0he4Vg==", "dev": true, "requires": { - "bluebird": "3.5.0", - "request-promise-core": "1.1.1", + "bluebird": "3.5.5", + "request-promise-core": "1.1.2", "stealthy-require": "1.1.1", - "tough-cookie": "2.3.4" + "tough-cookie": "2.4.3" } }, "request-promise-core": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", - "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz", + "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==", "dev": true, "requires": { "lodash": "4.17.15" @@ -6469,34 +3751,15 @@ "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", "dev": true }, - "require_optional": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", - "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", - "requires": { - "resolve-from": "2.0.0", - "semver": "5.5.0" - } - }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" - }, "resolve": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz", - "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz", + "integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==", "dev": true, "requires": { - "path-parse": "1.0.5" + "path-parse": "1.0.6" } }, - "resolve-from": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", - "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" - }, "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", @@ -6510,23 +3773,19 @@ "dev": true }, "rimraf": { - "version": "2.4.5", - "resolved": "http://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", - "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, "requires": { - "glob": "6.0.4" + "glob": "7.1.4" } }, "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" - }, - "safe-json-stringify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.1.0.tgz", - "integrity": "sha512-EzBtUaFH9bHYPc69wqjp0efJI/DPNHdFbGE3uIMn4sVbO0zx8vZ8cG4WKxQfOpUOKsQyGBiT2mTqnCw+6nLswA==", - "optional": true + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true }, "safe-regex": { "version": "1.1.0", @@ -6549,56 +3808,24 @@ "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==", "dev": true }, - "saslprep": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", - "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", - "optional": true, - "requires": { - "sparse-bitfield": "3.0.3" - } - }, "sax": { - "version": "1.2.1", - "resolved": "http://registry.npmjs.org/sax/-/sax-1.2.1.tgz", - "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true }, "selenium-webdriver": { - "version": "4.0.0-alpha.1", - "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.0.0-alpha.1.tgz", - "integrity": "sha512-z88rdjHAv3jmTZ7KSGUkTvo4rGzcDGMq0oXWHNIDK96Gs31JKVdu9+FMtT4KBrVoibg8dUicJDok6GnqqttO5Q==", + "version": "4.0.0-alpha.4", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.0.0-alpha.4.tgz", + "integrity": "sha512-etJt20d8qInkxMAHIm5SEpPBSS+CdxVcybnxzSIB/GlWErb8pIWrArz/VA6VfUW0/6tIcokepXQ5ufvdzqqk1A==", "dev": true, "requires": { - "jszip": "3.1.5", - "rimraf": "2.6.2", + "jszip": "3.2.1", + "rimraf": "2.6.3", "tmp": "0.0.30", - "xml2js": "0.4.17" + "xml2js": "0.4.19" }, "dependencies": { - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", - "dev": true, - "requires": { - "glob": "7.1.2" - } - }, "tmp": { "version": "0.0.30", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", @@ -6611,9 +3838,10 @@ } }, "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true }, "semver-diff": { "version": "2.1.0", @@ -6621,45 +3849,7 @@ "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", "dev": true, "requires": { - "semver": "5.5.0" - } - }, - "send": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", - "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", - "requires": { - "debug": "2.6.9", - "depd": "1.1.2", - "destroy": "1.0.4", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "etag": "1.8.1", - "fresh": "0.5.2", - "http-errors": "1.6.3", - "mime": "1.4.1", - "ms": "2.0.0", - "on-finished": "2.3.0", - "range-parser": "1.2.0", - "statuses": "1.4.0" - }, - "dependencies": { - "statuses": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", - "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" - } - } - }, - "serve-static": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", - "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", - "requires": { - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "parseurl": "1.3.2", - "send": "0.16.2" + "semver": "5.7.0" } }, "set-blocking": { @@ -6697,11 +3887,6 @@ } } }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" - }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -6718,16 +3903,16 @@ "dev": true }, "should": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/should/-/should-13.2.1.tgz", - "integrity": "sha512-l+/NwEMO+DcstsHEwPHRHzC9j4UOE3VQwJGcMWSsD/vqpqHbnQ+1iSHy64Ihmmjx1uiRPD9pFadTSc3MJtXAgw==", + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz", + "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==", "dev": true, "requires": { "should-equal": "2.0.0", "should-format": "3.0.3", "should-type": "1.4.0", "should-type-adaptors": "1.1.0", - "should-util": "1.0.0" + "should-util": "1.0.1" } }, "should-equal": { @@ -6762,13 +3947,13 @@ "dev": true, "requires": { "should-type": "1.4.0", - "should-util": "1.0.0" + "should-util": "1.0.1" } }, "should-util": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.0.tgz", - "integrity": "sha1-yYzaN0qmsZDfi6h8mInCtNtiAGM=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz", + "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==", "dev": true }, "signal-exit": { @@ -6778,30 +3963,24 @@ "dev": true }, "sinon": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-5.0.7.tgz", - "integrity": "sha512-GvNLrwpvLZ8jIMZBUhHGUZDq5wlUdceJWyHvZDmqBxnjazpxY1L0FNbGBX6VpcOEoQ8Q4XMWFzm2myJMvx+VjA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-5.1.1.tgz", + "integrity": "sha512-h/3uHscbt5pQNxkf7Y/Lb9/OM44YNCicHakcq73ncbrIS8lXg+ZGOZbtuU+/km4YnyiCYfQQEwANaReJz7KDfw==", "dev": true, "requires": { "@sinonjs/formatio": "2.0.0", "diff": "3.5.0", "lodash.get": "4.4.2", - "lolex": "2.3.2", - "nise": "1.4.8", - "supports-color": "5.4.0", + "lolex": "2.7.5", + "nise": "1.5.0", + "supports-color": "5.5.0", "type-detect": "4.0.8" }, "dependencies": { - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "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" @@ -6809,15 +3988,6 @@ } } }, - "smtp-connection": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/smtp-connection/-/smtp-connection-2.12.0.tgz", - "integrity": "sha1-1275EnyyPCJZ7bHoNJwujV4tdME=", - "requires": { - "httpntlm": "1.6.1", - "nodemailer-shared": "1.1.0" - } - }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -6902,18 +4072,6 @@ "is-data-descriptor": "1.0.0", "kind-of": "6.0.2" } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true } } }, @@ -6924,6 +4082,17 @@ "dev": true, "requires": { "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + } } }, "source-map": { @@ -6946,12 +4115,12 @@ } }, "source-map-support": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.5.tgz", - "integrity": "sha512-mR7/Nd5l1z6g99010shcXJiNEaf3fEtmLhRB/sBcQVJGodcHCULPp2y4Sfa43Kv2zq7T+Izmfp/WHCR6dYkQCA==", + "version": "0.5.12", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz", + "integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==", "dev": true, "requires": { - "buffer-from": "1.0.0", + "buffer-from": "1.1.1", "source-map": "0.6.1" }, "dependencies": { @@ -6969,103 +4138,21 @@ "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", "dev": true }, - "sparse-bitfield": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", - "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", - "optional": true, - "requires": { - "memory-pager": "1.5.0" - } - }, - "spawn-wrap": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.2.tgz", - "integrity": "sha512-vMwR3OmmDhnxCVxM8M+xO/FtIp6Ju/mNaDfCMMW7FDcLRTPFWUswec4LXJHTJE2hwTI9O0YBfygu4DalFl7Ylg==", - "dev": true, - "requires": { - "foreground-child": "1.5.6", - "mkdirp": "0.5.1", - "os-homedir": "1.0.2", - "rimraf": "2.6.3", - "signal-exit": "3.0.2", - "which": "1.3.1" - }, - "dependencies": { - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "7.1.3" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "spdx-correct": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.2.tgz", - "integrity": "sha512-q9hedtzyXHr5S0A1vEPoK/7l8NpfkFYTq6iCY+Pno2ZbdZR6WexZFtqeVGkGxW3TEJMN914Z55EnAGMmenlIQQ==", - "dev": true, - "requires": { - "spdx-expression-parse": "3.0.0", - "spdx-license-ids": "3.0.2" - } - }, - "spdx-exceptions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", - "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", - "dev": true, - "requires": { - "spdx-exceptions": "2.2.0", - "spdx-license-ids": "3.0.2" - } - }, - "spdx-license-ids": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.2.tgz", - "integrity": "sha512-qky9CVt0lVIECkEsYbNILVnPvycuEBkXoMFLRWsREkomQLevYhtRKC+R91a5TOAQ3bCMjikRwhyaRqj1VYatYg==", - "dev": true - }, "speakeasy": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/speakeasy/-/speakeasy-2.0.0.tgz", "integrity": "sha1-hckaBxsJpcuGQlkNmDVmFl9XYTo=", + "dev": true, "requires": { "base32.js": "0.0.1" } }, + "split-on-first": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", + "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==", + "dev": true + }, "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", @@ -7078,15 +4165,16 @@ "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true }, "sshpk": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.15.1.tgz", - "integrity": "sha512-mSdgNUaidk+dRU5MhYtN9zebdzF2iG0cNPWy8HG+W8y+fT1JnSkh0fzzpjOa0L7P8i1Rscz38t0h4gPcKz43xA==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", "dev": true, "requires": { - "asn1": "0.2.3", + "asn1": "0.2.4", "assert-plus": "1.0.0", "bcrypt-pbkdf": "1.0.2", "dashdash": "1.14.1", @@ -7097,11 +4185,6 @@ "tweetnacl": "0.14.5" } }, - "stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" - }, "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", @@ -7123,11 +4206,6 @@ } } }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" - }, "stealthy-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", @@ -7148,23 +4226,6 @@ "requires": { "is-fullwidth-code-point": "2.0.0", "strip-ansi": "4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "3.0.0" - } - } } }, "string_decoder": { @@ -7173,14 +4234,17 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "5.1.2" } }, "strip-ansi": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", - "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=", - "dev": true + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } }, "strip-eof": { "version": "1.0.0", @@ -7194,11 +4258,32 @@ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true + "tcp-port-used": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tcp-port-used/-/tcp-port-used-1.0.1.tgz", + "integrity": "sha512-rwi5xJeU6utXoEIiMvVBMc9eJ2/ofzB+7nLOdnZuFTmNCLqRiQh2sMG9MqCxHU/69VC/Fwp5dV9306Qd54ll1Q==", + "dev": true, + "requires": { + "debug": "4.1.0", + "is2": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz", + "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "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 + } + } }, "term-size": { "version": "1.2.0", @@ -7207,155 +4292,42 @@ "dev": true, "requires": { "execa": "0.7.0" - } - }, - "test-exclude": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.2.tgz", - "integrity": "sha512-N2pvaLpT8guUpb5Fe1GJlmvmzH3x+DAKmmyEQmFP792QcLYoGE1syxztSvPD1V8yPe6VrcCt6YGQVjSRjCASsA==", - "dev": true, - "requires": { - "glob": "7.1.3", - "minimatch": "3.0.4", - "read-pkg-up": "4.0.0", - "require-main-filename": "2.0.0" }, "dependencies": { - "find-up": { + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "4.1.5", + "shebang-command": "1.2.0", + "which": "1.3.1" + } + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "5.1.0", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" + } + }, + "get-stream": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "3.0.0" - } - }, - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "parse-json": "4.0.0", - "pify": "3.0.0", - "strip-bom": "3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "3.0.0", - "path-exists": "3.0.0" - } - }, - "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", - "dev": true, - "requires": { - "p-try": "2.2.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "1.3.2", - "json-parse-better-errors": "1.0.2" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "3.0.0" - } - }, - "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "requires": { - "load-json-file": "4.0.0", - "normalize-package-data": "2.4.0", - "path-type": "3.0.0" - } - }, - "read-pkg-up": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", - "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", - "dev": true, - "requires": { - "find-up": "3.0.0", - "read-pkg": "3.0.0" - } - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", "dev": true } } }, - "text-encoding": { - "version": "0.6.4", - "resolved": "http://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", - "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=", - "dev": true - }, "timed-out": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", @@ -7371,12 +4343,6 @@ "os-tmpdir": "1.0.2" } }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - }, "to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", @@ -7384,6 +4350,17 @@ "dev": true, "requires": { "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + } } }, "to-regex": { @@ -7406,17 +4383,6 @@ "requires": { "is-number": "3.0.0", "repeat-string": "1.6.1" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - } - } } }, "touch": { @@ -7426,25 +4392,15 @@ "dev": true, "requires": { "nopt": "1.0.10" - }, - "dependencies": { - "nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", - "dev": true, - "requires": { - "abbrev": "1.1.1" - } - } } }, "tough-cookie": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", - "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", "dev": true, "requires": { + "psl": "1.1.33", "punycode": "1.4.1" }, "dependencies": { @@ -7462,177 +4418,64 @@ "integrity": "sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q==", "dev": true }, - "trim-right": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", - "dev": true - }, - "ts-mock-imports": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/ts-mock-imports/-/ts-mock-imports-1.2.3.tgz", - "integrity": "sha512-pKeHFhlM4s4LvAPiixTsBTzJ65SY0pcXYFQ6nAmDOHl3lYZk4zi2zZFC3et6xX6tKhCCkt2NaYAY+vciPJlo8Q==", - "dev": true - }, "ts-node": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-6.0.2.tgz", - "integrity": "sha512-H/KWK27B3JJAc5WFOBBUxN638DukbV8PptdQgiHWPO2SGDVJzuVOl8Ye0XJ5+FiZIdFtgUuGOJRV4c/XBQ5dBg==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-6.2.0.tgz", + "integrity": "sha512-ZNT+OEGfUNVMGkpIaDJJ44Zq3Yr0bkU/ugN1PHbU+/01Z7UV1fsELRiTx1KuQNvQ1A3pGh3y25iYF6jXgxV21A==", "dev": true, "requires": { "arrify": "1.0.1", - "chalk": "2.4.1", + "buffer-from": "1.1.1", "diff": "3.5.0", - "make-error": "1.3.4", + "make-error": "1.3.5", "minimist": "1.2.0", "mkdirp": "0.5.1", - "source-map-support": "0.5.5", + "source-map-support": "0.5.12", "yn": "2.0.0" }, "dependencies": { - "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.1" - } - }, - "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "dev": true, - "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.4.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, "minimist": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true - }, - "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", - "dev": true, - "requires": { - "has-flag": "3.0.0" - } } } }, "tslib": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz", - "integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", "dev": true }, "tslint": { - "version": "5.9.1", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.9.1.tgz", - "integrity": "sha1-ElX4ej/1frCw4fDmEKi0dIBGya4=", + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.18.0.tgz", + "integrity": "sha512-Q3kXkuDEijQ37nXZZLKErssQVnwCV/+23gFEMROi8IlbaBG6tXqLPQJ5Wjcyt/yHPKBC+hD5SzuGaMora+ZS6w==", "dev": true, "requires": { - "babel-code-frame": "6.26.0", + "@babel/code-frame": "7.0.0", "builtin-modules": "1.1.1", - "chalk": "2.4.1", - "commander": "2.19.0", + "chalk": "2.4.2", + "commander": "2.20.0", "diff": "3.5.0", - "glob": "7.1.2", + "glob": "7.1.4", "js-yaml": "3.13.1", "minimatch": "3.0.4", - "resolve": "1.7.1", - "semver": "5.5.0", - "tslib": "1.9.0", - "tsutils": "2.26.2" - }, - "dependencies": { - "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.1" - } - }, - "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "dev": true, - "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.4.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 - }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "1.0.10", - "esprima": "4.0.1" - } - }, - "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", - "dev": true, - "requires": { - "has-flag": "3.0.0" - } - } + "mkdirp": "0.5.1", + "resolve": "1.11.1", + "semver": "5.7.0", + "tslib": "1.10.0", + "tsutils": "2.29.0" } }, "tsutils": { - "version": "2.26.2", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.26.2.tgz", - "integrity": "sha512-uzwnhmrSbyinPCiwfzGsOY3IulBTwoky7r83HmZdz9QNCjhSCzavkh47KLWuU0zF2F2WbpmmzoJUIEiYyd+jEQ==", + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", "dev": true, "requires": { - "tslib": "1.9.0" + "tslib": "1.10.0" } }, "tunnel-agent": { @@ -7641,7 +4484,7 @@ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "dev": true, "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "5.1.2" } }, "tweetnacl": { @@ -7665,15 +4508,6 @@ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true }, - "type-is": { - "version": "1.6.16", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", - "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "2.1.18" - } - }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -7686,135 +4520,21 @@ "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==", "dev": true }, - "typescript-json-schema": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.23.0.tgz", - "integrity": "sha512-1C7u4Dw0bYgt6+cdke7scazf/y7qOSRlPblqZxRjWByqGvIw8KYNfnLHOj8RCRarwCM7VZCj+uO6F8VngvMVMw==", - "dev": true, - "requires": { - "glob": "7.1.2", - "json-stable-stringify": "1.0.1", - "typescript": "2.8.4", - "yargs": "11.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", - "dev": true, - "requires": { - "string-width": "2.1.1", - "strip-ansi": "4.0.0", - "wrap-ansi": "2.1.0" - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "2.0.0" - } - }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "dev": true, - "requires": { - "jsonify": "0.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "3.0.0" - } - }, - "typescript": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.8.4.tgz", - "integrity": "sha512-IIU5cN1mR5J3z9jjdESJbnxikTrEz3lzAw/D0Tf45jHpBp55nY31UkUvmVHoffCfKHTqJs3fCLPDxknQTTFegQ==", - "dev": true - }, - "yargs": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.0.0.tgz", - "integrity": "sha512-Rjp+lMYQOWtgqojx1dEWorjCofi1YN7AoFvYV7b1gx/7dAAeuI4kN5SZiEvr0ZmsZTOpDRcCqrpI10L31tFkBw==", - "dev": true, - "requires": { - "cliui": "4.1.0", - "decamelize": "1.2.0", - "find-up": "2.1.0", - "get-caller-file": "1.0.2", - "os-locale": "2.1.0", - "require-directory": "2.1.1", - "require-main-filename": "1.0.1", - "set-blocking": "2.0.0", - "string-width": "2.1.1", - "which-module": "2.0.0", - "y18n": "3.2.1", - "yargs-parser": "9.0.2" - } - } - } - }, - "u2f": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/u2f/-/u2f-0.1.3.tgz", - "integrity": "sha512-/IaxeBqjo5o3D7plPkxdApbCpgGoI2bmTomS1kq5OjVflaE9UBJ0WfqoXqZryZKfFYBjQC7Tn1hA57WtRgh/Sg==" - }, - "u2f-api": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/u2f-api/-/u2f-api-1.0.7.tgz", - "integrity": "sha512-aey5tGk4hfw+EMKveDt0IQbM/5VCcACUBRpKU4iU42J6aD9xnmUH6aXFTVWkgfXsNKotbaNW0Tq4L1FKArI4bQ==" - }, - "uc.micro": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.5.tgz", - "integrity": "sha512-JoLI4g5zv5qNyT09f4YAvEZIIV1oOjqnewYg5D38dkQljIzpPT296dbIGvKro3digYI1bkb7W6EP1y4uDlmzLg==", - "dev": true - }, "uglify-js": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", - "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.3.tgz", + "integrity": "sha512-KfQUgOqTkLp2aZxrMbCuKCDGW9slFYu2A23A36Gs7sGzTLcRBDORdOi5E21KWHFIfkY8kzgi/Pr1cXCh0yIp5g==", "dev": true, "optional": true, "requires": { - "commander": "2.20.0", + "commander": "2.20.3", "source-map": "0.6.1" }, "dependencies": { "commander": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true, "optional": true }, @@ -7827,14 +4547,6 @@ } } }, - "uid-safe": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", - "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", - "requires": { - "random-bytes": "1.0.0" - } - }, "undefsafe": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.2.tgz", @@ -7844,11 +4556,6 @@ "debug": "2.6.9" } }, - "underscore": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", - "integrity": "sha1-YaajIBBiKvoHljvzJSA88SI51gQ=" - }, "union-value": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", @@ -7870,17 +4577,6 @@ "crypto-random-string": "1.0.0" } }, - "universalify": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", - "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=", - "dev": true - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" - }, "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", @@ -7918,12 +4614,6 @@ "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true } } }, @@ -7934,9 +4624,9 @@ "dev": true }, "upath": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", - "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", + "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==", "dev": true }, "update-notifier": { @@ -7955,51 +4645,15 @@ "latest-version": "3.1.0", "semver-diff": "2.1.0", "xdg-basedir": "3.0.0" - }, - "dependencies": { - "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.1" - } - }, - "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.5.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "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" - } - } } }, "uri-js": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-3.0.2.tgz", - "integrity": "sha1-+QuFhQf4HepNz7s8TD2/orVX+qo=", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, "requires": { - "punycode": "2.1.0" + "punycode": "2.1.1" } }, "urix": { @@ -8008,33 +4662,6 @@ "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", "dev": true }, - "url": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", - "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", - "dev": true, - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, - "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", - "dev": true - } - } - }, - "url-parse": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.4.tgz", - "integrity": "sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg==", - "requires": { - "querystringify": "2.1.0", - "requires-port": "1.0.0" - } - }, "url-parse-lax": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", @@ -8056,63 +4683,27 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" - }, "uuid": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", - "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==" - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "requires": { - "spdx-correct": "3.0.2", - "spdx-expression-parse": "3.0.0" - } - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" - }, - "vasync": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/vasync/-/vasync-1.6.4.tgz", - "integrity": "sha1-3+k2Fq0OeugBszKp2Iv8XNyOHR8=", - "requires": { - "verror": "1.6.0" - }, - "dependencies": { - "verror": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.6.0.tgz", - "integrity": "sha1-fROyex+swuLakEBetepuW90lLqU=", - "requires": { - "extsprintf": "1.2.0" - } - } - } + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, "requires": { "assert-plus": "1.0.0", "core-util-is": "1.0.2", - "extsprintf": "1.2.0" + "extsprintf": "1.3.0" } }, "which": { - "version": "1.2.14", - "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", - "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { "isexe": "2.0.0" @@ -8142,30 +4733,10 @@ "string-width": "2.1.1" } }, - "winston": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.2.tgz", - "integrity": "sha512-4S/Ad4ZfSNl8OccCLxnJmNISWcm2joa6Q0YGDxlxMzH0fgSwWsjMt+SmlNwCqdpaPg3ev1HKkMBsIiXeSUwpbA==", - "requires": { - "async": "1.0.0", - "colors": "1.0.3", - "cycle": "1.0.3", - "eyes": "0.1.8", - "isstream": "0.1.2", - "stack-trace": "0.0.10" - }, - "dependencies": { - "async": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", - "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=" - } - } - }, "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", "dev": true }, "wrap-ansi": { @@ -8178,6 +4749,12 @@ "strip-ansi": "3.0.1" }, "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, "is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", @@ -8212,24 +4789,20 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true }, "write-file-atomic": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz", - "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", "dev": true, "requires": { - "graceful-fs": "4.1.11", + "graceful-fs": "4.2.0", "imurmurhash": "0.1.4", "signal-exit": "3.0.2" } }, - "x-xss-protection": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/x-xss-protection/-/x-xss-protection-1.3.0.tgz", - "integrity": "sha512-kpyBI9TlVipZO4diReZMAHWtS0MMa/7Kgx8hwG/EuZLiA6sg4Ah/4TRdASHhRRN3boobzcYgFRUFSgHRge6Qhg==" - }, "xdg-basedir": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", @@ -8237,28 +4810,25 @@ "dev": true }, "xml2js": { - "version": "0.4.17", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz", - "integrity": "sha1-F76T6q4/O3eTWceVtBlwWogX6Gg=", + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", "dev": true, "requires": { - "sax": "1.2.1", - "xmlbuilder": "4.2.1" + "sax": "1.2.4", + "xmlbuilder": "9.0.7" } }, "xmlbuilder": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.2.1.tgz", - "integrity": "sha1-qlijBBoGb5DqoWwvU4n/GfP0YaU=", - "dev": true, - "requires": { - "lodash": "4.17.15" - } + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", + "dev": true }, "y18n": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", "dev": true }, "yallist": { @@ -8267,261 +4837,34 @@ "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", "dev": true }, - "yamljs": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz", - "integrity": "sha512-C/FsVVhht4iPQYXOInoxUM/1ELSf9EsgKH34FofQOp6hwCPrW4vG4w5++TED3xRUo8gD7l0P1J1dLlDYzODsTQ==", - "requires": { - "argparse": "1.0.10", - "glob": "7.1.2" - }, - "dependencies": { - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - } - } - }, "yargs": { - "version": "13.2.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.2.tgz", - "integrity": "sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA==", + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", "dev": true, "requires": { "cliui": "4.1.0", + "decamelize": "1.2.0", "find-up": "3.0.0", - "get-caller-file": "2.0.5", + "get-caller-file": "1.0.3", "os-locale": "3.1.0", "require-directory": "2.1.1", - "require-main-filename": "2.0.0", + "require-main-filename": "1.0.1", "set-blocking": "2.0.0", - "string-width": "3.1.0", + "string-width": "2.1.1", "which-module": "2.0.0", "y18n": "4.0.0", - "yargs-parser": "13.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "1.0.5", - "path-key": "2.0.1", - "semver": "5.5.0", - "shebang-command": "1.2.0", - "which": "1.2.14" - } - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "6.0.5", - "get-stream": "4.1.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "3.0.0" - } - }, - "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-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "3.0.0" - } - }, - "invert-kv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", - "dev": true - }, - "lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", - "dev": true, - "requires": { - "invert-kv": "2.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "3.0.0", - "path-exists": "3.0.0" - } - }, - "mem": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", - "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", - "dev": true, - "requires": { - "map-age-cleaner": "0.1.3", - "mimic-fn": "2.1.0", - "p-is-promise": "2.1.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "os-locale": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", - "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", - "dev": true, - "requires": { - "execa": "1.0.0", - "lcid": "2.0.0", - "mem": "4.3.0" - } - }, - "p-is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", - "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", - "dev": true - }, - "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", - "dev": true, - "requires": { - "p-try": "2.2.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "7.0.3", - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "5.2.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "4.1.0" - } - }, - "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", - "dev": true - }, - "yargs-parser": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.0.0.tgz", - "integrity": "sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw==", - "dev": true, - "requires": { - "camelcase": "5.3.1", - "decamelize": "1.2.0" - } - } + "yargs-parser": "11.1.1" } }, "yargs-parser": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", - "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", "dev": true, "requires": { - "camelcase": "4.1.0" - }, - "dependencies": { - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true - } + "camelcase": "5.3.1", + "decamelize": "1.2.0" } }, "yargs-unparser": { @@ -8533,179 +4876,6 @@ "flat": "4.1.0", "lodash": "4.17.15", "yargs": "12.0.5" - }, - "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "1.0.5", - "path-key": "2.0.1", - "semver": "5.5.0", - "shebang-command": "1.2.0", - "which": "1.2.14" - } - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "6.0.5", - "get-stream": "4.1.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "3.0.0" - } - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "3.0.0" - } - }, - "invert-kv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", - "dev": true - }, - "lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", - "dev": true, - "requires": { - "invert-kv": "2.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "3.0.0", - "path-exists": "3.0.0" - } - }, - "mem": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", - "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", - "dev": true, - "requires": { - "map-age-cleaner": "0.1.3", - "mimic-fn": "2.1.0", - "p-is-promise": "2.1.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "os-locale": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", - "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", - "dev": true, - "requires": { - "execa": "1.0.0", - "lcid": "2.0.0", - "mem": "4.3.0" - } - }, - "p-is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", - "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", - "dev": true - }, - "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", - "dev": true, - "requires": { - "p-try": "2.2.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "yargs": { - "version": "12.0.5", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", - "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", - "dev": true, - "requires": { - "cliui": "4.1.0", - "decamelize": "1.2.0", - "find-up": "3.0.0", - "get-caller-file": "1.0.2", - "os-locale": "3.1.0", - "require-directory": "2.1.1", - "require-main-filename": "1.0.1", - "set-blocking": "2.0.0", - "string-width": "2.1.1", - "which-module": "2.0.0", - "y18n": "3.2.1", - "yargs-parser": "11.1.1" - } - }, - "yargs-parser": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", - "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", - "dev": true, - "requires": { - "camelcase": "5.3.1", - "decamelize": "1.2.0" - } - } } }, "yauzl": { diff --git a/package.json b/package.json index c92b4e508..93df104fd 100644 --- a/package.json +++ b/package.json @@ -30,113 +30,43 @@ "apidoc": { "title": "Authelia API documentation" }, - "dependencies": { - "@duosecurity/duo_api": "^1.2.0", - "ajv": "^6.3.0", - "bluebird": "^3.5.0", - "body-parser": "^1.15.2", - "connect-redis": "^3.4.1", - "crypt3": "^1.0.0", - "ejs": "^2.5.5", - "express": "^4.14.0", - "express-request-id": "^1.4.0", - "express-session": "^1.14.2", - "helmet": "^3.21.1", - "ip-range-check": "0.0.2", - "ldapjs": "^1.0.2", - "mongodb": "^3.1.13", - "nedb": "^1.8.0", - "nodemailer": "^4.0.1", - "nodemailer-direct-transport": "^3.3.2", - "nodemailer-smtp-transport": "^2.7.4", - "object-path": "^0.11.3", - "randomatic": "^3.1.0", - "randomstring": "^1.1.5", - "speakeasy": "^2.0.0", - "u2f": "^0.1.2", - "u2f-api": "^1.0.7", - "url-parse": "^1.4.4", - "winston": "^2.3.1", - "yamljs": "^0.3.0" - }, + "dependencies": {}, "devDependencies": { - "@types/bluebird": "^3.5.4", - "@types/body-parser": "^1.16.3", "@types/chokidar": "^1.7.5", "@types/commander": "^2.12.2", - "@types/connect-redis": "0.0.9", - "@types/ejs": "^2.3.33", - "@types/express": "^4.0.35", - "@types/express-session": "1.15.8", - "@types/helmet": "0.0.37", - "@types/ldapjs": "^1.0.3", "@types/mocha": "^5.2.6", "@types/mockdate": "^2.0.0", - "@types/mongodb": "^3.0.9", - "@types/nedb": "^1.8.3", "@types/node-fetch": "^2.1.4", - "@types/nodemailer": "^4.6.0", - "@types/nodemailer-direct-transport": "^1.0.31", - "@types/nodemailer-smtp-transport": "^2.7.4", - "@types/object-path": "^0.9.28", "@types/query-string": "^5.1.0", - "@types/randomstring": "^1.1.5", + "@types/redis": "^2.8.14", "@types/request": "^2.0.5", "@types/request-promise": "^4.1.38", - "@types/selenium-webdriver": "^3.0.4", + "@types/selenium-webdriver": "^3.0.16", "@types/sinon": "^4.3.0", "@types/speakeasy": "^2.0.2", "@types/tmp": "0.0.33", - "@types/url-parse": "^1.4.2", - "@types/winston": "^2.3.2", - "@types/yamljs": "^0.2.30", - "apidoc": "^0.17.6", "chokidar": "^2.0.4", - "chromedriver": "^2.37.0", + "chromedriver": "^77.0.0", "commander": "^2.19.0", "istanbul": "^0.4.5", + "ejs": "^2.6.2", "mocha": "^6.1.4", "mockdate": "^2.0.1", "node-fetch": "^2.3.0", "nodemon": "^1.18.9", - "nyc": "^14.0.0", "query-string": "^6.0.0", "readable-stream": "^2.3.3", + "redis": "^2.8.0", "request": "^2.88.0", "request-promise": "^4.2.2", - "selenium-webdriver": "^4.0.0-alpha.1", + "selenium-webdriver": "^4.0.0-alpha.4", "should": "^13.2.1", "sinon": "^5.0.7", + "speakeasy": "^2.0.0", "tmp": "0.0.33", "tree-kill": "^1.2.1", - "ts-mock-imports": "^1.2.3", "ts-node": "^6.0.1", "tslint": "^5.2.0", - "typescript": "^2.9.2", - "typescript-json-schema": "^0.23.0" - }, - "nyc": { - "include": [ - "src/*.ts", - "src/**/*.ts" - ], - "exclude": [ - "doc", - "src/types", - "dist", - "test", - "src/**/*.d.ts" - ], - "extension": [ - ".ts" - ], - "require": [ - "ts-node/register" - ], - "reporter": [ - "json", - "html" - ], - "all": true + "typescript": "^2.9.2" } } diff --git a/regulation/const.go b/regulation/const.go new file mode 100644 index 000000000..bfcd57f24 --- /dev/null +++ b/regulation/const.go @@ -0,0 +1,5 @@ +package regulation + +import "fmt" + +var ErrUserIsBanned = fmt.Errorf("User is banned") diff --git a/regulation/regulator.go b/regulation/regulator.go new file mode 100644 index 000000000..a756052cf --- /dev/null +++ b/regulation/regulator.go @@ -0,0 +1,81 @@ +package regulation + +import ( + "fmt" + "time" + + "github.com/clems4ever/authelia/configuration/schema" + "github.com/clems4ever/authelia/models" + "github.com/clems4ever/authelia/storage" +) + +// NewRegulator create a regulator instance. +func NewRegulator(configuration *schema.RegulationConfiguration, provider storage.Provider) *Regulator { + regulator := &Regulator{storageProvider: provider} + if configuration != nil { + if configuration.FindTime > configuration.BanTime { + panic(fmt.Errorf("find_time cannot be greater than ban_time")) + } + regulator.enabled = true + regulator.maxRetries = configuration.MaxRetries + regulator.findTime = time.Duration(configuration.FindTime) * time.Second + regulator.banTime = time.Duration(configuration.BanTime) * time.Second + } + return regulator +} + +// Mark mark an authentication attempt. +// We split Mark and Regulate in order to avoid timing attacks since if +func (r *Regulator) Mark(username string, successful bool) error { + return r.storageProvider.AppendAuthenticationLog(models.AuthenticationAttempt{ + Username: username, + Successful: successful, + Time: time.Now(), + }) +} + +// Regulate regulate the authentication attempts for a given user. +// This method returns ErrUserIsBanned if the user is banned along with the time until when +// the user is banned. +func (r *Regulator) Regulate(username string) (time.Time, error) { + // If there is regulation configuration, no regulation applies. + if !r.enabled { + return time.Time{}, nil + } + now := time.Now() + + // TODO(c.michaud): make sure FindTime < BanTime. + attempts, err := r.storageProvider.LoadLatestAuthenticationLogs(username, now.Add(-r.banTime)) + + if err != nil { + return time.Time{}, nil + } + + latestFailedAttempts := make([]models.AuthenticationAttempt, 0, r.maxRetries) + for _, attempt := range attempts { + if attempt.Successful || len(latestFailedAttempts) >= r.maxRetries { + // We stop appending failed attempts once we find the first successful attempts or we reach + // the configured number of retries, meaning the user is already banned. + break + } else { + latestFailedAttempts = append(latestFailedAttempts, attempt) + } + } + + // If the number of failed attempts within the ban time is less than the max number of retries + // then the user is not banned. + if len(latestFailedAttempts) < r.maxRetries { + return time.Time{}, nil + } + + // Now we compute the time between the latest attempt and the MaxRetry-th one. If it's + // within the FindTime then it means that the user has been banned. + durationBetweenLatestAttempts := latestFailedAttempts[0].Time.Sub( + latestFailedAttempts[r.maxRetries-1].Time) + + if durationBetweenLatestAttempts < r.findTime { + bannedUntil := latestFailedAttempts[0].Time.Add(r.banTime) + return bannedUntil, ErrUserIsBanned + } + return time.Time{}, nil +} diff --git a/regulation/regulator_test.go b/regulation/regulator_test.go new file mode 100644 index 000000000..21e5a7afc --- /dev/null +++ b/regulation/regulator_test.go @@ -0,0 +1,258 @@ +package regulation_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/suite" + + "github.com/clems4ever/authelia/models" + + "github.com/stretchr/testify/assert" + + "github.com/clems4ever/authelia/configuration/schema" + "github.com/clems4ever/authelia/mocks" + "github.com/clems4ever/authelia/regulation" + "github.com/golang/mock/gomock" +) + +type RegulatorSuite struct { + suite.Suite + + ctrl *gomock.Controller + storageMock *mocks.MockStorageProvider + configuration schema.RegulationConfiguration + now time.Time +} + +func (s *RegulatorSuite) SetupTest() { + s.ctrl = gomock.NewController(s.T()) + s.storageMock = mocks.NewMockStorageProvider(s.ctrl) + + s.configuration = schema.RegulationConfiguration{ + MaxRetries: 3, + BanTime: 180, + FindTime: 30, + } + s.now = time.Now() +} + +func (s *RegulatorSuite) TearDownTest() { + s.ctrl.Finish() +} + +func (s *RegulatorSuite) TestShouldNotThrowWhenUserIsLegitimate() { + attempts := []models.AuthenticationAttempt{ + models.AuthenticationAttempt{ + Username: "john", + Successful: true, + Time: s.now.Add(-4 * time.Minute), + }, + } + + s.storageMock.EXPECT(). + LoadLatestAuthenticationLogs(gomock.Eq("john"), gomock.Any()). + Return(attempts, nil) + + regulator := regulation.NewRegulator(&s.configuration, s.storageMock) + + _, err := regulator.Regulate("john") + assert.NoError(s.T(), err) +} + +// This test checks the case in which a user failed to authenticate many times but always +// with a certain amount of time larger than FindTime. Meaning the user should not be banned. +func (s *RegulatorSuite) TestShouldNotThrowWhenFailedAuthenticationNotInFindTime() { + attemptsInDB := []models.AuthenticationAttempt{ + models.AuthenticationAttempt{ + Username: "john", + Successful: false, + Time: s.now.Add(-1 * time.Second), + }, + models.AuthenticationAttempt{ + Username: "john", + Successful: false, + Time: s.now.Add(-90 * time.Second), + }, + models.AuthenticationAttempt{ + Username: "john", + Successful: false, + Time: s.now.Add(-180 * time.Second), + }, + } + + s.storageMock.EXPECT(). + LoadLatestAuthenticationLogs(gomock.Eq("john"), gomock.Any()). + Return(attemptsInDB, nil) + + regulator := regulation.NewRegulator(&s.configuration, s.storageMock) + + _, err := regulator.Regulate("john") + assert.NoError(s.T(), err) +} + +// This test checks the case in which a user failed to authenticate many times only a few +// seconds ago (meaning we are checking from now back to now-FindTime). +func (s *RegulatorSuite) TestShouldBanUserIfLatestAttemptsAreWithinFinTime() { + attemptsInDB := []models.AuthenticationAttempt{ + models.AuthenticationAttempt{ + Username: "john", + Successful: false, + Time: s.now.Add(-1 * time.Second), + }, + models.AuthenticationAttempt{ + Username: "john", + Successful: false, + Time: s.now.Add(-4 * time.Second), + }, + models.AuthenticationAttempt{ + Username: "john", + Successful: false, + Time: s.now.Add(-6 * time.Second), + }, + models.AuthenticationAttempt{ + Username: "john", + Successful: false, + Time: s.now.Add(-180 * time.Second), + }, + } + + s.storageMock.EXPECT(). + LoadLatestAuthenticationLogs(gomock.Eq("john"), gomock.Any()). + Return(attemptsInDB, nil) + + regulator := regulation.NewRegulator(&s.configuration, s.storageMock) + + _, err := regulator.Regulate("john") + assert.Equal(s.T(), regulation.ErrUserIsBanned, err) +} + +// This test checks the case in which a user failed to authenticate many times only a few +// seconds ago (meaning we are checking from now-FindTime+X back to now-2FindTime+X knowing that +// we are within now and now-BanTime). It means the user has been banned some time ago and is still +// banned right now. +func (s *RegulatorSuite) TestShouldCheckUserIsStillBanned() { + attemptsInDB := []models.AuthenticationAttempt{ + models.AuthenticationAttempt{ + Username: "john", + Successful: false, + Time: s.now.Add(-31 * time.Second), + }, + models.AuthenticationAttempt{ + Username: "john", + Successful: false, + Time: s.now.Add(-34 * time.Second), + }, + models.AuthenticationAttempt{ + Username: "john", + Successful: false, + Time: s.now.Add(-36 * time.Second), + }, + } + + s.storageMock.EXPECT(). + LoadLatestAuthenticationLogs(gomock.Eq("john"), gomock.Any()). + Return(attemptsInDB, nil) + + regulator := regulation.NewRegulator(&s.configuration, s.storageMock) + + _, err := regulator.Regulate("john") + assert.Equal(s.T(), regulation.ErrUserIsBanned, err) +} + +func (s *RegulatorSuite) TestShouldCheckUserIsNotYetBanned() { + attemptsInDB := []models.AuthenticationAttempt{ + models.AuthenticationAttempt{ + Username: "john", + Successful: false, + Time: s.now.Add(-34 * time.Second), + }, + models.AuthenticationAttempt{ + Username: "john", + Successful: false, + Time: s.now.Add(-36 * time.Second), + }, + } + + s.storageMock.EXPECT(). + LoadLatestAuthenticationLogs(gomock.Eq("john"), gomock.Any()). + Return(attemptsInDB, nil) + + regulator := regulation.NewRegulator(&s.configuration, s.storageMock) + + _, err := regulator.Regulate("john") + assert.NoError(s.T(), err) +} + +func (s *RegulatorSuite) TestShouldCheckUserWasAboutToBeBanned() { + attemptsInDB := []models.AuthenticationAttempt{ + models.AuthenticationAttempt{ + Username: "john", + Successful: false, + Time: s.now.Add(-14 * time.Second), + }, + // more than 30 seconds elapsed between this auth and the preceding one. + // In that case we don't need to regulate the user even though the number + // of retrieved attempts is 3. + models.AuthenticationAttempt{ + Username: "john", + Successful: false, + Time: s.now.Add(-94 * time.Second), + }, + models.AuthenticationAttempt{ + Username: "john", + Successful: false, + Time: s.now.Add(-96 * time.Second), + }, + } + + s.storageMock.EXPECT(). + LoadLatestAuthenticationLogs(gomock.Eq("john"), gomock.Any()). + Return(attemptsInDB, nil) + + regulator := regulation.NewRegulator(&s.configuration, s.storageMock) + + _, err := regulator.Regulate("john") + assert.NoError(s.T(), err) +} + +func (s *RegulatorSuite) TestShouldCheckRegulationHasBeenResetOnSuccessfulAttempt() { + attemptsInDB := []models.AuthenticationAttempt{ + models.AuthenticationAttempt{ + Username: "john", + Successful: false, + Time: s.now.Add(-90 * time.Second), + }, + models.AuthenticationAttempt{ + Username: "john", + Successful: true, + Time: s.now.Add(-93 * time.Second), + }, + // The user was almost banned but he did a successful attempt. Therefore, even if the next + // failure happens withing FindTime, he should not be banned. + models.AuthenticationAttempt{ + Username: "john", + Successful: false, + Time: s.now.Add(-94 * time.Second), + }, + models.AuthenticationAttempt{ + Username: "john", + Successful: false, + Time: s.now.Add(-96 * time.Second), + }, + } + + s.storageMock.EXPECT(). + LoadLatestAuthenticationLogs(gomock.Eq("john"), gomock.Any()). + Return(attemptsInDB, nil) + + regulator := regulation.NewRegulator(&s.configuration, s.storageMock) + + _, err := regulator.Regulate("john") + assert.NoError(s.T(), err) +} + +func TestRunRegulatorSuite(t *testing.T) { + s := new(RegulatorSuite) + suite.Run(t, s) +} diff --git a/regulation/types.go b/regulation/types.go new file mode 100644 index 000000000..eb5aec8c4 --- /dev/null +++ b/regulation/types.go @@ -0,0 +1,21 @@ +package regulation + +import ( + "time" + + "github.com/clems4ever/authelia/storage" +) + +// Regulator an authentication regulator preventing attackers to brute force the service. +type Regulator struct { + // Is the regulation enabled. + enabled bool + // The number of failed authentication attempt before banning the user + maxRetries int + // If a user does the max number of retries within that duration, she will be banned. + findTime time.Duration + // If a user has been banned, this duration is the timelapse during which the user is banned. + banTime time.Duration + + storageProvider storage.Provider +} diff --git a/scripts/authelia-scripts-bootstrap b/scripts/authelia-scripts-bootstrap index c72246dde..816b8872e 100755 --- a/scripts/authelia-scripts-bootstrap +++ b/scripts/authelia-scripts-bootstrap @@ -65,12 +65,12 @@ async function checkKubernetesDependencies() { if (!fs.existsSync('/tmp/kind')) { console.log('Install Kind for spawning a Kubernetes cluster.'); - await exec('wget https://github.com/clems4ever/kind/releases/download/0.1.0-cmic1/kind-linux-amd64 -O /tmp/kind && chmod +x /tmp/kind'); + await exec('wget -nv https://github.com/kubernetes-sigs/kind/releases/download/v0.5.1/kind-linux-amd64 -O /tmp/kind && chmod +x /tmp/kind'); } if (!fs.existsSync('/tmp/kubectl')) { console.log('Install Kubectl for interacting with Kubernetes.'); - await exec('wget https://storage.googleapis.com/kubernetes-release/release/v1.13.0/bin/linux/amd64/kubectl -O /tmp/kubectl && chmod +x /tmp/kubectl'); + await exec('wget -nv https://storage.googleapis.com/kubernetes-release/release/v1.13.0/bin/linux/amd64/kubectl -O /tmp/kubectl && chmod +x /tmp/kubectl'); } } @@ -83,4 +83,4 @@ async function main() { main().catch((err) => { console.error(err); process.exit(1); -}) \ No newline at end of file +}) diff --git a/scripts/authelia-scripts-build b/scripts/authelia-scripts-build index 336aaed50..987ab4057 100755 --- a/scripts/authelia-scripts-build +++ b/scripts/authelia-scripts-build @@ -6,24 +6,14 @@ set -e DIST_DIR=dist rm -rf $DIST_DIR +mkdir -p $DIST_DIR -# Build the server -./node_modules/.bin/tslint -c server/tslint.json -p server/tsconfig.json -./node_modules/.bin/tsc -p server/tsconfig.json - -mkdir -p $DIST_DIR/server/src/resources -cp server/src/resources/** $DIST_DIR/server/src/resources/ - -./node_modules/.bin/typescript-json-schema -o server/src/lib/configuration/Configuration.schema.json --strictNullChecks --required server/tsconfig.json Configuration - -# Copy in dist -cp server/src/lib/configuration/Configuration.schema.json $DIST_DIR/server/src/lib/configuration - +GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -o $DIST_DIR/authelia # Build the client pushd client npm run build popd -mv client/build $DIST_DIR/server/src/public_html +mv client/build $DIST_DIR/public_html diff --git a/scripts/authelia-scripts-serve b/scripts/authelia-scripts-serve index 220922a76..79c609f03 100755 --- a/scripts/authelia-scripts-serve +++ b/scripts/authelia-scripts-serve @@ -16,7 +16,12 @@ if (!config) { config = 'config.yml'; // set default config file.; } -const server = spawn('/usr/bin/env', ['node', 'dist/server/src/index.js', config]); +const server = spawn(__dirname + '/../dist/authelia', ['-config', config], { + env: { + ...process.env, + PUBLIC_DIR: __dirname + "/../dist/public_html" + } +}); server.stdout.pipe(process.stdout); server.stderr.pipe(process.stderr); diff --git a/scripts/authelia-scripts-suites-start b/scripts/authelia-scripts-suites-start index 4faf9aa6e..7ba994da9 100755 --- a/scripts/authelia-scripts-suites-start +++ b/scripts/authelia-scripts-suites-start @@ -42,7 +42,11 @@ async function main() { // Start the environment from ts-node process. runEnvProcess = spawn('./node_modules/.bin/ts-node -P test/tsconfig.json -- ./scripts/run-environment.ts ' + suite, { - shell: true + shell: true, + env: { + ...process.env, + ENVIRONMENT: 'dev', + } }); runEnvProcess.stdout.pipe(process.stdout); runEnvProcess.stderr.pipe(process.stderr); diff --git a/scripts/authelia-scripts-suites-test b/scripts/authelia-scripts-suites-test index 09ce874de..ffcb947eb 100755 --- a/scripts/authelia-scripts-suites-test +++ b/scripts/authelia-scripts-suites-test @@ -30,7 +30,8 @@ async function runTests(suite, withEnv) { env: { ...process.env, TS_NODE_PROJECT: 'test/tsconfig.json', - HEADLESS: (program.headless) ? 'y' : 'n' + HEADLESS: (program.headless) ? 'y' : 'n', + ENVIRONMENT: 'dev', } }); } else { @@ -39,7 +40,8 @@ async function runTests(suite, withEnv) { env: { ...process.env, TS_NODE_PROJECT: 'test/tsconfig.json', - HEADLESS: (program.headless) ? 'y' : 'n' + HEADLESS: (program.headless) ? 'y' : 'n', + ENVIRONMENT: 'dev', } }); } diff --git a/scripts/authelia-scripts-travis b/scripts/authelia-scripts-travis index fdd1d16ab..f194d7e06 100755 --- a/scripts/authelia-scripts-travis +++ b/scripts/authelia-scripts-travis @@ -6,8 +6,6 @@ source bootstrap.sh docker --version docker-compose --version -echo "node `node -v`" -echo "npm `npm -v`" authelia-scripts bootstrap @@ -27,7 +25,7 @@ authelia-scripts build # Run unit tests echo "===> Unit tests stage" -authelia-scripts unittest --forbid-only +authelia-scripts unittest # Build the docker image echo "===> Docker image build stage" diff --git a/scripts/authelia-scripts-unittest b/scripts/authelia-scripts-unittest index 5168e9538..f9143f72f 100755 --- a/scripts/authelia-scripts-unittest +++ b/scripts/authelia-scripts-unittest @@ -1,47 +1,3 @@ -#!/usr/bin/env node - -var program = require('commander'); -var spawn = require('child_process').spawn; - -program - .option('--forbid-only', 'Forbid only and pending filters.') - .parse(process.argv); - -async function runTests(patterns) { - return new Promise((resolve, reject) => { - let mochaArgs = ['--require', 'ts-node/register', '--require', './spec-helper.js', '--colors']; - if (program.forbidOnly) { - mochaArgs = ['--forbid-only', '--forbid-pending'].concat(mochaArgs); - } - - const mocha = spawn('./node_modules/.bin/mocha', mochaArgs.concat(patterns), { - env: { - ...process.env, - 'TS_NODE_PROJECT': './server/tsconfig.json' - } - }); - - mocha.stdout.pipe(process.stdout); - mocha.stderr.pipe(process.stderr); - mocha.on('exit', (status) => { - if (status == 0) { - resolve(); - } - reject(new Error('Status code ' + status)); - }); - }); -} - -async function test() { - await runTests([ - 'server/src/**/*.spec.ts', - ]); -} - -test() - .then(() => { - process.exit(0); - }, (err) => { - process.exit(1); - }); +#!/bin/bash +go test ./... \ No newline at end of file diff --git a/scripts/run-environment.ts b/scripts/run-environment.ts index 33f2d9e6a..744391a2c 100644 --- a/scripts/run-environment.ts +++ b/scripts/run-environment.ts @@ -50,13 +50,18 @@ async function stop() { } async function start() { - const timer = setTimeout(() => { + const timer = setTimeout(async () => { console.error('Setup timed out...'); - teardown().finally(() => process.exit(1)); + try { + await teardown(); + } catch(err) { + process.exit(1) + } }, setup_timeout); console.log('>>> Setting up environment <<<'); try { await setup(); + await sleep(200); clearTimeout(timer); await blockOrRun(command); if (!teardownInProgress) { diff --git a/server/server.go b/server/server.go new file mode 100644 index 000000000..0b84620f3 --- /dev/null +++ b/server/server.go @@ -0,0 +1,102 @@ +package server + +import ( + "fmt" + "os" + + "github.com/clems4ever/authelia/configuration/schema" + "github.com/clems4ever/authelia/duo" + "github.com/clems4ever/authelia/handlers" + "github.com/clems4ever/authelia/logging" + "github.com/clems4ever/authelia/middlewares" + duoapi "github.com/duosecurity/duo_api_golang" + "github.com/fasthttp/router" + "github.com/valyala/fasthttp" +) + +// StartServer start Authelia server with the given configuration and providers. +func StartServer(configuration schema.Configuration, providers middlewares.Providers) { + router := router.New() + + autheliaMiddleware := middlewares.AutheliaMiddleware(configuration, providers) + + publicDir := os.Getenv("PUBLIC_DIR") + if publicDir == "" { + publicDir = "./public_html" + } + fmt.Println("Selected public_html directory is ", publicDir) + + router.GET("/", fasthttp.FSHandler(publicDir, 0)) + router.ServeFiles("/static/*filepath", publicDir+"/static") + + router.GET("/api/state", autheliaMiddleware(handlers.StateGet)) + + router.GET("/api/verify", autheliaMiddleware(handlers.VerifyGet)) + + router.POST("/api/firstfactor", autheliaMiddleware(handlers.FirstFactorPost)) + router.POST("/api/logout", autheliaMiddleware(handlers.LogoutPost)) + + // Password reset related endpoints. + router.POST("/api/reset-password/identity/start", autheliaMiddleware( + handlers.ResetPasswordIdentityStart)) + router.POST("/api/reset-password/identity/finish", autheliaMiddleware( + handlers.ResetPasswordIdentityFinish)) + router.POST("/api/reset-password", autheliaMiddleware( + handlers.ResetPasswordPost)) + + // 2FA preferences and settings related endpoints. + router.GET("/api/secondfactor/available", autheliaMiddleware( + middlewares.RequireFirstFactor(handlers.SecondFactorAvailableMethodsGet))) + + router.GET("/api/secondfactor/preferences", autheliaMiddleware( + middlewares.RequireFirstFactor(handlers.SecondFactorPreferencesGet))) + router.POST("/api/secondfactor/preferences", autheliaMiddleware( + middlewares.RequireFirstFactor(handlers.SecondFactorPreferencesPost))) + + // TOTP related endpoints + router.POST("/api/secondfactor/totp/identity/start", autheliaMiddleware( + middlewares.RequireFirstFactor(handlers.SecondFactorTOTPIdentityStart))) + router.POST("/api/secondfactor/totp/identity/finish", autheliaMiddleware( + middlewares.RequireFirstFactor(handlers.SecondFactorTOTPIdentityFinish))) + router.POST("/api/secondfactor/totp", autheliaMiddleware( + middlewares.RequireFirstFactor(handlers.SecondFactorTOTPPost))) + + // U2F related endpoints + router.POST("/api/secondfactor/u2f/identity/start", autheliaMiddleware( + middlewares.RequireFirstFactor(handlers.SecondFactorU2FIdentityStart))) + router.POST("/api/secondfactor/u2f/identity/finish", autheliaMiddleware( + middlewares.RequireFirstFactor(handlers.SecondFactorU2FIdentityFinish))) + + router.POST("/api/secondfactor/u2f/register", autheliaMiddleware( + middlewares.RequireFirstFactor(handlers.SecondFactorU2FRegister))) + + router.POST("/api/secondfactor/u2f/sign_request", autheliaMiddleware( + middlewares.RequireFirstFactor(handlers.SecondFactorU2FSignGet))) + router.POST("/api/secondfactor/u2f/sign", autheliaMiddleware( + middlewares.RequireFirstFactor(handlers.SecondFactorU2FSignPost))) + + // Configure DUO api endpoint only if configuration exists + if configuration.DuoAPI != nil { + var duoAPI duo.API + if os.Getenv("ENVIRONMENT") == "dev" { + duoAPI = duo.NewDuoAPI(duoapi.NewDuoApi( + configuration.DuoAPI.IntegrationKey, + configuration.DuoAPI.SecretKey, + configuration.DuoAPI.Hostname, "", duoapi.SetInsecure())) + } else { + duoAPI = duo.NewDuoAPI(duoapi.NewDuoApi( + configuration.DuoAPI.IntegrationKey, + configuration.DuoAPI.SecretKey, + configuration.DuoAPI.Hostname, "")) + } + + router.POST("/api/secondfactor/duo", autheliaMiddleware( + middlewares.RequireFirstFactor(handlers.SecondFactorDuoPost(duoAPI)))) + } + + portPattern := fmt.Sprintf(":%d", configuration.Port) + logging.Logger().Infof("Authelia is listening on %s", portPattern) + + logging.Logger().Fatal(fasthttp.ListenAndServe(portPattern, + middlewares.LogRequestMiddleware(router.Handler))) +} diff --git a/server/src/index.ts b/server/src/index.ts deleted file mode 100644 index fcbf4d022..000000000 --- a/server/src/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -#! /usr/bin/env node - -import Server from "./lib/Server"; -import { GlobalDependencies } from "../types/Dependencies"; -import YAML = require("yamljs"); - -const configurationFilepath = process.argv[2]; -if (!configurationFilepath) { - console.log("No config file has been provided."); - console.log("Usage: authelia "); - process.exit(0); -} - -const yamlContent = YAML.load(configurationFilepath); - -const deps: GlobalDependencies = { - u2f: require("u2f"), - ldapjs: require("ldapjs"), - session: require("express-session"), - winston: require("winston"), - speakeasy: require("speakeasy"), - nedb: require("nedb"), - ConnectRedis: require("connect-redis"), - Redis: require("redis") -}; - -const server = new Server(deps); -server.start(yamlContent, deps); diff --git a/server/src/lib/AuthenticationLevel.ts b/server/src/lib/AuthenticationLevel.ts deleted file mode 100644 index 8edae1fe0..000000000 --- a/server/src/lib/AuthenticationLevel.ts +++ /dev/null @@ -1,7 +0,0 @@ -enum Level { - NOT_AUTHENTICATED = 0, - ONE_FACTOR = 1, - TWO_FACTOR = 2 -} - -export default Level; diff --git a/server/src/lib/AuthenticationSessionHandler.ts b/server/src/lib/AuthenticationSessionHandler.ts deleted file mode 100644 index 799bd89a2..000000000 --- a/server/src/lib/AuthenticationSessionHandler.ts +++ /dev/null @@ -1,46 +0,0 @@ - - -import express = require("express"); -import { AuthenticationSession } from "../../types/AuthenticationSession"; -import { IRequestLogger } from "./logging/IRequestLogger"; -import { Level } from "./authentication/Level"; - -const INITIAL_AUTHENTICATION_SESSION: AuthenticationSession = { - keep_me_logged_in: false, - authentication_level: Level.NOT_AUTHENTICATED, - last_activity_datetime: undefined, - userid: undefined, - email: undefined, - groups: [], - register_request: undefined, - sign_request: undefined, - identity_check: undefined, - redirect: undefined -}; - -export class AuthenticationSessionHandler { - static reset(req: express.Request): void { - req.session.auth = Object.assign({}, INITIAL_AUTHENTICATION_SESSION, {}); - - // Initialize last activity with current time - req.session.auth.last_activity_datetime = new Date().getTime(); - } - - static get(req: express.Request, logger: IRequestLogger): AuthenticationSession { - if (!req.session) { - const errorMsg = "Something is wrong with session cookies. Please check Redis is running and Authelia can connect to it."; - logger.error(req, errorMsg); - throw new Error(errorMsg); - } - - if (!req.session.auth) { - logger.debug(req, "Session %s has no authentication information. Its internal id is: %s its current cookie is: %s", - req.sessionID, req.session.id, JSON.stringify(req.session.cookie)); - logger.debug(req, "Authentication session %s was undefined. Resetting..." + - " If it's unexpected, make sure you are visiting the expected domain.", req.sessionID); - AuthenticationSessionHandler.reset(req); - } - - return req.session.auth; - } -} \ No newline at end of file diff --git a/server/src/lib/BelongToDomain.ts b/server/src/lib/BelongToDomain.ts deleted file mode 100644 index 45ae80125..000000000 --- a/server/src/lib/BelongToDomain.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { DomainExtractor } from "./DomainExtractor"; -import { IRequestLogger } from "./logging/IRequestLogger"; -import express = require("express"); - -export function BelongToDomain(url: string, domain: string, logger: IRequestLogger, req: express.Request): boolean { - const urlDomain =  DomainExtractor.fromUrl(url); - if (!urlDomain) { - logger.debug(req, "Unable to extract domain from url %s the url doesn't parse correctly.", url); - return false; - } - logger.debug(req, "Extracted domain %s from url %s", urlDomain, url); - const idx = urlDomain.indexOf(domain); - logger.debug(req, "Found protected domain: %s in url extracted domain: %s at index: %s", - domain, urlDomain, idx); - logger.debug(req, "protected domain size: %s url extracted domain size: %s", domain.length, urlDomain.length); - logger.debug(req, "domain match url extracted: %s", idx + domain.length == urlDomain.length); - return idx + domain.length == urlDomain.length; -} \ No newline at end of file diff --git a/server/src/lib/DomainExtractor.spec.ts b/server/src/lib/DomainExtractor.spec.ts deleted file mode 100644 index 2a8f35580..000000000 --- a/server/src/lib/DomainExtractor.spec.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { DomainExtractor } from "./DomainExtractor"; -import Assert = require("assert"); - -describe("src/lib/DomainExtractor", function () { - describe("test fromUrl", function () { - it("should return domain from https url", function () { - const domain = DomainExtractor.fromUrl("https://www.example.com/test/abc"); - Assert.equal(domain, "www.example.com"); - }); - - it("should return domain from http url", function () { - const domain = DomainExtractor.fromUrl("http://www.example.com/test/abc"); - Assert.equal(domain, "www.example.com"); - }); - - it("should return domain when url contains port", function () { - const domain = DomainExtractor.fromUrl("https://www.example.com:8080/test/abc"); - Assert.equal(domain, "www.example.com"); - }); - - it("should return domain when url contains redirect param", function () { - const domain0 = DomainExtractor.fromUrl("https://www.example.com:8080/test/abc?rd=https://cool.test.com"); - Assert.equal(domain0, "www.example.com"); - - const domain1 = DomainExtractor.fromUrl("https://login.example.com:8080/?rd=https://public.example.com:8080/"); - Assert.equal(domain1, "login.example.com"); - - const domain2 = DomainExtractor.fromUrl("https://singlefactor.example.com:8080/secret.html"); - Assert.equal(domain2, "singlefactor.example.com"); - }); - }); -}); \ No newline at end of file diff --git a/server/src/lib/DomainExtractor.ts b/server/src/lib/DomainExtractor.ts deleted file mode 100644 index a84a77ecb..000000000 --- a/server/src/lib/DomainExtractor.ts +++ /dev/null @@ -1,11 +0,0 @@ -export class DomainExtractor { - static fromUrl(url: string): string { - if (!url) return; - const matches = url.match(/(https?:\/\/)?([a-zA-Z0-9_.-]+).*/); - - if (matches.length > 2) { - return matches[2]; - } - return; - } -} \ No newline at end of file diff --git a/server/src/lib/ErrorMessage.ts b/server/src/lib/ErrorMessage.ts deleted file mode 100644 index c5d9810a4..000000000 --- a/server/src/lib/ErrorMessage.ts +++ /dev/null @@ -1,4 +0,0 @@ - -export interface ErrorMessage { - error: string; -} \ No newline at end of file diff --git a/server/src/lib/ErrorReplies.ts b/server/src/lib/ErrorReplies.ts deleted file mode 100644 index 85a8d8178..000000000 --- a/server/src/lib/ErrorReplies.ts +++ /dev/null @@ -1,41 +0,0 @@ -import * as Express from "express"; -import { IRequestLogger } from "./logging/IRequestLogger"; - -function replyWithError(req: Express.Request, res: Express.Response, - code: number, logger: IRequestLogger, body?: Object): (err: Error) => void { - return function (err: Error): void { - logger.error(req, "Reply with error %d: %s", code, err.message); - logger.debug(req, "%s", err.stack); - res.status(code); - res.send(body); - }; -} - -export function redirectTo(redirectUrl: string, req: Express.Request, - res: Express.Response, logger: IRequestLogger) { - return function(err: Error) { - logger.error(req, "Error: %s", err.message); - logger.debug(req, "Redirecting to %s", redirectUrl); - res.redirect(redirectUrl); - }; -} - -export function replyWithError400(req: Express.Request, - res: Express.Response, logger: IRequestLogger) { - return replyWithError(req, res, 400, logger); -} - -export function replyWithError401(req: Express.Request, - res: Express.Response, logger: IRequestLogger) { - return replyWithError(req, res, 401, logger); -} - -export function replyWithError403(req: Express.Request, - res: Express.Response, logger: IRequestLogger) { - return replyWithError(req, res, 403, logger); -} - -export function replyWithError200(req: Express.Request, - res: Express.Response, logger: IRequestLogger, message: string) { - return replyWithError(req, res, 200, logger, { error: message }); -} \ No newline at end of file diff --git a/server/src/lib/Exceptions.ts b/server/src/lib/Exceptions.ts deleted file mode 100644 index 8db028267..000000000 --- a/server/src/lib/Exceptions.ts +++ /dev/null @@ -1,88 +0,0 @@ - -export class LdapSearchError extends Error { - constructor(message?: string) { - super(message); - this.name = "LdapSearchError"; - (Object).setPrototypeOf(this, LdapSearchError.prototype); - } -} - -export class LdapBindError extends Error { - constructor(message?: string) { - super(message); - this.name = "LdapBindError"; - (Object).setPrototypeOf(this, LdapBindError.prototype); - } -} - -export class LdapError extends Error { - constructor(message?: string) { - super(message); - this.name = "LdapError"; - (Object).setPrototypeOf(this, LdapError.prototype); - } -} - -export class IdentityError extends Error { - constructor(message?: string) { - super(message); - this.name = "IdentityError"; - (Object).setPrototypeOf(this, IdentityError.prototype); - } -} - -export class AccessDeniedError extends Error { - constructor(message?: string) { - super(message); - this.name = "AccessDeniedError"; - (Object).setPrototypeOf(this, AccessDeniedError.prototype); - } -} - -export class AuthenticationRegulationError extends Error { - constructor(message?: string) { - super(message); - this.name = "AuthenticationRegulationError"; - (Object).setPrototypeOf(this, AuthenticationRegulationError.prototype); - } -} - -export class InvalidTOTPError extends Error { - constructor(message?: string) { - super(message); - this.name = "InvalidTOTPError"; - (Object).setPrototypeOf(this, InvalidTOTPError.prototype); - } -} - -export class NotAuthenticatedError extends Error { - constructor(message?: string) { - super(message); - this.name = "NotAuthenticatedError"; - (Object).setPrototypeOf(this, NotAuthenticatedError.prototype); - } -} - -export class NotAuthorizedError extends Error { - constructor(message?: string) { - super(message); - this.name = "NotAuthenticatedError"; - (Object).setPrototypeOf(this, NotAuthorizedError.prototype); - } -} - -export class FirstFactorValidationError extends Error { - constructor(message?: string) { - super(message); - this.name = "FirstFactorValidationError"; - (Object).setPrototypeOf(this, FirstFactorValidationError.prototype); - } -} - -export class SecondFactorValidationError extends Error { - constructor(message?: string) { - super(message); - this.name = "SecondFactorValidationError"; - (Object).setPrototypeOf(this, FirstFactorValidationError.prototype); - } -} \ No newline at end of file diff --git a/server/src/lib/FirstFactorValidator.ts b/server/src/lib/FirstFactorValidator.ts deleted file mode 100644 index e098b7e92..000000000 --- a/server/src/lib/FirstFactorValidator.ts +++ /dev/null @@ -1,19 +0,0 @@ - -import BluebirdPromise = require("bluebird"); -import express = require("express"); -import Exceptions = require("./Exceptions"); -import { AuthenticationSessionHandler } from "./AuthenticationSessionHandler"; -import { IRequestLogger } from "./logging/IRequestLogger"; -import { Level } from "./authentication/Level"; - -export function validate(req: express.Request, logger: IRequestLogger): BluebirdPromise { - return new BluebirdPromise(function (resolve, reject) { - const authSession = AuthenticationSessionHandler.get(req, logger); - - if (!authSession.userid || authSession.authentication_level < Level.ONE_FACTOR) - return reject(new Exceptions.FirstFactorValidationError( - "First factor has not been validated yet.")); - - resolve(); - }); -} \ No newline at end of file diff --git a/server/src/lib/IdentityCheckMiddleware.spec.ts b/server/src/lib/IdentityCheckMiddleware.spec.ts deleted file mode 100644 index 521e093c1..000000000 --- a/server/src/lib/IdentityCheckMiddleware.spec.ts +++ /dev/null @@ -1,131 +0,0 @@ - -import * as Sinon from "sinon"; -import * as IdentityCheckMiddleware from "./IdentityCheckMiddleware"; -import { ServerVariables } from "./ServerVariables"; -import * as Assert from "assert"; -import * as Express from "express"; -import BluebirdPromise = require("bluebird"); -import ExpressMock = require("./stubs/express.spec"); -import { IdentityValidableStub } from "./IdentityValidableStub.spec"; -import { ServerVariablesMock, ServerVariablesMockBuilder } - from "./ServerVariablesMockBuilder.spec"; -import { OPERATION_FAILED } from "./UserMessages"; - -describe("IdentityCheckMiddleware", function () { - let req: Express.Request; - let res: ExpressMock.ResponseMock; - let app: Express.Application; - let app_get: Sinon.SinonStub; - let app_post: Sinon.SinonStub; - let identityValidable: IdentityValidableStub; - let mocks: ServerVariablesMock; - let vars: ServerVariables; - - beforeEach(function () { - const s = ServerVariablesMockBuilder.build(); - mocks = s.mocks; - vars = s.variables; - - req = ExpressMock.RequestMock(); - res = ExpressMock.ResponseMock(); - identityValidable = new IdentityValidableStub(); - - mocks.notifier.notifyStub.returns(BluebirdPromise.resolve()); - mocks.userDataStore.produceIdentityValidationTokenStub - .returns(BluebirdPromise.resolve()); - mocks.userDataStore.consumeIdentityValidationTokenStub - .returns(BluebirdPromise.resolve({ userId: "user" })); - - app = Express(); - app_get = Sinon.stub(app, "get"); - app_post = Sinon.stub(app, "post"); - }); - - afterEach(function () { - app_get.restore(); - app_post.restore(); - }); - - describe("test start GET", function () { - // In that case we answer with 200 to avoid user enumeration. - it("should send 200 if email is missing in provided identity", async function () { - const identity = { userid: "abc" }; - - identityValidable.preValidationInitStub - .returns(BluebirdPromise.resolve(identity)); - const callback = IdentityCheckMiddleware - .post_start_validation(identityValidable, vars); - - await callback(req as any, res as any, undefined) - Assert(identityValidable.preValidationResponseStub.called); - }); - - // In that case we answer with 200 to avoid user enumeration. - it("should send 200 if userid is missing in provided identity", async function () { - const identity = { email: "abc@example.com" }; - - identityValidable.preValidationInitStub - .returns(BluebirdPromise.resolve(identity)); - const callback = IdentityCheckMiddleware - .post_start_validation(identityValidable, vars); - - await callback(req as any, res as any, undefined) - Assert(identityValidable.preValidationResponseStub.called); - }); - - it("should issue a token, send an email and return 204", async function () { - const identity = { userid: "user", email: "abc@example.com" }; - req.get = Sinon.stub().withArgs("Host").returns("localhost"); - - identityValidable.preValidationInitStub - .returns(BluebirdPromise.resolve(identity)); - const callback = IdentityCheckMiddleware - .post_start_validation(identityValidable, vars); - - await callback(req as any, res as any, undefined) - Assert(mocks.notifier.notifyStub.calledOnce); - Assert(mocks.userDataStore.produceIdentityValidationTokenStub - .calledOnce); - Assert.equal(mocks.userDataStore.produceIdentityValidationTokenStub - .getCall(0).args[0], "user"); - Assert.equal(mocks.userDataStore.produceIdentityValidationTokenStub - .getCall(0).args[3], 240000); - }); - }); - - - - describe("test finish GET", function () { - it("should return an error if no identity_token is provided", async () => { - const callback = IdentityCheckMiddleware - .post_finish_validation(identityValidable, vars); - - await callback(req as any, res as any, undefined) - Assert(res.status.calledWith(200)); - Assert(res.send.calledWith({'error': OPERATION_FAILED})); - }); - - it("should call postValidation if identity_token is provided and still valid", async function () { - req.query.identity_token = "token"; - const callback = IdentityCheckMiddleware - .post_finish_validation(identityValidable, vars); - await callback(req as any, res as any, undefined); - }); - - it("should return an error if identity_token is provided but invalid", async function () { - req.query.identity_token = "token"; - - identityValidable.postValidationInitStub - .returns(BluebirdPromise.resolve()); - mocks.userDataStore.consumeIdentityValidationTokenStub.reset(); - mocks.userDataStore.consumeIdentityValidationTokenStub - .returns(() => Promise.reject(new Error("Invalid token"))); - - const callback = IdentityCheckMiddleware - .post_finish_validation(identityValidable, vars); - await callback(req as any, res as any, undefined) - Assert(res.status.calledWith(200)); - Assert(res.send.calledWith({'error': OPERATION_FAILED})); - }); - }); -}); diff --git a/server/src/lib/IdentityCheckMiddleware.ts b/server/src/lib/IdentityCheckMiddleware.ts deleted file mode 100644 index b13943ec0..000000000 --- a/server/src/lib/IdentityCheckMiddleware.ts +++ /dev/null @@ -1,136 +0,0 @@ -import objectPath = require("object-path"); -import randomstring = require("randomstring"); -import BluebirdPromise = require("bluebird"); -import util = require("util"); -import Exceptions = require("./Exceptions"); -import { IUserDataStore } from "./storage/IUserDataStore"; -import Express = require("express"); -import ErrorReplies = require("./ErrorReplies"); -import { AuthenticationSessionHandler } from "./AuthenticationSessionHandler"; -import { AuthenticationSession } from "../../types/AuthenticationSession"; -import { ServerVariables } from "./ServerVariables"; -import { IdentityValidable } from "./IdentityValidable"; -import * as Constants from "./constants"; - -import Identity = require("../../types/Identity"); -import { IdentityValidationDocument } - from "./storage/IdentityValidationDocument"; -import { OPERATION_FAILED } from "./UserMessages"; -import GetHeader from "./utils/GetHeader"; - -function createAndSaveToken(userid: string, challenge: string, - userDataStore: IUserDataStore): BluebirdPromise { - - const five_minutes = 4 * 60 * 1000; - const token = randomstring.generate({ length: 64 }); - - return userDataStore.produceIdentityValidationToken(userid, token, challenge, - five_minutes) - .then(function () { - return BluebirdPromise.resolve(token); - }); -} - -function consumeToken(token: string, challenge: string, - userDataStore: IUserDataStore) - : BluebirdPromise { - return userDataStore.consumeIdentityValidationToken(token, challenge); -} - -export function register(app: Express.Application, - pre_validation_endpoint: string, - post_validation_endpoint: string, - handler: IdentityValidable, - vars: ServerVariables) { - - app.post(pre_validation_endpoint, - post_start_validation(handler, vars)); - app.post(post_validation_endpoint, - post_finish_validation(handler, vars)); -} - -function checkIdentityToken(req: Express.Request, identityToken: string) - : BluebirdPromise { - if (!identityToken) - return BluebirdPromise.reject( - new Exceptions.AccessDeniedError("No identity token provided")); - return BluebirdPromise.resolve(); -} - -export function post_finish_validation(handler: IdentityValidable, - vars: ServerVariables) - : Express.RequestHandler { - - return function (req: Express.Request, res: Express.Response) - : BluebirdPromise { - - let authSession: AuthenticationSession; - const identityToken = objectPath.get( - req, "query.token"); - vars.logger.debug(req, "Identity token provided is %s", identityToken); - - return checkIdentityToken(req, identityToken) - .then(() => { - authSession = AuthenticationSessionHandler.get(req, vars.logger); - return handler.postValidationInit(req); - }) - .then(() => { - return consumeToken(identityToken, handler.challenge(), - vars.userDataStore); - }) - .then((doc: IdentityValidationDocument) => { - authSession.identity_check = { - challenge: handler.challenge(), - userid: doc.userId - }; - handler.postValidationResponse(req, res); - return BluebirdPromise.resolve(); - }) - .catch(ErrorReplies.replyWithError200(req, res, vars.logger, OPERATION_FAILED)); - }; -} - -export function post_start_validation(handler: IdentityValidable, - vars: ServerVariables) - : Express.RequestHandler { - return function (req: Express.Request, res: Express.Response) - : BluebirdPromise { - let identity: Identity.Identity; - - return handler.preValidationInit(req) - .then((id: Identity.Identity) => { - identity = id; - const email = identity.email; - const userid = identity.userid; - vars.logger.info(req, "Start identity validation of user \"%s\"", - userid); - - if (!(email && userid)) - return BluebirdPromise.reject(new Exceptions.IdentityError( - "Missing user id or email address")); - - return createAndSaveToken(userid, handler.challenge(), - vars.userDataStore); - }) - .then((token: string) => { - const scheme = GetHeader(req, Constants.HEADER_X_FORWARDED_PROTO); - const host = GetHeader(req, Constants.HEADER_X_FORWARDED_HOST); - const link_url = util.format("%s://%s/#%s?token=%s", scheme, host, - handler.destinationPath(), token); - vars.logger.info(req, "Notification sent to user \"%s\"", - identity.userid); - return vars.notifier.notify(identity.email, handler.mailSubject(), - link_url); - }) - .then(() => { - handler.preValidationResponse(req, res); - return BluebirdPromise.resolve(); - }) - .catch(Exceptions.IdentityError, (err: Error) => { - vars.logger.error(req, err.message); - handler.preValidationResponse(req, res); - return BluebirdPromise.resolve(); - }) - .catch(ErrorReplies.replyWithError401(req, res, vars.logger)); - }; -} diff --git a/server/src/lib/IdentityValidable.ts b/server/src/lib/IdentityValidable.ts deleted file mode 100644 index 85a9a45c2..000000000 --- a/server/src/lib/IdentityValidable.ts +++ /dev/null @@ -1,20 +0,0 @@ -import Bluebird = require("bluebird"); -import Identity = require("../../types/Identity"); - -// IdentityValidator allows user to go through a identity validation process -// in two steps: -// - Request an operation to be performed (password reset, registration). -// - Confirm operation with email. - -export interface IdentityValidable { - challenge(): string; - preValidationInit(req: Express.Request): Bluebird; - postValidationInit(req: Express.Request): Bluebird; - - // Serves a page after identity check request - preValidationResponse(req: Express.Request, res: Express.Response): void; - // Serves the page if identity validated - postValidationResponse(req: Express.Request, res: Express.Response): void; - mailSubject(): string; - destinationPath(): string; -} \ No newline at end of file diff --git a/server/src/lib/IdentityValidableStub.spec.ts b/server/src/lib/IdentityValidableStub.spec.ts deleted file mode 100644 index e378c095b..000000000 --- a/server/src/lib/IdentityValidableStub.spec.ts +++ /dev/null @@ -1,57 +0,0 @@ - -import Sinon = require("sinon"); -import { IdentityValidable } from "./IdentityValidable"; -import Bluebird = require("bluebird"); -import { Identity } from "../../types/Identity"; - - -export class IdentityValidableStub implements IdentityValidable { - challengeStub: Sinon.SinonStub; - preValidationInitStub: Sinon.SinonStub; - postValidationInitStub: Sinon.SinonStub; - preValidationResponseStub: Sinon.SinonStub; - postValidationResponseStub: Sinon.SinonStub; - mailSubjectStub: Sinon.SinonStub; - destinationPathStub: Sinon.SinonStub; - - constructor() { - this.challengeStub = Sinon.stub(); - - this.preValidationInitStub = Sinon.stub(); - this.postValidationInitStub = Sinon.stub(); - - this.preValidationResponseStub = Sinon.stub(); - this.postValidationResponseStub = Sinon.stub(); - - this.mailSubjectStub = Sinon.stub(); - this.destinationPathStub = Sinon.stub(); - } - - challenge(): string { - return this.challengeStub(); - } - - preValidationInit(req: Express.Request): Bluebird { - return this.preValidationInitStub(req); - } - - postValidationInit(req: Express.Request): Bluebird { - return this.postValidationInitStub(req); - } - - preValidationResponse(req: Express.Request, res: Express.Response): void { - return this.preValidationResponseStub(req, res); - } - - postValidationResponse(req: Express.Request, res: Express.Response): void { - return this.postValidationResponseStub(req, res); - } - - mailSubject(): string { - return this.mailSubjectStub(); - } - - destinationPath(): string { - return this.destinationPathStub(); - } -} \ No newline at end of file diff --git a/server/src/lib/Method2FA.ts b/server/src/lib/Method2FA.ts deleted file mode 100644 index 24391ef23..000000000 --- a/server/src/lib/Method2FA.ts +++ /dev/null @@ -1,3 +0,0 @@ -import Method2FA from "../../../client/src/types/Method2FA"; - -export default Method2FA; \ No newline at end of file diff --git a/server/src/lib/Server.spec.ts b/server/src/lib/Server.spec.ts deleted file mode 100644 index 4f204d8dc..000000000 --- a/server/src/lib/Server.spec.ts +++ /dev/null @@ -1,80 +0,0 @@ - -import Assert = require("assert"); -import Sinon = require("sinon"); -import nedb = require("nedb"); -import winston = require("winston"); -import speakeasy = require("speakeasy"); -import u2f = require("u2f"); -import session = require("express-session"); -import { Configuration } from "./configuration/schema/Configuration"; -import { GlobalDependencies } from "../../types/Dependencies"; -import Server from "./Server"; -import { LdapjsMock } from "./stubs/ldapjs.spec"; - - -describe("Server", function () { - let deps: GlobalDependencies; - let sessionMock: Sinon.SinonSpy; - let ldapjsMock: LdapjsMock; - - before(function () { - sessionMock = Sinon.spy(session); - ldapjsMock = new LdapjsMock(); - - deps = { - speakeasy: speakeasy, - u2f: u2f, - nedb: nedb, - winston: winston, - ldapjs: ldapjsMock as any, - session: sessionMock as any, - ConnectRedis: Sinon.spy(), - Redis: Sinon.spy() as any - }; - }); - - - it("should set cookie scope to domain set in the config", function () { - const config: Configuration = { - port: 8081, - session: { - domain: "example.com", - secret: "secret" - }, - authentication_backend: { - ldap: { - url: "http://ldap", - user: "user", - password: "password", - base_dn: "dc=example,dc=com" - }, - }, - notifier: { - email: { - username: "user@example.com", - password: "password", - sender: "test@authelia.com", - service: "gmail" - } - }, - regulation: { - max_retries: 3, - ban_time: 5 * 60, - find_time: 5 * 60 - }, - storage: { - local: { - in_memory: true - } - } - }; - - const server = new Server(deps); - server.start(config, deps) - .then(function () { - Assert(sessionMock.calledOnce); - Assert.equal(sessionMock.getCall(0).args[0].cookie.domain, "example.com"); - server.stop(); - }); - }); -}); diff --git a/server/src/lib/Server.ts b/server/src/lib/Server.ts deleted file mode 100644 index 374eaac56..000000000 --- a/server/src/lib/Server.ts +++ /dev/null @@ -1,155 +0,0 @@ -import * as Bluebird from "bluebird"; -import * as Express from "express"; -import * as http from "http"; - -import { Configuration } from "./configuration/schema/Configuration"; -import { GlobalDependencies } from "../../types/Dependencies"; -import { ConfigurationParser } from "./configuration/ConfigurationParser"; -import { GlobalLogger } from "./logging/GlobalLogger"; -import { RequestLogger } from "./logging/RequestLogger"; -import { ServerVariables } from "./ServerVariables"; -import { ServerVariablesInitializer } from "./ServerVariablesInitializer"; -import { Configurator } from "./web_server/Configurator"; - -import { GET_VARIABLE_KEY } from "./constants"; - -function clone(obj: any) { - return JSON.parse(JSON.stringify(obj)); -} - -export default class Server { - private httpServer: http.Server; - private globalLogger: GlobalLogger; - private requestLogger: RequestLogger; - - constructor(deps: GlobalDependencies) { - this.globalLogger = new GlobalLogger(deps.winston); - this.requestLogger = new RequestLogger(deps.winston); - } - - private displayConfigurations(configuration: Configuration) { - const displayableConfiguration: Configuration = clone(configuration); - const STARS = "*****"; - - if (displayableConfiguration.authentication_backend.ldap) { - displayableConfiguration.authentication_backend.ldap.password = STARS; - } - - displayableConfiguration.session.secret = STARS; - if (displayableConfiguration.notifier && displayableConfiguration.notifier.email) - displayableConfiguration.notifier.email.password = STARS; - if (displayableConfiguration.notifier && displayableConfiguration.notifier.smtp) - displayableConfiguration.notifier.smtp.password = STARS; - if (displayableConfiguration.duo_api) { - displayableConfiguration.duo_api.secret_key = STARS; - } - - this.globalLogger.debug("User configuration is %s", - JSON.stringify(displayableConfiguration, undefined, 2)); - } - - private setup(config: Configuration, app: Express.Application, deps: GlobalDependencies): Bluebird { - return ServerVariablesInitializer.initialize( - config, this.globalLogger, this.requestLogger, deps) - .then(function (vars: ServerVariables) { - app.set(GET_VARIABLE_KEY, vars); - return Configurator.configure(config, app, vars, deps); - }); - } - - private startServer(app: Express.Application, port: number) { - const that = this; - that.globalLogger.info("Starting Authelia..."); - return new Bluebird((resolve, reject) => { - this.httpServer = app.listen(port, function (err: string) { - that.globalLogger.info("Listening on port %d...", port); - resolve(); - }); - }); - } - - start(configuration: Configuration, deps: GlobalDependencies) - : Bluebird { - const that = this; - const app = Express(); - - const appConfiguration = ConfigurationParser.parse(configuration); - // by default the level of logs is info - deps.winston.level = appConfiguration.logs_level; - - // We want to get the ldap binding password from the environment if it has been set, otherwise it will come from - // the config file - if (process.env.LDAP_BACKEND_PASSWORD) { - if (appConfiguration.authentication_backend.ldap) { - appConfiguration.authentication_backend.ldap.password = process.env.LDAP_BACKEND_PASSWORD; - that.globalLogger.debug("Got ldap binding password from environment"); - } else { - const erMsg = - "Environment variable LDAP_BACKEND_PASSWORD set, but no ldap configuration is specified in configuration file."; - that.globalLogger.error(erMsg); - throw new Error(erMsg); - } - } - - // We want to get the session secret from the environment if it has been set, otherwise it will come from the - // config file - if (process.env.SESSION_SECRET) { - appConfiguration.session.secret = process.env.SESSION_SECRET; - that.globalLogger.debug("Got session secret from environment"); - } - - // We want to get the password for using an e-mail service from the environment if it has been set, otherwise it - // will come from the config file - if (process.env.EMAIL_SERVICE_PASSWORD) { - if (appConfiguration.notifier && appConfiguration.notifier.email) { - appConfiguration.notifier.email.password = process.env.EMAIL_SERVICE_PASSWORD; - that.globalLogger.debug("Got e-mail service notifier password from environment"); - } else { - const erMsg = "Environment variable EMAIL_SERVICE_PASSWORD set, but no e-mail service is given in the " + - "notifier section of the configuration file."; - that.globalLogger.error(erMsg); - throw new Error(erMsg); - } - } - - // We want to get the password for authenticating to an SMTP server for sending notifier e-mails if it has been set, - // otherwise it will come from the config file - if (process.env.SMTP_PASSWORD) { - if (appConfiguration.notifier && appConfiguration.notifier.smtp) { - appConfiguration.notifier.smtp.password = process.env.SMTP_PASSWORD; - that.globalLogger.debug("Got smtp service notifier password from environment"); - } else { - const erMsg = "Environment variable SMTP_PASSWORD set, but no smtp entry is given in the notifier section of " + - "the configuration file."; - that.globalLogger.error(erMsg); - throw new Error(erMsg); - } - } - - // We want to get the duo api secret key from the environment if it has been set, otherwise it will come from the - // config file - if (process.env.DUO_API_SECRET_KEY) { - if (appConfiguration.duo_api) { - appConfiguration.duo_api.secret_key = process.env.DUO_API_SECRET_KEY; - that.globalLogger.debug("Got duo api secret from environment"); - } else { - const erMsg = - "Environment variable DUO_API_SECRET_KEY set, but no duo_api section given in the configuration file."; - that.globalLogger.error(erMsg); - throw new Error(erMsg); - } - } - - this.displayConfigurations(appConfiguration); - - return this.setup(appConfiguration, app, deps) - .then(function () { - return that.startServer(app, appConfiguration.port); - }); - } - - stop() { - this.httpServer.close(); - } -} - diff --git a/server/src/lib/ServerVariables.ts b/server/src/lib/ServerVariables.ts deleted file mode 100644 index cd3dd6dc8..000000000 --- a/server/src/lib/ServerVariables.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { IRequestLogger } from "./logging/IRequestLogger"; -import { ITotpHandler } from "./authentication/totp/ITotpHandler"; -import { IU2fHandler } from "./authentication/u2f/IU2fHandler"; -import { IUserDataStore } from "./storage/IUserDataStore"; -import { INotifier } from "./notifiers/INotifier"; -import { IRegulator } from "./regulation/IRegulator"; -import { Configuration } from "./configuration/schema/Configuration"; -import { IAuthorizer } from "./authorization/IAuthorizer"; -import { IUsersDatabase } from "./authentication/backends/IUsersDatabase"; - -export interface ServerVariables { - logger: IRequestLogger; - usersDatabase: IUsersDatabase; - totpHandler: ITotpHandler; - u2f: IU2fHandler; - userDataStore: IUserDataStore; - notifier: INotifier; - regulator: IRegulator; - config: Configuration; - authorizer: IAuthorizer; -} \ No newline at end of file diff --git a/server/src/lib/ServerVariablesInitializer.ts b/server/src/lib/ServerVariablesInitializer.ts deleted file mode 100644 index 3f2d6fabc..000000000 --- a/server/src/lib/ServerVariablesInitializer.ts +++ /dev/null @@ -1,105 +0,0 @@ -import BluebirdPromise = require("bluebird"); -import Nodemailer = require("nodemailer"); - -import { IRequestLogger } from "./logging/IRequestLogger"; - -import { TotpHandler } from "./authentication/totp/TotpHandler"; -import { NotifierFactory } from "./notifiers/NotifierFactory"; -import { MailSenderBuilder } from "./notifiers/MailSenderBuilder"; -import { LdapUsersDatabase } from "./authentication/backends/ldap/LdapUsersDatabase"; -import { ConnectorFactory } from "./authentication/backends/ldap/connector/ConnectorFactory"; - -import { UserDataStore } from "./storage/UserDataStore"; -import { Regulator } from "./regulation/Regulator"; -import Configuration = require("./configuration/schema/Configuration"); -import { CollectionFactoryFactory } from "./storage/CollectionFactoryFactory"; - -import { GlobalDependencies } from "../../types/Dependencies"; -import { ServerVariables } from "./ServerVariables"; -import { MongoClient } from "./connectors/mongo/MongoClient"; -import { IGlobalLogger } from "./logging/IGlobalLogger"; -import { SessionFactory } from "./authentication/backends/ldap/SessionFactory"; -import { IUsersDatabase } from "./authentication/backends/IUsersDatabase"; -import { FileUsersDatabase } from "./authentication/backends/file/FileUsersDatabase"; -import { Authorizer } from "./authorization/Authorizer"; - -class UserDataStoreFactory { - static create(config: Configuration.Configuration, globalLogger: IGlobalLogger): BluebirdPromise { - if (config.storage.local) { - const nedbOptions: Nedb.DataStoreOptions = { - filename: config.storage.local.path, - inMemoryOnly: config.storage.local.in_memory - }; - const collectionFactory = CollectionFactoryFactory.createNedb(nedbOptions); - return BluebirdPromise.resolve(new UserDataStore(collectionFactory)); - } - else if (config.storage.mongo) { - const mongoClient = new MongoClient( - config.storage.mongo, - globalLogger); - const collectionFactory = CollectionFactoryFactory.createMongo(mongoClient); - return BluebirdPromise.resolve(new UserDataStore(collectionFactory)); - } - - return BluebirdPromise.reject(new Error("Storage backend incorrectly configured.")); - } -} - -export class ServerVariablesInitializer { - static createUsersDatabase( - config: Configuration.Configuration, - deps: GlobalDependencies) - : IUsersDatabase { - - if (config.authentication_backend.ldap) { - const ldapConfig = config.authentication_backend.ldap; - return new LdapUsersDatabase( - new SessionFactory( - ldapConfig, - new ConnectorFactory(ldapConfig, deps.ldapjs, deps.winston), - deps.winston - ), - ldapConfig - ); - } - else if (config.authentication_backend.file) { - return new FileUsersDatabase(config.authentication_backend.file); - } - } - - static initialize( - config: Configuration.Configuration, - globalLogger: IGlobalLogger, - requestLogger: IRequestLogger, - deps: GlobalDependencies) - : BluebirdPromise { - - const mailSenderBuilder = - new MailSenderBuilder(Nodemailer); - const notifier = NotifierFactory.build( - config.notifier, mailSenderBuilder); - const authorizer = new Authorizer(config.access_control, deps.winston); - const totpHandler = new TotpHandler(deps.speakeasy); - const usersDatabase = this.createUsersDatabase( - config, deps); - - return UserDataStoreFactory.create(config, globalLogger) - .then(function (userDataStore: UserDataStore) { - const regulator = new Regulator(userDataStore, config.regulation.max_retries, - config.regulation.find_time, config.regulation.ban_time); - - const variables: ServerVariables = { - authorizer: authorizer, - config: config, - usersDatabase: usersDatabase, - logger: requestLogger, - notifier: notifier, - regulator: regulator, - totpHandler: totpHandler, - u2f: deps.u2f, - userDataStore: userDataStore - }; - return BluebirdPromise.resolve(variables); - }); - } -} diff --git a/server/src/lib/ServerVariablesMockBuilder.spec.ts b/server/src/lib/ServerVariablesMockBuilder.spec.ts deleted file mode 100644 index 8e0eae06b..000000000 --- a/server/src/lib/ServerVariablesMockBuilder.spec.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { ServerVariables } from "./ServerVariables"; - -import { Configuration } from "./configuration/schema/Configuration"; -import { IUsersDatabaseStub } from "./authentication/backends/IUsersDatabaseStub.spec"; -import AuthorizerStub from "./authorization/AuthorizerStub.spec"; -import { RequestLoggerStub } from "./logging/RequestLoggerStub.spec"; -import { NotifierStub } from "./notifiers/NotifierStub.spec"; -import { RegulatorStub } from "./regulation/RegulatorStub.spec"; -import { TotpHandlerStub } from "./authentication/totp/TotpHandlerStub.spec"; -import { UserDataStoreStub } from "./storage/UserDataStoreStub.spec"; -import { U2fHandlerStub } from "./authentication/u2f/U2fHandlerStub.spec"; - -export interface ServerVariablesMock { - authorizer: AuthorizerStub; - config: Configuration; - usersDatabase: IUsersDatabaseStub; - logger: RequestLoggerStub; - notifier: NotifierStub; - regulator: RegulatorStub; - totpHandler: TotpHandlerStub; - userDataStore: UserDataStoreStub; - u2f: U2fHandlerStub; -} - -export class ServerVariablesMockBuilder { - static build(enableLogging?: boolean): { variables: ServerVariables, mocks: ServerVariablesMock} { - const mocks: ServerVariablesMock = { - authorizer: new AuthorizerStub(), - config: { - access_control: {}, - totp: { - issuer: "authelia.com" - }, - authentication_backend: { - ldap: { - url: "ldap://ldap", - base_dn: "dc=example,dc=com", - user: "user", - password: "password", - mail_attribute: "mail", - additional_users_dn: "ou=users", - additional_groups_dn: "ou=groups", - users_filter: "cn={0}", - groups_filter: "member={dn}", - group_name_attribute: "cn" - }, - }, - logs_level: "debug", - notifier: {}, - port: 8080, - regulation: { - ban_time: 50, - find_time: 50, - max_retries: 3 - }, - session: { - secret: "my_secret", - domain: "mydomain" - }, - storage: {} - }, - usersDatabase: new IUsersDatabaseStub(), - logger: new RequestLoggerStub(enableLogging), - notifier: new NotifierStub(), - regulator: new RegulatorStub(), - totpHandler: new TotpHandlerStub(), - userDataStore: new UserDataStoreStub(), - u2f: new U2fHandlerStub() - }; - const vars: ServerVariables = { - authorizer: mocks.authorizer, - config: mocks.config, - usersDatabase: mocks.usersDatabase, - logger: mocks.logger, - notifier: mocks.notifier, - regulator: mocks.regulator, - totpHandler: mocks.totpHandler, - userDataStore: mocks.userDataStore, - u2f: mocks.u2f - }; - - return { - variables: vars, - mocks: mocks - }; - } -} \ No newline at end of file diff --git a/server/src/lib/SignMessage.ts b/server/src/lib/SignMessage.ts deleted file mode 100644 index 8031ed632..000000000 --- a/server/src/lib/SignMessage.ts +++ /dev/null @@ -1,6 +0,0 @@ -import U2f = require("u2f"); - -export interface SignMessage { - request: U2f.Request; - keyHandle: string; -} \ No newline at end of file diff --git a/server/src/lib/UserMessages.ts b/server/src/lib/UserMessages.ts deleted file mode 100644 index ce83d23f8..000000000 --- a/server/src/lib/UserMessages.ts +++ /dev/null @@ -1,25 +0,0 @@ - -export const AUTHENTICATION_FAILED = "Authentication failed. Please check your credentials."; -export const AUTHENTICATION_SUCCEEDED = "Authentication succeeded. You can now access your services."; - -export const CANNOT_REDIRECT_TO_EXTERNAL_DOMAIN = "Cannot redirect to an external domain."; - -export const AUTHENTICATION_U2F_FAILED = "Authentication failed. Have you already registered your device?"; -export const AUTHENTICATION_TOTP_FAILED = "Authentication failed. Have you already registered your secret?"; - -export const U2F_TRANSACTION_FINISH_FAILED = "U2F validation failed unexpectedly."; -export const PLEASE_TOUCH_TOKEN = "Please touch the token on your U2F device."; - -export const REGISTRATION_U2F_FAILED = "Registration of U2F device failed."; - -export const DIFFERENT_PASSWORDS = "The passwords are different."; -export const MISSING_PASSWORD = "You must enter your password twice."; -export const RESET_PASSWORD_FAILED = "An error occurred during password reset. Your password has not been changed."; - -// Password reset request -export const MISSING_USERNAME = "You must provide your username to reset your password."; -export const MAIL_SENT = "An email has been sent to you. Follow the link to change your password."; -export const MAIL_NOT_SENT = "The email cannot be sent. Please retry in few minutes."; - -export const UNAUTHORIZED_OPERATION = "You are not allowed to perform this operation."; -export const OPERATION_FAILED = "Operation failed."; \ No newline at end of file diff --git a/server/src/lib/api.ts b/server/src/lib/api.ts deleted file mode 100644 index 73af9af00..000000000 --- a/server/src/lib/api.ts +++ /dev/null @@ -1,333 +0,0 @@ -/** - * @apiDefine UserSession - * @apiHeader {String} Cookie Cookie containing "connect.sid", the user - * session token. - */ - -/** - * @apiDefine InternalError - * @apiError (Error 500) {String} error Internal error message. - */ - -/** - * @apiDefine IdentityValidationStart - * - * @apiSuccess (Success 204) status Identity validation has been initiated. - * @apiError (Error 403) AccessDenied Access is denied. - * @apiError (Error 400) InvalidIdentity User identity is invalid. - * @apiError (Error 500) {String} error Internal error message. - * - * @apiDescription This request issue an identity validation token for the user - * bound to the session. It sends a challenge to the email address set in the user - * LDAP entry. The user must visit the sent URL to complete the validation and - * continue the registration process. - */ - -/** - * @apiDefine IdentityValidationFinish - * @apiParam {String} identity_token The one-time identity validation token provided in the email. - * @apiSuccess (Success 200) {String} content The content of the page. - * @apiError (Error 403) AccessDenied Access is denied. - * @apiError (Error 500) {String} error Internal error message. - */ - -/** - * @api {post} /api/secondfactor/u2f/register Complete U2F registration - * @apiName FinishU2FRegistration - * @apiGroup U2F - * @apiVersion 1.0.0 - * @apiUse UserSession - * @apiUse InternalError - * - * @apiSuccess (Success 302) Redirect to the URL that has been stored during last call to /api/verify. - * - * @apiDescription Complete U2F registration request. - */ -export const SECOND_FACTOR_U2F_REGISTER_POST = "/api/u2f/register"; - -/** - * @api {get} /api/u2f/register_request Start U2F registration - * @apiName StartU2FRegistration - * @apiGroup U2F - * @apiVersion 1.0.0 - * @apiUse UserSession - * @apiUse InternalError - * - * @apiSuccess (Success 200) authentication_request The U2F registration request. - * @apiError (Error 403) {none} error Unexpected identity validation challenge. - * - * @apiDescription Initiate a U2F device registration request. - */ -export const SECOND_FACTOR_U2F_REGISTER_REQUEST_GET = "/api/u2f/register_request"; - -/** - * @api {post} /api/u2f/sign Complete U2F authentication - * @apiName CompleteU2FAuthentication - * @apiGroup U2F - * @apiVersion 1.0.0 - * @apiUse UserSession - * @apiUse InternalError - * - * @apiSuccess (Success 302) Redirect to the URL that has been stored during last call to /api/verify. - * @apiError (Error 403) {none} error No authentication request has been provided. - * - * @apiDescription Complete authentication request of the U2F device. - */ -export const SECOND_FACTOR_U2F_SIGN_POST = "/api/u2f/sign"; - -/** - * @api {get} /api/u2f/sign_request Start U2F authentication - * @apiName StartU2FAuthentication - * @apiGroup U2F - * @apiVersion 1.0.0 - * @apiUse UserSession - * @apiUse InternalError - * - * @apiSuccess (Success 200) authentication_request The U2F authentication request. - * @apiError (Error 401) {none} error There is no key registered for user in session. - * - * @apiDescription Initiate an authentication request using a U2F device. - */ -export const SECOND_FACTOR_U2F_SIGN_REQUEST_GET = "/api/u2f/sign_request"; - -/** - * @api {post} /api/totp Complete TOTP authentication - * @apiName ValidateTOTPSecondFactor - * @apiGroup TOTP - * @apiVersion 1.0.0 - * @apiUse UserSession - * @apiUse InternalError - * - * @apiParam {String} token TOTP token. - * - * @apiSuccess (Success 302) Redirect to the URL that has been stored during last call to /api/verify. - * @apiError (Error 401) {none} error TOTP token is invalid. - * - * @apiDescription Verify TOTP token. The user is authenticated upon success. - */ -export const SECOND_FACTOR_TOTP_POST = "/api/totp"; - -/** - * @api {post} /api/duo-push Complete Duo Push Factor - * @apiName ValidateDuoPushSecondFactor - * @apiGroup DuoPush - * @apiVersion 1.0.0 - * @apiUse UserSession - * @apiUse InternalError - * - * @apiSuccess (Success 302) Redirect to the URL that has been stored during last call to /api/verify. - * @apiError (Error 401) {none} error TOTP token is invalid. - * - * @apiDescription Verify TOTP token. The user is authenticated upon success. - */ -export const SECOND_FACTOR_DUO_PUSH_POST = "/api/duo-push"; - - -/** - * @api {get} /api/secondfactor/u2f/identity/start Start U2F registration identity validation - * @apiName RequestU2FRegistration - * @apiGroup U2F - * @apiVersion 1.0.0 - * @apiUse UserSession - * @apiUse IdentityValidationStart - */ -export const SECOND_FACTOR_U2F_IDENTITY_START_POST = "/api/secondfactor/u2f/identity/start"; - -/** - * @api {get} /api/secondfactor/u2f/identity/finish Finish U2F registration identity validation - * @apiName ServeU2FRegistrationPage - * @apiGroup U2F - * @apiVersion 1.0.0 - * @apiUse UserSession - * @apiUse IdentityValidationFinish - * - * @apiDescription Serves the U2F registration page that asks the user to - * touch the token of the U2F device. - */ -export const SECOND_FACTOR_U2F_IDENTITY_FINISH_POST = "/api/secondfactor/u2f/identity/finish"; - - - -/** - * @api {get} /api/secondfactor/totp/identity/start Start TOTP registration identity validation - * @apiName StartTOTPRegistration - * @apiGroup TOTP - * @apiVersion 1.0.0 - * @apiUse UserSession - * @apiUse IdentityValidationStart - * - * @apiDescription Initiates the identity validation - */ -export const SECOND_FACTOR_TOTP_IDENTITY_START_POST = "/api/secondfactor/totp/identity/start"; - - - -/** - * @api {get} /api/secondfactor/totp/identity/finish Finish TOTP registration identity validation - * @apiName FinishTOTPRegistration - * @apiGroup TOTP - * @apiVersion 1.0.0 - * @apiUse UserSession - * @apiUse IdentityValidationFinish - * - * @apiDescription Serves the TOTP registration page that displays the secret. - * The secret is a QRCode and a base32 secret. - */ -export const SECOND_FACTOR_TOTP_IDENTITY_FINISH_POST = "/api/secondfactor/totp/identity/finish"; - -/** - * @api {get} /api/secondfactor/preferences Retrieve the user preferences. - * @apiName GetUserPreferences - * @apiGroup 2FA - * @apiVersion 1.0.0 - * @apiUse UserSession - * - * @apiDescription Retrieve the user preferences sucha as the prefered method to use (TOTP or U2F). - */ -export const SECOND_FACTOR_PREFERENCES_GET = "/api/secondfactor/preferences"; - -/** - * @api {post} /api/secondfactor/preferences Set the user preferences. - * @apiName SetUserPreferences - * @apiGroup 2FA - * @apiVersion 1.0.0 - * @apiUse UserSession - * - * @apiDescription Set the user preferences sucha as the prefered method to use (TOTP or U2F). - */ -export const SECOND_FACTOR_PREFERENCES_POST = "/api/secondfactor/preferences"; - -/** - * @api {post} /api/secondfactor/available List the available methods. - * @apiName GetAvailableMethods - * @apiGroup 2FA - * @apiVersion 1.0.0 - * - * @apiDescription Get the available 2FA methods. - */ -export const SECOND_FACTOR_AVAILABLE_GET = "/api/secondfactor/available"; - - -/** - * @api {post} /api/password-reset Set new password - * @apiName SetNewLDAPPassword - * @apiGroup PasswordReset - * @apiVersion 1.0.0 - * @apiUse UserSession - * - * @apiParam {String} password New password - * - * @apiDescription Set a new password for the user. - */ -export const RESET_PASSWORD_FORM_POST = "/api/password-reset"; - - - -/** - * @api {get} /password-reset/request Request username - * @apiName ServePasswordResetPage - * @apiGroup PasswordReset - * @apiVersion 1.0.0 - * @apiUse UserSession - * - * @apiDescription Serve a page that requires the username. - */ -export const RESET_PASSWORD_REQUEST_GET = "/api/password-reset/request"; - - - -/** - * @api {get} /password-reset/identity/start Start password reset request - * @apiName StartPasswordResetRequest - * @apiGroup PasswordReset - * @apiVersion 1.0.0 - * @apiUse UserSession - * @apiUse IdentityValidationStart - * - * @apiDescription Start password reset request. - */ -export const RESET_PASSWORD_IDENTITY_START_GET = "/api/password-reset/identity/start"; - - - -/** - * @api {post} /reset-password/request Finish password reset request - * @apiName FinishPasswordResetRequest - * @apiGroup PasswordReset - * @apiVersion 1.0.0 - * @apiUse UserSession - * @apiUse IdentityValidationFinish - * - * @apiDescription Start password reset request. - */ -export const RESET_PASSWORD_IDENTITY_FINISH_GET = "/api/password-reset/identity/finish"; - - - -/** - * @api {post} /1stfactor Bind user against LDAP - * @apiName ValidateFirstFactor - * @apiGroup Authentication - * @apiVersion 1.0.0 - * @apiUse UserSession - * @apiUse InternalError - * - * @apiParam {String} username User username. - * @apiParam {String} password User password. - * - * @apiSuccess (Success 204) status 1st factor is validated. - * @apiError (Error 401) {none} error 1st factor is not validated. - * @apiError (Error 401) {none} error Access has been restricted after too - * many authentication attempts - * - * @apiDescription Verify credentials against the LDAP. - */ -export const FIRST_FACTOR_POST = "/api/firstfactor"; - -/** - * @api {get} /state Authentication state - * @apiName State - * @apiGroup Authentication - * @apiVersion 1.0.0 - * - * @apiSuccess (Success 200) A dict containing the username and the authentication - * level - * - * @apiDescription Get the authentication state of the user based on the cookie. - */ -export const STATE_GET = "/api/state"; - -/** - * @api {get} /api/verify Verify user authentication - * @apiName VerifyAuthentication - * @apiGroup Verification - * @apiVersion 1.0.0 - * @apiUse UserSession - * - * @apiParam {String} redirect Optional parameter set to the url where the user - * is redirected if access is refused. It is mainly used by Traefik that does - * not control the redirection itself. - * - * @apiSuccess (Success 204) status The user is authenticated. - * @apiError (Error 302) redirect The user is redirected if redirect parameter is provided. - * @apiError (Error 401) status The user get an error if access failed - * - * @apiDescription Verify that the user is authenticated, i.e., the two - * factors have been validated. - * If the user is authenticated the response headers Remote-User and Remote-Groups - * are set. Remote-User contains the user id of the currently logged in user and Remote-Groups - * a comma separated list of assigned groups. - */ -export const VERIFY_GET = "/api/verify"; - -/** - * @api {post} /api/logout Logout procedure - * @apiName Logout - * @apiGroup Authentication - * @apiVersion 1.0.0 - * - * @apiSuccess (Success 200) - * - * @apiDescription Resets the session to logout the user. - */ -export const LOGOUT_POST = "/api/logout"; \ No newline at end of file diff --git a/server/src/lib/authentication/AuthenticationError.ts b/server/src/lib/authentication/AuthenticationError.ts deleted file mode 100644 index 9285ac49c..000000000 --- a/server/src/lib/authentication/AuthenticationError.ts +++ /dev/null @@ -1,11 +0,0 @@ - - -// Error thrown when the authentication failed when checking -// user/password. -class AuthenticationError extends Error { - constructor(msg: string) { - super(msg); - } -} - -export default AuthenticationError; \ No newline at end of file diff --git a/server/src/lib/authentication/Level.ts b/server/src/lib/authentication/Level.ts deleted file mode 100644 index 9cf7081fd..000000000 --- a/server/src/lib/authentication/Level.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { default as Level } from "../AuthenticationLevel"; - -export { Level }; diff --git a/server/src/lib/authentication/backends/GroupsAndEmails.ts b/server/src/lib/authentication/backends/GroupsAndEmails.ts deleted file mode 100644 index 3434ba66f..000000000 --- a/server/src/lib/authentication/backends/GroupsAndEmails.ts +++ /dev/null @@ -1,5 +0,0 @@ - -export interface GroupsAndEmails { - groups: string[]; - emails: string[]; -} diff --git a/server/src/lib/authentication/backends/IUsersDatabase.ts b/server/src/lib/authentication/backends/IUsersDatabase.ts deleted file mode 100644 index d7fa13b7a..000000000 --- a/server/src/lib/authentication/backends/IUsersDatabase.ts +++ /dev/null @@ -1,10 +0,0 @@ -import Bluebird = require("bluebird"); - -import { GroupsAndEmails } from "./GroupsAndEmails"; - -export interface IUsersDatabase { - checkUserPassword(username: string, password: string): Bluebird; - getEmails(username: string): Bluebird; - getGroups(username: string): Bluebird; - updatePassword(username: string, newPassword: string): Bluebird; -} \ No newline at end of file diff --git a/server/src/lib/authentication/backends/IUsersDatabaseStub.spec.ts b/server/src/lib/authentication/backends/IUsersDatabaseStub.spec.ts deleted file mode 100644 index 19341a5dd..000000000 --- a/server/src/lib/authentication/backends/IUsersDatabaseStub.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import Bluebird = require("bluebird"); -import Sinon = require("sinon"); - -import { IUsersDatabase } from "./IUsersDatabase"; -import { GroupsAndEmails } from "./GroupsAndEmails"; - -export class IUsersDatabaseStub implements IUsersDatabase { - checkUserPasswordStub: Sinon.SinonStub; - getEmailsStub: Sinon.SinonStub; - getGroupsStub: Sinon.SinonStub; - updatePasswordStub: Sinon.SinonStub; - - constructor() { - this.checkUserPasswordStub = Sinon.stub(); - this.getEmailsStub = Sinon.stub(); - this.getGroupsStub = Sinon.stub(); - this.updatePasswordStub = Sinon.stub(); - } - - checkUserPassword(username: string, password: string): Bluebird { - return this.checkUserPasswordStub(username, password); - } - - getEmails(username: string): Bluebird { - return this.getEmailsStub(username); - } - - getGroups(username: string): Bluebird { - return this.getGroupsStub(username); - } - - updatePassword(username: string, newPassword: string): Bluebird { - return this.updatePasswordStub(username, newPassword); - } -} \ No newline at end of file diff --git a/server/src/lib/authentication/backends/file/FileUsersDatabase.spec.ts b/server/src/lib/authentication/backends/file/FileUsersDatabase.spec.ts deleted file mode 100644 index a258a78f7..000000000 --- a/server/src/lib/authentication/backends/file/FileUsersDatabase.spec.ts +++ /dev/null @@ -1,224 +0,0 @@ -import Assert = require("assert"); -import Bluebird = require("bluebird"); -import Fs = require("fs"); -import Sinon = require("sinon"); -import Tmp = require("tmp"); - -import { FileUsersDatabase } from "./FileUsersDatabase"; -import { FileUsersDatabaseConfiguration } from "../../../configuration/schema/FileUsersDatabaseConfiguration"; -import { HashGenerator } from "../../../utils/HashGenerator"; - -const GOOD_DATABASE = ` -users: - john: - password: "{CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/" - email: john.doe@authelia.com - groups: - - admins - - dev - - harry: - password: "{CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/" - emails: harry.potter@authelia.com - groups: [] -`; - -const BAD_HASH = ` -users: - john: - password: "{CRYPT}$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/" - email: john.doe@authelia.com - groups: - - admins - - dev -`; - -const NO_PASSWORD_DATABASE = ` -users: - john: - email: john.doe@authelia.com - groups: - - admins - - dev -`; - -const NO_EMAIL_DATABASE = ` -users: - john: - password: "{CRYPT}$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/" - groups: - - admins - - dev -`; - -const SINGLE_USER_DATABASE = ` -users: - john: - password: "{CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/" - email: john.doe@authelia.com - groups: - - admins - - dev -` - -function createTmpFileFrom(yaml: string) { - const tmpFileAsync = Bluebird.promisify(Tmp.file); - return tmpFileAsync() - .then((path: string) => { - Fs.writeFileSync(path, yaml, "utf-8"); - return Bluebird.resolve(path); - }); -} - -describe("authentication/backends/file/FileUsersDatabase", function() { - let configuration: FileUsersDatabaseConfiguration; - - describe("checkUserPassword", () => { - describe("good config", () => { - beforeEach(() => { - return createTmpFileFrom(GOOD_DATABASE) - .then((path: string) => configuration = { - path: path - }); - }); - - it("should succeed", () => { - const usersDatabase = new FileUsersDatabase(configuration); - return usersDatabase.checkUserPassword("john", "password") - .then((groupsAndEmails) => { - Assert.deepEqual(groupsAndEmails.groups, ["admins", "dev"]); - Assert.deepEqual(groupsAndEmails.emails, ["john.doe@authelia.com"]); - }); - }); - - it("should fail when password is wrong", () => { - const usersDatabase = new FileUsersDatabase(configuration); - return usersDatabase.checkUserPassword("john", "bad_password") - .then(() => Bluebird.reject(new Error("should not be here."))) - .catch((err) => { - return Bluebird.resolve(); - }); - }); - - it("should fail when user does not exist", () => { - const usersDatabase = new FileUsersDatabase(configuration); - return usersDatabase.checkUserPassword("no_user", "password") - .then(() => Bluebird.reject(new Error("should not be here."))) - .catch((err) => { - return Bluebird.resolve(); - }); - }); - }); - - describe("bad hash", () => { - beforeEach(() => { - return createTmpFileFrom(GOOD_DATABASE) - .then((path: string) => configuration = { - path: path - }); - }); - - it("should fail when hash is wrong", () => { - const usersDatabase = new FileUsersDatabase(configuration); - return usersDatabase.checkUserPassword("john", "password") - .then(() => Bluebird.reject(new Error("should not be here."))) - .catch((err) => { - return Bluebird.resolve(); - }); - }); - }); - - describe("no password", () => { - beforeEach(() => { - return createTmpFileFrom(NO_PASSWORD_DATABASE) - .then((path: string) => configuration = { - path: path - }); - }); - - it("should fail", () => { - const usersDatabase = new FileUsersDatabase(configuration); - return usersDatabase.checkUserPassword("john", "password") - .then(() => Bluebird.reject(new Error("should not be here."))) - .catch((err) => { - return Bluebird.resolve(); - }); - }); - }); - }); - - describe("getEmails", () => { - describe("good config", () => { - beforeEach(() => { - return createTmpFileFrom(GOOD_DATABASE) - .then((path: string) => configuration = { - path: path - }); - }); - - it("should succeed", () => { - const usersDatabase = new FileUsersDatabase(configuration); - return usersDatabase.getEmails("john") - .then((emails) => { - Assert.deepEqual(emails, ["john.doe@authelia.com"]); - }); - }); - - it("should fail when user does not exist", () => { - const usersDatabase = new FileUsersDatabase(configuration); - return usersDatabase.getEmails("no_user") - .then(() => Bluebird.reject(new Error("should not be here."))) - .catch((err) => { - return Bluebird.resolve(); - }); - }); - }); - - describe("no email provided", () => { - beforeEach(() => { - return createTmpFileFrom(NO_EMAIL_DATABASE) - .then((path: string) => configuration = { - path: path - }); - }); - - it("should fail", () => { - const usersDatabase = new FileUsersDatabase(configuration); - return usersDatabase.getEmails("john") - .then(() => Bluebird.reject(new Error("should not be here."))) - .catch((err) => { - return Bluebird.resolve(); - }); - }); - }); - }); - - describe("updatePassword", () => { - beforeEach(() => { - return createTmpFileFrom(SINGLE_USER_DATABASE) - .then((path: string) => configuration = { - path: path - }); - }); - - it("should succeed", () => { - const usersDatabase = new FileUsersDatabase(configuration); - const NEW_HASH = "{CRYPT}$6$rounds=500000$Qw6MhgADvLyYMEq9$ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - const stub = Sinon.stub(HashGenerator, "ssha512").returns(Bluebird.resolve(NEW_HASH)); - return usersDatabase.updatePassword("john", "mypassword") - .then(() => { - const content = Fs.readFileSync(configuration.path, "utf-8"); - const matches = content.match(/password: '(.+)'/); - Assert.equal(matches[1], NEW_HASH); - }) - .finally(() => stub.restore()); - }); - - it("should fail when user does not exist", () => { - const usersDatabase = new FileUsersDatabase(configuration); - return usersDatabase.updatePassword("bad_user", "mypassword") - .then(() => Bluebird.reject(new Error("should not be here"))) - .catch(() => Bluebird.resolve()); - }); - }); -}); \ No newline at end of file diff --git a/server/src/lib/authentication/backends/file/FileUsersDatabase.ts b/server/src/lib/authentication/backends/file/FileUsersDatabase.ts deleted file mode 100644 index 32bbff856..000000000 --- a/server/src/lib/authentication/backends/file/FileUsersDatabase.ts +++ /dev/null @@ -1,183 +0,0 @@ -import Bluebird = require("bluebird"); -import Fs = require("fs"); -import Yaml = require("yamljs"); - -import { FileUsersDatabaseConfiguration } - from "../../../configuration/schema/FileUsersDatabaseConfiguration"; -import { GroupsAndEmails } from "../GroupsAndEmails"; -import { IUsersDatabase } from "../IUsersDatabase"; -import { HashGenerator } from "../../../utils/HashGenerator"; -import { ReadWriteQueue } from "./ReadWriteQueue"; -import AuthenticationError from "../../AuthenticationError"; - -const loadAsync = Bluebird.promisify(Yaml.load); - -export class FileUsersDatabase implements IUsersDatabase { - private configuration: FileUsersDatabaseConfiguration; - private queue: ReadWriteQueue; - - constructor(configuration: FileUsersDatabaseConfiguration) { - this.configuration = configuration; - this.queue = new ReadWriteQueue(this.configuration.path); - } - - /** - * Read database from file. - * It enqueues the read task so that it is scheduled - * between other reads and writes. - */ - private readDatabase(): Bluebird { - return new Bluebird((resolve, reject) => { - this.queue.read((err: Error, data: string) => { - if (err) { - reject(err); - return; - } - resolve(data); - this.queue.next(); - }); - }) - .then((content) => { - const database = Yaml.parse(content); - if (!database) { - return Bluebird.reject(new Error("Unable to parse YAML file.")); - } - return Bluebird.resolve(database); - }); - } - - /** - * Checks the user exists in the database. - */ - private checkUserExists( - database: any, - username: string) - : Bluebird { - if (!(username in database.users)) { - return Bluebird.reject( - new Error(`User ${username} does not exist in database.`)); - } - return Bluebird.resolve(); - } - - /** - * Check the password of a given user. - */ - private checkPassword( - database: any, - username: string, - password: string) - : Bluebird { - const storedHash: string = database.users[username].password; - const matches = storedHash.match(/rounds=([0-9]+)\$([a-zA-z0-9./]+)\$/); - if (!(matches && matches.length == 3)) { - return Bluebird.reject(new Error("Unable to detect the hash salt and rounds. " + - "Make sure the password is hashed with SSHA512.")); - } - - const rounds: number = parseInt(matches[1]); - const salt = matches[2]; - - return HashGenerator.ssha512(password, rounds, salt) - .then((hash: string) => { - if (hash !== storedHash) { - return Bluebird.reject(new AuthenticationError("Wrong username/password.")); - } - return Bluebird.resolve(); - }); - } - - /** - * Retrieve email addresses of a given user. - */ - private retrieveEmails( - database: any, - username: string) - : Bluebird { - if (!("email" in database.users[username])) { - return Bluebird.reject( - new Error(`User ${username} has no email address.`)); - } - return Bluebird.resolve( - [database.users[username].email]); - } - - private retrieveGroups( - database: any, - username: string) - : Bluebird { - if (!("groups" in database.users[username])) { - return Bluebird.resolve([]); - } - return Bluebird.resolve( - database.users[username].groups); - } - - private replacePassword( - database: any, - username: string, - newPassword: string) - : Bluebird { - const that = this; - return HashGenerator.ssha512(newPassword) - .then((hash) => { - database.users[username].password = hash; - const str = Yaml.stringify(database, 4, 2); - return Bluebird.resolve(str); - }) - .then((content: string) => { - return new Bluebird((resolve, reject) => { - that.queue.write(content, (err) => { - if (err) { - return reject(err); - } - resolve(); - that.queue.next(); - }); - }); - }); - } - - checkUserPassword( - username: string, - password: string) - : Bluebird { - return this.readDatabase() - .then((database) => { - return this.checkUserExists(database, username) - .then(() => this.checkPassword(database, username, password)) - .then(() => { - return Bluebird.join( - this.retrieveEmails(database, username), - this.retrieveGroups(database, username) - ).spread((emails: string[], groups: string[]) => { - return { emails: emails, groups: groups }; - }); - }); - }); - } - - getEmails(username: string): Bluebird { - return this.readDatabase() - .then((database) => { - return this.checkUserExists(database, username) - .then(() => this.retrieveEmails(database, username)); - }); - } - - getGroups(username: string): Bluebird { - return this.readDatabase() - .then((database) => { - return this.checkUserExists(database, username) - .then(() => this.retrieveGroups(database, username)); - }); - } - - updatePassword(username: string, newPassword: string): Bluebird { - return this.readDatabase() - .then((database) => { - return this.checkUserExists(database, username) - .then(() => this.replacePassword(database, username, newPassword)); - }); - } -} \ No newline at end of file diff --git a/server/src/lib/authentication/backends/file/ReadWriteQueue.ts b/server/src/lib/authentication/backends/file/ReadWriteQueue.ts deleted file mode 100644 index 957ddaec5..000000000 --- a/server/src/lib/authentication/backends/file/ReadWriteQueue.ts +++ /dev/null @@ -1,60 +0,0 @@ -import Fs = require("fs"); - -type Callback = (err: Error, data?: string) => void; -type ContentAndCallback = [string, Callback] | [string, string, Callback]; - -/** - * WriteQueue is a queue synchronizing writes to a file. - * - * Example of use: - * - * queue.add(mycontent, (err) => { - * // do whatever you want here. - * queue.next(); - * }) - */ -export class ReadWriteQueue { - private filePath: string; - private queue: ContentAndCallback[]; - - constructor (filePath: string) { - this.queue = []; - this.filePath = filePath; - } - - next () { - if (this.queue.length === 0) - return; - - const task = this.queue[0]; - - if (task[0] == "write") { - Fs.writeFile(this.filePath, task[1], "utf-8", (err) => { - this.queue.shift(); - const cb = task[2] as Callback; - cb(err); - }); - } - else if (task[0] == "read") { - Fs.readFile(this.filePath, { encoding: "utf-8"} , (err, data) => { - this.queue.shift(); - const cb = task[1] as Callback; - cb(err, data); - }); - } - } - - write (content: string, cb: Callback) { - this.queue.push(["write", content, cb]); - if (this.queue.length === 1) { - this.next(); - } - } - - read (cb: Callback) { - this.queue.push(["read", cb]); - if (this.queue.length === 1) { - this.next(); - } - } -} \ No newline at end of file diff --git a/server/src/lib/authentication/backends/ldap/ISession.ts b/server/src/lib/authentication/backends/ldap/ISession.ts deleted file mode 100644 index da2c74433..000000000 --- a/server/src/lib/authentication/backends/ldap/ISession.ts +++ /dev/null @@ -1,12 +0,0 @@ - -import BluebirdPromise = require("bluebird"); - -export interface ISession { - open(): BluebirdPromise; - close(): BluebirdPromise; - - searchUserDn(username: string): BluebirdPromise; - searchEmails(username: string): BluebirdPromise; - searchGroups(username: string): BluebirdPromise; - modifyPassword(username: string, newPassword: string): BluebirdPromise; -} \ No newline at end of file diff --git a/server/src/lib/authentication/backends/ldap/ISessionFactory.ts b/server/src/lib/authentication/backends/ldap/ISessionFactory.ts deleted file mode 100644 index 014d1eea5..000000000 --- a/server/src/lib/authentication/backends/ldap/ISessionFactory.ts +++ /dev/null @@ -1,6 +0,0 @@ - -import { ISession } from "./ISession"; - -export interface ISessionFactory { - create(userDN: string, password: string): ISession; -} \ No newline at end of file diff --git a/server/src/lib/authentication/backends/ldap/LdapUsersDatabase.spec.ts b/server/src/lib/authentication/backends/ldap/LdapUsersDatabase.spec.ts deleted file mode 100644 index f4a6e6306..000000000 --- a/server/src/lib/authentication/backends/ldap/LdapUsersDatabase.spec.ts +++ /dev/null @@ -1,386 +0,0 @@ -import Assert = require("assert"); -import Bluebird = require("bluebird"); - -import { LdapUsersDatabase } from "./LdapUsersDatabase"; - -import { SessionFactoryStub } from "./SessionFactoryStub.spec"; -import { SessionStub } from "./SessionStub.spec"; - -const ADMIN_USER_DN = "cn=admin,dc=example,dc=com"; -const ADMIN_PASSWORD = "password"; - -describe("ldap/connector/LdapUsersDatabase", function() { - let sessionFactory: SessionFactoryStub; - let usersDatabase: LdapUsersDatabase; - - const USERNAME = "user"; - const PASSWORD = "pass"; - const NEW_PASSWORD = "pass2"; - - const LDAP_CONFIG = { - url: "http://localhost:324", - additional_users_dn: "ou=users", - additional_groups_dn: "ou=groups", - base_dn: "dc=example,dc=com", - users_filter: "cn={0}", - groups_filter: "member={0}", - mail_attribute: "mail", - group_name_attribute: "cn", - user: ADMIN_USER_DN, - password: ADMIN_PASSWORD - }; - - beforeEach(function() { - sessionFactory = new SessionFactoryStub(); - usersDatabase = new LdapUsersDatabase(sessionFactory, LDAP_CONFIG); - }) - - describe("checkUserPassword", function() { - it("should return groups and emails when user/password matches", function() { - const USER_DN = `cn=${USERNAME},dc=example,dc=com`; - const emails = ["email1", "email2"]; - const groups = ["group1", "group2"]; - - const adminSession = new SessionStub(); - const userSession = new SessionStub(); - - sessionFactory.createStub.withArgs(ADMIN_USER_DN, ADMIN_PASSWORD).returns(adminSession); - sessionFactory.createStub.withArgs(USER_DN, PASSWORD).returns(userSession); - - adminSession.openStub.returns(Bluebird.resolve()); - adminSession.closeStub.returns(Bluebird.resolve()); - adminSession.searchUserDnStub.returns(Bluebird.resolve(USER_DN)); - adminSession.searchEmailsStub.withArgs(USERNAME).returns(Bluebird.resolve(emails)); - adminSession.searchGroupsStub.withArgs(USERNAME).returns(Bluebird.resolve(groups)); - - userSession.openStub.returns(Bluebird.resolve()); - userSession.closeStub.returns(Bluebird.resolve()); - - return usersDatabase.checkUserPassword(USERNAME, PASSWORD) - .then((groupsAndEmails) => { - Assert.deepEqual(groupsAndEmails.groups, groups); - Assert.deepEqual(groupsAndEmails.emails, emails); - }) - }); - - it("should fail when username/password is wrong", function() { - const USER_DN = `cn=${USERNAME},dc=example,dc=com`; - - const adminSession = new SessionStub(); - const userSession = new SessionStub(); - - sessionFactory.createStub.withArgs(ADMIN_USER_DN, ADMIN_PASSWORD).returns(adminSession); - sessionFactory.createStub.withArgs(USER_DN, PASSWORD).returns(userSession); - - adminSession.openStub.returns(Bluebird.resolve()); - adminSession.closeStub.returns(Bluebird.resolve()); - adminSession.searchUserDnStub.returns(Bluebird.resolve(USER_DN)); - - userSession.openStub.returns(Bluebird.reject(new Error("Failed binding"))); - userSession.closeStub.returns(Bluebird.resolve()); - - return usersDatabase.checkUserPassword(USERNAME, PASSWORD) - .then(() => Bluebird.reject(new Error("should not be here"))) - .catch((err) => { - Assert(userSession.closeStub.called); - Assert(adminSession.closeStub.called); - return Bluebird.resolve(); - }) - }); - - it("should fail when admin binding fails", function() { - const USER_DN = `cn=${USERNAME},dc=example,dc=com`; - - const adminSession = new SessionStub(); - const userSession = new SessionStub(); - - sessionFactory.createStub.withArgs(ADMIN_USER_DN, ADMIN_PASSWORD).returns(adminSession); - sessionFactory.createStub.withArgs(USER_DN, PASSWORD).returns(userSession); - - adminSession.openStub.returns(Bluebird.reject(new Error("Failed binding"))); - adminSession.closeStub.returns(Bluebird.resolve()); - adminSession.searchUserDnStub.returns(Bluebird.resolve(USER_DN)); - - return usersDatabase.checkUserPassword(USERNAME, PASSWORD) - .then(() => Bluebird.reject(new Error("should not be here"))) - .catch((err) => { - Assert(userSession.closeStub.notCalled); - Assert(adminSession.closeStub.called); - return Bluebird.resolve(); - }) - }); - - it("should fail when search for user dn fails", function() { - const USER_DN = `cn=${USERNAME},dc=example,dc=com`; - - const adminSession = new SessionStub(); - const userSession = new SessionStub(); - - sessionFactory.createStub.withArgs(ADMIN_USER_DN, ADMIN_PASSWORD).returns(adminSession); - sessionFactory.createStub.withArgs(USER_DN, PASSWORD).returns(userSession); - - adminSession.openStub.returns(Bluebird.resolve()); - adminSession.closeStub.returns(Bluebird.resolve()); - adminSession.searchUserDnStub.returns(Bluebird.reject(new Error("Failed searching user dn"))); - - return usersDatabase.checkUserPassword(USERNAME, PASSWORD) - .then(() => Bluebird.reject(new Error("should not be here"))) - .catch((err) => { - Assert(userSession.closeStub.notCalled); - Assert(adminSession.closeStub.called); - return Bluebird.resolve(); - }) - }); - - it("should fail when groups retrieval fails", function() { - const USER_DN = `cn=${USERNAME},dc=example,dc=com`; - const emails = ["email1", "email2"]; - const groups = ["group1", "group2"]; - - const adminSession = new SessionStub(); - const userSession = new SessionStub(); - - sessionFactory.createStub.withArgs(ADMIN_USER_DN, ADMIN_PASSWORD).returns(adminSession); - sessionFactory.createStub.withArgs(USER_DN, PASSWORD).returns(userSession); - - adminSession.openStub.returns(Bluebird.resolve()); - adminSession.closeStub.returns(Bluebird.resolve()); - adminSession.searchUserDnStub.returns(Bluebird.resolve(USER_DN)); - adminSession.searchEmailsStub.withArgs(USERNAME) - .returns(Bluebird.resolve(emails)); - adminSession.searchGroupsStub.withArgs(USERNAME) - .returns(Bluebird.reject(new Error("Failed retrieving groups"))); - - userSession.openStub.returns(Bluebird.resolve()); - userSession.closeStub.returns(Bluebird.resolve()); - - return usersDatabase.checkUserPassword(USERNAME, PASSWORD) - .then((groupsAndEmails) => Bluebird.reject(new Error("should not be here"))) - .catch((err) => { - Assert(userSession.closeStub.called); - Assert(adminSession.closeStub.called); - }) - }); - - it("should fail when emails retrieval fails", function() { - const USER_DN = `cn=${USERNAME},dc=example,dc=com`; - const emails = ["email1", "email2"]; - const groups = ["group1", "group2"]; - - const adminSession = new SessionStub(); - const userSession = new SessionStub(); - - sessionFactory.createStub.withArgs(ADMIN_USER_DN, ADMIN_PASSWORD).returns(adminSession); - sessionFactory.createStub.withArgs(USER_DN, PASSWORD).returns(userSession); - - adminSession.openStub.returns(Bluebird.resolve()); - adminSession.closeStub.returns(Bluebird.resolve()); - adminSession.searchUserDnStub.returns(Bluebird.resolve(USER_DN)); - adminSession.searchEmailsStub.withArgs(USERNAME) - .returns(Bluebird.reject(new Error("Emails retrieval failed"))); - adminSession.searchGroupsStub.withArgs(USERNAME) - .returns(Bluebird.resolve(groups)); - - userSession.openStub.returns(Bluebird.resolve()); - userSession.closeStub.returns(Bluebird.resolve()); - - return usersDatabase.checkUserPassword(USERNAME, PASSWORD) - .then((groupsAndEmails) => Bluebird.reject(new Error("should not be here"))) - .catch((err) => { - Assert(userSession.closeStub.called); - Assert(adminSession.closeStub.called); - }) - }); - }); - - describe("getEmails", function() { - it("should succefully retrieves email", () => { - const emails = ["email1", "email2"]; - const session = new SessionStub(); - sessionFactory.createStub.withArgs(ADMIN_USER_DN, ADMIN_PASSWORD).returns(session); - - session.openStub.returns(Bluebird.resolve()); - session.closeStub.returns(Bluebird.resolve()); - session.searchEmailsStub.returns(Bluebird.resolve(emails)); - - return usersDatabase.getEmails(USERNAME) - .then((foundEmails) => { - Assert(session.closeStub.called); - Assert.deepEqual(foundEmails, emails); - }) - }); - - it("should fail when binding fails", () => { - const emails = ["email1", "email2"]; - const session = new SessionStub(); - sessionFactory.createStub.withArgs(ADMIN_USER_DN, ADMIN_PASSWORD).returns(session); - - session.openStub.returns(Bluebird.reject(new Error("Binding failed"))); - - return usersDatabase.getEmails(USERNAME) - .then(() => Bluebird.reject(new Error("should not be here"))) - .catch((err) => { - Assert(session.closeStub.called); - }) - }); - - it("should fail when unbinding fails", () => { - const emails = ["email1", "email2"]; - const session = new SessionStub(); - sessionFactory.createStub.withArgs(ADMIN_USER_DN, ADMIN_PASSWORD).returns(session); - - session.openStub.returns(Bluebird.resolve()); - session.searchEmailsStub.returns(Bluebird.resolve(emails)); - session.closeStub.returns(Bluebird.reject(new Error("Unbinding failed"))); - - return usersDatabase.getEmails(USERNAME) - .then(() => Bluebird.reject(new Error("should not be here"))) - .catch((err) => { - Assert(session.closeStub.called); - }) - }); - - it("should fail when search fails", () => { - const emails = ["email1", "email2"]; - const session = new SessionStub(); - sessionFactory.createStub.withArgs(ADMIN_USER_DN, ADMIN_PASSWORD).returns(session); - - session.openStub.returns(Bluebird.resolve()); - session.searchEmailsStub.returns(Bluebird.reject(new Error("Search failed"))); - session.closeStub.returns(Bluebird.resolve()); - - return usersDatabase.getEmails(USERNAME) - .then(() => Bluebird.reject(new Error("should not be here"))) - .catch((err) => { - Assert(session.closeStub.called); - }) - }); - }); - - - describe("getGroups", function() { - it("should succefully retrieves groups", () => { - const groups = ["group1", "group2"]; - const session = new SessionStub(); - sessionFactory.createStub.withArgs(ADMIN_USER_DN, ADMIN_PASSWORD).returns(session); - - session.openStub.returns(Bluebird.resolve()); - session.closeStub.returns(Bluebird.resolve()); - session.searchGroupsStub.returns(Bluebird.resolve(groups)); - - return usersDatabase.getGroups(USERNAME) - .then((foundGroups) => { - Assert(session.closeStub.called); - Assert.deepEqual(foundGroups, groups); - }) - }); - - it("should fail when binding fails", () => { - const session = new SessionStub(); - sessionFactory.createStub.withArgs(ADMIN_USER_DN, ADMIN_PASSWORD).returns(session); - - session.openStub.returns(Bluebird.reject(new Error("Binding failed"))); - - return usersDatabase.getGroups(USERNAME) - .then(() => Bluebird.reject(new Error("should not be here"))) - .catch((err) => { - Assert(session.closeStub.called); - }) - }); - - it("should fail when unbinding fails", () => { - const groups = ["group1", "group2"]; - const session = new SessionStub(); - sessionFactory.createStub.withArgs(ADMIN_USER_DN, ADMIN_PASSWORD).returns(session); - - session.openStub.returns(Bluebird.resolve()); - session.searchGroupsStub.returns(Bluebird.resolve(groups)); - session.closeStub.returns(Bluebird.reject(new Error("Unbinding failed"))); - - return usersDatabase.getGroups(USERNAME) - .then(() => Bluebird.reject(new Error("should not be here"))) - .catch((err) => { - Assert(session.closeStub.called); - }) - }); - - it("should fail when search fails", () => { - const groups = ["group1", "group2"]; - const session = new SessionStub(); - sessionFactory.createStub.withArgs(ADMIN_USER_DN, ADMIN_PASSWORD).returns(session); - - session.openStub.returns(Bluebird.resolve()); - session.searchGroupsStub.returns(Bluebird.reject(new Error("Search failed"))); - session.closeStub.returns(Bluebird.resolve()); - - return usersDatabase.getGroups(USERNAME) - .then(() => Bluebird.reject(new Error("should not be here"))) - .catch((err) => { - Assert(session.closeStub.called); - }) - }); - }); - - - describe("updatePassword", function() { - it("should successfully update password", () => { - const session = new SessionStub(); - sessionFactory.createStub.withArgs(ADMIN_USER_DN, ADMIN_PASSWORD).returns(session); - - session.openStub.returns(Bluebird.resolve()); - session.closeStub.returns(Bluebird.resolve()); - session.modifyPasswordStub.returns(Bluebird.resolve()); - - return usersDatabase.updatePassword(USERNAME, NEW_PASSWORD) - .then(() => { - Assert(session.modifyPasswordStub.calledWith(USERNAME, NEW_PASSWORD)); - Assert(session.closeStub.called); - }) - }); - - it("should fail when binding fails", () => { - const session = new SessionStub(); - sessionFactory.createStub.withArgs(ADMIN_USER_DN, ADMIN_PASSWORD).returns(session); - - session.openStub.returns(Bluebird.reject(new Error("Binding failed"))); - session.closeStub.returns(Bluebird.resolve()); - session.modifyPasswordStub.returns(Bluebird.resolve()); - - return usersDatabase.updatePassword(USERNAME, NEW_PASSWORD) - .then(() => Bluebird.reject(new Error("should not be here"))) - .catch(() => { - Assert(session.closeStub.called); - }) - }); - - it("should fail when update fails", () => { - const session = new SessionStub(); - sessionFactory.createStub.withArgs(ADMIN_USER_DN, ADMIN_PASSWORD).returns(session); - - session.openStub.returns(Bluebird.resolve()); - session.closeStub.returns(Bluebird.reject(new Error("Update failed"))); - session.modifyPasswordStub.returns(Bluebird.resolve()); - - return usersDatabase.updatePassword(USERNAME, NEW_PASSWORD) - .then(() => Bluebird.reject(new Error("should not be here"))) - .catch(() => { - Assert(session.closeStub.called); - }) - }); - - it("should fail when unbind fails", () => { - const session = new SessionStub(); - sessionFactory.createStub.withArgs(ADMIN_USER_DN, ADMIN_PASSWORD).returns(session); - - session.openStub.returns(Bluebird.resolve()); - session.closeStub.returns(Bluebird.resolve()); - session.modifyPasswordStub.returns(Bluebird.reject(new Error("Unbind failed"))); - - return usersDatabase.updatePassword(USERNAME, NEW_PASSWORD) - .then(() => Bluebird.reject(new Error("should not be here"))) - .catch(() => { - Assert(session.closeStub.called); - }) - }); - }); -}); \ No newline at end of file diff --git a/server/src/lib/authentication/backends/ldap/LdapUsersDatabase.ts b/server/src/lib/authentication/backends/ldap/LdapUsersDatabase.ts deleted file mode 100644 index d41743279..000000000 --- a/server/src/lib/authentication/backends/ldap/LdapUsersDatabase.ts +++ /dev/null @@ -1,108 +0,0 @@ -import Bluebird = require("bluebird"); -import { IUsersDatabase } from "../IUsersDatabase"; -import { ISessionFactory } from "./ISessionFactory"; -import { LdapConfiguration } from "../../../configuration/schema/LdapConfiguration"; -import { ISession } from "./ISession"; -import { GroupsAndEmails } from "../GroupsAndEmails"; -import Exceptions = require("../../../Exceptions"); -import AuthenticationError from "../../AuthenticationError"; - -type SessionCallback = (session: ISession) => Bluebird; - -export class LdapUsersDatabase implements IUsersDatabase { - private sessionFactory: ISessionFactory; - private configuration: LdapConfiguration; - - constructor( - sessionFactory: ISessionFactory, - configuration: LdapConfiguration) { - this.sessionFactory = sessionFactory; - this.configuration = configuration; - } - - private withSession( - username: string, - password: string, - cb: SessionCallback): Bluebird { - const session = this.sessionFactory.create(username, password); - return session.open() - .then(() => cb(session)) - .finally(() => session.close()); - } - - checkUserPassword(username: string, password: string): Bluebird { - const that = this; - function verifyUserPassword(userDN: string) { - return that.withSession( - userDN, - password, - (session) => Bluebird.resolve() - ); - } - - function getInfo(session: ISession) { - return Bluebird.join( - session.searchGroups(username), - session.searchEmails(username) - ) - .spread((groups: string[], emails: string[]) => { - return { groups: groups, emails: emails }; - }); - } - - return that.withSession( - that.configuration.user, - that.configuration.password, - (session) => { - return session.searchUserDn(username) - .then(verifyUserPassword) - .then(() => getInfo(session)); - }) - .catch((err) => - Bluebird.reject(new AuthenticationError(err.message))); - } - - getEmails(username: string): Bluebird { - const that = this; - return that.withSession( - that.configuration.user, - that.configuration.password, - (session) => { - return session.searchEmails(username); - } - ) - .catch((err) => - Bluebird.reject(new Exceptions.LdapError("Failed during email retrieval: " + err.message)) - ); - } - - getGroups(username: string): Bluebird { - const that = this; - return that.withSession( - that.configuration.user, - that.configuration.password, - (session) => { - return session.searchGroups(username); - } - ) - .catch((err) => - Bluebird.reject(new Exceptions.LdapError("Failed during email retrieval: " + err.message)) - ); - } - - updatePassword(username: string, newPassword: string): Bluebird { - const that = this; - return that.withSession( - that.configuration.user, - that.configuration.password, - (session) => { - return session.modifyPassword(username, newPassword); - } - ) - .catch(function (err: Error) { - return Bluebird.reject( - new Exceptions.LdapError( - "Error while updating password: " + err.message)); - }); - } -} \ No newline at end of file diff --git a/server/src/lib/authentication/backends/ldap/SafeSession.spec.ts b/server/src/lib/authentication/backends/ldap/SafeSession.spec.ts deleted file mode 100644 index c02e0dfa7..000000000 --- a/server/src/lib/authentication/backends/ldap/SafeSession.spec.ts +++ /dev/null @@ -1,77 +0,0 @@ -import BluebirdPromise = require("bluebird"); -import { SessionStub } from "./SessionStub.spec"; -import { SafeSession } from "./SafeSession"; -import Winston = require("winston"); - -describe("ldap/SanitizedClient", function () { - let client: SafeSession; - - beforeEach(function () { - const clientStub = new SessionStub(); - clientStub.searchUserDnStub.onCall(0).returns(BluebirdPromise.resolve()); - clientStub.searchGroupsStub.onCall(0).returns(BluebirdPromise.resolve()); - clientStub.searchEmailsStub.onCall(0).returns(BluebirdPromise.resolve()); - clientStub.modifyPasswordStub.onCall(0).returns(BluebirdPromise.resolve()); - client = new SafeSession(clientStub, Winston); - }); - - describe("special chars are used", function () { - it("should fail when special chars are used in searchUserDn", function () { - // potential ldap injection"; - return client.searchUserDn("cn=dummy_user,ou=groupgs") - .then(function () { - return BluebirdPromise.reject(new Error("Should not be here.")); - }, function () { - return BluebirdPromise.resolve(); - }); - }); - - it("should fail when special chars are used in searchGroups", function () { - // potential ldap injection"; - return client.searchGroups("cn=dummy_user,ou=groupgs") - .then(function () { - return BluebirdPromise.reject(new Error("Should not be here.")); - }, function () { - return BluebirdPromise.resolve(); - }); - }); - - it("should fail when special chars are used in searchEmails", function () { - // potential ldap injection"; - return client.searchEmails("cn=dummy_user,ou=groupgs") - .then(function () { - return BluebirdPromise.reject(new Error("Should not be here.")); - }, function () { - return BluebirdPromise.resolve(); - }); - }); - - it("should fail when special chars are used in modifyPassword", function () { - // potential ldap injection"; - return client.modifyPassword("cn=dummy_user,ou=groupgs", "abc") - .then(function () { - return BluebirdPromise.reject(new Error("Should not be here.")); - }, function () { - return BluebirdPromise.resolve(); - }); - }); - }); - - describe("no special chars are used", function() { - it("should succeed when no special chars are used in searchUserDn", function () { - return client.searchUserDn("dummy_user"); - }); - - it("should succeed when no special chars are used in searchGroups", function () { - return client.searchGroups("dummy_user"); - }); - - it("should succeed when no special chars are used in searchEmails", function () { - return client.searchEmails("dummy_user"); - }); - - it("should succeed when no special chars are used in modifyPassword", function () { - return client.modifyPassword("dummy_user", "abc"); - }); - }); -}); diff --git a/server/src/lib/authentication/backends/ldap/SafeSession.ts b/server/src/lib/authentication/backends/ldap/SafeSession.ts deleted file mode 100644 index fda99c8e5..000000000 --- a/server/src/lib/authentication/backends/ldap/SafeSession.ts +++ /dev/null @@ -1,69 +0,0 @@ -import BluebirdPromise = require("bluebird"); -import { ISession } from "./ISession"; -import { Sanitizer } from "./Sanitizer"; -import { Winston } from "../../../../../types/Dependencies"; - -const SPECIAL_CHAR_USED_MESSAGE = "Special character used in LDAP query."; - - -export class SafeSession implements ISession { - private sesion: ISession; - private logger: Winston; - - constructor(sesion: ISession, logger: Winston) { - this.sesion = sesion; - this.logger = logger; - } - - open(): BluebirdPromise { - return this.sesion.open(); - } - - close(): BluebirdPromise { - return this.sesion.close(); - } - - searchGroups(username: string): BluebirdPromise { - try { - const sanitizedUsername = Sanitizer.sanitize(username); - return this.sesion.searchGroups(sanitizedUsername); - } - catch (e) { - this.logger.error("Error with input " + username + ". Cause:" + e); - return BluebirdPromise.reject(new Error(SPECIAL_CHAR_USED_MESSAGE)); - } - } - - searchUserDn(username: string): BluebirdPromise { - try { - const sanitizedUsername = Sanitizer.sanitize(username); - return this.sesion.searchUserDn(sanitizedUsername); - } - catch (e) { - this.logger.error("Error with input " + username + ". Cause:" + e); - return BluebirdPromise.reject(new Error(SPECIAL_CHAR_USED_MESSAGE)); - } - } - - searchEmails(username: string): BluebirdPromise { - try { - const sanitizedUsername = Sanitizer.sanitize(username); - return this.sesion.searchEmails(sanitizedUsername); - } - catch (e) { - this.logger.error("Error with input " + username + ". Cause:" + e); - return BluebirdPromise.reject(new Error(SPECIAL_CHAR_USED_MESSAGE)); - } - } - - modifyPassword(username: string, newPassword: string): BluebirdPromise { - try { - const sanitizedUsername = Sanitizer.sanitize(username); - return this.sesion.modifyPassword(sanitizedUsername, newPassword); - } - catch (e) { - this.logger.error("Error with input " + username + ". Cause:" + e); - return BluebirdPromise.reject(new Error(SPECIAL_CHAR_USED_MESSAGE)); - } - } -} diff --git a/server/src/lib/authentication/backends/ldap/Sanitizer.spec.ts b/server/src/lib/authentication/backends/ldap/Sanitizer.spec.ts deleted file mode 100644 index 9dd33fed4..000000000 --- a/server/src/lib/authentication/backends/ldap/Sanitizer.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import Assert = require("assert"); -import { Sanitizer } from "./Sanitizer"; - -describe("ldap/InputsSanitizer", function () { - it("should fail when special characters are used", function () { - Assert.throws(() => { Sanitizer.sanitize("ab,c"); }, Error); - Assert.throws(() => { Sanitizer.sanitize("a\\bc"); }, Error); - Assert.throws(() => { Sanitizer.sanitize("a'bc"); }, Error); - Assert.throws(() => { Sanitizer.sanitize("a#bc"); }, Error); - Assert.throws(() => { Sanitizer.sanitize("a+bc"); }, Error); - Assert.throws(() => { Sanitizer.sanitize("a { Sanitizer.sanitize("a>bc"); }, Error); - Assert.throws(() => { Sanitizer.sanitize("a;bc"); }, Error); - Assert.throws(() => { Sanitizer.sanitize("a\"bc"); }, Error); - Assert.throws(() => { Sanitizer.sanitize("a=bc"); }, Error); - }); - - it("should return original string", function () { - Assert.equal(Sanitizer.sanitize("abcdef"), "abcdef"); - }); - - it("should trim", function () { - Assert.throws(() => { Sanitizer.sanitize(" abc "); }, Error); - }); -}); diff --git a/server/src/lib/authentication/backends/ldap/Sanitizer.ts b/server/src/lib/authentication/backends/ldap/Sanitizer.ts deleted file mode 100644 index 2790de7fa..000000000 --- a/server/src/lib/authentication/backends/ldap/Sanitizer.ts +++ /dev/null @@ -1,27 +0,0 @@ - -// returns true for 1 or more matches, where 'a' is an array and 'b' is a search string or an array of multiple search strings -function contains(a: string, character: string) { - // string match - return a.indexOf(character) > -1; -} - -function containsOneOf(s: string, characters: string[]) { - return characters - .map((character: string) => { return contains(s, character); }) - .reduce((acc: boolean, current: boolean) => { return acc || current; }, false); -} - -export class Sanitizer { - static sanitize(input: string): string { - const forbiddenChars = [",", "\\", "'", "#", "+", "<", ">", ";", "\"", "="]; - if (containsOneOf(input, forbiddenChars)) { - throw new Error("Input containing unsafe characters."); - } - - if (input != input.trim()) { - throw new Error("Input has unexpected spaces."); - } - - return input; - } -} diff --git a/server/src/lib/authentication/backends/ldap/Session.spec.ts b/server/src/lib/authentication/backends/ldap/Session.spec.ts deleted file mode 100644 index ce11c5ab8..000000000 --- a/server/src/lib/authentication/backends/ldap/Session.spec.ts +++ /dev/null @@ -1,170 +0,0 @@ - -import { LdapConfiguration } from "../../../configuration/schema/LdapConfiguration"; -import { Session } from "./Session"; -import { ConnectorFactoryStub } from "./connector/ConnectorFactoryStub.spec"; -import { ConnectorStub } from "./connector/ConnectorStub.spec"; - -import Sinon = require("sinon"); -import BluebirdPromise = require("bluebird"); -import Assert = require("assert"); -import Winston = require("winston"); - -describe("ldap/Session", function () { - const USERNAME = "username"; - const ADMIN_USER_DN = "cn=admin,dc=example,dc=com"; - const ADMIN_PASSWORD = "password"; - - it("should replace {0} by username when searching for groups in LDAP", function () { - const options: LdapConfiguration = { - url: "ldap://ldap", - additional_users_dn: "ou=users", - additional_groups_dn: "ou=groups", - base_dn: "dc=example,dc=com", - users_filter: "cn={0}", - groups_filter: "member=cn={0},ou=users,dc=example,dc=com", - group_name_attribute: "cn", - mail_attribute: "mail", - user: "cn=admin,dc=example,dc=com", - password: "password" - }; - const connectorStub = new ConnectorStub(); - connectorStub.searchAsyncStub.returns(BluebirdPromise.resolve([{ - cn: "group1" - }])); - const client = new Session(ADMIN_USER_DN, ADMIN_PASSWORD, options, connectorStub, Winston); - - return client.searchGroups("user1") - .then(function () { - Assert.equal(connectorStub.searchAsyncStub.getCall(0).args[1].filter, - "member=cn=user1,ou=users,dc=example,dc=com"); - }); - }); - - it("should replace {dn} by user DN when searching for groups in LDAP", function () { - const USER_DN = "cn=user1,ou=users,dc=example,dc=com"; - const options: LdapConfiguration = { - url: "ldap://ldap", - additional_users_dn: "ou=users", - additional_groups_dn: "ou=groups", - base_dn: "dc=example,dc=com", - users_filter: "cn={0}", - groups_filter: "member={dn}", - group_name_attribute: "cn", - mail_attribute: "mail", - user: "cn=admin,dc=example,dc=com", - password: "password" - }; - const ldapClient = new ConnectorStub(); - - // Retrieve user DN - ldapClient.searchAsyncStub.withArgs("ou=users,dc=example,dc=com", { - scope: "sub", - sizeLimit: 1, - attributes: ["dn"], - filter: "cn=user1" - }).returns(BluebirdPromise.resolve([{ - dn: USER_DN - }])); - - // Retrieve groups - ldapClient.searchAsyncStub.withArgs("ou=groups,dc=example,dc=com", { - scope: "sub", - attributes: ["cn"], - filter: "member=" + USER_DN - }).returns(BluebirdPromise.resolve([{ - cn: "group1" - }])); - - const client = new Session(ADMIN_USER_DN, ADMIN_PASSWORD, options, ldapClient, Winston); - - return client.searchGroups("user1") - .then(function (groups: string[]) { - Assert.deepEqual(groups, ["group1"]); - }); - }); - - it("should replace {uid} by user uid when searching for groups in LDAP", function () { - const USER_UID = "user1"; - const options: LdapConfiguration = { - url: "ldap://ldap", - additional_users_dn: "ou=users", - additional_groups_dn: "ou=groups", - base_dn: "dc=example,dc=com", - users_filter: "cn={0}", - groups_filter: "member=cn={uid},ou=users,dc=example,dc=com", - group_name_attribute: "cn", - mail_attribute: "mail", - user: "cn=admin,dc=example,dc=com", - password: "password" - }; - const ldapClient = new ConnectorStub(); - - // Retrieve user DN - ldapClient.searchAsyncStub.withArgs("ou=users,dc=example,dc=com", { - scope: "sub", - sizeLimit: 1, - attributes: ["uid"], - filter: "cn=user1" - }).returns(BluebirdPromise.resolve([{ - uid: USER_UID - }])); - - // Retrieve groups - ldapClient.searchAsyncStub.withArgs("ou=groups,dc=example,dc=com", { - scope: "sub", - attributes: ["cn"], - filter: "member=cn=user1,ou=users,dc=example,dc=com" - }).returns(BluebirdPromise.resolve([{ - cn: "group1" - }])); - - const client = new Session(ADMIN_USER_DN, ADMIN_PASSWORD, options, ldapClient, Winston); - - return client.searchGroups("user1") - .then(function (groups: string[]) { - Assert.deepEqual(groups, ["group1"]); - }); - }); - - it("should retrieve mail from custom attribute", function () { - const USER_DN = "cn=user1,ou=users,dc=example,dc=com"; - const options: LdapConfiguration = { - url: "ldap://ldap", - additional_users_dn: "ou=users", - additional_groups_dn: "ou=groups", - base_dn: "dc=example,dc=com", - users_filter: "cn={0}", - groups_filter: "member={dn}", - group_name_attribute: "cn", - mail_attribute: "custom_mail", - user: "cn=admin,dc=example,dc=com", - password: "password" - }; - const connector = new ConnectorStub(); - // Retrieve user DN - connector.searchAsyncStub.withArgs("ou=users,dc=example,dc=com", { - scope: "sub", - sizeLimit: 1, - attributes: ["dn"], - filter: "cn=user1" - }).returns(BluebirdPromise.resolve([{ - dn: USER_DN - }])); - - // Retrieve email - connector.searchAsyncStub.withArgs("cn=user1,ou=users,dc=example,dc=com", { - scope: "base", - sizeLimit: 1, - attributes: ["custom_mail"], - }).returns(BluebirdPromise.resolve([{ - custom_mail: "user1@example.com" - }])); - - const client = new Session(ADMIN_USER_DN, ADMIN_PASSWORD, options, connector, Winston); - - return client.searchEmails("user1") - .then(function (emails: string[]) { - Assert.deepEqual(emails, ["user1@example.com"]); - }); - }); -}); \ No newline at end of file diff --git a/server/src/lib/authentication/backends/ldap/Session.ts b/server/src/lib/authentication/backends/ldap/Session.ts deleted file mode 100644 index d6312cca0..000000000 --- a/server/src/lib/authentication/backends/ldap/Session.ts +++ /dev/null @@ -1,169 +0,0 @@ -import BluebirdPromise = require("bluebird"); -import exceptions = require("../../../Exceptions"); -import { ISession } from "./ISession"; -import { LdapConfiguration } from "../../../configuration/schema/LdapConfiguration"; -import { Winston } from "../../../../../types/Dependencies"; -import Util = require("util"); -import { HashGenerator } from "../../../utils/HashGenerator"; -import { IConnector } from "./connector/IConnector"; - -export class Session implements ISession { - private userDN: string; - private password: string; - private connector: IConnector; - private logger: Winston; - private options: LdapConfiguration; - - private groupsSearchBase: string; - private usersSearchBase: string; - - constructor(userDN: string, password: string, options: LdapConfiguration, - connector: IConnector, logger: Winston) { - this.options = options; - this.logger = logger; - this.userDN = userDN; - this.password = password; - this.connector = connector; - - this.groupsSearchBase = (this.options.additional_groups_dn) - ? Util.format("%s,%s", this.options.additional_groups_dn, this.options.base_dn) - : this.options.base_dn; - - this.usersSearchBase = (this.options.additional_users_dn) - ? Util.format("%s,%s", this.options.additional_users_dn, this.options.base_dn) - : this.options.base_dn; - } - - open(): BluebirdPromise { - this.logger.debug("LDAP: Bind user '%s'", this.userDN); - return this.connector.bindAsync(this.userDN, this.password) - .error(function (err: Error) { - return BluebirdPromise.reject(new exceptions.LdapBindError(err.message)); - }); - } - - close(): BluebirdPromise { - this.logger.debug("LDAP: Unbind user '%s'", this.userDN); - return this.connector.unbindAsync() - .error(function (err: Error) { - return BluebirdPromise.reject(new exceptions.LdapBindError(err.message)); - }); - } - - private createGroupsFilter(userGroupsFilter: string, username: string): BluebirdPromise { - if (userGroupsFilter.indexOf("{0}") > 0) { - return BluebirdPromise.resolve(userGroupsFilter.replace("{0}", username)); - } - else if (userGroupsFilter.indexOf("{dn}") > 0) { - return this.searchUserDn(username) - .then(function (userDN: string) { - return BluebirdPromise.resolve(userGroupsFilter.replace("{dn}", userDN)); - }); - } - else if (userGroupsFilter.indexOf("{uid}") > 0) { - return this.searchUserUid(username) - .then(function (userUid: string) { - return BluebirdPromise.resolve(userGroupsFilter.replace("{uid}", userUid)); - }); - } - return BluebirdPromise.resolve(userGroupsFilter); - } - - searchGroups(username: string): BluebirdPromise { - const that = this; - return this.createGroupsFilter(this.options.groups_filter, username) - .then(function (groupsFilter: string) { - that.logger.debug("Computed groups filter is %s", groupsFilter); - const query = { - scope: "sub", - attributes: [that.options.group_name_attribute], - filter: groupsFilter - }; - return that.connector.searchAsync(that.groupsSearchBase, query); - }) - .then(function (docs: { cn: string }[]) { - const groups = docs.map((doc: any) => { return doc.cn; }); - that.logger.debug("LDAP: groups of user %s are [%s]", username, groups.join(",")); - return BluebirdPromise.resolve(groups); - }); - } - - searchUserAttribute(username: string, attribute: string): BluebirdPromise { - const that = this; - const filter = this.options.users_filter.replace("{0}", username); - this.logger.debug("Computed users filter is %s", filter); - const query = { - scope: "sub", - sizeLimit: 1, - attributes: [attribute], - filter: filter - }; - - that.logger.debug("LDAP: searching for user %s of %s", attribute, username); - return that.connector.searchAsync(this.usersSearchBase, query) - .then(function (users: { [attribute: string]: string }[]) { - if (users.length > 0) { - that.logger.debug("LDAP: retrieved user %s is %s", attribute, users[0][attribute]); - return BluebirdPromise.resolve(users[0][attribute]); - } - return BluebirdPromise.reject(new Error( - Util.format("No user %s found for user '%s'", attribute, username))); - }); - } - - searchUserDn(username: string): BluebirdPromise { - return this.searchUserAttribute(username, "dn"); - } - - searchUserUid(username: string): BluebirdPromise { - return this.searchUserAttribute(username, "uid"); - } - - searchEmails(username: string): BluebirdPromise { - const that = this; - const query = { - scope: "base", - sizeLimit: 1, - attributes: [this.options.mail_attribute] - }; - - return this.searchUserDn(username) - .then(function (userDN) { - return that.connector.searchAsync(userDN, query); - }) - .then(function (docs: { [mail_attribute: string]: string }[]) { - const emails: string[] = docs - .filter((d) => { return typeof d[that.options.mail_attribute] === "string"; }) - .map((d) => { return d[that.options.mail_attribute]; }); - that.logger.debug("LDAP: emails of user '%s' are %s", username, emails); - return BluebirdPromise.resolve(emails); - }) - .catch(function (err: Error) { - return BluebirdPromise.reject(new exceptions.LdapError("Error while searching emails. " + err.stack)); - }); - } - - modifyPassword(username: string, newPassword: string): BluebirdPromise { - const that = this; - this.logger.debug("LDAP: update password of user '%s'", username); - return this.searchUserDn(username) - .then(function (userDN: string) { - return BluebirdPromise.join( - HashGenerator.ssha512(newPassword), - BluebirdPromise.resolve(userDN)); - }) - .then(function (res: string[]) { - const change = { - operation: "replace", - modification: { - userPassword: res[0] - } - }; - that.logger.debug("Password new='%s'", change.modification.userPassword); - return that.connector.modifyAsync(res[1], change); - }) - .then(function () { - return that.connector.unbindAsync(); - }); - } -} diff --git a/server/src/lib/authentication/backends/ldap/SessionFactory.ts b/server/src/lib/authentication/backends/ldap/SessionFactory.ts deleted file mode 100644 index 579fe46d8..000000000 --- a/server/src/lib/authentication/backends/ldap/SessionFactory.ts +++ /dev/null @@ -1,37 +0,0 @@ -import Winston = require("winston"); - -import { IConnectorFactory } from "./connector/IConnectorFactory"; -import { ISessionFactory } from "./ISessionFactory"; -import { ISession } from "./ISession"; -import { LdapConfiguration } from "../../../configuration/schema/LdapConfiguration"; -import { Session } from "./Session"; -import { SafeSession } from "./SafeSession"; - - -export class SessionFactory implements ISessionFactory { - private config: LdapConfiguration; - private connectorFactory: IConnectorFactory; - private logger: typeof Winston; - - constructor(ldapConfiguration: LdapConfiguration, - connectorFactory: IConnectorFactory, - logger: typeof Winston) { - this.config = ldapConfiguration; - this.connectorFactory = connectorFactory; - this.logger = logger; - } - - create(userDN: string, password: string): ISession { - const connector = this.connectorFactory.create(); - return new SafeSession( - new Session( - userDN, - password, - this.config, - connector, - this.logger - ), - this.logger - ); - } -} diff --git a/server/src/lib/authentication/backends/ldap/SessionFactoryStub.spec.ts b/server/src/lib/authentication/backends/ldap/SessionFactoryStub.spec.ts deleted file mode 100644 index face3930d..000000000 --- a/server/src/lib/authentication/backends/ldap/SessionFactoryStub.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import Sinon = require("sinon"); - -import { ISession } from "./ISession"; -import { ISessionFactory } from "./ISessionFactory"; - -export class SessionFactoryStub implements ISessionFactory { - createStub: Sinon.SinonStub; - - constructor() { - this.createStub = Sinon.stub(); - } - - create(userDN: string, password: string): ISession { - return this.createStub(userDN, password); - } -} \ No newline at end of file diff --git a/server/src/lib/authentication/backends/ldap/SessionStub.spec.ts b/server/src/lib/authentication/backends/ldap/SessionStub.spec.ts deleted file mode 100644 index 5faf2ba18..000000000 --- a/server/src/lib/authentication/backends/ldap/SessionStub.spec.ts +++ /dev/null @@ -1,46 +0,0 @@ -import Bluebird = require("bluebird"); -import Sinon = require("sinon"); - -import { ISession } from "./ISession"; - -export class SessionStub implements ISession { - openStub: Sinon.SinonStub; - closeStub: Sinon.SinonStub; - searchUserDnStub: Sinon.SinonStub; - searchEmailsStub: Sinon.SinonStub; - searchGroupsStub: Sinon.SinonStub; - modifyPasswordStub: Sinon.SinonStub; - - constructor() { - this.openStub = Sinon.stub(); - this.closeStub = Sinon.stub(); - this.searchUserDnStub = Sinon.stub(); - this.searchEmailsStub = Sinon.stub(); - this.searchGroupsStub = Sinon.stub(); - this.modifyPasswordStub = Sinon.stub(); - } - - open(): Bluebird { - return this.openStub(); - } - - close(): Bluebird { - return this.closeStub(); - } - - searchUserDn(username: string): Bluebird { - return this.searchUserDnStub(username); - } - - searchEmails(username: string): Bluebird { - return this.searchEmailsStub(username); - } - - searchGroups(username: string): Bluebird { - return this.searchGroupsStub(username); - } - - modifyPassword(username: string, newPassword: string): Bluebird { - return this.modifyPasswordStub(username, newPassword); - } -} \ No newline at end of file diff --git a/server/src/lib/authentication/backends/ldap/connector/Connector.ts b/server/src/lib/authentication/backends/ldap/connector/Connector.ts deleted file mode 100644 index 5eaee9a12..000000000 --- a/server/src/lib/authentication/backends/ldap/connector/Connector.ts +++ /dev/null @@ -1,67 +0,0 @@ -import LdapJs = require("ldapjs"); -import EventEmitter = require("events"); -import Bluebird = require("bluebird"); -import { IConnector } from "./IConnector"; -import Exceptions = require("../../../../Exceptions"); -import { Client, ClientOptions } from "ldapjs"; - -interface SearchEntry { - object: any; -} - -export interface ClientAsync { - on(event: string, callback: (data?: any) => void): void; - bindAsync(username: string, password: string): Bluebird; - unbindAsync(): Bluebird; - searchAsync(base: string, query: LdapJs.SearchOptions): Bluebird; - modifyAsync(userdn: string, change: LdapJs.Change): Bluebird; -} - -export class Connector implements IConnector { - private client: ClientAsync; - - constructor(clientOptions: ClientOptions, ldapjs: typeof LdapJs) { - const ldapClient: Client = ldapjs.createClient(clientOptions); - - /*const clientLogger = (ldapClient as any).log; - if (clientLogger) { - clientLogger.level("trace"); - }*/ - - this.client = Bluebird.promisifyAll(ldapClient) as any; - } - - bindAsync(username: string, password: string): Bluebird { - return this.client.bindAsync(username, password); - } - - unbindAsync(): Bluebird { - return this.client.unbindAsync(); - } - - searchAsync(base: string, query: any): Bluebird { - const that = this; - return this.client.searchAsync(base, query) - .then(function (res: EventEmitter) { - const doc: SearchEntry[] = []; - return new Bluebird((resolve, reject) => { - res.on("searchEntry", function (entry: SearchEntry) { - doc.push(entry.object); - }); - res.on("error", function (err: Error) { - reject(new Exceptions.LdapSearchError(err.message)); - }); - res.on("end", function () { - resolve(doc); - }); - }); - }) - .catch(function (err: Error) { - return Bluebird.reject(new Exceptions.LdapSearchError(err.message)); - }); - } - - modifyAsync(dn: string, changeRequest: any): Bluebird { - return this.client.modifyAsync(dn, changeRequest); - } -} \ No newline at end of file diff --git a/server/src/lib/authentication/backends/ldap/connector/ConnectorFactory.ts b/server/src/lib/authentication/backends/ldap/connector/ConnectorFactory.ts deleted file mode 100644 index f2ff0227c..000000000 --- a/server/src/lib/authentication/backends/ldap/connector/ConnectorFactory.ts +++ /dev/null @@ -1,36 +0,0 @@ -import Winston = require("winston"); -import { IConnector } from "./IConnector"; -import { Connector } from "./Connector"; -import { LdapConfiguration } from "../../../../configuration/schema/LdapConfiguration"; -import { Ldapjs } from "Dependencies"; -import { ClientOptions } from "ldapjs"; -import * as fs from "fs"; - -export class ConnectorFactory { - private configuration: LdapConfiguration; - private ldapjs: Ldapjs; - private logger: typeof Winston; - - constructor(configuration: LdapConfiguration, ldapjs: Ldapjs, logger: typeof Winston) { - this.configuration = configuration; - this.ldapjs = ldapjs; - this.logger = logger; - } - - create(): IConnector { - const options: ClientOptions = { - url: this.configuration.url, - reconnect: this.configuration.reconnect - }; - - if (this.configuration.caCert && (this.configuration.url.toLowerCase().startsWith("ldaps"))) { - this.logger.info("Reading CA certificate from: %s", this.configuration.caCert); - options.tlsOptions = { - ca: [ fs.readFileSync(this.configuration.caCert, "utf-8") ], - }; - } - - this.logger.debug("Using ldap client options: %s", JSON.stringify(options)); - return new Connector(options, this.ldapjs); - } -} \ No newline at end of file diff --git a/server/src/lib/authentication/backends/ldap/connector/ConnectorFactoryStub.spec.ts b/server/src/lib/authentication/backends/ldap/connector/ConnectorFactoryStub.spec.ts deleted file mode 100644 index d11fa6386..000000000 --- a/server/src/lib/authentication/backends/ldap/connector/ConnectorFactoryStub.spec.ts +++ /dev/null @@ -1,17 +0,0 @@ -import BluebirdPromise = require("bluebird"); -import Sinon = require("sinon"); - -import { IConnectorFactory } from "./IConnectorFactory"; -import { IConnector } from "./IConnector"; - -export class ConnectorFactoryStub implements IConnectorFactory { - createStub: Sinon.SinonStub; - - constructor() { - this.createStub = Sinon.stub(); - } - - create(): IConnector { - return this.createStub(); - } -} \ No newline at end of file diff --git a/server/src/lib/authentication/backends/ldap/connector/ConnectorStub.spec.ts b/server/src/lib/authentication/backends/ldap/connector/ConnectorStub.spec.ts deleted file mode 100644 index 0b78225bf..000000000 --- a/server/src/lib/authentication/backends/ldap/connector/ConnectorStub.spec.ts +++ /dev/null @@ -1,34 +0,0 @@ -import BluebirdPromise = require("bluebird"); -import Sinon = require("sinon"); - -import { IConnector } from "./IConnector"; - -export class ConnectorStub implements IConnector { - bindAsyncStub: Sinon.SinonStub; - unbindAsyncStub: Sinon.SinonStub; - searchAsyncStub: Sinon.SinonStub; - modifyAsyncStub: Sinon.SinonStub; - - constructor() { - this.bindAsyncStub = Sinon.stub(); - this.unbindAsyncStub = Sinon.stub(); - this.searchAsyncStub = Sinon.stub(); - this.modifyAsyncStub = Sinon.stub(); - } - - bindAsync(username: string, password: string): BluebirdPromise { - return this.bindAsyncStub(username, password); - } - - unbindAsync(): BluebirdPromise { - return this.unbindAsyncStub(); - } - - searchAsync(base: string, query: any): BluebirdPromise { - return this.searchAsyncStub(base, query); - } - - modifyAsync(dn: string, changeRequest: any): BluebirdPromise { - return this.modifyAsyncStub(dn, changeRequest); - } -} \ No newline at end of file diff --git a/server/src/lib/authentication/backends/ldap/connector/IConnector.ts b/server/src/lib/authentication/backends/ldap/connector/IConnector.ts deleted file mode 100644 index 1e63ab193..000000000 --- a/server/src/lib/authentication/backends/ldap/connector/IConnector.ts +++ /dev/null @@ -1,9 +0,0 @@ -import Bluebird = require("bluebird"); -import EventEmitter = require("events"); - -export interface IConnector { - bindAsync(username: string, password: string): Bluebird; - unbindAsync(): Bluebird; - searchAsync(base: string, query: any): Bluebird; - modifyAsync(dn: string, changeRequest: any): Bluebird; -} \ No newline at end of file diff --git a/server/src/lib/authentication/backends/ldap/connector/IConnectorFactory.ts b/server/src/lib/authentication/backends/ldap/connector/IConnectorFactory.ts deleted file mode 100644 index f9ed65eff..000000000 --- a/server/src/lib/authentication/backends/ldap/connector/IConnectorFactory.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { IConnector } from "./IConnector"; - -export interface IConnectorFactory { - create(): IConnector; -} \ No newline at end of file diff --git a/server/src/lib/authentication/totp/ITotpHandler.ts b/server/src/lib/authentication/totp/ITotpHandler.ts deleted file mode 100644 index d600d31e4..000000000 --- a/server/src/lib/authentication/totp/ITotpHandler.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { TOTPSecret } from "../../../../types/TOTPSecret"; - -export interface ITotpHandler { - generate(label: string, issuer: string): TOTPSecret; - validate(token: string, secret: string): boolean; -} \ No newline at end of file diff --git a/server/src/lib/authentication/totp/TotpHandler.spec.ts b/server/src/lib/authentication/totp/TotpHandler.spec.ts deleted file mode 100644 index 67cffa638..000000000 --- a/server/src/lib/authentication/totp/TotpHandler.spec.ts +++ /dev/null @@ -1,39 +0,0 @@ - -import { TotpHandler } from "./TotpHandler"; -import Sinon = require("sinon"); -import Speakeasy = require("speakeasy"); -import Assert = require("assert"); - -describe("authentication/totp/TotpHandler", function() { - let totpValidator: TotpHandler; - let validateStub: Sinon.SinonStub; - - beforeEach(() => { - validateStub = Sinon.stub(Speakeasy.totp, "verify"); - totpValidator = new TotpHandler(Speakeasy); - }); - - afterEach(function() { - validateStub.restore(); - }); - - it("should validate the TOTP token", function() { - const totp_secret = "NBD2ZV64R9UV1O7K"; - const token = "token"; - validateStub.withArgs({ - secret: totp_secret, - token: token, - encoding: "base32", - window: 1 - }).returns(true); - Assert(totpValidator.validate(token, totp_secret)); - }); - - it("should not validate a wrong TOTP token", function() { - const totp_secret = "NBD2ZV64R9UV1O7K"; - const token = "wrong token"; - validateStub.returns(false); - Assert(!totpValidator.validate(token, totp_secret)); - }); -}); - diff --git a/server/src/lib/authentication/totp/TotpHandler.ts b/server/src/lib/authentication/totp/TotpHandler.ts deleted file mode 100644 index dfab502a7..000000000 --- a/server/src/lib/authentication/totp/TotpHandler.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { ITotpHandler } from "./ITotpHandler"; -import { TOTPSecret } from "../../../../types/TOTPSecret"; -import Speakeasy = require("speakeasy"); - -const TOTP_ENCODING = "base32"; -const WINDOW: number = 1; - -export class TotpHandler implements ITotpHandler { - private speakeasy: typeof Speakeasy; - - constructor(speakeasy: typeof Speakeasy) { - this.speakeasy = speakeasy; - } - - generate(label: string, issuer: string): TOTPSecret { - const secret = this.speakeasy.generateSecret({ - otpauth_url: false - }) as TOTPSecret; - - secret.otpauth_url = this.speakeasy.otpauthURL({ - secret: secret.ascii, - label: label, - issuer: issuer - }); - return secret; - } - - validate(token: string, secret: string): boolean { - return this.speakeasy.totp.verify({ - secret: secret, - encoding: TOTP_ENCODING, - token: token, - window: WINDOW - }); - } -} diff --git a/server/src/lib/authentication/totp/TotpHandlerStub.spec.ts b/server/src/lib/authentication/totp/TotpHandlerStub.spec.ts deleted file mode 100644 index ea93330d9..000000000 --- a/server/src/lib/authentication/totp/TotpHandlerStub.spec.ts +++ /dev/null @@ -1,22 +0,0 @@ -import Sinon = require("sinon"); -import BluebirdPromise = require("bluebird"); -import { ITotpHandler } from "./ITotpHandler"; -import { TOTPSecret } from "../../../../types/TOTPSecret"; - -export class TotpHandlerStub implements ITotpHandler { - generateStub: Sinon.SinonStub; - validateStub: Sinon.SinonStub; - - constructor() { - this.generateStub = Sinon.stub(); - this.validateStub = Sinon.stub(); - } - - generate(label: string, issuer: string): TOTPSecret { - return this.generateStub(label, issuer); - } - - validate(token: string, secret: string): boolean { - return this.validateStub(token, secret); - } -} \ No newline at end of file diff --git a/server/src/lib/authentication/u2f/IU2fHandler.ts b/server/src/lib/authentication/u2f/IU2fHandler.ts deleted file mode 100644 index b9b7d6f26..000000000 --- a/server/src/lib/authentication/u2f/IU2fHandler.ts +++ /dev/null @@ -1,9 +0,0 @@ -import U2f = require("u2f"); - -export interface IU2fHandler { - request(appId: string, keyHandle?: string): U2f.Request; - checkRegistration(registrationRequest: U2f.Request, registrationResponse: U2f.RegistrationData) - : U2f.RegistrationResult | U2f.Error; - checkSignature(signatureRequest: U2f.Request, signatureResponse: U2f.SignatureData, publicKey: string) - : U2f.SignatureResult | U2f.Error; -} \ No newline at end of file diff --git a/server/src/lib/authentication/u2f/U2fHandler.ts b/server/src/lib/authentication/u2f/U2fHandler.ts deleted file mode 100644 index bf3891e5b..000000000 --- a/server/src/lib/authentication/u2f/U2fHandler.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { IU2fHandler } from "./IU2fHandler"; -import U2f = require("u2f"); - -export class U2fHandler implements IU2fHandler { - private u2f: typeof U2f; - - constructor(u2f: typeof U2f) { - this.u2f = u2f; - } - - request(appId: string, keyHandle?: string): U2f.Request { - return this.u2f.request(appId, keyHandle); - } - - checkRegistration(registrationRequest: U2f.Request, registrationResponse: U2f.RegistrationData) - : U2f.RegistrationResult | U2f.Error { - return this.u2f.checkRegistration(registrationRequest, registrationResponse); - } - - checkSignature(signatureRequest: U2f.Request, signatureResponse: U2f.SignatureData, publicKey: string) - : U2f.SignatureResult | U2f.Error { - return this.u2f.checkSignature(signatureRequest, signatureResponse, publicKey); - } -} diff --git a/server/src/lib/authentication/u2f/U2fHandlerStub.spec.ts b/server/src/lib/authentication/u2f/U2fHandlerStub.spec.ts deleted file mode 100644 index 135d7eb06..000000000 --- a/server/src/lib/authentication/u2f/U2fHandlerStub.spec.ts +++ /dev/null @@ -1,31 +0,0 @@ -import Sinon = require("sinon"); -import BluebirdPromise = require("bluebird"); -import U2f = require("u2f"); -import { IU2fHandler } from "./IU2fHandler"; - - -export class U2fHandlerStub implements IU2fHandler { - requestStub: Sinon.SinonStub; - checkRegistrationStub: Sinon.SinonStub; - checkSignatureStub: Sinon.SinonStub; - - constructor() { - this.requestStub = Sinon.stub(); - this.checkRegistrationStub = Sinon.stub(); - this.checkSignatureStub = Sinon.stub(); - } - - request(appId: string, keyHandle?: string): U2f.Request { - return this.requestStub(appId, keyHandle); - } - - checkRegistration(registrationRequest: U2f.Request, registrationResponse: U2f.RegistrationData) - : U2f.RegistrationResult | U2f.Error { - return this.checkRegistrationStub(registrationRequest, registrationResponse); - } - - checkSignature(signatureRequest: U2f.Request, signatureResponse: U2f.SignatureData, publicKey: string) - : U2f.SignatureResult | U2f.Error { - return this.checkSignatureStub(signatureRequest, signatureResponse, publicKey); - } -} \ No newline at end of file diff --git a/server/src/lib/authorization/Authorizer.spec.ts b/server/src/lib/authorization/Authorizer.spec.ts deleted file mode 100644 index e47e356a7..000000000 --- a/server/src/lib/authorization/Authorizer.spec.ts +++ /dev/null @@ -1,400 +0,0 @@ - -import Assert = require("assert"); -import winston = require("winston"); -import { Authorizer } from "./Authorizer"; -import { ACLConfiguration, ACLRule } from "../configuration/schema/AclConfiguration"; -import { Level } from "./Level"; - -describe("authorization/Authorizer", function () { - let authorizer: Authorizer; - let configuration: ACLConfiguration; - - describe("configuration is null", function() { - it("should allow access to anything, anywhere for anybody", function() { - configuration = undefined; - authorizer = new Authorizer(configuration, winston); - - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/"}, {user: "user1", groups: ["group1", "group2"]}, "127.0.0.1"), Level.BYPASS); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/abc"}, {user: "user1", groups: ["group1", "group2"]}, "127.0.0.1"), Level.BYPASS); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/"}, {user: "user2", groups: ["group1", "group2"]}, "127.0.0.1"), Level.BYPASS); - Assert.equal(authorizer.authorization({domain: "admin.example.com", resource: "/"}, {user: "user3", groups: ["group3"]}, "127.0.0.1"), Level.BYPASS); - }); - }); - - describe("configuration is not null", function () { - beforeEach(function () { - configuration = { - default_policy: "deny", - rules: [] - }; - authorizer = new Authorizer(configuration, winston); - }); - - describe("check access control with default policy to deny", function () { - beforeEach(function () { - configuration.default_policy = "deny"; - }); - - it("should deny access when no rule is provided", function () { - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.DENY); - }); - - it("should control access when multiple domain matcher is provided", function () { - configuration.rules = [{ - domain: "*.mail.example.com", - policy: "two_factor", - subject: "user:user1", - resources: [".*"] - }]; - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.DENY); - Assert.equal(authorizer.authorization({domain: "mx1.mail.example.com", resource: "/"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "mx1.server.mail.example.com", resource: "/"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "mail.example.com", resource: "/"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.DENY); - }); - - it("should allow access to all resources when resources is not provided", function () { - configuration.rules = [{ - domain: "*.mail.example.com", - policy: "two_factor", - subject: "user:user1" - }]; - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.DENY); - Assert.equal(authorizer.authorization({domain: "mx1.mail.example.com", resource: "/"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "mx1.server.mail.example.com", resource: "/"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "mail.example.com", resource: "/"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.DENY); - }); - - describe("check user rules", function () { - it("should allow access when user has a matching allowing rule", function () { - configuration.rules = [{ - domain: "home.example.com", - policy: "two_factor", - resources: [".*"], - subject: "user:user1" - }]; - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/another/resource"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "another.home.example.com", resource: "/"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.DENY); - }); - - it("should deny to other users", function () { - configuration.rules = [{ - domain: "home.example.com", - policy: "two_factor", - resources: [".*"], - subject: "user:user1" - }]; - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/"}, {user: "user2", groups: ["group1"]}, "127.0.0.1"), Level.DENY); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/another/resource"}, {user: "user2", groups: ["group1"]}, "127.0.0.1"), Level.DENY); - Assert.equal(authorizer.authorization({domain: "another.home.example.com", resource: "/"}, {user: "user2", groups: ["group1"]}, "127.0.0.1"), Level.DENY); - }); - - it("should allow user access only to specific resources", function () { - configuration.rules = [{ - domain: "home.example.com", - policy: "two_factor", - resources: ["/private/.*", "^/begin", "/end$"], - subject: "user:user1" - }]; - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.DENY); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/private"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.DENY); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/private/class"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/middle/private/class"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.TWO_FACTOR); - - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/begin"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/not/begin"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.DENY); - - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/abc/end"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/abc/end/x"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.DENY); - }); - - it("should allow access to multiple domains", function () { - configuration.rules = [{ - domain: "home.example.com", - policy: "two_factor", - resources: [".*"], - subject: "user:user1" - }, { - domain: "home1.example.com", - policy: "one_factor", - resources: [".*"], - subject: "user:user1" - }, { - domain: "home2.example.com", - policy: "deny", - resources: [".*"], - subject: "user:user1" - }]; - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "home1.example.com", resource: "/"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.ONE_FACTOR); - Assert.equal(authorizer.authorization({domain: "home2.example.com", resource: "/"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.DENY); - Assert.equal(authorizer.authorization({domain: "home3.example.com", resource: "/"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.DENY); - }); - - it("should apply rules in order", function () { - configuration.rules = [{ - domain: "home.example.com", - policy: "one_factor", - resources: ["/my/private/resource"], - subject: "user:user1" - }, { - domain: "home.example.com", - policy: "deny", - resources: ["^/my/private/.*"], - subject: "user:user1" - }, { - domain: "home.example.com", - policy: "two_factor", - resources: ["^/my/.*"], - subject: "user:user1" - }]; - - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/my/poney"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/my/private/duck"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.DENY); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/my/private/resource"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.ONE_FACTOR); - }); - }); - - describe("check group rules", function () { - it("should allow access when user is in group having a matching allowing rule", function () { - configuration.rules = [{ - domain: "home.example.com", - policy: "two_factor", - resources: ["^/$"], - subject: "group:group1" - }, { - domain: "home.example.com", - policy: "one_factor", - resources: ["^/test$"], - subject: "group:group2" - }, { - domain: "home.example.com", - policy: "deny", - resources: ["^/private$"], - subject: "group:group2" - }]; - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/"}, - {user: "user1", groups: ["group1", "group2", "group3"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/test"}, - {user: "user1", groups: ["group1", "group2", "group3"]}, "127.0.0.1"), Level.ONE_FACTOR); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/private"}, - {user: "user1", groups: ["group1", "group2", "group3"]}, "127.0.0.1"), Level.DENY); - Assert.equal(authorizer.authorization({domain: "another.home.example.com", resource: "/"}, - {user: "user1", groups: ["group1", "group2", "group3"]}, "127.0.0.1"), Level.DENY); - }); - }); - }); - - describe("check any rules", function () { - it("should control access when any rules are defined", function () { - configuration.rules = [{ - domain: "home.example.com", - policy: "bypass", - resources: ["^/public$"] - }, { - domain: "home.example.com", - policy: "deny", - resources: ["^/private$"] - }]; - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/public"}, - {user: "user1", groups: ["group1", "group2", "group3"]}, "127.0.0.1"), Level.BYPASS); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/private"}, - {user: "user1", groups: ["group1", "group2", "group3"]}, "127.0.0.1"), Level.DENY); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/public"}, - {user: "user4", groups: ["group5"]}, "127.0.0.1"), Level.BYPASS); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/private"}, - {user: "user4", groups: ["group5"]}, "127.0.0.1"), Level.DENY); - }); - }); - - describe("check access control with default policy to allow", function () { - beforeEach(function () { - configuration.default_policy = "bypass"; - }); - - it("should allow access to anything when no rule is provided", function () { - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.BYPASS); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/test"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.BYPASS); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/dev"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.BYPASS); - }); - - it("should deny access to one resource when defined", function () { - configuration.rules = [{ - domain: "home.example.com", - policy: "deny", - resources: ["/test"], - subject: "user:user1" - }]; - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.BYPASS); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/test"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.DENY); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/dev"}, {user: "user1", groups: ["group1"]}, "127.0.0.1"), Level.BYPASS); - }); - }); - - describe("check access control with complete use case", function () { - beforeEach(function () { - configuration.default_policy = "deny"; - }); - - it("should control access of multiple user (real use case)", function () { - // Let say we have three users: admin, john, harry. - // admin is in groups ["admins"] - // john is in groups ["dev", "admin-private"] - // harry is in groups ["dev"] - configuration.rules = [{ - domain: "home.example.com", - policy: "two_factor", - resources: ["^/public$", "^/$"] - }, { - domain: "home.example.com", - policy: "two_factor", - resources: [".*"], - subject: "group:admins" - }, { - domain: "home.example.com", - policy: "two_factor", - resources: ["^/private/?.*"], - subject: "group:admin-private" - }, { - domain: "home.example.com", - policy: "two_factor", - resources: ["^/private/john$"], - subject: "user:john" - }, { - domain: "home.example.com", - policy: "two_factor", - resources: ["^/private/harry"], - subject: "user:harry" - }]; - - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/"}, {user: "admin", groups: ["admins"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/public"}, {user: "admin", groups: ["admins"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/dev"}, {user: "admin", groups: ["admins"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/dev/bob"}, {user: "admin", groups: ["admins"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/admin"}, {user: "admin", groups: ["admins"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/private/josh"}, {user: "admin", groups: ["admins"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/private/john"}, {user: "admin", groups: ["admins"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/private/harry"}, {user: "admin", groups: ["admins"]}, "127.0.0.1"), Level.TWO_FACTOR); - - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/"}, {user: "john", groups: ["dev", "admin-private"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/public"}, {user: "john", groups: ["dev", "admin-private"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/dev"}, {user: "john", groups: ["dev", "admin-private"]}, "127.0.0.1"), Level.DENY); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/dev/bob"}, {user: "john", groups: ["dev", "admin-private"]}, "127.0.0.1"), Level.DENY); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/admin"}, {user: "john", groups: ["dev", "admin-private"]}, "127.0.0.1"), Level.DENY); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/private/josh"}, {user: "john", groups: ["dev", "admin-private"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/private/john"}, {user: "john", groups: ["dev", "admin-private"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/private/harry"}, {user: "john", groups: ["dev", "admin-private"]}, "127.0.0.1"), Level.TWO_FACTOR); - - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/"}, {user: "harry", groups: ["dev"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/public"}, {user: "harry", groups: ["dev"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/dev"}, {user: "harry", groups: ["dev"]}, "127.0.0.1"), Level.DENY); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/dev/bob"}, {user: "harry", groups: ["dev"]}, "127.0.0.1"), Level.DENY); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/admin"}, {user: "harry", groups: ["dev"]}, "127.0.0.1"), Level.DENY); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/private/josh"}, {user: "harry", groups: ["dev"]}, "127.0.0.1"), Level.DENY); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/private/john"}, {user: "harry", groups: ["dev"]}, "127.0.0.1"), Level.DENY); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/private/harry"}, {user: "harry", groups: ["dev"]}, "127.0.0.1"), Level.TWO_FACTOR); - }); - - it("should allow when allowed at group level and denied at user level", function () { - configuration.rules = [{ - domain: "home.example.com", - policy: "deny", - resources: ["^/dev/bob$"], - subject: "user:john" - }, { - domain: "home.example.com", - policy: "two_factor", - resources: ["^/dev/?.*$"], - subject: "group:dev" - }]; - - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/dev/john"}, {user: "john", groups: ["dev"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/dev/bob"}, {user: "john", groups: ["dev"]}, "127.0.0.1"), Level.DENY); - }); - - it("should allow access when allowed at 'any' level and denied at user level", function () { - configuration.rules = [{ - domain: "home.example.com", - policy: "deny", - resources: ["^/dev/bob$"], - subject: "user:john" - }, { - domain: "home.example.com", - policy: "two_factor", - resources: ["^/dev/?.*$"] - }]; - - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/dev/john"}, {user: "john", groups: ["dev"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/dev/bob"}, {user: "john", groups: ["dev"]}, "127.0.0.1"), Level.DENY); - }); - - it("should allow access when allowed at 'any' level and denied at group level", function () { - configuration.rules = [{ - domain: "home.example.com", - policy: "deny", - resources: ["^/dev/bob$"], - subject: "group:dev" - }, { - domain: "home.example.com", - policy: "two_factor", - resources: ["^/dev/?.*$"] - }]; - - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/dev/john"}, {user: "john", groups: ["dev"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/dev/bob"}, {user: "john", groups: ["dev"]}, "127.0.0.1"), Level.DENY); - }); - - it("should respect rules precedence", function () { - // the priority from least to most is 'default_policy', 'all', 'group', 'user' - // and the first rules in each category as a lower priority than the latest. - // You can think of it that way: they override themselves inside each category. - configuration.rules = [{ - domain: "home.example.com", - policy: "two_factor", - resources: ["^/dev/?.*$"], - subject: "user:john" - }, { - domain: "home.example.com", - policy: "deny", - resources: ["^/dev/bob$"], - subject: "group:dev" - }, { - domain: "home.example.com", - policy: "two_factor", - resources: ["^/dev/?.*$"] - }]; - - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/dev/john"}, {user: "john", groups: ["dev"]}, "127.0.0.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/dev/bob"}, {user: "john", groups: ["dev"]}, "127.0.0.1"), Level.TWO_FACTOR); - }); - }); - - describe("check network rules", function () { - beforeEach(function () { - configuration.rules = [{ - domain: "home.example.com", - policy: "one_factor", - subject: "user:john", - networks: ["192.168.0.0/24", "10.0.0.0/8"] - }, - { - domain: "home.example.com", - policy: "two_factor", - subject: "user:john", - }, - { - domain: "public.example.com", - policy: "bypass", - networks: ["10.0.0.0/8"] - }]; - }); - - it("should respect network ranges", function() { - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/dev/john"}, {user: "john", groups: ["dev"]}, "192.168.4.1"), Level.TWO_FACTOR); - Assert.equal(authorizer.authorization({domain: "home.example.com", resource: "/dev/bob"}, {user: "john", groups: ["dev"]}, "192.168.0.5"), Level.ONE_FACTOR); - Assert.equal(authorizer.authorization({domain: "public.example.com", resource: "/dev/bob"}, {user: "john", groups: ["dev"]}, "10.1.3.0"), Level.BYPASS); - Assert.equal(authorizer.authorization({domain: "public.example.com", resource: "/dev/bob"}, {user: "john", groups: ["dev"]}, "11.1.3.0"), Level.DENY); - }); - }); - }); -}); diff --git a/server/src/lib/authorization/Authorizer.ts b/server/src/lib/authorization/Authorizer.ts deleted file mode 100644 index d7243e747..000000000 --- a/server/src/lib/authorization/Authorizer.ts +++ /dev/null @@ -1,95 +0,0 @@ - -import { ACLConfiguration, ACLRule, ACLPolicy } from "../configuration/schema/AclConfiguration"; -import { IAuthorizer } from "./IAuthorizer"; -import { Winston } from "../../../types/Dependencies"; -import { MultipleDomainMatcher } from "./MultipleDomainMatcher"; -import { Level } from "./Level"; -import { Object } from "./Object"; -import { Subject } from "./Subject"; -const IpRangeCheck = require("ip-range-check"); - -function MatchDomain(actualDomain: string) { - return function (rule: ACLRule): boolean { - return MultipleDomainMatcher.match(actualDomain, rule.domain); - }; -} - -function MatchResource(actualResource: string) { - return function (rule: ACLRule): boolean { - // If resources key is not provided, the rule applies to all resources. - if (!rule.resources) return true; - - for (let i = 0; i < rule.resources.length; ++i) { - const regexp = new RegExp(rule.resources[i]); - if (regexp.test(actualResource)) return true; - } - return false; - }; -} - -function MatchSubject(subject: Subject) { - return (rule: ACLRule) => { - // If no subject, matches anybody - if (!rule.subject) return true; - - if (rule.subject.startsWith("user:")) { - const ruleUser = rule.subject.split(":")[1]; - if (subject.user == ruleUser) return true; - } - - if (rule.subject.startsWith("group:")) { - const ruleGroup = rule.subject.split(":")[1]; - if (subject.groups.indexOf(ruleGroup) > -1) return true; - } - return false; - }; -} - -function MatchNetworks(ip: string) { - return (rule: ACLRule): boolean => { - if (!rule.networks) return true; // all networks match - - return rule.networks - .map(net => IpRangeCheck(ip, net) as boolean) - .reduce((acc, v) => acc || v, false); - }; -} - -export class Authorizer implements IAuthorizer { - private readonly configuration: ACLConfiguration; - - constructor(configuration: ACLConfiguration, logger_: Winston) { - this.configuration = configuration; - } - - private getMatchingRules(object: Object, subject: Subject, ip: string): ACLRule[] { - const rules = this.configuration.rules; - if (!rules) return []; - return rules - .filter(MatchDomain(object.domain)) - .filter(MatchResource(object.resource)) - .filter(MatchSubject(subject)) - .filter(MatchNetworks(ip)); - } - - private ruleToLevel(policy: ACLPolicy): Level { - if (policy == "bypass") { - return Level.BYPASS; - } else if (policy == "one_factor") { - return Level.ONE_FACTOR; - } else if (policy == "two_factor") { - return Level.TWO_FACTOR; - } - return Level.DENY; - } - - authorization(object: Object, subject: Subject, ip: string): Level { - if (!this.configuration) return Level.BYPASS; - - const rules = this.getMatchingRules(object, subject, ip); - - return (rules.length > 0) - ? this.ruleToLevel(rules[0].policy) // extract the policy of the first matching rule - : this.ruleToLevel(this.configuration.default_policy); // otherwise use the default policy - } -} \ No newline at end of file diff --git a/server/src/lib/authorization/AuthorizerStub.spec.ts b/server/src/lib/authorization/AuthorizerStub.spec.ts deleted file mode 100644 index b0b03dbee..000000000 --- a/server/src/lib/authorization/AuthorizerStub.spec.ts +++ /dev/null @@ -1,17 +0,0 @@ -import Sinon = require("sinon"); -import { IAuthorizer } from "./IAuthorizer"; -import { Level } from "./Level"; -import { Object } from "./Object"; -import { Subject } from "./Subject"; - -export default class AuthorizerStub implements IAuthorizer { - authorizationMock: Sinon.SinonStub; - - constructor() { - this.authorizationMock = Sinon.stub(); - } - - authorization(object: Object, subject: Subject, ip: string): Level { - return this.authorizationMock(object, subject, ip); - } -} diff --git a/server/src/lib/authorization/IAuthorizer.ts b/server/src/lib/authorization/IAuthorizer.ts deleted file mode 100644 index 42afe7745..000000000 --- a/server/src/lib/authorization/IAuthorizer.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Level } from "./Level"; -import { Subject } from "./Subject"; -import { Object } from "./Object"; - -export interface IAuthorizer { - authorization(object: Object, subject: Subject, ip: string): Level; -} \ No newline at end of file diff --git a/server/src/lib/authorization/Level.ts b/server/src/lib/authorization/Level.ts deleted file mode 100644 index d12802610..000000000 --- a/server/src/lib/authorization/Level.ts +++ /dev/null @@ -1,6 +0,0 @@ -export enum Level { - BYPASS = 0, - ONE_FACTOR = 1, - TWO_FACTOR = 2, - DENY = 3 -} \ No newline at end of file diff --git a/server/src/lib/authorization/MultipleDomainMatcher.ts b/server/src/lib/authorization/MultipleDomainMatcher.ts deleted file mode 100644 index 64c647a4a..000000000 --- a/server/src/lib/authorization/MultipleDomainMatcher.ts +++ /dev/null @@ -1,12 +0,0 @@ - -export class MultipleDomainMatcher { - static match(domain: string, pattern: string): boolean { - if (pattern.startsWith("*") && - domain.endsWith(pattern.substr(1))) { - return true; - } - else if (domain == pattern) { - return true; - } - } -} \ No newline at end of file diff --git a/server/src/lib/authorization/Object.ts b/server/src/lib/authorization/Object.ts deleted file mode 100644 index 5411b0d24..000000000 --- a/server/src/lib/authorization/Object.ts +++ /dev/null @@ -1,5 +0,0 @@ - -export interface Object { - domain: string; - resource: string; -} \ No newline at end of file diff --git a/server/src/lib/authorization/Subject.ts b/server/src/lib/authorization/Subject.ts deleted file mode 100644 index 310d6b4c0..000000000 --- a/server/src/lib/authorization/Subject.ts +++ /dev/null @@ -1,5 +0,0 @@ - -export interface Subject { - user: string; - groups: string[]; -} \ No newline at end of file diff --git a/server/src/lib/configuration/ConfigurationParser.spec.ts b/server/src/lib/configuration/ConfigurationParser.spec.ts deleted file mode 100644 index 60c0f6182..000000000 --- a/server/src/lib/configuration/ConfigurationParser.spec.ts +++ /dev/null @@ -1,171 +0,0 @@ -import * as Assert from "assert"; -import { Configuration } from "./schema/Configuration"; -import { ACLConfiguration } from "./schema/AclConfiguration"; -import { ConfigurationParser } from "./ConfigurationParser"; - -describe("configuration/ConfigurationParser", function () { - function buildYamlConfig(): Configuration { - const yaml_config: Configuration = { - port: 8080, - authentication_backend: { - ldap: { - url: "http://ldap", - base_dn: "dc=example,dc=com", - additional_users_dn: "ou=users", - additional_groups_dn: "ou=groups", - user: "user", - password: "pass" - }, - }, - session: { - domain: "example.com", - secret: "secret", - expiration: 40000 - }, - storage: { - local: { - path: "/mydirectory" - } - }, - regulation: { - max_retries: 3, - find_time: 5 * 60, - ban_time: 5 * 60 - }, - logs_level: "debug", - notifier: { - email: { - username: "user", - password: "password", - sender: "admin@example.com", - service: "gmail" - } - } - }; - return yaml_config; - } - - describe("port", function () { - it("should read the port from the yaml file", function () { - const yaml_config = buildYamlConfig(); - yaml_config.port = 7070; - const config = ConfigurationParser.parse(yaml_config); - Assert.equal(config.port, 7070); - }); - - it("should default the port to 8080 if not provided", function () { - const yaml_config = buildYamlConfig(); - delete yaml_config.port; - const config = ConfigurationParser.parse(yaml_config); - Assert.equal(config.port, 8080); - }); - }); - - describe("test session configuration", function() { - it("should get the session attributes", function () { - const yaml_config = buildYamlConfig(); - yaml_config.session = { - domain: "example.com", - secret: "secret", - expiration: 3600, - inactivity: 4000 - }; - const config = ConfigurationParser.parse(yaml_config); - Assert.equal(config.session.domain, "example.com"); - Assert.equal(config.session.secret, "secret"); - Assert.equal(config.session.expiration, 3600); - Assert.equal(config.session.inactivity, 4000); - }); - - it("should be ok not specifying inactivity", function () { - const yaml_config = buildYamlConfig(); - yaml_config.session = { - domain: "example.com", - secret: "secret", - expiration: 3600 - }; - const config = ConfigurationParser.parse(yaml_config); - Assert.equal(config.session.domain, "example.com"); - Assert.equal(config.session.secret, "secret"); - Assert.equal(config.session.expiration, 3600); - Assert.equal(config.session.inactivity, undefined); - }); - }); - - it("should get the log level", function () { - const yaml_config = buildYamlConfig(); - yaml_config.logs_level = "debug"; - const config = ConfigurationParser.parse(yaml_config); - Assert.equal(config.logs_level, "debug"); - }); - - it("should get the notifier config", function () { - const userConfig = buildYamlConfig(); - userConfig.notifier = { - email: { - username: "user", - password: "pass", - sender: "admin@example.com", - service: "gmail" - } - }; - const config = ConfigurationParser.parse(userConfig); - Assert.deepEqual(config.notifier, { - email: { - username: "user", - password: "pass", - sender: "admin@example.com", - service: "gmail" - } - }); - }); - - describe("access_control", function() { - it("should adapt access_control when it is already ok", function () { - const userConfig = buildYamlConfig(); - userConfig.access_control = { - default_policy: "deny", - rules: [{ - domain: "www.example.com", - policy: "two_factor", - subject: "user:user" - }, { - domain: "public.example.com", - policy: "two_factor" - }] - }; - const config = ConfigurationParser.parse(userConfig); - Assert.deepEqual(config.access_control, { - default_policy: "deny", - rules: [{ - domain: "www.example.com", - policy: "two_factor", - subject: "user:user" - }, { - domain: "public.example.com", - policy: "two_factor" - }] - } as ACLConfiguration); - }); - - - it("should adapt access_control when it is empty", function () { - const userConfig = buildYamlConfig(); - userConfig.access_control = {} as any; - const config = ConfigurationParser.parse(userConfig); - Assert.deepEqual(config.access_control, { - default_policy: "bypass", - rules: [] - }); - }); - }); - - describe("default_redirection_url", function() { - it("should parse default_redirection_url", function() { - const userConfig = buildYamlConfig(); - userConfig.default_redirection_url = "dummy_url"; - const config = ConfigurationParser.parse(userConfig); - Assert.deepEqual(config.default_redirection_url, "dummy_url"); - }); - }); -}); diff --git a/server/src/lib/configuration/ConfigurationParser.ts b/server/src/lib/configuration/ConfigurationParser.ts deleted file mode 100644 index d92d163c4..000000000 --- a/server/src/lib/configuration/ConfigurationParser.ts +++ /dev/null @@ -1,39 +0,0 @@ - -import * as ObjectPath from "object-path"; -import { Configuration, complete } from "./schema/Configuration"; -import Ajv = require("ajv"); -import Path = require("path"); -import Util = require("util"); - -export class ConfigurationParser { - private static parseTypes(configuration: Configuration): string[] { - const schema = require(Path.resolve(__dirname, "./Configuration.schema.json")); - const ajv = new Ajv({ - allErrors: true, - missingRefs: "fail" - }); - ajv.addMetaSchema(require("ajv/lib/refs/json-schema-draft-06.json")); - const valid = ajv.validate(schema, configuration); - if (!valid) - return ajv.errors.map( - (e: Ajv.ErrorObject) => { return ajv.errorsText([e]); }); - return []; - } - - static parse(configuration: Configuration): Configuration { - const validationErrors = this.parseTypes(configuration); - if (validationErrors.length > 0) { - validationErrors.forEach((e: string) => { console.log(e); }); - throw new Error("Malformed configuration (schema). Please double-check your configuration file."); - } - - const [newConfiguration, completionErrors] = complete(configuration); - - if (completionErrors.length > 0) { - completionErrors.forEach((e: string) => { console.log(e); }); - throw new Error("Malformed configuration (validator). Please double-check your configuration file."); - } - return newConfiguration; - } -} - diff --git a/server/src/lib/configuration/SessionConfigurationBuilder.spec.ts b/server/src/lib/configuration/SessionConfigurationBuilder.spec.ts deleted file mode 100644 index 1ecc3c21c..000000000 --- a/server/src/lib/configuration/SessionConfigurationBuilder.spec.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { SessionConfigurationBuilder } from "./SessionConfigurationBuilder"; -import { Configuration } from "./schema/Configuration"; -import { GlobalDependencies } from "../../../types/Dependencies"; - -import ExpressSession = require("express-session"); -import Sinon = require("sinon"); -import Assert = require("assert"); - -describe("configuration/SessionConfigurationBuilder", function () { - const configuration: Configuration = { - access_control: { - default_policy: "deny", - rules: [] - }, - totp: { - issuer: "authelia.com" - }, - authentication_backend: { - ldap: { - url: "ldap://ldap", - user: "user", - base_dn: "dc=example,dc=com", - password: "password", - additional_groups_dn: "ou=groups", - additional_users_dn: "ou=users", - group_name_attribute: "", - groups_filter: "", - mail_attribute: "", - users_filter: "" - }, - }, - logs_level: "debug", - notifier: { - filesystem: { - filename: "/test" - } - }, - port: 8080, - session: { - name: "authelia_session", - domain: "example.com", - expiration: 3600, - secret: "secret" - }, - regulation: { - max_retries: 3, - ban_time: 5 * 60, - find_time: 5 * 60 - }, - storage: { - local: { - in_memory: true - } - } - }; - - const deps: GlobalDependencies = { - ConnectRedis: Sinon.spy() as any, - ldapjs: Sinon.spy() as any, - nedb: Sinon.spy() as any, - session: Sinon.spy() as any, - speakeasy: Sinon.spy() as any, - u2f: Sinon.spy() as any, - winston: Sinon.spy() as any, - Redis: Sinon.spy() as any - }; - - it("should return session options without redis options", function () { - const options = SessionConfigurationBuilder.build(configuration, deps); - const expectedOptions = { - name: "authelia_session", - secret: "secret", - resave: false, - saveUninitialized: true, - cookie: { - secure: true, - httpOnly: true, - maxAge: 3600, - domain: "example.com" - } - }; - - Assert.deepEqual(expectedOptions, options); - }); - - it("should return session options with redis options", function () { - configuration.session["redis"] = { - host: "redis.example.com", - port: 6379 - }; - const RedisStoreMock = Sinon.spy(); - const redisClient = Sinon.mock().returns({ on: Sinon.spy() }); - - deps.ConnectRedis = Sinon.stub().returns(RedisStoreMock) as any; - deps.Redis = { - createClient: Sinon.mock().returns(redisClient) - } as any; - - const options = SessionConfigurationBuilder.build(configuration, deps); - - const expectedOptions: ExpressSession.SessionOptions = { - secret: "secret", - resave: false, - saveUninitialized: true, - name: "authelia_session", - cookie: { - secure: true, - httpOnly: true, - maxAge: 3600, - domain: "example.com" - }, - store: Sinon.match.object as any - }; - - Assert((deps.ConnectRedis as Sinon.SinonStub).calledWith(deps.session)); - Assert.equal(options.secret, expectedOptions.secret); - Assert.equal(options.resave, expectedOptions.resave); - Assert.equal(options.saveUninitialized, expectedOptions.saveUninitialized); - Assert.deepEqual(options.cookie, expectedOptions.cookie); - Assert(options.store != undefined); - }); - - it("should return session options with redis password", function () { - configuration.session["redis"] = { - host: "redis.example.com", - port: 6379, - password: "authelia_pass" - }; - const RedisStoreMock = Sinon.spy(); - deps.ConnectRedis = Sinon.stub().returns(RedisStoreMock); - - SessionConfigurationBuilder.build(configuration, deps); - - Assert(RedisStoreMock.calledWith({ - host: "redis.example.com", - port: 6379, - pass: "authelia_pass", - logErrors: true, - })); - }); -}); \ No newline at end of file diff --git a/server/src/lib/configuration/SessionConfigurationBuilder.ts b/server/src/lib/configuration/SessionConfigurationBuilder.ts deleted file mode 100644 index 6f621b317..000000000 --- a/server/src/lib/configuration/SessionConfigurationBuilder.ts +++ /dev/null @@ -1,31 +0,0 @@ -import ExpressSession = require("express-session"); -import { Configuration } from "./schema/Configuration"; -import { GlobalDependencies } from "../../../types/Dependencies"; - -export class SessionConfigurationBuilder { - static build(configuration: Configuration, deps: GlobalDependencies): ExpressSession.SessionOptions { - const sessionOptions: ExpressSession.SessionOptions = { - name: configuration.session.name, - secret: configuration.session.secret, - resave: false, - saveUninitialized: true, - cookie: { - secure: true, - httpOnly: true, - maxAge: configuration.session.expiration, - domain: configuration.session.domain - }, - }; - - if (configuration.session.redis) { - const RedisStore = deps.ConnectRedis(deps.session); - sessionOptions.store = new RedisStore({ - host: configuration.session.redis.host, - port: configuration.session.redis.port, - pass: configuration.session.redis.password, - logErrors: true - }); - } - return sessionOptions; - } -} \ No newline at end of file diff --git a/server/src/lib/configuration/schema/AclConfiguration.spec.ts b/server/src/lib/configuration/schema/AclConfiguration.spec.ts deleted file mode 100644 index d1e2a03a2..000000000 --- a/server/src/lib/configuration/schema/AclConfiguration.spec.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { ACLConfiguration, complete } from "./AclConfiguration"; -import Assert = require("assert"); - -describe("configuration/schema/AclConfiguration", function() { - it("should complete ACLConfiguration", function() { - const configuration: ACLConfiguration = {}; - const [newConfiguration, errors] = complete(configuration); - - Assert.deepEqual(newConfiguration.default_policy, "bypass"); - Assert.deepEqual(newConfiguration.rules, []); - }); - - it("should return errors when subject is not good", function() { - const configuration: ACLConfiguration = { - default_policy: "deny", - rules: [{ - domain: "dev.example.com", - subject: "user:abc", - policy: "bypass" - }, { - domain: "dev.example.com", - subject: "user:def", - policy: "bypass" - }, { - domain: "dev.example.com", - subject: "badkey:abc", - policy: "bypass" - }] - }; - const [newConfiguration, errors] = complete(configuration); - - Assert.deepEqual(errors, ["Rule 2 has wrong subject. It should be starting with user: or group:."]); - }); -}); \ No newline at end of file diff --git a/server/src/lib/configuration/schema/AclConfiguration.ts b/server/src/lib/configuration/schema/AclConfiguration.ts deleted file mode 100644 index 0ca22aeda..000000000 --- a/server/src/lib/configuration/schema/AclConfiguration.ts +++ /dev/null @@ -1,44 +0,0 @@ - -export type ACLPolicy = "deny" | "bypass" | "one_factor" | "two_factor"; - -export type ACLNetwork = string[]; - -export type ACLRule = { - domain: string; - resources?: string[]; - subject?: string; - policy: ACLPolicy; - networks?: ACLNetwork; -}; - -export interface ACLConfiguration { - default_policy?: ACLPolicy; - rules?: ACLRule[]; -} - -export function complete(configuration: ACLConfiguration): [ACLConfiguration, string[]] { - const newConfiguration: ACLConfiguration = (configuration) - ? JSON.parse(JSON.stringify(configuration)) : {}; - - if (!newConfiguration.default_policy) { - newConfiguration.default_policy = "bypass"; - } - - if (!newConfiguration.rules) { - newConfiguration.rules = []; - } - - if (newConfiguration.rules.length > 0) { - const errors: string[] = []; - newConfiguration.rules.forEach((r, idx) => { - if (r.subject && !r.subject.match(/^(user|group):[a-zA-Z0-9]+$/)) { - errors.push(`Rule ${idx} has wrong subject. It should be starting with user: or group:.`); - } - }); - if (errors.length > 0) { - return [newConfiguration, errors]; - } - } - - return [newConfiguration, []]; -} \ No newline at end of file diff --git a/server/src/lib/configuration/schema/AuthenticationBackendConfiguration.spec.ts b/server/src/lib/configuration/schema/AuthenticationBackendConfiguration.spec.ts deleted file mode 100644 index 3ca86381c..000000000 --- a/server/src/lib/configuration/schema/AuthenticationBackendConfiguration.spec.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { AuthenticationBackendConfiguration, complete } from "./AuthenticationBackendConfiguration"; -import Assert = require("assert"); - -describe("configuration/schema/AuthenticationBackendConfiguration", function() { - it("should ensure there is at least one key", function() { - const configuration: AuthenticationBackendConfiguration = {} as any; - const [newConfiguration, error] = complete(configuration); - - Assert.equal(error, "Authentication backend must have one of the following keys:`ldap` or `file`"); - }); -}); \ No newline at end of file diff --git a/server/src/lib/configuration/schema/AuthenticationBackendConfiguration.ts b/server/src/lib/configuration/schema/AuthenticationBackendConfiguration.ts deleted file mode 100644 index 7f77f894f..000000000 --- a/server/src/lib/configuration/schema/AuthenticationBackendConfiguration.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { LdapConfiguration } from "./LdapConfiguration"; -import { FileUsersDatabaseConfiguration } from "./FileUsersDatabaseConfiguration"; - -export interface AuthenticationBackendConfiguration { - ldap?: LdapConfiguration; - file?: FileUsersDatabaseConfiguration; -} - -export function complete( - configuration: AuthenticationBackendConfiguration) - : [AuthenticationBackendConfiguration, string] { - - const newConfiguration: AuthenticationBackendConfiguration = (configuration) - ? JSON.parse(JSON.stringify(configuration)) : {}; - - if (Object.keys(newConfiguration).length != 1) { - return [ - newConfiguration, - "Authentication backend must have one of the following keys:" + - "`ldap` or `file`" - ]; - } - - return [newConfiguration, undefined]; -} \ No newline at end of file diff --git a/server/src/lib/configuration/schema/Configuration.ts b/server/src/lib/configuration/schema/Configuration.ts deleted file mode 100644 index d0584732b..000000000 --- a/server/src/lib/configuration/schema/Configuration.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { ACLConfiguration, complete as AclConfigurationComplete } from "./AclConfiguration"; -import { AuthenticationBackendConfiguration, complete as AuthenticationBackendComplete } from "./AuthenticationBackendConfiguration"; -import { NotifierConfiguration, complete as NotifierConfigurationComplete } from "./NotifierConfiguration"; -import { RegulationConfiguration, complete as RegulationConfigurationComplete } from "./RegulationConfiguration"; -import { SessionConfiguration, complete as SessionConfigurationComplete } from "./SessionConfiguration"; -import { StorageConfiguration, complete as StorageConfigurationComplete } from "./StorageConfiguration"; -import { TotpConfiguration, complete as TotpConfigurationComplete } from "./TotpConfiguration"; -import { DuoPushConfiguration } from "./DuoPushConfiguration"; - -export interface Configuration { - access_control?: ACLConfiguration; - authentication_backend: AuthenticationBackendConfiguration; - default_redirection_url?: string; - logs_level?: string; - notifier?: NotifierConfiguration; - port?: number; - regulation?: RegulationConfiguration; - session?: SessionConfiguration; - storage?: StorageConfiguration; - totp?: TotpConfiguration; - duo_api?: DuoPushConfiguration; -} - -export function complete( - configuration: Configuration): - [Configuration, string[]] { - - const newConfiguration: Configuration = JSON.parse( - JSON.stringify(configuration)); - const errors: string[] = []; - - const [acls, aclsErrors] = AclConfigurationComplete( - newConfiguration.access_control); - - newConfiguration.access_control = acls; - if (aclsErrors.length > 0) { - errors.concat(aclsErrors); - } - - const [backend, error] = - AuthenticationBackendComplete( - newConfiguration.authentication_backend); - - if (error) errors.push(error); - newConfiguration.authentication_backend = backend; - - if (!newConfiguration.logs_level) { - newConfiguration.logs_level = "info"; - } - - const [notifier, notifierError] = NotifierConfigurationComplete( - newConfiguration.notifier); - newConfiguration.notifier = notifier; - if (notifierError) errors.push(notifierError); - - if (!newConfiguration.port) { - newConfiguration.port = 8080; - } - - newConfiguration.regulation = RegulationConfigurationComplete( - newConfiguration.regulation); - newConfiguration.session = SessionConfigurationComplete( - newConfiguration.session); - newConfiguration.storage = StorageConfigurationComplete( - newConfiguration.storage); - newConfiguration.totp = TotpConfigurationComplete( - newConfiguration.totp); - - return [newConfiguration, errors]; -} \ No newline at end of file diff --git a/server/src/lib/configuration/schema/DuoPushConfiguration.ts b/server/src/lib/configuration/schema/DuoPushConfiguration.ts deleted file mode 100644 index bede37674..000000000 --- a/server/src/lib/configuration/schema/DuoPushConfiguration.ts +++ /dev/null @@ -1,6 +0,0 @@ - -export interface DuoPushConfiguration { - hostname: string; - integration_key: string; - secret_key: string; -} \ No newline at end of file diff --git a/server/src/lib/configuration/schema/FileUsersDatabaseConfiguration.ts b/server/src/lib/configuration/schema/FileUsersDatabaseConfiguration.ts deleted file mode 100644 index d19002ba9..000000000 --- a/server/src/lib/configuration/schema/FileUsersDatabaseConfiguration.ts +++ /dev/null @@ -1,4 +0,0 @@ - -export interface FileUsersDatabaseConfiguration { - path: string; -} \ No newline at end of file diff --git a/server/src/lib/configuration/schema/LdapConfiguration.spec.ts b/server/src/lib/configuration/schema/LdapConfiguration.spec.ts deleted file mode 100644 index cc73d1085..000000000 --- a/server/src/lib/configuration/schema/LdapConfiguration.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import Assert = require("assert"); -import { LdapConfiguration, complete } from "./LdapConfiguration"; - -describe("configuration/schema/AuthenticationMethodsConfiguration", function() { - it("should ensure at least one key is provided", function() { - const configuration: LdapConfiguration = { - url: "ldap.example.com", - base_dn: "dc=example,dc=com", - user: "admin", - password: "password" - }; - const newConfiguration = complete(configuration); - - Assert.deepEqual(newConfiguration, { - url: "ldap.example.com", - base_dn: "dc=example,dc=com", - user: "admin", - password: "password", - users_filter: "cn={0}", - group_name_attribute: "cn", - groups_filter: "member={dn}", - mail_attribute: "mail" - }); - }); -}); \ No newline at end of file diff --git a/server/src/lib/configuration/schema/LdapConfiguration.ts b/server/src/lib/configuration/schema/LdapConfiguration.ts deleted file mode 100644 index 9421d116f..000000000 --- a/server/src/lib/configuration/schema/LdapConfiguration.ts +++ /dev/null @@ -1,47 +0,0 @@ -import Util = require("util"); - -export interface LdapConfiguration { - url: string; - base_dn: string; - - additional_users_dn?: string; - users_filter?: string; - - additional_groups_dn?: string; - groups_filter?: string; - - group_name_attribute?: string; - mail_attribute?: string; - - user: string; // admin username - password: string; // admin password - - // The file name where node can find the ldap server CA certificate - // for when the ldap server uses a self signed cert - caCert?: string; - - // Used to try to reconnect on an ldap connection failure, defaults to true - reconnect?: boolean; -} - -export function complete(configuration: LdapConfiguration): LdapConfiguration { - const newConfiguration: LdapConfiguration = (configuration) ? JSON.parse(JSON.stringify(configuration)) : {}; - - if (!newConfiguration.users_filter) { - newConfiguration.users_filter = "cn={0}"; - } - - if (!newConfiguration.groups_filter) { - newConfiguration.groups_filter = "member={dn}"; - } - - if (!newConfiguration.group_name_attribute) { - newConfiguration.group_name_attribute = "cn"; - } - - if (!newConfiguration.mail_attribute) { - newConfiguration.mail_attribute = "mail"; - } - - return newConfiguration; -} \ No newline at end of file diff --git a/server/src/lib/configuration/schema/NotifierConfiguration.spec.ts b/server/src/lib/configuration/schema/NotifierConfiguration.spec.ts deleted file mode 100644 index 6c576e8e0..000000000 --- a/server/src/lib/configuration/schema/NotifierConfiguration.spec.ts +++ /dev/null @@ -1,40 +0,0 @@ -import Assert = require("assert"); -import { NotifierConfiguration, complete } from "./NotifierConfiguration"; - -describe("configuration/schema/NotifierConfiguration", function() { - it("should use a default notifier when none is provided", function() { - const configuration: NotifierConfiguration = {}; - const [newConfiguration, error] = complete(configuration); - - Assert.deepEqual(newConfiguration.filesystem, {filename: "/tmp/authelia/notification.txt"}); - }); - - it("should ensure correct key is provided", function() { - const configuration = { - abc: "badvalue" - }; - const [newConfiguration, error] = complete(configuration as any); - - Assert.equal(error, "Notifier must have one of the following keys: 'filesystem', 'email' or 'smtp'"); - }); - - it("should ensure there is no more than one key", function() { - const configuration: NotifierConfiguration = { - smtp: { - host: "smtp.example.com", - port: 25, - secure: false, - sender: "test@example.com" - }, - email: { - username: "test", - password: "test", - sender: "test@example.com", - service: "gmail" - } - }; - const [newConfiguration, error] = complete(configuration); - - Assert.equal(error, "Notifier must have one of the following keys: 'filesystem', 'email' or 'smtp'"); - }); -}); \ No newline at end of file diff --git a/server/src/lib/configuration/schema/NotifierConfiguration.ts b/server/src/lib/configuration/schema/NotifierConfiguration.ts deleted file mode 100644 index 7bcce15c2..000000000 --- a/server/src/lib/configuration/schema/NotifierConfiguration.ts +++ /dev/null @@ -1,45 +0,0 @@ - -export interface EmailNotifierConfiguration { - username: string; - password: string; - sender: string; - service: string; -} - -export interface SmtpNotifierConfiguration { - username?: string; - password?: string; - host: string; - port: number; - secure: boolean; - sender: string; -} - -export interface FileSystemNotifierConfiguration { - filename: string; -} - -export interface NotifierConfiguration { - email?: EmailNotifierConfiguration; - smtp?: SmtpNotifierConfiguration; - filesystem?: FileSystemNotifierConfiguration; -} - -export function complete(configuration: NotifierConfiguration): [NotifierConfiguration, string] { - const newConfiguration: NotifierConfiguration = (configuration) ? JSON.parse(JSON.stringify(configuration)) : {}; - - if (Object.keys(newConfiguration).length == 0) - newConfiguration.filesystem = { filename: "/tmp/authelia/notification.txt" }; - - const ERROR = "Notifier must have one of the following keys: 'filesystem', 'email' or 'smtp'"; - - if (Object.keys(newConfiguration).length != 1) - return [newConfiguration, ERROR]; - - const key = Object.keys(newConfiguration)[0]; - - if (key != "filesystem" && key != "smtp" && key != "email") - return [newConfiguration, ERROR]; - - return [newConfiguration, undefined]; -} diff --git a/server/src/lib/configuration/schema/RegulationConfiguration.spec.ts b/server/src/lib/configuration/schema/RegulationConfiguration.spec.ts deleted file mode 100644 index dce2caf4e..000000000 --- a/server/src/lib/configuration/schema/RegulationConfiguration.spec.ts +++ /dev/null @@ -1,13 +0,0 @@ -import Assert = require("assert"); -import { RegulationConfiguration, complete } from "./RegulationConfiguration"; - -describe("configuration/schema/RegulationConfiguration", function() { - it("should return default regulation configuration", function() { - const configuration: RegulationConfiguration = {}; - const newConfiguration = complete(configuration); - - Assert.equal(newConfiguration.ban_time, 300); - Assert.equal(newConfiguration.find_time, 120); - Assert.equal(newConfiguration.max_retries, 3); - }); -}); \ No newline at end of file diff --git a/server/src/lib/configuration/schema/RegulationConfiguration.ts b/server/src/lib/configuration/schema/RegulationConfiguration.ts deleted file mode 100644 index 117463f43..000000000 --- a/server/src/lib/configuration/schema/RegulationConfiguration.ts +++ /dev/null @@ -1,23 +0,0 @@ -export interface RegulationConfiguration { - max_retries?: number; - find_time?: number; - ban_time?: number; -} - -export function complete(configuration: RegulationConfiguration): RegulationConfiguration { - const newConfiguration: RegulationConfiguration = (configuration) ? JSON.parse(JSON.stringify(configuration)) : {}; - - if (!newConfiguration.max_retries) { - newConfiguration.max_retries = 3; - } - - if (!newConfiguration.find_time) { - newConfiguration.find_time = 120; // seconds - } - - if (!newConfiguration.ban_time) { - newConfiguration.ban_time = 300; // seconds - } - - return newConfiguration; -} \ No newline at end of file diff --git a/server/src/lib/configuration/schema/SessionConfiguration.spec.ts b/server/src/lib/configuration/schema/SessionConfiguration.spec.ts deleted file mode 100644 index e54010837..000000000 --- a/server/src/lib/configuration/schema/SessionConfiguration.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import Assert = require("assert"); -import { SessionConfiguration, complete } from "./SessionConfiguration"; - -describe("configuration/schema/SessionConfiguration", function() { - it("should return default regulation configuration", function() { - const configuration: SessionConfiguration = { - domain: "example.com", - secret: "unsecure_secret" - }; - const newConfiguration = complete(configuration); - - Assert.equal(newConfiguration.name, 'authelia_session'); - Assert.equal(newConfiguration.expiration, 3600000); - Assert.equal(newConfiguration.inactivity, undefined); - }); -}); \ No newline at end of file diff --git a/server/src/lib/configuration/schema/SessionConfiguration.ts b/server/src/lib/configuration/schema/SessionConfiguration.ts deleted file mode 100644 index 2c88bb215..000000000 --- a/server/src/lib/configuration/schema/SessionConfiguration.ts +++ /dev/null @@ -1,32 +0,0 @@ -export interface SessionRedisOptions { - host: string; - port: number; - password?: string; -} - -export interface SessionConfiguration { - name?: string; - domain: string; - secret: string; - expiration?: number; - inactivity?: number; - redis?: SessionRedisOptions; -} - -export function complete(configuration: SessionConfiguration): SessionConfiguration { - const newConfiguration: SessionConfiguration = (configuration) ? JSON.parse(JSON.stringify(configuration)) : {}; - - if (!newConfiguration.name) { - newConfiguration.name = "authelia_session"; - } - - if (!newConfiguration.expiration) { - newConfiguration.expiration = 3600000; // 1 hour - } - - if (!newConfiguration.inactivity) { - newConfiguration.inactivity = undefined; // disabled - } - - return newConfiguration; -} \ No newline at end of file diff --git a/server/src/lib/configuration/schema/StorageConfiguration.spec.ts b/server/src/lib/configuration/schema/StorageConfiguration.spec.ts deleted file mode 100644 index 9d02a11b6..000000000 --- a/server/src/lib/configuration/schema/StorageConfiguration.spec.ts +++ /dev/null @@ -1,15 +0,0 @@ -import Assert = require("assert"); -import { StorageConfiguration, complete } from "./StorageConfiguration"; - -describe("configuration/schema/StorageConfiguration", function() { - it("should return default regulation configuration", function() { - const configuration: StorageConfiguration = {}; - const newConfiguration = complete(configuration); - - Assert.deepEqual(newConfiguration, { - local: { - in_memory: true - } - }); - }); -}); \ No newline at end of file diff --git a/server/src/lib/configuration/schema/StorageConfiguration.ts b/server/src/lib/configuration/schema/StorageConfiguration.ts deleted file mode 100644 index 47e356ef4..000000000 --- a/server/src/lib/configuration/schema/StorageConfiguration.ts +++ /dev/null @@ -1,30 +0,0 @@ -export interface MongoStorageConfiguration { - url: string; - database: string; - auth?: { - username: string; - password: string; - }; -} - -export interface LocalStorageConfiguration { - path?: string; - in_memory?: boolean; -} - -export interface StorageConfiguration { - local?: LocalStorageConfiguration; - mongo?: MongoStorageConfiguration; -} - -export function complete(configuration: StorageConfiguration): StorageConfiguration { - const newConfiguration: StorageConfiguration = (configuration) ? JSON.parse(JSON.stringify(configuration)) : {}; - - if (!newConfiguration.local && !newConfiguration.mongo) { - newConfiguration.local = { - in_memory: true - }; - } - - return newConfiguration; -} \ No newline at end of file diff --git a/server/src/lib/configuration/schema/TotpConfiguration.ts b/server/src/lib/configuration/schema/TotpConfiguration.ts deleted file mode 100644 index 683135639..000000000 --- a/server/src/lib/configuration/schema/TotpConfiguration.ts +++ /dev/null @@ -1,13 +0,0 @@ -export interface TotpConfiguration { - issuer: string; -} - -export function complete(configuration: TotpConfiguration): TotpConfiguration { - const newConfiguration: TotpConfiguration = (configuration) ? JSON.parse(JSON.stringify(configuration)) : {}; - - if (!newConfiguration.issuer) { - newConfiguration.issuer = "authelia.com"; - } - - return newConfiguration; -} \ No newline at end of file diff --git a/server/src/lib/configuration/schema/UserDatabaseConfiguration.ts b/server/src/lib/configuration/schema/UserDatabaseConfiguration.ts deleted file mode 100644 index 8008b4833..000000000 --- a/server/src/lib/configuration/schema/UserDatabaseConfiguration.ts +++ /dev/null @@ -1,9 +0,0 @@ - -export interface UserInfo { - username: string; - password_hash: string; - email: string; - groups?: string[]; -} - -export type UserDatabaseConfiguration = UserInfo[]; \ No newline at end of file diff --git a/server/src/lib/connectors/mongo/IMongoClient.d.ts b/server/src/lib/connectors/mongo/IMongoClient.d.ts deleted file mode 100644 index 36cb4b8bf..000000000 --- a/server/src/lib/connectors/mongo/IMongoClient.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -import MongoDB = require("mongodb"); -import Bluebird = require("bluebird"); - -export interface IMongoClient { - collection(name: string): Bluebird -} \ No newline at end of file diff --git a/server/src/lib/connectors/mongo/MongoClient.spec.ts b/server/src/lib/connectors/mongo/MongoClient.spec.ts deleted file mode 100644 index ca0c68593..000000000 --- a/server/src/lib/connectors/mongo/MongoClient.spec.ts +++ /dev/null @@ -1,119 +0,0 @@ -import Assert = require("assert"); -import Bluebird = require("bluebird"); -import MongoDB = require("mongodb"); -import Sinon = require("sinon"); - -import { MongoClient } from "./MongoClient"; -import { GlobalLoggerStub } from "../../logging/GlobalLoggerStub.spec"; -import { MongoStorageConfiguration } from "../../configuration/schema/StorageConfiguration"; - -describe("connectors/mongo/MongoClient", function () { - let MongoClientStub: any; - let mongoClientStub: any; - let mongoDatabaseStub: any; - let logger: GlobalLoggerStub = new GlobalLoggerStub(); - - const configuration: MongoStorageConfiguration = { - url: "mongo://url", - database: "databasename" - }; - - describe("connection", () => { - before(() => { - mongoClientStub = { - db: Sinon.stub() - }; - mongoDatabaseStub = { - on: Sinon.stub(), - collection: Sinon.stub() - } - MongoClientStub = Sinon.stub( - MongoDB.MongoClient, "connect"); - MongoClientStub.yields( - undefined, mongoClientStub); - mongoClientStub.db.returns( - mongoDatabaseStub); - }); - - after(() => { - MongoClientStub.restore(); - }); - - it("should use credentials from configuration", () => { - configuration.auth = { - username: "authelia", - password: "authelia_pass" - }; - - const client = new MongoClient(configuration, logger); - return client.collection("test") - .then(() => { - Assert(MongoClientStub.calledWith("mongo://url", { - auth: { - user: "authelia", - password: "authelia_pass" - } - })) - }); - }); - }); - - describe("collection", () => { - before(function() { - mongoClientStub = { - db: Sinon.stub() - }; - mongoDatabaseStub = { - on: Sinon.stub(), - collection: Sinon.stub() - } - }); - - describe("Connection to mongo is ok", function() { - before(function () { - MongoClientStub = Sinon.stub( - MongoDB.MongoClient, "connect"); - MongoClientStub.yields( - undefined, mongoClientStub); - mongoClientStub.db.returns( - mongoDatabaseStub); - }); - - after(function () { - MongoClientStub.restore(); - }); - - it("should create a collection", function () { - const COLLECTION_NAME = "mycollection"; - const client = new MongoClient(configuration, logger); - - mongoDatabaseStub.collection.returns("COL"); - return client.collection(COLLECTION_NAME) - .then((collection) => mongoDatabaseStub.collection.calledWith(COLLECTION_NAME)); - }); - }); - - describe("Connection to mongo is broken", function() { - before(function () { - MongoClientStub = Sinon.stub( - MongoDB.MongoClient, "connect"); - MongoClientStub.yields( - new Error("Failed connection"), undefined); - }); - - after(function () { - MongoClientStub.restore(); - }); - - it("should fail creating the collection", function() { - const COLLECTION_NAME = "mycollection"; - const client = new MongoClient(configuration, logger); - - mongoDatabaseStub.collection.returns("COL"); - return client.collection(COLLECTION_NAME) - .then((collection) => Bluebird.reject(new Error("should not be here."))) - .catch((err) => Bluebird.resolve()); - }); - }) - }); -}); diff --git a/server/src/lib/connectors/mongo/MongoClient.ts b/server/src/lib/connectors/mongo/MongoClient.ts deleted file mode 100644 index 885abc90d..000000000 --- a/server/src/lib/connectors/mongo/MongoClient.ts +++ /dev/null @@ -1,75 +0,0 @@ - -import MongoDB = require("mongodb"); -import { IMongoClient } from "./IMongoClient"; -import Bluebird = require("bluebird"); -import { IGlobalLogger } from "../../logging/IGlobalLogger"; -import { MongoStorageConfiguration } from "../../configuration/schema/StorageConfiguration"; - -export class MongoClient implements IMongoClient { - private configuration: MongoStorageConfiguration; - - private database: MongoDB.Db; - private client: MongoDB.MongoClient; - private logger: IGlobalLogger; - - constructor( - configuration: MongoStorageConfiguration, - logger: IGlobalLogger) { - - this.configuration = configuration; - this.logger = logger; - } - - connect(): Bluebird { - const that = this; - const options: MongoDB.MongoClientOptions = {}; - if (that.configuration.auth) { - options["auth"] = { - user: that.configuration.auth.username, - password: that.configuration.auth.password - }; - } - - return new Bluebird((resolve, reject) => { - MongoDB.MongoClient.connect( - this.configuration.url, - options, - function(err, client) { - if (err) { - reject(err); - return; - } - resolve(client); - }); - }) - .then(function (client: MongoDB.MongoClient) { - that.database = client.db(that.configuration.database); - that.database.on("close", () => { - that.logger.info("[MongoClient] Lost connection."); - }); - that.database.on("reconnect", () => { - that.logger.info("[MongoClient] Reconnected."); - }); - that.client = client; - }); - } - - close(): Bluebird { - if (this.client) { - this.client.close(); - this.database = undefined; - this.client = undefined; - } - return Bluebird.resolve(); - } - - collection(name: string): Bluebird { - if (!this.client) { - const that = this; - return this.connect() - .then(() => Bluebird.resolve(that.database.collection(name))); - } - - return Bluebird.resolve(this.database.collection(name)); - } -} \ No newline at end of file diff --git a/server/src/lib/connectors/mongo/MongoClientStub.spec.ts b/server/src/lib/connectors/mongo/MongoClientStub.spec.ts deleted file mode 100644 index 1cfd48e32..000000000 --- a/server/src/lib/connectors/mongo/MongoClientStub.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import Sinon = require("sinon"); -import MongoDB = require("mongodb"); -import Bluebird = require("bluebird"); -import { IMongoClient } from "../../../../src/lib/connectors/mongo/IMongoClient"; - -export class MongoClientStub implements IMongoClient { - public collectionStub: Sinon.SinonStub; - - constructor() { - this.collectionStub = Sinon.stub(); - } - - collection(name: string): Bluebird { - return this.collectionStub(name); - } -} \ No newline at end of file diff --git a/server/src/lib/constants.ts b/server/src/lib/constants.ts deleted file mode 100644 index 2d449013b..000000000 --- a/server/src/lib/constants.ts +++ /dev/null @@ -1,17 +0,0 @@ -export const REDIRECT_QUERY_PARAM = "rd"; - -// Used as a first factor script parameter for knowing the authorizations -// related to the domain and resource. -export const HEADER_X_TARGET_URL = "x-target-url"; - -export const HEADER_X_ORIGINAL_URL = "x-original-url"; -export const HEADER_X_FORWARDED_PROTO = "x-forwarded-proto"; -export const HEADER_X_FORWARDED_HOST = "x-forwarded-host"; -export const HEADER_X_FORWARDED_URI = "x-forwarded-uri"; -export const HEADER_PROXY_AUTHORIZATION = "proxy-authorization"; -export const HEADER_REDIRECT = "redirect"; - -export const GET_VARIABLE_KEY = "variables"; - -export const HEADER_REMOTE_USER = "Remote-User"; -export const HEADER_REMOTE_GROUPS = "Remote-Groups"; diff --git a/server/src/lib/logging/GlobalLogger.ts b/server/src/lib/logging/GlobalLogger.ts deleted file mode 100644 index 4da7acf49..000000000 --- a/server/src/lib/logging/GlobalLogger.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { IGlobalLogger } from "./IGlobalLogger"; -import Util = require("util"); -import Express = require("express"); -import Winston = require("winston"); - -declare module "express" { - interface Request { - id: string; - } -} - -export class GlobalLogger implements IGlobalLogger { - private winston: typeof Winston; - constructor(winston: typeof Winston) { - this.winston = winston; - } - - private buildMessage(message: string, ...args: any[]): string { - return Util.format("date='%s' message='%s'", new Date(), - Util.format(message, ...args)); - } - - info(message: string, ...args: any[]): void { - this.winston.info(this.buildMessage(message, ...args)); - } - - debug(message: string, ...args: any[]): void { - this.winston.debug(this.buildMessage(message, ...args)); - } - - error(message: string, ...args: any[]): void { - this.winston.debug(this.buildMessage(message, ...args)); - } -} \ No newline at end of file diff --git a/server/src/lib/logging/GlobalLoggerStub.spec.ts b/server/src/lib/logging/GlobalLoggerStub.spec.ts deleted file mode 100644 index d4bb13710..000000000 --- a/server/src/lib/logging/GlobalLoggerStub.spec.ts +++ /dev/null @@ -1,38 +0,0 @@ -import Sinon = require("sinon"); -import { GlobalLogger } from "./GlobalLogger"; -import Winston = require("winston"); -import Express = require("express"); -import { IGlobalLogger } from "./IGlobalLogger"; - -export class GlobalLoggerStub implements IGlobalLogger { - infoStub: Sinon.SinonStub; - debugStub: Sinon.SinonStub; - errorStub: Sinon.SinonStub; - private globalLogger: IGlobalLogger; - - constructor(enableLogging?: boolean) { - this.infoStub = Sinon.stub(); - this.debugStub = Sinon.stub(); - this.errorStub = Sinon.stub(); - if (enableLogging) - this.globalLogger = new GlobalLogger(Winston); - } - - info(message: string, ...args: any[]): void { - if (this.globalLogger) - this.globalLogger.info(message, ...args); - this.infoStub(message, ...args); - } - - debug(message: string, ...args: any[]): void { - if (this.globalLogger) - this.globalLogger.info(message, ...args); - this.debugStub(message, ...args); - } - - error(message: string, ...args: any[]): void { - if (this.globalLogger) - this.globalLogger.info(message, ...args); - this.errorStub(message, ...args); - } -} \ No newline at end of file diff --git a/server/src/lib/logging/IGlobalLogger.ts b/server/src/lib/logging/IGlobalLogger.ts deleted file mode 100644 index 548515ec7..000000000 --- a/server/src/lib/logging/IGlobalLogger.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface IGlobalLogger { - info(message: string, ...args: any[]): void; - debug(message: string, ...args: any[]): void; - error(message: string, ...args: any[]): void; -} diff --git a/server/src/lib/logging/IRequestLogger.ts b/server/src/lib/logging/IRequestLogger.ts deleted file mode 100644 index 126a601fe..000000000 --- a/server/src/lib/logging/IRequestLogger.ts +++ /dev/null @@ -1,7 +0,0 @@ -import Express = require("express"); - -export interface IRequestLogger { - info(req: Express.Request, message: string, ...args: any[]): void; - debug(req: Express.Request, message: string, ...args: any[]): void; - error(req: Express.Request, message: string, ...args: any[]): void; -} \ No newline at end of file diff --git a/server/src/lib/logging/RequestLogger.ts b/server/src/lib/logging/RequestLogger.ts deleted file mode 100644 index c45c66018..000000000 --- a/server/src/lib/logging/RequestLogger.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { IRequestLogger } from "./IRequestLogger"; -import Util = require("util"); -import Express = require("express"); -import Winston = require("winston"); - -declare module "express" { - interface Request { - id: string; - } -} - -export class RequestLogger implements IRequestLogger { - private winston: typeof Winston; - - constructor(winston: typeof Winston) { - this.winston = winston; - } - - private formatHeader(req: Express.Request) { - const clientIP = req.ip; // The IP of the original client going through the proxy chain. - return Util.format("date='%s' method='%s', path='%s' requestId='%s' sessionId='%s' ip='%s'", - new Date(), req.method, req.path, req.id, req.sessionID, clientIP); - } - - private formatBody(message: string) { - return Util.format("message='%s'", message); - } - - private formatMessage(req: Express.Request, message: string) { - return Util.format("%s %s", this.formatHeader(req), - this.formatBody(message)); - } - - info(req: Express.Request, message: string, ...args: any[]): void { - this.winston.info(this.formatMessage(req, message), ...args); - } - - debug(req: Express.Request, message: string, ...args: any[]): void { - this.winston.debug(this.formatMessage(req, message), ...args); - } - - error(req: Express.Request, message: string, ...args: any[]): void { - this.winston.error(this.formatMessage(req, message), ...args); - } -} \ No newline at end of file diff --git a/server/src/lib/logging/RequestLoggerStub.spec.ts b/server/src/lib/logging/RequestLoggerStub.spec.ts deleted file mode 100644 index b0e375210..000000000 --- a/server/src/lib/logging/RequestLoggerStub.spec.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { IRequestLogger } from "./IRequestLogger"; -import Sinon = require("sinon"); -import { RequestLogger } from "./RequestLogger"; -import Winston = require("winston"); -import Express = require("express"); - -export class RequestLoggerStub implements IRequestLogger { - infoStub: Sinon.SinonStub; - debugStub: Sinon.SinonStub; - errorStub: Sinon.SinonStub; - private requestLogger: RequestLogger; - - constructor(enableLogging?: boolean) { - this.infoStub = Sinon.stub(); - this.debugStub = Sinon.stub(); - this.errorStub = Sinon.stub(); - if (enableLogging) - this.requestLogger = new RequestLogger(Winston); - } - - info(req: Express.Request, message: string, ...args: any[]): void { - if (this.requestLogger) - this.requestLogger.info(req, message, ...args); - this.infoStub(req, message, ...args); - } - - debug(req: Express.Request, message: string, ...args: any[]): void { - if (this.requestLogger) - this.requestLogger.info(req, message, ...args); - this.debugStub(req, message, ...args); - } - - error(req: Express.Request, message: string, ...args: any[]): void { - if (this.requestLogger) - this.requestLogger.info(req, message, ...args); - this.errorStub(req, message, ...args); - } -} \ No newline at end of file diff --git a/server/src/lib/notifiers/AbstractEmailNotifier.ts b/server/src/lib/notifiers/AbstractEmailNotifier.ts deleted file mode 100644 index 626f2b6ae..000000000 --- a/server/src/lib/notifiers/AbstractEmailNotifier.ts +++ /dev/null @@ -1,22 +0,0 @@ - -import { INotifier } from "../notifiers/INotifier"; - -import Fs = require("fs"); -import Path = require("path"); -import Ejs = require("ejs"); -import BluebirdPromise = require("bluebird"); - -const email_template = Fs.readFileSync(Path.join(__dirname, "../../resources/email-template.ejs"), "UTF-8"); - -export abstract class AbstractEmailNotifier implements INotifier { - notify(to: string, subject: string, link: string): BluebirdPromise { - const d = { - url: link, - button_title: "Continue", - title: subject - }; - return this.sendEmail(to, subject, Ejs.render(email_template, d)); - } - - abstract sendEmail(to: string, subject: string, content: string): BluebirdPromise; -} \ No newline at end of file diff --git a/server/src/lib/notifiers/EmailNotifier.spec.ts b/server/src/lib/notifiers/EmailNotifier.spec.ts deleted file mode 100644 index 8211bbc02..000000000 --- a/server/src/lib/notifiers/EmailNotifier.spec.ts +++ /dev/null @@ -1,54 +0,0 @@ -import * as sinon from "sinon"; -import * as Assert from "assert"; -import BluebirdPromise = require("bluebird"); - -import { MailSenderStub } from "./MailSenderStub.spec"; -import EmailNotifier = require("./EmailNotifier"); - - -describe("notifiers/EmailNotifier", function () { - it("should send an email to given user", function () { - const mailSender = new MailSenderStub(); - const options = { - username: "user_gmail", - password: "pass_gmail", - sender: "admin@example.com", - service: "gmail" - }; - - mailSender.sendStub.returns(BluebirdPromise.resolve()); - const sender = new EmailNotifier.EmailNotifier(options, mailSender); - const subject = "subject"; - const url = "http://test.com"; - - return sender.notify("user@example.com", subject, url) - .then(function () { - Assert.equal(mailSender.sendStub.getCall(0).args[0].to, "user@example.com"); - Assert.equal(mailSender.sendStub.getCall(0).args[0].subject, "subject"); - return BluebirdPromise.resolve(); - }); - }); - - it("should fail while sending an email", function () { - const mailSender = new MailSenderStub(); - const options = { - username: "user_gmail", - password: "pass_gmail", - sender: "admin@example.com", - service: "gmail" - }; - - mailSender.sendStub.returns(BluebirdPromise.reject(new Error("Failed to send mail"))); - const sender = new EmailNotifier.EmailNotifier(options, mailSender); - const subject = "subject"; - const url = "http://test.com"; - - return sender.notify("user@example.com", subject, url) - .then(function () { - return BluebirdPromise.reject(new Error()); - }, function() { - Assert.equal(mailSender.sendStub.getCall(0).args[0].from, "admin@example.com"); - return BluebirdPromise.resolve(); - }); - }); -}); diff --git a/server/src/lib/notifiers/EmailNotifier.ts b/server/src/lib/notifiers/EmailNotifier.ts deleted file mode 100644 index 4ffd385d0..000000000 --- a/server/src/lib/notifiers/EmailNotifier.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { AbstractEmailNotifier } from "../notifiers/AbstractEmailNotifier"; -import { EmailNotifierConfiguration } from "../configuration/schema/NotifierConfiguration"; -import { IMailSender } from "./IMailSender"; - -export class EmailNotifier extends AbstractEmailNotifier { - private mailSender: IMailSender; - private sender: string; - - constructor(options: EmailNotifierConfiguration, mailSender: IMailSender) { - super(); - this.mailSender = mailSender; - this.sender = options.sender; - } - - sendEmail(to: string, subject: string, content: string) { - const mailOptions = { - from: this.sender, - to: to, - subject: subject, - html: content - }; - return this.mailSender.send(mailOptions); - } -} diff --git a/server/src/lib/notifiers/FileSystemNotifier.ts b/server/src/lib/notifiers/FileSystemNotifier.ts deleted file mode 100644 index 23f6242c4..000000000 --- a/server/src/lib/notifiers/FileSystemNotifier.ts +++ /dev/null @@ -1,22 +0,0 @@ -import * as BluebirdPromise from "bluebird"; -import * as util from "util"; -import * as Fs from "fs"; -import { INotifier } from "./INotifier"; -import { Identity } from "../../../types/Identity"; - -import { FileSystemNotifierConfiguration } from "../configuration/schema/NotifierConfiguration"; - -export class FileSystemNotifier implements INotifier { - private filename: string; - - constructor(options: FileSystemNotifierConfiguration) { - this.filename = options.filename; - } - - notify(to: string, subject: string, link: string): BluebirdPromise { - const content = util.format("Date: %s\nEmail: %s\nSubject: %s\nLink: %s", - new Date().toString(), to, subject, link); - const writeFilePromised: any = BluebirdPromise.promisify(Fs.writeFile); - return writeFilePromised(this.filename, content); - } -} \ No newline at end of file diff --git a/server/src/lib/notifiers/IMailSender.ts b/server/src/lib/notifiers/IMailSender.ts deleted file mode 100644 index 34ac464a8..000000000 --- a/server/src/lib/notifiers/IMailSender.ts +++ /dev/null @@ -1,6 +0,0 @@ -import BluebirdPromise = require("bluebird"); -import Nodemailer = require("nodemailer"); - -export interface IMailSender { - send(mailOptions: Nodemailer.SendMailOptions): BluebirdPromise; -} \ No newline at end of file diff --git a/server/src/lib/notifiers/IMailSenderBuilder.ts b/server/src/lib/notifiers/IMailSenderBuilder.ts deleted file mode 100644 index 36d4dcdf7..000000000 --- a/server/src/lib/notifiers/IMailSenderBuilder.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { IMailSender } from "./IMailSender"; -import { SmtpNotifierConfiguration, EmailNotifierConfiguration } from "../configuration/schema/NotifierConfiguration"; - -export interface IMailSenderBuilder { - buildEmail(options: EmailNotifierConfiguration): IMailSender; - buildSmtp(options: SmtpNotifierConfiguration): IMailSender; -} \ No newline at end of file diff --git a/server/src/lib/notifiers/INotifier.ts b/server/src/lib/notifiers/INotifier.ts deleted file mode 100644 index b9a6b138c..000000000 --- a/server/src/lib/notifiers/INotifier.ts +++ /dev/null @@ -1,5 +0,0 @@ -import * as BluebirdPromise from "bluebird"; - -export interface INotifier { - notify(to: string, subject: string, link: string): BluebirdPromise; -} \ No newline at end of file diff --git a/server/src/lib/notifiers/MailSender.ts b/server/src/lib/notifiers/MailSender.ts deleted file mode 100644 index 536a88e63..000000000 --- a/server/src/lib/notifiers/MailSender.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { IMailSender } from "./IMailSender"; -import Nodemailer = require("nodemailer"); -import NodemailerDirectTransport = require("nodemailer-direct-transport"); -import NodemailerSmtpTransport = require("nodemailer-smtp-transport"); -import BluebirdPromise = require("bluebird"); - -export class MailSender implements IMailSender { - private transporter: Nodemailer.Transporter; - - constructor(options: NodemailerDirectTransport.DirectOptions | - NodemailerSmtpTransport.SmtpOptions, nodemailer: typeof Nodemailer) { - this.transporter = nodemailer.createTransport(options); - } - - verify(): BluebirdPromise { - const that = this; - return new BluebirdPromise(function (resolve, reject) { - that.transporter.verify(function (error: Error, success: any) { - if (error) { - reject(new Error("Unable to connect to SMTP server. \ - Please check the service is running and your credentials are correct.")); - return; - } - resolve(); - }); - }); - } - - send(mailOptions: Nodemailer.SendMailOptions): BluebirdPromise { - const that = this; - return new BluebirdPromise(function (resolve, reject) { - that.transporter.sendMail(mailOptions, (error: Error, - data: Nodemailer.SentMessageInfo) => { - if (error) { - reject(new Error("Error while sending email: " + error.message)); - return; - } - resolve(); - }); - }); - } -} \ No newline at end of file diff --git a/server/src/lib/notifiers/MailSenderBuilder.spec.ts b/server/src/lib/notifiers/MailSenderBuilder.spec.ts deleted file mode 100644 index 41e0db426..000000000 --- a/server/src/lib/notifiers/MailSenderBuilder.spec.ts +++ /dev/null @@ -1,67 +0,0 @@ - -import { MailSenderBuilder } from ".//MailSenderBuilder"; -import Nodemailer = require("nodemailer"); -import Sinon = require("sinon"); -import Assert = require("assert"); - -describe("notifiers/MailSenderBuilder", function() { - let createTransportStub: Sinon.SinonStub; - beforeEach(function() { - createTransportStub = Sinon.stub(Nodemailer, "createTransport"); - }); - - afterEach(function() { - createTransportStub.restore(); - }); - - it("should create a email mail sender", function() { - const mailSenderBuilder = new MailSenderBuilder(Nodemailer); - mailSenderBuilder.buildEmail({ - username: "user_gmail", - password: "pass_gmail", - sender: "admin@example.com", - service: "gmail" - }); - Assert.equal(createTransportStub.getCall(0).args[0].auth.user, "user_gmail"); - Assert.equal(createTransportStub.getCall(0).args[0].auth.pass, "pass_gmail"); - Assert.equal(createTransportStub.getCall(0).args[0].service, "gmail"); - }); - - describe("build smtp mail sender", function() { - it("should create a smtp mail sender with authenticated user", function() { - const mailSenderBuilder = new MailSenderBuilder(Nodemailer); - mailSenderBuilder.buildSmtp({ - host: "mail.example.com", - password: "password", - port: 25, - secure: true, - username: "user", - sender: "admin@example.com" - }); - Assert.deepStrictEqual(createTransportStub.getCall(0).args[0], { - host: "mail.example.com", - auth: { - pass: "password", - user: "user" - }, - port: 25, - secure: true, - }); - }); - - it("should create a smtp mail sender with anonymous user", function() { - const mailSenderBuilder = new MailSenderBuilder(Nodemailer); - mailSenderBuilder.buildSmtp({ - host: "mail.example.com", - port: 25, - secure: true, - sender: "admin@example.com" - }); - Assert.deepStrictEqual(createTransportStub.getCall(0).args[0], { - host: "mail.example.com", - port: 25, - secure: true, - }); - }); - }); -}); \ No newline at end of file diff --git a/server/src/lib/notifiers/MailSenderBuilder.ts b/server/src/lib/notifiers/MailSenderBuilder.ts deleted file mode 100644 index 1d06be52f..000000000 --- a/server/src/lib/notifiers/MailSenderBuilder.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { IMailSender } from "./IMailSender"; -import { IMailSenderBuilder } from "./IMailSenderBuilder"; -import { MailSender } from "./MailSender"; -import Nodemailer = require("nodemailer"); -import NodemailerSmtpTransport = require("nodemailer-smtp-transport"); -import { SmtpNotifierConfiguration, EmailNotifierConfiguration } from "../configuration/schema/NotifierConfiguration"; - -export class MailSenderBuilder implements IMailSenderBuilder { - private nodemailer: typeof Nodemailer; - - constructor(nodemailer: typeof Nodemailer) { - this.nodemailer = nodemailer; - } - - buildEmail(options: EmailNotifierConfiguration): IMailSender { - const emailOptions = { - service: options.service, - auth: { - user: options.username, - pass: options.password - } - }; - return new MailSender(emailOptions, this.nodemailer); - } - - buildSmtp(options: SmtpNotifierConfiguration): IMailSender { - const smtpOptions: NodemailerSmtpTransport.SmtpOptions = { - host: options.host, - port: options.port, - secure: options.secure, // upgrade later with STARTTLS - }; - - if (options.username && options.password) { - smtpOptions.auth = { - user: options.username, - pass: options.password - }; - } - - return new MailSender(smtpOptions, this.nodemailer); - } -} \ No newline at end of file diff --git a/server/src/lib/notifiers/MailSenderBuilderStub.spec.ts b/server/src/lib/notifiers/MailSenderBuilderStub.spec.ts deleted file mode 100644 index 5b76f6e56..000000000 --- a/server/src/lib/notifiers/MailSenderBuilderStub.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { IMailSenderBuilder } from "../../../src/lib/notifiers/IMailSenderBuilder"; -import BluebirdPromise = require("bluebird"); -import Nodemailer = require("nodemailer"); -import Sinon = require("sinon"); -import { IMailSender } from "../../../src/lib/notifiers/IMailSender"; -import { SmtpNotifierConfiguration, EmailNotifierConfiguration } from "../../../src/lib/configuration/schema/NotifierConfiguration"; - -export class MailSenderBuilderStub implements IMailSenderBuilder { - buildEmailStub: Sinon.SinonStub; - buildSmtpStub: Sinon.SinonStub; - - constructor() { - this.buildEmailStub = Sinon.stub(); - this.buildSmtpStub = Sinon.stub(); - } - - buildEmail(options: EmailNotifierConfiguration): IMailSender { - return this.buildEmailStub(options); - } - - buildSmtp(options: SmtpNotifierConfiguration): IMailSender { - return this.buildSmtpStub(options); - } - -} \ No newline at end of file diff --git a/server/src/lib/notifiers/MailSenderStub.spec.ts b/server/src/lib/notifiers/MailSenderStub.spec.ts deleted file mode 100644 index d57c458fc..000000000 --- a/server/src/lib/notifiers/MailSenderStub.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { IMailSender } from "../../../src/lib/notifiers/IMailSender"; -import BluebirdPromise = require("bluebird"); -import Nodemailer = require("nodemailer"); -import Sinon = require("sinon"); - -export class MailSenderStub implements IMailSender { - sendStub: Sinon.SinonStub; - - constructor() { - this.sendStub = Sinon.stub(); - } - - send(mailOptions: Nodemailer.SendMailOptions): BluebirdPromise { - return this.sendStub(mailOptions); - } -} \ No newline at end of file diff --git a/server/src/lib/notifiers/NotifierFactory.spec.ts b/server/src/lib/notifiers/NotifierFactory.spec.ts deleted file mode 100644 index f15e7667f..000000000 --- a/server/src/lib/notifiers/NotifierFactory.spec.ts +++ /dev/null @@ -1,42 +0,0 @@ - -import * as sinon from "sinon"; -import * as BluebirdPromise from "bluebird"; -import * as assert from "assert"; - -import { NotifierFactory } from "./NotifierFactory"; -import { EmailNotifier } from "./EmailNotifier"; -import { SmtpNotifier } from "./SmtpNotifier"; -import { MailSenderBuilderStub } from "./MailSenderBuilderStub.spec"; - - -describe("notifiers/NotifierFactory", function () { - let mailSenderBuilderStub: MailSenderBuilderStub; - it("should build a Email Notifier", function () { - const options = { - email: { - username: "abc", - password: "password", - sender: "admin@example.com", - service: "gmail" - } - }; - mailSenderBuilderStub = new MailSenderBuilderStub(); - assert(NotifierFactory.build(options, mailSenderBuilderStub) instanceof EmailNotifier); - }); - - it("should build a SMTP Notifier", function () { - const options = { - smtp: { - username: "user", - password: "pass", - secure: true, - host: "localhost", - port: 25, - sender: "admin@example.com" - } - }; - - mailSenderBuilderStub = new MailSenderBuilderStub(); - assert(NotifierFactory.build(options, mailSenderBuilderStub) instanceof SmtpNotifier); - }); -}); diff --git a/server/src/lib/notifiers/NotifierFactory.ts b/server/src/lib/notifiers/NotifierFactory.ts deleted file mode 100644 index a89155feb..000000000 --- a/server/src/lib/notifiers/NotifierFactory.ts +++ /dev/null @@ -1,33 +0,0 @@ - -import { NotifierConfiguration } from "../configuration/schema/NotifierConfiguration"; -import Nodemailer = require("nodemailer"); -import { INotifier } from "./INotifier"; - -import { FileSystemNotifier } from "./FileSystemNotifier"; -import { EmailNotifier } from "./EmailNotifier"; -import { SmtpNotifier } from "./SmtpNotifier"; -import { IMailSender } from "./IMailSender"; -import { IMailSenderBuilder } from "./IMailSenderBuilder"; - -export class NotifierFactory { - static build(options: NotifierConfiguration, mailSenderBuilder: IMailSenderBuilder): INotifier { - if ("email" in options) { - const mailSender = mailSenderBuilder.buildEmail(options.email); - return new EmailNotifier(options.email, mailSender); - } - else if ("smtp" in options) { - const mailSender = mailSenderBuilder.buildSmtp(options.smtp); - return new SmtpNotifier(options.smtp, mailSender); - } - else if ("filesystem" in options) { - return new FileSystemNotifier(options.filesystem); - } - else { - throw new Error("No available notifier option detected."); - } - } -} - - - - diff --git a/server/src/lib/notifiers/NotifierStub.spec.ts b/server/src/lib/notifiers/NotifierStub.spec.ts deleted file mode 100644 index f99231b50..000000000 --- a/server/src/lib/notifiers/NotifierStub.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import Sinon = require("sinon"); -import BluebirdPromise = require("bluebird"); - -import { INotifier } from "./INotifier"; - -export class NotifierStub implements INotifier { - notifyStub: Sinon.SinonStub; - - constructor() { - this.notifyStub = Sinon.stub(); - } - - notify(to: string, subject: string, link: string): BluebirdPromise { - return this.notifyStub(to, subject, link); - } -} \ No newline at end of file diff --git a/server/src/lib/notifiers/SmtpNotifier.ts b/server/src/lib/notifiers/SmtpNotifier.ts deleted file mode 100644 index f93a6d4a0..000000000 --- a/server/src/lib/notifiers/SmtpNotifier.ts +++ /dev/null @@ -1,30 +0,0 @@ - - -import * as BluebirdPromise from "bluebird"; - -import { IMailSender } from "./IMailSender"; -import { AbstractEmailNotifier } from "../notifiers/AbstractEmailNotifier"; -import { SmtpNotifierConfiguration } from "../configuration/schema/NotifierConfiguration"; - -export class SmtpNotifier extends AbstractEmailNotifier { - private mailSender: IMailSender; - private sender: string; - - constructor(options: SmtpNotifierConfiguration, - mailSender: IMailSender) { - super(); - this.mailSender = mailSender; - this.sender = options.sender; - } - - sendEmail(to: string, subject: string, content: string) { - const mailOptions = { - from: this.sender, - to: to, - subject: subject, - html: content - }; - const that = this; - return this.mailSender.send(mailOptions); - } -} diff --git a/server/src/lib/regulation/IRegulator.ts b/server/src/lib/regulation/IRegulator.ts deleted file mode 100644 index c49425b24..000000000 --- a/server/src/lib/regulation/IRegulator.ts +++ /dev/null @@ -1,6 +0,0 @@ -import BluebirdPromise = require("bluebird"); - -export interface IRegulator { - mark(userId: string, isAuthenticationSuccessful: boolean): BluebirdPromise; - regulate(userId: string): BluebirdPromise; -} \ No newline at end of file diff --git a/server/src/lib/regulation/Regulator.spec.ts b/server/src/lib/regulation/Regulator.spec.ts deleted file mode 100644 index f9c6e6086..000000000 --- a/server/src/lib/regulation/Regulator.spec.ts +++ /dev/null @@ -1,186 +0,0 @@ - -import Sinon = require("sinon"); -import BluebirdPromise = require("bluebird"); -import Assert = require("assert"); - -import { Regulator } from "./Regulator"; -import MockDate = require("mockdate"); -import exceptions = require("../Exceptions"); -import { UserDataStoreStub } from "../storage/UserDataStoreStub.spec"; - -describe("regulation/Regulator", function () { - const USER1 = "USER1"; - const USER2 = "USER2"; - let userDataStoreStub: UserDataStoreStub; - - beforeEach(function () { - userDataStoreStub = new UserDataStoreStub(); - const dataStore: { [userId: string]: { userId: string, date: Date, isAuthenticationSuccessful: boolean }[] } = { - [USER1]: [], - [USER2]: [] - }; - - userDataStoreStub.saveAuthenticationTraceStub.callsFake(function (userId, isAuthenticationSuccessful) { - dataStore[userId].unshift({ - userId: userId, - date: new Date(), - isAuthenticationSuccessful: isAuthenticationSuccessful, - }); - return BluebirdPromise.resolve(); - }); - - userDataStoreStub.retrieveLatestAuthenticationTracesStub.callsFake(function (userId, count) { - const ret = (dataStore[userId].length <= count) ? dataStore[userId] : dataStore[userId].slice(0, 3); - return BluebirdPromise.resolve(ret); - }); - }); - - afterEach(function () { - MockDate.reset(); - }); - - function markAuthenticationAt(regulator: Regulator, user: string, time: string, success: boolean) { - MockDate.set(time); - return regulator.mark(user, success); - } - - it("should mark 2 authentication and regulate (accept)", function () { - const regulator = new Regulator(userDataStoreStub, 3, 10, 10); - - return regulator.mark(USER1, false) - .then(function () { - return regulator.mark(USER1, true); - }) - .then(function () { - return regulator.regulate(USER1); - }); - }); - - it("should mark 3 authentications and regulate (reject)", function () { - const regulator = new Regulator(userDataStoreStub, 3, 10, 10); - - return regulator.mark(USER1, false) - .then(function () { - return regulator.mark(USER1, false); - }) - .then(function () { - return regulator.mark(USER1, false); - }) - .then(function () { - return regulator.regulate(USER1); - }) - .then(function () { return BluebirdPromise.reject(new Error("should not be here!")); }) - .catch(exceptions.AuthenticationRegulationError, function () { - return BluebirdPromise.resolve(); - }); - }); - - it("should mark 1 failed, 1 successful and 1 failed authentications within minimum time and regulate (accept)", function () { - const regulator = new Regulator(userDataStoreStub, 3, 60, 30); - - return markAuthenticationAt(regulator, USER1, "1/2/2000 00:00:00", false) - .then(function () { - return markAuthenticationAt(regulator, USER1, "1/2/2000 00:00:10", true); - }) - .then(function () { - return markAuthenticationAt(regulator, USER1, "1/2/2000 00:00:20", false); - }) - .then(function () { - return regulator.regulate(USER1); - }) - .then(function () { - return markAuthenticationAt(regulator, USER1, "1/2/2000 00:00:30", false); - }) - .then(function () { - return regulator.regulate(USER1); - }) - .then(function () { - return markAuthenticationAt(regulator, USER1, "1/2/2000 00:00:39", false); - }) - .then(function () { - return regulator.regulate(USER1); - }) - .then(function () { - return BluebirdPromise.reject(new Error("should not be here!")); - }, - function () { - return BluebirdPromise.resolve(); - }); - }); - - it("should regulate user if number of failures is greater than 3 in allowed time lapse", function () { - function markAuthentications(regulator: Regulator, user: string) { - return markAuthenticationAt(regulator, user, "1/2/2000 00:00:00", false) - .then(function () { - return markAuthenticationAt(regulator, user, "1/2/2000 00:00:45", false); - }) - .then(function () { - return markAuthenticationAt(regulator, user, "1/2/2000 00:01:05", false); - }) - .then(function () { - return regulator.regulate(user); - }); - } - - const regulator1 = new Regulator(userDataStoreStub, 3, 60, 60); - const regulator2 = new Regulator(userDataStoreStub, 3, 2 * 60, 60); - - const p1 = markAuthentications(regulator1, USER1); - const p2 = markAuthentications(regulator2, USER2); - - return BluebirdPromise.join(p1, p2) - .then(function () { - return BluebirdPromise.reject(new Error("should not be here...")); - }, function () { - Assert(p1.isFulfilled()); - Assert(p2.isRejected()); - }); - }); - - it("should user wait after regulation to authenticate again", function () { - function markAuthentications(regulator: Regulator, user: string) { - return markAuthenticationAt(regulator, user, "1/2/2000 00:00:00", false) - .then(function () { - return markAuthenticationAt(regulator, user, "1/2/2000 00:00:10", false); - }) - .then(function () { - return markAuthenticationAt(regulator, user, "1/2/2000 00:00:15", false); - }) - .then(function () { - return markAuthenticationAt(regulator, user, "1/2/2000 00:00:25", false); - }) - .then(function () { - MockDate.set("1/2/2000 00:00:54"); - return regulator.regulate(user); - }) - .then(function () { - return BluebirdPromise.reject(new Error("should fail at this time")); - }, function () { - MockDate.set("1/2/2000 00:00:56"); - return regulator.regulate(user); - }); - } - - const regulator = new Regulator(userDataStoreStub, 4, 30, 30); - return markAuthentications(regulator, USER1); - }); - - it("should disable regulation when max_retries is set to 0", function () { - const maxRetries = 0; - const regulator = new Regulator(userDataStoreStub, maxRetries, 60, 30); - return markAuthenticationAt(regulator, USER1, "1/2/2000 00:00:00", false) - .then(function () { - return markAuthenticationAt(regulator, USER1, "1/2/2000 00:00:10", false); - }) - .then(function () { - return markAuthenticationAt(regulator, USER1, "1/2/2000 00:00:15", false); - }) - .then(function () { - return markAuthenticationAt(regulator, USER1, "1/2/2000 00:00:25", false); - }) - .then(function () { - MockDate.set("1/2/2000 00:00:26"); - return regulator.regulate(USER1); - }); - }); -}); \ No newline at end of file diff --git a/server/src/lib/regulation/Regulator.ts b/server/src/lib/regulation/Regulator.ts deleted file mode 100644 index 1037a6a17..000000000 --- a/server/src/lib/regulation/Regulator.ts +++ /dev/null @@ -1,55 +0,0 @@ - -import * as BluebirdPromise from "bluebird"; -import exceptions = require("../Exceptions"); -import { IUserDataStore } from "../storage/IUserDataStore"; -import { AuthenticationTraceDocument } from "../storage/AuthenticationTraceDocument"; -import { IRegulator } from "./IRegulator"; - -export class Regulator implements IRegulator { - private userDataStore: IUserDataStore; - private banTime: number; - private findTime: number; - private maxRetries: number; - - constructor(userDataStore: any, maxRetries: number, findTime: number, banTime: number) { - this.userDataStore = userDataStore; - this.banTime = banTime; - this.findTime = findTime; - this.maxRetries = maxRetries; - } - - // Mark authentication - mark(userId: string, isAuthenticationSuccessful: boolean): BluebirdPromise { - return this.userDataStore.saveAuthenticationTrace(userId, isAuthenticationSuccessful); - } - - regulate(userId: string): BluebirdPromise { - const that = this; - - if (that.maxRetries <= 0) return BluebirdPromise.resolve(); - - return this.userDataStore.retrieveLatestAuthenticationTraces(userId, that.maxRetries) - .then((docs: AuthenticationTraceDocument[]) => { - // less than the max authorized number of authentication in time range, thus authorizing access - if (docs.length < that.maxRetries) return BluebirdPromise.resolve(); - - const numberOfFailedAuth = docs - .map(function (d: AuthenticationTraceDocument) { return d.isAuthenticationSuccessful == false ? 1 : 0; }) - .reduce(function (acc, v) { return acc + v; }, 0); - - if (numberOfFailedAuth < this.maxRetries) return BluebirdPromise.resolve(); - - const newestDocument = docs[0]; - const oldestDocument = docs[that.maxRetries - 1]; - - const authenticationsTimeRangeInSeconds = (newestDocument.date.getTime() - oldestDocument.date.getTime()) / 1000; - const tooManyAuthInTimelapse = (authenticationsTimeRangeInSeconds < this.findTime); - const stillInBannedTimeRange = (new Date(new Date().getTime() - this.banTime * 1000) < newestDocument.date); - - if (tooManyAuthInTimelapse && stillInBannedTimeRange) - throw new exceptions.AuthenticationRegulationError("Max number of authentication. Please retry in few minutes."); - - return BluebirdPromise.resolve(); - }); - } -} diff --git a/server/src/lib/regulation/RegulatorStub.spec.ts b/server/src/lib/regulation/RegulatorStub.spec.ts deleted file mode 100644 index ca8a00fb1..000000000 --- a/server/src/lib/regulation/RegulatorStub.spec.ts +++ /dev/null @@ -1,22 +0,0 @@ -import Bluebird = require("bluebird"); -import Sinon = require("sinon"); -import { IRegulator } from "./IRegulator"; - - -export class RegulatorStub implements IRegulator { - markStub: Sinon.SinonStub; - regulateStub: Sinon.SinonStub; - - constructor() { - this.markStub = Sinon.stub(); - this.regulateStub = Sinon.stub(); - } - - mark(userId: string, isAuthenticationSuccessful: boolean): Bluebird { - return this.markStub(userId, isAuthenticationSuccessful); - } - - regulate(userId: string): Bluebird { - return this.regulateStub(userId); - } -} diff --git a/server/src/lib/routes/firstfactor/post.spec.ts b/server/src/lib/routes/firstfactor/post.spec.ts deleted file mode 100644 index eb5fc6a3e..000000000 --- a/server/src/lib/routes/firstfactor/post.spec.ts +++ /dev/null @@ -1,122 +0,0 @@ -import * as Express from 'express'; -import BluebirdPromise = require("bluebird"); -import Assert = require("assert"); -import FirstFactorPost = require("./post"); -import exceptions = require("../../Exceptions"); -import { AuthenticationSessionHandler } from "../../AuthenticationSessionHandler"; -import { AuthenticationSession } from "../../../../types/AuthenticationSession"; -import * as ExpressMock from "../../stubs/express.spec"; -import { ServerVariablesMock, ServerVariablesMockBuilder } from "../../ServerVariablesMockBuilder.spec"; -import { ServerVariables } from "../../ServerVariables"; -import AuthenticationError from "../../authentication/AuthenticationError"; - -describe("routes/firstfactor/post", function () { - let req: Express.Request; - let res: ExpressMock.ResponseMock; - let emails: string[]; - let groups: string[]; - let vars: ServerVariables; - let mocks: ServerVariablesMock; - let authSession: AuthenticationSession; - - beforeEach(function () { - emails = ["test_ok@example.com"]; - groups = ["group1", "group2" ]; - const s = ServerVariablesMockBuilder.build(); - mocks = s.mocks; - vars = s.variables; - - mocks.authorizer.authorizationMock.returns(true); - mocks.regulator.regulateStub.returns(BluebirdPromise.resolve()); - mocks.regulator.markStub.returns(BluebirdPromise.resolve()); - - req = ExpressMock.RequestMock(); - req.body = { - username: "username", - password: "password" - } - res = ExpressMock.ResponseMock(); - authSession = AuthenticationSessionHandler.get(req as any, vars.logger); - }); - - it("should reply with 204 if success", function () { - mocks.usersDatabase.checkUserPasswordStub.withArgs("username", "password") - .returns(BluebirdPromise.resolve({ - emails: emails, - groups: groups - })); - return FirstFactorPost.default(vars)(req as any, res as any) - .then(function () { - Assert.equal("username", authSession.userid); - Assert(res.send.calledOnce); - }); - }); - - describe("keep me logged in", () => { - beforeEach(() => { - mocks.usersDatabase.checkUserPasswordStub.withArgs("username", "password") - .returns(BluebirdPromise.resolve({ - emails: emails, - groups: groups - })); - req.body.keepMeLoggedIn = true; - return FirstFactorPost.default(vars)(req as any, res as any); - }); - - it("should set keep_me_logged_in session variable to true", function () { - Assert.equal(authSession.keep_me_logged_in, true); - }); - - it("should set cookie maxAge to one year", function () { - Assert.equal(req.session.cookie.maxAge, 365 * 24 * 60 * 60 * 1000); - }); - }); - - it("should retrieve email from LDAP", function () { - mocks.usersDatabase.checkUserPasswordStub.withArgs("username", "password") - .returns(BluebirdPromise.resolve([{ mail: ["test@example.com"] }])); - return FirstFactorPost.default(vars)(req as any, res as any); - }); - - it("should set first email address as user session variable", function () { - const emails = ["test_ok@example.com"]; - mocks.usersDatabase.checkUserPasswordStub.withArgs("username", "password") - .returns(BluebirdPromise.resolve({ - emails: emails, - groups: groups - })); - - return FirstFactorPost.default(vars)(req as any, res as any) - .then(function () { - Assert.equal("test_ok@example.com", authSession.email); - }); - }); - - it("should return error message when LDAP authenticator throws", function () { - mocks.usersDatabase.checkUserPasswordStub.withArgs("username", "password") - .returns(BluebirdPromise.reject(new AuthenticationError("Bad credentials"))); - - return FirstFactorPost.default(vars)(req as any, res as any) - .then(function () { - Assert.equal(res.status.getCall(0).args[0], 200); - Assert.equal(mocks.regulator.markStub.getCall(0).args[0], "username"); - Assert.deepEqual(res.send.getCall(0).args[0], { - error: "Authentication failed. Please check your credentials." - }); - }); - }); - - it("should return error message when regulator rejects authentication", function () { - const err = new exceptions.AuthenticationRegulationError("Authentication regulation..."); - mocks.regulator.regulateStub.returns(BluebirdPromise.reject(err)); - return FirstFactorPost.default(vars)(req as any, res as any) - .then(function () { - Assert.equal(res.status.getCall(0).args[0], 200); - Assert.deepEqual(res.send.getCall(0).args[0], { - error: "Authentication failed. Please check your credentials." - }); - }); - }); -}); - - diff --git a/server/src/lib/routes/firstfactor/post.ts b/server/src/lib/routes/firstfactor/post.ts deleted file mode 100644 index e5f51a1b4..000000000 --- a/server/src/lib/routes/firstfactor/post.ts +++ /dev/null @@ -1,118 +0,0 @@ -import BluebirdPromise = require("bluebird"); -import express = require("express"); -import ErrorReplies = require("../../ErrorReplies"); -import { AuthenticationSessionHandler } from "../../AuthenticationSessionHandler"; -import UserMessages = require("../../UserMessages"); -import { ServerVariables } from "../../ServerVariables"; -import { AuthenticationSession } from "../../../../types/AuthenticationSession"; -import { GroupsAndEmails } from "../../authentication/backends/GroupsAndEmails"; -import { Level } from "../../authentication/Level"; -import { Level as AuthorizationLevel } from "../../authorization/Level"; -import { BelongToDomain } from "../../BelongToDomain"; -import { URLDecomposer } from "../..//utils/URLDecomposer"; -import { Object } from "../../../lib/authorization/Object"; -import { Subject } from "../../../lib/authorization/Subject"; -import AuthenticationError from "../../../lib/authentication/AuthenticationError"; -import IsRedirectionSafe from "../../../lib/utils/IsRedirectionSafe"; -import * as URLParse from "url-parse"; -import GetHeader from "../../utils/GetHeader"; - -export default function (vars: ServerVariables) { - return function (req: express.Request, res: express.Response) - : BluebirdPromise { - const username: string = req.body.username; - const password: string = req.body.password; - const keepMeLoggedIn: boolean = req.body.keepMeLoggedIn; - let authSession: AuthenticationSession; - - if (keepMeLoggedIn) { - // Stay connected for 1 year. - vars.logger.debug(req, "User requested to stay logged in for one year."); - req.session.cookie.maxAge = 365 * 24 * 60 * 60 * 1000; - } - - return BluebirdPromise.resolve() - .then(function () { - if (!username || !password) { - return BluebirdPromise.reject(new Error("No username or password.")); - } - vars.logger.info(req, "Starting authentication of user \"%s\"", username); - authSession = AuthenticationSessionHandler.get(req, vars.logger); - return vars.regulator.regulate(username); - }) - .then(function () { - vars.logger.info(req, "No regulation applied."); - return vars.usersDatabase.checkUserPassword(username, password); - }) - .then(function (groupsAndEmails: GroupsAndEmails) { - vars.logger.info(req, - "Backend lookup successful. Retrieved information about user %s are %s", username, - JSON.stringify(groupsAndEmails)); - authSession.userid = username; - authSession.keep_me_logged_in = keepMeLoggedIn; - authSession.authentication_level = Level.ONE_FACTOR; - - const emails: string[] = groupsAndEmails.emails; - const groups: string[] = groupsAndEmails.groups; - - if (emails.length > 0) - authSession.email = emails[0]; - authSession.groups = groups; - - vars.logger.debug(req, "Mark successful authentication to regulator."); - vars.regulator.mark(username, true); - }) - .then(function() { - const targetUrl = GetHeader(req, "x-target-url"); - - if (!targetUrl) { - vars.logger.debug(req, "Sending status 204 due to missing header 'x-target-url'"); - res.status(204); - res.send(); - return BluebirdPromise.resolve(); - } - - if (BelongToDomain(targetUrl, vars.config.session.domain, vars.logger, req)) { - vars.logger.debug(req, "%s was found to be in domain %s", targetUrl, vars.config.session.domain); - const resource = URLDecomposer.fromUrl(targetUrl); - const resObject: Object = { - domain: resource.domain, - resource: resource.path, - }; - - const subject: Subject = { - user: authSession.userid, - groups: authSession.groups - }; - - const authorizationLevel = vars.authorizer.authorization(resObject, subject, req.ip); - vars.logger.debug(req, "calculated authorization level: %s from resObject: %s subject: %s and ip: %s", - authorizationLevel, JSON.stringify(resObject), JSON.stringify(subject), req.ip); - - if (authorizationLevel <= AuthorizationLevel.ONE_FACTOR) { - if (IsRedirectionSafe(vars, new URLParse(targetUrl))) { - vars.logger.debug(req, "sending redirect to: %s", targetUrl); - res.json({redirect: targetUrl}); - return BluebirdPromise.resolve(); - } else { - res.json({error: "You're authenticated but cannot be automatically redirected to an unsafe URL."}); - return BluebirdPromise.resolve(); - } - } else { - vars.logger.debug(req, "Current authorization level %s indicates no further action for %s", authorizationLevel, username); - } - } else { - vars.logger.debug(req, "%s was not found to be in domain %s", targetUrl, vars.config.session.domain); - } - - res.status(204); - res.send(); - return BluebirdPromise.resolve(); - }) - .catch(AuthenticationError, function (err: Error) { - vars.regulator.mark(username, false); - return ErrorReplies.replyWithError200(req, res, vars.logger, UserMessages.AUTHENTICATION_FAILED)(err); - }) - .catch(ErrorReplies.replyWithError200(req, res, vars.logger, UserMessages.AUTHENTICATION_FAILED)); - }; -} diff --git a/server/src/lib/routes/logout/post.ts b/server/src/lib/routes/logout/post.ts deleted file mode 100644 index f98ffebfe..000000000 --- a/server/src/lib/routes/logout/post.ts +++ /dev/null @@ -1,20 +0,0 @@ - -import express = require("express"); -import { AuthenticationSessionHandler } from "../../AuthenticationSessionHandler"; -import Constants = require("../../constants"); -import { ServerVariables } from "../../ServerVariables"; - -function getRedirectParam(req: express.Request) { - return req.query[Constants.REDIRECT_QUERY_PARAM] != "undefined" - ? req.query[Constants.REDIRECT_QUERY_PARAM] - : undefined; -} - -export default function (vars: ServerVariables) { - return function(req: express.Request, res: express.Response) { - const redirect_param = getRedirectParam(req); - const redirect_url = redirect_param || "/"; - AuthenticationSessionHandler.reset(req); - res.redirect(redirect_url); - }; -} \ No newline at end of file diff --git a/server/src/lib/routes/password-reset/constants.ts b/server/src/lib/routes/password-reset/constants.ts deleted file mode 100644 index 5c639e92a..000000000 --- a/server/src/lib/routes/password-reset/constants.ts +++ /dev/null @@ -1,2 +0,0 @@ - -export const CHALLENGE = "reset-password"; \ No newline at end of file diff --git a/server/src/lib/routes/password-reset/form/post.spec.ts b/server/src/lib/routes/password-reset/form/post.spec.ts deleted file mode 100644 index 87b03390e..000000000 --- a/server/src/lib/routes/password-reset/form/post.spec.ts +++ /dev/null @@ -1,105 +0,0 @@ -import * as Express from "express"; -import PasswordResetFormPost = require("./post"); -import { AuthenticationSessionHandler } from "../../../AuthenticationSessionHandler"; -import { AuthenticationSession } from "../../../../../types/AuthenticationSession"; -import Assert = require("assert"); -import BluebirdPromise = require("bluebird"); -import ExpressMock = require("../../../stubs/express.spec"); -import { ServerVariablesMock, ServerVariablesMockBuilder } from "../../../ServerVariablesMockBuilder.spec"; -import { ServerVariables } from "../../../ServerVariables"; -import { Level } from "../../../authentication/Level"; - -describe("routes/password-reset/form/post", function () { - let req: Express.Request; - let res: ExpressMock.ResponseMock; - let vars: ServerVariables; - let mocks: ServerVariablesMock; - let authSession: AuthenticationSession; - - beforeEach(function () { - req = ExpressMock.RequestMock(); - - const s = ServerVariablesMockBuilder.build(); - mocks = s.mocks; - vars = s.variables; - - mocks.userDataStore.saveU2FRegistrationStub.returns(BluebirdPromise.resolve({})); - mocks.userDataStore.retrieveU2FRegistrationStub.returns(BluebirdPromise.resolve({})); - mocks.userDataStore.produceIdentityValidationTokenStub.returns(BluebirdPromise.resolve({})); - mocks.userDataStore.consumeIdentityValidationTokenStub.returns(BluebirdPromise.resolve({})); - - mocks.config.authentication_backend.ldap = { - url: "ldap://ldapjs", - mail_attribute: "mail", - user: "user", - password: "password", - additional_users_dn: "ou=users", - additional_groups_dn: "ou=groups", - base_dn: "dc=example,dc=com", - users_filter: "user", - group_name_attribute: "cn", - groups_filter: "groups" - }; - - res = ExpressMock.ResponseMock(); - authSession = AuthenticationSessionHandler.get(req as any, vars.logger); - authSession.userid = "user"; - authSession.email = "user@example.com"; - authSession.authentication_level = Level.ONE_FACTOR; - }); - - describe("test reset password post", () => { - it("should update the password and reset auth_session for reauthentication", function () { - req.body.password = "new-password"; - - mocks.usersDatabase.updatePasswordStub.returns(BluebirdPromise.resolve()); - - authSession.identity_check = { - userid: "user", - challenge: "reset-password" - }; - return PasswordResetFormPost.default(vars)(req as any, res as any) - .then(function () { - return AuthenticationSessionHandler.get(req as any, vars.logger); - }).then(function (_authSession) { - Assert.equal(res.status.getCall(0).args[0], 204); - Assert.equal(_authSession.authentication_level, Level.NOT_AUTHENTICATED); - return BluebirdPromise.resolve(); - }); - }); - - it("should fail if identity_challenge does not exist", function () { - authSession.identity_check = { - userid: "user", - challenge: undefined - }; - return PasswordResetFormPost.default(vars)(req as any, res as any) - .then(function () { - Assert.equal(res.status.getCall(0).args[0], 200); - Assert.deepEqual(res.send.getCall(0).args[0], { - error: "An error occurred during password reset. Your password has not been changed." - }); - }); - }); - - it("should fail when ldap fails", function () { - req.body.password = "new-password"; - - mocks.usersDatabase.updatePasswordStub - .returns(BluebirdPromise.reject("Internal error with LDAP")); - - authSession.identity_check = { - challenge: "reset-password", - userid: "user" - }; - return PasswordResetFormPost.default(vars)(req as any, res as any) - .then(function () { - Assert.equal(res.status.getCall(0).args[0], 200); - Assert.deepEqual(res.send.getCall(0).args[0], { - error: "An error occurred during password reset. Your password has not been changed." - }); - return BluebirdPromise.resolve(); - }); - }); - }); -}); diff --git a/server/src/lib/routes/password-reset/form/post.ts b/server/src/lib/routes/password-reset/form/post.ts deleted file mode 100644 index 5e21b27e1..000000000 --- a/server/src/lib/routes/password-reset/form/post.ts +++ /dev/null @@ -1,49 +0,0 @@ - -import express = require("express"); -import BluebirdPromise = require("bluebird"); -import objectPath = require("object-path"); -import { AuthenticationSessionHandler } from "../../../AuthenticationSessionHandler"; -import { AuthenticationSession } from "../../../../../types/AuthenticationSession"; -import ErrorReplies = require("../../../ErrorReplies"); -import UserMessages = require("../../../UserMessages"); -import { ServerVariables } from "../../../ServerVariables"; - -import Constants = require("./../constants"); - -export default function (vars: ServerVariables) { - return function (req: express.Request, res: express.Response): BluebirdPromise { - let authSession: AuthenticationSession; - const newPassword = objectPath.get(req, "body.password"); - - return new BluebirdPromise(function (resolve, reject) { - authSession = AuthenticationSessionHandler.get(req, vars.logger); - if (!authSession.identity_check) { - reject(new Error("No identity check initiated")); - return; - } - - vars.logger.info(req, "User %s wants to reset his/her password.", - authSession.identity_check.userid); - vars.logger.debug(req, "Challenge %s", authSession.identity_check.challenge); - - if (authSession.identity_check.challenge != Constants.CHALLENGE) { - reject(new Error("Bad challenge.")); - return; - } - resolve(); - }) - .then(function () { - return vars.usersDatabase.updatePassword(authSession.identity_check.userid, newPassword); - }) - .then(function () { - vars.logger.info(req, "Password reset for user '%s'", - authSession.identity_check.userid); - AuthenticationSessionHandler.reset(req); - res.status(204); - res.send(); - return BluebirdPromise.resolve(); - }) - .catch(ErrorReplies.replyWithError200(req, res, vars.logger, - UserMessages.RESET_PASSWORD_FAILED)); - }; -} diff --git a/server/src/lib/routes/password-reset/identity/PasswordResetHandler.spec.ts b/server/src/lib/routes/password-reset/identity/PasswordResetHandler.spec.ts deleted file mode 100644 index b3f3980b6..000000000 --- a/server/src/lib/routes/password-reset/identity/PasswordResetHandler.spec.ts +++ /dev/null @@ -1,74 +0,0 @@ -import * as Express from "express"; -import PasswordResetHandler - from "./PasswordResetHandler"; -import BluebirdPromise = require("bluebird"); -import ExpressMock = require("../../../stubs/express.spec"); -import { ServerVariablesMock, ServerVariablesMockBuilder } - from "../../../ServerVariablesMockBuilder.spec"; -import { ServerVariables } from "../../../ServerVariables"; - -describe("routes/password-reset/identity/PasswordResetHandler", function () { - let req: Express.Request; - let mocks: ServerVariablesMock; - let vars: ServerVariables; - - beforeEach(function () { - req = ExpressMock.RequestMock(); - req.body.username = "user"; - req.session.auth = { - userid: "user", - email: "user@example.com", - first_factor: true, - second_factor: false - }; - req.headers.host = "localhost"; - - const s = ServerVariablesMockBuilder.build(); - mocks = s.mocks; - vars = s.variables; - - mocks.userDataStore.saveU2FRegistrationStub - .returns(BluebirdPromise.resolve({})); - mocks.userDataStore.retrieveU2FRegistrationStub - .returns(BluebirdPromise.resolve({})); - mocks.userDataStore.produceIdentityValidationTokenStub - .returns(BluebirdPromise.resolve({})); - mocks.userDataStore.consumeIdentityValidationTokenStub - .returns(BluebirdPromise.resolve({})); - }); - - describe("test reset password identity pre check", () => { - it("should fail when no userid is provided", function () { - req.body.username = undefined; - const handler = new PasswordResetHandler(vars.logger, - vars.usersDatabase); - return handler.preValidationInit(req as any) - .then(function () { - return BluebirdPromise.reject("It should fail"); - }) - .catch(function (err: Error) { - return BluebirdPromise.resolve(); - }); - }); - - it("should fail if ldap fail", function () { - mocks.usersDatabase.getEmailsStub - .returns(BluebirdPromise.reject("Internal error")); - new PasswordResetHandler(vars.logger, vars.usersDatabase) - .preValidationInit(req as any) - .then(function () { - return BluebirdPromise.reject(new Error("should not be here")); - }, - function (err: Error) { - return BluebirdPromise.resolve(); - }); - }); - - it("should returns identity when ldap replies", function () { - mocks.usersDatabase.getEmailsStub - .returns(BluebirdPromise.resolve(["test@example.com"])); - return new PasswordResetHandler(vars.logger, vars.usersDatabase) - .preValidationInit(req as any); - }); - }); -}); diff --git a/server/src/lib/routes/password-reset/identity/PasswordResetHandler.ts b/server/src/lib/routes/password-reset/identity/PasswordResetHandler.ts deleted file mode 100644 index c32815755..000000000 --- a/server/src/lib/routes/password-reset/identity/PasswordResetHandler.ts +++ /dev/null @@ -1,72 +0,0 @@ -import express = require("express"); -import BluebirdPromise = require("bluebird"); -import objectPath = require("object-path"); - -import exceptions = require("../../../Exceptions"); -import { Identity } from "../../../../../types/Identity"; -import { IdentityValidable } from "../../../IdentityValidable"; -import Constants = require("../constants"); -import { IRequestLogger } from "../../../logging/IRequestLogger"; -import { IUsersDatabase } from "../../../authentication/backends/IUsersDatabase"; - -export default class PasswordResetHandler implements IdentityValidable { - private logger: IRequestLogger; - private usersDatabase: IUsersDatabase; - - constructor(logger: IRequestLogger, usersDatabase: IUsersDatabase) { - this.logger = logger; - this.usersDatabase = usersDatabase; - } - - challenge(): string { - return Constants.CHALLENGE; - } - - preValidationInit(req: express.Request): BluebirdPromise { - const that = this; - const userid: string = - objectPath.get(req, "body.username"); - return BluebirdPromise.resolve() - .then(function () { - that.logger.debug(req, "User '%s' requested a password reset", userid); - if (!userid) { - return BluebirdPromise.reject( - new exceptions.AccessDeniedError("No user id provided")); - } - return that.usersDatabase.getEmails(userid); - }) - .then(function (emails: string[]) { - if (!emails && emails.length <= 0) throw new Error("No email found"); - const identity = { - email: emails[0], - userid: userid - }; - return BluebirdPromise.resolve(identity); - }) - .catch(function (err: Error) { - return BluebirdPromise.reject(new exceptions.IdentityError(err.message)); - }); - } - - preValidationResponse(req: express.Request, res: express.Response) { - res.status(204); - res.send(); - } - - postValidationInit(req: express.Request) { - return BluebirdPromise.resolve(); - } - - postValidationResponse(req: express.Request, res: express.Response) { - res.status(204); - res.send(); - } - - mailSubject(): string { - return "Reset your password"; - } - - destinationPath(): string { - return "/reset-password"; - } -} \ No newline at end of file diff --git a/server/src/lib/routes/secondfactor/available/Get.spec.ts b/server/src/lib/routes/secondfactor/available/Get.spec.ts deleted file mode 100644 index ff700805e..000000000 --- a/server/src/lib/routes/secondfactor/available/Get.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -import * as Express from "express"; -import { ServerVariables } from "../../../ServerVariables"; -import { ServerVariablesMockBuilder } from "../../../ServerVariablesMockBuilder.spec"; -import * as ExpressMock from "../../../stubs/express.spec"; -import Get from "./Get"; -import * as Assert from "assert"; - - -describe("routes/secondfactor/duo-push/Post", function() { - let vars: ServerVariables; - let req: Express.Request; - let res: ExpressMock.ResponseMock; - - beforeEach(function() { - const sv = ServerVariablesMockBuilder.build(); - vars = sv.variables; - - req = ExpressMock.RequestMock(); - res = ExpressMock.ResponseMock(); - }) - - it("should return default available methods", async function() { - await Get(vars)(req, res as any); - Assert(res.json.calledWith(["u2f", "totp"])); - }); - - it("should return duo as an available method", async function() { - vars.config.duo_api = { - hostname: "example.com", - integration_key: "ABCDEFG", - secret_key: "ekjfzelfjz", - } - await Get(vars)(req, res as any); - Assert(res.json.calledWith(["u2f", "totp", "duo_push"])); - }); -}); \ No newline at end of file diff --git a/server/src/lib/routes/secondfactor/available/Get.ts b/server/src/lib/routes/secondfactor/available/Get.ts deleted file mode 100644 index ccbaa42ea..000000000 --- a/server/src/lib/routes/secondfactor/available/Get.ts +++ /dev/null @@ -1,14 +0,0 @@ -import * as Express from "express"; -import { ServerVariables } from "../../../ServerVariables"; -import Method2FA from "../../../Method2FA"; - - -export default function(vars: ServerVariables) { - return async function(_: Express.Request, res: Express.Response) { - const availableMethods: Method2FA[] = ["u2f", "totp"]; - if (vars.config.duo_api) { - availableMethods.push("duo_push"); - } - res.json(availableMethods); - }; -} \ No newline at end of file diff --git a/server/src/lib/routes/secondfactor/duo-push/Post.spec.ts b/server/src/lib/routes/secondfactor/duo-push/Post.spec.ts deleted file mode 100644 index b71bb234b..000000000 --- a/server/src/lib/routes/secondfactor/duo-push/Post.spec.ts +++ /dev/null @@ -1,109 +0,0 @@ -import * as Express from "express"; -import { ServerVariables } from "../../../ServerVariables"; -import { ServerVariablesMockBuilder, ServerVariablesMock } from "../../../ServerVariablesMockBuilder.spec"; -import * as ExpressMock from "../../../stubs/express.spec"; -import Post from "./Post"; -import * as Sinon from "sinon"; -import * as Assert from "assert"; -import { Level } from "../../../authentication/Level"; -const DuoApi = require("@duosecurity/duo_api"); - - -describe("routes/secondfactor/duo-push/Post", function() { - let vars: ServerVariables; - let mocks: ServerVariablesMock; - let req: Express.Request; - let res: ExpressMock.ResponseMock; - - beforeEach(function() { - const sv = ServerVariablesMockBuilder.build(); - vars = sv.variables; - mocks = sv.mocks; - - vars.config.duo_api = { - hostname: 'abc', - integration_key: 'xyz', - secret_key: 'secret', - }; - - req = ExpressMock.RequestMock(); - res = ExpressMock.ResponseMock(); - }); - - it("should raise authentication level of user", async function() { - const mock = Sinon.stub(DuoApi, "Client"); - mock.returns({ - jsonApiCall: Sinon.stub().yields({response: {result: 'allow'}}) - }); - req.session.auth = { - userid: 'john' - }; - - Assert.equal(req.session.auth.authentication_level, undefined); - await Post(vars)(req, res as any); - Assert(res.status.calledWith(204)); - Assert(res.send.calledWith()); - Assert.equal(req.session.auth.authentication_level, Level.TWO_FACTOR); - mock.restore(); - }); - - it("should block if no duo API is configured", async function() { - const mock = Sinon.stub(DuoApi, "Client"); - mock.returns({ - jsonApiCall: Sinon.stub().yields({response: {result: 'allow'}}) - }); - req.session.auth = { - userid: 'john' - }; - vars.config.duo_api = undefined; - - Assert.equal(req.session.auth.authentication_level, undefined); - await Post(vars)(req, res as any); - Assert(res.status.calledWith(200)); - Assert(res.send.calledWith({error: 'Operation failed.'})); - Assert.equal(req.session.auth.authentication_level, undefined); - mock.restore(); - }); - - it("should block if user denied notification", async function() { - const mock = Sinon.stub(DuoApi, "Client"); - mock.returns({ - jsonApiCall: Sinon.stub().yields({response: {result: 'deny'}}) - }); - req.session.auth = { - userid: 'john' - }; - - Assert.equal(req.session.auth.authentication_level, undefined); - await Post(vars)(req, res as any); - Assert(res.status.calledWith(200)); - Assert(res.send.calledWith({error: 'Operation failed.'})); - Assert.equal(req.session.auth.authentication_level, undefined); - mock.restore(); - }); - - it("should block if duo push service is down", function() { - const mock = Sinon.stub(DuoApi, "Client"); - const timerMock = Sinon.useFakeTimers(); - mock.returns({ - jsonApiCall: Sinon.stub() - }); - req.session.auth = { - userid: 'john' - }; - - Assert.equal(req.session.auth.authentication_level, undefined); - const promise = Post(vars)(req, res as any) - .then(() => { - Assert(res.status.calledWith(200)); - Assert(res.send.calledWith({error: 'Operation failed.'})); - Assert.equal(req.session.auth.authentication_level, undefined); - - mock.restore(); - timerMock.restore(); - }); - // Move forward in time to timeout. - timerMock.tick(62000); - return promise; - }); -}); \ No newline at end of file diff --git a/server/src/lib/routes/secondfactor/duo-push/Post.ts b/server/src/lib/routes/secondfactor/duo-push/Post.ts deleted file mode 100644 index 6ceb75847..000000000 --- a/server/src/lib/routes/secondfactor/duo-push/Post.ts +++ /dev/null @@ -1,55 +0,0 @@ -import * as Express from "express"; -import { ServerVariables } from "../../../ServerVariables"; -import { AuthenticationSessionHandler } from "../../../AuthenticationSessionHandler"; -import * as ErrorReplies from "../../../ErrorReplies"; -import * as UserMessage from "../../../UserMessages"; -import redirect from "../redirect"; -import { Level } from "../../../authentication/Level"; -import { DuoPushConfiguration } from "../../../configuration/schema/DuoPushConfiguration"; -import GetHeader from "../../../utils/GetHeader"; -import { HEADER_X_TARGET_URL } from "../../../constants"; -const DuoApi = require("@duosecurity/duo_api"); - -interface DuoResponse { - response: { - result: "allow" | "deny"; - status: "allow" | "deny" | "fraud"; - status_msg: string; - }; - stat: "OK" | "FAIL"; -} - -function triggerAuth(username: string, config: DuoPushConfiguration, req: Express.Request): Promise { - return new Promise((resolve, reject) => { - const clientIP = req.ip; - const targetURL = GetHeader(req, HEADER_X_TARGET_URL); - const client = new DuoApi.Client(config.integration_key, config.secret_key, config.hostname); - const timer = setTimeout(() => reject(new Error("Call to duo push API timed out.")), 60000); - client.jsonApiCall("POST", "/auth/v2/auth", { username, ipaddr: clientIP, factor: "push", device: "auto", pushinfo: `target%20url=${targetURL}`}, (data: DuoResponse) => { - clearTimeout(timer); - resolve(data); - }); - }); -} - - -export default function(vars: ServerVariables) { - return async function(req: Express.Request, res: Express.Response) { - try { - if (!vars.config.duo_api) { - throw new Error("Duo Push Notification is not configured."); - } - - const authSession = AuthenticationSessionHandler.get(req, vars.logger); - const authRes = await triggerAuth(authSession.userid, vars.config.duo_api, req); - if (authRes.response.result !== "allow") { - throw new Error("User denied access."); - } - vars.logger.debug(req, "Access allowed by user via Duo Push."); - authSession.authentication_level = Level.TWO_FACTOR; - await redirect(vars)(req, res); - } catch (err) { - ErrorReplies.replyWithError200(req, res, vars.logger, UserMessage.OPERATION_FAILED)(err); - } - }; -} \ No newline at end of file diff --git a/server/src/lib/routes/secondfactor/preferences/Get.spec.ts b/server/src/lib/routes/secondfactor/preferences/Get.spec.ts deleted file mode 100644 index 7767672cc..000000000 --- a/server/src/lib/routes/secondfactor/preferences/Get.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -import * as Express from "express"; -import * as Bluebird from "bluebird"; -import { ServerVariables } from "../../../ServerVariables"; -import { ServerVariablesMockBuilder, ServerVariablesMock } from "../../../ServerVariablesMockBuilder.spec"; -import * as ExpressMock from "../../../stubs/express.spec"; -import Get from "./Get"; -import * as Assert from "assert"; - -describe("routes/secondfactor/preferences/Get", function() { - let vars: ServerVariables; - let mocks: ServerVariablesMock; - let req: Express.Request; - let res: ExpressMock.ResponseMock; - - beforeEach(function() { - const sv = ServerVariablesMockBuilder.build(); - vars = sv.variables; - mocks = sv.mocks; - - req = ExpressMock.RequestMock(); - res = ExpressMock.ResponseMock(); - }) - - it("should get the method from db", async function() { - mocks.userDataStore.retrievePrefered2FAMethodStub.returns(Bluebird.resolve('totp')); - await Get(vars)(req, res as any); - Assert(res.json.calledWith({method: 'totp'})); - }); - - it("should fail when database fail to retrieve method", async function() { - mocks.userDataStore.retrievePrefered2FAMethodStub.returns(Bluebird.reject(new Error('DB connection failed.'))); - await Get(vars)(req, res as any); - Assert(res.status.calledWith(200)); - Assert(res.send.calledWith({ error: "Operation failed." })); - }) -}); \ No newline at end of file diff --git a/server/src/lib/routes/secondfactor/preferences/Get.ts b/server/src/lib/routes/secondfactor/preferences/Get.ts deleted file mode 100644 index 6a39d5ed2..000000000 --- a/server/src/lib/routes/secondfactor/preferences/Get.ts +++ /dev/null @@ -1,18 +0,0 @@ -import * as Express from "express"; -import { ServerVariables } from "../../../ServerVariables"; -import { AuthenticationSessionHandler } from "../../../AuthenticationSessionHandler"; -import * as ErrorReplies from "../../../ErrorReplies"; -import * as UserMessage from "../../../UserMessages"; - - -export default function(vars: ServerVariables) { - return async function(req: Express.Request, res: Express.Response) { - try { - const authSession = AuthenticationSessionHandler.get(req, vars.logger); - const method = await vars.userDataStore.retrievePrefered2FAMethod(authSession.userid); - res.json({method}); - } catch (err) { - ErrorReplies.replyWithError200(req, res, vars.logger, UserMessage.OPERATION_FAILED)(err); - } - }; -} \ No newline at end of file diff --git a/server/src/lib/routes/secondfactor/preferences/Post.spec.ts b/server/src/lib/routes/secondfactor/preferences/Post.spec.ts deleted file mode 100644 index da2b71e82..000000000 --- a/server/src/lib/routes/secondfactor/preferences/Post.spec.ts +++ /dev/null @@ -1,55 +0,0 @@ -import * as Express from "express"; -import * as Bluebird from "bluebird"; -import { ServerVariables } from "../../../ServerVariables"; -import { ServerVariablesMockBuilder, ServerVariablesMock } from "../../../ServerVariablesMockBuilder.spec"; -import * as ExpressMock from "../../../stubs/express.spec"; -import Post from "./Post"; -import * as Assert from "assert"; - -describe("routes/secondfactor/preferences/Post", function() { - let vars: ServerVariables; - let mocks: ServerVariablesMock; - let req: Express.Request; - let res: ExpressMock.ResponseMock; - - beforeEach(function() { - const sv = ServerVariablesMockBuilder.build(); - vars = sv.variables; - mocks = sv.mocks; - - req = ExpressMock.RequestMock(); - res = ExpressMock.ResponseMock(); - }) - - it("should save the method in DB", async function() { - mocks.userDataStore.savePrefered2FAMethodStub.returns(Bluebird.resolve()); - req.body.method = 'totp'; - req.session.auth = { - userid: 'john' - } - await Post(vars)(req, res as any); - Assert(mocks.userDataStore.savePrefered2FAMethodStub.calledWith('john', 'totp')); - Assert(res.status.calledWith(204)); - Assert(res.send.calledWith()); - }); - - it("should fail if no method is provided in body", async function() { - req.session.auth = { - userid: 'john' - } - await Post(vars)(req, res as any); - Assert(res.status.calledWith(200)); - Assert(res.send.calledWith({ error: "Operation failed." })); - }); - - it("should fail if access to DB fails", async function() { - mocks.userDataStore.savePrefered2FAMethodStub.returns(Bluebird.reject(new Error('DB access failed.'))); - req.body.method = 'totp' - req.session.auth = { - userid: 'john' - } - await Post(vars)(req, res as any); - Assert(res.status.calledWith(200)); - Assert(res.send.calledWith({ error: "Operation failed." })); - }); -}); \ No newline at end of file diff --git a/server/src/lib/routes/secondfactor/preferences/Post.ts b/server/src/lib/routes/secondfactor/preferences/Post.ts deleted file mode 100644 index a04b24ad8..000000000 --- a/server/src/lib/routes/secondfactor/preferences/Post.ts +++ /dev/null @@ -1,23 +0,0 @@ -import * as Express from "express"; -import { ServerVariables } from "../../../ServerVariables"; -import { AuthenticationSessionHandler } from "../../../AuthenticationSessionHandler"; -import * as ErrorReplies from "../../../ErrorReplies"; -import * as UserMessage from "../../../UserMessages"; - - -export default function(vars: ServerVariables) { - return async function(req: Express.Request, res: Express.Response) { - try { - if (!(req.body && req.body.method)) { - throw new Error("No 'method' key in request body"); - } - - const authSession = AuthenticationSessionHandler.get(req, vars.logger); - await vars.userDataStore.savePrefered2FAMethod(authSession.userid, req.body.method); - res.status(204); - res.send(); - } catch (err) { - ErrorReplies.replyWithError200(req, res, vars.logger, UserMessage.OPERATION_FAILED)(err); - } - }; -} \ No newline at end of file diff --git a/server/src/lib/routes/secondfactor/redirect.spec.ts b/server/src/lib/routes/secondfactor/redirect.spec.ts deleted file mode 100644 index e31f364b5..000000000 --- a/server/src/lib/routes/secondfactor/redirect.spec.ts +++ /dev/null @@ -1,44 +0,0 @@ -import * as Express from "express"; -import Redirect from "./redirect"; -import ExpressMock = require("../../stubs/express.spec"); -import { ServerVariablesMockBuilder } -from "../../ServerVariablesMockBuilder.spec"; -import { ServerVariables } from "../../ServerVariables"; -import Assert = require("assert"); -import { HEADER_X_TARGET_URL } from "../../constants"; - -describe("routes/secondfactor/redirect", function() { - let req: Express.Request; - let res: ExpressMock.ResponseMock; - let vars: ServerVariables; - - beforeEach(function () { - const s = ServerVariablesMockBuilder.build(); - vars = s.variables; - - req = ExpressMock.RequestMock(); - res = ExpressMock.ResponseMock(); - vars.config.session.domain = 'example.com'; - }); - - describe('redirect to default url if no target provided', () => { - it("should redirect to default url", async () => { - vars.config.default_redirection_url = "https://home.example.com"; - await Redirect(vars)(req, res as any) - Assert(res.json.calledWith({redirect: "https://home.example.com"})); - }); - }); - - it("should redirect to safe url https://test.example.com/", async () => { - req.headers[HEADER_X_TARGET_URL] = "https://test.example.com/"; - await Redirect(vars)(req, res as any); - Assert(res.json.calledWith({redirect: "https://test.example.com/"})); - }); - - it('should not redirect to unsafe target url', async () => { - vars.config.default_redirection_url = "https://home.example.com"; - req.headers[HEADER_X_TARGET_URL] = "http://test.example.com/"; - await Redirect(vars)(req, res as any); - Assert(res.status.calledWith(204)); - }) -}); \ No newline at end of file diff --git a/server/src/lib/routes/secondfactor/redirect.ts b/server/src/lib/routes/secondfactor/redirect.ts deleted file mode 100644 index 83bb88abe..000000000 --- a/server/src/lib/routes/secondfactor/redirect.ts +++ /dev/null @@ -1,27 +0,0 @@ - -import * as Express from "express"; -import * as URLParse from "url-parse"; -import { ServerVariables } from "../../ServerVariables"; -import IsRedirectionSafe from "../../../lib/utils/IsRedirectionSafe"; -import GetHeader from "../../utils/GetHeader"; -import { HEADER_X_TARGET_URL } from "../../constants"; - - -export default function (vars: ServerVariables) { - return async function (req: Express.Request, res: Express.Response): Promise { - let redirectUrl = GetHeader(req, HEADER_X_TARGET_URL); - - if (!redirectUrl && vars.config.default_redirection_url) { - redirectUrl = vars.config.default_redirection_url; - } - - if ((redirectUrl && !IsRedirectionSafe(vars, new URLParse(redirectUrl))) - || !redirectUrl) { - res.status(204); - res.send(); - return; - } - - res.json({redirect: redirectUrl}); - }; -} diff --git a/server/src/lib/routes/secondfactor/totp/constants.ts b/server/src/lib/routes/secondfactor/totp/constants.ts deleted file mode 100644 index 7b5a1dcfe..000000000 --- a/server/src/lib/routes/secondfactor/totp/constants.ts +++ /dev/null @@ -1,4 +0,0 @@ - -export const CHALLENGE = "totp-register"; -export const TEMPLATE_NAME = "totp-register"; - diff --git a/server/src/lib/routes/secondfactor/totp/identity/RegistrationHandler.spec.ts b/server/src/lib/routes/secondfactor/totp/identity/RegistrationHandler.spec.ts deleted file mode 100644 index 394ee1412..000000000 --- a/server/src/lib/routes/secondfactor/totp/identity/RegistrationHandler.spec.ts +++ /dev/null @@ -1,108 +0,0 @@ -import RegistrationHandler from "./RegistrationHandler"; -import BluebirdPromise = require("bluebird"); -import ExpressMock = require("../../../../stubs/express.spec"); -import { ServerVariablesMock, ServerVariablesMockBuilder } - from "../../../../ServerVariablesMockBuilder.spec"; -import { ServerVariables } from "../../../../ServerVariables"; -import Assert = require("assert"); - -describe("routes/secondfactor/totp/identity/RegistrationHandler", function () { - let req: Express.Request; - let res: ExpressMock.ResponseMock; - let mocks: ServerVariablesMock; - let vars: ServerVariables; - - beforeEach(function () { - const s = ServerVariablesMockBuilder.build(); - mocks = s.mocks; - vars = s.variables; - - req = ExpressMock.RequestMock(); - req.session = { - ...req.session, - auth: { - userid: "user", - email: "user@example.com", - first_factor: true, - second_factor: false, - identity_check: { - userid: "user", - challenge: "totp-register" - } - } - }; - - mocks.userDataStore.saveU2FRegistrationStub - .returns(BluebirdPromise.resolve({})); - mocks.userDataStore.retrieveU2FRegistrationStub - .returns(BluebirdPromise.resolve({})); - mocks.userDataStore.produceIdentityValidationTokenStub - .returns(BluebirdPromise.resolve({})); - mocks.userDataStore.consumeIdentityValidationTokenStub - .returns(BluebirdPromise.resolve({})); - mocks.userDataStore.saveTOTPSecretStub - .returns(BluebirdPromise.resolve({})); - - res = ExpressMock.ResponseMock(); - }); - - describe("test totp registration pre validation", function () { - it("should fail if first_factor has not been passed", function () { - req.session.auth.first_factor = false; - return new RegistrationHandler(vars.logger, vars.userDataStore, - vars.totpHandler, vars.config.totp) - .preValidationInit(req as any) - .then(function () { - return BluebirdPromise.reject(new Error("It should fail")); - }) - .catch(function (err: Error) { - return BluebirdPromise.resolve(); - }); - }); - - it("should fail if userid is missing", function (done) { - req.session.auth.first_factor = false; - req.session.auth.userid = undefined; - - new RegistrationHandler(vars.logger, vars.userDataStore, vars.totpHandler, - vars.config.totp) - .preValidationInit(req as any) - .catch(function (err: Error) { - done(); - }); - }); - - it("should fail if email is missing", function (done) { - req.session.auth.first_factor = false; - req.session.auth.email = undefined; - - new RegistrationHandler(vars.logger, vars.userDataStore, vars.totpHandler, - vars.config.totp) - .preValidationInit(req as any) - .catch(function (err: Error) { - done(); - }); - }); - - it("should succeed if first factor passed, userid and email are provided", - function () { - return new RegistrationHandler(vars.logger, vars.userDataStore, - vars.totpHandler, vars.config.totp) - .preValidationInit(req as any); - }); - }); - - describe("test totp registration post validation", function () { - it("should generate a secret using userId as label and issuer defined in config", function () { - vars.config.totp = { - issuer: "issuer" - }; - return new RegistrationHandler(vars.logger, vars.userDataStore, - vars.totpHandler, vars.config.totp) - .postValidationResponse(req as any, res as any) - .then(function() { - Assert(mocks.totpHandler.generateStub.calledWithExactly("user", "issuer")); - }); - }); - }); -}); diff --git a/server/src/lib/routes/secondfactor/totp/identity/RegistrationHandler.ts b/server/src/lib/routes/secondfactor/totp/identity/RegistrationHandler.ts deleted file mode 100644 index 69bac57d6..000000000 --- a/server/src/lib/routes/secondfactor/totp/identity/RegistrationHandler.ts +++ /dev/null @@ -1,112 +0,0 @@ - -import * as Express from "express"; -import BluebirdPromise = require("bluebird"); - -import { Identity } from "../../../../../../types/Identity"; -import { IdentityValidable } from "../../../../IdentityValidable"; -import Constants = require("../constants"); -import ErrorReplies = require("../../../../ErrorReplies"); -import { AuthenticationSessionHandler } from "../../../../AuthenticationSessionHandler"; -import UserMessages = require("../../../../UserMessages"); -import FirstFactorValidator = require("../../../../FirstFactorValidator"); -import { IRequestLogger } from "../../../../logging/IRequestLogger"; -import { IUserDataStore } from "../../../../storage/IUserDataStore"; -import { ITotpHandler } from "../../../../authentication/totp/ITotpHandler"; -import { TOTPSecret } from "../../../../../../types/TOTPSecret"; -import { TotpConfiguration } from "../../../../configuration/schema/TotpConfiguration"; - - -export default class RegistrationHandler implements IdentityValidable { - private logger: IRequestLogger; - private userDataStore: IUserDataStore; - private totp: ITotpHandler; - private configuration: TotpConfiguration; - - constructor(logger: IRequestLogger, - userDataStore: IUserDataStore, - totp: ITotpHandler, configuration: TotpConfiguration) { - this.logger = logger; - this.userDataStore = userDataStore; - this.totp = totp; - this.configuration = configuration; - } - - challenge(): string { - return Constants.CHALLENGE; - } - - private retrieveIdentity(req: Express.Request): BluebirdPromise { - const that = this; - return new BluebirdPromise(function (resolve, reject) { - const authSession = AuthenticationSessionHandler.get(req, that.logger); - const userid = authSession.userid; - const email = authSession.email; - - if (!(userid && email)) { - return reject(new Error("User ID or email is missing")); - } - - const identity = { - email: email, - userid: userid - }; - return resolve(identity); - }); - } - - preValidationInit(req: Express.Request): BluebirdPromise { - const that = this; - return FirstFactorValidator.validate(req, this.logger) - .then(function () { - return that.retrieveIdentity(req); - }); - } - - preValidationResponse(req: Express.Request, res: Express.Response) { - res.json({message: "OK"}); - } - - postValidationInit(req: Express.Request) { - return FirstFactorValidator.validate(req, this.logger); - } - - postValidationResponse(req: Express.Request, res: Express.Response) - : BluebirdPromise { - const that = this; - let secret: TOTPSecret; - let userId: string; - return new BluebirdPromise(function (resolve, reject) { - const authSession = AuthenticationSessionHandler.get(req, that.logger); - userId = authSession.userid; - - if (authSession.identity_check.challenge != Constants.CHALLENGE - || !userId) - return reject(new Error("Bad challenge.")); - - resolve(); - }) - .then(function () { - secret = that.totp.generate(userId, - that.configuration.issuer); - that.logger.debug(req, "Save the TOTP secret in DB"); - return that.userDataStore.saveTOTPSecret(userId, secret); - }) - .then(function () { - AuthenticationSessionHandler.reset(req); - - res.json({ - base32_secret: secret.base32, - otpauth_url: secret.otpauth_url, - }); - }) - .catch(ErrorReplies.replyWithError200(req, res, that.logger, UserMessages.OPERATION_FAILED)); - } - - mailSubject(): string { - return "Set up Authelia's one-time password"; - } - - destinationPath(): string { - return "/one-time-password-registration"; - } -} \ No newline at end of file diff --git a/server/src/lib/routes/secondfactor/totp/sign/post.spec.ts b/server/src/lib/routes/secondfactor/totp/sign/post.spec.ts deleted file mode 100644 index 58c367c47..000000000 --- a/server/src/lib/routes/secondfactor/totp/sign/post.spec.ts +++ /dev/null @@ -1,65 +0,0 @@ - -import BluebirdPromise = require("bluebird"); -import Assert = require("assert"); -import * as Express from "express"; -import { AuthenticationSessionHandler } from "../../../../AuthenticationSessionHandler"; -import { AuthenticationSession } from "../../../../../../types/AuthenticationSession"; -import SignPost = require("./post"); -import { ServerVariables } from "../../../../ServerVariables"; -import ExpressMock = require("../../../../stubs/express.spec"); -import { ServerVariablesMock, ServerVariablesMockBuilder } from "../../../../ServerVariablesMockBuilder.spec"; -import { Level } from "../../../../authentication/Level"; - -describe("routes/secondfactor/totp/sign/post", function () { - let req: Express.Request; - let res: ExpressMock.ResponseMock; - let authSession: AuthenticationSession; - let vars: ServerVariables; - let mocks: ServerVariablesMock; - - beforeEach(function () { - const s = ServerVariablesMockBuilder.build(); - vars = s.variables; - mocks = s.mocks; - req = ExpressMock.RequestMock(); - req.body = { - token: "abc", - }; - res = ExpressMock.ResponseMock(); - - const doc = { - userid: "user", - secret: { - base32: "ABCDEF" - } - }; - mocks.userDataStore.retrieveTOTPSecretStub.returns(BluebirdPromise.resolve(doc)); - authSession = AuthenticationSessionHandler.get(req as any, vars.logger); - authSession.userid = "user"; - authSession.authentication_level = Level.ONE_FACTOR; - }); - - - it("should send status code 200 when totp is valid", function () { - mocks.totpHandler.validateStub.returns(true); - return SignPost.default(vars)(req as any, res as any) - .then(function () { - Assert.equal(authSession.authentication_level, Level.TWO_FACTOR); - return BluebirdPromise.resolve(); - }); - }); - - it("should send error message when totp is not valid", function () { - mocks.totpHandler.validateStub.returns(false); - return SignPost.default(vars)(req as any, res as any) - .then(function () { - Assert.notEqual(authSession.authentication_level, Level.TWO_FACTOR); - Assert.equal(res.status.getCall(0).args[0], 200); - Assert.deepEqual(res.send.getCall(0).args[0], { - error: "Authentication failed. Have you already registered your secret?" - }); - return BluebirdPromise.resolve(); - }); - }); -}); - diff --git a/server/src/lib/routes/secondfactor/totp/sign/post.ts b/server/src/lib/routes/secondfactor/totp/sign/post.ts deleted file mode 100644 index 55ee564f8..000000000 --- a/server/src/lib/routes/secondfactor/totp/sign/post.ts +++ /dev/null @@ -1,40 +0,0 @@ -import Bluebird = require("bluebird"); -import Express = require("express"); - -import { TOTPSecretDocument } from "../../../../storage/TOTPSecretDocument"; -import Redirect from "../../redirect"; -import ErrorReplies = require("../../../../ErrorReplies"); -import { AuthenticationSessionHandler } from "../../../../AuthenticationSessionHandler"; -import { AuthenticationSession } from "../../../../../../types/AuthenticationSession"; -import UserMessages = require("../../../../UserMessages"); -import { ServerVariables } from "../../../../ServerVariables"; -import { Level } from "../../../../authentication/Level"; - -export default function (vars: ServerVariables) { - function handler(req: Express.Request, res: Express.Response): Bluebird { - let authSession: AuthenticationSession; - const token = req.body.token; - - return new Bluebird(function (resolve, reject) { - authSession = AuthenticationSessionHandler.get(req, vars.logger); - vars.logger.info(req, "Initiate TOTP validation for user \"%s\".", authSession.userid); - resolve(); - }) - .then(function () { - return vars.userDataStore.retrieveTOTPSecret(authSession.userid); - }) - .then(function (doc: TOTPSecretDocument) { - if (!vars.totpHandler.validate(token, doc.secret.base32)) { - return Bluebird.reject(new Error("Invalid TOTP token.")); - } - - vars.logger.debug(req, "TOTP validation succeeded."); - authSession.authentication_level = Level.TWO_FACTOR; - Redirect(vars)(req, res); - return Bluebird.resolve(); - }) - .catch(ErrorReplies.replyWithError200(req, res, vars.logger, - UserMessages.AUTHENTICATION_TOTP_FAILED)); - } - return handler; -} diff --git a/server/src/lib/routes/secondfactor/u2f/identity/RegistrationHandler.spec.ts b/server/src/lib/routes/secondfactor/u2f/identity/RegistrationHandler.spec.ts deleted file mode 100644 index ad65a1e8c..000000000 --- a/server/src/lib/routes/secondfactor/u2f/identity/RegistrationHandler.spec.ts +++ /dev/null @@ -1,89 +0,0 @@ -import * as Express from "express"; -import Sinon = require("sinon"); -import BluebirdPromise = require("bluebird"); -import RegistrationHandler from "./RegistrationHandler"; -import ExpressMock = require("../../../../stubs/express.spec"); -import { ServerVariablesMock, ServerVariablesMockBuilder } from "../../../../ServerVariablesMockBuilder.spec"; -import { ServerVariables } from "../../../../ServerVariables"; - -describe("routes/secondfactor/u2f/identity/RegistrationHandler", function () { - let req: Express.Request; - let res: ExpressMock.ResponseMock; - let mocks: ServerVariablesMock; - let vars: ServerVariables; - - beforeEach(function () { - const s = ServerVariablesMockBuilder.build(); - mocks = s.mocks; - vars = s.variables; - - req = ExpressMock.RequestMock(); - req.session = { - ...req.session, - auth: { - userid: "user", - email: "user@example.com", - first_factor: true, - second_factor: false - } - }; - req.headers = {}; - req.headers.host = "localhost"; - - mocks.userDataStore.saveU2FRegistrationStub.returns(BluebirdPromise.resolve({})); - mocks.userDataStore.retrieveU2FRegistrationStub.returns(BluebirdPromise.resolve({})); - mocks.userDataStore.produceIdentityValidationTokenStub.returns(BluebirdPromise.resolve({})); - mocks.userDataStore.consumeIdentityValidationTokenStub.returns(BluebirdPromise.resolve({})); - - res = ExpressMock.ResponseMock(); - res.send = Sinon.spy(); - res.json = Sinon.spy(); - res.status = Sinon.spy(); - }); - - describe("test u2f registration check", test_registration_check); - - function test_registration_check() { - it("should fail if first_factor has not been passed", function () { - req.session.auth.first_factor = false; - return new RegistrationHandler(vars.logger).preValidationInit(req as any) - .then(function () { return BluebirdPromise.reject(new Error("It should fail")); }) - .catch(function (err: Error) { - return BluebirdPromise.resolve(); - }); - }); - - it("should fail if userid is missing", function () { - req.session.auth.first_factor = false; - req.session.auth.userid = undefined; - - return new RegistrationHandler(vars.logger).preValidationInit(req as any) - .then(function () { - return BluebirdPromise.reject(new Error("should not be here")); - }, - function (err: Error) { - return BluebirdPromise.resolve(); - }); - }); - - it("should fail if email is missing", function () { - req.session.auth.first_factor = false; - req.session.auth.email = undefined; - - return new RegistrationHandler(vars.logger).preValidationInit(req as any) - .then(function () { - return BluebirdPromise.reject(new Error("should not be here")); - }, - function (err: Error) { - return BluebirdPromise.resolve(); - }); - }); - - it("should succeed if first factor passed, userid and email are provided", function () { - req.session.auth.first_factor = true; - req.session.auth.email = "admin@example.com"; - req.session.auth.userid = "user"; - return new RegistrationHandler(vars.logger).preValidationInit(req as any); - }); - } -}); diff --git a/server/src/lib/routes/secondfactor/u2f/identity/RegistrationHandler.ts b/server/src/lib/routes/secondfactor/u2f/identity/RegistrationHandler.ts deleted file mode 100644 index 3d9557835..000000000 --- a/server/src/lib/routes/secondfactor/u2f/identity/RegistrationHandler.ts +++ /dev/null @@ -1,73 +0,0 @@ - -import BluebirdPromise = require("bluebird"); -import express = require("express"); - -import { IdentityValidable } from "../../../../IdentityValidable"; -import { Identity } from "../../../../../../types/Identity"; -import FirstFactorValidator = require("../../../../FirstFactorValidator"); -import { AuthenticationSessionHandler } from "../../../../AuthenticationSessionHandler"; -import { IRequestLogger } from "../../../../logging/IRequestLogger"; - -const CHALLENGE = "u2f-register"; -const MAIL_SUBJECT = "Register your security key with Authelia"; - - -export default class RegistrationHandler implements IdentityValidable { - private logger: IRequestLogger; - - constructor(logger: IRequestLogger) { - this.logger = logger; - } - - challenge(): string { - return CHALLENGE; - } - - private retrieveIdentity(req: express.Request): BluebirdPromise { - const that = this; - return new BluebirdPromise(function(resolve, reject) { - const authSession = AuthenticationSessionHandler.get(req, that.logger); - const userid = authSession.userid; - const email = authSession.email; - - if (!(userid && email)) { - return reject(new Error("User ID or email is missing")); - } - - const identity = { - email: email, - userid: userid - }; - return resolve(identity); - }); - } - - preValidationInit(req: express.Request): BluebirdPromise { - const that = this; - return FirstFactorValidator.validate(req, this.logger) - .then(function () { - return that.retrieveIdentity(req); - }); - } - - preValidationResponse(req: express.Request, res: express.Response) { - res.json({message: "OK"}); - } - - postValidationInit(req: express.Request) { - return FirstFactorValidator.validate(req, this.logger); - } - - postValidationResponse(req: express.Request, res: express.Response) { - res.json({message: "OK"}); - } - - mailSubject(): string { - return MAIL_SUBJECT; - } - - destinationPath(): string { - return "/security-key-registration"; - } -} - diff --git a/server/src/lib/routes/secondfactor/u2f/register/post.spec.ts b/server/src/lib/routes/secondfactor/u2f/register/post.spec.ts deleted file mode 100644 index 1bf7e1034..000000000 --- a/server/src/lib/routes/secondfactor/u2f/register/post.spec.ts +++ /dev/null @@ -1,141 +0,0 @@ -import * as Express from "express"; -import sinon = require("sinon"); -import BluebirdPromise = require("bluebird"); -import assert = require("assert"); -import U2FRegisterPost = require("./post"); -import { AuthenticationSessionHandler } from "../../../../AuthenticationSessionHandler"; -import { AuthenticationSession } from "../../../../../../types/AuthenticationSession"; -import ExpressMock = require("../../../../stubs/express.spec"); -import { ServerVariablesMockBuilder, ServerVariablesMock } from "../../../../ServerVariablesMockBuilder.spec"; -import { ServerVariables } from "../../../../ServerVariables"; - - -describe("routes/secondfactor/u2f/register/post", function () { - let req: Express.Request; - let res: ExpressMock.ResponseMock; - let mocks: ServerVariablesMock; - let vars: ServerVariables; - let authSession: AuthenticationSession; - - beforeEach(function () { - req = ExpressMock.RequestMock(); - req.originalUrl = "/api/xxxx"; - req.session = { - ...req.session, - auth: { - userid: "user", - first_factor: true, - second_factor: false, - identity_check: { - challenge: "u2f-register", - userid: "user" - } - } - }; - req.headers = {}; - req.headers.host = "localhost"; - - const s = ServerVariablesMockBuilder.build(); - mocks = s.mocks; - vars = s.variables; - - mocks.userDataStore.saveU2FRegistrationStub.returns(BluebirdPromise.resolve({})); - mocks.userDataStore.retrieveU2FRegistrationStub.returns(BluebirdPromise.resolve({})); - - res = ExpressMock.ResponseMock(); - res.send = sinon.spy(); - res.json = sinon.spy(); - res.status = sinon.spy(); - - authSession = AuthenticationSessionHandler.get(req as any, vars.logger); - }); - - describe("test registration", test_registration); - - - function test_registration() { - it("should save u2f meta and return status code 200", function () { - const expectedStatus = { - keyHandle: "keyHandle", - publicKey: "pbk", - certificate: "cert" - }; - mocks.u2f.checkRegistrationStub.returns(BluebirdPromise.resolve(expectedStatus)); - - authSession.register_request = { - appId: "app", - challenge: "challenge", - keyHandle: "key", - version: "U2F_V2" - }; - return U2FRegisterPost.default(vars)(req as any, res as any) - .then(function () { - assert.equal("user", mocks.userDataStore.saveU2FRegistrationStub.getCall(0).args[0]); - assert.equal(authSession.identity_check, undefined); - }); - }); - - it("should return error message on finishRegistration error", function () { - mocks.u2f.checkRegistrationStub.returns({ errorCode: 500 }); - - authSession.register_request = { - appId: "app", - challenge: "challenge", - keyHandle: "key", - version: "U2F_V2" - }; - - return U2FRegisterPost.default(vars)(req as any, res as any) - .then(function () { return BluebirdPromise.reject(new Error("It should fail")); }) - .catch(function () { - assert.equal(200, res.status.getCall(0).args[0]); - assert.deepEqual(res.send.getCall(0).args[0], { - error: "Operation failed." - }); - return BluebirdPromise.resolve(); - }); - }); - - it("should return error message when register_request is not provided", function () { - mocks.u2f.checkRegistrationStub.returns(BluebirdPromise.resolve()); - authSession.register_request = undefined; - return U2FRegisterPost.default(vars)(req as any, res as any) - .then(function () { return BluebirdPromise.reject(new Error("It should fail")); }) - .catch(function () { - assert.equal(200, res.status.getCall(0).args[0]); - assert.deepEqual(res.send.getCall(0).args[0], { - error: "Operation failed." - }); - return BluebirdPromise.resolve(); - }); - }); - - it("should return error message when no auth request has been initiated", function () { - mocks.u2f.checkRegistrationStub.returns(BluebirdPromise.resolve()); - authSession.register_request = undefined; - return U2FRegisterPost.default(vars)(req as any, res as any) - .then(function () { return BluebirdPromise.reject(new Error("It should fail")); }) - .catch(function () { - assert.equal(200, res.status.getCall(0).args[0]); - assert.deepEqual(res.send.getCall(0).args[0], { - error: "Operation failed." - }); - return BluebirdPromise.resolve(); - }); - }); - - it("should return error message when identity has not been verified", function () { - authSession.identity_check = undefined; - return U2FRegisterPost.default(vars)(req as any, res as any) - .then(function () { return BluebirdPromise.reject(new Error("It should fail")); }) - .catch(function () { - assert.equal(200, res.status.getCall(0).args[0]); - assert.deepEqual(res.send.getCall(0).args[0], { - error: "Operation failed." - }); - return BluebirdPromise.resolve(); - }); - }); - } -}); - diff --git a/server/src/lib/routes/secondfactor/u2f/register/post.ts b/server/src/lib/routes/secondfactor/u2f/register/post.ts deleted file mode 100644 index d6b1cc028..000000000 --- a/server/src/lib/routes/secondfactor/u2f/register/post.ts +++ /dev/null @@ -1,65 +0,0 @@ -import objectPath = require("object-path"); -import BluebirdPromise = require("bluebird"); -import express = require("express"); -import U2f = require("u2f"); -import { U2FRegistration } from "../../../../../../types/U2FRegistration"; -import redirect from "../../redirect"; -import ErrorReplies = require("../../../../ErrorReplies"); -import { ServerVariables } from "../../../../ServerVariables"; -import { AuthenticationSessionHandler } from "../../../../AuthenticationSessionHandler"; -import UserMessages = require("../../../../UserMessages"); -import { AuthenticationSession } from "../../../../../../types/AuthenticationSession"; -import GetHeader from "../../../../utils/GetHeader"; -import * as Constants from "../../../../constants"; - - -export default function (vars: ServerVariables) { - function handler(req: express.Request, res: express.Response): BluebirdPromise { - let authSession: AuthenticationSession; - const scheme = GetHeader(req, Constants.HEADER_X_FORWARDED_PROTO); - const host = GetHeader(req, Constants.HEADER_X_FORWARDED_HOST); - const appid = scheme + "://" + host; - const registrationResponse: U2f.RegistrationData = req.body; - - return new BluebirdPromise(function (resolve, reject) { - authSession = AuthenticationSessionHandler.get(req, vars.logger); - const registrationRequest = authSession.register_request; - - if (!registrationRequest) { - return reject(new Error("No registration request")); - } - - if (!authSession.identity_check - || authSession.identity_check.challenge != "u2f-register") { - return reject(new Error("Bad challenge for registration request")); - } - - vars.logger.info(req, "Finishing registration"); - vars.logger.debug(req, "RegistrationRequest = %s", JSON.stringify(registrationRequest)); - vars.logger.debug(req, "RegistrationResponse = %s", JSON.stringify(registrationResponse)); - - return resolve(vars.u2f.checkRegistration(registrationRequest, registrationResponse)); - }) - .then(function (u2fResult: U2f.RegistrationResult | U2f.Error): BluebirdPromise { - if (objectPath.has(u2fResult, "errorCode")) - return BluebirdPromise.reject(new Error("Error while registering.")); - - const registrationResult: U2f.RegistrationResult = u2fResult as U2f.RegistrationResult; - vars.logger.info(req, "Store registration and reply"); - vars.logger.debug(req, "RegistrationResult = %s", JSON.stringify(registrationResult)); - const registration: U2FRegistration = { - keyHandle: registrationResult.keyHandle, - publicKey: registrationResult.publicKey - }; - return vars.userDataStore.saveU2FRegistration(authSession.userid, appid, registration); - }) - .then(function () { - authSession.identity_check = undefined; - redirect(vars)(req, res); - return BluebirdPromise.resolve(); - }) - .catch(ErrorReplies.replyWithError200(req, res, vars.logger, - UserMessages.OPERATION_FAILED)); - } - return handler; -} diff --git a/server/src/lib/routes/secondfactor/u2f/register_request/get.spec.ts b/server/src/lib/routes/secondfactor/u2f/register_request/get.spec.ts deleted file mode 100644 index 7dd19716b..000000000 --- a/server/src/lib/routes/secondfactor/u2f/register_request/get.spec.ts +++ /dev/null @@ -1,83 +0,0 @@ -import * as Express from "express"; -import sinon = require("sinon"); -import BluebirdPromise = require("bluebird"); -import Assert = require("assert"); -import U2FRegisterRequestGet = require("./get"); -import ExpressMock = require("../../../../stubs/express.spec"); -import { ServerVariablesMockBuilder, ServerVariablesMock } from "../../../../ServerVariablesMockBuilder.spec"; -import { ServerVariables } from "../../../../ServerVariables"; - -describe("routes/secondfactor/u2f/register_request/get", function () { - let req: Express.Request; - let res: ExpressMock.ResponseMock; - let mocks: ServerVariablesMock; - let vars: ServerVariables; - - beforeEach(function () { - req = ExpressMock.RequestMock(); - req.originalUrl = "/api/xxxx"; - req.session = { - ...req.session, - auth: { - userid: "user", - first_factor: true, - second_factor: false, - identity_check: { - challenge: "u2f-register", - userid: "user" - } - } - }; - req.headers = {}; - req.headers.host = "localhost"; - - const s = ServerVariablesMockBuilder.build(); - mocks = s.mocks; - vars = s.variables; - - mocks.userDataStore.saveU2FRegistrationStub.returns(BluebirdPromise.resolve({})); - mocks.userDataStore.retrieveU2FRegistrationStub.returns(BluebirdPromise.resolve({})); - - res = ExpressMock.ResponseMock(); - res.send = sinon.spy(); - res.json = sinon.spy(); - res.status = sinon.spy(); - }); - - describe("test registration request", () => { - it("should send back the registration request and save it in the session", function () { - const expectedRequest = { - test: "abc" - }; - mocks.u2f.requestStub.returns(BluebirdPromise.resolve(expectedRequest)); - return U2FRegisterRequestGet.default(vars)(req as any, res as any) - .then(function () { - Assert.deepEqual(expectedRequest, res.json.getCall(0).args[0]); - }); - }); - - it("should return internal error on registration request", function () { - res.send = sinon.spy(); - mocks.u2f.requestStub.returns(BluebirdPromise.reject("Internal error")); - return U2FRegisterRequestGet.default(vars)(req as any, res as any) - .then(function () { - Assert.equal(res.status.getCall(0).args[0], 200); - Assert.deepEqual(res.send.getCall(0).args[0], { - error: "Operation failed." - }); - }); - }); - - it("should return forbidden if identity has not been verified", function () { - req.session.auth.identity_check = undefined; - return U2FRegisterRequestGet.default(vars)(req as any, res as any) - .then(function () { - Assert.equal(200, res.status.getCall(0).args[0]); - Assert.deepEqual(res.send.getCall(0).args[0], { - error: "Operation failed." - }); - }); - }); - }); -}); - diff --git a/server/src/lib/routes/secondfactor/u2f/register_request/get.ts b/server/src/lib/routes/secondfactor/u2f/register_request/get.ts deleted file mode 100644 index 4c08d57d9..000000000 --- a/server/src/lib/routes/secondfactor/u2f/register_request/get.ts +++ /dev/null @@ -1,41 +0,0 @@ - -import BluebirdPromise = require("bluebird"); -import express = require("express"); -import U2f = require("u2f"); -import ErrorReplies = require("../../../../ErrorReplies"); -import { AuthenticationSessionHandler } from "../../../../AuthenticationSessionHandler"; -import { AuthenticationSession } from "../../../../../../types/AuthenticationSession"; -import UserMessages = require("../../../../UserMessages"); -import { ServerVariables } from "../../../../ServerVariables"; -import GetHeader from "../../../../utils/GetHeader"; -import * as Constants from "../../../../constants"; - -export default function (vars: ServerVariables) { - function handler(req: express.Request, res: express.Response): BluebirdPromise { - let authSession: AuthenticationSession; - const scheme = GetHeader(req, Constants.HEADER_X_FORWARDED_PROTO); - const host = GetHeader(req, Constants.HEADER_X_FORWARDED_HOST); - const appid = scheme + "://" + host; - - return new BluebirdPromise(function (resolve, reject) { - authSession = AuthenticationSessionHandler.get(req, vars.logger); - if (!authSession.identity_check - || authSession.identity_check.challenge != "u2f-register") { - return reject(new Error("Bad challenge.")); - } - - vars.logger.info(req, "Starting registration for appId '%s'", appid); - return resolve(vars.u2f.request(appid)); - }) - .then(function (registrationRequest: U2f.Request) { - vars.logger.debug(req, "RegistrationRequest = %s", JSON.stringify(registrationRequest)); - authSession.register_request = registrationRequest; - res.json(registrationRequest); - return BluebirdPromise.resolve(); - }) - .catch(ErrorReplies.replyWithError200(req, res, vars.logger, - UserMessages.OPERATION_FAILED)); - } - - return handler; -} \ No newline at end of file diff --git a/server/src/lib/routes/secondfactor/u2f/sign/post.spec.ts b/server/src/lib/routes/secondfactor/u2f/sign/post.spec.ts deleted file mode 100644 index a1e8f9a30..000000000 --- a/server/src/lib/routes/secondfactor/u2f/sign/post.spec.ts +++ /dev/null @@ -1,94 +0,0 @@ -import * as Express from "express"; -import sinon = require("sinon"); -import BluebirdPromise = require("bluebird"); -import Assert = require("assert"); -import U2FSignPost = require("./post"); -import { ServerVariables } from "../../../../ServerVariables"; -import UserMessages = require("../../../../UserMessages"); -import { ServerVariablesMockBuilder, ServerVariablesMock } from "../../../../ServerVariablesMockBuilder.spec"; -import ExpressMock = require("../../../../stubs/express.spec"); -import { Level } from "../../../../authentication/Level"; - -describe("routes/secondfactor/u2f/sign/post", function () { - let req: Express.Request; - let res: ExpressMock.ResponseMock; - let mocks: ServerVariablesMock; - let vars: ServerVariables; - - beforeEach(function () { - req = ExpressMock.RequestMock(); - req.originalUrl = "/api/xxxx"; - - const s = ServerVariablesMockBuilder.build(); - mocks = s.mocks; - vars = s.variables; - - req.session = { - ...req.session, - auth: { - userid: "user", - authentication_level: Level.ONE_FACTOR, - identity_check: { - challenge: "u2f-register", - userid: "user" - } - } - }; - req.headers = {}; - req.headers.host = "localhost"; - - res = ExpressMock.ResponseMock(); - res.send = sinon.spy(); - res.json = sinon.spy(); - res.status = sinon.spy(); - }); - - it("should return status code 204", function () { - const expectedStatus = { - keyHandle: "keyHandle", - publicKey: "pbk", - certificate: "cert" - }; - mocks.u2f.checkSignatureStub.returns(expectedStatus); - - mocks.userDataStore.retrieveU2FRegistrationStub.returns(BluebirdPromise.resolve({ - registration: { - publicKey: "PUBKEY" - } - })); - - req.session.auth.sign_request = { - appId: "app", - challenge: "challenge", - keyHandle: "key", - version: "U2F_V2" - }; - return U2FSignPost.default(vars)(req as any, res as any) - .then(function () { - Assert.equal(req.session.auth.authentication_level, Level.TWO_FACTOR); - }); - }); - - it("should return unauthorized error on registration request internal error", function () { - mocks.userDataStore.retrieveU2FRegistrationStub.returns(BluebirdPromise.resolve({ - registration: { - publicKey: "PUBKEY" - } - })); - mocks.u2f.checkSignatureStub.returns({ errorCode: 500 }); - - req.session.auth.sign_request = { - appId: "app", - challenge: "challenge", - keyHandle: "key", - version: "U2F_V2" - }; - return U2FSignPost.default(vars)(req as any, res as any) - .then(function () { - Assert.equal(res.status.getCall(0).args[0], 200); - Assert.deepEqual(res.send.getCall(0).args[0], - { error: UserMessages.OPERATION_FAILED }); - }); - }); -}); - diff --git a/server/src/lib/routes/secondfactor/u2f/sign/post.ts b/server/src/lib/routes/secondfactor/u2f/sign/post.ts deleted file mode 100644 index b307ab8b6..000000000 --- a/server/src/lib/routes/secondfactor/u2f/sign/post.ts +++ /dev/null @@ -1,56 +0,0 @@ -import objectPath = require("object-path"); -import BluebirdPromise = require("bluebird"); -import express = require("express"); -import { U2FRegistrationDocument } from "../../../../storage/U2FRegistrationDocument"; -import U2f = require("u2f"); -import Redirect from "../../redirect"; -import ErrorReplies = require("../../../../ErrorReplies"); -import { ServerVariables } from "../../../../ServerVariables"; -import { AuthenticationSessionHandler } from "../../../../AuthenticationSessionHandler"; -import UserMessages = require("../../../../UserMessages"); -import { AuthenticationSession } from "../../../../../../types/AuthenticationSession"; -import { Level } from "../../../../authentication/Level"; -import GetHeader from "../../../../utils/GetHeader"; -import * as Constants from "../../../../constants"; - -export default function (vars: ServerVariables) { - function handler(req: express.Request, res: express.Response): BluebirdPromise { - let authSession: AuthenticationSession; - const scheme = GetHeader(req, Constants.HEADER_X_FORWARDED_PROTO); - const host = GetHeader(req, Constants.HEADER_X_FORWARDED_HOST); - const appid = scheme + "://" + host; - - return new BluebirdPromise(function (resolve, reject) { - authSession = AuthenticationSessionHandler.get(req, vars.logger); - if (!authSession.sign_request) { - const err = new Error("No sign request"); - ErrorReplies.replyWithError401(req, res, vars.logger)(err); - return reject(err); - } - resolve(); - }) - .then(function () { - const userid = authSession.userid; - return vars.userDataStore.retrieveU2FRegistration(userid, appid); - }) - .then(function (doc: U2FRegistrationDocument): BluebirdPromise { - const signRequest = authSession.sign_request; - const signData: U2f.SignatureData = req.body; - vars.logger.info(req, "Finish authentication"); - return BluebirdPromise.resolve(vars.u2f.checkSignature(signRequest, signData, doc.registration.publicKey)); - }) - .then(function (result: U2f.SignatureResult | U2f.Error): BluebirdPromise { - if (objectPath.has(result, "errorCode")) - return BluebirdPromise.reject(new Error("Error while signing")); - vars.logger.info(req, "Successful authentication"); - authSession.authentication_level = Level.TWO_FACTOR; - Redirect(vars)(req, res); - return BluebirdPromise.resolve(); - }) - .catch(ErrorReplies.replyWithError200(req, res, vars.logger, - UserMessages.OPERATION_FAILED)); - } - - return handler; -} - diff --git a/server/src/lib/routes/secondfactor/u2f/sign_request/get.spec.ts b/server/src/lib/routes/secondfactor/u2f/sign_request/get.spec.ts deleted file mode 100644 index 415feaf59..000000000 --- a/server/src/lib/routes/secondfactor/u2f/sign_request/get.spec.ts +++ /dev/null @@ -1,66 +0,0 @@ -import * as Express from "express"; -import sinon = require("sinon"); -import BluebirdPromise = require("bluebird"); -import assert = require("assert"); -import U2FSignRequestGet = require("./get"); -import ExpressMock = require("../../../../stubs/express.spec"); -import { Request } from "u2f"; -import { ServerVariablesMock, ServerVariablesMockBuilder } from "../../../../ServerVariablesMockBuilder.spec"; -import { ServerVariables } from "../../../../ServerVariables"; - -describe("routes/secondfactor/u2f/sign_request/get", function () { - let req: Express.Request; - let res: ExpressMock.ResponseMock; - let mocks: ServerVariablesMock; - let vars: ServerVariables; - - beforeEach(function () { - req = ExpressMock.RequestMock(); - req.originalUrl = "/api/xxxx"; - req.session = { - ...req.session, - auth: { - userid: "user", - first_factor: true, - second_factor: false, - identity_check: { - challenge: "u2f-register", - userid: "user" - } - } - }; - req.headers = {}; - req.headers.host = "localhost"; - - const s = ServerVariablesMockBuilder.build(); - mocks = s.mocks; - vars = s.variables; - - res = ExpressMock.ResponseMock(); - res.send = sinon.spy(); - res.json = sinon.spy(); - res.status = sinon.spy(); - }); - - it("should send back the sign request and save it in the session", function () { - const expectedRequest: Request = { - version: "U2F_V2", - appId: 'app', - challenge: 'challenge!' - }; - mocks.u2f.requestStub.returns(expectedRequest); - mocks.userDataStore.retrieveU2FRegistrationStub - .returns(BluebirdPromise.resolve({ - registration: { - keyHandle: "KeyHandle" - } - })); - - return U2FSignRequestGet.default(vars)(req as any, res as any) - .then(() => { - assert.deepEqual(expectedRequest, req.session.auth.sign_request); - assert.deepEqual(expectedRequest, res.json.getCall(0).args[0]); - }); - }); -}); - diff --git a/server/src/lib/routes/secondfactor/u2f/sign_request/get.ts b/server/src/lib/routes/secondfactor/u2f/sign_request/get.ts deleted file mode 100644 index 6715e53e7..000000000 --- a/server/src/lib/routes/secondfactor/u2f/sign_request/get.ts +++ /dev/null @@ -1,43 +0,0 @@ -import BluebirdPromise = require("bluebird"); -import express = require("express"); -import { U2FRegistrationDocument } from "../../../../storage/U2FRegistrationDocument"; -import exceptions = require("../../../../Exceptions"); -import ErrorReplies = require("../../../../ErrorReplies"); -import { AuthenticationSessionHandler } from "../../../../AuthenticationSessionHandler"; -import UserMessages = require("../../../../UserMessages"); -import { ServerVariables } from "../../../../ServerVariables"; -import { AuthenticationSession } from "../../../../../../types/AuthenticationSession"; -import GetHeader from "../../../../utils/GetHeader"; -import * as Constants from "../../../../constants"; - -export default function (vars: ServerVariables) { - function handler(req: express.Request, res: express.Response): BluebirdPromise { - let authSession: AuthenticationSession; - const scheme = GetHeader(req, Constants.HEADER_X_FORWARDED_PROTO); - const host = GetHeader(req, Constants.HEADER_X_FORWARDED_HOST); - const appid = scheme + "://" + host; - - return new BluebirdPromise(function (resolve, reject) { - authSession = AuthenticationSessionHandler.get(req, vars.logger); - resolve(); - }) - .then(function () { - return vars.userDataStore.retrieveU2FRegistration(authSession.userid, appid); - }) - .then(function (doc: U2FRegistrationDocument): BluebirdPromise { - if (!doc) - return BluebirdPromise.reject(new exceptions.AccessDeniedError("No U2F registration document found.")); - - vars.logger.info(req, "Start authentication of app '%s'", appid); - vars.logger.debug(req, "AppId = %s, keyHandle = %s", appid, JSON.stringify(doc.registration.keyHandle)); - - const request = vars.u2f.request(appid, doc.registration.keyHandle); - authSession.sign_request = request; - res.json(request); - return BluebirdPromise.resolve(); - }) - .catch(ErrorReplies.replyWithError200(req, res, vars.logger, - UserMessages.OPERATION_FAILED)); - } - return handler; -} diff --git a/server/src/lib/routes/state/get.ts b/server/src/lib/routes/state/get.ts deleted file mode 100644 index 5c3fce6df..000000000 --- a/server/src/lib/routes/state/get.ts +++ /dev/null @@ -1,18 +0,0 @@ -import * as Express from "express"; -import * as Bluebird from "bluebird"; -import { ServerVariables } from "../../ServerVariables"; -import { AuthenticationSessionHandler } from "../../AuthenticationSessionHandler"; - -export default function (vars: ServerVariables) { - return function (req: Express.Request, res: Express.Response): Bluebird { - return new Bluebird(function (resolve, reject) { - const authSession = AuthenticationSessionHandler.get(req, vars.logger); - res.json({ - username: authSession.userid, - authentication_level: authSession.authentication_level, - default_redirection_url: vars.config.default_redirection_url, - }); - resolve(); - }); - }; -} diff --git a/server/src/lib/routes/verify/CheckAuthorizations.spec.ts b/server/src/lib/routes/verify/CheckAuthorizations.spec.ts deleted file mode 100644 index fc94a2c80..000000000 --- a/server/src/lib/routes/verify/CheckAuthorizations.spec.ts +++ /dev/null @@ -1,100 +0,0 @@ -import CheckAuthorizations from "./CheckAuthorizations"; -import AuthorizerStub from "../../authorization/AuthorizerStub.spec"; -import { Level } from "../../authentication/Level"; -import { Level as AuthorizationLevel } from "../../authorization/Level"; -import * as Assert from "assert"; -import { NotAuthenticatedError, NotAuthorizedError } from "../../Exceptions"; - -describe('routes/verify/CheckAuthorizations', function() { - describe('bypass policy', function() { - it('should allow an anonymous user', function() { - const authorizer = new AuthorizerStub(); - authorizer.authorizationMock.returns(AuthorizationLevel.BYPASS); - CheckAuthorizations(authorizer, "public.example.com", "/index.html", undefined, - undefined, "127.0.0.1", Level.NOT_AUTHENTICATED); - }); - - it('should allow an authenticated user (1FA)', function() { - const authorizer = new AuthorizerStub(); - authorizer.authorizationMock.returns(AuthorizationLevel.BYPASS); - CheckAuthorizations(authorizer, "public.example.com", "/index.html", "john", - ["group1", "group2"], "127.0.0.1", Level.ONE_FACTOR); - }); - - it('should allow an authenticated user (2FA)', function() { - const authorizer = new AuthorizerStub(); - authorizer.authorizationMock.returns(AuthorizationLevel.BYPASS); - CheckAuthorizations(authorizer, "public.example.com", "/index.html", "john", - ["group1", "group2"], "127.0.0.1", Level.TWO_FACTOR); - }); - }); - - describe('one_factor policy', function() { - it('should not allow an anonymous user', function() { - const authorizer = new AuthorizerStub(); - authorizer.authorizationMock.returns(AuthorizationLevel.ONE_FACTOR); - Assert.throws(() => { CheckAuthorizations(authorizer, "public.example.com", "/index.html", undefined, - undefined, "127.0.0.1", Level.NOT_AUTHENTICATED) }, NotAuthenticatedError); - }); - - it('should allow an authenticated user (1FA)', function() { - const authorizer = new AuthorizerStub(); - authorizer.authorizationMock.returns(AuthorizationLevel.ONE_FACTOR); - CheckAuthorizations(authorizer, "public.example.com", "/index.html", "john", - ["group1", "group2"], "127.0.0.1", Level.ONE_FACTOR); - }); - - it('should allow an authenticated user (2FA)', function() { - const authorizer = new AuthorizerStub(); - authorizer.authorizationMock.returns(AuthorizationLevel.ONE_FACTOR); - CheckAuthorizations(authorizer, "public.example.com", "/index.html", "john", - ["group1", "group2"], "127.0.0.1", Level.TWO_FACTOR); - }); - }); - - describe('two_factor policy', function() { - it('should not allow an anonymous user', function() { - const authorizer = new AuthorizerStub(); - authorizer.authorizationMock.returns(AuthorizationLevel.TWO_FACTOR); - Assert.throws(() => CheckAuthorizations(authorizer, "public.example.com", "/index.html", undefined, - undefined, "127.0.0.1", Level.NOT_AUTHENTICATED), NotAuthenticatedError); - }); - - it('should not allow an authenticated user (1FA)', function() { - const authorizer = new AuthorizerStub(); - authorizer.authorizationMock.returns(AuthorizationLevel.TWO_FACTOR); - Assert.throws(() => CheckAuthorizations(authorizer, "public.example.com", "/index.html", "john", - ["group1", "group2"], "127.0.0.1", Level.ONE_FACTOR), NotAuthenticatedError); - }); - - it('should allow an authenticated user (2FA)', function() { - const authorizer = new AuthorizerStub(); - authorizer.authorizationMock.returns(AuthorizationLevel.TWO_FACTOR); - CheckAuthorizations(authorizer, "public.example.com", "/index.html", "john", - ["group1", "group2"], "127.0.0.1", Level.TWO_FACTOR); - }); - }); - - describe('deny policy', function() { - it('should not allow an anonymous user', function() { - const authorizer = new AuthorizerStub(); - authorizer.authorizationMock.returns(AuthorizationLevel.DENY); - Assert.throws(() => CheckAuthorizations(authorizer, "public.example.com", "/index.html", undefined, - undefined, "127.0.0.1", Level.NOT_AUTHENTICATED), NotAuthenticatedError); - }); - - it('should not allow an authenticated user (1FA)', function() { - const authorizer = new AuthorizerStub(); - authorizer.authorizationMock.returns(AuthorizationLevel.DENY); - Assert.throws(() => CheckAuthorizations(authorizer, "public.example.com", "/index.html", "john", - ["group1", "group2"], "127.0.0.1", Level.ONE_FACTOR), NotAuthorizedError); - }); - - it('should not allow an authenticated user (2FA)', function() { - const authorizer = new AuthorizerStub(); - authorizer.authorizationMock.returns(AuthorizationLevel.DENY); - Assert.throws(() => CheckAuthorizations(authorizer, "public.example.com", "/index.html", "john", - ["group1", "group2"], "127.0.0.1", Level.TWO_FACTOR), NotAuthorizedError); - }); - }); -}); \ No newline at end of file diff --git a/server/src/lib/routes/verify/CheckAuthorizations.ts b/server/src/lib/routes/verify/CheckAuthorizations.ts deleted file mode 100644 index 5f667f83b..000000000 --- a/server/src/lib/routes/verify/CheckAuthorizations.ts +++ /dev/null @@ -1,45 +0,0 @@ -import * as Util from "util"; - -import Exceptions = require("../../Exceptions"); - -import { Level as AuthorizationLevel } from "../../authorization/Level"; -import { Level as AuthenticationLevel } from "../../authentication/Level"; -import { IAuthorizer } from "../../authorization/IAuthorizer"; - -function isAuthorized( - authorization: AuthorizationLevel, - authentication: AuthenticationLevel): boolean { - - if (authorization == AuthorizationLevel.BYPASS) { - return true; - } else if (authorization == AuthorizationLevel.ONE_FACTOR && - authentication >= AuthenticationLevel.ONE_FACTOR) { - return true; - } else if (authorization == AuthorizationLevel.TWO_FACTOR && - authentication >= AuthenticationLevel.TWO_FACTOR) { - return true; - } - return false; -} - -export default function ( - authorizer: IAuthorizer, - domain: string, resource: string, - user: string, groups: string[], ip: string, - authenticationLevel: AuthenticationLevel): void { - - const authorizationLevel = authorizer - .authorization({domain, resource}, {user, groups}, ip); - - if (authorizationLevel == AuthorizationLevel.BYPASS) { - return; - } - else if (user && authorizationLevel == AuthorizationLevel.DENY) { - throw new Exceptions.NotAuthorizedError( - Util.format("User %s is not authorized to access %s%s", (user) ? user : "unknown", domain, resource)); - } - else if (!isAuthorized(authorizationLevel, authenticationLevel)) { - throw new Exceptions.NotAuthenticatedError(Util.format( - "User '%s' is not sufficiently authorized to access %s%s.", (user) ? user : "unknown", domain, resource)); - } -} \ No newline at end of file diff --git a/server/src/lib/routes/verify/CheckInactivity.spec.ts b/server/src/lib/routes/verify/CheckInactivity.spec.ts deleted file mode 100644 index 85c2b2c08..000000000 --- a/server/src/lib/routes/verify/CheckInactivity.spec.ts +++ /dev/null @@ -1,68 +0,0 @@ -import * as Express from "express"; -import * as ExpressMock from "../../stubs/express.spec"; -import * as Sinon from "sinon"; -import * as Assert from "assert"; -import CheckInactivity from "./CheckInactivity"; -import { AuthenticationSession } from "../../../../types/AuthenticationSession"; -import { Configuration } from "../../configuration/schema/Configuration"; -import { RequestLoggerStub } from "../../logging/RequestLoggerStub.spec"; -import { Level } from "../../authentication/Level"; - - -describe('routes/verify/VerifyInactivity', function() { - let req: Express.Request; - let authSession: AuthenticationSession; - let configuration: Configuration; - let logger: RequestLoggerStub; - - beforeEach(function() { - req = ExpressMock.RequestMock(); - authSession = { - authentication_level: Level.TWO_FACTOR, - } as any; - configuration = { - session: { - domain: 'example.com', - secret: 'abc', - inactivity: 1000, - }, - authentication_backend: { - file: { - path: 'abc' - } - } - } - logger = new RequestLoggerStub(); - }); - - it('should not throw if user is not authenticated', function() { - authSession.authentication_level = Level.NOT_AUTHENTICATED; - CheckInactivity(req, authSession, configuration, logger); - }); - - it('should not throw if inactivity timeout is disabled', function() { - delete configuration.session.inactivity; - CheckInactivity(req, authSession, configuration, logger); - }); - - it('should not throw if keep me logged in has been checked', function() { - authSession.keep_me_logged_in = true; - CheckInactivity(req, authSession, configuration, logger); - }); - - it('should not throw if the inactivity timeout has not timed out', function() { - this.clock = Sinon.useFakeTimers(); - authSession.last_activity_datetime = new Date().getTime(); - this.clock.tick(200); - CheckInactivity(req, authSession, configuration, logger); - this.clock.restore(); - }); - - it('should throw if the inactivity timeout has timed out', function() { - this.clock = Sinon.useFakeTimers(); - authSession.last_activity_datetime = new Date().getTime(); - this.clock.tick(2000); - Assert.throws(() => CheckInactivity(req, authSession, configuration, logger)); - this.clock.restore(); - }); -}); \ No newline at end of file diff --git a/server/src/lib/routes/verify/CheckInactivity.ts b/server/src/lib/routes/verify/CheckInactivity.ts deleted file mode 100644 index 4e0b2444c..000000000 --- a/server/src/lib/routes/verify/CheckInactivity.ts +++ /dev/null @@ -1,37 +0,0 @@ -import * as Express from "express"; -import { AuthenticationSession } from "AuthenticationSession"; -import { Configuration } from "../../configuration/schema/Configuration"; -import { IRequestLogger } from "../../logging/IRequestLogger"; -import { AuthenticationSessionHandler } from "../../AuthenticationSessionHandler"; -import { Level } from "../../authentication/Level"; - -export default function(req: Express.Request, - authSession: AuthenticationSession, - configuration: Configuration, logger: IRequestLogger): void { - - // If the user is not authenticated, we don't check inactivity. - if (authSession.authentication_level == Level.NOT_AUTHENTICATED) { - return; - } - - // If inactivity is not specified, then inactivity timeout does not apply - if (!configuration.session.inactivity || authSession.keep_me_logged_in) { - return; - } - - const lastActivityTime = authSession.last_activity_datetime; - const currentTime = new Date().getTime(); - authSession.last_activity_datetime = currentTime; - - const inactivityPeriodMs = currentTime - lastActivityTime; - logger.debug(req, "Inactivity period was %s sec and max period was %s sec.", - inactivityPeriodMs / 1000, configuration.session.inactivity / 1000); - - if (inactivityPeriodMs < configuration.session.inactivity) { - return; - } - - logger.debug(req, "Session has been reset after too long inactivity period."); - AuthenticationSessionHandler.reset(req); - throw new Error("Inactivity period exceeded."); -} diff --git a/server/src/lib/routes/verify/Get.spec.ts b/server/src/lib/routes/verify/Get.spec.ts deleted file mode 100644 index 2ac5267f7..000000000 --- a/server/src/lib/routes/verify/Get.spec.ts +++ /dev/null @@ -1,96 +0,0 @@ - -import * as Assert from "assert"; -import * as Express from "express"; -import { AuthenticationSessionHandler } from "../../AuthenticationSessionHandler"; -import { AuthenticationSession } from "../../../../types/AuthenticationSession"; -import ExpressMock = require("../../stubs/express.spec"); -import { ServerVariables } from "../../ServerVariables"; -import { ServerVariablesMockBuilder, ServerVariablesMock } from "../../ServerVariablesMockBuilder.spec"; -import { HEADER_X_ORIGINAL_URL } from "../../constants"; -import Get from "./Get"; -import { ImportMock } from 'ts-mock-imports'; -import * as GetBasicAuth from "./GetBasicAuth"; -import * as GetSessionCookie from "./GetSessionCookie"; -import { NotAuthorizedError, NotAuthenticatedError } from "../../Exceptions"; - - -describe("routes/verify/get", function () { - let req: Express.Request; - let res: ExpressMock.ResponseMock; - let mocks: ServerVariablesMock; - let vars: ServerVariables; - let authSession: AuthenticationSession; - - beforeEach(function () { - req = ExpressMock.RequestMock(); - res = ExpressMock.ResponseMock(); - req.query = { - redirect: "undefined" - }; - AuthenticationSessionHandler.reset(req as any); - req.headers[HEADER_X_ORIGINAL_URL] = "https://secret.example.com/"; - const s = ServerVariablesMockBuilder.build(false); - mocks = s.mocks; - vars = s.variables; - authSession = AuthenticationSessionHandler.get(req as any, vars.logger); - }); - - describe("with basic auth", function () { - it('should allow access to user', async function() { - req.headers['proxy-authorization'] = 'zglfzeljfzelmkj'; - const mock = ImportMock.mockOther(GetBasicAuth, "default", () => Promise.resolve()); - await Get(vars)(req, res as any); - Assert(res.send.calledWithExactly()); - Assert(res.status.calledWithExactly(204)) - mock.restore(); - }); - }); - - describe("with session cookie", function () { - it('should allow access to user', async function() { - const mock = ImportMock.mockOther(GetSessionCookie, "default", () => Promise.resolve()); - await Get(vars)(req, res as any); - Assert(res.send.calledWithExactly()); - Assert(res.status.calledWithExactly(204)) - mock.restore(); - }); - }); - - describe('Deny access', function() { - it('should deny access to user on NotAuthorizedError', async function() { - req.headers['proxy-authorization'] = 'zglfzeljfzelmkj'; - const mock = ImportMock.mockOther(GetBasicAuth, "default", () => Promise.reject(new NotAuthorizedError('No!'))); - await Get(vars)(req, res as any); - Assert(res.status.calledWith(403)); - mock.restore(); - }); - - it('should deny access to user on NotAuthenticatedError', async function() { - req.headers['proxy-authorization'] = 'zglfzeljfzelmkj'; - const mock = ImportMock.mockOther(GetBasicAuth, "default", () => Promise.reject(new NotAuthenticatedError('No!'))); - await Get(vars)(req, res as any); - Assert(res.status.calledWith(401)); - mock.restore(); - }); - - it('should deny access to user on any exception', async function() { - req.headers['proxy-authorization'] = 'zglfzeljfzelmkj'; - const mock = ImportMock.mockOther(GetBasicAuth, "default", () => Promise.reject(new Error('No!'))); - await Get(vars)(req, res as any); - Assert(res.status.calledWith(401)); - mock.restore(); - }); - }) - - describe('Kubernetes ingress controller', function() { - it('should redirect user to login portal', async function() { - req.headers['proxy-authorization'] = 'zglfzeljfzelmkj'; - req.query.rd = 'https://login.example.com/'; - const mock = ImportMock.mockOther(GetBasicAuth, "default", () => Promise.reject(new NotAuthenticatedError('No!'))); - await Get(vars)(req, res as any); - Assert(res.redirect.calledWith('https://login.example.com/?rd=https://secret.example.com/')); - mock.restore(); - }); - }); -}); - diff --git a/server/src/lib/routes/verify/Get.ts b/server/src/lib/routes/verify/Get.ts deleted file mode 100644 index 291b447e3..000000000 --- a/server/src/lib/routes/verify/Get.ts +++ /dev/null @@ -1,72 +0,0 @@ -import Express = require("express"); -import Exceptions = require("../../Exceptions"); -import ErrorReplies = require("../../ErrorReplies"); -import { ServerVariables } from "../../ServerVariables"; -import GetSessionCookie from "./GetSessionCookie"; -import GetBasicAuth from "./GetBasicAuth"; -import Constants = require("../../constants"); -import { AuthenticationSessionHandler } - from "../../AuthenticationSessionHandler"; -import { AuthenticationSession } - from "../../../../types/AuthenticationSession"; -import HasHeader from "../..//utils/HasHeader"; -import RequestUrlGetter from "../../utils/RequestUrlGetter"; - - -async function verifyWithSelectedMethod(req: Express.Request, res: Express.Response, - vars: ServerVariables, authSession: AuthenticationSession | undefined) - : Promise { - if (HasHeader(req, Constants.HEADER_PROXY_AUTHORIZATION)) { - vars.logger.debug(req, "Got PROXY_AUTHORIZATION header checking basic auth"); - await GetBasicAuth(req, res, vars); - } else { - vars.logger.debug(req, "Checking session cookie"); - await GetSessionCookie(req, res, vars, authSession); - } -} - -function getRedirectParam(req: Express.Request) { - return req.query[Constants.REDIRECT_QUERY_PARAM] != "undefined" - ? req.query[Constants.REDIRECT_QUERY_PARAM] - : undefined; -} - -async function unsafeGet(vars: ServerVariables, req: Express.Request, res: Express.Response) { - const authSession = AuthenticationSessionHandler.get(req, vars.logger); - try { - await verifyWithSelectedMethod(req, res, vars, authSession); - res.status(204); - res.send(); - } catch (err) { - // Kubernetes ingress controller and Traefik use the rd parameter of the verify - // endpoint to provide the URL of the login portal. The target URL of the user - // is computed from X-Fowarded-* headers or X-Original-Url. - let redirectUrl = getRedirectParam(req); - const originalUrl = RequestUrlGetter.getOriginalUrl(req); - if (redirectUrl && originalUrl) { - redirectUrl = redirectUrl + `?${Constants.REDIRECT_QUERY_PARAM}=` + originalUrl; - ErrorReplies.redirectTo(redirectUrl, req, res, vars.logger)(err); - return; - } - - // Reply with an error. - vars.logger.error(req, "Got an error state when processing verify. Error was: %s", err.toString()); - throw err; - } -} - -export default function (vars: ServerVariables) { - return async function (req: Express.Request, res: Express.Response) - : Promise { - try { - await unsafeGet(vars, req, res); - } catch (err) { - if (err instanceof Exceptions.NotAuthorizedError) { - ErrorReplies.replyWithError403(req, res, vars.logger)(err); - } else { - ErrorReplies.replyWithError401(req, res, vars.logger)(err); - } - } - }; -} - diff --git a/server/src/lib/routes/verify/GetBasicAuth.spec.ts b/server/src/lib/routes/verify/GetBasicAuth.spec.ts deleted file mode 100644 index ed09010d4..000000000 --- a/server/src/lib/routes/verify/GetBasicAuth.spec.ts +++ /dev/null @@ -1,65 +0,0 @@ -import * as Express from "express"; -import { ServerVariables } from "../../ServerVariables"; -import * as ExpressMock from "../../stubs/express.spec"; -import { ServerVariablesMockBuilder, ServerVariablesMock } from "../../ServerVariablesMockBuilder.spec"; -import { HEADER_X_ORIGINAL_URL } from "../../constants"; -import { Level } from "../../authorization/Level"; -import GetBasicAuthModule from "./GetBasicAuth"; -import * as CheckAuthorizations from "./CheckAuthorizations"; -import { ImportMock } from 'ts-mock-imports'; -import AssertRejects from "../../utils/AssertRejects"; - -describe('routes/verify/GetBasicAuth', function() { - let req: Express.Request; - let res: ExpressMock.ResponseMock; - let vars: ServerVariables; - let mocks: ServerVariablesMock; - - beforeEach(function() { - req = ExpressMock.RequestMock(); - res = ExpressMock.ResponseMock(); - req.headers[HEADER_X_ORIGINAL_URL] = 'https://secure.example.com'; - const sv = ServerVariablesMockBuilder.build(); - vars = sv.variables; - mocks = sv.mocks; - }) - - it('should fail on invalid format of token', async function() { - req.headers['proxy-authorization'] = 'Basic abc'; - AssertRejects(async () => GetBasicAuthModule(req, res as any, vars)); - }); - - it('should fail decoded token is not of form user:pass', function() { - req.headers['proxy-authorization'] = 'Basic aGVsbG93b3JsZAo='; - AssertRejects(async () => GetBasicAuthModule(req, res as any, vars)); - }); - - it('should fail when credentials are wrong', function() { - req.headers['proxy-authorization'] = 'Basic aGVsbG8xOndvcmxkCg=='; - mocks.usersDatabase.checkUserPasswordStub.rejects(new Error('Bad credentials')); - AssertRejects(async () => await GetBasicAuthModule(req, res as any, vars)); - }); - - it('should fail when authorizations are not sufficient', function() { - req.headers['proxy-authorization'] = 'Basic aGVsbG8xOndvcmxkCg=='; - const mock = ImportMock.mockOther(CheckAuthorizations, 'default', () => { throw new Error('Not enough permissions.')}); - mocks.usersDatabase.checkUserPasswordStub.resolves({ - email: 'john@example.com', - groups: ['group1', 'group2'], - }); - AssertRejects(async () => await GetBasicAuthModule(req, res as any, vars)); - mock.restore(); - }); - - it('should succeed when user is authenticated and authorizations are sufficient', async function() { - req.headers['proxy-authorization'] = 'Basic aGVsbG8xOndvcmxkCg=='; - const mock = ImportMock.mockOther(CheckAuthorizations, 'default', () => Level.TWO_FACTOR); - mocks.usersDatabase.checkUserPasswordStub.resolves({ - email: 'john@example.com', - groups: ['group1', 'group2'], - }); - await GetBasicAuthModule(req, res as any, vars); - mock.restore(); - }); - -}) \ No newline at end of file diff --git a/server/src/lib/routes/verify/GetBasicAuth.ts b/server/src/lib/routes/verify/GetBasicAuth.ts deleted file mode 100644 index 269118956..000000000 --- a/server/src/lib/routes/verify/GetBasicAuth.ts +++ /dev/null @@ -1,47 +0,0 @@ -import Express = require("express"); -import { ServerVariables } from "../../ServerVariables"; -import { URLDecomposer } from "../../utils/URLDecomposer"; -import { Level } from "../../authentication/Level"; -import GetHeader from "../../utils/GetHeader"; -import { HEADER_PROXY_AUTHORIZATION } from "../../constants"; -import setUserAndGroupsHeaders from "./SetUserAndGroupsHeaders"; -import CheckAuthorizations from "./CheckAuthorizations"; -import RequestUrlGetter from "../../utils/RequestUrlGetter"; - -export default async function(req: Express.Request, res: Express.Response, - vars: ServerVariables) - : Promise { - const authorizationValue = GetHeader(req, HEADER_PROXY_AUTHORIZATION); - - if (!authorizationValue.startsWith("Basic ")) { - throw new Error("The authorization header should be of the form 'Basic XXXXXX'"); - } - - const base64Re = new RegExp("^Basic ((?:[A-Za-z0-9+/]{4})*" + - "(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?)$"); - const isTokenValidBase64 = base64Re.test(authorizationValue); - - if (!isTokenValidBase64) { - throw new Error("No valid base64 token found in the header"); - } - - const tokenMatches = authorizationValue.match(base64Re); - const base64Token = tokenMatches[1]; - const decodedToken = Buffer.from(base64Token, "base64").toString(); - const splittedToken = decodedToken.split(":"); - - if (splittedToken.length != 2) { - throw new Error("The authorization token is invalid. Expecting 'userid:password'"); - } - - const username = splittedToken[0]; - const password = splittedToken[1]; - const groupsAndEmails = await vars.usersDatabase.checkUserPassword(username, password); - - const uri = RequestUrlGetter.getOriginalUrl(req); - const urlDecomposition = URLDecomposer.fromUrl(uri); - - CheckAuthorizations(vars.authorizer, urlDecomposition.domain, urlDecomposition.path, - username, groupsAndEmails.groups, req.ip, Level.ONE_FACTOR); - setUserAndGroupsHeaders(res, username, groupsAndEmails.groups); -} diff --git a/server/src/lib/routes/verify/GetSessionCookie.spec.ts b/server/src/lib/routes/verify/GetSessionCookie.spec.ts deleted file mode 100644 index 374e836c5..000000000 --- a/server/src/lib/routes/verify/GetSessionCookie.spec.ts +++ /dev/null @@ -1,57 +0,0 @@ -import * as Express from "express"; -import * as ExpressMock from "../../stubs/express.spec"; -import { ImportMock } from 'ts-mock-imports'; -import * as CheckAuthorizations from "./CheckAuthorizations"; -import * as CheckInactivity from "./CheckInactivity"; -import GetSessionCookie from "./GetSessionCookie"; -import { ServerVariables } from "../../ServerVariables"; -import { ServerVariablesMockBuilder } from "../../ServerVariablesMockBuilder.spec"; -import { AuthenticationSession } from "../../../../types/AuthenticationSession"; -import AssertRejects from "../../utils/AssertRejects"; -import { Level } from "../../authorization/Level"; - - -describe('routes/verify/GetSessionCookie', function() { - let req: Express.Request; - let res: ExpressMock.ResponseMock; - let vars: ServerVariables; - let authSession: AuthenticationSession; - - beforeEach(function() { - req = ExpressMock.RequestMock(); - res = ExpressMock.ResponseMock(); - const sv = ServerVariablesMockBuilder.build(); - vars = sv.variables; - authSession = {} as any; - }); - - it("should fail when target url is not provided", async function() { - AssertRejects(async () => await GetSessionCookie(req, res as any, vars, authSession)); - }); - - it("should not let unauthorized users in", async function() { - req.originalUrl = "https://public.example.com"; - const mock = ImportMock.mockOther(CheckAuthorizations, "default", () => { throw new Error('Not authorized')}); - AssertRejects(async () => await GetSessionCookie(req, res as any, vars, authSession)); - mock.restore(); - }); - - it("should not let authorize user after a long period of inactivity", async function() { - req.originalUrl = "https://public.example.com"; - const checkAuthorizationsMock = ImportMock.mockOther(CheckAuthorizations, "default", () => Level.ONE_FACTOR); - const checkInactivityMock = ImportMock.mockOther(CheckInactivity, "default", () => { throw new Error('Timed out')}); - AssertRejects(async () => await GetSessionCookie(req, res as any, vars, authSession)); - checkInactivityMock.restore(); - checkAuthorizationsMock.restore(); - }); - - it("should let the user in", async function() { - req.headers['x-original-url'] = "https://public.example.com"; - - const checkAuthorizationsMock = ImportMock.mockOther(CheckAuthorizations, "default", () => Level.ONE_FACTOR); - const checkInactivityMock = ImportMock.mockOther(CheckInactivity, "default", () => {}); - await GetSessionCookie(req, res as any, vars, authSession); - checkInactivityMock.restore(); - checkAuthorizationsMock.restore(); - }); -}); \ No newline at end of file diff --git a/server/src/lib/routes/verify/GetSessionCookie.ts b/server/src/lib/routes/verify/GetSessionCookie.ts deleted file mode 100644 index 98a794e9a..000000000 --- a/server/src/lib/routes/verify/GetSessionCookie.ts +++ /dev/null @@ -1,37 +0,0 @@ -import Express = require("express"); -import { ServerVariables } from "../../ServerVariables"; -import { AuthenticationSession } - from "../../../../types/AuthenticationSession"; -import setUserAndGroupsHeaders from "./SetUserAndGroupsHeaders"; -import CheckAuthorizations from "./CheckAuthorizations"; -import CheckInactivity from "./CheckInactivity"; -import RequestUrlGetter from "../../utils/RequestUrlGetter"; -import * as URLParse from "url-parse"; - - -export default async function (req: Express.Request, res: Express.Response, - vars: ServerVariables, authSession: AuthenticationSession | undefined) - : Promise { - if (!authSession) { - throw new Error("No cookie detected."); - } - - const originalUrl = RequestUrlGetter.getOriginalUrl(req); - - if (!originalUrl) { - throw new Error("Cannot detect the original URL from headers."); - } - - const url = new URLParse(originalUrl); - const username = authSession.userid; - const groups = authSession.groups; - - vars.logger.debug(req, "domain=%s, path=%s, user=%s, groups=%s, ip=%s", url.hostname, - url.pathname, (username) ? username : "unknown", - (groups instanceof Array && groups.length > 0) ? groups.join(",") : "unknown", req.ip); - - CheckAuthorizations(vars.authorizer, url.hostname, url.pathname, username, groups, - req.ip, authSession.authentication_level); - CheckInactivity(req, authSession, vars.config, vars.logger); - setUserAndGroupsHeaders(res, username, groups); -} diff --git a/server/src/lib/routes/verify/SetUserAndGroupsHeaders.spec.ts b/server/src/lib/routes/verify/SetUserAndGroupsHeaders.spec.ts deleted file mode 100644 index 6eadf88d0..000000000 --- a/server/src/lib/routes/verify/SetUserAndGroupsHeaders.spec.ts +++ /dev/null @@ -1,13 +0,0 @@ -import * as ExpressMock from "../../stubs/express.spec"; -import * as Assert from "assert"; -import { HEADER_REMOTE_USER, HEADER_REMOTE_GROUPS } from "../../constants"; -import SetUserAndGroupsHeaders from "./SetUserAndGroupsHeaders"; - -describe("routes/verify/SetUserAndGroupsHeaders", function() { - it('should set the correct headers', function() { - const res = ExpressMock.ResponseMock(); - SetUserAndGroupsHeaders(res as any, "john", ["group1", "group2"]); - Assert(res.setHeader.calledWith(HEADER_REMOTE_USER, "john")); - Assert(res.setHeader.calledWith(HEADER_REMOTE_GROUPS, "group1,group2")); - }) -}) \ No newline at end of file diff --git a/server/src/lib/routes/verify/SetUserAndGroupsHeaders.ts b/server/src/lib/routes/verify/SetUserAndGroupsHeaders.ts deleted file mode 100644 index dce59be19..000000000 --- a/server/src/lib/routes/verify/SetUserAndGroupsHeaders.ts +++ /dev/null @@ -1,7 +0,0 @@ -import * as Express from "express"; -import { HEADER_REMOTE_USER, HEADER_REMOTE_GROUPS } from "../../constants"; - -export default function(res: Express.Response, username: string | undefined, groups: string[] | undefined) { - if (username) res.setHeader(HEADER_REMOTE_USER, username); - if (groups instanceof Array) res.setHeader(HEADER_REMOTE_GROUPS, groups.join(",")); -} \ No newline at end of file diff --git a/server/src/lib/storage/AuthenticationTraceDocument.d.ts b/server/src/lib/storage/AuthenticationTraceDocument.d.ts deleted file mode 100644 index 69818c055..000000000 --- a/server/src/lib/storage/AuthenticationTraceDocument.d.ts +++ /dev/null @@ -1,6 +0,0 @@ - -export interface AuthenticationTraceDocument { - userId: string; - date: Date; - isAuthenticationSuccessful: boolean; -} \ No newline at end of file diff --git a/server/src/lib/storage/CollectionFactoryFactory.ts b/server/src/lib/storage/CollectionFactoryFactory.ts deleted file mode 100644 index 92b29abfa..000000000 --- a/server/src/lib/storage/CollectionFactoryFactory.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { ICollectionFactory } from "./ICollectionFactory"; -import { NedbCollectionFactory } from "./nedb/NedbCollectionFactory"; -import { MongoCollectionFactory } from "./mongo/MongoCollectionFactory"; -import { IMongoClient } from "../connectors/mongo/IMongoClient"; - - -export class CollectionFactoryFactory { - static createNedb(options: Nedb.DataStoreOptions): ICollectionFactory { - return new NedbCollectionFactory(options); - } - - static createMongo(client: IMongoClient): ICollectionFactory { - return new MongoCollectionFactory(client); - } -} \ No newline at end of file diff --git a/server/src/lib/storage/CollectionFactoryStub.spec.ts b/server/src/lib/storage/CollectionFactoryStub.spec.ts deleted file mode 100644 index 34dc40ecb..000000000 --- a/server/src/lib/storage/CollectionFactoryStub.spec.ts +++ /dev/null @@ -1,15 +0,0 @@ -import Sinon = require("sinon"); -import { ICollection } from "./ICollection"; -import { ICollectionFactory } from "./ICollectionFactory"; - -export class CollectionFactoryStub implements ICollectionFactory { - buildStub: Sinon.SinonStub; - - constructor() { - this.buildStub = Sinon.stub(); - } - - build(collectionName: string): ICollection { - return this.buildStub(collectionName); - } -} diff --git a/server/src/lib/storage/CollectionStub.spec.ts b/server/src/lib/storage/CollectionStub.spec.ts deleted file mode 100644 index 42895d672..000000000 --- a/server/src/lib/storage/CollectionStub.spec.ts +++ /dev/null @@ -1,39 +0,0 @@ -import BluebirdPromise = require("bluebird"); -import Sinon = require("sinon"); -import { ICollection } from "./ICollection"; - -export class CollectionStub implements ICollection { - findStub: Sinon.SinonStub; - findOneStub: Sinon.SinonStub; - updateStub: Sinon.SinonStub; - removeStub: Sinon.SinonStub; - insertStub: Sinon.SinonStub; - - constructor() { - this.findStub = Sinon.stub(); - this.findOneStub = Sinon.stub(); - this.updateStub = Sinon.stub(); - this.removeStub = Sinon.stub(); - this.insertStub = Sinon.stub(); - } - - find(filter: any, sortKeys: any, count: number): BluebirdPromise { - return this.findStub(filter, sortKeys, count); - } - - findOne(filter: any): BluebirdPromise { - return this.findOneStub(filter); - } - - update(filter: any, document: any, options: any): BluebirdPromise { - return this.updateStub(filter, document, options); - } - - remove(filter: any): BluebirdPromise { - return this.removeStub(filter); - } - - insert(document: any): BluebirdPromise { - return this.insertStub(document); - } -} diff --git a/server/src/lib/storage/ICollection.d.ts b/server/src/lib/storage/ICollection.d.ts deleted file mode 100644 index caa6c2a87..000000000 --- a/server/src/lib/storage/ICollection.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* istanbul ignore next */ -import BluebirdPromise = require("bluebird"); - -/* istanbul ignore next */ -export interface ICollection { - find(query: any, sortKeys: any, count: number): BluebirdPromise; - findOne(query: any): BluebirdPromise; - update(query: any, updateQuery: any, options?: any): BluebirdPromise; - remove(query: any): BluebirdPromise; - insert(document: any): BluebirdPromise; -} \ No newline at end of file diff --git a/server/src/lib/storage/ICollectionFactory.d.ts b/server/src/lib/storage/ICollectionFactory.d.ts deleted file mode 100644 index 39eb42c77..000000000 --- a/server/src/lib/storage/ICollectionFactory.d.ts +++ /dev/null @@ -1,6 +0,0 @@ - -import { ICollection } from "./ICollection"; - -export interface ICollectionFactory { - build(collectionName: string): ICollection; -} \ No newline at end of file diff --git a/server/src/lib/storage/IUserDataStore.d.ts b/server/src/lib/storage/IUserDataStore.d.ts deleted file mode 100644 index 74f2fe9ab..000000000 --- a/server/src/lib/storage/IUserDataStore.d.ts +++ /dev/null @@ -1,25 +0,0 @@ -import BluebirdPromise = require("bluebird"); -import { TOTPSecretDocument } from "./TOTPSecretDocument"; -import { U2FRegistrationDocument } from "./U2FRegistrationDocument"; -import { U2FRegistration } from "../../../types/U2FRegistration"; -import { TOTPSecret } from "../../../types/TOTPSecret"; -import { AuthenticationTraceDocument } from "./AuthenticationTraceDocument"; -import { IdentityValidationDocument } from "./IdentityValidationDocument"; -import Method2FA from "../Method2FA"; - -export interface IUserDataStore { - saveU2FRegistration(userId: string, appId: string, registration: U2FRegistration): BluebirdPromise; - retrieveU2FRegistration(userId: string, appId: string): BluebirdPromise; - - saveAuthenticationTrace(userId: string, isAuthenticationSuccessful: boolean): BluebirdPromise; - retrieveLatestAuthenticationTraces(userId: string, count: number): BluebirdPromise; - - produceIdentityValidationToken(userId: string, token: string, challenge: string, maxAge: number): BluebirdPromise; - consumeIdentityValidationToken(token: string, challenge: string): BluebirdPromise; - - saveTOTPSecret(userId: string, secret: TOTPSecret): BluebirdPromise; - retrieveTOTPSecret(userId: string): BluebirdPromise; - - savePrefered2FAMethod(userId: string, method: Method2FA): BluebirdPromise; - retrievePrefered2FAMethod(userId: string): BluebirdPromise; -} \ No newline at end of file diff --git a/server/src/lib/storage/IdentityValidationDocument.d.ts b/server/src/lib/storage/IdentityValidationDocument.d.ts deleted file mode 100644 index e7fd7b3f4..000000000 --- a/server/src/lib/storage/IdentityValidationDocument.d.ts +++ /dev/null @@ -1,7 +0,0 @@ - -export interface IdentityValidationDocument { - userId: string; - token: string; - challenge: string; - maxDate: Date; -} \ No newline at end of file diff --git a/server/src/lib/storage/TOTPSecretDocument.d.ts b/server/src/lib/storage/TOTPSecretDocument.d.ts deleted file mode 100644 index a6c0bf9e6..000000000 --- a/server/src/lib/storage/TOTPSecretDocument.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { TOTPSecret } from "../../../types/TOTPSecret"; - -export interface TOTPSecretDocument { - userid: string; - secret: TOTPSecret; -} \ No newline at end of file diff --git a/server/src/lib/storage/U2FRegistrationDocument.d.ts b/server/src/lib/storage/U2FRegistrationDocument.d.ts deleted file mode 100644 index efec6cb1d..000000000 --- a/server/src/lib/storage/U2FRegistrationDocument.d.ts +++ /dev/null @@ -1,8 +0,0 @@ - -import { U2FRegistration } from "../../../types/U2FRegistration"; - -export interface U2FRegistrationDocument { - userId: string; - appId: string; - registration: U2FRegistration; -} \ No newline at end of file diff --git a/server/src/lib/storage/UserDataStore.spec.ts b/server/src/lib/storage/UserDataStore.spec.ts deleted file mode 100644 index 7c2f4be6d..000000000 --- a/server/src/lib/storage/UserDataStore.spec.ts +++ /dev/null @@ -1,289 +0,0 @@ - -import * as Assert from "assert"; -import * as Sinon from "sinon"; -import * as MockDate from "mockdate"; -import BluebirdPromise = require("bluebird"); - -import { UserDataStore } from "./UserDataStore"; -import { TOTPSecret } from "../../../types/TOTPSecret"; -import { U2FRegistration } from "../../../types/U2FRegistration"; -import { AuthenticationTraceDocument } from "./AuthenticationTraceDocument"; -import { CollectionStub } from "./CollectionStub.spec"; -import { CollectionFactoryStub } from "./CollectionFactoryStub.spec"; - -describe("storage/UserDataStore", function () { - let factory: CollectionFactoryStub; - let collection: CollectionStub; - let userId: string; - let appId: string; - let totpSecret: TOTPSecret; - let u2fRegistration: U2FRegistration; - - beforeEach(function () { - factory = new CollectionFactoryStub(); - collection = new CollectionStub(); - - userId = "user"; - appId = "https://myappId"; - - totpSecret = { - ascii: "abc", - base32: "ABCDKZLEFZGREJK", - otpauth_url: "totp://test", - google_auth_qr: "dummy", - hex: "dummy", - qr_code_ascii: "dummy", - qr_code_base32: "dummy", - qr_code_hex: "dummy" - }; - - u2fRegistration = { - keyHandle: "KEY_HANDLE", - publicKey: "publickey" - }; - }); - - it("should correctly creates collections", function () { - new UserDataStore(factory); - - Assert.equal(5, factory.buildStub.callCount); - Assert(factory.buildStub.calledWith("authentication_traces")); - Assert(factory.buildStub.calledWith("identity_validation_tokens")); - Assert(factory.buildStub.calledWith("u2f_registrations")); - Assert(factory.buildStub.calledWith("totp_secrets")); - Assert(factory.buildStub.calledWith("prefered_2fa_method")); - }); - - describe("TOTP secrets collection", function () { - it("should save a totp secret", function () { - factory.buildStub.returns(collection); - collection.updateStub.returns(BluebirdPromise.resolve()); - - const dataStore = new UserDataStore(factory); - - return dataStore.saveTOTPSecret(userId, totpSecret) - .then(function (doc) { - Assert(collection.updateStub.calledOnce); - Assert(collection.updateStub.calledWith({ userId: userId }, { - userId: userId, - secret: totpSecret - }, { upsert: true })); - return BluebirdPromise.resolve(); - }); - }); - - it("should retrieve a totp secret", function () { - factory.buildStub.returns(collection); - collection.findOneStub.withArgs().returns(BluebirdPromise.resolve()); - - const dataStore = new UserDataStore(factory); - - return dataStore.retrieveTOTPSecret(userId) - .then(function (doc) { - Assert(collection.findOneStub.calledOnce); - Assert(collection.findOneStub.calledWith({ userId: userId })); - return BluebirdPromise.resolve(); - }); - }); - }); - - describe("U2F secrets collection", function () { - it("should save a U2F secret", function () { - factory.buildStub.returns(collection); - collection.updateStub.returns(BluebirdPromise.resolve()); - - const dataStore = new UserDataStore(factory); - - return dataStore.saveU2FRegistration(userId, appId, u2fRegistration) - .then(function (doc) { - Assert(collection.updateStub.calledOnce); - Assert(collection.updateStub.calledWith({ - userId: userId, - appId: appId - }, { - userId: userId, - appId: appId, - registration: u2fRegistration - }, { upsert: true })); - return BluebirdPromise.resolve(); - }); - }); - - it("should retrieve a U2F secret", function () { - factory.buildStub.returns(collection); - collection.findOneStub.withArgs().returns(BluebirdPromise.resolve()); - - const dataStore = new UserDataStore(factory); - - return dataStore.retrieveU2FRegistration(userId, appId) - .then(function (doc) { - Assert(collection.findOneStub.calledOnce); - Assert(collection.findOneStub.calledWith({ - userId: userId, - appId: appId - })); - return BluebirdPromise.resolve(); - }); - }); - }); - - - describe("Regulator traces collection", function () { - it("should save a trace", function () { - factory.buildStub.returns(collection); - collection.insertStub.returns(BluebirdPromise.resolve()); - - const dataStore = new UserDataStore(factory); - - return dataStore.saveAuthenticationTrace(userId, true) - .then(function (doc) { - Assert(collection.insertStub.calledOnce); - Assert(collection.insertStub.calledWith({ - userId: userId, - date: Sinon.match.date, - isAuthenticationSuccessful: true - })); - return BluebirdPromise.resolve(); - }); - }); - - function should_retrieve_latest_authentication_traces(count: number) { - factory.buildStub.returns(collection); - collection.findStub.withArgs().returns(BluebirdPromise.resolve()); - - const dataStore = new UserDataStore(factory); - - return dataStore.retrieveLatestAuthenticationTraces(userId, count) - .then(function (doc: AuthenticationTraceDocument[]) { - Assert(collection.findStub.calledOnce); - Assert(collection.findStub.calledWith({ - userId: userId, - }, { date: -1 }, count)); - return BluebirdPromise.resolve(); - }); - } - - it("should retrieve 3 latest failed authentication traces", function () { - should_retrieve_latest_authentication_traces(3); - }); - }); - - - describe("Identity validation collection", function () { - it("should save a identity validation token", function () { - factory.buildStub.returns(collection); - collection.insertStub.returns(BluebirdPromise.resolve()); - - const dataStore = new UserDataStore(factory); - const maxAge = 400; - const token = "TOKEN"; - const challenge = "CHALLENGE"; - - return dataStore.produceIdentityValidationToken(userId, token, challenge, maxAge) - .then(function (doc) { - Assert(collection.insertStub.calledOnce); - Assert(collection.insertStub.calledWith({ - userId: userId, - token: token, - challenge: challenge, - maxDate: Sinon.match.date - })); - return BluebirdPromise.resolve(); - }); - }); - - it("should consume an identity token successfully", function () { - factory.buildStub.returns(collection); - - MockDate.set(100); - - const token = "TOKEN"; - const challenge = "CHALLENGE"; - - collection.findOneStub.withArgs().returns(BluebirdPromise.resolve({ - userId: "USER", - token: token, - challenge: challenge, - maxDate: new Date() - })); - collection.removeStub.returns(BluebirdPromise.resolve()); - - const dataStore = new UserDataStore(factory); - - MockDate.set(80); - - return dataStore.consumeIdentityValidationToken(token, challenge) - .then(function (doc) { - MockDate.reset(); - Assert(collection.findOneStub.calledOnce); - Assert(collection.findOneStub.calledWith({ - token: token, - challenge: challenge - })); - - Assert(collection.removeStub.calledOnce); - Assert(collection.removeStub.calledWith({ - token: token, - challenge: challenge - })); - return BluebirdPromise.resolve(); - }); - }); - - it("should consume an expired identity token", function () { - factory.buildStub.returns(collection); - - MockDate.set(0); - - const token = "TOKEN"; - const challenge = "CHALLENGE"; - - collection.findOneStub.withArgs().returns(BluebirdPromise.resolve({ - userId: "USER", - token: token, - challenge: challenge, - maxDate: new Date() - })); - - const dataStore = new UserDataStore(factory); - - MockDate.set(80000); - - return dataStore.consumeIdentityValidationToken(token, challenge) - .then(function () { return BluebirdPromise.reject(new Error("should not be here")); }) - .catch(function () { - MockDate.reset(); - Assert(collection.findOneStub.calledOnce); - Assert(collection.findOneStub.calledWith({ - token: token, - challenge: challenge - })); - return BluebirdPromise.resolve(); - }); - }); - }); - describe("Prefered 2FA method", function () { - it("should save a prefered 2FA method", async function () { - factory.buildStub.returns(collection); - collection.insertStub.returns(BluebirdPromise.resolve()); - - const dataStore = new UserDataStore(factory); - - await dataStore.savePrefered2FAMethod(userId, "totp") - Assert(collection.updateStub.calledOnce); - Assert(collection.updateStub.calledWith( - {userId}, {userId, method: "totp"}, {upsert: true})); - }); - - it("should retrieve a prefered 2FA method", async function () { - factory.buildStub.returns(collection); - collection.findOneStub.returns(BluebirdPromise.resolve()); - - const dataStore = new UserDataStore(factory); - - await dataStore.retrievePrefered2FAMethod(userId) - Assert(collection.findOneStub.calledOnce); - Assert(collection.findOneStub.calledWith({userId})); - }); - }); -}); diff --git a/server/src/lib/storage/UserDataStore.ts b/server/src/lib/storage/UserDataStore.ts deleted file mode 100644 index 54b6b5706..000000000 --- a/server/src/lib/storage/UserDataStore.ts +++ /dev/null @@ -1,127 +0,0 @@ -import * as BluebirdPromise from "bluebird"; -import { IUserDataStore } from "./IUserDataStore"; -import { ICollection } from "./ICollection"; -import { ICollectionFactory } from "./ICollectionFactory"; -import { TOTPSecretDocument } from "./TOTPSecretDocument"; -import { U2FRegistrationDocument } from "./U2FRegistrationDocument"; -import { U2FRegistration } from "../../../types/U2FRegistration"; -import { TOTPSecret } from "../../../types/TOTPSecret"; -import { AuthenticationTraceDocument } from "./AuthenticationTraceDocument"; -import { IdentityValidationDocument } from "./IdentityValidationDocument"; -import Method2FA from "../Method2FA"; - -// Constants - -const IDENTITY_VALIDATION_TOKENS_COLLECTION_NAME = "identity_validation_tokens"; -const AUTHENTICATION_TRACES_COLLECTION_NAME = "authentication_traces"; - -const U2F_REGISTRATIONS_COLLECTION_NAME = "u2f_registrations"; -const TOTP_SECRETS_COLLECTION_NAME = "totp_secrets"; -const PREFERED_2FA_METHOD_COLLECTION_NAME = "prefered_2fa_method"; - - -export interface U2FRegistrationKey { - userId: string; - appId: string; -} - -// Source - -export class UserDataStore implements IUserDataStore { - private u2fSecretCollection: ICollection; - private identityCheckTokensCollection: ICollection; - private authenticationTracesCollection: ICollection; - private totpSecretCollection: ICollection; - private prefered2faMethodCollection: ICollection; - - private collectionFactory: ICollectionFactory; - - constructor(collectionFactory: ICollectionFactory) { - this.collectionFactory = collectionFactory; - - this.u2fSecretCollection = this.collectionFactory.build(U2F_REGISTRATIONS_COLLECTION_NAME); - this.identityCheckTokensCollection = this.collectionFactory.build(IDENTITY_VALIDATION_TOKENS_COLLECTION_NAME); - this.authenticationTracesCollection = this.collectionFactory.build(AUTHENTICATION_TRACES_COLLECTION_NAME); - this.totpSecretCollection = this.collectionFactory.build(TOTP_SECRETS_COLLECTION_NAME); - this.prefered2faMethodCollection = this.collectionFactory.build(PREFERED_2FA_METHOD_COLLECTION_NAME); - } - - saveU2FRegistration(userId: string, appId: string, registration: U2FRegistration): BluebirdPromise { - const newDocument: U2FRegistrationDocument = {userId, appId, registration}; - const filter: U2FRegistrationKey = {userId, appId}; - - return this.u2fSecretCollection.update(filter, newDocument, { upsert: true }); - } - - retrieveU2FRegistration(userId: string, appId: string): BluebirdPromise { - const filter: U2FRegistrationKey = { userId, appId }; - return this.u2fSecretCollection.findOne(filter); - } - - saveAuthenticationTrace(userId: string, isAuthenticationSuccessful: boolean): BluebirdPromise { - const newDocument: AuthenticationTraceDocument = { - userId, date: new Date(), - isAuthenticationSuccessful: isAuthenticationSuccessful, - }; - - return this.authenticationTracesCollection.insert(newDocument); - } - - retrieveLatestAuthenticationTraces(userId: string, count: number): BluebirdPromise { - return this.authenticationTracesCollection.find({userId}, { date: -1 }, count); - } - - produceIdentityValidationToken(userId: string, token: string, challenge: string, maxAge: number): BluebirdPromise { - const newDocument: IdentityValidationDocument = { - userId, token, challenge, - maxDate: new Date(new Date().getTime() + maxAge) - }; - - return this.identityCheckTokensCollection.insert(newDocument); - } - - consumeIdentityValidationToken(token: string, challenge: string): BluebirdPromise { - const that = this; - const filter = {token, challenge}; - - let identityValidationDocument: IdentityValidationDocument; - - return this.identityCheckTokensCollection.findOne(filter) - .then(function (doc: IdentityValidationDocument) { - if (!doc) { - return BluebirdPromise.reject(new Error("Registration token does not exist")); - } - - identityValidationDocument = doc; - const current_date = new Date(); - if (current_date > doc.maxDate) - return BluebirdPromise.reject(new Error("Registration token is not valid anymore")); - - return that.identityCheckTokensCollection.remove(filter); - }) - .then(() => { - return BluebirdPromise.resolve(identityValidationDocument); - }); - } - - saveTOTPSecret(userId: string, secret: TOTPSecret): BluebirdPromise { - const doc = {userId, secret}; - return this.totpSecretCollection.update({userId}, doc, { upsert: true }); - } - - retrieveTOTPSecret(userId: string): BluebirdPromise { - return this.totpSecretCollection.findOne({userId}); - } - - savePrefered2FAMethod(userId: string, method: Method2FA): BluebirdPromise { - const newDoc = {userId, method}; - return this.prefered2faMethodCollection.update({userId}, newDoc, {upsert: true}); - } - - retrievePrefered2FAMethod(userId: string): BluebirdPromise { - return this.prefered2faMethodCollection.findOne({userId}) - .then((doc) => { - return (doc && doc.method) ? doc.method : undefined; - }); - } -} diff --git a/server/src/lib/storage/UserDataStoreStub.spec.ts b/server/src/lib/storage/UserDataStoreStub.spec.ts deleted file mode 100644 index 74a2e32f1..000000000 --- a/server/src/lib/storage/UserDataStoreStub.spec.ts +++ /dev/null @@ -1,77 +0,0 @@ -import * as Sinon from "sinon"; -import * as BluebirdPromise from "bluebird"; - -import { TOTPSecretDocument } from "./TOTPSecretDocument"; -import { U2FRegistrationDocument } from "./U2FRegistrationDocument"; -import { U2FRegistration } from "../../../types/U2FRegistration"; -import { TOTPSecret } from "../../../types/TOTPSecret"; -import { AuthenticationTraceDocument } from "./AuthenticationTraceDocument"; -import { IdentityValidationDocument } from "./IdentityValidationDocument"; -import { IUserDataStore } from "./IUserDataStore"; -import Method2FA from "../Method2FA"; - -export class UserDataStoreStub implements IUserDataStore { - saveU2FRegistrationStub: Sinon.SinonStub; - retrieveU2FRegistrationStub: Sinon.SinonStub; - saveAuthenticationTraceStub: Sinon.SinonStub; - retrieveLatestAuthenticationTracesStub: Sinon.SinonStub; - produceIdentityValidationTokenStub: Sinon.SinonStub; - consumeIdentityValidationTokenStub: Sinon.SinonStub; - saveTOTPSecretStub: Sinon.SinonStub; - retrieveTOTPSecretStub: Sinon.SinonStub; - savePrefered2FAMethodStub: Sinon.SinonStub; - retrievePrefered2FAMethodStub: Sinon.SinonStub; - - constructor() { - this.saveU2FRegistrationStub = Sinon.stub(); - this.retrieveU2FRegistrationStub = Sinon.stub(); - this.saveAuthenticationTraceStub = Sinon.stub(); - this.retrieveLatestAuthenticationTracesStub = Sinon.stub(); - this.produceIdentityValidationTokenStub = Sinon.stub(); - this.consumeIdentityValidationTokenStub = Sinon.stub(); - this.saveTOTPSecretStub = Sinon.stub(); - this.retrieveTOTPSecretStub = Sinon.stub(); - this.savePrefered2FAMethodStub = Sinon.stub(); - this.retrievePrefered2FAMethodStub = Sinon.stub(); - } - - saveU2FRegistration(userId: string, appId: string, registration: U2FRegistration): BluebirdPromise { - return this.saveU2FRegistrationStub(userId, appId, registration); - } - - retrieveU2FRegistration(userId: string, appId: string): BluebirdPromise { - return this.retrieveU2FRegistrationStub(userId, appId); - } - - saveAuthenticationTrace(userId: string, isAuthenticationSuccessful: boolean): BluebirdPromise { - return this.saveAuthenticationTraceStub(userId, isAuthenticationSuccessful); - } - - retrieveLatestAuthenticationTraces(userId: string, count: number): BluebirdPromise { - return this.retrieveLatestAuthenticationTracesStub(userId, count); - } - - produceIdentityValidationToken(userId: string, token: string, challenge: string, maxAge: number): BluebirdPromise { - return this.produceIdentityValidationTokenStub(userId, token, challenge, maxAge); - } - - consumeIdentityValidationToken(token: string, challenge: string): BluebirdPromise { - return this.consumeIdentityValidationTokenStub(token, challenge); - } - - saveTOTPSecret(userId: string, secret: TOTPSecret): BluebirdPromise { - return this.saveTOTPSecretStub(userId, secret); - } - - retrieveTOTPSecret(userId: string): BluebirdPromise { - return this.retrieveTOTPSecretStub(userId); - } - - savePrefered2FAMethod(userId: string, method: Method2FA): BluebirdPromise { - return this.savePrefered2FAMethodStub(userId, method); - } - - retrievePrefered2FAMethod(userId: string): BluebirdPromise { - return this.retrievePrefered2FAMethodStub(userId); - } -} \ No newline at end of file diff --git a/server/src/lib/storage/mongo/MongoCollection.spec.ts b/server/src/lib/storage/mongo/MongoCollection.spec.ts deleted file mode 100644 index 74a773a1e..000000000 --- a/server/src/lib/storage/mongo/MongoCollection.spec.ts +++ /dev/null @@ -1,110 +0,0 @@ -import Assert = require("assert"); -import Sinon = require("sinon"); -import MongoDB = require("mongodb"); -import BluebirdPromise = require("bluebird"); -import { MongoClientStub } from "../../connectors/mongo/MongoClientStub.spec"; -import { MongoCollection } from "./MongoCollection"; - -describe("storage/mongo/MongoCollection", function () { - let mongoCollectionStub: any; - let mongoClientStub: MongoClientStub; - let findStub: Sinon.SinonStub; - let findOneStub: Sinon.SinonStub; - let insertOneStub: Sinon.SinonStub; - let updateStub: Sinon.SinonStub; - let removeStub: Sinon.SinonStub; - let countStub: Sinon.SinonStub; - const COLLECTION_NAME = "collection"; - - before(function () { - mongoClientStub = new MongoClientStub(); - mongoCollectionStub = Sinon.createStubInstance(require("mongodb").Collection as any); - findStub = mongoCollectionStub.find as Sinon.SinonStub; - findOneStub = mongoCollectionStub.findOne as Sinon.SinonStub; - insertOneStub = mongoCollectionStub.insertOne as Sinon.SinonStub; - updateStub = mongoCollectionStub.update as Sinon.SinonStub; - removeStub = mongoCollectionStub.remove as Sinon.SinonStub; - countStub = mongoCollectionStub.count as Sinon.SinonStub; - mongoClientStub.collectionStub.returns( - BluebirdPromise.resolve(mongoCollectionStub) - ); - }); - - describe("find", function () { - it("should find a document in the collection", function () { - const collection = new MongoCollection(COLLECTION_NAME, mongoClientStub); - findStub.returns({ - sort: Sinon.stub().returns({ - limit: Sinon.stub().returns({ - toArray: Sinon.stub().returns(BluebirdPromise.resolve([])) - }) - }) - }); - - return collection.find({ key: "KEY" }) - .then(function () { - Assert(findStub.calledWith({ key: "KEY" })); - }); - }); - }); - - describe("findOne", function () { - it("should find one document in the collection", function () { - const collection = new MongoCollection(COLLECTION_NAME, mongoClientStub); - findOneStub.returns(BluebirdPromise.resolve({})); - - return collection.findOne({ key: "KEY" }) - .then(function () { - Assert(findOneStub.calledWith({ key: "KEY" })); - }); - }); - }); - - describe("insert", function () { - it("should insert a document in the collection", function () { - const collection = new MongoCollection(COLLECTION_NAME, mongoClientStub); - insertOneStub.returns(BluebirdPromise.resolve({})); - - return collection.insert({ key: "KEY" }) - .then(function () { - Assert(insertOneStub.calledWith({ key: "KEY" })); - }); - }); - }); - - describe("update", function () { - it("should update a document in the collection", function () { - const collection = new MongoCollection(COLLECTION_NAME, mongoClientStub); - updateStub.returns(BluebirdPromise.resolve({})); - - return collection.update({ key: "KEY" }, { key: "KEY", value: 1 }) - .then(function () { - Assert(updateStub.calledWith({ key: "KEY" }, { key: "KEY", value: 1 })); - }); - }); - }); - - describe("remove", function () { - it("should remove a document in the collection", function () { - const collection = new MongoCollection(COLLECTION_NAME, mongoClientStub); - removeStub.returns(BluebirdPromise.resolve({})); - - return collection.remove({ key: "KEY" }) - .then(function () { - Assert(removeStub.calledWith({ key: "KEY" })); - }); - }); - }); - - describe("count", function () { - it("should count documents in the collection", function () { - const collection = new MongoCollection(COLLECTION_NAME, mongoClientStub); - countStub.returns(BluebirdPromise.resolve({})); - - return collection.count({ key: "KEY" }) - .then(function () { - Assert(countStub.calledWith({ key: "KEY" })); - }); - }); - }); -}); diff --git a/server/src/lib/storage/mongo/MongoCollection.ts b/server/src/lib/storage/mongo/MongoCollection.ts deleted file mode 100644 index 9771389f1..000000000 --- a/server/src/lib/storage/mongo/MongoCollection.ts +++ /dev/null @@ -1,50 +0,0 @@ -import Bluebird = require("bluebird"); -import { ICollection } from "../ICollection"; -import MongoDB = require("mongodb"); -import { IMongoClient } from "../../connectors/mongo/IMongoClient"; - - -export class MongoCollection implements ICollection { - private mongoClient: IMongoClient; - private collectionName: string; - - constructor(collectionName: string, mongoClient: IMongoClient) { - this.collectionName = collectionName; - this.mongoClient = mongoClient; - } - - private collection(): Bluebird { - return this.mongoClient.collection(this.collectionName); - } - - find(query: any, sortKeys?: any, count?: number): Bluebird { - return this.collection() - .then((collection) => collection.find(query).sort(sortKeys).limit(count)) - .then((query) => query.toArray()); - } - - findOne(query: any): Bluebird { - return this.collection() - .then((collection) => collection.findOne(query)); - } - - update(query: any, updateQuery: any, options?: any): Bluebird { - return this.collection() - .then((collection) => collection.update(query, updateQuery, options)); - } - - remove(query: any): Bluebird { - return this.collection() - .then((collection) => collection.remove(query)); - } - - insert(document: any): Bluebird { - return this.collection() - .then((collection) => collection.insertOne(document)); - } - - count(query: any): Bluebird { - return this.collection() - .then((collection) => collection.count(query)); - } -} \ No newline at end of file diff --git a/server/src/lib/storage/mongo/MongoCollectionFactory.spec.ts b/server/src/lib/storage/mongo/MongoCollectionFactory.spec.ts deleted file mode 100644 index bd959cacb..000000000 --- a/server/src/lib/storage/mongo/MongoCollectionFactory.spec.ts +++ /dev/null @@ -1,21 +0,0 @@ -import Assert = require("assert"); -import Sinon = require("sinon"); -import { MongoClientStub } from "../../connectors/mongo/MongoClientStub.spec"; -import { MongoCollectionFactory } from "./MongoCollectionFactory"; - -describe("storage/mongo/MongoCollectionFactory", function () { - let mongoClient: MongoClientStub; - - before(function() { - mongoClient = new MongoClientStub(); - }); - - describe("create", function () { - it("should create a collection", function () { - const COLLECTION_NAME = "COLLECTION_NAME"; - - const factory = new MongoCollectionFactory(mongoClient); - Assert(factory.build(COLLECTION_NAME)); - }); - }); -}); diff --git a/server/src/lib/storage/mongo/MongoCollectionFactory.ts b/server/src/lib/storage/mongo/MongoCollectionFactory.ts deleted file mode 100644 index 14a8262c9..000000000 --- a/server/src/lib/storage/mongo/MongoCollectionFactory.ts +++ /dev/null @@ -1,19 +0,0 @@ -import BluebirdPromise = require("bluebird"); -import { ICollection } from "../ICollection"; -import { ICollectionFactory } from "../ICollectionFactory"; -import { MongoCollection } from "./MongoCollection"; -import path = require("path"); -import MongoDB = require("mongodb"); -import { IMongoClient } from "../../connectors/mongo/IMongoClient"; - -export class MongoCollectionFactory implements ICollectionFactory { - private mongoClient: IMongoClient; - - constructor(mongoClient: IMongoClient) { - this.mongoClient = mongoClient; - } - - build(collectionName: string): ICollection { - return new MongoCollection(collectionName, this.mongoClient); - } -} \ No newline at end of file diff --git a/server/src/lib/storage/nedb/NedbCollection.spec.ts b/server/src/lib/storage/nedb/NedbCollection.spec.ts deleted file mode 100644 index a69962b67..000000000 --- a/server/src/lib/storage/nedb/NedbCollection.spec.ts +++ /dev/null @@ -1,136 +0,0 @@ -import Sinon = require("sinon"); -import Assert = require("assert"); - -import { NedbCollection } from "./NedbCollection"; - -describe("storage/nedb/NedbCollection", function () { - describe("insert", function () { - it("should insert one entry", function () { - const nedbOptions = { - inMemoryOnly: true - }; - const collection = new NedbCollection(nedbOptions); - - collection.insert({ key: "coucou" }); - - return collection.count({}).then(function (count: number) { - Assert.equal(1, count); - }); - }); - - it("should insert three entries", function () { - const nedbOptions = { - inMemoryOnly: true - }; - const collection = new NedbCollection(nedbOptions); - - collection.insert({ key: "coucou" }); - collection.insert({ key: "hello" }); - collection.insert({ key: "hey" }); - - return collection.count({}).then(function (count: number) { - Assert.equal(3, count); - }); - }); - }); - - describe("find", function () { - let collection: NedbCollection; - before(function () { - const nedbOptions = { - inMemoryOnly: true - }; - collection = new NedbCollection(nedbOptions); - - collection.insert({ key: "coucou", value: 1 }); - collection.insert({ key: "hello" }); - collection.insert({ key: "hey" }); - collection.insert({ key: "coucou", value: 2 }); - }); - - it("should find one hello", function () { - return collection.find({ key: "hello" }, { key: 1 }) - .then(function (docs: { key: string }[]) { - Assert.equal(1, docs.length); - Assert(docs[0].key == "hello"); - }); - }); - - it("should find two coucou", function () { - return collection.find({ key: "coucou" }, { value: 1 }) - .then(function (docs: { value: number }[]) { - Assert.equal(2, docs.length); - }); - }); - }); - - describe("findOne", function () { - let collection: NedbCollection; - before(function () { - const nedbOptions = { - inMemoryOnly: true - }; - collection = new NedbCollection(nedbOptions); - - collection.insert({ key: "coucou", value: 1 }); - collection.insert({ key: "coucou", value: 1 }); - collection.insert({ key: "coucou", value: 1 }); - collection.insert({ key: "coucou", value: 1 }); - }); - - it("should find two coucou", function () { - const doc = { key: "coucou", value: 1 }; - return collection.count(doc) - .then(function (count: number) { - Assert.equal(4, count); - return collection.findOne(doc); - }); - }); - }); - - describe("update", function () { - let collection: NedbCollection; - before(function () { - const nedbOptions = { - inMemoryOnly: true - }; - collection = new NedbCollection(nedbOptions); - - collection.insert({ key: "coucou", value: 1 }); - }); - - it("should update the value", function () { - return collection.update({ key: "coucou" }, { key: "coucou", value: 2 }, { multi: true }) - .then(function () { - return collection.find({ key: "coucou" }); - }) - .then(function (docs: { key: string, value: number }[]) { - Assert.equal(1, docs.length); - Assert.equal(2, docs[0].value); - }); - }); - }); - - describe("update", function () { - let collection: NedbCollection; - before(function () { - const nedbOptions = { - inMemoryOnly: true - }; - collection = new NedbCollection(nedbOptions); - - collection.insert({ key: "coucou" }); - collection.insert({ key: "hello" }); - }); - - it("should update the value", function () { - return collection.remove({ key: "coucou" }) - .then(function () { - return collection.count({}); - }) - .then(function (count: number) { - Assert.equal(1, count); - }); - }); - }); -}); \ No newline at end of file diff --git a/server/src/lib/storage/nedb/NedbCollection.ts b/server/src/lib/storage/nedb/NedbCollection.ts deleted file mode 100644 index 88a93ad05..000000000 --- a/server/src/lib/storage/nedb/NedbCollection.ts +++ /dev/null @@ -1,47 +0,0 @@ -import BluebirdPromise = require("bluebird"); -import { ICollection } from "../ICollection"; -import Nedb = require("nedb"); - -declare module "nedb" { - export class NedbAsync extends Nedb { - constructor(pathOrOptions?: string | Nedb.DataStoreOptions); - updateAsync(query: any, updateQuery: any, options?: Nedb.UpdateOptions): BluebirdPromise; - findOneAsync(query: any): BluebirdPromise; - insertAsync(newDoc: T): BluebirdPromise; - removeAsync(query: any): BluebirdPromise; - countAsync(query: any): BluebirdPromise; - } -} - -export class NedbCollection implements ICollection { - private collection: Nedb.NedbAsync; - - constructor(options: Nedb.DataStoreOptions) { - this.collection = BluebirdPromise.promisifyAll(new Nedb(options)) as Nedb.NedbAsync; - } - - find(query: any, sortKeys?: any, count?: number): BluebirdPromise { - const q = this.collection.find(query).sort(sortKeys).limit(count); - return BluebirdPromise.promisify(q.exec, { context: q })(); - } - - findOne(query: any): BluebirdPromise { - return this.collection.findOneAsync(query); - } - - update(query: any, updateQuery: any, options?: any): BluebirdPromise { - return this.collection.updateAsync(query, updateQuery, options); - } - - remove(query: any): BluebirdPromise { - return this.collection.removeAsync(query); - } - - insert(document: any): BluebirdPromise { - return this.collection.insertAsync(document); - } - - count(query: any): BluebirdPromise { - return this.collection.countAsync(query); - } -} \ No newline at end of file diff --git a/server/src/lib/storage/nedb/NedbCollectionFactory.spec.ts b/server/src/lib/storage/nedb/NedbCollectionFactory.spec.ts deleted file mode 100644 index da90c661f..000000000 --- a/server/src/lib/storage/nedb/NedbCollectionFactory.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import Sinon = require("sinon"); -import Assert = require("assert"); - -import { NedbCollectionFactory } from "./NedbCollectionFactory"; - -describe("storage/nedb/NedbCollectionFactory", function() { - it("should create a nedb collection", function() { - const nedbOptions = { - inMemoryOnly: true - }; - const factory = new NedbCollectionFactory(nedbOptions); - - const collection = factory.build("mycollection"); - Assert(collection); - }); -}); \ No newline at end of file diff --git a/server/src/lib/storage/nedb/NedbCollectionFactory.ts b/server/src/lib/storage/nedb/NedbCollectionFactory.ts deleted file mode 100644 index 49c4dc853..000000000 --- a/server/src/lib/storage/nedb/NedbCollectionFactory.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { ICollection } from "../ICollection"; -import { ICollectionFactory } from "../ICollectionFactory"; -import { NedbCollection } from "./NedbCollection"; -import path = require("path"); -import Nedb = require("nedb"); - -export interface NedbOptions { - inMemoryOnly?: boolean; - directory?: string; -} - -export class NedbCollectionFactory implements ICollectionFactory { - private options: Nedb.DataStoreOptions; - - constructor(options: Nedb.DataStoreOptions) { - this.options = options; - } - - build(collectionName: string): ICollection { - const datastoreOptions: Nedb.DataStoreOptions = { - inMemoryOnly: this.options.inMemoryOnly || false, - autoload: true, - filename: (this.options.filename) ? path.resolve(this.options.filename, collectionName) : undefined - }; - - return new NedbCollection(datastoreOptions); - } -} \ No newline at end of file diff --git a/server/src/lib/stubs/express.spec.ts b/server/src/lib/stubs/express.spec.ts deleted file mode 100644 index 6c30b441b..000000000 --- a/server/src/lib/stubs/express.spec.ts +++ /dev/null @@ -1,117 +0,0 @@ - -import * as Sinon from "sinon"; -import * as Express from "express"; -import { GET_VARIABLE_KEY } from "../constants"; -import { RequestLoggerStub } from "../logging/RequestLoggerStub.spec"; - -export interface ResponseMock { - send: Sinon.SinonStub | Sinon.SinonSpy; - sendStatus: Sinon.SinonStub; - sendFile: Sinon.SinonStub; - sendfile: Sinon.SinonStub; - status: Sinon.SinonStub | Sinon.SinonSpy; - json: Sinon.SinonStub | Sinon.SinonSpy; - links: Sinon.SinonStub; - jsonp: Sinon.SinonStub; - download: Sinon.SinonStub; - contentType: Sinon.SinonStub; - type: Sinon.SinonStub; - format: Sinon.SinonStub; - attachment: Sinon.SinonStub; - set: Sinon.SinonStub; - header: Sinon.SinonStub; - headersSent: boolean; - get: Sinon.SinonStub; - clearCookie: Sinon.SinonStub; - cookie: Sinon.SinonStub; - location: Sinon.SinonStub; - redirect: Sinon.SinonStub | Sinon.SinonSpy; - render: Sinon.SinonStub | Sinon.SinonSpy; - locals: Sinon.SinonStub; - charset: string; - vary: Sinon.SinonStub; - app: any; - write: Sinon.SinonStub; - writeContinue: Sinon.SinonStub; - writeHead: Sinon.SinonStub; - statusCode: number; - statusMessage: string; - setHeader: Sinon.SinonStub; - setTimeout: Sinon.SinonStub; - sendDate: boolean; - getHeader: Sinon.SinonStub; -} - -export function RequestMock(): Express.Request { - const getMock = Sinon.mock() - .withArgs(GET_VARIABLE_KEY).atLeast(0).returns({ - logger: new RequestLoggerStub() - }); - return { - id: '1234', - headers: {}, - app: { - get: getMock, - set: Sinon.mock(), - }, - body: {}, - query: {}, - session: { - id: '1234', - regenerate: function() {}, - reload: function() {}, - destroy: function() {}, - save: function() {}, - touch: function() {}, - cookie: { - domain: 'example.com', - expires: true, - httpOnly: true, - maxAge: 36000, - originalMaxAge: 36000, - path: '/', - secure: true, - serialize: () => '', - } - } - } as any; -} -export function ResponseMock(): ResponseMock { - return { - send: Sinon.stub(), - status: Sinon.stub(), - json: Sinon.stub(), - sendStatus: Sinon.stub(), - links: Sinon.stub(), - jsonp: Sinon.stub(), - sendFile: Sinon.stub(), - sendfile: Sinon.stub(), - download: Sinon.stub(), - contentType: Sinon.stub(), - type: Sinon.stub(), - format: Sinon.stub(), - attachment: Sinon.stub(), - set: Sinon.stub(), - header: Sinon.stub(), - headersSent: true, - get: Sinon.stub(), - clearCookie: Sinon.stub(), - cookie: Sinon.stub(), - location: Sinon.stub(), - redirect: Sinon.stub(), - render: Sinon.stub(), - locals: Sinon.stub(), - charset: "utf-8", - vary: Sinon.stub(), - app: Sinon.stub(), - write: Sinon.stub(), - writeContinue: Sinon.stub(), - writeHead: Sinon.stub(), - statusCode: 200, - statusMessage: "message", - setHeader: Sinon.stub(), - setTimeout: Sinon.stub(), - sendDate: true, - getHeader: Sinon.stub() - }; -} diff --git a/server/src/lib/stubs/ldapjs.spec.ts b/server/src/lib/stubs/ldapjs.spec.ts deleted file mode 100644 index 045c0e11b..000000000 --- a/server/src/lib/stubs/ldapjs.spec.ts +++ /dev/null @@ -1,50 +0,0 @@ - -import Sinon = require("sinon"); - -export class LdapjsMock { - createClientStub: sinon.SinonStub; - - constructor() { - this.createClientStub = Sinon.stub(); - } - - createClient(params: any) { - return this.createClientStub(params); - } -} - -export class LdapjsClientMock { - bindStub: sinon.SinonStub; - unbindStub: sinon.SinonStub; - searchStub: sinon.SinonStub; - modifyStub: sinon.SinonStub; - onStub: sinon.SinonStub; - - constructor() { - this.bindStub = Sinon.stub(); - this.unbindStub = Sinon.stub(); - this.searchStub = Sinon.stub(); - this.modifyStub = Sinon.stub(); - this.onStub = Sinon.stub(); - } - - bind() { - return this.bindStub(); - } - - unbind() { - return this.unbindStub(); - } - - search() { - return this.searchStub(); - } - - modify() { - return this.modifyStub(); - } - - on() { - return this.onStub(); - } -} \ No newline at end of file diff --git a/server/src/lib/stubs/speakeasy.spec.ts b/server/src/lib/stubs/speakeasy.spec.ts deleted file mode 100644 index 023614dcd..000000000 --- a/server/src/lib/stubs/speakeasy.spec.ts +++ /dev/null @@ -1,7 +0,0 @@ - -import sinon = require("sinon"); - -export = { - totp: sinon.stub(), - generateSecret: sinon.stub() -}; diff --git a/server/src/lib/stubs/u2f.spec.ts b/server/src/lib/stubs/u2f.spec.ts deleted file mode 100644 index 234b28c11..000000000 --- a/server/src/lib/stubs/u2f.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ - -import sinon = require("sinon"); - -export interface U2FMock { - request: sinon.SinonStub; - checkSignature: sinon.SinonStub; - checkRegistration: sinon.SinonStub; -} - -export function U2FMock(): U2FMock { - return { - request: sinon.stub(), - checkSignature: sinon.stub(), - checkRegistration: sinon.stub() - }; -} diff --git a/server/src/lib/utils/AssertRejects.ts b/server/src/lib/utils/AssertRejects.ts deleted file mode 100644 index cca93b63f..000000000 --- a/server/src/lib/utils/AssertRejects.ts +++ /dev/null @@ -1,11 +0,0 @@ - -export default function(fn: () => Promise, expectedErrorType: any = Error, logs = false): void { - fn().then(() => { - throw new Error("Should reject"); - }, (err: Error) => { - if (!(err instanceof expectedErrorType)) { - throw new Error(`Received error ${typeof err} != Expected error ${expectedErrorType}`); - } - if (logs) console.error(err); - }); -} \ No newline at end of file diff --git a/server/src/lib/utils/GetHeader.spec.ts b/server/src/lib/utils/GetHeader.spec.ts deleted file mode 100644 index 0377f173f..000000000 --- a/server/src/lib/utils/GetHeader.spec.ts +++ /dev/null @@ -1,20 +0,0 @@ -import * as Express from "express"; -import GetHeader from "./GetHeader"; -import { RequestMock } from "../stubs/express.spec"; -import * as Assert from "assert"; - -describe('utils/GetHeader', function() { - let req: Express.Request; - beforeEach(() => { - req = RequestMock(); - }); - - it('should return the header if it exists', function() { - req.headers["x-target-url"] = 'www.example.com'; - Assert.equal(GetHeader(req, 'x-target-url'), 'www.example.com'); - }); - - it('should return undefined if header does not exist', function() { - Assert.equal(GetHeader(req, 'x-target-url'), undefined); - }); -}); \ No newline at end of file diff --git a/server/src/lib/utils/GetHeader.ts b/server/src/lib/utils/GetHeader.ts deleted file mode 100644 index 882accec8..000000000 --- a/server/src/lib/utils/GetHeader.ts +++ /dev/null @@ -1,19 +0,0 @@ -import * as Express from "express"; -import * as ObjectPath from "object-path"; -import { ServerVariables } from "../ServerVariables"; -import { GET_VARIABLE_KEY } from "../constants"; - -/** - * - * @param req The express request to extract headers from - * @param header The name of the header to extract in lowercase. - * @returns The header if found, otherwise undefined. - */ -export default function(req: Express.Request, header: string): string | undefined { - const variables: ServerVariables = req.app.get(GET_VARIABLE_KEY); - if (!variables) throw new Error("There are no server variables set."); - - const value = ObjectPath.get(req, "headers." + header, undefined); - variables.logger.debug(req, "Header %s is set to %s", header, value); - return value; -} \ No newline at end of file diff --git a/server/src/lib/utils/HasHeader.spec.ts b/server/src/lib/utils/HasHeader.spec.ts deleted file mode 100644 index f435117d2..000000000 --- a/server/src/lib/utils/HasHeader.spec.ts +++ /dev/null @@ -1,20 +0,0 @@ -import * as Express from "express"; -import HasHeader from "./HasHeader"; -import { RequestMock } from "../stubs/express.spec"; -import * as Assert from "assert"; - -describe('utils/HasHeader', function() { - let req: Express.Request; - beforeEach(() => { - req = RequestMock(); - }); - - it('should return the header if it exists', function() { - req.headers["x-target-url"] = 'www.example.com'; - Assert(HasHeader(req, 'x-target-url')); - }); - - it('should return undefined if header does not exist', function() { - Assert(!HasHeader(req, 'x-target-url')); - }); -}); \ No newline at end of file diff --git a/server/src/lib/utils/HasHeader.ts b/server/src/lib/utils/HasHeader.ts deleted file mode 100644 index 74ce354d8..000000000 --- a/server/src/lib/utils/HasHeader.ts +++ /dev/null @@ -1,12 +0,0 @@ -import * as Express from "express"; -import * as ObjectPath from "object-path"; - -/** - * - * @param req The express request to extract headers from - * @param header The name of the header to check the existence of. - * @returns true if the header is found, otherwise false. - */ -export default function(req: Express.Request, header: string): boolean { - return ObjectPath.has(req, "headers." + header); -} \ No newline at end of file diff --git a/server/src/lib/utils/HashGenerator.spec.ts b/server/src/lib/utils/HashGenerator.spec.ts deleted file mode 100644 index f19619a65..000000000 --- a/server/src/lib/utils/HashGenerator.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import Assert = require("assert"); -import { HashGenerator } from "./HashGenerator"; - -describe("utils/HashGenerator", function () { - it("should compute correct ssha512 (password)", function () { - return HashGenerator.ssha512("password", 500000, "jgiCMRyGXzoqpxS3") - .then(function (hash: string) { - Assert.equal(hash, "{CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/"); - }); - }); - - it("should compute correct ssha512 (test)", function () { - return HashGenerator.ssha512("test", 500000, "abcdefghijklmnop") - .then(function (hash: string) { - Assert.equal(hash, "{CRYPT}$6$rounds=500000$abcdefghijklmnop$sTlNGf0VO/HTQIOXemmaBbV28HUch/qhWOA1/4dsDj6CDQYhUgXbYSPL6gccAsWMr2zD5fFWwhKmPdG.yxphs."); - }); - }); -}); \ No newline at end of file diff --git a/server/src/lib/utils/HashGenerator.ts b/server/src/lib/utils/HashGenerator.ts deleted file mode 100644 index a88a21e48..000000000 --- a/server/src/lib/utils/HashGenerator.ts +++ /dev/null @@ -1,22 +0,0 @@ -import BluebirdPromise = require("bluebird"); -import RandomString = require("randomstring"); -import Util = require("util"); -const crypt = require("crypt3"); - -export class HashGenerator { - static ssha512( - password: string, - rounds: number = 500000, - salt?: string): BluebirdPromise { - // $6 means SHA512 - const _salt = Util.format("$6$rounds=%d$%s", rounds, - (salt) ? salt : RandomString.generate(16)); - - const cryptAsync = BluebirdPromise.promisify(crypt); - - return cryptAsync(password, _salt) - .then(function (hash: string) { - return BluebirdPromise.resolve(Util.format("{CRYPT}%s", hash)); - }); - } -} \ No newline at end of file diff --git a/server/src/lib/utils/IsRedirectionSafe.ts b/server/src/lib/utils/IsRedirectionSafe.ts deleted file mode 100644 index ad5f1aaab..000000000 --- a/server/src/lib/utils/IsRedirectionSafe.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ServerVariables } from "../ServerVariables"; -import * as URLParse from "url-parse"; - -export default function IsRedirectionSafe( - vars: ServerVariables, - url: URLParse): boolean { - - const urlInDomain = url.hostname.endsWith(vars.config.session.domain); - const protocolIsHttps = url.protocol === "https:"; - return urlInDomain && protocolIsHttps; -} diff --git a/server/src/lib/utils/ObjectCloner.ts b/server/src/lib/utils/ObjectCloner.ts deleted file mode 100644 index 3e125d749..000000000 --- a/server/src/lib/utils/ObjectCloner.ts +++ /dev/null @@ -1,6 +0,0 @@ - -export class ObjectCloner { - static clone(obj: any): any { - return JSON.parse(JSON.stringify(obj)); - } -} \ No newline at end of file diff --git a/server/src/lib/utils/RequestUrlGetter.spec.ts b/server/src/lib/utils/RequestUrlGetter.spec.ts deleted file mode 100644 index 81e30fda2..000000000 --- a/server/src/lib/utils/RequestUrlGetter.spec.ts +++ /dev/null @@ -1,51 +0,0 @@ -import RequestUrlGetter from "./RequestUrlGetter"; -import * as Assert from "assert"; -import * as Sinon from "sinon"; -import { RequestLoggerStub } from "../logging/RequestLoggerStub.spec"; - -describe('RequestUrlGetter', function() { - let req: any; - beforeEach(function() { - req = { - app: { - get: Sinon.stub().returns({ - logger: new RequestLoggerStub() - }) - }, - headers: {} - } - }) - - it("should return the content of X-Original-Uri header", function() { - req.headers["x-original-url"] = "https://mytarget.example.com"; - Assert.equal(RequestUrlGetter.getOriginalUrl(req), "https://mytarget.example.com"); - }) - - describe("Use X-Forwarded-Proto, X-Forwarded-Host and X-Forwarded-Uri headers", function() { - it("should get URL from Forwarded headers", function() { - req.headers["x-forwarded-proto"] = "https"; - req.headers["x-forwarded-host"] = "mytarget.example.com"; - req.headers["x-forwarded-uri"] = "/" - Assert.equal(RequestUrlGetter.getOriginalUrl(req), "https://mytarget.example.com/"); - }) - - it("should get URL from Forwarded headers without URI", function() { - req.headers["x-forwarded-proto"] = "https"; - req.headers["x-forwarded-host"] = "mytarget.example.com"; - Assert.equal(RequestUrlGetter.getOriginalUrl(req), "https://mytarget.example.com"); - }) - }); - - it("should throw when no header is provided", function() { - Assert.throws(() => { - RequestUrlGetter.getOriginalUrl(req) - }) - }) - - it("should throw when only some of X-Forwarded-* headers are provided", function() { - req.headers["x-forwarded-proto"] = "https"; - Assert.throws(() => { - RequestUrlGetter.getOriginalUrl(req) - }) - }) -}) \ No newline at end of file diff --git a/server/src/lib/utils/RequestUrlGetter.ts b/server/src/lib/utils/RequestUrlGetter.ts deleted file mode 100644 index 875620428..000000000 --- a/server/src/lib/utils/RequestUrlGetter.ts +++ /dev/null @@ -1,29 +0,0 @@ -import Constants = require("../constants"); -import Express = require("express"); -import GetHeader from "./GetHeader"; -import HasHeader from "./HasHeader"; - -export default class RequestUrlGetter { - static getOriginalUrl(req: Express.Request): string { - - if (HasHeader(req, Constants.HEADER_X_ORIGINAL_URL)) { - return GetHeader(req, Constants.HEADER_X_ORIGINAL_URL); - } - - // X-Forwarded-Port is not mandatory since the port is included in X-Forwarded-Host - // at least in nginx and Traefik. - const proto = GetHeader(req, Constants.HEADER_X_FORWARDED_PROTO); - const host = GetHeader(req, Constants.HEADER_X_FORWARDED_HOST); - const uri = GetHeader(req, Constants.HEADER_X_FORWARDED_URI); - - if (!proto || !host) { - throw new Error("Missing headers holding requested URL. Requires either X-Original-Url or X-Forwarded-Proto, X-Forwarded-Host and X-Forwarded-Uri."); - } - - if (!uri) { - return `${proto}://${host}`; - } - - return `${proto}://${host}${uri}`; - } -} diff --git a/server/src/lib/utils/URLDecomposer.spec.ts b/server/src/lib/utils/URLDecomposer.spec.ts deleted file mode 100644 index cbb038738..000000000 --- a/server/src/lib/utils/URLDecomposer.spec.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { URLDecomposer } from "./URLDecomposer"; -import Assert = require("assert"); - -describe("utils/URLDecomposer", function () { - describe("test fromUrl", function () { - it("should return domain from https url", function () { - const d = URLDecomposer.fromUrl("https://www.example.com/test/abc"); - Assert.equal(d.domain, "www.example.com"); - Assert.equal(d.path, "/test/abc"); - }); - - it("should return domain from http url", function () { - const d = URLDecomposer.fromUrl("http://www.example.com/test/abc"); - Assert.equal(d.domain, "www.example.com"); - Assert.equal(d.path, "/test/abc"); - }); - - it("should return domain when url contains port", function () { - const d = URLDecomposer.fromUrl("https://www.example.com:8080/test/abc"); - Assert.equal(d.domain, "www.example.com"); - Assert.equal(d.path, "/test/abc"); - }); - - it("should return default path when no path provided", function () { - const d = URLDecomposer.fromUrl("https://www.example.com:8080"); - Assert.equal(d.domain, "www.example.com"); - Assert.equal(d.path, "/"); - }); - - it("should return default path when provided", function () { - const d = URLDecomposer.fromUrl("https://www.example.com:8080/"); - Assert.equal(d.domain, "www.example.com"); - Assert.equal(d.path, "/"); - }); - - it("should return undefined when does not match", function () { - const d = URLDecomposer.fromUrl("https:///abc/test"); - Assert.equal(d, undefined); - }); - - it("should return undefined when does not match", function () { - const d = URLDecomposer.fromUrl("https:///abc/test"); - Assert.equal(d, undefined); - }); - }); -}); \ No newline at end of file diff --git a/server/src/lib/utils/URLDecomposer.ts b/server/src/lib/utils/URLDecomposer.ts deleted file mode 100644 index e86d64fcb..000000000 --- a/server/src/lib/utils/URLDecomposer.ts +++ /dev/null @@ -1,16 +0,0 @@ -// TODO: replace this decompose by third party library. -export class URLDecomposer { - static fromUrl(url: string): {domain: string, path: string} { - if (!url) return; - const match = url.match(/https?:\/\/([a-z0-9_.-]+)(:[0-9]+)?(.*)/); - - if (!match) return; - - if (match[1] && !match[3]) { - return {domain: match[1], path: "/"}; - } else if (match[1] && match[3]) { - return {domain: match[1], path: match[3]}; - } - return; - } -} \ No newline at end of file diff --git a/server/src/lib/web_server/Configurator.ts b/server/src/lib/web_server/Configurator.ts deleted file mode 100644 index 93ffd8ab0..000000000 --- a/server/src/lib/web_server/Configurator.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Configuration } from "../configuration/schema/Configuration"; -import { GlobalDependencies } from "../../../types/Dependencies"; -import { SessionConfigurationBuilder } from - "../configuration/SessionConfigurationBuilder"; -import Path = require("path"); -import Express = require("express"); -import * as BodyParser from "body-parser"; -import { RestApi } from "./RestApi"; -import { WithHeadersLogged } from "./middlewares/WithHeadersLogged"; -import { ServerVariables } from "../ServerVariables"; -import Helmet = require("helmet"); - -const addRequestId = require("express-request-id")(); - -// Constants -const TRUST_PROXY = "trust proxy"; -const X_POWERED_BY = "x-powered-by"; - -export class Configurator { - static configure(config: Configuration, - app: Express.Application, - vars: ServerVariables, - deps: GlobalDependencies): void { - const publicHtmlDirectory = Path.resolve(__dirname, "../../public_html"); - - const expressSessionOptions = SessionConfigurationBuilder.build(config, deps); - - app.use(Express.static(publicHtmlDirectory)); - app.use(BodyParser.urlencoded({ extended: false })); - app.use(BodyParser.json()); - app.use(deps.session(expressSessionOptions)); - app.use(addRequestId); - app.use(WithHeadersLogged.middleware(vars.logger)); - app.disable(X_POWERED_BY); - app.enable(TRUST_PROXY); - app.use(Helmet()); - app.use(function (req, res, next) { - if (!req.session) { - return next(new Error("No session available.")); - } - next(); - }); - - RestApi.setup(app, vars); - } -} \ No newline at end of file diff --git a/server/src/lib/web_server/RestApi.ts b/server/src/lib/web_server/RestApi.ts deleted file mode 100644 index 01ed41295..000000000 --- a/server/src/lib/web_server/RestApi.ts +++ /dev/null @@ -1,121 +0,0 @@ -import * as Express from "express"; -import SecondFactorPreferencesGet from "../routes/secondfactor/preferences/Get"; -import SecondFactorPreferencesPost from "../routes/secondfactor/preferences/Post"; -import SecondFactorDuoPushPost from "../routes/secondfactor/duo-push/Post"; -import SecondFactorAvailableGet from "../routes/secondfactor/available/Get"; - -import FirstFactorPost = require("../routes/firstfactor/post"); -import LogoutPost from "../routes/logout/post"; -import StateGet from "../routes/state/get"; -import VerifyGet = require("../routes/verify/Get"); -import TOTPSignGet = require("../routes/secondfactor/totp/sign/post"); - -import IdentityCheckMiddleware = require("../IdentityCheckMiddleware"); - -import TOTPRegistrationIdentityHandler from "../routes/secondfactor/totp/identity/RegistrationHandler"; -import U2FRegistrationIdentityHandler from "../routes/secondfactor/u2f/identity/RegistrationHandler"; -import ResetPasswordIdentityHandler from "../routes/password-reset/identity/PasswordResetHandler"; - -import U2FSignPost = require("../routes/secondfactor/u2f/sign/post"); -import U2FSignRequestGet = require("../routes/secondfactor/u2f/sign_request/get"); - -import U2FRegisterPost = require("../routes/secondfactor/u2f/register/post"); -import U2FRegisterRequestGet = require("../routes/secondfactor/u2f/register_request/get"); - -import ResetPasswordFormPost = require("../routes/password-reset/form/post"); - -import { ServerVariables } from "../ServerVariables"; -import Endpoints = require("../api"); -import { RequireValidatedFirstFactor } from "./middlewares/RequireValidatedFirstFactor"; - -function setupTotp(app: Express.Application, vars: ServerVariables) { - app.post(Endpoints.SECOND_FACTOR_TOTP_POST, - RequireValidatedFirstFactor.middleware(vars.logger), - TOTPSignGet.default(vars)); - - app.post(Endpoints.SECOND_FACTOR_TOTP_IDENTITY_START_POST, - RequireValidatedFirstFactor.middleware(vars.logger)); - - app.post(Endpoints.SECOND_FACTOR_TOTP_IDENTITY_FINISH_POST, - RequireValidatedFirstFactor.middleware(vars.logger)); - - IdentityCheckMiddleware.register(app, - Endpoints.SECOND_FACTOR_TOTP_IDENTITY_START_POST, - Endpoints.SECOND_FACTOR_TOTP_IDENTITY_FINISH_POST, - new TOTPRegistrationIdentityHandler(vars.logger, - vars.userDataStore, vars.totpHandler, vars.config.totp), - vars); -} - -function setupU2f(app: Express.Application, vars: ServerVariables) { - app.get(Endpoints.SECOND_FACTOR_U2F_SIGN_REQUEST_GET, - RequireValidatedFirstFactor.middleware(vars.logger), - U2FSignRequestGet.default(vars)); - - app.post(Endpoints.SECOND_FACTOR_U2F_SIGN_POST, - RequireValidatedFirstFactor.middleware(vars.logger), - U2FSignPost.default(vars)); - - app.get(Endpoints.SECOND_FACTOR_U2F_REGISTER_REQUEST_GET, - RequireValidatedFirstFactor.middleware(vars.logger), - U2FRegisterRequestGet.default(vars)); - - app.post(Endpoints.SECOND_FACTOR_U2F_REGISTER_POST, - RequireValidatedFirstFactor.middleware(vars.logger), - U2FRegisterPost.default(vars)); - - app.post(Endpoints.SECOND_FACTOR_U2F_IDENTITY_START_POST, - RequireValidatedFirstFactor.middleware(vars.logger)); - - app.post(Endpoints.SECOND_FACTOR_U2F_IDENTITY_FINISH_POST, - RequireValidatedFirstFactor.middleware(vars.logger)); - - IdentityCheckMiddleware.register(app, - Endpoints.SECOND_FACTOR_U2F_IDENTITY_START_POST, - Endpoints.SECOND_FACTOR_U2F_IDENTITY_FINISH_POST, - new U2FRegistrationIdentityHandler(vars.logger), vars); -} - -function setupResetPassword(app: Express.Application, vars: ServerVariables) { - IdentityCheckMiddleware.register(app, - Endpoints.RESET_PASSWORD_IDENTITY_START_GET, - Endpoints.RESET_PASSWORD_IDENTITY_FINISH_GET, - new ResetPasswordIdentityHandler(vars.logger, vars.usersDatabase), - vars); - - app.post(Endpoints.RESET_PASSWORD_FORM_POST, - ResetPasswordFormPost.default(vars)); -} - -export class RestApi { - static setup(app: Express.Application, vars: ServerVariables): void { - app.get(Endpoints.STATE_GET, StateGet(vars)); - - app.post(Endpoints.LOGOUT_POST, LogoutPost(vars)); - - app.get(Endpoints.VERIFY_GET, VerifyGet.default(vars)); - app.post(Endpoints.FIRST_FACTOR_POST, FirstFactorPost.default(vars)); - - app.get(Endpoints.SECOND_FACTOR_PREFERENCES_GET, - RequireValidatedFirstFactor.middleware(vars.logger), - SecondFactorPreferencesGet(vars)); - - app.post(Endpoints.SECOND_FACTOR_PREFERENCES_POST, - RequireValidatedFirstFactor.middleware(vars.logger), - SecondFactorPreferencesPost(vars)); - - if (vars.config.duo_api) { - app.post(Endpoints.SECOND_FACTOR_DUO_PUSH_POST, - RequireValidatedFirstFactor.middleware(vars.logger), - SecondFactorDuoPushPost(vars)); - } - - app.get(Endpoints.SECOND_FACTOR_AVAILABLE_GET, - RequireValidatedFirstFactor.middleware(vars.logger), - SecondFactorAvailableGet(vars)); - - setupTotp(app, vars); - setupU2f(app, vars); - setupResetPassword(app, vars); - } -} diff --git a/server/src/lib/web_server/middlewares/RequireValidatedFirstFactor.ts b/server/src/lib/web_server/middlewares/RequireValidatedFirstFactor.ts deleted file mode 100644 index ecfd75765..000000000 --- a/server/src/lib/web_server/middlewares/RequireValidatedFirstFactor.ts +++ /dev/null @@ -1,27 +0,0 @@ -import Express = require("express"); -import BluebirdPromise = require("bluebird"); -import ErrorReplies = require("../../ErrorReplies"); -import { IRequestLogger } from "../../logging/IRequestLogger"; -import { AuthenticationSessionHandler } from "../../AuthenticationSessionHandler"; -import Exceptions = require("../../Exceptions"); -import { Level } from "../../authentication/Level"; - -export class RequireValidatedFirstFactor { - static middleware(logger: IRequestLogger) { - return function (req: Express.Request, res: Express.Response, - next: Express.NextFunction): BluebirdPromise { - - return new BluebirdPromise(function (resolve, reject) { - const authSession = AuthenticationSessionHandler.get(req, logger); - if (!authSession.userid || authSession.authentication_level < Level.ONE_FACTOR) - return reject( - new Exceptions.FirstFactorValidationError( - "First factor has not been validated yet.")); - - next(); - resolve(); - }) - .catch(ErrorReplies.replyWithError401(req, res, logger)); - }; - } -} \ No newline at end of file diff --git a/server/src/lib/web_server/middlewares/WithHeadersLogged.ts b/server/src/lib/web_server/middlewares/WithHeadersLogged.ts deleted file mode 100644 index 139db1141..000000000 --- a/server/src/lib/web_server/middlewares/WithHeadersLogged.ts +++ /dev/null @@ -1,12 +0,0 @@ -import Express = require("express"); -import { IRequestLogger } from "../../logging/IRequestLogger"; - -export class WithHeadersLogged { - static middleware(logger: IRequestLogger) { - return function (req: Express.Request, res: Express.Response, - next: Express.NextFunction): void { - logger.debug(req, "Headers = %s", JSON.stringify(req.headers)); - next(); - }; - } -} \ No newline at end of file diff --git a/server/src/resources/email-template.ejs b/server/src/resources/email-template.ejs deleted file mode 100644 index ee87c09f8..000000000 --- a/server/src/resources/email-template.ejs +++ /dev/null @@ -1,254 +0,0 @@ - - - - - - Simples-Minimalistic Responsive Template - - - - - - - - - - - -
- - - - - - -
- - - - - - - - - - - - - - - - -
 
- - - - - - - -
-

<%= title %>

-
- -
 
-
-
- - - - - - - - -
- - - - - - -
 
-
- - - - - - - - -
- - - - - - -
- - - - - - - - - - - - - - - - -
 
- - - - - - - - - - - - - - - - - - -
- This email has been sent to you in order to validate your identity. Please ignore it if you do not know why you received it. -
 
- <%= button_title %> -
-
 
-
-
- - - - - - - - -
- - - - - - - - - - - - -
 
 
 
-
- - - - - - - - -
- - - - - - -
- - - - - - - - - - - -
- If you did not initiate the process your credentials might have been compromised. You should reset your password and contact an administrator. -
-
-
- - - - - diff --git a/server/src/types/u2f.d.ts b/server/src/types/u2f.d.ts deleted file mode 100644 index b308fbc42..000000000 --- a/server/src/types/u2f.d.ts +++ /dev/null @@ -1,45 +0,0 @@ - - -declare module "u2f" { - export interface Request { - version: "U2F_V2"; - appId: string; - challenge: string; - keyHandle?: string; - } - - export interface RegistrationData { - clientData: string; - registrationData: string; - errorCode?: number; - } - - export interface RegistrationResult { - successful: boolean; - publicKey: string; - keyHandle: string; - certificate: string; - } - - - export interface SignatureData { - clientData: string; - signatureData: string; - errorCode?: number; - } - - export interface SignatureResult { - successful: boolean; - userPresent: boolean; - counter: number; - } - - export interface Error { - errorCode: number; - errorMessage: string; - } - - export function request(appId: string, keyHandle?: string): Request; - export function checkRegistration(request: Request, registerData: RegistrationData): RegistrationResult | Error; - export function checkSignature(request: Request, signData: SignatureData, publicKey: string): SignatureResult | Error; -} \ No newline at end of file diff --git a/server/tsconfig.json b/server/tsconfig.json deleted file mode 100644 index 36e999058..000000000 --- a/server/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "es6", - "moduleResolution": "node", - "noImplicitAny": true, - "sourceMap": true, - "removeComments": true, - "outDir": "../dist", - "baseUrl": ".", - "paths": { - "*": [ - "./types/*", - ] - } - }, - "exclude": [ - "src/**/*.spec.ts" - ] -} diff --git a/server/tslint.json b/server/tslint.json deleted file mode 100644 index c2c1b7501..000000000 --- a/server/tslint.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "rules": { - "class-name": true, - "comment-format": [ - true, - "check-space" - ], - "indent": [ - true, - "spaces" - ], - "one-line": [ - true, - "check-open-brace", - "check-whitespace" - ], - "no-var-keyword": true, - "quotemark": [ - true, - "double", - "avoid-escape" - ], - "semicolon": [ - true, - "always", - "ignore-bound-class-methods" - ], - "whitespace": [ - true, - "check-branch", - "check-decl", - "check-operator", - "check-module", - "check-separator", - "check-type" - ], - "typedef-whitespace": [ - true, - { - "call-signature": "nospace", - "index-signature": "nospace", - "parameter": "nospace", - "property-declaration": "nospace", - "variable-declaration": "nospace" - }, - { - "call-signature": "onespace", - "index-signature": "onespace", - "parameter": "onespace", - "property-declaration": "onespace", - "variable-declaration": "onespace" - } - ], - "no-internal-module": true, - "no-trailing-whitespace": true, - "no-null-keyword": true, - "prefer-const": true, - "jsdoc-format": true - } -} diff --git a/server/types/AuthenticationSession.ts b/server/types/AuthenticationSession.ts deleted file mode 100644 index bbed0e715..000000000 --- a/server/types/AuthenticationSession.ts +++ /dev/null @@ -1,18 +0,0 @@ -import U2f = require("u2f"); -import { Level } from "../src/lib/authentication/Level"; - -export interface AuthenticationSession { - userid: string; - authentication_level: Level; - keep_me_logged_in: boolean; - last_activity_datetime: number; - identity_check?: { - challenge: string; - userid: string; - }; - register_request?: U2f.Request; - sign_request?: U2f.Request; - email: string; - groups: string[]; - redirect?: string; -} \ No newline at end of file diff --git a/server/types/Dependencies.ts b/server/types/Dependencies.ts deleted file mode 100644 index f20404dbc..000000000 --- a/server/types/Dependencies.ts +++ /dev/null @@ -1,29 +0,0 @@ -import winston = require("winston"); -import speakeasy = require("speakeasy"); -import nodemailer = require("nodemailer"); -import session = require("express-session"); -import nedb = require("nedb"); -import ldapjs = require("ldapjs"); -import u2f = require("u2f"); -import RedisSession = require("connect-redis"); -import Redis = require("redis"); - -export type Speakeasy = typeof speakeasy; -export type Winston = typeof winston; -export type Session = typeof session; -export type Nedb = typeof nedb; -export type Ldapjs = typeof ldapjs; -export type U2f = typeof u2f; -export type ConnectRedis = typeof RedisSession; -export type Redis = typeof Redis; - -export interface GlobalDependencies { - u2f: U2f; - ldapjs: Ldapjs; - session: Session; - Redis: Redis; - ConnectRedis: ConnectRedis; - winston: Winston; - speakeasy: Speakeasy; - nedb: Nedb; -} \ No newline at end of file diff --git a/server/types/Identity.ts b/server/types/Identity.ts deleted file mode 100644 index e985984e2..000000000 --- a/server/types/Identity.ts +++ /dev/null @@ -1,6 +0,0 @@ - - -export interface Identity { - userid: string; - email: string; -} \ No newline at end of file diff --git a/server/types/TOTPSecret.ts b/server/types/TOTPSecret.ts deleted file mode 100644 index d6775f2f0..000000000 --- a/server/types/TOTPSecret.ts +++ /dev/null @@ -1,11 +0,0 @@ - -export interface TOTPSecret { - ascii: string; - hex: string; - base32: string; - qr_code_ascii: string; - qr_code_hex: string; - qr_code_base32: string; - google_auth_qr: string; - otpauth_url: string; - } \ No newline at end of file diff --git a/server/types/U2FRegistration.ts b/server/types/U2FRegistration.ts deleted file mode 100644 index b6080af07..000000000 --- a/server/types/U2FRegistration.ts +++ /dev/null @@ -1,5 +0,0 @@ - -export interface U2FRegistration { - keyHandle: string; - publicKey: string; -} \ No newline at end of file diff --git a/server/types/dovehash.d.ts b/server/types/dovehash.d.ts deleted file mode 100644 index c354609c0..000000000 --- a/server/types/dovehash.d.ts +++ /dev/null @@ -1,4 +0,0 @@ - -declare module "dovehash" { - function encode(algo: string, text: string): string; -} \ No newline at end of file diff --git a/server/types/speakeasy.d.ts b/server/types/speakeasy.d.ts deleted file mode 100644 index 6ea06948b..000000000 --- a/server/types/speakeasy.d.ts +++ /dev/null @@ -1,96 +0,0 @@ -declare module "speakeasy" { - export = speakeasy - - interface SharedOptions { - encoding?: string - algorithm?: string - } - - interface DigestOptions extends SharedOptions { - secret: string - counter: number - } - - interface HOTPOptions extends SharedOptions { - secret: string - counter: number - digest?: Buffer - digits?: number - } - - interface HOTPVerifyOptions extends SharedOptions { - secret: string - token: string - counter: number - digits?: number - window?: number - } - - interface TOTPOptions extends SharedOptions { - secret: string - time?: number - step?: number - epoch?: number - counter?: number - digits?: number - } - - interface TOTPVerifyOptions extends SharedOptions { - secret: string - token: string - time?: number - step?: number - epoch?: number - counter?: number - digits?: number - window?: number - } - - interface GenerateSecretOptions { - length?: number - symbols?: boolean - otpauth_url?: boolean - name?: string - issuer?: string - } - - interface GeneratedSecret { - ascii: string - hex: string - base32: string - qr_code_ascii: string - qr_code_hex: string - qr_code_base32: string - google_auth_qr: string - otpauth_url: string - } - - interface OTPAuthURLOptions extends SharedOptions { - secret: string - label: string - type?: string - counter?: number - issuer?: string - digits?: number - period?: number - } - - interface Speakeasy { - digest: (options: DigestOptions) => Buffer - hotp: { - (options: HOTPOptions): string, - verifyDelta: (options: HOTPVerifyOptions) => boolean, - verify: (options: HOTPVerifyOptions) => boolean, - } - totp: { - (options: TOTPOptions): string - verifyDelta: (options: TOTPVerifyOptions) => boolean, - verify: (options: TOTPVerifyOptions) => boolean, - } - generateSecret: (options?: GenerateSecretOptions) => GeneratedSecret - generateSecretASCII: (length?: number, symbols?: boolean) => string - otpauthURL: (options: OTPAuthURLOptions) => string - } - - const speakeasy: Speakeasy -} \ No newline at end of file diff --git a/session/const.go b/session/const.go new file mode 100644 index 000000000..eb4c75e26 --- /dev/null +++ b/session/const.go @@ -0,0 +1,3 @@ +package session + +const userSessionStorerKey = "UserSession" diff --git a/session/mocks/mock_storer.go b/session/mocks/mock_storer.go new file mode 100644 index 000000000..416f31625 --- /dev/null +++ b/session/mocks/mock_storer.go @@ -0,0 +1,207 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/fasthttp/session (interfaces: Storer) + +// Package mock_session is a generated GoMock package. +package mock_session + +import ( + session "github.com/fasthttp/session" + gomock "github.com/golang/mock/gomock" + reflect "reflect" + time "time" +) + +// MockStorer is a mock of Storer interface +type MockStorer struct { + ctrl *gomock.Controller + recorder *MockStorerMockRecorder +} + +// MockStorerMockRecorder is the mock recorder for MockStorer +type MockStorerMockRecorder struct { + mock *MockStorer +} + +// NewMockStorer creates a new mock instance +func NewMockStorer(ctrl *gomock.Controller) *MockStorer { + mock := &MockStorer{ctrl: ctrl} + mock.recorder = &MockStorerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockStorer) EXPECT() *MockStorerMockRecorder { + return m.recorder +} + +// Delete mocks base method +func (m *MockStorer) Delete(arg0 string) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Delete", arg0) +} + +// Delete indicates an expected call of Delete +func (mr *MockStorerMockRecorder) Delete(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockStorer)(nil).Delete), arg0) +} + +// DeleteBytes mocks base method +func (m *MockStorer) DeleteBytes(arg0 []byte) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "DeleteBytes", arg0) +} + +// DeleteBytes indicates an expected call of DeleteBytes +func (mr *MockStorerMockRecorder) DeleteBytes(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteBytes", reflect.TypeOf((*MockStorer)(nil).DeleteBytes), arg0) +} + +// Flush mocks base method +func (m *MockStorer) Flush() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Flush") +} + +// Flush indicates an expected call of Flush +func (mr *MockStorerMockRecorder) Flush() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Flush", reflect.TypeOf((*MockStorer)(nil).Flush)) +} + +// Get mocks base method +func (m *MockStorer) Get(arg0 string) interface{} { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Get", arg0) + ret0, _ := ret[0].(interface{}) + return ret0 +} + +// Get indicates an expected call of Get +func (mr *MockStorerMockRecorder) Get(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockStorer)(nil).Get), arg0) +} + +// GetAll mocks base method +func (m *MockStorer) GetAll() session.Dict { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAll") + ret0, _ := ret[0].(session.Dict) + return ret0 +} + +// GetAll indicates an expected call of GetAll +func (mr *MockStorerMockRecorder) GetAll() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAll", reflect.TypeOf((*MockStorer)(nil).GetAll)) +} + +// GetBytes mocks base method +func (m *MockStorer) GetBytes(arg0 []byte) interface{} { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetBytes", arg0) + ret0, _ := ret[0].(interface{}) + return ret0 +} + +// GetBytes indicates an expected call of GetBytes +func (mr *MockStorerMockRecorder) GetBytes(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBytes", reflect.TypeOf((*MockStorer)(nil).GetBytes), arg0) +} + +// GetExpiration mocks base method +func (m *MockStorer) GetExpiration() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetExpiration") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// GetExpiration indicates an expected call of GetExpiration +func (mr *MockStorerMockRecorder) GetExpiration() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetExpiration", reflect.TypeOf((*MockStorer)(nil).GetExpiration)) +} + +// GetSessionID mocks base method +func (m *MockStorer) GetSessionID() []byte { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSessionID") + ret0, _ := ret[0].([]byte) + return ret0 +} + +// GetSessionID indicates an expected call of GetSessionID +func (mr *MockStorerMockRecorder) GetSessionID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSessionID", reflect.TypeOf((*MockStorer)(nil).GetSessionID)) +} + +// HasExpirationChanged mocks base method +func (m *MockStorer) HasExpirationChanged() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HasExpirationChanged") + ret0, _ := ret[0].(bool) + return ret0 +} + +// HasExpirationChanged indicates an expected call of HasExpirationChanged +func (mr *MockStorerMockRecorder) HasExpirationChanged() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasExpirationChanged", reflect.TypeOf((*MockStorer)(nil).HasExpirationChanged)) +} + +// Save mocks base method +func (m *MockStorer) Save() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Save") + ret0, _ := ret[0].(error) + return ret0 +} + +// Save indicates an expected call of Save +func (mr *MockStorerMockRecorder) Save() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Save", reflect.TypeOf((*MockStorer)(nil).Save)) +} + +// Set mocks base method +func (m *MockStorer) Set(arg0 string, arg1 interface{}) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Set", arg0, arg1) +} + +// Set indicates an expected call of Set +func (mr *MockStorerMockRecorder) Set(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Set", reflect.TypeOf((*MockStorer)(nil).Set), arg0, arg1) +} + +// SetBytes mocks base method +func (m *MockStorer) SetBytes(arg0 []byte, arg1 interface{}) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetBytes", arg0, arg1) +} + +// SetBytes indicates an expected call of SetBytes +func (mr *MockStorerMockRecorder) SetBytes(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetBytes", reflect.TypeOf((*MockStorer)(nil).SetBytes), arg0, arg1) +} + +// SetExpiration mocks base method +func (m *MockStorer) SetExpiration(arg0 time.Duration) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetExpiration", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetExpiration indicates an expected call of SetExpiration +func (mr *MockStorerMockRecorder) SetExpiration(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetExpiration", reflect.TypeOf((*MockStorer)(nil).SetExpiration), arg0) +} diff --git a/session/provider.go b/session/provider.go new file mode 100644 index 000000000..87ca835a6 --- /dev/null +++ b/session/provider.go @@ -0,0 +1,115 @@ +package session + +import ( + "encoding/json" + "time" + + "github.com/clems4ever/authelia/configuration/schema" + fasthttpsession "github.com/fasthttp/session" + "github.com/valyala/fasthttp" +) + +// Provider a session provider. +type Provider struct { + sessionHolder *fasthttpsession.Session +} + +// NewProvider instantiate a session provider given a configuration. +func NewProvider(configuration schema.SessionConfiguration) *Provider { + providerConfig := NewProviderConfig(configuration) + + provider := new(Provider) + provider.sessionHolder = fasthttpsession.New(providerConfig.config) + err := provider.sessionHolder.SetProvider(providerConfig.providerName, providerConfig.providerConfig) + if err != nil { + panic(err) + } + return provider +} + +// GetSession return the user session from a request +func (p *Provider) GetSession(ctx *fasthttp.RequestCtx) (UserSession, error) { + store, err := p.sessionHolder.Get(ctx) + + if err != nil { + return NewDefaultUserSession(), err + } + + userSessionJSON, ok := store.Get(userSessionStorerKey).([]byte) + + // If userSession is not yet defined we create the new session with default values + // and save it in the store. + if !ok { + userSession := NewDefaultUserSession() + store.Set(userSessionStorerKey, userSession) + return userSession, nil + } + + var userSession UserSession + err = json.Unmarshal(userSessionJSON, &userSession) + + if err != nil { + return NewDefaultUserSession(), err + } + + return userSession, nil +} + +// SaveSession save the user session. +func (p *Provider) SaveSession(ctx *fasthttp.RequestCtx, userSession UserSession) error { + store, err := p.sessionHolder.Get(ctx) + + if err != nil { + return err + } + + userSessionJSON, err := json.Marshal(userSession) + + if err != nil { + return err + } + + store.Set(userSessionStorerKey, userSessionJSON) + p.sessionHolder.Save(ctx, store) + return nil +} + +// RegenerateSession regenerate a session ID. +func (p *Provider) RegenerateSession(ctx *fasthttp.RequestCtx) error { + _, err := p.sessionHolder.Regenerate(ctx) + return err +} + +// DestroySession destroy a session ID and delete the cookie. +func (p *Provider) DestroySession(ctx *fasthttp.RequestCtx) error { + return p.sessionHolder.Destroy(ctx) +} + +// UpdateExpiration update the expiration of the cookie and session. +func (p *Provider) UpdateExpiration(ctx *fasthttp.RequestCtx, expiration time.Duration) error { + store, err := p.sessionHolder.Get(ctx) + + if err != nil { + return err + } + + err = store.SetExpiration(expiration) + + if err != nil { + return err + } + + p.sessionHolder.Save(ctx, store) + return nil +} + +// GetExpiration get the expiration of the current session. +func (p *Provider) GetExpiration(ctx *fasthttp.RequestCtx) (time.Duration, error) { + store, err := p.sessionHolder.Get(ctx) + + if err != nil { + return time.Duration(0), err + } + + return store.GetExpiration(), nil +} diff --git a/session/provider_config.go b/session/provider_config.go new file mode 100644 index 000000000..75358a326 --- /dev/null +++ b/session/provider_config.go @@ -0,0 +1,62 @@ +package session + +import ( + "time" + + "github.com/valyala/fasthttp" + + "github.com/clems4ever/authelia/configuration/schema" + "github.com/fasthttp/session" + "github.com/fasthttp/session/memory" + "github.com/fasthttp/session/redis" +) + +// NewProviderConfig creates a configuration for creating the session provider +func NewProviderConfig(configuration schema.SessionConfiguration) ProviderConfig { + config := session.NewDefaultConfig() + + // Override the cookie name. + config.CookieName = configuration.Name + + // Set the cookie to the given domain. + config.Domain = configuration.Domain + + // Only serve the header over HTTPS. + config.Secure = true + + if configuration.Expiration > 0 { + config.Expires = time.Duration(configuration.Expiration) * time.Second + } else { + // If Expiration is 0 then cookie expiration is disabled. + config.Expires = 0 + } + + // TODO(c.michaud): Make this configurable by giving the list of IPs that are trustable. + config.IsSecureFunc = func(*fasthttp.RequestCtx) bool { + return true + } + + var providerConfig session.ProviderConfig + var providerName string + + // If redis configuration is provided, then use the redis provider. + if configuration.Redis != nil { + providerName = "redis" + providerConfig = &redis.Config{ + Host: configuration.Redis.Host, + Port: configuration.Redis.Port, + Password: configuration.Redis.Password, + PoolSize: 8, + IdleTimeout: 300, + KeyPrefix: "authelia-session", + } + } else { // if no option is provided, use the memory provider. + providerName = "memory" + providerConfig = &memory.Config{} + } + return ProviderConfig{ + config: config, + providerName: providerName, + providerConfig: providerConfig, + } +} diff --git a/session/provider_config_test.go b/session/provider_config_test.go new file mode 100644 index 000000000..21a70645a --- /dev/null +++ b/session/provider_config_test.go @@ -0,0 +1,57 @@ +package session + +import ( + "testing" + "time" + + "github.com/clems4ever/authelia/configuration/schema" + "github.com/fasthttp/session/memory" + "github.com/fasthttp/session/redis" + "github.com/stretchr/testify/assert" +) + +func TestShouldCreateInMemorySessionProvider(t *testing.T) { + // The redis configuration is not provided so we create a in-memory provider. + configuration := schema.SessionConfiguration{} + configuration.Domain = "example.com" + configuration.Name = "my_session" + configuration.Expiration = 40 + providerConfig := NewProviderConfig(configuration) + + assert.Equal(t, "my_session", providerConfig.config.CookieName) + assert.Equal(t, "example.com", providerConfig.config.Domain) + assert.Equal(t, true, providerConfig.config.Secure) + assert.Equal(t, time.Duration(40)*time.Second, providerConfig.config.Expires) + assert.True(t, providerConfig.config.IsSecureFunc(nil)) + + assert.Equal(t, "memory", providerConfig.providerName) + assert.IsType(t, &memory.Config{}, providerConfig.providerConfig) +} + +func TestShouldCreateRedisSessionProvider(t *testing.T) { + // The redis configuration is not provided so we create a in-memory provider. + configuration := schema.SessionConfiguration{} + configuration.Domain = "example.com" + configuration.Name = "my_session" + configuration.Expiration = 40 + configuration.Redis = &schema.RedisSessionConfiguration{ + Host: "redis.example.com", + Port: 6379, + Password: "pass", + } + providerConfig := NewProviderConfig(configuration) + + assert.Equal(t, "my_session", providerConfig.config.CookieName) + assert.Equal(t, "example.com", providerConfig.config.Domain) + assert.Equal(t, true, providerConfig.config.Secure) + assert.Equal(t, time.Duration(40)*time.Second, providerConfig.config.Expires) + assert.True(t, providerConfig.config.IsSecureFunc(nil)) + + assert.Equal(t, "redis", providerConfig.providerName) + assert.IsType(t, &redis.Config{}, providerConfig.providerConfig) + + pConfig := providerConfig.providerConfig.(*redis.Config) + assert.Equal(t, "redis.example.com", pConfig.Host) + assert.Equal(t, int64(6379), pConfig.Port) + assert.Equal(t, "pass", pConfig.Password) +} diff --git a/session/provider_test.go b/session/provider_test.go new file mode 100644 index 000000000..30864f93c --- /dev/null +++ b/session/provider_test.go @@ -0,0 +1,49 @@ +package session + +import ( + "testing" + + "github.com/clems4ever/authelia/authentication" + + "github.com/stretchr/testify/assert" + + "github.com/valyala/fasthttp" + + "github.com/clems4ever/authelia/configuration/schema" +) + +func TestShouldInitializerSession(t *testing.T) { + ctx := &fasthttp.RequestCtx{} + configuration := schema.SessionConfiguration{} + configuration.Domain = "example.com" + configuration.Name = "my_session" + configuration.Expiration = 40 + + provider := NewProvider(configuration) + session, _ := provider.GetSession(ctx) + + assert.Equal(t, NewDefaultUserSession(), session) +} + +func TestShouldUpdateSession(t *testing.T) { + ctx := &fasthttp.RequestCtx{} + configuration := schema.SessionConfiguration{} + configuration.Domain = "example.com" + configuration.Name = "my_session" + configuration.Expiration = 40 + + provider := NewProvider(configuration) + session, _ := provider.GetSession(ctx) + + session.Username = "john" + session.AuthenticationLevel = authentication.TwoFactor + + _ = provider.SaveSession(ctx, session) + + session, _ = provider.GetSession(ctx) + + assert.Equal(t, UserSession{ + Username: "john", + AuthenticationLevel: authentication.TwoFactor, + }, session) +} diff --git a/session/types.go b/session/types.go new file mode 100644 index 000000000..33ab8e65d --- /dev/null +++ b/session/types.go @@ -0,0 +1,43 @@ +package session + +import ( + "github.com/clems4ever/authelia/authentication" + "github.com/fasthttp/session" + "github.com/tstranex/u2f" +) + +// ProviderConfig is the configuration used to create the session provider. +type ProviderConfig struct { + config *session.Config + providerName string + providerConfig session.ProviderConfig +} + +// UserSession is the structure representing the session of a user. +type UserSession struct { + Username string + // TODO(c.michaud): move groups out of the session. + Groups []string + Emails []string + + KeepMeLoggedIn bool + AuthenticationLevel authentication.Level + LastActivity int64 + + // The challenge generated in first step of U2F registration (after identity verification) or authentication. + // This is used reused in the second phase to check that the challenge has been completed. + U2FChallenge *u2f.Challenge + // The registration representing a U2F device in DB set after identity verification. + // This is used in second phase of a U2F authentication. + U2FRegistration *u2f.Registration + + // This boolean is set to true after identity verification and checked + // while doing the query actually updating the password. + PasswordResetUsername *string +} + +// Identity identity of the user who is being verified. +type Identity struct { + Username string + Email string +} diff --git a/session/user_session.go b/session/user_session.go new file mode 100644 index 000000000..4a537c14b --- /dev/null +++ b/session/user_session.go @@ -0,0 +1,12 @@ +package session + +import "github.com/clems4ever/authelia/authentication" + +// NewDefaultUserSession create a default user session. +func NewDefaultUserSession() UserSession { + return UserSession{ + KeepMeLoggedIn: false, + AuthenticationLevel: authentication.NotAuthenticated, + LastActivity: 0, + } +} diff --git a/spec-helper.js b/spec-helper.js deleted file mode 100644 index d43365b92..000000000 --- a/spec-helper.js +++ /dev/null @@ -1,3 +0,0 @@ -var colors = require('mocha/lib/reporters/base').colors; - colors['pass'] = 32; - colors['error stack'] = 34; \ No newline at end of file diff --git a/storage/errors.go b/storage/errors.go new file mode 100644 index 000000000..40473dc2b --- /dev/null +++ b/storage/errors.go @@ -0,0 +1,8 @@ +package storage + +import "errors" + +var ( + // ErrNoU2FDeviceHandle error thrown when no U2F device handle has been found in DB. + ErrNoU2FDeviceHandle = errors.New("No U2F device handle found") +) diff --git a/storage/mongo_provider.go b/storage/mongo_provider.go new file mode 100644 index 000000000..4326929eb --- /dev/null +++ b/storage/mongo_provider.go @@ -0,0 +1,379 @@ +package storage + +import ( + "context" + "time" + + "github.com/clems4ever/authelia/configuration/schema" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + + "github.com/clems4ever/authelia/models" +) + +const ( + prefered2FAMethodCollection = "prefered_2fa_method" + identityValidationTokensCollection = "identity_validation_tokens" + authenticationLogsCollection = "authentication_logs" + u2fRegistrationsCollection = "u2f_devices" + totpSecretsCollection = "totp_secrets" +) + +// MongoProvider is a storage provider persisting data in a SQLite database. +type MongoProvider struct { + configuration schema.MongoStorageConfiguration +} + +// NewMongoProvider construct a mongo provider. +func NewMongoProvider(configuration schema.MongoStorageConfiguration) *MongoProvider { + return &MongoProvider{configuration} +} + +func (p *MongoProvider) connect() (*mongo.Client, error) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + clientOptions := options.Client().ApplyURI(p.configuration.URL) + + if p.configuration.Auth.Username != "" && p.configuration.Auth.Password != "" { + credentials := options.Credential{ + Username: p.configuration.Auth.Username, + Password: p.configuration.Auth.Password, + } + clientOptions.SetAuth(credentials) + } + return mongo.Connect(ctx, clientOptions) +} + +type prefered2FAMethodDocument struct { + UserID string `bson:"userId"` + Method string `bson:"method"` +} + +// LoadPrefered2FAMethod load the prefered method for 2FA from sqlite db. +func (p *MongoProvider) LoadPrefered2FAMethod(username string) (string, error) { + client, err := p.connect() + if err != nil { + return "", nil + } + defer client.Disconnect(context.Background()) + + collection := client. + Database(p.configuration.Database). + Collection(prefered2FAMethodCollection) + + res := prefered2FAMethodDocument{} + err = collection.FindOne(context.Background(), + bson.M{"userId": username}). + Decode(&res) + + if err != nil { + if err == mongo.ErrNoDocuments { + return "", nil + } + return "", err + } + + return res.Method, nil +} + +// SavePrefered2FAMethod save the prefered method for 2FA in sqlite db. +func (p *MongoProvider) SavePrefered2FAMethod(username string, method string) error { + client, err := p.connect() + if err != nil { + return nil + } + defer client.Disconnect(context.Background()) + + collection := client. + Database(p.configuration.Database). + Collection(prefered2FAMethodCollection) + + updateOptions := options.ReplaceOptions{} + updateOptions.SetUpsert(true) + _, err = collection.ReplaceOne(context.Background(), + bson.M{"userId": username}, + bson.M{"userId": username, "method": method}, + &updateOptions) + + if err != nil { + return err + } + + return nil +} + +// IdentityTokenDocument model for the identiy token documents. +type IdentityTokenDocument struct { + Token string `bson:"token"` +} + +// FindIdentityVerificationToken look for an identity verification token in DB. +func (p *MongoProvider) FindIdentityVerificationToken(token string) (bool, error) { + client, err := p.connect() + if err != nil { + return false, nil + } + defer client.Disconnect(context.Background()) + + collection := client. + Database(p.configuration.Database). + Collection(identityValidationTokensCollection) + + res := IdentityTokenDocument{} + err = collection.FindOne(context.Background(), + bson.M{"token": token}).Decode(&res) + + if err != nil { + if err == mongo.ErrNoDocuments { + return false, nil + } + return false, err + } + + return true, nil +} + +// SaveIdentityVerificationToken save an identity verification token in DB. +func (p *MongoProvider) SaveIdentityVerificationToken(token string) error { + client, err := p.connect() + if err != nil { + return nil + } + defer client.Disconnect(context.Background()) + + collection := client. + Database(p.configuration.Database). + Collection(identityValidationTokensCollection) + + options := options.InsertOneOptions{} + _, err = collection.InsertOne(context.Background(), + bson.M{"token": token}, + &options) + + if err != nil { + return err + } + + return nil +} + +// RemoveIdentityVerificationToken remove an identity verification token from the DB. +func (p *MongoProvider) RemoveIdentityVerificationToken(token string) error { + client, err := p.connect() + if err != nil { + return nil + } + defer client.Disconnect(context.Background()) + + collection := client. + Database(p.configuration.Database). + Collection(identityValidationTokensCollection) + + options := options.DeleteOptions{} + _, err = collection.DeleteOne(context.Background(), + bson.M{"token": token}, + &options) + + if err != nil { + return err + } + return nil +} + +// TOTPSecretDocument model of document storing TOTP secrets +type TOTPSecretDocument struct { + UserID string `bson:"userId"` + Secret string `bson:"secret"` +} + +// SaveTOTPSecret save a TOTP secret of a given user. +func (p *MongoProvider) SaveTOTPSecret(username string, secret string) error { + client, err := p.connect() + if err != nil { + return nil + } + defer client.Disconnect(context.Background()) + + collection := client. + Database(p.configuration.Database). + Collection(totpSecretsCollection) + + options := options.ReplaceOptions{} + options.SetUpsert(true) + _, err = collection.ReplaceOne(context.Background(), + bson.M{"userId": username}, + bson.M{"userId": username, "secret": secret}, + &options) + + if err != nil { + return err + } + + return nil +} + +// LoadTOTPSecret load a TOTP secret given a username. +func (p *MongoProvider) LoadTOTPSecret(username string) (string, error) { + client, err := p.connect() + if err != nil { + return "", nil + } + defer client.Disconnect(context.Background()) + + collection := client. + Database(p.configuration.Database). + Collection(totpSecretsCollection) + + res := TOTPSecretDocument{} + err = collection.FindOne(context.Background(), + bson.M{"userId": username}).Decode(&res) + + if err != nil { + if err == mongo.ErrNoDocuments { + return "", nil + } + return "", err + } + return res.Secret, nil +} + +// U2FDeviceDocument model of document storing U2F device +type U2FDeviceDocument struct { + UserID string `bson:"userId"` + DeviceHandle []byte `bson:"deviceHandle"` +} + +// SaveU2FDeviceHandle save a registered U2F device registration blob. +func (p *MongoProvider) SaveU2FDeviceHandle(username string, deviceBytes []byte) error { + client, err := p.connect() + if err != nil { + return nil + } + defer client.Disconnect(context.Background()) + + collection := client. + Database(p.configuration.Database). + Collection(u2fRegistrationsCollection) + + options := options.ReplaceOptions{} + options.SetUpsert(true) + + _, err = collection.ReplaceOne(context.Background(), + bson.M{"userId": username}, + bson.M{"userId": username, "deviceHandle": deviceBytes}, + &options) + + if err != nil { + return err + } + + return nil +} + +// LoadU2FDeviceHandle load a U2F device registration blob for a given username. +func (p *MongoProvider) LoadU2FDeviceHandle(username string) ([]byte, error) { + client, err := p.connect() + if err != nil { + return nil, nil + } + defer client.Disconnect(context.Background()) + + collection := client. + Database(p.configuration.Database). + Collection(u2fRegistrationsCollection) + + res := U2FDeviceDocument{} + err = collection.FindOne(context.Background(), + bson.M{"userId": username}).Decode(&res) + + if err != nil { + if err == mongo.ErrNoDocuments { + return nil, ErrNoU2FDeviceHandle + } + return nil, err + } + + return res.DeviceHandle, nil +} + +// AuthenticationLogDocument model of document storing authentication logs +type AuthenticationLogDocument struct { + UserID string `bson:"userId"` + Time time.Time `bson:"time"` + Success bool `bson:"success"` +} + +// AppendAuthenticationLog append a mark to the authentication log. +func (p *MongoProvider) AppendAuthenticationLog(attempt models.AuthenticationAttempt) error { + client, err := p.connect() + if err != nil { + return nil + } + defer client.Disconnect(context.Background()) + + collection := client. + Database(p.configuration.Database). + Collection(authenticationLogsCollection) + + options := options.InsertOneOptions{} + _, err = collection.InsertOne(context.Background(), + bson.M{ + "userId": attempt.Username, + "time": attempt.Time, + "success": attempt.Successful, + }, + &options) + + if err != nil { + return err + } + + return nil +} + +// LoadLatestAuthenticationLogs retrieve the latest marks from the authentication log. +func (p *MongoProvider) LoadLatestAuthenticationLogs(username string, fromDate time.Time) ([]models.AuthenticationAttempt, error) { + client, err := p.connect() + if err != nil { + return nil, nil + } + defer client.Disconnect(context.Background()) + + collection := client. + Database(p.configuration.Database). + Collection(authenticationLogsCollection) + + options := options.FindOptions{} + options.SetSort(bson.M{"time": -1}) + cursor, err := collection.Find(context.Background(), + bson.M{ + "$and": bson.M{ + "userId": username, + "time": bson.M{"$gt": fromDate}, + }, + }) + + if err != nil { + if err == mongo.ErrNoDocuments { + return nil, nil + } + return nil, err + } + + res := []AuthenticationLogDocument{} + cursor.All(context.Background(), &res) + + attempts := []models.AuthenticationAttempt{} + for _, r := range res { + attempt := models.AuthenticationAttempt{ + Username: r.UserID, + Time: r.Time, + Successful: r.Success, + } + attempts = append(attempts, attempt) + } + + return attempts, nil +} diff --git a/storage/provider.go b/storage/provider.go new file mode 100644 index 000000000..99ce3f949 --- /dev/null +++ b/storage/provider.go @@ -0,0 +1,27 @@ +package storage + +import ( + "time" + + "github.com/clems4ever/authelia/models" +) + +// Provider is an interface providing storage capabilities for +// persisting any kind of data related to Authelia. +type Provider interface { + LoadPrefered2FAMethod(username string) (string, error) + SavePrefered2FAMethod(username string, method string) error + + FindIdentityVerificationToken(token string) (bool, error) + SaveIdentityVerificationToken(token string) error + RemoveIdentityVerificationToken(token string) error + + SaveTOTPSecret(username string, secret string) error + LoadTOTPSecret(username string) (string, error) + + SaveU2FDeviceHandle(username string, device []byte) error + LoadU2FDeviceHandle(username string) ([]byte, error) + + AppendAuthenticationLog(attempt models.AuthenticationAttempt) error + LoadLatestAuthenticationLogs(username string, fromDate time.Time) ([]models.AuthenticationAttempt, error) +} diff --git a/storage/sqlite_provider.go b/storage/sqlite_provider.go new file mode 100644 index 000000000..5c5e9ae41 --- /dev/null +++ b/storage/sqlite_provider.go @@ -0,0 +1,229 @@ +package storage + +import ( + "database/sql" + "time" + + "github.com/clems4ever/authelia/models" + + "github.com/clems4ever/authelia/logging" + _ "github.com/mattn/go-sqlite3" // Load the SQLite Driver used in the connection string. +) + +// SQLiteProvider is a storage provider persisting data in a SQLite database. +type SQLiteProvider struct { + db *sql.DB +} + +// NewSQLiteProvider construct a sqlite provider. +func NewSQLiteProvider(path string) *SQLiteProvider { + provider := SQLiteProvider{} + err := provider.initialize(path) + if err != nil { + logging.Logger().Fatalf("Unable to create SQLite database %s: %s", path, err) + } + return &provider +} + +func (p *SQLiteProvider) initialize(path string) error { + db, err := sql.Open("sqlite3", path) + if err != nil { + return err + } + p.db = db + + _, err = db.Exec("CREATE TABLE IF NOT EXISTS SecondFactorPreferences (username VARCHAR(100) PRIMARY KEY, method VARCHAR(10))") + if err != nil { + return err + } + + _, err = db.Exec("CREATE TABLE IF NOT EXISTS IdentityVerificationTokens (token VARCHAR(512))") + if err != nil { + return err + } + + _, err = db.Exec("CREATE TABLE IF NOT EXISTS TOTPSecrets (username VARCHAR(100) PRIMARY KEY, secret VARCHAR(64))") + if err != nil { + return err + } + + _, err = db.Exec("CREATE TABLE IF NOT EXISTS U2FDeviceHandles (username VARCHAR(100) PRIMARY KEY, deviceHandle BLOB)") + if err != nil { + return err + } + + _, err = db.Exec("CREATE TABLE IF NOT EXISTS AuthenticationLogs (username VARCHAR(100), successful BOOL, time INTEGER)") + if err != nil { + return err + } + + _, err = db.Exec("CREATE INDEX IF NOT EXISTS time ON AuthenticationLogs (time);") + if err != nil { + return err + } + + _, err = db.Exec("CREATE INDEX IF NOT EXISTS username ON AuthenticationLogs (username);") + if err != nil { + return err + } + return nil +} + +// LoadPrefered2FAMethod load the prefered method for 2FA from sqlite db. +func (p *SQLiteProvider) LoadPrefered2FAMethod(username string) (string, error) { + stmt, err := p.db.Prepare("SELECT method FROM SecondFactorPreferences WHERE username=?") + if err != nil { + return "", err + } + rows, err := stmt.Query(username) + defer rows.Close() + if err != nil { + return "", err + } + if rows.Next() { + var method string + err = rows.Scan(&method) + if err != nil { + return "", err + } + return method, nil + } + return "", nil +} + +// SavePrefered2FAMethod save the prefered method for 2FA in sqlite db. +func (p *SQLiteProvider) SavePrefered2FAMethod(username string, method string) error { + stmt, err := p.db.Prepare("INSERT OR REPLACE INTO SecondFactorPreferences (username, method) VALUES (?, ?)") + if err != nil { + return err + } + _, err = stmt.Exec(username, method) + return err +} + +// FindIdentityVerificationToken look for an identity verification token in DB. +func (p *SQLiteProvider) FindIdentityVerificationToken(token string) (bool, error) { + stmt, err := p.db.Prepare("SELECT token FROM IdentityVerificationTokens WHERE token=?") + if err != nil { + return false, err + } + var found string + err = stmt.QueryRow(token).Scan(&found) + if err != nil { + if err == sql.ErrNoRows { + return false, nil + } + return false, err + } + return true, nil +} + +// SaveIdentityVerificationToken save an identity verification token in DB. +func (p *SQLiteProvider) SaveIdentityVerificationToken(token string) error { + stmt, err := p.db.Prepare("INSERT INTO IdentityVerificationTokens (token) VALUES (?)") + if err != nil { + return err + } + _, err = stmt.Exec(token) + return err +} + +// RemoveIdentityVerificationToken remove an identity verification token from the DB. +func (p *SQLiteProvider) RemoveIdentityVerificationToken(token string) error { + stmt, err := p.db.Prepare("DELETE FROM IdentityVerificationTokens WHERE token=?") + if err != nil { + return err + } + _, err = stmt.Exec(token) + return err +} + +// SaveTOTPSecret save a TOTP secret of a given user. +func (p *SQLiteProvider) SaveTOTPSecret(username string, secret string) error { + stmt, err := p.db.Prepare("INSERT OR REPLACE INTO TOTPSecrets (username, secret) VALUES (?, ?)") + if err != nil { + return err + } + _, err = stmt.Exec(username, secret) + return err +} + +// LoadTOTPSecret load a TOTP secret given a username. +func (p *SQLiteProvider) LoadTOTPSecret(username string) (string, error) { + stmt, err := p.db.Prepare("SELECT secret FROM TOTPSecrets WHERE username=?") + if err != nil { + return "", err + } + var secret string + err = stmt.QueryRow(username).Scan(&secret) + if err != nil { + if err == sql.ErrNoRows { + return "", nil + } + return "", err + } + return secret, nil +} + +// SaveU2FDeviceHandle save a registered U2F device registration blob. +func (p *SQLiteProvider) SaveU2FDeviceHandle(username string, keyHandle []byte) error { + stmt, err := p.db.Prepare("INSERT OR REPLACE INTO U2FDeviceHandles (username, deviceHandle) VALUES (?, ?)") + if err != nil { + return err + } + _, err = stmt.Exec(username, keyHandle) + return err +} + +// LoadU2FDeviceHandle load a U2F device registration blob for a given username. +func (p *SQLiteProvider) LoadU2FDeviceHandle(username string) ([]byte, error) { + stmt, err := p.db.Prepare("SELECT deviceHandle FROM U2FDeviceHandles WHERE username=?") + if err != nil { + return nil, err + } + var deviceHandle []byte + err = stmt.QueryRow(username).Scan(&deviceHandle) + if err != nil { + if err == sql.ErrNoRows { + return nil, ErrNoU2FDeviceHandle + } + return nil, err + } + return deviceHandle, nil +} + +// AppendAuthenticationLog append a mark to the authentication log. +func (p *SQLiteProvider) AppendAuthenticationLog(attempt models.AuthenticationAttempt) error { + stmt, err := p.db.Prepare("INSERT INTO AuthenticationLogs (username, successful, time) VALUES (?, ?, ?)") + if err != nil { + return err + } + _, err = stmt.Exec(attempt.Username, attempt.Successful, attempt.Time.Unix()) + return err +} + +// LoadLatestAuthenticationLogs retrieve the latest marks from the authentication log. +func (p *SQLiteProvider) LoadLatestAuthenticationLogs(username string, fromDate time.Time) ([]models.AuthenticationAttempt, error) { + rows, err := p.db.Query("SELECT successful, time FROM AuthenticationLogs WHERE time>? AND username=? ORDER BY time DESC", + fromDate.Unix(), username) + + if err != nil { + return nil, err + } + + attempts := make([]models.AuthenticationAttempt, 0, 10) + for rows.Next() { + attempt := models.AuthenticationAttempt{ + Username: username, + } + var t int64 + err = rows.Scan(&attempt.Successful, &t) + attempt.Time = time.Unix(t, 0) + + if err != nil { + return nil, err + } + attempts = append(attempts, attempt) + } + return attempts, nil +} diff --git a/templates/email.go b/templates/email.go new file mode 100644 index 000000000..7c161ff5b --- /dev/null +++ b/templates/email.go @@ -0,0 +1,420 @@ +package templates + +import ( + "text/template" +) + +// EmailTemplate the template of email that the user will receive for identity verification. +var EmailTemplate *template.Template + +func init() { + t, err := template.New("email_template").Parse(string(emailContent)) + if err != nil { + panic(err) + } + + EmailTemplate = t +} + +const emailContent = ` + + + + + + + Authelia + + + + + + + + + + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + +
  +
+ + + + + + + +
+

{{.title}}

+
+ +
  +
+
+
+ + + + + + + + +
+ + + + + + +
 
+
+ + + + + + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + +
  +
+ + + + + + + + + + + + + + + + + + +
+ This email has been sent to you in order to validate your identity. + If you did not initiate the process your credentials might have been compromised. You should reset your password and contact an administrator. +
+  
+ {{.button}} +
+
  +
+
+
+ + + + + + + + +
+ + + + + + + + + + + + +
 
 
 
+
+ + + + + + + + +
+ + + + + + +
+ + + + + + + + + + + +
+ Please ignore this email if you did not initiate the process. +
+
+
+ + + + +` diff --git a/test-resources/config.yml b/test-resources/config.yml new file mode 100644 index 000000000..8403a339d --- /dev/null +++ b/test-resources/config.yml @@ -0,0 +1,283 @@ +############################################################### +# Authelia configuration # +############################################################### + +# The port to listen on +port: 9091 + +# Log level +# +# Level of verbosity for logs +logs_level: debug + +jwt_secret: a_secret + +# Default redirection URL +# +# If user tries to authenticate without any referer, Authelia +# does not know where to redirect the user to at the end of the +# authentication process. +# This parameter allows you to specify the default redirection +# URL Authelia will use in such a case. +# +# Note: this parameter is optional. If not provided, user won't +# be redirected upon successful authentication. +default_redirection_url: https://home.example.com:8080/ + +# TOTP Issuer Name +# +# This will be the issuer name displayed in Google Authenticator +# See: https://github.com/google/google-authenticator/wiki/Key-Uri-Format for more info on issuer names +totp: + issuer: authelia.com + +# Duo Push API +# +# Parameters used to contact the Duo API. Those are generated when you protect an application +# of type "Partner Auth API" in the management panel. +duo_api: + hostname: api-123456789.example.com + integration_key: ABCDEF + secret_key: 1234567890abcdefghifjkl + +# The authentication backend to use for verifying user passwords +# and retrieve information such as email address and groups +# users belong to. +# +# There are two supported backends: `ldap` and `file`. +authentication_backend: + # LDAP backend configuration. + # + # This backend allows Authelia to be scaled to more + # than one instance and therefore is recommended for + # production. + ldap: + # The url of the ldap server + url: ldap://127.0.0.1 + + # The base dn for every entries + base_dn: dc=example,dc=com + + # An additional dn to define the scope to all users + additional_users_dn: ou=users + + # The users filter used to find the user DN + # {0} is a matcher replaced by username. + # 'cn={0}' by default. + users_filter: cn={0} + + # An additional dn to define the scope of groups + additional_groups_dn: ou=groups + + # The groups filter used for retrieving groups of a given user. + # {0} is a matcher replaced by username. + # {dn} is a matcher replaced by user DN. + # {uid} is a matcher replaced by user uid. + # 'member={dn}' by default. + groups_filter: (&(member={dn})(objectclass=groupOfNames)) + + # The attribute holding the name of the group + group_name_attribute: cn + + # The attribute holding the mail address of the user + mail_attribute: mail + + # The username and password of the admin user. + user: cn=admin,dc=example,dc=com + password: password + + # File backend configuration. + # + # With this backend, the users database is stored in a file + # which is updated when users reset their passwords. + # Therefore, this backend is meant to be used in a dev environment + # and not in production since it prevents Authelia to be scaled to + # more than one instance. + # + ## file: + ## path: ./users_database.yml + + +# Access Control +# +# Access control is a list of rules defining the authorizations applied for one +# resource to users or group of users. +# +# If 'access_control' is not defined, ACL rules are disabled and the `bypass` +# rule is applied, i.e., access is allowed to anyone. Otherwise restrictions follow +# the rules defined. +# +# Note: One can use the wildcard * to match any subdomain. +# It must stand at the beginning of the pattern. (example: *.mydomain.com) +# +# Note: You must put patterns containing wildcards between simple quotes for the YAML +# to be syntaxically correct. +# +# Definition: A `rule` is an object with the following keys: `domain`, `subject`, +# `policy` and `resources`. +# +# - `domain` defines which domain or set of domains the rule applies to. +# +# - `subject` defines the subject to apply authorizations to. This parameter is +# optional and matching any user if not provided. If provided, the parameter +# represents either a user or a group. It should be of the form 'user:' +# or 'group:'. +# +# - `policy` is the policy to apply to resources. It must be either `bypass`, +# `one_factor`, `two_factor` or `deny`. +# +# - `resources` is a list of regular expressions that matches a set of resources to +# apply the policy to. This parameter is optional and matches any resource if not +# provided. +# +# Note: the order of the rules is important. The first policy matching +# (domain, resource, subject) applies. +access_control: + # Default policy can either be `bypass`, `one_factor`, `two_factor` or `deny`. + # It is the policy applied to any resource if there is no policy to be applied + # to the user. + default_policy: deny + + rules: + # Rules applied to everyone + - domain: public.example.com + policy: bypass + + - domain: secure.example.com + policy: one_factor + # Network based rule, if not provided any network matches. + networks: + - 192.168.1.0/24 + - domain: secure.example.com + policy: two_factor + + - domain: singlefactor.example.com + policy: one_factor + + # Rules applied to 'admin' group + - domain: 'mx2.mail.example.com' + subject: 'group:admin' + policy: deny + - domain: '*.example.com' + subject: 'group:admin' + policy: two_factor + + # Rules applied to 'dev' group + - domain: dev.example.com + resources: + - '^/groups/dev/.*$' + subject: 'group:dev' + policy: two_factor + + # Rules applied to user 'john' + - domain: dev.example.com + resources: + - '^/users/john/.*$' + subject: 'user:john' + policy: two_factor + + + # Rules applied to user 'harry' + - domain: dev.example.com + resources: + - '^/users/harry/.*$' + subject: 'user:harry' + policy: two_factor + + # Rules applied to user 'bob' + - domain: '*.mail.example.com' + subject: 'user:bob' + policy: two_factor + - domain: 'dev.example.com' + resources: + - '^/users/bob/.*$' + subject: 'user:bob' + policy: two_factor + + +# Configuration of session cookies +# +# The session cookies identify the user once logged in. +session: + # The name of the session cookie. (default: authelia_session). + name: authelia_session + + # The secret to encrypt the session cookie. + secret: unsecure_session_secret + + # The time in ms before the cookie expires and session is reset. + expiration: 3600000 # 1 hour + + # The inactivity time in ms before the session is reset. + inactivity: 300000 # 5 minutes + + # The domain to protect. + # Note: the authenticator must also be in that domain. If empty, the cookie + # is restricted to the subdomain of the issuer. + domain: example.com + + # The redis connection details + redis: + host: 127.0.0.1 + port: 6379 + password: authelia + +# Configuration of the authentication regulation mechanism. +# +# This mechanism prevents attackers from brute forcing the first factor. +# It bans the user if too many attempts are done in a short period of +# time. +regulation: + # The number of failed login attempts before user is banned. + # Set it to 0 to disable regulation. + max_retries: 3 + + # The time range during which the user can attempt login before being banned. + # The user is banned if the authenticaction failed `max_retries` times in a `find_time` seconds window. + find_time: 120 + + # The length of time before a banned user can login again. + ban_time: 300 + +# Configuration of the storage backend used to store data and secrets. +# +# You must use only an available configuration: local, mongo +storage: + # The directory where the DB files will be saved + ## local: + ## path: /var/lib/authelia/store + + # Settings to connect to mongo server + mongo: + url: mongodb://127.0.0.1 + database: authelia + auth: + username: authelia + password: authelia + +# Configuration of the notification system. +# +# Notifications are sent to users when they require a password reset, a u2f +# registration or a TOTP registration. +# Use only an available configuration: filesystem, gmail +notifier: + # For testing purpose, notifications can be sent in a file + ## filesystem: + ## filename: /tmp/authelia/notification.txt + + # Use your email account to send the notifications. You can use an app password. + # List of valid services can be found here: https://nodemailer.com/smtp/well-known/ + ## email: + ## username: user@example.com + ## password: yourpassword + ## sender: admin@example.com + ## service: gmail + + # Use a SMTP server for sending notifications + smtp: + username: test + password: password + secure: false + host: 127.0.0.1 + port: 1025 + sender: admin@example.com diff --git a/test/helpers/ClickOnLink.ts b/test/helpers/ClickOnLink.ts index 50e056531..eee73bab0 100644 --- a/test/helpers/ClickOnLink.ts +++ b/test/helpers/ClickOnLink.ts @@ -3,6 +3,6 @@ import SeleniumWebdriver, { WebDriver } from "selenium-webdriver"; export default async function(driver: WebDriver, linkText: string, timeout: number = 5000) { const element = await driver.wait( SeleniumWebdriver.until.elementLocated( - SeleniumWebdriver.By.linkText(linkText)), timeout) + SeleniumWebdriver.By.linkText(linkText)), timeout); await element.click(); }; \ No newline at end of file diff --git a/test/helpers/GetIdentityLink.ts b/test/helpers/GetIdentityLink.ts index fe237dc23..e7162a553 100644 --- a/test/helpers/GetIdentityLink.ts +++ b/test/helpers/GetIdentityLink.ts @@ -25,7 +25,7 @@ export async function GetLinkFromEmail() { rejectUnauthorized: false, uri: `https://mail.example.com:8080/messages/${messageId}.html` }); - const regexp = new RegExp(/Continue<\/a>/); + const regexp = new RegExp(/.*<\/a>/); const match = regexp.exec(data2); if (match == null) { throw new Error('No match'); diff --git a/test/helpers/LoginAndRegisterTotp.ts b/test/helpers/LoginAndRegisterTotp.ts index 7a25c3a1c..5fa4326d4 100644 --- a/test/helpers/LoginAndRegisterTotp.ts +++ b/test/helpers/LoginAndRegisterTotp.ts @@ -6,5 +6,5 @@ import VerifyIsSecondFactorStage from './assertions/VerifyIsSecondFactorStage'; export default async function(driver: WebDriver, user: string, password: string, email: boolean = false, timeout: number = 5000) { await LoginAs(driver, user, password, undefined, timeout); await VerifyIsSecondFactorStage(driver, timeout); - return await RegisterTotp(driver, email, timeout); + return RegisterTotp(driver, email, timeout); } \ No newline at end of file diff --git a/test/helpers/Logout.ts b/test/helpers/Logout.ts index 2410ce8bf..69b116b6e 100644 --- a/test/helpers/Logout.ts +++ b/test/helpers/Logout.ts @@ -1,6 +1,8 @@ import { WebDriver } from "selenium-webdriver"; +import VerifyIsFirstFactorStage from "./assertions/VerifyIsFirstFactorStage"; import VisitPage from "./VisitPage"; export default async function(driver: WebDriver) { - await VisitPage(driver, `https://login.example.com:8080/#/logout`); + await VisitPage(driver, "https://login.example.com:8080/#/logout"); + await VerifyIsFirstFactorStage(driver); } \ No newline at end of file diff --git a/test/helpers/assertions/VerifyIsFirstFactorStage.ts b/test/helpers/assertions/VerifyIsFirstFactorStage.ts new file mode 100644 index 000000000..335d2be4a --- /dev/null +++ b/test/helpers/assertions/VerifyIsFirstFactorStage.ts @@ -0,0 +1,6 @@ +import SeleniumWebDriver, { WebDriver } from "selenium-webdriver"; + +export default async function(driver: WebDriver, timeout: number = 5000) { + await driver.wait(SeleniumWebDriver.until.elementLocated( + SeleniumWebDriver.By.className('first-factor-step')), timeout); +} \ No newline at end of file diff --git a/test/helpers/assertions/WaitUrlIs.ts b/test/helpers/assertions/WaitUrlIs.ts new file mode 100644 index 000000000..a6a8477b8 --- /dev/null +++ b/test/helpers/assertions/WaitUrlIs.ts @@ -0,0 +1,3 @@ +import VerifyUrlIs from "./VerifyUrlIs"; + +export default VerifyUrlIs; \ No newline at end of file diff --git a/test/helpers/behaviors/ClearFieldById.ts b/test/helpers/behaviors/ClearFieldById.ts new file mode 100644 index 000000000..dd45efed1 --- /dev/null +++ b/test/helpers/behaviors/ClearFieldById.ts @@ -0,0 +1,9 @@ +import SeleniumWebdriver, { WebDriver, Key, ActionSequence } from "selenium-webdriver"; + +export default async function(driver: WebDriver, fieldId: string, timeout: number = 5000) { + const element = await driver.wait( + SeleniumWebdriver.until.elementLocated( + SeleniumWebdriver.By.id(fieldId)), timeout) + + await element.sendKeys(Key.chord(Key.CONTROL, "a", Key.BACK_SPACE)); +}; \ No newline at end of file diff --git a/test/helpers/behaviors/RegisterAndLoginTwoFactor.ts b/test/helpers/behaviors/RegisterAndLoginTwoFactor.ts index 6f9846657..701398733 100644 --- a/test/helpers/behaviors/RegisterAndLoginTwoFactor.ts +++ b/test/helpers/behaviors/RegisterAndLoginTwoFactor.ts @@ -2,6 +2,9 @@ import { WebDriver } from "selenium-webdriver"; import LoginAndRegisterTotp from "../LoginAndRegisterTotp"; import FullLogin from "../FullLogin"; import VerifyUrlIs from "../assertions/VerifyUrlIs"; +import VisitPageAndWaitUrlIs from "./VisitPageAndWaitUrlIs"; +import ValidateTotp from "../ValidateTotp"; +import FillLoginPageAndClick from "../FillLoginPageAndClick"; export default async function( driver: WebDriver, @@ -12,7 +15,8 @@ export default async function( timeout: number = 5000) { const secret = await LoginAndRegisterTotp(driver, username, password, email, timeout); - await FullLogin(driver, username, secret, targetUrl, timeout); + await VisitPageAndWaitUrlIs(driver, `https://login.example.com:8080/#/?rd=${targetUrl}`, timeout); + await ValidateTotp(driver, secret, timeout); await VerifyUrlIs(driver, targetUrl, timeout); return secret; }; \ No newline at end of file diff --git a/test/helpers/behaviors/ResetPassword.ts b/test/helpers/behaviors/ResetPassword.ts new file mode 100644 index 000000000..1111680f5 --- /dev/null +++ b/test/helpers/behaviors/ResetPassword.ts @@ -0,0 +1,23 @@ +import SeleniumWebDriver from "selenium-webdriver" +import VisitPageAndWaitUrlIs from "./VisitPageAndWaitUrlIs"; +import ClickOnLink from "../ClickOnLink"; +import VerifyUrlIs from "../assertions/VerifyUrlIs"; +import FillField from "../FillField"; +import ClickOn from "../ClickOn"; +import { GetLinkFromEmail } from "../GetIdentityLink"; + +export default async function(driver: SeleniumWebDriver.WebDriver, username: string, password: string, timeout: number = 5000) { + await VisitPageAndWaitUrlIs(driver, "https://login.example.com:8080/#/"); + await ClickOnLink(driver, "Forgot password\?"); + await VerifyUrlIs(driver, "https://login.example.com:8080/#/forgot-password"); + await FillField(driver, "username", username); + await ClickOn(driver, SeleniumWebDriver.By.id('next-button')); + await VerifyUrlIs(driver, 'https://login.example.com:8080/#/confirmation-sent'); + + await driver.sleep(500); // Simulate the time it takes to receive the e-mail. + const link = await GetLinkFromEmail(); + await VisitPageAndWaitUrlIs(driver, link); + await FillField(driver, "password1", password); + await FillField(driver, "password2", password); + await ClickOn(driver, SeleniumWebDriver.By.id('reset-button')); +} \ No newline at end of file diff --git a/test/helpers/context/AutheliaServerFromDist.ts b/test/helpers/context/AutheliaServerFromDist.ts index 6e0954d08..1c1767daf 100644 --- a/test/helpers/context/AutheliaServerFromDist.ts +++ b/test/helpers/context/AutheliaServerFromDist.ts @@ -14,10 +14,12 @@ class AutheliaServerFromDist implements AutheliaServerInterface { } async start() { + console.log("Spawn authelia server from dist."); this.serverProcess = ChildProcess.spawn('./scripts/authelia-scripts serve ' + this.configPath, { shell: true, env: process.env, } as any); + if (!this.serverProcess || !this.serverProcess.stdout || !this.serverProcess.stderr) return; if (this.logInFile) { var logStream = fs.createWriteStream('/tmp/authelia-server.log', {flags: 'a'}); this.serverProcess.stdout.pipe(logStream); diff --git a/test/helpers/context/AutheliaServerWithHotReload.ts b/test/helpers/context/AutheliaServerWithHotReload.ts index 000ae0c84..7281f9a8b 100644 --- a/test/helpers/context/AutheliaServerWithHotReload.ts +++ b/test/helpers/context/AutheliaServerWithHotReload.ts @@ -1,6 +1,5 @@ import Chokidar from 'chokidar'; import fs from 'fs'; -import { exec } from '../utils/exec'; import ChildProcess from 'child_process'; import kill from 'tree-kill'; import AutheliaServerInterface from './AutheliaServerInterface'; @@ -14,10 +13,11 @@ class AutheliaServerWithHotReload implements AutheliaServerInterface { private clientProcess: ChildProcess.ChildProcess | undefined; private filesChangedBuffer: string[] = []; private changeInProgress: boolean = false; + private isInterrupted: boolean = false constructor(configPath: string, watchedPaths: string[]) { this.configPath = configPath; - const pathsToReload = ['server', 'node_modules', + const pathsToReload = ['**/*.go', this.AUTHELIA_INTERRUPT_FILENAME, configPath].concat(watchedPaths); console.log("Authelia will reload on changes of files or directories in " + pathsToReload.join(', ')); this.watcher = Chokidar.watch(pathsToReload, { @@ -28,14 +28,14 @@ class AutheliaServerWithHotReload implements AutheliaServerInterface { private async startServer() { if (this.serverProcess) return; - await exec('./node_modules/.bin/tslint -c server/tslint.json -p server/tsconfig.json') - this.serverProcess = ChildProcess.spawn('./node_modules/.bin/ts-node', - ['-P', './server/tsconfig.json', './server/src/index.ts', this.configPath], { + this.serverProcess = ChildProcess.spawn('go', + ['run', 'main.go', '-config', this.configPath], { env: { ...process.env, - NODE_TLS_REJECT_UNAUTHORIZED: 0, + NODE_TLS_REJECT_UNAUTHORIZED: "0", }, }); + if (!this.serverProcess || !this.serverProcess.stdout || !this.serverProcess.stderr) return; this.serverProcess.stdout.pipe(process.stdout); this.serverProcess.stderr.pipe(process.stderr); this.serverProcess.on('exit', () => { @@ -77,6 +77,7 @@ class AutheliaServerWithHotReload implements AutheliaServerInterface { 'BROWSER': 'none' } }); + if (!this.clientProcess || !this.clientProcess.stdout || !this.clientProcess.stderr) return; this.clientProcess.stdout.pipe(process.stdout); this.clientProcess.stderr.pipe(process.stderr); this.clientProcess.on('exit', () => { @@ -108,36 +109,27 @@ class AutheliaServerWithHotReload implements AutheliaServerInterface { }); } - private async generateConfigurationSchema() { - await exec('./node_modules/.bin/typescript-json-schema -o ' + - 'server/src/lib/configuration/Configuration.schema.json ' + - '--strictNullChecks --required server/tsconfig.json Configuration'); - } - /** * Handle file changes. * @param path The path of the file that has been changed. */ - private onFilesChanged = async (paths: string[]) => { - const containsSchemaFiles = paths.filter( - (p) => p.startsWith('server/src/lib/configuration/schema')).length > 0; - if (containsSchemaFiles) { - console.log('Schema needs to be regenerated.'); - await this.generateConfigurationSchema(); - } - - const interruptFile = paths.filter( + private onFilesChanged = async (paths: string[]) => { + const interruptFileExist = fs.existsSync(this.AUTHELIA_INTERRUPT_FILENAME); + const interruptFileModified = paths.filter( (p) => p === this.AUTHELIA_INTERRUPT_FILENAME).length > 0; - if (interruptFile) { - if (fs.existsSync(this.AUTHELIA_INTERRUPT_FILENAME)) { - console.log('Authelia is being interrupted.'); - await this.killServer(); - } else { + if (interruptFileExist) { + if (interruptFileModified) { + console.log('Authelia is being interrupted.'); + this.isInterrupted = true; + await this.killServer(); + } + return; + } else if (this.isInterrupted && interruptFileModified && !interruptFileExist){ console.log('Authelia is restarting.'); await this.startServer(); + this.isInterrupted = false; + return; } - return; - } await this.killServer(); await this.startServer(); diff --git a/test/helpers/context/AutheliaSuite.ts b/test/helpers/context/AutheliaSuite.ts index 121064f26..c00cfa1c6 100644 --- a/test/helpers/context/AutheliaSuite.ts +++ b/test/helpers/context/AutheliaSuite.ts @@ -1,5 +1,3 @@ -import fs from 'fs'; - interface AutheliaSuiteType { (suitePath: string, cb: (this: Mocha.ISuiteCallbackContext) => void): Mocha.ISuite; only: (suitePath: string, cb: (this: Mocha.ISuiteCallbackContext) => void) => Mocha.ISuite; diff --git a/test/helpers/scenarii/AuthenticationBlacklisting.ts b/test/helpers/scenarii/AuthenticationBlacklisting.ts new file mode 100644 index 000000000..392f96e1f --- /dev/null +++ b/test/helpers/scenarii/AuthenticationBlacklisting.ts @@ -0,0 +1,45 @@ +import { StartDriver, StopDriver } from "../../helpers/context/WithDriver"; +import LoginAs from "../../helpers/LoginAs"; +import VerifyNotificationDisplayed from "../../helpers/assertions/VerifyNotificationDisplayed"; +import VerifyIsSecondFactorStage from "../../helpers/assertions/VerifyIsSecondFactorStage"; +import ClearFieldById from "../behaviors/ClearFieldById"; + +export default function(regulationMilliseconds: number) { + return function () { + describe('Authelia regulates authentications when a hacker is brute forcing', function() { + this.timeout(30000); + beforeEach(async function() { + this.driver = await StartDriver(); + }); + + afterEach(async function() { + await StopDriver(this.driver); + }); + + it("should return an error message when providing correct credentials the 4th time.", async function() { + await LoginAs(this.driver, "james", "bad-password"); + await VerifyNotificationDisplayed(this.driver, "Authentication failed. Check your credentials."); + await ClearFieldById(this.driver, "username"); + + await LoginAs(this.driver, "james", "bad-password"); + await VerifyNotificationDisplayed(this.driver, "Authentication failed. Check your credentials."); + await ClearFieldById(this.driver, "username"); + + await LoginAs(this.driver, "james", "bad-password"); + await VerifyNotificationDisplayed(this.driver, "Authentication failed. Check your credentials."); + await ClearFieldById(this.driver, "username"); + + // when providing good credentials, the hacker is regulated and see same message as previously. + await LoginAs(this.driver, "james", "bad-password"); + await VerifyNotificationDisplayed(this.driver, "Authentication failed. Check your credentials."); + await ClearFieldById(this.driver, "username"); + + // Wait the regulation ban time before retrying with correct credentials. + // It should authenticate normally. + await this.driver.sleep(regulationMilliseconds); + await LoginAs(this.driver, "james", "password"); + await VerifyIsSecondFactorStage(this.driver); + }); + }); + } +} \ No newline at end of file diff --git a/test/helpers/utils/Requests.ts b/test/helpers/utils/Requests.ts index 51a334899..1605a4dd1 100644 --- a/test/helpers/utils/Requests.ts +++ b/test/helpers/utils/Requests.ts @@ -27,11 +27,15 @@ export async function GET_Expect401(url: string, headers: {[key: string]: string return await GET_ExpectError(url, headers, 401); } +export async function GET_Expect403(url: string, headers: {[key: string]: string} = {}) { + return await GET_ExpectError(url, headers, 403); +} + export async function GET_Expect502(url: string, headers: {[key: string]: string} = {}) { return await GET_ExpectError(url, headers, 502); } -export async function POST_Expect401(url: string, body?: any) { +export async function POST_Expect403(url: string, body?: any) { try { await Request.post(url, { json: true, @@ -41,7 +45,7 @@ export async function POST_Expect401(url: string, body?: any) { throw new Error('No response'); } catch (e) { if (e instanceof StatusCodeError) { - Assert.equal(e.statusCode, 401); + Assert.equal(e.statusCode, 403); return; } } diff --git a/test/helpers/utils/WaitUntil.ts b/test/helpers/utils/WaitUntil.ts index ea8679a25..1c4c81262 100644 --- a/test/helpers/utils/WaitUntil.ts +++ b/test/helpers/utils/WaitUntil.ts @@ -2,10 +2,12 @@ import sleep from "./sleep"; export default function WaitUntil( fn: () => Promise, timeout: number = 15000, - interval: number = 1000, waitAfter: number = 0): Promise { + interval: number = 1000, waitBefore: number = 0, waitAfter: number = 0): Promise { return new Promise(async (resolve, reject) => { const timer = setTimeout(() => { throw new Error('Timeout') }, timeout); + if (waitBefore > 0) + await sleep(waitBefore); while (true) { try { const res = await fn(); diff --git a/test/suites/basic-bypass-no-redirect/config.yml b/test/suites/basic-bypass-no-redirect/config.yml index bc4ace586..147176855 100644 --- a/test/suites/basic-bypass-no-redirect/config.yml +++ b/test/suites/basic-bypass-no-redirect/config.yml @@ -6,6 +6,8 @@ port: 9091 logs_level: debug +jwt_secret: unsecure_secret + authentication_backend: file: path: ./test/suites/basic/users_database.test.yml @@ -18,7 +20,7 @@ session: storage: local: - path: /tmp/authelia/db + path: /tmp/authelia/db.sqlite # The Duo Push Notification API configuration duo_api: @@ -36,9 +38,6 @@ access_control: notifier: smtp: - username: test - password: password - secure: false host: 127.0.0.1 port: 1025 sender: admin@example.com diff --git a/test/suites/basic-bypass-no-redirect/environment.ts b/test/suites/basic-bypass-no-redirect/environment.ts index e37101e48..989981cb0 100644 --- a/test/suites/basic-bypass-no-redirect/environment.ts +++ b/test/suites/basic-bypass-no-redirect/environment.ts @@ -18,7 +18,6 @@ const dockerEnv = new DockerEnvironment([ async function setup() { await exec(`cp ${__dirname}/users_database.yml ${__dirname}/users_database.test.yml`); - await exec('mkdir -p /tmp/authelia/db'); await exec('./example/compose/nginx/portal/render.js ' + (fs.existsSync('.suite') ? '': '--production')); await dockerEnv.start(); await autheliaServer.start(); @@ -27,7 +26,6 @@ async function setup() { async function teardown() { await autheliaServer.stop(); await dockerEnv.stop(); - await exec('rm -rf /tmp/authelia/db'); } const setup_timeout = 30000; diff --git a/test/suites/basic/config.yml b/test/suites/basic/config.yml index 122f100b2..a7d5d9b8d 100644 --- a/test/suites/basic/config.yml +++ b/test/suites/basic/config.yml @@ -8,6 +8,8 @@ logs_level: debug default_redirection_url: https://home.example.com:8080/ +jwt_secret: very_important_secret + authentication_backend: file: path: ./test/suites/basic/users_database.test.yml @@ -15,13 +17,13 @@ authentication_backend: session: secret: unsecure_session_secret domain: example.com - expiration: 3600000 # 1 hour - inactivity: 300000 # 5 minutes + expiration: 3600 # 1 hour + inactivity: 300 # 5 minutes # Configuration of the storage backend used to store data and secrets. i.e. totp data storage: local: - path: /tmp/authelia/db + path: /tmp/authelia/db.sqlite3 # TOTP Issuer Name # @@ -89,9 +91,6 @@ regulation: notifier: # Use a SMTP server for sending notifications smtp: - username: test - password: password - secure: false host: 127.0.0.1 port: 1025 sender: admin@example.com diff --git a/test/suites/basic/environment.ts b/test/suites/basic/environment.ts index cc2bb83fb..fd00f93c5 100644 --- a/test/suites/basic/environment.ts +++ b/test/suites/basic/environment.ts @@ -13,7 +13,6 @@ const dockerEnv = new DockerEnvironment([ async function setup() { await exec(`cp ${__dirname}/users_database.yml ${__dirname}/users_database.test.yml`); - await exec('mkdir -p /tmp/authelia/db'); await exec('./example/compose/nginx/portal/render.js ' + (fs.existsSync('.suite') ? '': '--production')); await dockerEnv.start(); await autheliaServer.start(); @@ -22,7 +21,6 @@ async function setup() { async function teardown() { await autheliaServer.stop(); await dockerEnv.stop(); - await exec('rm -rf /tmp/authelia/db'); } const setup_timeout = 30000; diff --git a/test/suites/basic/scenarii/LogoutRedirectToAlreadyLoggedIn.ts b/test/suites/basic/scenarii/AlreadyLoggedIn.ts similarity index 83% rename from test/suites/basic/scenarii/LogoutRedirectToAlreadyLoggedIn.ts rename to test/suites/basic/scenarii/AlreadyLoggedIn.ts index 8bd8874c9..937f2b467 100644 --- a/test/suites/basic/scenarii/LogoutRedirectToAlreadyLoggedIn.ts +++ b/test/suites/basic/scenarii/AlreadyLoggedIn.ts @@ -5,7 +5,7 @@ import RegisterAndLoginTwoFactor from "../../../helpers/behaviors/RegisterAndLog export default function() { - describe('When visiting /logout the user is redirected to already logged in page to log out', function() { + describe('When visiting https://login.example.com:8080/#/ while authenticated, the user is redirected to already logged in page', function() { before(async function() { this.driver = await StartDriver(); await RegisterAndLoginTwoFactor(this.driver, 'john', "password", true); @@ -16,7 +16,7 @@ export default function() { }); it('should redirect the user', async function() { - await VisitPage(this.driver, 'https://login.example.com:8080/#/logout'); + await VisitPage(this.driver, 'https://login.example.com:8080/#/'); await VerifyIsAlreadyAuthenticatedStage(this.driver); }); }); diff --git a/test/suites/basic/scenarii/BackendProtection.ts b/test/suites/basic/scenarii/BackendProtection.ts index 8de7c4ff3..bb32e777e 100644 --- a/test/suites/basic/scenarii/BackendProtection.ts +++ b/test/suites/basic/scenarii/BackendProtection.ts @@ -1,45 +1,51 @@ -import { POST_Expect401, GET_Expect401 } from "../../../helpers/utils/Requests"; +import { POST_Expect403, GET_Expect403 } from "../../../helpers/utils/Requests"; export default function() { // POST - it('should return 401 error when posting to https://login.example.com:8080/api/totp', async function() { - await POST_Expect401('https://login.example.com:8080/api/totp', { token: 'MALICIOUS_TOKEN' }); + it('should return 403 error when posting to https://login.example.com:8080/api/secondfactor/totp', async function() { + await POST_Expect403('https://login.example.com:8080/api/secondfactor/totp', { token: 'MALICIOUS_TOKEN' }); }); - it('should return 401 error when posting to https://login.example.com:8080/api/u2f/sign', async function() { - await POST_Expect401('https://login.example.com:8080/api/u2f/sign'); + it('should return 403 error when posting to https://login.example.com:8080/api/secondfactor/u2f/sign', async function() { + await POST_Expect403('https://login.example.com:8080/api/secondfactor/u2f/sign'); }); - it('should return 401 error when posting to https://login.example.com:8080/api/u2f/register', async function() { - await POST_Expect401('https://login.example.com:8080/api/u2f/register'); + it('should return 403 error when posting to https://login.example.com:8080/api/secondfactor/u2f/register', async function() { + await POST_Expect403('https://login.example.com:8080/api/secondfactor/u2f/register'); }); - - // GET - it('should return 401 error on GET to https://login.example.com:8080/api/u2f/sign_request', async function() { - await GET_Expect401('https://login.example.com:8080/api/u2f/sign_request'); + it('should return 403 error on GET to https://login.example.com:8080/api/secondfactor/u2f/sign_request', async function() { + await POST_Expect403('https://login.example.com:8080/api/secondfactor/u2f/sign_request'); }); - it('should return 401 error on GET to https://login.example.com:8080/api/u2f/register_request', async function() { - await GET_Expect401('https://login.example.com:8080/api/u2f/register_request'); + it('should return 403 error when posting to https://login.example.com:8080/api/secondfactor/preferences', async function() { + await POST_Expect403('https://login.example.com:8080/api/secondfactor/preferences'); + }); + + it('should return 403 error on GET to https://login.example.com:8080/api/secondfactor/preferences', async function() { + await GET_Expect403('https://login.example.com:8080/api/secondfactor/preferences'); + }); + + it('should return 403 error on GET to https://login.example.com:8080/api/secondfactor/available', async function() { + await GET_Expect403('https://login.example.com:8080/api/secondfactor/available'); }); describe('Identity validation endpoints blocked to unauthenticated users', function() { - it('should return 401 error on POST to https://login.example.com:8080/api/secondfactor/u2f/identity/start', async function() { - await POST_Expect401('https://login.example.com:8080/api/secondfactor/u2f/identity/start'); + it('should return 403 error on POST to https://login.example.com:8080/api/secondfactor/u2f/identity/start', async function() { + await POST_Expect403('https://login.example.com:8080/api/secondfactor/u2f/identity/start'); }); - it('should return 401 error on POST to https://login.example.com:8080/api/secondfactor/u2f/identity/finish', async function() { - await POST_Expect401('https://login.example.com:8080/api/secondfactor/u2f/identity/finish'); + it('should return 403 error on POST to https://login.example.com:8080/api/secondfactor/u2f/identity/finish', async function() { + await POST_Expect403('https://login.example.com:8080/api/secondfactor/u2f/identity/finish'); }); - it('should return 401 error on POST to https://login.example.com:8080/api/secondfactor/totp/identity/start', async function() { - await POST_Expect401('https://login.example.com:8080/api/secondfactor/totp/identity/start'); + it('should return 403 error on POST to https://login.example.com:8080/api/secondfactor/totp/identity/start', async function() { + await POST_Expect403('https://login.example.com:8080/api/secondfactor/totp/identity/start'); }); - it('should return 401 error on POST to https://login.example.com:8080/api/secondfactor/totp/identity/finish', async function() { - await POST_Expect401('https://login.example.com:8080/api/secondfactor/totp/identity/finish'); + it('should return 403 error on POST to https://login.example.com:8080/api/secondfactor/totp/identity/finish', async function() { + await POST_Expect403('https://login.example.com:8080/api/secondfactor/totp/identity/finish'); }); }); } \ No newline at end of file diff --git a/test/suites/basic/scenarii/BadPassword.ts b/test/suites/basic/scenarii/BadPassword.ts index b861a45d8..eeac44fa4 100644 --- a/test/suites/basic/scenarii/BadPassword.ts +++ b/test/suites/basic/scenarii/BadPassword.ts @@ -1,5 +1,4 @@ import FillLoginPageWithUserAndPasswordAndClick from '../../../helpers/FillLoginPageAndClick'; -import {AUTHENTICATION_FAILED} from '../../../../server/src/lib/UserMessages'; import VisitPageAndWaitUrlIs from '../../../helpers/behaviors/VisitPageAndWaitUrlIs'; import VerifyNotificationDisplayed from '../../../helpers/assertions/VerifyNotificationDisplayed'; import { StartDriver, StopDriver } from '../../../helpers/context/WithDriver'; @@ -23,7 +22,7 @@ export default function() { }) it('should get a notification message', async function () { - await VerifyNotificationDisplayed(this.driver, AUTHENTICATION_FAILED); + await VerifyNotificationDisplayed(this.driver, "Authentication failed. Check your credentials."); }); }); } diff --git a/test/suites/basic/scenarii/RegisterTotp.ts b/test/suites/basic/scenarii/RegisterTotp.ts index 636d5f888..4aa465e7c 100644 --- a/test/suites/basic/scenarii/RegisterTotp.ts +++ b/test/suites/basic/scenarii/RegisterTotp.ts @@ -2,6 +2,7 @@ import SeleniumWebdriver, { WebDriver } from "selenium-webdriver"; import Assert from 'assert'; import LoginAndRegisterTotp from '../../../helpers/LoginAndRegisterTotp'; import { StartDriver, StopDriver } from "../../../helpers/context/WithDriver"; +import sleep from "../../../helpers/utils/sleep"; /** * Given the user logs in as john, @@ -12,12 +13,12 @@ export default function() { describe('successfully login as john', function() { this.timeout(10000); - beforeEach(async function() { + before(async function() { this.driver = await StartDriver(); await LoginAndRegisterTotp(this.driver, "john", "password", true); }); - afterEach(async function() { + after(async function() { await StopDriver(this.driver); }) @@ -44,7 +45,7 @@ export default function() { const label = 'john'; const issuer = 'example.com'; - Assert(new RegExp(`^otpauth://totp/${label}\\?secret=[A-Z0-9]+&issuer=${issuer}$`).test(otpauthUrl)); + Assert(new RegExp(`^otpauth://totp/${issuer}:${label}\\?algorithm=SHA1&digits=6&issuer=${issuer}&period=30&secret=[A-Z0-9]+$`).test(otpauthUrl)); }) }); }; diff --git a/test/suites/basic/scenarii/RequiredTwoFactor.ts b/test/suites/basic/scenarii/RequiredTwoFactor.ts index a6f831dc3..4b967aa4c 100644 --- a/test/suites/basic/scenarii/RequiredTwoFactor.ts +++ b/test/suites/basic/scenarii/RequiredTwoFactor.ts @@ -15,8 +15,6 @@ export default function() { await VisitPage(this.driver, "https://admin.example.com:8080/secret.html"); await VerifyUrlIs(this.driver, "https://login.example.com:8080/#/?rd=https://admin.example.com:8080/secret.html"); - await FillLoginPageAndClick(this.driver, "john", "password"); - await VerifyIsSecondFactorStage(this.driver); }); after(async function() { diff --git a/test/suites/basic/scenarii/ResetPassword.ts b/test/suites/basic/scenarii/ResetPassword.ts index 42ed31d5b..77d2cc3ac 100644 --- a/test/suites/basic/scenarii/ResetPassword.ts +++ b/test/suites/basic/scenarii/ResetPassword.ts @@ -10,6 +10,7 @@ import VisitPageAndWaitUrlIs from '../../../helpers/behaviors/VisitPageAndWaitUr import VerifyNotificationDisplayed from '../../../helpers/assertions/VerifyNotificationDisplayed'; import VerifyUrlIs from '../../../helpers/assertions/VerifyUrlIs'; import { StartDriver, StopDriver } from '../../../helpers/context/WithDriver'; +import ResetPassword from '../../../helpers/behaviors/ResetPassword'; export default function() { beforeEach(async function() { @@ -21,27 +22,19 @@ export default function() { }) it("should reset password for john", async function() { - await VisitPageAndWaitUrlIs(this.driver, "https://login.example.com:8080/#/"); - await ClickOnLink(this.driver, "Forgot password\?"); - await VerifyUrlIs(this.driver, "https://login.example.com:8080/#/forgot-password"); - await FillField(this.driver, "username", "john"); - await ClickOn(this.driver, SeleniumWebDriver.By.id('next-button')); - await VerifyUrlIs(this.driver, 'https://login.example.com:8080/#/confirmation-sent'); - - await this.driver.sleep(500); // Simulate the time it takes to receive the e-mail. - const link = await GetLinkFromEmail(); - await VisitPageAndWaitUrlIs(this.driver, link); - await FillField(this.driver, "password1", "newpass"); - await FillField(this.driver, "password2", "newpass"); - await ClickOn(this.driver, SeleniumWebDriver.By.id('reset-button')); + await ResetPassword(this.driver, "john", "newpass"); await VerifyUrlIs(this.driver, "https://login.example.com:8080/#/"); await FillLoginPageAndClick(this.driver, "john", "newpass"); // The user reaches the second factor page using the new password. await IsSecondFactorStage(this.driver); + + // restore password + await ClickOnLink(this.driver, "Logout"); + await ResetPassword(this.driver, "john", "password"); }); - it("should persuade reset password is initiated for unknown user", async function() { + it("should make attacker think reset password is initiated", async function() { await VisitPageAndWaitUrlIs(this.driver, "https://login.example.com:8080/#/"); await ClickOnLink(this.driver, "Forgot password\?"); await VerifyUrlIs(this.driver, "https://login.example.com:8080/#/forgot-password"); diff --git a/test/suites/basic/scenarii/TOTPValidation.ts b/test/suites/basic/scenarii/TOTPValidation.ts index 2f4df3b0e..24f77f15b 100644 --- a/test/suites/basic/scenarii/TOTPValidation.ts +++ b/test/suites/basic/scenarii/TOTPValidation.ts @@ -2,7 +2,6 @@ import FillLoginPageWithUserAndPasswordAndClick from '../../../helpers/FillLogin import ValidateTotp from '../../../helpers/ValidateTotp'; import VerifySecretObserved from "../../../helpers/assertions/VerifySecretObserved"; import LoginAndRegisterTotp from '../../../helpers/LoginAndRegisterTotp'; -import { AUTHENTICATION_TOTP_FAILED } from '../../../../server/src/lib/UserMessages'; import VisitPageAndWaitUrlIs from '../../../helpers/behaviors/VisitPageAndWaitUrlIs'; import VerifyNotificationDisplayed from '../../../helpers/assertions/VerifyNotificationDisplayed'; import VerifyUrlIs from '../../../helpers/assertions/VerifyUrlIs'; @@ -21,7 +20,6 @@ export default function() { if (!secret) throw new Error('No secret!'); await VisitPageAndWaitUrlIs(this.driver, "https://login.example.com:8080/#/?rd=https://admin.example.com:8080/secret.html"); - await FillLoginPageWithUserAndPasswordAndClick(this.driver, 'john', 'password'); await ValidateTotp(this.driver, secret); }); @@ -50,7 +48,6 @@ export default function() { const BAD_TOKEN = "125478"; await VisitPageAndWaitUrlIs(this.driver, "https://login.example.com:8080/#/?rd=https://admin.example.com:8080/secret.html"); - await FillLoginPageWithUserAndPasswordAndClick(this.driver, 'john', 'password'); await ValidateTotp(this.driver, BAD_TOKEN); }); @@ -59,7 +56,7 @@ export default function() { }); it("get a notification message", async function() { - await VerifyNotificationDisplayed(this.driver, AUTHENTICATION_TOTP_FAILED); + await VerifyNotificationDisplayed(this.driver, "Authentication failed, please retry later."); }); }); } diff --git a/test/suites/basic/scenarii/VerifyEndpoint.ts b/test/suites/basic/scenarii/VerifyEndpoint.ts index e845512e8..1da93b378 100644 --- a/test/suites/basic/scenarii/VerifyEndpoint.ts +++ b/test/suites/basic/scenarii/VerifyEndpoint.ts @@ -11,9 +11,9 @@ export default function() { describe('Kubernetes nginx ingress controller', async function() { it('should redirect to https://login.example.com:8080', async function() { await GET_ExpectRedirect('http://192.168.240.1:9091/api/verify?rd=https://login.example.com:8080/%23/', - 'https://login.example.com:8080/#/?rd=https://secure.example.com:8080', + 'https://login.example.com:8080/#/?rd=https://secure.example.com:8080/', { - 'X-Original-Url': 'https://secure.example.com:8080', + 'X-Original-Url': 'https://secure.example.com:8080/', 'X-Forwarded-Proto': 'https' }); }); diff --git a/test/suites/basic/test.ts b/test/suites/basic/test.ts index 02e03593f..7c82219a2 100644 --- a/test/suites/basic/test.ts +++ b/test/suites/basic/test.ts @@ -6,7 +6,7 @@ import TOTPValidation from './scenarii/TOTPValidation'; import BackendProtection from './scenarii/BackendProtection'; import VerifyEndpoint from './scenarii/VerifyEndpoint'; import RequiredTwoFactor from './scenarii/RequiredTwoFactor'; -import LogoutRedirectToAlreadyLoggedIn from './scenarii/LogoutRedirectToAlreadyLoggedIn'; +import AlreadyLoggedIn from './scenarii/AlreadyLoggedIn'; import { exec } from '../../helpers/utils/exec'; import TwoFactorAuthentication from "../../helpers/scenarii/TwoFactorAuthentication"; import BypassPolicy from "./scenarii/BypassPolicy"; @@ -28,6 +28,6 @@ AutheliaSuite(__dirname, function() { describe('TOTP Registration', RegisterTotp); describe('TOTP Validation', TOTPValidation); describe('Required two factor', RequiredTwoFactor); - describe('Logout endpoint redirect to already logged in page', LogoutRedirectToAlreadyLoggedIn); + describe('Already logged in', AlreadyLoggedIn); describe('No Duo Push method available', NoDuoPushOption); }); \ No newline at end of file diff --git a/test/suites/duo-push/config.yml b/test/suites/duo-push/config.yml index f02a0fe59..13a0f853e 100644 --- a/test/suites/duo-push/config.yml +++ b/test/suites/duo-push/config.yml @@ -6,6 +6,8 @@ port: 9091 logs_level: debug +jwt_secret: very_important_secret + authentication_backend: file: path: ./test/suites/basic/users_database.test.yml @@ -19,7 +21,7 @@ session: # Configuration of the storage backend used to store data and secrets. i.e. totp data storage: local: - path: /tmp/authelia/db + path: /tmp/authelia/db.sqlite # TOTP Issuer Name # @@ -93,9 +95,6 @@ regulation: notifier: # Use a SMTP server for sending notifications smtp: - username: test - password: password - secure: false host: 127.0.0.1 port: 1025 sender: admin@example.com diff --git a/test/suites/duo-push/environment.ts b/test/suites/duo-push/environment.ts index c612370b0..f32d1d7e0 100644 --- a/test/suites/duo-push/environment.ts +++ b/test/suites/duo-push/environment.ts @@ -15,7 +15,6 @@ const dockerEnv = new DockerEnvironment([ async function setup() { await exec(`cp ${__dirname}/users_database.yml ${__dirname}/users_database.test.yml`); - await exec('mkdir -p /tmp/authelia/db'); await exec('./example/compose/nginx/portal/render.js ' + (fs.existsSync('.suite') ? '': '--production')); await dockerEnv.start(); await autheliaServer.start(); @@ -24,7 +23,6 @@ async function setup() { async function teardown() { await autheliaServer.stop(); await dockerEnv.stop(); - await exec('rm -rf /tmp/authelia/db'); } const setup_timeout = 30000; diff --git a/test/suites/high-availability/config.yml b/test/suites/high-availability/config.yml index 8395d79e5..11b7a6211 100644 --- a/test/suites/high-availability/config.yml +++ b/test/suites/high-availability/config.yml @@ -10,6 +10,8 @@ port: 9091 # Level of verbosity for logs logs_level: debug +jwt_secret: unsecure_secret + # Default redirection URL # # If user tries to authenticate without any referer, Authelia @@ -42,7 +44,7 @@ authentication_backend: # production. ldap: # The url of the ldap server - url: ldap://127.0.0.1 + url: 127.0.0.1:389 # The base dn for every entries base_dn: dc=example,dc=com @@ -53,7 +55,7 @@ authentication_backend: # The users filter used to find the user DN # {0} is a matcher replaced by username. # 'cn={0}' by default. - users_filter: cn={0} + users_filter: (cn={0}) # An additional dn to define the scope of groups additional_groups_dn: ou=groups @@ -213,10 +215,10 @@ regulation: # The time range during which the user can attempt login before being banned. # The user is banned if the authenticaction failed `max_retries` times in a `find_time` seconds window. - find_time: 15 + find_time: 8 # The length of time before a banned user can login again. - ban_time: 5 + ban_time: 10 # Configuration of the storage backend used to store data and secrets. # @@ -240,23 +242,8 @@ storage: # registration or a TOTP registration. # Use only an available configuration: filesystem, gmail notifier: - # For testing purpose, notifications can be sent in a file - ## filesystem: - ## filename: /tmp/authelia/notification.txt - - # Use your email account to send the notifications. You can use an app password. - # List of valid services can be found here: https://nodemailer.com/smtp/well-known/ - ## email: - ## username: user@example.com - ## password: yourpassword - ## sender: admin@example.com - ## service: gmail - # Use a SMTP server for sending notifications smtp: - username: test - password: password - secure: false host: 127.0.0.1 port: 1025 sender: admin@example.com diff --git a/test/suites/high-availability/scenarii/AccessControl.ts b/test/suites/high-availability/scenarii/AccessControl.ts index 7197fb067..37bb61816 100644 --- a/test/suites/high-availability/scenarii/AccessControl.ts +++ b/test/suites/high-availability/scenarii/AccessControl.ts @@ -1,13 +1,11 @@ import LoginAndRegisterTotp from "../../../helpers/LoginAndRegisterTotp"; import VerifySecretObserved from "../../../helpers/assertions/VerifySecretObserved"; -import WithDriver from "../../../helpers/context/WithDriver"; -import FillLoginPageAndClick from "../../../helpers/FillLoginPageAndClick"; +import { StartDriver, StopDriver } from "../../../helpers/context/WithDriver"; import ValidateTotp from "../../../helpers/ValidateTotp"; import Logout from "../../../helpers/Logout"; import VisitPageAndWaitUrlIs from "../../../helpers/behaviors/VisitPageAndWaitUrlIs"; import VerifyBodyContains from "../../../helpers/assertions/VerifyBodyContains"; -import VerifyIsSecondFactorStage from "../../../helpers/assertions/VerifyIsSecondFactorStage"; -import VerifyUrlIs from "../../../helpers/assertions/VerifyUrlIs"; +import VerifyUrlIs from "../../../helpers/assertions/WaitUrlIs"; async function ShouldHaveAccessTo(url: string) { it('should have access to ' + url, async function() { @@ -25,23 +23,20 @@ async function ShouldNotHaveAccessTo(url: string) { // we verify that the user has only access to want he is granted to. export default function() { - // We ensure that bob has access to what he is granted to describe('Permissions of user john', function() { - after(async function() { - await Logout(this.driver); - }) - - WithDriver(); - before(async function() { + this.driver = await StartDriver(); const secret = await LoginAndRegisterTotp(this.driver, "john", "password", true); await VisitPageAndWaitUrlIs(this.driver, 'https://login.example.com:8080/#/'); - await FillLoginPageAndClick(this.driver, 'john', 'password', false); await ValidateTotp(this.driver, secret); - // Default URL in conf is home. - await VerifyUrlIs(this.driver, 'https://home.example.com:8080/'); - }) + await VerifyUrlIs(this.driver, "https://home.example.com:8080/"); + }); + + after(async function() { + await Logout(this.driver); + await StopDriver(this.driver); + }); ShouldHaveAccessTo('https://public.example.com:8080/secret.html'); ShouldHaveAccessTo('https://secure.example.com:8080/secret.html'); @@ -58,20 +53,18 @@ export default function() { // We ensure that bob has access to what he is granted to describe('Permissions of user bob', function() { - after(async function() { - await Logout(this.driver); - }) - - WithDriver(); - before(async function() { + this.driver = await StartDriver(); const secret = await LoginAndRegisterTotp(this.driver, "bob", "password", true); await VisitPageAndWaitUrlIs(this.driver, 'https://login.example.com:8080/#/'); - await FillLoginPageAndClick(this.driver, 'bob', 'password', false); await ValidateTotp(this.driver, secret); - // Default URL in conf is home. - await VerifyUrlIs(this.driver, 'https://home.example.com:8080/'); - }) + await VerifyUrlIs(this.driver, "https://home.example.com:8080/"); + }); + + after(async function() { + await Logout(this.driver); + await StopDriver(this.driver); + }); ShouldHaveAccessTo('https://public.example.com:8080/secret.html'); ShouldHaveAccessTo('https://secure.example.com:8080/secret.html'); @@ -84,24 +77,22 @@ export default function() { ShouldHaveAccessTo('https://mx1.mail.example.com:8080/secret.html'); ShouldHaveAccessTo('https://singlefactor.example.com:8080/secret.html'); ShouldHaveAccessTo('https://mx2.mail.example.com:8080/secret.html'); - }) + }); // We ensure that harry has access to what he is granted to describe('Permissions of user harry', function() { - after(async function() { - await Logout(this.driver); - }) - - WithDriver(); - before(async function() { + this.driver = await StartDriver(); const secret = await LoginAndRegisterTotp(this.driver, "harry", "password", true); await VisitPageAndWaitUrlIs(this.driver, 'https://login.example.com:8080/#/'); - await FillLoginPageAndClick(this.driver, 'harry', 'password', false); await ValidateTotp(this.driver, secret); - // Default URL in conf is home. - await VerifyUrlIs(this.driver, 'https://home.example.com:8080/'); - }) + await VerifyUrlIs(this.driver, "https://home.example.com:8080/"); + }); + + after(async function() { + await Logout(this.driver); + await StopDriver(this.driver); + }); ShouldHaveAccessTo('https://public.example.com:8080/secret.html'); ShouldHaveAccessTo('https://secure.example.com:8080/secret.html'); @@ -114,5 +105,5 @@ export default function() { ShouldNotHaveAccessTo('https://mx1.mail.example.com:8080/secret.html'); ShouldHaveAccessTo('https://singlefactor.example.com:8080/secret.html'); ShouldNotHaveAccessTo('https://mx2.mail.example.com:8080/secret.html'); - }) + }); } \ No newline at end of file diff --git a/test/suites/high-availability/scenarii/AutheliaRestart.ts b/test/suites/high-availability/scenarii/AutheliaRestart.ts index c2cad8cbb..08680394e 100644 --- a/test/suites/high-availability/scenarii/AutheliaRestart.ts +++ b/test/suites/high-availability/scenarii/AutheliaRestart.ts @@ -2,51 +2,30 @@ import Logout from "../../../helpers/Logout"; import ChildProcess from 'child_process'; import { StartDriver, StopDriver } from "../../../helpers/context/WithDriver"; import VerifySecretObserved from "../../../helpers/assertions/VerifySecretObserved"; -import RegisterAndLoginTwoFactor from "../../../helpers/behaviors/RegisterAndLoginTwoFactor"; import VisitPageAndWaitUrlIs from "../../../helpers/behaviors/VisitPageAndWaitUrlIs"; import { GET_Expect502 } from "../../../helpers/utils/Requests"; import LoginAndRegisterTotp from "../../../helpers/LoginAndRegisterTotp"; import FullLogin from "../../../helpers/FullLogin"; +import ValidateTotp from "../../../helpers/ValidateTotp"; +import VerifyUrlIs from "../../../helpers/assertions/WaitUrlIs"; export default function() { describe('Session is still valid after Authelia restarts', function() { - before(async function() { - // Be sure to start fresh - ChildProcess.execSync('rm -f .authelia-interrupt'); - - this.driver = await StartDriver(); - await RegisterAndLoginTwoFactor(this.driver, 'john', "password", true, 'https://admin.example.com:8080/secret.html'); - await VisitPageAndWaitUrlIs(this.driver, 'https://home.example.com:8080/'); - }); - - after(async function() { - await Logout(this.driver); - await StopDriver(this.driver); - - // Be sure to cleanup - ChildProcess.execSync('rm -f .authelia-interrupt'); - }); - - it("should still access the secret after Authelia restarted", async function() { - ChildProcess.execSync('touch .authelia-interrupt'); - await GET_Expect502('https://login.example.com:8080/api/state'); - await this.driver.sleep(1000); - ChildProcess.execSync('rm .authelia-interrupt'); - await this.driver.sleep(4000); - - await VisitPageAndWaitUrlIs(this.driver, 'https://admin.example.com:8080/secret.html'); - await VerifySecretObserved(this.driver); - }); - }); - - describe('Secrets are persisted even if Authelia restarts', function() { before(async function() { // Be sure to start fresh ChildProcess.execSync('rm -f .authelia-interrupt'); this.driver = await StartDriver(); this.secret = await LoginAndRegisterTotp(this.driver, 'john', "password", true); - await Logout(this.driver); + await VisitPageAndWaitUrlIs(this.driver, "https://login.example.com:8080/#/"); + await ValidateTotp(this.driver, this.secret); + await VerifyUrlIs(this.driver, "https://home.example.com:8080/"); + + ChildProcess.execSync('touch .authelia-interrupt'); + await GET_Expect502('https://login.example.com:8080/api/state'); + await this.driver.sleep(1000); + ChildProcess.execSync('rm .authelia-interrupt'); + await this.driver.sleep(4000); }); after(async function() { @@ -58,14 +37,16 @@ export default function() { }); it("should still access the secret after Authelia restarted", async function() { - ChildProcess.execSync('touch .authelia-interrupt'); - await GET_Expect502('https://login.example.com:8080/api/state'); - await this.driver.sleep(1000); - ChildProcess.execSync('rm .authelia-interrupt'); - await this.driver.sleep(4000); - + await VisitPageAndWaitUrlIs(this.driver, "https://admin.example.com:8080/secret.html"); + await VerifySecretObserved(this.driver); + }); + + it("should still access the secret after Authelia restarted", async function() { + await Logout(this.driver); // The user can re-authenticate with the secret. - await FullLogin(this.driver, 'john', this.secret, 'https://admin.example.com:8080/secret.html') + await FullLogin(this.driver, 'john', this.secret, "https://admin.example.com:8080/secret.html"); + await VerifyUrlIs(this.driver, "https://admin.example.com:8080/secret.html"); + await VerifySecretObserved(this.driver); }); }); } \ No newline at end of file diff --git a/test/suites/high-availability/scenarii/AuthenticationRegulation.ts b/test/suites/high-availability/scenarii/AuthenticationRegulation.ts index 87e5c2020..05541c013 100644 --- a/test/suites/high-availability/scenarii/AuthenticationRegulation.ts +++ b/test/suites/high-availability/scenarii/AuthenticationRegulation.ts @@ -2,10 +2,17 @@ import { StartDriver, StopDriver } from "../../../helpers/context/WithDriver"; import LoginAs from "../../../helpers/LoginAs"; import VerifyNotificationDisplayed from "../../../helpers/assertions/VerifyNotificationDisplayed"; import VerifyIsSecondFactorStage from "../../../helpers/assertions/VerifyIsSecondFactorStage"; +import ClearFieldById from "../../../helpers/behaviors/ClearFieldById"; +import {WebDriver} from "selenium-webdriver"; + +async function ClearAndLoginAgain(driver: WebDriver, username: string, password: string) { + await ClearFieldById(driver, "username"); + await LoginAs(driver, username, password); +} export default function() { describe('Authelia regulates authentications when a hacker is brute forcing', function() { - this.timeout(15000); + this.timeout(30000); beforeEach(async function() { this.driver = await StartDriver(); }); @@ -16,20 +23,20 @@ export default function() { it("should return an error message when providing correct credentials the 4th time.", async function() { await LoginAs(this.driver, "blackhat", "bad-password"); - await VerifyNotificationDisplayed(this.driver, "Authentication failed. Please check your credentials."); - await LoginAs(this.driver, "blackhat", "bad-password"); - await VerifyNotificationDisplayed(this.driver, "Authentication failed. Please check your credentials."); - await LoginAs(this.driver, "blackhat", "bad-password"); - await VerifyNotificationDisplayed(this.driver, "Authentication failed. Please check your credentials."); + await VerifyNotificationDisplayed(this.driver, "Authentication failed. Check your credentials."); + await ClearAndLoginAgain(this.driver, "blackhat", "bad-password"); + await VerifyNotificationDisplayed(this.driver, "Authentication failed. Check your credentials."); + await ClearAndLoginAgain(this.driver, "blackhat", "bad-password"); + await VerifyNotificationDisplayed(this.driver, "Authentication failed. Check your credentials."); // when providing good credentials, the hacker is regulated and see same message as previously. - await LoginAs(this.driver, "blackhat", "bad-password"); - await VerifyNotificationDisplayed(this.driver, "Authentication failed. Please check your credentials."); + await ClearAndLoginAgain(this.driver, "blackhat", "bad-password"); + await VerifyNotificationDisplayed(this.driver, "Authentication failed. Check your credentials."); // Wait the regulation ban time before retrying with correct credentials. // It should authenticate normally. - await this.driver.sleep(6000); - await LoginAs(this.driver, "blackhat", "password"); + await this.driver.sleep(12000); + await ClearAndLoginAgain(this.driver, "blackhat", "password"); await VerifyIsSecondFactorStage(this.driver); }); }); diff --git a/test/suites/high-availability/scenarii/CustomHeadersForwarded.ts b/test/suites/high-availability/scenarii/CustomHeadersForwarded.ts index 83f6ac987..47e7f4508 100644 --- a/test/suites/high-availability/scenarii/CustomHeadersForwarded.ts +++ b/test/suites/high-availability/scenarii/CustomHeadersForwarded.ts @@ -3,7 +3,6 @@ import { StartDriver, StopDriver } from "../../../helpers/context/WithDriver"; import RegisterAndLoginWith2FA from "../../../helpers/behaviors/RegisterAndLoginTwoFactor"; import VerifyForwardedHeaderIs from "../../../helpers/assertions/VerifyForwardedHeaderIs"; import LoginOneFactor from "../../../helpers/behaviors/LoginOneFactor"; -import VerifyUrlIs from "../../../helpers/assertions/VerifyUrlIs"; export default function() { describe("Custom-Forwarded-User and Custom-Forwarded-Groups are correctly forwarded to protected backend", function() { diff --git a/test/suites/high-availability/scenarii/EnforceInternalRedirectionsOnly.ts b/test/suites/high-availability/scenarii/EnforceInternalRedirectionsOnly.ts index dd870b557..36112213b 100644 --- a/test/suites/high-availability/scenarii/EnforceInternalRedirectionsOnly.ts +++ b/test/suites/high-availability/scenarii/EnforceInternalRedirectionsOnly.ts @@ -1,12 +1,10 @@ import LoginAndRegisterTotp from "../../../helpers/LoginAndRegisterTotp"; -import FillLoginPageWithUserAndPasswordAndClick from '../../../helpers/FillLoginPageAndClick'; import ValidateTotp from "../../../helpers/ValidateTotp"; -import Logout from "../../../helpers/Logout"; import VerifyIsAlreadyAuthenticatedStage from "../../../helpers/assertions/VerifyIsAlreadyAuthenticatedStage"; import { StartDriver, StopDriver } from "../../../helpers/context/WithDriver"; import VisitPageAndWaitUrlIs from "../../../helpers/behaviors/VisitPageAndWaitUrlIs"; import VerifyUrlIs from "../../../helpers/assertions/VerifyUrlIs"; -import VerifyNotificationDisplayed from "../../../helpers/assertions/VerifyNotificationDisplayed"; +import Logout from "../../../helpers/Logout"; /* * Authelia should not be vulnerable to open redirection. Otherwise it would aid an @@ -15,67 +13,60 @@ import VerifyNotificationDisplayed from "../../../helpers/assertions/VerifyNotif * To avoid the issue, Authelia's client scans the URL and prevent any redirection if * the URL is pointing to an external domain. */ -export default function() { - describe("Only redirection to a subdomain of the protected domain should be allowed", function() { - this.timeout(10000); - let secret: string; - - beforeEach(async function() { - this.driver = await StartDriver(); - secret = await LoginAndRegisterTotp(this.driver, "john", "password", true) - }); - - afterEach(async function() { - await Logout(this.driver); - await StopDriver(this.driver); - }) - - function CannotRedirectTo(url: string, twoFactor: boolean = true) { - it(`should redirect to already authenticated page when requesting ${url}`, async function() { - await VisitPageAndWaitUrlIs(this.driver, `https://login.example.com:8080/#/?rd=${url}`); - await FillLoginPageWithUserAndPasswordAndClick(this.driver, 'john', 'password'); - if (twoFactor) { - await ValidateTotp(this.driver, secret); - await VerifyIsAlreadyAuthenticatedStage(this.driver); - } else { - await VerifyNotificationDisplayed(this.driver, - "You're authenticated but cannot be automatically redirected to an unsafe URL."); +export default function () { + describe("Only redirection to a subdomain of the protected domain should be allowed", function () { + this.timeout(10000); + let secret: string; + + beforeEach(async function () { + this.driver = await StartDriver(); + secret = await LoginAndRegisterTotp(this.driver, "john", "password", true) + }); + + afterEach(async function () { + await Logout(this.driver); + await StopDriver(this.driver); + }) + + function CannotRedirectTo(url: string, twoFactor: boolean = true) { + it(`should redirect to already authenticated page when requesting ${url}`, async function () { + await VisitPageAndWaitUrlIs(this.driver, `https://login.example.com:8080/#/?rd=${url}`); + await ValidateTotp(this.driver, secret); + await VerifyIsAlreadyAuthenticatedStage(this.driver); + }); } - }); - } - function CanRedirectTo(url: string) { - it(`should redirect to ${url}`, async function() { - await VisitPageAndWaitUrlIs(this.driver, `https://login.example.com:8080/#/?rd=${url}`); - await FillLoginPageWithUserAndPasswordAndClick(this.driver, 'john', 'password'); - await ValidateTotp(this.driver, secret); - await VerifyUrlIs(this.driver, url); - }); - } - - describe('Cannot redirect to https://www.google.fr', function() { - // Do not redirect to another domain than example.com - CannotRedirectTo("https://www.google.fr"); - }); + function CanRedirectTo(url: string) { + it(`should redirect to ${url}`, async function () { + await VisitPageAndWaitUrlIs(this.driver, `https://login.example.com:8080/#/?rd=${url}`); + await ValidateTotp(this.driver, secret); + await VerifyUrlIs(this.driver, url); + }); + } - describe('Cannot redirect to https://public.example.com.a:8080', function() { - // Do not redirect to another domain than example.com - CannotRedirectTo("https://public.example.com.a:8080"); - }); + describe('Cannot redirect to https://www.google.fr', function () { + // Do not redirect to another domain than example.com + CannotRedirectTo("https://www.google.fr"); + }); - describe('Cannot redirect to http://secure.example.com:8080', function() { - // Do not redirect to http website - CannotRedirectTo("http://secure.example.com:8080"); - }); + describe('Cannot redirect to https://public.example.com.a:8080/secret.html', function () { + // Do not redirect to another domain than example.com + CannotRedirectTo("https://public.example.com.a:8080/secret.html"); + }); - describe('Cannot redirect to http://singlefactor.example.com:8080', function() { - // Do not redirect to http website - CannotRedirectTo("http://singlefactor.example.com:8080", false); - }); + describe('Cannot redirect to http://secure.example.com:8080/secret.html', function () { + // Do not redirect to http website + CannotRedirectTo("http://secure.example.com:8080/secret.html"); + }); - describe('Can redirect to https://secure.example.com:8080/', function() { - // Can redirect to any subdomain of the domain protected by Authelia. - CanRedirectTo("https://secure.example.com:8080/"); + describe('Cannot redirect to http://singlefactor.example.com:8080/secret.html', function () { + // Do not redirect to http website + CannotRedirectTo("http://singlefactor.example.com:8080/secret.html", false); + }); + + describe('Can redirect to https://secure.example.com:8080/secret.html', function () { + // Can redirect to any subdomain of the domain protected by Authelia. + CanRedirectTo("https://secure.example.com:8080/secret.html"); + }); }); - }); } \ No newline at end of file diff --git a/test/suites/high-availability/scenarii/MongoConnectionRecovery.ts b/test/suites/high-availability/scenarii/MongoConnectionRecovery.ts index db72213dd..5e67806cd 100644 --- a/test/suites/high-availability/scenarii/MongoConnectionRecovery.ts +++ b/test/suites/high-availability/scenarii/MongoConnectionRecovery.ts @@ -1,15 +1,12 @@ import LoginAndRegisterTotp from "../../../helpers/LoginAndRegisterTotp"; import FullLogin from "../../../helpers/FullLogin"; -import child_process from 'child_process'; import WithDriver from "../../../helpers/context/WithDriver"; import Logout from "../../../helpers/Logout"; import { composeFiles } from '../environment'; import DockerCompose from "../../../helpers/context/DockerCompose"; export default function() { - after(async function() { - await Logout(this.driver); - }) + const dockerCompose = new DockerCompose(composeFiles); WithDriver(); @@ -17,8 +14,11 @@ export default function() { this.timeout(30000); const secret = await LoginAndRegisterTotp(this.driver, "john", "password", true); - const dockerCompose = new DockerCompose(composeFiles); await dockerCompose.restart('mongo'); + + await Logout(this.driver); await FullLogin(this.driver, "john", secret, "https://admin.example.com:8080/secret.html"); - }); + // TODO(clems4ever): logout here but right now visiting login.example.com redirects to home.example.com + // according to the configuration so it's not possible to click on Logout link. + }); } \ No newline at end of file diff --git a/test/suites/kubernetes/environment.ts b/test/suites/kubernetes/environment.ts index 5dd054a51..8a2b1d396 100644 --- a/test/suites/kubernetes/environment.ts +++ b/test/suites/kubernetes/environment.ts @@ -16,14 +16,14 @@ function arePodsReady(kubernetes: Kubernetes): boolean { ...process.env, }}).toString('utf-8').split("\n").filter((x) => x !== ''); console.log(lines.join('\n')); - return lines.reduce((acc, line) => { + return lines.reduce((acc: boolean, line: string) => { return acc && line.indexOf('1/1') > -1; }, true); } function servicesReady(kubernetes: Kubernetes): Promise { return WaitUntil(async () => arePodsReady(kubernetes), - 300000, 15000, 5000); + 600000, 15000, 5000, 5000); } function redisConnected(redisClient: RedisClient): Promise { @@ -83,8 +83,9 @@ function startAutheliaPortForwarding(kubernetes: Kubernetes) { shell: true, env: {KUBECONFIG: kubernetes.kubeConfig, ...process.env} } as any); - portFowardingProcess.stdout.pipe(process.stdout); - portFowardingProcess.stderr.pipe(process.stderr); + if (!portFowardingProcess) return; + portFowardingProcess.stdout!.pipe(process.stdout); + portFowardingProcess.stderr!.pipe(process.stderr); } const dockerEnv = new DockerEnvironment([ @@ -136,7 +137,7 @@ async function teardown() { await KubernetesManager.delete(); } -const setup_timeout = 300000; +const setup_timeout = 600000; const teardown_timeout = 30000; export { diff --git a/test/suites/ldap/README.md b/test/suites/ldap/README.md new file mode 100644 index 000000000..bee6a33c0 --- /dev/null +++ b/test/suites/ldap/README.md @@ -0,0 +1,12 @@ +# LDAP suite + +This suite is made to test Authelia with an LDAP server + +## Components + +This suite will spawn nginx as the edge reverse proxy and an LDAP server as the user +storage. + +## Tests + +Basic authentication tests \ No newline at end of file diff --git a/test/suites/ldap/config.yml b/test/suites/ldap/config.yml new file mode 100644 index 000000000..f186515e4 --- /dev/null +++ b/test/suites/ldap/config.yml @@ -0,0 +1,96 @@ +############################################################### +# Authelia minimal configuration # +############################################################### + +port: 9091 + +logs_level: debug + +default_redirection_url: https://home.example.com:8080/ + +jwt_secret: very_important_secret + +authentication_backend: + ldap: + # The url of the ldap server + url: 127.0.0.1:389 + + # The base dn for every entries + base_dn: dc=example,dc=com + + # An additional dn to define the scope to all users + additional_users_dn: ou=users + + # The users filter used to find the user DN + # {0} is a matcher replaced by username. + # 'cn={0}' by default. + users_filter: (cn={0}) + + # An additional dn to define the scope of groups + additional_groups_dn: ou=groups + + # The groups filter used for retrieving groups of a given user. + # {0} is a matcher replaced by username. + # {dn} is a matcher replaced by user DN. + # 'member={dn}' by default. + groups_filter: (&(member={dn})(objectclass=groupOfNames)) + + # The attribute holding the name of the group + group_name_attribute: cn + + # The attribute holding the mail address of the user + mail_attribute: mail + + # The username and password of the admin user. + user: cn=admin,dc=example,dc=com + password: password + +session: + secret: unsecure_session_secret + domain: example.com + expiration: 3600 # 1 hour + inactivity: 300 # 5 minutes + +# Configuration of the storage backend used to store data and secrets. i.e. totp data +storage: + local: + path: /tmp/authelia/db.sqlite3 + +# TOTP Issuer Name +# +# This will be the issuer name displayed in Google Authenticator +# See: https://github.com/google/google-authenticator/wiki/Key-Uri-Format for more info on issuer names +totp: + issuer: example.com + +access_control: + default_policy: deny + rules: + - domain: 'public.example.com' + policy: bypass + - domain: 'admin.example.com' + policy: two_factor + - domain: 'secure.example.com' + policy: two_factor + - domain: 'singlefactor.example.com' + policy: one_factor + + +# Configuration of the authentication regulation mechanism. +regulation: + # Set it to 0 to disable max_retries. + max_retries: 3 + + # The user is banned if the authenticaction failed `max_retries` times in a `find_time` seconds window. + find_time: 300 + + # The length of time before a banned user can login again. + ban_time: 900 + +notifier: + # Use a SMTP server for sending notifications + smtp: + host: 127.0.0.1 + port: 1025 + sender: admin@example.com + diff --git a/test/suites/ldap/environment.ts b/test/suites/ldap/environment.ts new file mode 100644 index 000000000..4c6d7fa49 --- /dev/null +++ b/test/suites/ldap/environment.ts @@ -0,0 +1,45 @@ +import DockerEnvironment from "../../helpers/context/DockerEnvironment"; +import AutheliaServer from "../../helpers/context/AutheliaServer"; +import { exec } from "../../helpers/utils/exec"; +import fs from 'fs'; + +const composeFiles = [ + 'docker-compose.yml', + 'example/compose/nginx/backend/docker-compose.yml', + 'example/compose/nginx/portal/docker-compose.yml', + 'example/compose/smtp/docker-compose.yml', + 'example/compose/ldap/docker-compose.yml' +] + +const dockerEnv = new DockerEnvironment(composeFiles); +const autheliaServer = new AutheliaServer(__dirname + '/config.yml'); + +async function setup() { + // In dev mode Authelia has the server served on one port and the frontend on another port. + await exec('./example/compose/nginx/portal/render.js ' + (fs.existsSync('.suite') ? '': '--production')); + + console.log(`Prepare environment with docker-compose...`); + await dockerEnv.start(); + + console.log('Start Authelia server.'); + await autheliaServer.start(); +} + +async function teardown() { + console.log('Stop Authelia server.'); + await autheliaServer.stop(); + + console.log(`Cleanup environment with docker-compose...`); + await dockerEnv.stop(); +} + +const setup_timeout = 30000; +const teardown_timeout = 30000; + +export { + setup, + setup_timeout, + teardown, + teardown_timeout, + composeFiles +}; \ No newline at end of file diff --git a/test/suites/ldap/test.ts b/test/suites/ldap/test.ts new file mode 100644 index 000000000..c7e192cb6 --- /dev/null +++ b/test/suites/ldap/test.ts @@ -0,0 +1,10 @@ +import AutheliaSuite from "../../helpers/context/AutheliaSuite"; +import SingleFactorAuthentication from "../../helpers/scenarii/SingleFactorAuthentication"; +import TwoFactorAuthentication from "../../helpers/scenarii/TwoFactorAuthentication"; + +AutheliaSuite(__dirname, function() { + this.timeout(10000); + + describe('Single-factor authentication', SingleFactorAuthentication()) + describe('Two-factor authentication', TwoFactorAuthentication()); +}); \ No newline at end of file diff --git a/test/suites/mongo/README.md b/test/suites/mongo/README.md new file mode 100644 index 000000000..420a6fc97 --- /dev/null +++ b/test/suites/mongo/README.md @@ -0,0 +1,11 @@ +# Mongo suite + +This suite is made to test Authelia with a Mongo storage backend + +## Components + +This suite will spawn nginx as the edge reverse proxy and a mongo server. + +## Tests + +Basic authentication tests \ No newline at end of file diff --git a/test/suites/mongo/config.yml b/test/suites/mongo/config.yml new file mode 100644 index 000000000..803814cae --- /dev/null +++ b/test/suites/mongo/config.yml @@ -0,0 +1,69 @@ +############################################################### +# Authelia minimal configuration # +############################################################### + +port: 9091 + +logs_level: debug + +default_redirection_url: https://home.example.com:8080/ + +jwt_secret: very_important_secret + +authentication_backend: + file: + path: ./test/suites/mongo/users_database.test.yml + +session: + secret: unsecure_session_secret + domain: example.com + expiration: 3600 # 1 hour + inactivity: 300 # 5 minutes + +# Configuration of the storage backend used to store data and secrets. i.e. totp data +storage: + mongo: + url: mongodb://127.0.0.1 + database: authelia + auth: + username: authelia + password: authelia + +# TOTP Issuer Name +# +# This will be the issuer name displayed in Google Authenticator +# See: https://github.com/google/google-authenticator/wiki/Key-Uri-Format for more info on issuer names +totp: + issuer: example.com + +access_control: + default_policy: deny + rules: + - domain: 'public.example.com' + policy: bypass + - domain: 'admin.example.com' + policy: two_factor + - domain: 'secure.example.com' + policy: two_factor + - domain: 'singlefactor.example.com' + policy: one_factor + + +# Configuration of the authentication regulation mechanism. +regulation: + # Set it to 0 to disable max_retries. + max_retries: 3 + + # The user is banned if the authenticaction failed `max_retries` times in a `find_time` seconds window. + find_time: 8 + + # The length of time before a banned user can login again. + ban_time: 10 + +notifier: + # Use a SMTP server for sending notifications + smtp: + host: 127.0.0.1 + port: 1025 + sender: admin@example.com + diff --git a/test/suites/mongo/environment.ts b/test/suites/mongo/environment.ts new file mode 100644 index 000000000..c2da6df49 --- /dev/null +++ b/test/suites/mongo/environment.ts @@ -0,0 +1,47 @@ +import DockerEnvironment from "../../helpers/context/DockerEnvironment"; +import AutheliaServer from "../../helpers/context/AutheliaServer"; +import { exec } from "../../helpers/utils/exec"; +import fs from 'fs'; + +const composeFiles = [ + 'docker-compose.yml', + 'example/compose/nginx/backend/docker-compose.yml', + 'example/compose/nginx/portal/docker-compose.yml', + 'example/compose/smtp/docker-compose.yml', + 'example/compose/mongo/docker-compose.yml', + 'example/compose/ldap/docker-compose.yml' +] + +const dockerEnv = new DockerEnvironment(composeFiles); +const autheliaServer = new AutheliaServer(__dirname + '/config.yml'); + +async function setup() { + await exec(`cp ${__dirname}/users_database.yml ${__dirname}/users_database.test.yml`); + // In dev mode Authelia has the server served on one port and the frontend on another port. + await exec('./example/compose/nginx/portal/render.js ' + (fs.existsSync('.suite') ? '': '--production')); + + console.log(`Prepare environment with docker-compose...`); + await dockerEnv.start(); + + console.log('Start Authelia server.'); + await autheliaServer.start(); +} + +async function teardown() { + console.log('Stop Authelia server.'); + await autheliaServer.stop(); + + console.log(`Cleanup environment with docker-compose...`); + await dockerEnv.stop(); +} + +const setup_timeout = 30000; +const teardown_timeout = 30000; + +export { + setup, + setup_timeout, + teardown, + teardown_timeout, + composeFiles +}; \ No newline at end of file diff --git a/test/suites/mongo/test.ts b/test/suites/mongo/test.ts new file mode 100644 index 000000000..f3bcede26 --- /dev/null +++ b/test/suites/mongo/test.ts @@ -0,0 +1,12 @@ +import AutheliaSuite from "../../helpers/context/AutheliaSuite"; +import SingleFactorAuthentication from "../../helpers/scenarii/SingleFactorAuthentication"; +import TwoFactorAuthentication from "../../helpers/scenarii/TwoFactorAuthentication"; +import AuthenticationBlacklisting from "../../helpers/scenarii/AuthenticationBlacklisting"; + +AutheliaSuite(__dirname, function() { + this.timeout(20000); + + describe('Single-factor authentication', SingleFactorAuthentication()) + describe('Two-factor authentication', TwoFactorAuthentication()); + describe('Authentication blacklisting', AuthenticationBlacklisting(12000)); +}); \ No newline at end of file diff --git a/test/suites/mongo/users_database.yml b/test/suites/mongo/users_database.yml new file mode 100644 index 000000000..6fe7a384d --- /dev/null +++ b/test/suites/mongo/users_database.yml @@ -0,0 +1,29 @@ +############################################################### +# Users Database # +############################################################### + +# This file can be used if you do not have an LDAP set up. + +# List of users +users: + john: + password: "{CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/" + email: john.doe@authelia.com + groups: + - admins + - dev + + harry: + password: "{CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/" + email: harry.potter@authelia.com + groups: [] + + bob: + password: "{CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/" + email: bob.dylan@authelia.com + groups: + - dev + + james: + password: "{CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/" + email: james.dean@authelia.com \ No newline at end of file diff --git a/test/suites/network-acls/config.yml b/test/suites/network-acls/config.yml index 280e1a38c..d8b99fa0e 100644 --- a/test/suites/network-acls/config.yml +++ b/test/suites/network-acls/config.yml @@ -6,6 +6,8 @@ port: 9091 logs_level: debug +jwt_secret: unsecure_password + authentication_backend: file: path: ./test/suites/basic/users_database.test.yml @@ -19,7 +21,7 @@ session: # Configuration of the storage backend used to store data and secrets. i.e. totp data storage: local: - path: /tmp/authelia/db + path: /tmp/authelia/db.sqlite # Access Control # @@ -55,9 +57,6 @@ regulation: notifier: # Use a SMTP server for sending notifications smtp: - username: test - password: password - secure: false host: 127.0.0.1 port: 1025 sender: admin@example.com diff --git a/test/suites/network-acls/environment.ts b/test/suites/network-acls/environment.ts index f73320351..adee3e677 100644 --- a/test/suites/network-acls/environment.ts +++ b/test/suites/network-acls/environment.ts @@ -10,11 +10,12 @@ const dockerEnv = new DockerEnvironment([ 'example/compose/nginx/portal/docker-compose.yml', 'example/compose/squid/docker-compose.yml', 'example/compose/smtp/docker-compose.yml', + // To debug headers + 'example/compose/httpbin/docker-compose.yml', ]) async function setup() { await exec(`cp ${__dirname}/users_database.yml ${__dirname}/users_database.test.yml`); - await exec('mkdir -p /tmp/authelia/db'); await exec('./example/compose/nginx/portal/render.js ' + (fs.existsSync('.suite') ? '': '--production')); await dockerEnv.start(); await autheliaServer.start(); @@ -23,7 +24,6 @@ async function setup() { async function teardown() { await autheliaServer.stop(); await dockerEnv.stop(); - await exec('rm -rf /tmp/authelia/db'); } const setup_timeout = 30000; diff --git a/test/suites/network-acls/scenarii/NetworkACLs.ts b/test/suites/network-acls/scenarii/NetworkACLs.ts index 3a563718d..acff0d81a 100644 --- a/test/suites/network-acls/scenarii/NetworkACLs.ts +++ b/test/suites/network-acls/scenarii/NetworkACLs.ts @@ -34,7 +34,7 @@ export default function() { it("should require two factor", async function() { await VisitPage(this.driver, "https://secure.example.com:8080/secret.html"); await VerifyUrlIs(this.driver, "https://login.example.com:8080/#/?rd=https://secure.example.com:8080/secret.html"); - await FillLoginPageAndClick(this.driver, 'john', 'password'); + await FillLoginPageAndClick(this.driver, "john", "password"); await ValidateTotp(this.driver, this.secret); await VerifyUrlIs(this.driver, "https://secure.example.com:8080/secret.html"); await VerifySecretObserved(this.driver); diff --git a/test/suites/short-timeouts/config.yml b/test/suites/short-timeouts/config.yml index 9aa9b5404..5766dbd11 100644 --- a/test/suites/short-timeouts/config.yml +++ b/test/suites/short-timeouts/config.yml @@ -6,6 +6,8 @@ port: 9091 logs_level: debug +jwt_secret: unsecure_secret + default_redirection_url: https://home.example.com:8080/ authentication_backend: @@ -15,13 +17,13 @@ authentication_backend: session: secret: unsecure_session_secret domain: example.com - inactivity: 5000 - expiration: 8000 + inactivity: 5 + expiration: 8 # Configuration of the storage backend used to store data and secrets. i.e. totp data storage: local: - path: /tmp/authelia/db + path: /tmp/authelia/db.sqlite # TOTP Issuer Name # @@ -75,7 +77,7 @@ regulation: max_retries: 3 # The user is banned if the authenticaction failed `max_retries` times in a `find_time` seconds window. - find_time: 10 + find_time: 3 # The length of time before a banned user can login again. ban_time: 5 @@ -101,9 +103,6 @@ notifier: # Use a SMTP server for sending notifications smtp: - username: test - password: password - secure: false host: 127.0.0.1 port: 1025 sender: admin@example.com diff --git a/test/suites/short-timeouts/environment.ts b/test/suites/short-timeouts/environment.ts index 8fa6b2f2a..c015abedc 100644 --- a/test/suites/short-timeouts/environment.ts +++ b/test/suites/short-timeouts/environment.ts @@ -13,7 +13,6 @@ const dockerEnv = new DockerEnvironment([ async function setup() { await exec(`cp ${__dirname}/users_database.yml ${__dirname}/users_database.test.yml`); - await exec('mkdir -p /tmp/authelia/db'); await exec('./example/compose/nginx/portal/render.js ' + (fs.existsSync('.suite') ? '': '--production')); await dockerEnv.start(); await autheliaServer.start(); @@ -22,7 +21,6 @@ async function setup() { async function teardown() { await autheliaServer.stop(); await dockerEnv.stop(); - await exec('rm -rf /tmp/authelia/db'); } const setup_timeout = 30000; diff --git a/test/suites/short-timeouts/scenarii/Inactivity.ts b/test/suites/short-timeouts/scenarii/Inactivity.ts index 9a0f03a38..aba3c991b 100644 --- a/test/suites/short-timeouts/scenarii/Inactivity.ts +++ b/test/suites/short-timeouts/scenarii/Inactivity.ts @@ -1,59 +1,68 @@ import LoginAndRegisterTotp from "../../../helpers/LoginAndRegisterTotp"; -import FillLoginPageWithUserAndPasswordAndClick from "../../../helpers/FillLoginPageAndClick"; import ValidateTotp from "../../../helpers/ValidateTotp"; import VisitPageAndWaitUrlIs from "../../../helpers/behaviors/VisitPageAndWaitUrlIs"; import VisitPage from "../../../helpers/VisitPage"; import VerifyUrlIs from "../../../helpers/assertions/VerifyUrlIs"; import { StartDriver, StopDriver } from "../../../helpers/context/WithDriver"; -import Logout from "../../../helpers/Logout"; +import ClickOnLink from "../../../helpers/ClickOnLink"; +import FillLoginPageAndClick from "../../../helpers/FillLoginPageAndClick"; export default function(this: Mocha.ISuiteCallbackContext) { this.timeout(20000); beforeEach(async function() { this.driver = await StartDriver(); - this.secret = await LoginAndRegisterTotp(this.driver, "john", "password", true); }); afterEach(async function() { await StopDriver(this.driver); }) - it("should disconnect user after inactivity period", async function() { - await VisitPageAndWaitUrlIs(this.driver, "https://login.example.com:8080/#/?rd=https://admin.example.com:8080/secret.html"); - await FillLoginPageWithUserAndPasswordAndClick(this.driver, 'john', 'password', false); - await ValidateTotp(this.driver, this.secret); - await VerifyUrlIs(this.driver, "https://admin.example.com:8080/secret.html"); - await VisitPageAndWaitUrlIs(this.driver, "https://home.example.com:8080/"); - await this.driver.sleep(6000); - await VisitPage(this.driver, "https://admin.example.com:8080/secret.html"); - await VerifyUrlIs(this.driver, "https://login.example.com:8080/#/?rd=https://admin.example.com:8080/secret.html"); - }); + describe('Remember me not checked', function() { + beforeEach(async function() { + this.secret = await LoginAndRegisterTotp(this.driver, "john", "password", true); + }); - it('should disconnect user after cookie expiration', async function() { - await VisitPageAndWaitUrlIs(this.driver, "https://login.example.com:8080/#/?rd=https://admin.example.com:8080/secret.html"); - await FillLoginPageWithUserAndPasswordAndClick(this.driver, 'john', 'password', false); - await ValidateTotp(this.driver, this.secret); - await VerifyUrlIs(this.driver, "https://admin.example.com:8080/secret.html"); - - await this.driver.sleep(2000); - await VisitPageAndWaitUrlIs(this.driver, "https://admin.example.com:8080/secret.html"); - await this.driver.sleep(2000); - await VisitPageAndWaitUrlIs(this.driver, "https://admin.example.com:8080/secret.html"); - await this.driver.sleep(2000); - await VisitPageAndWaitUrlIs(this.driver, "https://admin.example.com:8080/secret.html"); - await this.driver.sleep(2000); - await VisitPage(this.driver, "https://admin.example.com:8080/secret.html"); - await VerifyUrlIs(this.driver, "https://login.example.com:8080/#/?rd=https://admin.example.com:8080/secret.html"); - }); - - describe('With remember me checkbox checked', function() { - it("should keep user logged in after inactivity period", async function() { + it("should disconnect user after inactivity period", async function() { await VisitPageAndWaitUrlIs(this.driver, "https://login.example.com:8080/#/?rd=https://admin.example.com:8080/secret.html"); - await FillLoginPageWithUserAndPasswordAndClick(this.driver, 'john', 'password', true); await ValidateTotp(this.driver, this.secret); await VerifyUrlIs(this.driver, "https://admin.example.com:8080/secret.html"); await VisitPageAndWaitUrlIs(this.driver, "https://home.example.com:8080/"); + await this.driver.sleep(6000); + await VisitPage(this.driver, "https://admin.example.com:8080/secret.html"); + await VerifyUrlIs(this.driver, "https://login.example.com:8080/#/?rd=https://admin.example.com:8080/secret.html"); + }); + + it('should disconnect user after cookie expiration', async function() { + await VisitPageAndWaitUrlIs(this.driver, "https://login.example.com:8080/#/?rd=https://admin.example.com:8080/secret.html"); + await ValidateTotp(this.driver, this.secret); + await VerifyUrlIs(this.driver, "https://admin.example.com:8080/secret.html"); + + await this.driver.sleep(2000); + await VisitPageAndWaitUrlIs(this.driver, "https://admin.example.com:8080/secret.html"); + await this.driver.sleep(2000); + await VisitPageAndWaitUrlIs(this.driver, "https://admin.example.com:8080/secret.html"); + await this.driver.sleep(2000); + await VisitPageAndWaitUrlIs(this.driver, "https://admin.example.com:8080/secret.html"); + await this.driver.sleep(2000); + await VisitPage(this.driver, "https://admin.example.com:8080/secret.html"); + await VerifyUrlIs(this.driver, "https://login.example.com:8080/#/?rd=https://admin.example.com:8080/secret.html"); + }); + }); + + describe('With remember me checkbox checked', function() { + beforeEach(async function() { + this.secret = await LoginAndRegisterTotp(this.driver, "john", "password", true); + await VisitPageAndWaitUrlIs(this.driver, "https://login.example.com:8080/#/"); + await ClickOnLink(this.driver, "Logout"); + }); + + it("should keep user logged in after inactivity period", async function() { + await VisitPageAndWaitUrlIs(this.driver, "https://login.example.com:8080/#/?rd=https://admin.example.com:8080/secret.html"); + await FillLoginPageAndClick(this.driver, "john", "password", true); + await ValidateTotp(this.driver, this.secret); + await VerifyUrlIs(this.driver, "https://admin.example.com:8080/secret.html"); + await VisitPageAndWaitUrlIs(this.driver, "https://home.example.com:8080/#/"); await this.driver.sleep(9000); await VisitPage(this.driver, "https://admin.example.com:8080/secret.html"); await VerifyUrlIs(this.driver, "https://admin.example.com:8080/secret.html"); diff --git a/test/suites/traefik/config.yml b/test/suites/traefik/config.yml index 340e173a5..bad35cf36 100644 --- a/test/suites/traefik/config.yml +++ b/test/suites/traefik/config.yml @@ -6,6 +6,8 @@ port: 9091 logs_level: debug +jwt_secret: unsecure_secret + authentication_backend: file: path: ./test/suites/basic/users_database.test.yml @@ -18,7 +20,7 @@ session: storage: local: - path: /tmp/authelia/db + path: /tmp/authelia/db.sqlite access_control: default_policy: bypass @@ -34,9 +36,6 @@ access_control: notifier: smtp: - username: test - password: password - secure: false host: 127.0.0.1 port: 1025 sender: admin@example.com diff --git a/test/suites/traefik/environment.ts b/test/suites/traefik/environment.ts index 471069058..0acd18b17 100644 --- a/test/suites/traefik/environment.ts +++ b/test/suites/traefik/environment.ts @@ -14,7 +14,6 @@ const dockerEnv = new DockerEnvironment([ async function setup() { await exec('./example/compose/traefik/render.js ' + (fs.existsSync('.suite') ? '': '--production')); await exec(`cp ${__dirname}/users_database.yml ${__dirname}/users_database.test.yml`); - await exec('mkdir -p /tmp/authelia/db'); await dockerEnv.start(); await autheliaServer.start(); } @@ -22,7 +21,6 @@ async function setup() { async function teardown() { await autheliaServer.stop(); await dockerEnv.stop(); - await exec('rm -rf /tmp/authelia/db'); } const setup_timeout = 30000;