Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gitealize usernames #3

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions assets/go-licenses.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ require (
github.com/microcosm-cc/bluemonday v1.0.25
github.com/minio/minio-go/v7 v7.0.52
github.com/minio/sha256-simd v1.0.0
github.com/mozillazg/go-unidecode v0.2.0
github.com/msteinert/pam v1.1.0
github.com/nektos/act v0.2.45
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -829,6 +829,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/mozillazg/go-unidecode v0.2.0 h1:vFGEzAH9KSwyWmXCOblazEWDh7fOkpmy/Z4ArmamSUc=
github.com/mozillazg/go-unidecode v0.2.0/go.mod h1:zB48+/Z5toiRolOZy9ksLryJ976VIwmDmpQ2quyt1aA=
github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c/go.mod h1:skjdDftzkFALcuGzYSklqYd8gvat6F1gZJ4YPVbkZpM=
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 h1:j2kD3MT1z4PXCiUllUJF9mWUESr9TWKS7iEKsQ/IipM=
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450/go.mod h1:skjdDftzkFALcuGzYSklqYd8gvat6F1gZJ4YPVbkZpM=
Expand Down
2 changes: 1 addition & 1 deletion services/auth/source/oauth2/blenderid/blenderid.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ func userFromReader(r io.Reader, user *goth.User) error {
}
user.Email = u.Email
user.Name = u.Name
user.NickName = u.NickName
user.NickName = gitealizeUsername(u.NickName)
user.UserID = strconv.Itoa(u.ID)
user.AvatarURL = fmt.Sprintf("https://id.blender.org/api/user/%s/avatar", user.UserID)
return nil
Expand Down
65 changes: 65 additions & 0 deletions services/auth/source/oauth2/blenderid/gitealize_usernames.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package blenderid

import (
"regexp"
"strings"

"code.gitea.io/gitea/models/user"

"github.com/mozillazg/go-unidecode"
)

var (
reInvalidCharsPattern = regexp.MustCompile(`[^\da-zA-Z.\w-]+`)

// Consecutive non-alphanumeric at start:
reConsPrefix = regexp.MustCompile(`^[._-]+`)
reConsSuffix = regexp.MustCompile(`[._-]+$`)
reConsInfix = regexp.MustCompile(`[._-]{2,}`)
)

// gitealizeUsername turns a valid Blender ID nickname into a valid Gitea username.
func gitealizeUsername(bidNickname string) string {
// Remove accents and other non-ASCIIness.
asciiUsername := unidecode.Unidecode(bidNickname)
asciiUsername = strings.TrimSpace(asciiUsername)
asciiUsername = strings.ReplaceAll(asciiUsername, " ", "_")

err := user.IsUsableUsername(asciiUsername)
if err == nil && len(asciiUsername) <= 40 {
return asciiUsername
}

newUsername := asciiUsername
newUsername = reInvalidCharsPattern.ReplaceAllString(newUsername, "_")
newUsername = reConsPrefix.ReplaceAllString(newUsername, "")
newUsername = reConsSuffix.ReplaceAllString(newUsername, "")
newUsername = reConsInfix.ReplaceAllStringFunc(
newUsername,
func(match string) string {
firstRune := []rune(match)[0]
return string(firstRune)
})

if newUsername == "" {
// Everything was stripped and nothing was left. Better to keep as-is and
// just let Gitea bork on it.
return asciiUsername
}

// This includes a test for reserved names, which are easily circumvented by
// appending another character.
if user.IsUsableUsername(newUsername) != nil {
if len(newUsername) > 39 {
return newUsername[:39] + "2"
}
return newUsername + "2"
}

if len(newUsername) > 40 {
return newUsername[:40]
}
return newUsername
}
43 changes: 43 additions & 0 deletions services/auth/source/oauth2/blenderid/gitealize_usernames_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package blenderid

import "testing"

func Test_gitealizeUsername(t *testing.T) {
tests := []struct {
name string
bidNickname string
want string
}{
{"empty", "", ""},
{"underscore", "_", "_"},
{"reserved-name", "ghost", "ghost2"}, // Reserved name in Gitea.
{"short", "x", "x"},
{"simple", "simple", "simple"},
{"start-bad", "____startbad", "startbad"},
{"end-bad", "endbad___", "endbad"},
{"mid-bad-1", "mid__bad", "mid_bad"},
{"mid-bad-2", "user_.-name", "user_name"},
{"plus-mid-single", "RT2+356", "RT2_356"},
{"plus-mid-many", "RT2+++356", "RT2_356"},
{"plus-end", "RT2356+", "RT2356"},
{
"too-long", // # Max username length is 40:
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
},
{"accented-latin", "Ümlaut-Đenja", "Umlaut-Denja"},
{"thai", "แบบไทย", "aebbaithy"},
{"mandarin", "普通话", "Pu_Tong_Hua"},
{"cyrillic", "ћирилица", "tshirilitsa"},
{"all-bad", "------", "------"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := gitealizeUsername(tt.bidNickname); got != tt.want {
t.Errorf("gitealizeUsername() = %v, want %v", got, tt.want)
}
})
}
}
Loading