diff --git a/backend/db/member.go b/backend/db/member.go index e893348..71b3bd0 100644 --- a/backend/db/member.go +++ b/backend/db/member.go @@ -3,6 +3,7 @@ package db import ( "context" "regexp" + "strings" "time" "emperror.dev/errors" @@ -40,10 +41,18 @@ const ( // member names must match this regex var memberNameRegex = regexp.MustCompile("^[^@\\?!#/\\\\[\\]\"\\{\\}'$%&()+<=>^|~`,]{1,100}$") +// List of member names that cannot be used because they would break routing or be inaccessible due to page conflicts. +var invalidMemberNames = []string{ + ".", + "..", + "edit", +} + func MemberNameValid(name string) bool { - // These two names will break routing, but periods should still be allowed in names otherwise. - if name == "." || name == ".." { - return false + for i := range invalidMemberNames { + if strings.EqualFold(name, invalidMemberNames[i]) { + return false + } } return memberNameRegex.MatchString(name) diff --git a/backend/db/user.go b/backend/db/user.go index 7f6834e..2389a56 100644 --- a/backend/db/user.go +++ b/backend/db/user.go @@ -6,6 +6,7 @@ import ( "encoding/hex" "fmt" "regexp" + "strings" "time" "codeberg.org/pronounscc/pronouns.cc/backend/common" @@ -138,12 +139,22 @@ const ( // usernames must match this regex var usernameRegex = regexp.MustCompile(`^[\w-.]{2,40}$`) -func UsernameValid(username string) (err error) { - // This name would break routing, but periods should still be allowed in names otherwise. - if username == ".." { - return ErrInvalidUsername - } +// List of usernames that cannot be used, because they could create confusion, conflict with other pages, or cause bugs. +var invalidUsernames = []string{ + "..", + "admin", + "administrator", + "mod", + "moderator", + "api", + "page", + "pronouns", + "settings", + "pronouns.cc", + "pronounscc", +} +func UsernameValid(username string) (err error) { if !usernameRegex.MatchString(username) { if len(username) < 2 { return ErrUsernameTooShort @@ -153,6 +164,13 @@ func UsernameValid(username string) (err error) { return ErrInvalidUsername } + + for i := range invalidUsernames { + if strings.EqualFold(username, invalidUsernames[i]) { + return ErrBannedUsername + } + } + return nil } @@ -163,6 +181,7 @@ const ( ErrInvalidUsername = errors.Sentinel("username contains invalid characters") ErrUsernameTooShort = errors.Sentinel("username is too short") ErrUsernameTooLong = errors.Sentinel("username is too long") + ErrBannedUsername = errors.Sentinel("username is banned") ) const ( diff --git a/backend/routes/user/patch_user.go b/backend/routes/user/patch_user.go index a07f6e9..fc465b1 100644 --- a/backend/routes/user/patch_user.go +++ b/backend/routes/user/patch_user.go @@ -232,6 +232,8 @@ func (s *Server) patchUser(w http.ResponseWriter, r *http.Request) error { return server.APIError{Code: server.ErrUsernameTaken} case db.ErrInvalidUsername: return server.APIError{Code: server.ErrInvalidUsername} + case db.ErrBannedUsername: + return server.APIError{Code: server.ErrInvalidUsername, Details: "That username cannot be used."} default: return errors.Wrap(err, "updating username") }