aboutsummaryrefslogtreecommitdiffstats
path: root/models
diff options
context:
space:
mode:
authorKyle D <kdumontnu@gmail.com>2024-01-03 16:48:20 -0800
committerGitHub <noreply@github.com>2024-01-03 18:48:20 -0600
commit54acf7b0d4b57907a6d8a2ac470744f185adf0b5 (patch)
treea9c6a5df44c445b5301ad8f7e3e3218f68fde5f7 /models
parent657b23d6359bbbb25b3dcfee233cae0735997188 (diff)
downloadgitea-54acf7b0d4b57907a6d8a2ac470744f185adf0b5.tar.gz
gitea-54acf7b0d4b57907a6d8a2ac470744f185adf0b5.zip
Normalize oauth email username (#28561)
Diffstat (limited to 'models')
-rw-r--r--models/user/user.go25
-rw-r--r--models/user/user_test.go28
2 files changed, 53 insertions, 0 deletions
diff --git a/models/user/user.go b/models/user/user.go
index ce0e055b15..d828f3d65d 100644
--- a/models/user/user.go
+++ b/models/user/user.go
@@ -10,8 +10,10 @@ import (
"fmt"
"net/url"
"path/filepath"
+ "regexp"
"strings"
"time"
+ "unicode"
_ "image/jpeg" // Needed for jpeg support
@@ -29,6 +31,9 @@ import (
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/validation"
+ "golang.org/x/text/runes"
+ "golang.org/x/text/transform"
+ "golang.org/x/text/unicode/norm"
"xorm.io/builder"
)
@@ -515,6 +520,26 @@ func GetUserSalt() (string, error) {
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(`['´\x60]`)
+ removeDiacriticsTransform = transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC)
+ replaceCharsHyphenRE = regexp.MustCompile(`[\s~+]`)
+)
+
+// normalizeUserName returns a string with single-quotes and diacritics
+// removed, and any other non-supported username characters replaced with
+// a `-` character
+func NormalizeUserName(s string) (string, error) {
+ strDiacriticsRemoved, n, err := transform.String(removeDiacriticsTransform, customCharsReplacement.Replace(s))
+ if err != nil {
+ return "", fmt.Errorf("Failed to normalize character `%v` in provided username `%v`", s[n], s)
+ }
+ return replaceCharsHyphenRE.ReplaceAllLiteralString(removeCharsRE.ReplaceAllLiteralString(strDiacriticsRemoved, ""), "-"), nil
+}
+
var (
reservedUsernames = []string{
".",
diff --git a/models/user/user_test.go b/models/user/user_test.go
index 971117482c..65aebea43a 100644
--- a/models/user/user_test.go
+++ b/models/user/user_test.go
@@ -544,3 +544,31 @@ func Test_ValidateUser(t *testing.T) {
assert.EqualValues(t, expected, err == nil, fmt.Sprintf("case: %+v", kase))
}
}
+
+func Test_NormalizeUserFromEmail(t *testing.T) {
+ testCases := []struct {
+ Input string
+ Expected string
+ IsNormalizedValid bool
+ }{
+ {"test", "test", true},
+ {"Sinéad.O'Connor", "Sinead.OConnor", true},
+ {"Æsir", "AEsir", true},
+ // \u00e9\u0065\u0301
+ {"éé", "ee", true},
+ {"Awareness Hub", "Awareness-Hub", true},
+ {"double__underscore", "double__underscore", false}, // We should consider squashing double non-alpha characters
+ {".bad.", ".bad.", false},
+ {"new😀user", "new😀user", false}, // No plans to support
+ }
+ for _, testCase := range testCases {
+ normalizedName, err := user_model.NormalizeUserName(testCase.Input)
+ assert.NoError(t, err)
+ assert.EqualValues(t, testCase.Expected, normalizedName)
+ if testCase.IsNormalizedValid {
+ assert.NoError(t, user_model.IsUsableUsername(normalizedName))
+ } else {
+ assert.Error(t, user_model.IsUsableUsername(normalizedName))
+ }
+ }
+}