|
|
|
@ -14,6 +14,7 @@ import (
|
|
|
|
|
"path/filepath"
|
|
|
|
|
"regexp"
|
|
|
|
|
"strings"
|
|
|
|
|
"sync"
|
|
|
|
|
"time"
|
|
|
|
|
"unicode"
|
|
|
|
|
|
|
|
|
@ -417,19 +418,9 @@ func (u *User) DisplayName() string {
|
|
|
|
|
return u.Name
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var emailToReplacer = strings.NewReplacer(
|
|
|
|
|
"\n", "",
|
|
|
|
|
"\r", "",
|
|
|
|
|
"<", "",
|
|
|
|
|
">", "",
|
|
|
|
|
",", "",
|
|
|
|
|
":", "",
|
|
|
|
|
";", "",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// EmailTo returns a string suitable to be put into a e-mail `To:` header.
|
|
|
|
|
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
|
|
|
|
|
if sanitizedDisplayName == u.Email {
|
|
|
|
@ -526,28 +517,52 @@ func GetUserSalt() (string, error) {
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
// Returns a 32 bytes long string.
|
|
|
|
|
// Returns a 32-byte long string.
|
|
|
|
|
return hex.EncodeToString(rBytes), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
var (
|
|
|
|
|
customCharsReplacement = strings.NewReplacer("Æ", "AE")
|
|
|
|
|
removeCharsRE = regexp.MustCompile("['`´]")
|
|
|
|
|
transformDiacritics = transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC)
|
|
|
|
|
replaceCharsHyphenRE = regexp.MustCompile(`[\s~+]`)
|
|
|
|
|
)
|
|
|
|
|
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,
|
|
|
|
|
// but characters removed from this set can cause user account linking to break
|
|
|
|
|
customCharsReplacement: strings.NewReplacer("Æ", "AE"),
|
|
|
|
|
|
|
|
|
|
removeCharsRE: regexp.MustCompile("['`´]"),
|
|
|
|
|
transformDiacritics: transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC),
|
|
|
|
|
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.
|
|
|
|
|
// 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) {
|
|
|
|
|
vars := globalVars()
|
|
|
|
|
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 {
|
|
|
|
|
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 (
|
|
|
|
|