Skip to content

Commit 8bf5e68

Browse files
committed
Remove diacritics
1 parent a41bd17 commit 8bf5e68

File tree

6 files changed

+36
-16
lines changed

6 files changed

+36
-16
lines changed

docs/content/administration/config-cheat-sheet.en-us.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -598,7 +598,7 @@ And the following unique queues:
598598
- userid - use the userid / sub attribute
599599
- nickname - use the nickname attribute
600600
- email - use the username part of the email attribute
601-
- email-normalized - use the username part of the email attribute,with single-quotes removed and any other non-supported username characters replaced with a `-` character
601+
- email-normalized - use the username part of the email attribute with diacritics and single-quotes removed, and any other non-supported username characters replaced with a `-` character
602602
- `UPDATE_AVATAR`: **false**: Update avatar if available from oauth2 provider. Update will be performed on each login.
603603
- `ACCOUNT_LINKING`: **login**: How to handle if an account / email already exists:
604604
- disabled - show an error

models/user/user.go

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"regexp"
1414
"strings"
1515
"time"
16+
"unicode"
1617

1718
_ "image/jpeg" // Needed for jpeg support
1819

@@ -29,6 +30,9 @@ import (
2930
"code.gitea.io/gitea/modules/timeutil"
3031
"code.gitea.io/gitea/modules/util"
3132
"code.gitea.io/gitea/modules/validation"
33+
"golang.org/x/text/runes"
34+
"golang.org/x/text/transform"
35+
"golang.org/x/text/unicode/norm"
3236

3337
"xorm.io/builder"
3438
)
@@ -516,13 +520,19 @@ func GetUserSalt() (string, error) {
516520
return hex.EncodeToString(rBytes), nil
517521
}
518522

519-
var validUsernameRE = regexp.MustCompile(`[^\w-.]`)
523+
var invalidUsernameCharsRE = regexp.MustCompile(`[^\w-.]`)
524+
var removeDiacriticsTransform = transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC)
525+
var removeChars = strings.NewReplacer("'", "")
520526

521-
// normalizeUserName returns a string with single-quotes removed,
522-
// and any other non-supported username characters replaced with
527+
// normalizeUserName returns a string with single-quotes and diacritics
528+
// removed, and any other non-supported username characters replaced with
523529
// a `-` character
524-
func NormalizeUserName(s string) string {
525-
return validUsernameRE.ReplaceAllString(strings.ReplaceAll(s, "'", ""), "-")
530+
func NormalizeUserName(s string) (string, error) {
531+
strDiacriticsRemoved, n, err := transform.String(removeDiacriticsTransform, s)
532+
if err != nil {
533+
return "", fmt.Errorf("Failed to normalize character `%v` in provided username `%v`", s[n], s)
534+
}
535+
return invalidUsernameCharsRE.ReplaceAllString(removeChars.Replace(strDiacriticsRemoved), "-"), nil
526536
}
527537

528538
var (

models/user/user_test.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -552,17 +552,18 @@ func Test_NormalizeUserFromEmail(t *testing.T) {
552552
IsNormalizedValid bool
553553
}{
554554
{"test", "test", true},
555-
{"Sinéad.O'Connor", "Sin-ad.OConnor", true},
556-
{"Æsir", "-sir", false},
555+
{"Sinéad.O'Connor", "Sinead.OConnor", true},
556+
{"Æsir", "-sir", false}, // Currently unsupported
557557
// \u00e9\u0065\u0301
558-
{"éé", "-e-", false},
558+
{"éé", "ee", true},
559559
{"Awareness Hub", "Awareness-Hub", true},
560560
{"double__underscore", "double__underscore", false}, // We should consider squashing double non-alpha characters
561561
{".bad.", ".bad.", false},
562562
{"new😀user", "new-user", true},
563563
}
564564
for _, testCase := range testCases {
565-
normalizedName := user_model.NormalizeUserName(testCase.Input)
565+
normalizedName, err := user_model.NormalizeUserName(testCase.Input)
566+
assert.NoError(t, err)
566567
assert.EqualValues(t, testCase.Expected, normalizedName)
567568
if testCase.IsNormalizedValid {
568569
assert.NoError(t, user_model.IsUsableUsername(normalizedName))

routers/web/auth/auth.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -368,16 +368,16 @@ func handleSignInFull(ctx *context.Context, u *user_model.User, remember, obeyRe
368368
return setting.AppSubURL + "/"
369369
}
370370

371-
func getUserName(gothUser *goth.User) string {
371+
func getUserName(gothUser *goth.User) (string, error) {
372372
switch setting.OAuth2Client.Username {
373373
case setting.OAuth2UsernameEmail:
374-
return strings.Split(gothUser.Email, "@")[0]
374+
return strings.Split(gothUser.Email, "@")[0], nil
375375
case setting.OAuth2UsernameEmailNormalized:
376376
return user_model.NormalizeUserName(strings.Split(gothUser.Email, "@")[0])
377377
case setting.OAuth2UsernameNickname:
378-
return gothUser.NickName
378+
return gothUser.NickName, nil
379379
default: // OAuth2UsernameUserid
380-
return gothUser.UserID
380+
return gothUser.UserID, nil
381381
}
382382
}
383383

routers/web/auth/linkaccount.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,11 @@ func LinkAccount(ctx *context.Context) {
5555
}
5656

5757
gu, _ := gothUser.(goth.User)
58-
uname := getUserName(&gu)
58+
uname, err := getUserName(&gu)
59+
if err != nil {
60+
ctx.ServerError("UserSignIn", err)
61+
return
62+
}
5963
email := gu.Email
6064
ctx.Data["user_name"] = uname
6165
ctx.Data["email"] = email

routers/web/auth/oauth.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -970,8 +970,13 @@ func SignInOAuthCallback(ctx *context.Context) {
970970
ctx.ServerError("CreateUser", err)
971971
return
972972
}
973+
uname, err := getUserName(&gothUser)
974+
if err != nil {
975+
ctx.ServerError("UserSignIn", err)
976+
return
977+
}
973978
u = &user_model.User{
974-
Name: getUserName(&gothUser),
979+
Name: uname,
975980
FullName: gothUser.Name,
976981
Email: gothUser.Email,
977982
LoginType: auth.OAuth2,

0 commit comments

Comments
 (0)