aboutsummaryrefslogtreecommitdiff
path: root/internal/db
diff options
context:
space:
mode:
Diffstat (limited to 'internal/db')
-rw-r--r--internal/db/org_team.go4
-rw-r--r--internal/db/repo.go10
-rw-r--r--internal/db/user.go110
-rw-r--r--internal/db/users.go141
-rw-r--r--internal/db/users_test.go40
5 files changed, 175 insertions, 130 deletions
diff --git a/internal/db/org_team.go b/internal/db/org_team.go
index 6bdf4253..cfc4c08c 100644
--- a/internal/db/org_team.go
+++ b/internal/db/org_team.go
@@ -245,7 +245,9 @@ func (t *Team) RemoveRepository(repoID int64) error {
return sess.Commit()
}
-var reservedTeamNames = []string{"new"}
+var reservedTeamNames = map[string]struct{}{
+ "new": {},
+}
// IsUsableTeamName return an error if given name is a reserved name or pattern.
func IsUsableTeamName(name string) error {
diff --git a/internal/db/repo.go b/internal/db/repo.go
index bb2cd52e..81a6cd00 100644
--- a/internal/db/repo.go
+++ b/internal/db/repo.go
@@ -1081,8 +1081,14 @@ func initRepository(e Engine, repoPath string, doer *User, repo *Repository, opt
}
var (
- reservedRepoNames = []string{".", ".."}
- reservedRepoPatterns = []string{"*.git", "*.wiki"}
+ reservedRepoNames = map[string]struct{}{
+ ".": {},
+ "..": {},
+ }
+ reservedRepoPatterns = []string{
+ "*.git",
+ "*.wiki",
+ }
)
// isRepoNameAllowed return an error if given name is a reserved name or pattern for repositories.
diff --git a/internal/db/user.go b/internal/db/user.go
index 4e5e4c1f..e15c9410 100644
--- a/internal/db/user.go
+++ b/internal/db/user.go
@@ -13,7 +13,6 @@ import (
"path/filepath"
"strings"
"time"
- "unicode/utf8"
"github.com/unknwon/com"
log "unknwon.dev/clog/v2"
@@ -59,115 +58,6 @@ func (u *User) getOrganizationCount(e Engine) (int64, error) {
return e.Where("uid=?", u.ID).Count(new(OrgUser))
}
-var (
- reservedUsernames = []string{"-", "explore", "create", "assets", "css", "img", "js", "less", "plugins", "debug", "raw", "install", "api", "avatar", "user", "org", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin", "new", ".", ".."}
- reservedUserPatterns = []string{"*.keys"}
-)
-
-type ErrNameNotAllowed struct {
- args errutil.Args
-}
-
-func IsErrNameNotAllowed(err error) bool {
- _, ok := err.(ErrNameNotAllowed)
- return ok
-}
-
-func (err ErrNameNotAllowed) Value() string {
- val, ok := err.args["name"].(string)
- if ok {
- return val
- }
-
- val, ok = err.args["pattern"].(string)
- if ok {
- return val
- }
-
- return "<value not found>"
-}
-
-func (err ErrNameNotAllowed) Error() string {
- return fmt.Sprintf("name is not allowed: %v", err.args)
-}
-
-// isNameAllowed checks if name is reserved or pattern of name is not allowed
-// based on given reserved names and patterns.
-// Names are exact match, patterns can be prefix or suffix match with placeholder '*'.
-func isNameAllowed(names, patterns []string, name string) error {
- name = strings.TrimSpace(strings.ToLower(name))
- if utf8.RuneCountInString(name) == 0 {
- return ErrNameNotAllowed{args: errutil.Args{"reason": "empty name"}}
- }
-
- for i := range names {
- if name == names[i] {
- return ErrNameNotAllowed{args: errutil.Args{"reason": "reserved", "name": name}}
- }
- }
-
- for _, pat := range patterns {
- if pat[0] == '*' && strings.HasSuffix(name, pat[1:]) ||
- (pat[len(pat)-1] == '*' && strings.HasPrefix(name, pat[:len(pat)-1])) {
- return ErrNameNotAllowed{args: errutil.Args{"reason": "reserved", "pattern": pat}}
- }
- }
-
- return nil
-}
-
-// isUsernameAllowed return an error if given name is a reserved name or pattern for users.
-func isUsernameAllowed(name string) error {
- return isNameAllowed(reservedUsernames, reservedUserPatterns, name)
-}
-
-// CreateUser creates record of a new user.
-//
-// Deprecated: Use Users.Create instead.
-func CreateUser(u *User) (err error) {
- if err = isUsernameAllowed(u.Name); err != nil {
- return err
- }
-
- if Users.IsUsernameUsed(context.TODO(), u.Name) {
- return ErrUserAlreadyExist{args: errutil.Args{"name": u.Name}}
- }
-
- u.Email = strings.ToLower(u.Email)
- isExist, err := IsEmailUsed(u.Email)
- if err != nil {
- return err
- } else if isExist {
- return ErrEmailAlreadyUsed{args: errutil.Args{"email": u.Email}}
- }
-
- u.LowerName = strings.ToLower(u.Name)
- u.AvatarEmail = u.Email
- u.Avatar = tool.HashEmail(u.AvatarEmail)
- if u.Rands, err = userutil.RandomSalt(); err != nil {
- return err
- }
- if u.Salt, err = userutil.RandomSalt(); err != nil {
- return err
- }
- u.Password = userutil.EncodePassword(u.Password, u.Salt)
- u.MaxRepoCreation = -1
-
- sess := x.NewSession()
- defer sess.Close()
- if err = sess.Begin(); err != nil {
- return err
- }
-
- if _, err = sess.Insert(u); err != nil {
- return err
- } else if err = os.MkdirAll(UserPath(u.Name), os.ModePerm); err != nil {
- return err
- }
-
- return sess.Commit()
-}
-
func countUsers(e Engine) int64 {
count, _ := e.Where("type=0").Count(new(User))
return count
diff --git a/internal/db/users.go b/internal/db/users.go
index f87dc28d..37494638 100644
--- a/internal/db/users.go
+++ b/internal/db/users.go
@@ -10,6 +10,7 @@ import (
"os"
"strings"
"time"
+ "unicode/utf8"
"github.com/go-macaron/binding"
api "github.com/gogs/go-gogs-client"
@@ -234,12 +235,20 @@ func (db *users) Create(ctx context.Context, username, email string, opts Create
}
if db.IsUsernameUsed(ctx, username) {
- return nil, ErrUserAlreadyExist{args: errutil.Args{"name": username}}
+ return nil, ErrUserAlreadyExist{
+ args: errutil.Args{
+ "name": username,
+ },
+ }
}
_, err = db.GetByEmail(ctx, email)
if err == nil {
- return nil, ErrEmailAlreadyUsed{args: errutil.Args{"email": email}}
+ return nil, ErrEmailAlreadyUsed{
+ args: errutil.Args{
+ "email": email,
+ },
+ }
} else if !IsErrUserNotExist(err) {
return nil, err
}
@@ -257,7 +266,7 @@ func (db *users) Create(ctx context.Context, username, email string, opts Create
MaxRepoCreation: -1,
IsActive: opts.Activated,
IsAdmin: opts.Admin,
- Avatar: cryptoutil.MD5(email),
+ Avatar: cryptoutil.MD5(email), // Gravatar URL uses the MD5 hash of the email, see https://en.gravatar.com/site/implement/hash/
AvatarEmail: email,
}
@@ -579,16 +588,6 @@ func (u *User) DisplayName() string {
return u.Name
}
-// NewGhostUser creates and returns a fake user for people who has deleted their
-// accounts.
-func NewGhostUser() *User {
- return &User{
- ID: -1,
- Name: "Ghost",
- LowerName: "ghost",
- }
-}
-
// HomeURLPath returns the URL path to the user or organization home page.
//
// TODO(unknwon): This is also used in templates, which should be fixed by
@@ -693,3 +692,119 @@ func (u *User) GetOrganizationCount() (int64, error) {
func (u *User) ShortName(length int) string {
return strutil.Ellipsis(u.Name, length)
}
+
+// NewGhostUser creates and returns a fake user for people who has deleted their
+// accounts.
+//
+// TODO: Once migrated to unknwon.dev/i18n, pass in the `i18n.Locale` to
+// translate the text to local language.
+func NewGhostUser() *User {
+ return &User{
+ ID: -1,
+ Name: "Ghost",
+ LowerName: "ghost",
+ }
+}
+
+var (
+ reservedUsernames = map[string]struct{}{
+ "-": {},
+ "explore": {},
+ "create": {},
+ "assets": {},
+ "css": {},
+ "img": {},
+ "js": {},
+ "less": {},
+ "plugins": {},
+ "debug": {},
+ "raw": {},
+ "install": {},
+ "api": {},
+ "avatar": {},
+ "user": {},
+ "org": {},
+ "help": {},
+ "stars": {},
+ "issues": {},
+ "pulls": {},
+ "commits": {},
+ "repo": {},
+ "template": {},
+ "admin": {},
+ "new": {},
+ ".": {},
+ "..": {},
+ }
+ reservedUsernamePatterns = []string{"*.keys"}
+)
+
+type ErrNameNotAllowed struct {
+ args errutil.Args
+}
+
+func IsErrNameNotAllowed(err error) bool {
+ _, ok := err.(ErrNameNotAllowed)
+ return ok
+}
+
+func (err ErrNameNotAllowed) Value() string {
+ val, ok := err.args["name"].(string)
+ if ok {
+ return val
+ }
+
+ val, ok = err.args["pattern"].(string)
+ if ok {
+ return val
+ }
+
+ return "<value not found>"
+}
+
+func (err ErrNameNotAllowed) Error() string {
+ return fmt.Sprintf("name is not allowed: %v", err.args)
+}
+
+// isNameAllowed checks if the name is reserved or pattern of the name is not
+// allowed based on given reserved names and patterns. Names are exact match,
+// patterns can be prefix or suffix match with the wildcard ("*").
+func isNameAllowed(names map[string]struct{}, patterns []string, name string) error {
+ name = strings.TrimSpace(strings.ToLower(name))
+ if utf8.RuneCountInString(name) == 0 {
+ return ErrNameNotAllowed{
+ args: errutil.Args{
+ "reason": "empty name",
+ },
+ }
+ }
+
+ if _, ok := names[name]; ok {
+ return ErrNameNotAllowed{
+ args: errutil.Args{
+ "reason": "reserved",
+ "name": name,
+ },
+ }
+ }
+
+ for _, pattern := range patterns {
+ if pattern[0] == '*' && strings.HasSuffix(name, pattern[1:]) ||
+ (pattern[len(pattern)-1] == '*' && strings.HasPrefix(name, pattern[:len(pattern)-1])) {
+ return ErrNameNotAllowed{
+ args: errutil.Args{
+ "reason": "reserved",
+ "pattern": pattern,
+ },
+ }
+ }
+ }
+
+ return nil
+}
+
+// isUsernameAllowed returns ErrNameNotAllowed if the given name or pattern of
+// the name is not allowed as a username.
+func isUsernameAllowed(name string) error {
+ return isNameAllowed(reservedUsernames, reservedUsernamePatterns, name)
+}
diff --git a/internal/db/users_test.go b/internal/db/users_test.go
index 9c940f6b..2479702a 100644
--- a/internal/db/users_test.go
+++ b/internal/db/users_test.go
@@ -8,6 +8,7 @@ import (
"context"
"fmt"
"os"
+ "strings"
"testing"
"time"
@@ -211,7 +212,10 @@ func usersAuthenticate(t *testing.T, db *users) {
func usersCreate(t *testing.T, db *users) {
ctx := context.Background()
- alice, err := db.Create(ctx, "alice", "alice@example.com",
+ alice, err := db.Create(
+ ctx,
+ "alice",
+ "alice@example.com",
CreateUserOptions{
Activated: true,
},
@@ -220,19 +224,32 @@ func usersCreate(t *testing.T, db *users) {
t.Run("name not allowed", func(t *testing.T) {
_, err := db.Create(ctx, "-", "", CreateUserOptions{})
- wantErr := ErrNameNotAllowed{args: errutil.Args{"reason": "reserved", "name": "-"}}
+ wantErr := ErrNameNotAllowed{
+ args: errutil.Args{
+ "reason": "reserved",
+ "name": "-",
+ },
+ }
assert.Equal(t, wantErr, err)
})
t.Run("name already exists", func(t *testing.T) {
_, err := db.Create(ctx, alice.Name, "", CreateUserOptions{})
- wantErr := ErrUserAlreadyExist{args: errutil.Args{"name": alice.Name}}
+ wantErr := ErrUserAlreadyExist{
+ args: errutil.Args{
+ "name": alice.Name,
+ },
+ }
assert.Equal(t, wantErr, err)
})
t.Run("email already exists", func(t *testing.T) {
_, err := db.Create(ctx, "bob", alice.Email, CreateUserOptions{})
- wantErr := ErrEmailAlreadyUsed{args: errutil.Args{"email": alice.Email}}
+ wantErr := ErrEmailAlreadyUsed{
+ args: errutil.Args{
+ "email": alice.Email,
+ },
+ }
assert.Equal(t, wantErr, err)
})
@@ -495,3 +512,18 @@ func usersUseCustomAvatar(t *testing.T, db *users) {
require.NoError(t, err)
assert.True(t, alice.UseCustomAvatar)
}
+
+func TestIsUsernameAllowed(t *testing.T) {
+ for name := range reservedUsernames {
+ t.Run(name, func(t *testing.T) {
+ assert.True(t, IsErrNameNotAllowed(isUsernameAllowed(name)))
+ })
+ }
+
+ for _, pattern := range reservedUsernamePatterns {
+ t.Run(pattern, func(t *testing.T) {
+ username := strings.ReplaceAll(pattern, "*", "alice")
+ assert.True(t, IsErrNameNotAllowed(isUsernameAllowed(username)))
+ })
+ }
+}