|
|
|
@ -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 ( |
|
|
|
|