mirror of
https://github.com/go-gitea/gitea.git
synced 2025-02-02 15:09:33 -05:00
parent
a9577e0808
commit
8c4f0f02ef
@ -7,6 +7,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
@ -321,6 +322,11 @@ func valuesUser(m map[int64]*user_model.User) []*user_model.User {
|
|||||||
return values
|
return values
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// newMigrationOriginalUser creates and returns a fake user for external user
|
||||||
|
func newMigrationOriginalUser(name string) *user_model.User {
|
||||||
|
return &user_model.User{ID: 0, Name: name, LowerName: strings.ToLower(name)}
|
||||||
|
}
|
||||||
|
|
||||||
// LoadUsers loads reactions' all users
|
// LoadUsers loads reactions' all users
|
||||||
func (list ReactionList) LoadUsers(ctx context.Context, repo *repo_model.Repository) ([]*user_model.User, error) {
|
func (list ReactionList) LoadUsers(ctx context.Context, repo *repo_model.Repository) ([]*user_model.User, error) {
|
||||||
if len(list) == 0 {
|
if len(list) == 0 {
|
||||||
@ -338,7 +344,7 @@ func (list ReactionList) LoadUsers(ctx context.Context, repo *repo_model.Reposit
|
|||||||
|
|
||||||
for _, reaction := range list {
|
for _, reaction := range list {
|
||||||
if reaction.OriginalAuthor != "" {
|
if reaction.OriginalAuthor != "" {
|
||||||
reaction.User = user_model.NewReplaceUser(fmt.Sprintf("%s(%s)", reaction.OriginalAuthor, repo.OriginalServiceType.Name()))
|
reaction.User = newMigrationOriginalUser(fmt.Sprintf("%s(%s)", reaction.OriginalAuthor, repo.OriginalServiceType.Name()))
|
||||||
} else if user, ok := userMaps[reaction.UserID]; ok {
|
} else if user, ok := userMaps[reaction.UserID]; ok {
|
||||||
reaction.User = user
|
reaction.User = user
|
||||||
} else {
|
} else {
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/mail"
|
"net/mail"
|
||||||
"regexp"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -153,8 +152,6 @@ func UpdateEmailAddress(ctx context.Context, email *EmailAddress) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var emailRegexp = regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]*@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")
|
|
||||||
|
|
||||||
// ValidateEmail check if email is a valid & allowed address
|
// ValidateEmail check if email is a valid & allowed address
|
||||||
func ValidateEmail(email string) error {
|
func ValidateEmail(email string) error {
|
||||||
if err := validateEmailBasic(email); err != nil {
|
if err := validateEmailBasic(email); err != nil {
|
||||||
@ -514,7 +511,7 @@ func validateEmailBasic(email string) error {
|
|||||||
return ErrEmailInvalid{email}
|
return ErrEmailInvalid{email}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !emailRegexp.MatchString(email) {
|
if !globalVars().emailRegexp.MatchString(email) {
|
||||||
return ErrEmailCharIsNotSupported{email}
|
return ErrEmailCharIsNotSupported{email}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,9 +11,6 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrOpenIDNotExist openid is not known
|
|
||||||
var ErrOpenIDNotExist = util.NewNotExistErrorf("OpenID is unknown")
|
|
||||||
|
|
||||||
// UserOpenID is the list of all OpenID identities of a user.
|
// UserOpenID is the list of all OpenID identities of a user.
|
||||||
// Since this is a middle table, name it OpenID is not suitable, so we ignore the lint here
|
// Since this is a middle table, name it OpenID is not suitable, so we ignore the lint here
|
||||||
type UserOpenID struct { //revive:disable-line:exported
|
type UserOpenID struct { //revive:disable-line:exported
|
||||||
@ -99,7 +96,7 @@ func DeleteUserOpenID(ctx context.Context, openid *UserOpenID) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
} else if deleted != 1 {
|
} else if deleted != 1 {
|
||||||
return ErrOpenIDNotExist
|
return util.NewNotExistErrorf("OpenID is unknown")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
@ -417,19 +418,9 @@ func (u *User) DisplayName() string {
|
|||||||
return u.Name
|
return u.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
var emailToReplacer = strings.NewReplacer(
|
|
||||||
"\n", "",
|
|
||||||
"\r", "",
|
|
||||||
"<", "",
|
|
||||||
">", "",
|
|
||||||
",", "",
|
|
||||||
":", "",
|
|
||||||
";", "",
|
|
||||||
)
|
|
||||||
|
|
||||||
// EmailTo returns a string suitable to be put into a e-mail `To:` header.
|
// EmailTo returns a string suitable to be put into a e-mail `To:` header.
|
||||||
func (u *User) EmailTo() string {
|
func (u *User) EmailTo() string {
|
||||||
sanitizedDisplayName := emailToReplacer.Replace(u.DisplayName())
|
sanitizedDisplayName := globalVars().emailToReplacer.Replace(u.DisplayName())
|
||||||
|
|
||||||
// should be an edge case but nice to have
|
// should be an edge case but nice to have
|
||||||
if sanitizedDisplayName == u.Email {
|
if sanitizedDisplayName == u.Email {
|
||||||
@ -526,28 +517,52 @@ func GetUserSalt() (string, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
// Returns a 32 bytes long string.
|
// Returns a 32-byte long string.
|
||||||
return hex.EncodeToString(rBytes), nil
|
return hex.EncodeToString(rBytes), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type globalVarsStruct struct {
|
||||||
|
customCharsReplacement *strings.Replacer
|
||||||
|
removeCharsRE *regexp.Regexp
|
||||||
|
transformDiacritics transform.Transformer
|
||||||
|
replaceCharsHyphenRE *regexp.Regexp
|
||||||
|
emailToReplacer *strings.Replacer
|
||||||
|
emailRegexp *regexp.Regexp
|
||||||
|
}
|
||||||
|
|
||||||
|
var globalVars = sync.OnceValue(func() *globalVarsStruct {
|
||||||
|
return &globalVarsStruct{
|
||||||
// Note: The set of characters here can safely expand without a breaking change,
|
// Note: The set of characters here can safely expand without a breaking change,
|
||||||
// but characters removed from this set can cause user account linking to break
|
// but characters removed from this set can cause user account linking to break
|
||||||
var (
|
customCharsReplacement: strings.NewReplacer("Æ", "AE"),
|
||||||
customCharsReplacement = strings.NewReplacer("Æ", "AE")
|
|
||||||
removeCharsRE = regexp.MustCompile("['`´]")
|
removeCharsRE: regexp.MustCompile("['`´]"),
|
||||||
transformDiacritics = transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC)
|
transformDiacritics: transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC),
|
||||||
replaceCharsHyphenRE = regexp.MustCompile(`[\s~+]`)
|
replaceCharsHyphenRE: regexp.MustCompile(`[\s~+]`),
|
||||||
)
|
|
||||||
|
emailToReplacer: strings.NewReplacer(
|
||||||
|
"\n", "",
|
||||||
|
"\r", "",
|
||||||
|
"<", "",
|
||||||
|
">", "",
|
||||||
|
",", "",
|
||||||
|
":", "",
|
||||||
|
";", "",
|
||||||
|
),
|
||||||
|
emailRegexp: regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]*@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$"),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// NormalizeUserName only takes the name part if it is an email address, transforms it diacritics to ASCII characters.
|
// NormalizeUserName only takes the name part if it is an email address, transforms it diacritics to ASCII characters.
|
||||||
// It returns a string with the single-quotes removed, and any other non-supported username characters are replaced with a `-` character
|
// It returns a string with the single-quotes removed, and any other non-supported username characters are replaced with a `-` character
|
||||||
func NormalizeUserName(s string) (string, error) {
|
func NormalizeUserName(s string) (string, error) {
|
||||||
|
vars := globalVars()
|
||||||
s, _, _ = strings.Cut(s, "@")
|
s, _, _ = strings.Cut(s, "@")
|
||||||
strDiacriticsRemoved, n, err := transform.String(transformDiacritics, customCharsReplacement.Replace(s))
|
strDiacriticsRemoved, n, err := transform.String(vars.transformDiacritics, vars.customCharsReplacement.Replace(s))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to normalize the string of provided username %q at position %d", s, n)
|
return "", fmt.Errorf("failed to normalize the string of provided username %q at position %d", s, n)
|
||||||
}
|
}
|
||||||
return replaceCharsHyphenRE.ReplaceAllLiteralString(removeCharsRE.ReplaceAllLiteralString(strDiacriticsRemoved, ""), "-"), nil
|
return vars.replaceCharsHyphenRE.ReplaceAllLiteralString(vars.removeCharsRE.ReplaceAllLiteralString(strDiacriticsRemoved, ""), "-"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -12,7 +12,6 @@ import (
|
|||||||
const (
|
const (
|
||||||
GhostUserID = -1
|
GhostUserID = -1
|
||||||
GhostUserName = "Ghost"
|
GhostUserName = "Ghost"
|
||||||
GhostUserLowerName = "ghost"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewGhostUser creates and returns a fake user for someone has deleted their account.
|
// NewGhostUser creates and returns a fake user for someone has deleted their account.
|
||||||
@ -20,10 +19,14 @@ func NewGhostUser() *User {
|
|||||||
return &User{
|
return &User{
|
||||||
ID: GhostUserID,
|
ID: GhostUserID,
|
||||||
Name: GhostUserName,
|
Name: GhostUserName,
|
||||||
LowerName: GhostUserLowerName,
|
LowerName: strings.ToLower(GhostUserName),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsGhostUserName(name string) bool {
|
||||||
|
return strings.EqualFold(name, GhostUserName)
|
||||||
|
}
|
||||||
|
|
||||||
// IsGhost check if user is fake user for a deleted account
|
// IsGhost check if user is fake user for a deleted account
|
||||||
func (u *User) IsGhost() bool {
|
func (u *User) IsGhost() bool {
|
||||||
if u == nil {
|
if u == nil {
|
||||||
@ -32,20 +35,10 @@ func (u *User) IsGhost() bool {
|
|||||||
return u.ID == GhostUserID && u.Name == GhostUserName
|
return u.ID == GhostUserID && u.Name == GhostUserName
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewReplaceUser creates and returns a fake user for external user
|
|
||||||
func NewReplaceUser(name string) *User {
|
|
||||||
return &User{
|
|
||||||
ID: 0,
|
|
||||||
Name: name,
|
|
||||||
LowerName: strings.ToLower(name),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ActionsUserID = -2
|
ActionsUserID = -2
|
||||||
ActionsUserName = "gitea-actions"
|
ActionsUserName = "gitea-actions"
|
||||||
ActionsFullName = "Gitea Actions"
|
ActionsUserEmail = "teabot@gitea.io"
|
||||||
ActionsEmail = "teabot@gitea.io"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewActionsUser creates and returns a fake user for running the actions.
|
// NewActionsUser creates and returns a fake user for running the actions.
|
||||||
@ -55,8 +48,8 @@ func NewActionsUser() *User {
|
|||||||
Name: ActionsUserName,
|
Name: ActionsUserName,
|
||||||
LowerName: ActionsUserName,
|
LowerName: ActionsUserName,
|
||||||
IsActive: true,
|
IsActive: true,
|
||||||
FullName: ActionsFullName,
|
FullName: "Gitea Actions",
|
||||||
Email: ActionsEmail,
|
Email: ActionsUserEmail,
|
||||||
KeepEmailPrivate: true,
|
KeepEmailPrivate: true,
|
||||||
LoginName: ActionsUserName,
|
LoginName: ActionsUserName,
|
||||||
Type: UserTypeIndividual,
|
Type: UserTypeIndividual,
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
package user
|
package user
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/avatars"
|
"code.gitea.io/gitea/models/avatars"
|
||||||
@ -27,7 +26,7 @@ func AvatarByUserName(ctx *context.Context) {
|
|||||||
size := int(ctx.PathParamInt64("size"))
|
size := int(ctx.PathParamInt64("size"))
|
||||||
|
|
||||||
var user *user_model.User
|
var user *user_model.User
|
||||||
if strings.ToLower(userName) != user_model.GhostUserLowerName {
|
if !user_model.IsGhostUserName(userName) {
|
||||||
var err error
|
var err error
|
||||||
if user, err = user_model.GetUserByName(ctx, userName); err != nil {
|
if user, err = user_model.GetUserByName(ctx, userName); err != nil {
|
||||||
if user_model.IsErrUserNotExist(err) {
|
if user_model.IsErrUserNotExist(err) {
|
||||||
|
Loading…
Reference in New Issue
Block a user