Skip to content

Commit 5fe699d

Browse files
committed
Merge remote-tracking branch 'giteaofficial/main'
* giteaofficial/main: Normalize oauth email username (go-gitea#28561) Fix wrapping of label list (go-gitea#28684) Fix grammar in `actions.variables.id_not_exist` (en-US) (go-gitea#28680) Fix grammar issues on the repository Actions page (en-US) (go-gitea#28679) Fix tooltip of variable edit button (go-gitea#28681) Make cross-reference issue links work in markdown documents again (go-gitea#28682)
2 parents 98ba2e6 + 54acf7b commit 5fe699d

File tree

14 files changed

+103
-21
lines changed

14 files changed

+103
-21
lines changed

custom/conf/app.example.ini

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1529,6 +1529,10 @@ LEVEL = Info
15291529
;; userid = use the userid / sub attribute
15301530
;; nickname = use the nickname attribute
15311531
;; email = use the username part of the email attribute
1532+
;; Note: `nickname` and `email` options will normalize input strings using the following criteria:
1533+
;; - diacritics are removed
1534+
;; - the characters in the set `['´\x60]` are removed
1535+
;; - the characters in the set `[\s~+]` are replaced with `-`
15321536
;USERNAME = nickname
15331537
;;
15341538
;; Update avatar if available from oauth2 provider.

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -596,9 +596,13 @@ And the following unique queues:
596596
- `OPENID_CONNECT_SCOPES`: **_empty_**: List of additional openid connect scopes. (`openid` is implicitly added)
597597
- `ENABLE_AUTO_REGISTRATION`: **false**: Automatically create user accounts for new oauth2 users.
598598
- `USERNAME`: **nickname**: The source of the username for new oauth2 accounts:
599-
- userid - use the userid / sub attribute
600-
- nickname - use the nickname attribute
601-
- email - use the username part of the email attribute
599+
- `userid` - use the userid / sub attribute
600+
- `nickname` - use the nickname attribute
601+
- `email` - use the username part of the email attribute
602+
- Note: `nickname` and `email` options will normalize input strings using the following criteria:
603+
- diacritics are removed
604+
- the characters in the set `['´\x60]` are removed
605+
- the characters in the set `[\s~+]` are replaced with `-`
602606
- `UPDATE_AVATAR`: **false**: Update avatar if available from oauth2 provider. Update will be performed on each login.
603607
- `ACCOUNT_LINKING`: **login**: How to handle if an account / email already exists:
604608
- disabled - show an error

models/user/user.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ import (
1010
"fmt"
1111
"net/url"
1212
"path/filepath"
13+
"regexp"
1314
"strings"
1415
"time"
16+
"unicode"
1517

1618
_ "image/jpeg" // Needed for jpeg support
1719

@@ -29,6 +31,9 @@ import (
2931
"code.gitea.io/gitea/modules/util"
3032
"code.gitea.io/gitea/modules/validation"
3133

34+
"golang.org/x/text/runes"
35+
"golang.org/x/text/transform"
36+
"golang.org/x/text/unicode/norm"
3237
"xorm.io/builder"
3338
)
3439

@@ -515,6 +520,26 @@ func GetUserSalt() (string, error) {
515520
return hex.EncodeToString(rBytes), nil
516521
}
517522

523+
// Note: The set of characters here can safely expand without a breaking change,
524+
// but characters removed from this set can cause user account linking to break
525+
var (
526+
customCharsReplacement = strings.NewReplacer("Æ", "AE")
527+
removeCharsRE = regexp.MustCompile(`['´\x60]`)
528+
removeDiacriticsTransform = transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC)
529+
replaceCharsHyphenRE = regexp.MustCompile(`[\s~+]`)
530+
)
531+
532+
// normalizeUserName returns a string with single-quotes and diacritics
533+
// removed, and any other non-supported username characters replaced with
534+
// a `-` character
535+
func NormalizeUserName(s string) (string, error) {
536+
strDiacriticsRemoved, n, err := transform.String(removeDiacriticsTransform, customCharsReplacement.Replace(s))
537+
if err != nil {
538+
return "", fmt.Errorf("Failed to normalize character `%v` in provided username `%v`", s[n], s)
539+
}
540+
return replaceCharsHyphenRE.ReplaceAllLiteralString(removeCharsRE.ReplaceAllLiteralString(strDiacriticsRemoved, ""), "-"), nil
541+
}
542+
518543
var (
519544
reservedUsernames = []string{
520545
".",

models/user/user_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,3 +544,31 @@ func Test_ValidateUser(t *testing.T) {
544544
assert.EqualValues(t, expected, err == nil, fmt.Sprintf("case: %+v", kase))
545545
}
546546
}
547+
548+
func Test_NormalizeUserFromEmail(t *testing.T) {
549+
testCases := []struct {
550+
Input string
551+
Expected string
552+
IsNormalizedValid bool
553+
}{
554+
{"test", "test", true},
555+
{"Sinéad.O'Connor", "Sinead.OConnor", true},
556+
{"Æsir", "AEsir", true},
557+
// \u00e9\u0065\u0301
558+
{"éé", "ee", true},
559+
{"Awareness Hub", "Awareness-Hub", true},
560+
{"double__underscore", "double__underscore", false}, // We should consider squashing double non-alpha characters
561+
{".bad.", ".bad.", false},
562+
{"new😀user", "new😀user", false}, // No plans to support
563+
}
564+
for _, testCase := range testCases {
565+
normalizedName, err := user_model.NormalizeUserName(testCase.Input)
566+
assert.NoError(t, err)
567+
assert.EqualValues(t, testCase.Expected, normalizedName)
568+
if testCase.IsNormalizedValid {
569+
assert.NoError(t, user_model.IsUsableUsername(normalizedName))
570+
} else {
571+
assert.Error(t, user_model.IsUsableUsername(normalizedName))
572+
}
573+
}
574+
}

modules/markup/html.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -852,11 +852,14 @@ func fullIssuePatternProcessor(ctx *RenderContext, node *html.Node) {
852852
}
853853

854854
func issueIndexPatternProcessor(ctx *RenderContext, node *html.Node) {
855-
// FIXME: the use of "mode" is quite dirty and hacky, for example: what is a "document"? how should it be rendered?
856-
// The "mode" approach should be refactored to some other more clear&reliable way.
857-
if ctx.Metas == nil || (ctx.Metas["mode"] == "document" && !ctx.IsWiki) {
855+
if ctx.Metas == nil {
858856
return
859857
}
858+
859+
// FIXME: the use of "mode" is quite dirty and hacky, for example: what is a "document"? how should it be rendered?
860+
// The "mode" approach should be refactored to some other more clear&reliable way.
861+
crossLinkOnly := (ctx.Metas["mode"] == "document" && !ctx.IsWiki)
862+
860863
var (
861864
found bool
862865
ref *references.RenderizableReference
@@ -870,7 +873,7 @@ func issueIndexPatternProcessor(ctx *RenderContext, node *html.Node) {
870873
// Repos with external issue trackers might still need to reference local PRs
871874
// We need to concern with the first one that shows up in the text, whichever it is
872875
isNumericStyle := ctx.Metas["style"] == "" || ctx.Metas["style"] == IssueNameStyleNumeric
873-
foundNumeric, refNumeric := references.FindRenderizableReferenceNumeric(node.Data, hasExtTrackFormat && !isNumericStyle)
876+
foundNumeric, refNumeric := references.FindRenderizableReferenceNumeric(node.Data, hasExtTrackFormat && !isNumericStyle, crossLinkOnly)
874877

875878
switch ctx.Metas["style"] {
876879
case "", IssueNameStyleNumeric:

modules/markup/html_test.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,11 +561,16 @@ func TestPostProcess_RenderDocument(t *testing.T) {
561561
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(res.String()))
562562
}
563563

564-
// Issue index shouldn't be post processing in an document.
564+
// Issue index shouldn't be post processing in a document.
565565
test(
566566
"#1",
567567
"#1")
568568

569+
// But cross-referenced issue index should work.
570+
test(
571+
"go-gitea/gitea#12345",
572+
`<a href="`+util.URLJoin(markup.TestAppURL, "go-gitea", "gitea", "issues", "12345")+`" class="ref-issue">go-gitea/gitea#12345</a>`)
573+
569574
// Test that other post processing still works.
570575
test(
571576
":gitea:",

modules/references/references.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,8 +331,11 @@ func FindAllIssueReferences(content string) []IssueReference {
331331
}
332332

333333
// FindRenderizableReferenceNumeric returns the first unvalidated reference found in a string.
334-
func FindRenderizableReferenceNumeric(content string, prOnly bool) (bool, *RenderizableReference) {
335-
match := issueNumericPattern.FindStringSubmatchIndex(content)
334+
func FindRenderizableReferenceNumeric(content string, prOnly, crossLinkOnly bool) (bool, *RenderizableReference) {
335+
var match []int
336+
if !crossLinkOnly {
337+
match = issueNumericPattern.FindStringSubmatchIndex(content)
338+
}
336339
if match == nil {
337340
if match = crossReferenceIssueNumericPattern.FindStringSubmatchIndex(content); match == nil {
338341
return false, nil

modules/setting/oauth2.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const (
2121
OAuth2UsernameUserid OAuth2UsernameType = "userid"
2222
// OAuth2UsernameNickname oauth2 nickname field will be used as gitea name
2323
OAuth2UsernameNickname OAuth2UsernameType = "nickname"
24-
// OAuth2UsernameEmail username of oauth2 email filed will be used as gitea name
24+
// OAuth2UsernameEmail username of oauth2 email field will be used as gitea name
2525
OAuth2UsernameEmail OAuth2UsernameType = "email"
2626
)
2727

options/locale/locale_en-US.ini

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3532,8 +3532,8 @@ runs.actors_no_select = All actors
35323532
runs.status_no_select = All status
35333533
runs.no_results = No results matched.
35343534
runs.no_workflows = There are no workflows yet.
3535-
runs.no_workflows.quick_start = Don't know how to start with Gitea Action? See <a target="_blank" rel="noopener noreferrer" href="%s">the quick start guide</a>.
3536-
runs.no_workflows.documentation = For more information on the Gitea Action, see <a target="_blank" rel="noopener noreferrer" href="%s">the documentation</a>.
3535+
runs.no_workflows.quick_start = Don't know how to start with Gitea Actions? See <a target="_blank" rel="noopener noreferrer" href="%s">the quick start guide</a>.
3536+
runs.no_workflows.documentation = For more information on Gitea Actions, see <a target="_blank" rel="noopener noreferrer" href="%s">the documentation</a>.
35373537
runs.no_runs = The workflow has no runs yet.
35383538
runs.empty_commit_message = (empty commit message)
35393539
@@ -3552,7 +3552,7 @@ variables.none = There are no variables yet.
35523552
variables.deletion = Remove variable
35533553
variables.deletion.description = Removing a variable is permanent and cannot be undone. Continue?
35543554
variables.description = Variables will be passed to certain actions and cannot be read otherwise.
3555-
variables.id_not_exist = Variable with id %d not exists.
3555+
variables.id_not_exist = Variable with ID %d does not exist.
35563556
variables.edit = Edit Variable
35573557
variables.deletion.failed = Failed to remove variable.
35583558
variables.deletion.success = The variable has been removed.

routers/web/auth/auth.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -368,14 +368,14 @@ 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 user_model.NormalizeUserName(strings.Split(gothUser.Email, "@")[0])
375375
case setting.OAuth2UsernameNickname:
376-
return gothUser.NickName
376+
return user_model.NormalizeUserName(gothUser.NickName)
377377
default: // OAuth2UsernameUserid
378-
return gothUser.UserID
378+
return gothUser.UserID, nil
379379
}
380380
}
381381

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,

templates/shared/variables/variable_list.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
{{ctx.Locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix) | Safe}}
3434
</span>
3535
<button class="btn interact-bg gt-p-3 show-modal"
36-
data-tooltip-content="{{ctx.Locale.Tr "variables.edit"}}"
36+
data-tooltip-content="{{ctx.Locale.Tr "actions.variables.edit"}}"
3737
data-modal="#edit-variable-modal"
3838
data-modal-form.action="{{$.Link}}/{{.ID}}/edit"
3939
data-modal-header="{{ctx.Locale.Tr "actions.variables.edit"}}"

web_src/css/repo/issue-list.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535

3636
#issue-list .flex-item-title .labels-list {
3737
display: flex;
38+
flex-wrap: wrap;
3839
gap: 0.25em;
3940
}
4041

0 commit comments

Comments
 (0)