summaryrefslogtreecommitdiff
path: root/internal/util
diff options
context:
space:
mode:
Diffstat (limited to 'internal/util')
-rw-r--r--internal/util/regexes.go114
-rw-r--r--internal/util/statustools.go12
-rw-r--r--internal/util/uri.go42
-rw-r--r--internal/util/validation.go178
-rw-r--r--internal/util/validation_test.go283
5 files changed, 29 insertions, 600 deletions
diff --git a/internal/util/regexes.go b/internal/util/regexes.go
deleted file mode 100644
index 36af9e7aa..000000000
--- a/internal/util/regexes.go
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- GoToSocial
- Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package util
-
-import (
- "fmt"
- "regexp"
-)
-
-const (
- maximumUsernameLength = 64
- maximumEmojiShortcodeLength = 30
- maximumHashtagLength = 30
-)
-
-var (
- mentionNameRegexString = `^@(\w+)(?:@([a-zA-Z0-9_\-\.:]+)?)$`
- // mention name regex captures the username and domain part from a mention string
- // such as @whatever_user@example.org, returning whatever_user and example.org (without the @ symbols)
- mentionNameRegex = regexp.MustCompile(mentionNameRegexString)
-
- // mention regex can be played around with here: https://regex101.com/r/qwM9D3/1
- mentionFinderRegexString = `(?:\B)(@\w+(?:@[a-zA-Z0-9_\-\.]+)?)(?:\B)?`
- mentionFinderRegex = regexp.MustCompile(mentionFinderRegexString)
-
- // hashtag regex can be played with here: https://regex101.com/r/bPxeca/1
- hashtagFinderRegexString = fmt.Sprintf(`(?:^|\n|\s)(#[a-zA-Z0-9]{1,%d})(?:\b)`, maximumHashtagLength)
- // HashtagFinderRegex finds possible hashtags in a string.
- // It returns just the string part of the hashtag, not the # symbol.
- HashtagFinderRegex = regexp.MustCompile(hashtagFinderRegexString)
-
- emojiShortcodeRegexString = fmt.Sprintf(`\w{2,%d}`, maximumEmojiShortcodeLength)
- emojiShortcodeValidationRegex = regexp.MustCompile(fmt.Sprintf("^%s$", emojiShortcodeRegexString))
-
- // emoji regex can be played with here: https://regex101.com/r/478XGM/1
- emojiFinderRegexString = fmt.Sprintf(`(?:\B)?:(%s):(?:\B)?`, emojiShortcodeRegexString)
- emojiFinderRegex = regexp.MustCompile(emojiFinderRegexString)
-
- // usernameRegexString defines an acceptable username on this instance
- usernameRegexString = fmt.Sprintf(`[a-z0-9_]{2,%d}`, maximumUsernameLength)
- // usernameValidationRegex can be used to validate usernames of new signups
- usernameValidationRegex = regexp.MustCompile(fmt.Sprintf(`^%s$`, usernameRegexString))
-
- userPathRegexString = fmt.Sprintf(`^?/%s/(%s)$`, UsersPath, usernameRegexString)
- // userPathRegex parses a path that validates and captures the username part from eg /users/example_username
- userPathRegex = regexp.MustCompile(userPathRegexString)
-
- userPublicKeyPathRegexString = fmt.Sprintf(`^?/%s/(%s)/%s`, UsersPath, usernameRegexString, PublicKeyPath)
- userPublicKeyPathRegex = regexp.MustCompile(userPublicKeyPathRegexString)
-
- inboxPathRegexString = fmt.Sprintf(`^/?%s/(%s)/%s$`, UsersPath, usernameRegexString, InboxPath)
- // inboxPathRegex parses a path that validates and captures the username part from eg /users/example_username/inbox
- inboxPathRegex = regexp.MustCompile(inboxPathRegexString)
-
- outboxPathRegexString = fmt.Sprintf(`^/?%s/(%s)/%s$`, UsersPath, usernameRegexString, OutboxPath)
- // outboxPathRegex parses a path that validates and captures the username part from eg /users/example_username/outbox
- outboxPathRegex = regexp.MustCompile(outboxPathRegexString)
-
- actorPathRegexString = fmt.Sprintf(`^?/%s/(%s)$`, ActorsPath, usernameRegexString)
- // actorPathRegex parses a path that validates and captures the username part from eg /actors/example_username
- actorPathRegex = regexp.MustCompile(actorPathRegexString)
-
- followersPathRegexString = fmt.Sprintf(`^/?%s/(%s)/%s$`, UsersPath, usernameRegexString, FollowersPath)
- // followersPathRegex parses a path that validates and captures the username part from eg /users/example_username/followers
- followersPathRegex = regexp.MustCompile(followersPathRegexString)
-
- followingPathRegexString = fmt.Sprintf(`^/?%s/(%s)/%s$`, UsersPath, usernameRegexString, FollowingPath)
- // followingPathRegex parses a path that validates and captures the username part from eg /users/example_username/following
- followingPathRegex = regexp.MustCompile(followingPathRegexString)
-
- followPathRegexString = fmt.Sprintf(`^/?%s/(%s)/%s/(%s)$`, UsersPath, usernameRegexString, FollowPath, ulidRegexString)
- // followPathRegex parses a path that validates and captures the username part and the ulid part
- // from eg /users/example_username/follow/01F7XT5JZW1WMVSW1KADS8PVDH
- followPathRegex = regexp.MustCompile(followPathRegexString)
-
- ulidRegexString = `[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}`
- ulidRegex = regexp.MustCompile(fmt.Sprintf(`^%s$`, ulidRegexString))
-
- likedPathRegexString = fmt.Sprintf(`^/?%s/(%s)/%s$`, UsersPath, usernameRegexString, LikedPath)
- // likedPathRegex parses a path that validates and captures the username part from eg /users/example_username/liked
- likedPathRegex = regexp.MustCompile(likedPathRegexString)
-
- likePathRegexString = fmt.Sprintf(`^/?%s/(%s)/%s/(%s)$`, UsersPath, usernameRegexString, LikedPath, ulidRegexString)
- // likePathRegex parses a path that validates and captures the username part and the ulid part
- // from eg /users/example_username/like/01F7XT5JZW1WMVSW1KADS8PVDH
- likePathRegex = regexp.MustCompile(likePathRegexString)
-
- statusesPathRegexString = fmt.Sprintf(`^/?%s/(%s)/%s/(%s)$`, UsersPath, usernameRegexString, StatusesPath, ulidRegexString)
- // statusesPathRegex parses a path that validates and captures the username part and the ulid part
- // from eg /users/example_username/statuses/01F7XT5JZW1WMVSW1KADS8PVDH
- // The regex can be played with here: https://regex101.com/r/G9zuxQ/1
- statusesPathRegex = regexp.MustCompile(statusesPathRegexString)
-
- blockPathRegexString = fmt.Sprintf(`^/?%s/(%s)/%s/(%s)$`, UsersPath, usernameRegexString, BlocksPath, ulidRegexString)
- // blockPathRegex parses a path that validates and captures the username part and the ulid part
- // from eg /users/example_username/blocks/01F7XT5JZW1WMVSW1KADS8PVDH
- blockPathRegex = regexp.MustCompile(blockPathRegexString)
-)
diff --git a/internal/util/statustools.go b/internal/util/statustools.go
index 4a89e60f6..ca18577b0 100644
--- a/internal/util/statustools.go
+++ b/internal/util/statustools.go
@@ -21,6 +21,8 @@ package util
import (
"fmt"
"strings"
+
+ "github.com/superseriousbusiness/gotosocial/internal/regexes"
)
// DeriveMentionsFromStatus takes a plaintext (ie., not html-formatted) status,
@@ -31,7 +33,7 @@ import (
// or the form "@username" for local users.
func DeriveMentionsFromStatus(status string) []string {
mentionedAccounts := []string{}
- for _, m := range mentionFinderRegex.FindAllStringSubmatch(status, -1) {
+ for _, m := range regexes.MentionFinder.FindAllStringSubmatch(status, -1) {
mentionedAccounts = append(mentionedAccounts, m[1])
}
return UniqueStrings(mentionedAccounts)
@@ -43,7 +45,7 @@ func DeriveMentionsFromStatus(status string) []string {
// tags will be lowered, for consistency.
func DeriveHashtagsFromStatus(status string) []string {
tags := []string{}
- for _, m := range HashtagFinderRegex.FindAllStringSubmatch(status, -1) {
+ for _, m := range regexes.HashtagFinder.FindAllStringSubmatch(status, -1) {
tags = append(tags, strings.TrimPrefix(m[1], "#"))
}
return UniqueStrings(tags)
@@ -54,7 +56,7 @@ func DeriveHashtagsFromStatus(status string) []string {
// used in that status, without the surround ::.
func DeriveEmojisFromStatus(status string) []string {
emojis := []string{}
- for _, m := range emojiFinderRegex.FindAllStringSubmatch(status, -1) {
+ for _, m := range regexes.EmojiFinder.FindAllStringSubmatch(status, -1) {
emojis = append(emojis, m[1])
}
return UniqueStrings(emojis)
@@ -65,7 +67,7 @@ func DeriveEmojisFromStatus(status string) []string {
//
// If nothing is matched, it will return an error.
func ExtractMentionParts(mention string) (username, domain string, err error) {
- matches := mentionNameRegex.FindStringSubmatch(mention)
+ matches := regexes.MentionName.FindStringSubmatch(mention)
if matches == nil || len(matches) != 3 {
err = fmt.Errorf("could't match mention %s", mention)
return
@@ -77,5 +79,5 @@ func ExtractMentionParts(mention string) (username, domain string, err error) {
// IsMention returns true if the passed string looks like @whatever@example.org
func IsMention(mention string) bool {
- return mentionNameRegex.MatchString(strings.ToLower(mention))
+ return regexes.MentionName.MatchString(strings.ToLower(mention))
}
diff --git a/internal/util/uri.go b/internal/util/uri.go
index 370b2fa6f..91f523a4d 100644
--- a/internal/util/uri.go
+++ b/internal/util/uri.go
@@ -21,6 +21,8 @@ package util
import (
"fmt"
"net/url"
+
+ "github.com/superseriousbusiness/gotosocial/internal/regexes"
)
const (
@@ -169,67 +171,67 @@ func GenerateURIsForAccount(username string, protocol string, host string) *User
// IsUserPath returns true if the given URL path corresponds to eg /users/example_username
func IsUserPath(id *url.URL) bool {
- return userPathRegex.MatchString(id.Path)
+ return regexes.UserPath.MatchString(id.Path)
}
// IsInboxPath returns true if the given URL path corresponds to eg /users/example_username/inbox
func IsInboxPath(id *url.URL) bool {
- return inboxPathRegex.MatchString(id.Path)
+ return regexes.InboxPath.MatchString(id.Path)
}
// IsOutboxPath returns true if the given URL path corresponds to eg /users/example_username/outbox
func IsOutboxPath(id *url.URL) bool {
- return outboxPathRegex.MatchString(id.Path)
+ return regexes.OutboxPath.MatchString(id.Path)
}
// IsInstanceActorPath returns true if the given URL path corresponds to eg /actors/example_username
func IsInstanceActorPath(id *url.URL) bool {
- return actorPathRegex.MatchString(id.Path)
+ return regexes.ActorPath.MatchString(id.Path)
}
// IsFollowersPath returns true if the given URL path corresponds to eg /users/example_username/followers
func IsFollowersPath(id *url.URL) bool {
- return followersPathRegex.MatchString(id.Path)
+ return regexes.FollowersPath.MatchString(id.Path)
}
// IsFollowingPath returns true if the given URL path corresponds to eg /users/example_username/following
func IsFollowingPath(id *url.URL) bool {
- return followingPathRegex.MatchString(id.Path)
+ return regexes.FollowingPath.MatchString(id.Path)
}
// IsFollowPath returns true if the given URL path corresponds to eg /users/example_username/follow/SOME_ULID_OF_A_FOLLOW
func IsFollowPath(id *url.URL) bool {
- return followPathRegex.MatchString(id.Path)
+ return regexes.FollowPath.MatchString(id.Path)
}
// IsLikedPath returns true if the given URL path corresponds to eg /users/example_username/liked
func IsLikedPath(id *url.URL) bool {
- return likedPathRegex.MatchString(id.Path)
+ return regexes.LikedPath.MatchString(id.Path)
}
// IsLikePath returns true if the given URL path corresponds to eg /users/example_username/liked/SOME_ULID_OF_A_STATUS
func IsLikePath(id *url.URL) bool {
- return likePathRegex.MatchString(id.Path)
+ return regexes.LikePath.MatchString(id.Path)
}
// IsStatusesPath returns true if the given URL path corresponds to eg /users/example_username/statuses/SOME_ULID_OF_A_STATUS
func IsStatusesPath(id *url.URL) bool {
- return statusesPathRegex.MatchString(id.Path)
+ return regexes.StatusesPath.MatchString(id.Path)
}
// IsPublicKeyPath returns true if the given URL path corresponds to eg /users/example_username/main-key
func IsPublicKeyPath(id *url.URL) bool {
- return userPublicKeyPathRegex.MatchString(id.Path)
+ return regexes.PublicKeyPath.MatchString(id.Path)
}
// IsBlockPath returns true if the given URL path corresponds to eg /users/example_username/blocks/SOME_ULID_OF_A_BLOCK
func IsBlockPath(id *url.URL) bool {
- return blockPathRegex.MatchString(id.Path)
+ return regexes.BlockPath.MatchString(id.Path)
}
// ParseStatusesPath returns the username and ulid from a path such as /users/example_username/statuses/SOME_ULID_OF_A_STATUS
func ParseStatusesPath(id *url.URL) (username string, ulid string, err error) {
- matches := statusesPathRegex.FindStringSubmatch(id.Path)
+ matches := regexes.StatusesPath.FindStringSubmatch(id.Path)
if len(matches) != 3 {
err = fmt.Errorf("expected 3 matches but matches length was %d", len(matches))
return
@@ -241,7 +243,7 @@ func ParseStatusesPath(id *url.URL) (username string, ulid string, err error) {
// ParseUserPath returns the username from a path such as /users/example_username
func ParseUserPath(id *url.URL) (username string, err error) {
- matches := userPathRegex.FindStringSubmatch(id.Path)
+ matches := regexes.UserPath.FindStringSubmatch(id.Path)
if len(matches) != 2 {
err = fmt.Errorf("expected 2 matches but matches length was %d", len(matches))
return
@@ -252,7 +254,7 @@ func ParseUserPath(id *url.URL) (username string, err error) {
// ParseInboxPath returns the username from a path such as /users/example_username/inbox
func ParseInboxPath(id *url.URL) (username string, err error) {
- matches := inboxPathRegex.FindStringSubmatch(id.Path)
+ matches := regexes.InboxPath.FindStringSubmatch(id.Path)
if len(matches) != 2 {
err = fmt.Errorf("expected 2 matches but matches length was %d", len(matches))
return
@@ -263,7 +265,7 @@ func ParseInboxPath(id *url.URL) (username string, err error) {
// ParseOutboxPath returns the username from a path such as /users/example_username/outbox
func ParseOutboxPath(id *url.URL) (username string, err error) {
- matches := outboxPathRegex.FindStringSubmatch(id.Path)
+ matches := regexes.OutboxPath.FindStringSubmatch(id.Path)
if len(matches) != 2 {
err = fmt.Errorf("expected 2 matches but matches length was %d", len(matches))
return
@@ -274,7 +276,7 @@ func ParseOutboxPath(id *url.URL) (username string, err error) {
// ParseFollowersPath returns the username from a path such as /users/example_username/followers
func ParseFollowersPath(id *url.URL) (username string, err error) {
- matches := followersPathRegex.FindStringSubmatch(id.Path)
+ matches := regexes.FollowersPath.FindStringSubmatch(id.Path)
if len(matches) != 2 {
err = fmt.Errorf("expected 2 matches but matches length was %d", len(matches))
return
@@ -285,7 +287,7 @@ func ParseFollowersPath(id *url.URL) (username string, err error) {
// ParseFollowingPath returns the username from a path such as /users/example_username/following
func ParseFollowingPath(id *url.URL) (username string, err error) {
- matches := followingPathRegex.FindStringSubmatch(id.Path)
+ matches := regexes.FollowingPath.FindStringSubmatch(id.Path)
if len(matches) != 2 {
err = fmt.Errorf("expected 2 matches but matches length was %d", len(matches))
return
@@ -296,7 +298,7 @@ func ParseFollowingPath(id *url.URL) (username string, err error) {
// ParseLikedPath returns the username and ulid from a path such as /users/example_username/liked/SOME_ULID_OF_A_STATUS
func ParseLikedPath(id *url.URL) (username string, ulid string, err error) {
- matches := likePathRegex.FindStringSubmatch(id.Path)
+ matches := regexes.LikePath.FindStringSubmatch(id.Path)
if len(matches) != 3 {
err = fmt.Errorf("expected 3 matches but matches length was %d", len(matches))
return
@@ -308,7 +310,7 @@ func ParseLikedPath(id *url.URL) (username string, ulid string, err error) {
// ParseBlockPath returns the username and ulid from a path such as /users/example_username/blocks/SOME_ULID_OF_A_BLOCK
func ParseBlockPath(id *url.URL) (username string, ulid string, err error) {
- matches := blockPathRegex.FindStringSubmatch(id.Path)
+ matches := regexes.BlockPath.FindStringSubmatch(id.Path)
if len(matches) != 3 {
err = fmt.Errorf("expected 3 matches but matches length was %d", len(matches))
return
diff --git a/internal/util/validation.go b/internal/util/validation.go
deleted file mode 100644
index aa25ccd16..000000000
--- a/internal/util/validation.go
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- GoToSocial
- Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package util
-
-import (
- "errors"
- "fmt"
- "net/mail"
-
- pwv "github.com/wagslane/go-password-validator"
- "golang.org/x/text/language"
-)
-
-const (
- maximumPasswordLength = 64
- minimumPasswordEntropy = 60 // dictates password strength. See https://github.com/wagslane/go-password-validator
- minimumReasonLength = 40
- maximumReasonLength = 500
- maximumSiteTitleLength = 40
- maximumShortDescriptionLength = 500
- maximumDescriptionLength = 5000
- maximumSiteTermsLength = 5000
-)
-
-// ValidateNewPassword returns an error if the given password is not sufficiently strong, or nil if it's ok.
-func ValidateNewPassword(password string) error {
- if password == "" {
- return errors.New("no password provided")
- }
-
- if len(password) > maximumPasswordLength {
- return fmt.Errorf("password should be no more than %d chars", maximumPasswordLength)
- }
-
- return pwv.Validate(password, minimumPasswordEntropy)
-}
-
-// ValidateUsername makes sure that a given username is valid (ie., letters, numbers, underscores, check length).
-// Returns an error if not.
-func ValidateUsername(username string) error {
- if username == "" {
- return errors.New("no username provided")
- }
-
- if !usernameValidationRegex.MatchString(username) {
- return fmt.Errorf("given username %s was invalid: must contain only lowercase letters, numbers, and underscores, max %d characters", username, maximumUsernameLength)
- }
-
- return nil
-}
-
-// ValidateEmail makes sure that a given email address is a valid address.
-// Returns an error if not.
-func ValidateEmail(email string) error {
- if email == "" {
- return errors.New("no email provided")
- }
-
- _, err := mail.ParseAddress(email)
- return err
-}
-
-// ValidateLanguage checks that the given language string is a 2- or 3-letter ISO 639 code.
-// Returns an error if the language cannot be parsed. See: https://pkg.go.dev/golang.org/x/text/language
-func ValidateLanguage(lang string) error {
- if lang == "" {
- return errors.New("no language provided")
- }
- _, err := language.ParseBase(lang)
- return err
-}
-
-// ValidateSignUpReason checks that a sufficient reason is given for a server signup request
-func ValidateSignUpReason(reason string, reasonRequired bool) error {
- if !reasonRequired {
- // we don't care!
- // we're not going to do anything with this text anyway if no reason is required
- return nil
- }
-
- if reason == "" {
- return errors.New("no reason provided")
- }
-
- if len(reason) < minimumReasonLength {
- return fmt.Errorf("reason should be at least %d chars but '%s' was %d", minimumReasonLength, reason, len(reason))
- }
-
- if len(reason) > maximumReasonLength {
- return fmt.Errorf("reason should be no more than %d chars but given reason was %d", maximumReasonLength, len(reason))
- }
- return nil
-}
-
-// ValidateDisplayName checks that a requested display name is valid
-func ValidateDisplayName(displayName string) error {
- // TODO: add some validation logic here -- length, characters, etc
- return nil
-}
-
-// ValidateNote checks that a given profile/account note/bio is valid
-func ValidateNote(note string) error {
- // TODO: add some validation logic here -- length, characters, etc
- return nil
-}
-
-// ValidatePrivacy checks that the desired privacy setting is valid
-func ValidatePrivacy(privacy string) error {
- // TODO: add some validation logic here -- length, characters, etc
- return nil
-}
-
-// ValidateEmojiShortcode just runs the given shortcode through the regular expression
-// for emoji shortcodes, to figure out whether it's a valid shortcode, ie., 2-30 characters,
-// lowercase a-z, numbers, and underscores.
-func ValidateEmojiShortcode(shortcode string) error {
- if !emojiShortcodeValidationRegex.MatchString(shortcode) {
- return fmt.Errorf("shortcode %s did not pass validation, must be between 2 and 30 characters, lowercase letters, numbers, and underscores only", shortcode)
- }
- return nil
-}
-
-// ValidateSiteTitle ensures that the given site title is within spec.
-func ValidateSiteTitle(siteTitle string) error {
- if len(siteTitle) > maximumSiteTitleLength {
- return fmt.Errorf("site title should be no more than %d chars but given title was %d", maximumSiteTitleLength, len(siteTitle))
- }
-
- return nil
-}
-
-// ValidateSiteShortDescription ensures that the given site short description is within spec.
-func ValidateSiteShortDescription(d string) error {
- if len(d) > maximumShortDescriptionLength {
- return fmt.Errorf("short description should be no more than %d chars but given description was %d", maximumShortDescriptionLength, len(d))
- }
-
- return nil
-}
-
-// ValidateSiteDescription ensures that the given site description is within spec.
-func ValidateSiteDescription(d string) error {
- if len(d) > maximumDescriptionLength {
- return fmt.Errorf("description should be no more than %d chars but given description was %d", maximumDescriptionLength, len(d))
- }
-
- return nil
-}
-
-// ValidateSiteTerms ensures that the given site terms string is within spec.
-func ValidateSiteTerms(t string) error {
- if len(t) > maximumSiteTermsLength {
- return fmt.Errorf("terms should be no more than %d chars but given terms was %d", maximumSiteTermsLength, len(t))
- }
-
- return nil
-}
-
-// ValidateULID returns true if the passed string is a valid ULID.
-func ValidateULID(i string) bool {
- return ulidRegex.MatchString(i)
-}
diff --git a/internal/util/validation_test.go b/internal/util/validation_test.go
deleted file mode 100644
index 639a89bbd..000000000
--- a/internal/util/validation_test.go
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- GoToSocial
- Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package util_test
-
-import (
- "errors"
- "fmt"
- "testing"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/suite"
- "github.com/superseriousbusiness/gotosocial/internal/util"
-)
-
-type ValidationTestSuite struct {
- suite.Suite
-}
-
-func (suite *ValidationTestSuite) TestCheckPasswordStrength() {
- empty := ""
- terriblePassword := "password"
- weakPassword := "OKPassword"
- shortPassword := "Ok12"
- specialPassword := "Ok12%"
- longPassword := "thisisafuckinglongpasswordbutnospecialchars"
- tooLong := "Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Quisque a enim nibh. Vestibulum bibendum leo ac porttitor auctor."
- strongPassword := "3dX5@Zc%mV*W2MBNEy$@"
- var err error
-
- err = util.ValidateNewPassword(empty)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("no password provided"), err)
- }
-
- err = util.ValidateNewPassword(terriblePassword)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("insecure password, try including more special characters, using uppercase letters, using numbers or using a longer password"), err)
- }
-
- err = util.ValidateNewPassword(weakPassword)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("insecure password, try including more special characters, using numbers or using a longer password"), err)
- }
-
- err = util.ValidateNewPassword(shortPassword)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("insecure password, try including more special characters or using a longer password"), err)
- }
-
- err = util.ValidateNewPassword(specialPassword)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("insecure password, try including more special characters or using a longer password"), err)
- }
-
- err = util.ValidateNewPassword(longPassword)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
- }
-
- err = util.ValidateNewPassword(tooLong)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("password should be no more than 64 chars"), err)
- }
-
- err = util.ValidateNewPassword(strongPassword)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
- }
-}
-
-func (suite *ValidationTestSuite) TestValidateUsername() {
- empty := ""
- tooLong := "holycrapthisisthelongestusernameiveeverseeninmylifethatstoomuchman"
- withSpaces := "this username has spaces in it"
- weirdChars := "thisusername&&&&&&&istooweird!!"
- leadingSpace := " see_that_leading_space"
- trailingSpace := "thisusername_ends_with_a_space "
- newlines := "this_is\n_almost_ok"
- goodUsername := "this_is_a_good_username"
- var err error
-
- err = util.ValidateUsername(empty)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("no username provided"), err)
- }
-
- err = util.ValidateUsername(tooLong)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), fmt.Errorf("given username %s was invalid: must contain only lowercase letters, numbers, and underscores, max 64 characters", tooLong), err)
- }
-
- err = util.ValidateUsername(withSpaces)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), fmt.Errorf("given username %s was invalid: must contain only lowercase letters, numbers, and underscores, max 64 characters", withSpaces), err)
- }
-
- err = util.ValidateUsername(weirdChars)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), fmt.Errorf("given username %s was invalid: must contain only lowercase letters, numbers, and underscores, max 64 characters", weirdChars), err)
- }
-
- err = util.ValidateUsername(leadingSpace)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), fmt.Errorf("given username %s was invalid: must contain only lowercase letters, numbers, and underscores, max 64 characters", leadingSpace), err)
- }
-
- err = util.ValidateUsername(trailingSpace)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), fmt.Errorf("given username %s was invalid: must contain only lowercase letters, numbers, and underscores, max 64 characters", trailingSpace), err)
- }
-
- err = util.ValidateUsername(newlines)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), fmt.Errorf("given username %s was invalid: must contain only lowercase letters, numbers, and underscores, max 64 characters", newlines), err)
- }
-
- err = util.ValidateUsername(goodUsername)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
- }
-}
-
-func (suite *ValidationTestSuite) TestValidateEmail() {
- empty := ""
- notAnEmailAddress := "this-is-no-email-address!"
- almostAnEmailAddress := "@thisisalmostan@email.address"
- aWebsite := "https://thisisawebsite.com"
- emailAddress := "thisis.actually@anemail.address"
- var err error
-
- err = util.ValidateEmail(empty)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("no email provided"), err)
- }
-
- err = util.ValidateEmail(notAnEmailAddress)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("mail: missing '@' or angle-addr"), err)
- }
-
- err = util.ValidateEmail(almostAnEmailAddress)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("mail: no angle-addr"), err)
- }
-
- err = util.ValidateEmail(aWebsite)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("mail: missing '@' or angle-addr"), err)
- }
-
- err = util.ValidateEmail(emailAddress)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
- }
-}
-
-func (suite *ValidationTestSuite) TestValidateLanguage() {
- empty := ""
- notALanguage := "this isn't a language at all!"
- english := "en"
- capitalEnglish := "EN"
- arabic3Letters := "ara"
- mixedCapsEnglish := "eN"
- englishUS := "en-us"
- dutch := "nl"
- german := "de"
- var err error
-
- err = util.ValidateLanguage(empty)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("no language provided"), err)
- }
-
- err = util.ValidateLanguage(notALanguage)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("language: tag is not well-formed"), err)
- }
-
- err = util.ValidateLanguage(english)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
- }
-
- err = util.ValidateLanguage(capitalEnglish)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
- }
-
- err = util.ValidateLanguage(arabic3Letters)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
- }
-
- err = util.ValidateLanguage(mixedCapsEnglish)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
- }
-
- err = util.ValidateLanguage(englishUS)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("language: tag is not well-formed"), err)
- }
-
- err = util.ValidateLanguage(dutch)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
- }
-
- err = util.ValidateLanguage(german)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
- }
-}
-
-func (suite *ValidationTestSuite) TestValidateReason() {
- empty := ""
- badReason := "because"
- goodReason := "to smash the state and destroy capitalism ultimately and completely"
- tooLong := "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris auctor mollis viverra. Maecenas maximus mollis sem, nec fermentum velit consectetur non. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Quisque a enim nibh. Vestibulum bibendum leo ac porttitor auctor. Curabitur velit tellus, facilisis vitae lorem a, ullamcorper efficitur leo. Sed a auctor tortor. Sed ut finibus ante, sit amet laoreet sapien. Donec ullamcorper tellus a nibh sodales vulputate. Donec id dolor eu odio mollis bibendum. Pellentesque habitant morbi tristique senectus et netus at."
- var err error
-
- // check with no reason required
- err = util.ValidateSignUpReason(empty, false)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
- }
-
- err = util.ValidateSignUpReason(badReason, false)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
- }
-
- err = util.ValidateSignUpReason(tooLong, false)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
- }
-
- err = util.ValidateSignUpReason(goodReason, false)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
- }
-
- // check with reason required
- err = util.ValidateSignUpReason(empty, true)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("no reason provided"), err)
- }
-
- err = util.ValidateSignUpReason(badReason, true)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("reason should be at least 40 chars but 'because' was 7"), err)
- }
-
- err = util.ValidateSignUpReason(tooLong, true)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("reason should be no more than 500 chars but given reason was 600"), err)
- }
-
- err = util.ValidateSignUpReason(goodReason, true)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
- }
-}
-
-func TestValidationTestSuite(t *testing.T) {
- suite.Run(t, new(ValidationTestSuite))
-}