Skip to content

Commit 9ad2bd8

Browse files
committed
Merge remote-tracking branch 'giteaofficial/main'
* giteaofficial/main: Fix non-admins unable to automerge PRs from forks (go-gitea#36833) upgrade to github.com/cloudflare/circl 1.6.3, svgo 4.0.1, markdownlint-cli 0.48.0 (go-gitea#36837) Fix dump release asset bug (go-gitea#36799) build(deps): update material-icon-theme v5.32.0 (go-gitea#36832) Fix bug to check whether user can update pull request branch or rebase branch (go-gitea#36465) Fix forwarded proto handling for public URL detection (go-gitea#36810) Fix artifacts v4 backend upload problems (go-gitea#36805) Add a git grep search timeout (go-gitea#36809) fix(repo): unify DEFAULT_SHOW_FULL_NAME output in templates and dropdown (go-gitea#36597) Harden render iframe open-link handling (go-gitea#36811)
2 parents 702a676 + c710ce3 commit 9ad2bd8

46 files changed

Lines changed: 3056 additions & 602 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ require (
174174
github.com/caddyserver/zerossl v0.1.4 // indirect
175175
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect
176176
github.com/cespare/xxhash/v2 v2.3.0 // indirect
177-
github.com/cloudflare/circl v1.6.1 // indirect
177+
github.com/cloudflare/circl v1.6.3 // indirect
178178
github.com/couchbase/go-couchbase v0.1.1 // indirect
179179
github.com/couchbase/gomemcached v0.3.3 // indirect
180180
github.com/couchbase/goutils v0.1.2 // indirect

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,8 +227,8 @@ github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObk
227227
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
228228
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
229229
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
230-
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
231-
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
230+
github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=
231+
github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
232232
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
233233
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
234234
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=

models/repo/user_repo.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -147,19 +147,21 @@ func GetRepoAssignees(ctx context.Context, repo *Repository) (_ []*user_model.Us
147147
}
148148

149149
// GetIssuePostersWithSearch returns users with limit of 30 whose username started with prefix that have authored an issue/pull request for the given repository
150-
// If isShowFullName is set to true, also include full name prefix search
151-
func GetIssuePostersWithSearch(ctx context.Context, repo *Repository, isPull bool, search string, isShowFullName bool) ([]*user_model.User, error) {
150+
// It searches with the "user.name" and "user.full_name" fields case-insensitively.
151+
func GetIssuePostersWithSearch(ctx context.Context, repo *Repository, isPull bool, search string) ([]*user_model.User, error) {
152152
users := make([]*user_model.User, 0, 30)
153-
var prefixCond builder.Cond = builder.Like{"lower_name", strings.ToLower(search) + "%"}
154-
if search != "" && isShowFullName {
155-
prefixCond = prefixCond.Or(db.BuildCaseInsensitiveLike("full_name", "%"+search+"%"))
156-
}
157153

158154
cond := builder.In("`user`.id",
159155
builder.Select("poster_id").From("issue").Where(
160156
builder.Eq{"repo_id": repo.ID}.
161157
And(builder.Eq{"is_pull": isPull}),
162-
).GroupBy("poster_id")).And(prefixCond)
158+
).GroupBy("poster_id"))
159+
160+
if search != "" {
161+
var prefixCond builder.Cond = builder.Like{"lower_name", strings.ToLower(search) + "%"}
162+
prefixCond = prefixCond.Or(db.BuildCaseInsensitiveLike("full_name", "%"+search+"%"))
163+
cond = cond.And(prefixCond)
164+
}
163165

164166
return users, db.GetEngine(ctx).
165167
Where(cond).

models/repo/user_repo_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,12 @@ func TestGetIssuePostersWithSearch(t *testing.T) {
4444

4545
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
4646

47-
users, err := repo_model.GetIssuePostersWithSearch(t.Context(), repo2, false, "USER", false /* full name */)
47+
users, err := repo_model.GetIssuePostersWithSearch(t.Context(), repo2, false, "USER")
4848
require.NoError(t, err)
4949
require.Len(t, users, 1)
5050
assert.Equal(t, "user2", users[0].Name)
5151

52-
users, err = repo_model.GetIssuePostersWithSearch(t.Context(), repo2, false, "TW%O", true /* full name */)
52+
users, err = repo_model.GetIssuePostersWithSearch(t.Context(), repo2, false, "TW%O")
5353
require.NoError(t, err)
5454
require.Len(t, users, 1)
5555
assert.Equal(t, "user2", users[0].Name)

models/user/user.go

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"context"
99
"encoding/hex"
1010
"fmt"
11+
"html/template"
1112
"mime"
1213
"net/mail"
1314
"net/url"
@@ -28,6 +29,7 @@ import (
2829
"code.gitea.io/gitea/modules/base"
2930
"code.gitea.io/gitea/modules/container"
3031
"code.gitea.io/gitea/modules/git"
32+
"code.gitea.io/gitea/modules/htmlutil"
3133
"code.gitea.io/gitea/modules/httplib"
3234
"code.gitea.io/gitea/modules/log"
3335
"code.gitea.io/gitea/modules/optional"
@@ -417,16 +419,6 @@ func (u *User) IsTokenAccessAllowed() bool {
417419
return u.Type == UserTypeIndividual || u.Type == UserTypeBot
418420
}
419421

420-
// DisplayName returns full name if it's not empty,
421-
// returns username otherwise.
422-
func (u *User) DisplayName() string {
423-
trimmed := strings.TrimSpace(u.FullName)
424-
if len(trimmed) > 0 {
425-
return trimmed
426-
}
427-
return u.Name
428-
}
429-
430422
// EmailTo returns a string suitable to be put into a e-mail `To:` header.
431423
func (u *User) EmailTo() string {
432424
sanitizedDisplayName := globalVars().emailToReplacer.Replace(u.DisplayName())
@@ -445,27 +437,45 @@ func (u *User) EmailTo() string {
445437
return fmt.Sprintf("%s <%s>", mime.QEncoding.Encode("utf-8", add.Name), add.Address)
446438
}
447439

448-
// GetDisplayName returns full name if it's not empty and DEFAULT_SHOW_FULL_NAME is set,
449-
// returns username otherwise.
440+
// TODO: DefaultShowFullName causes messy logic, there are already too many methods to display a user's "display name", need to refactor them
441+
// * user.Name / user.FullName: directly used in templates
442+
// * user.DisplayName(): always show FullName if it's not empty, otherwise show Name
443+
// * user.GetDisplayName(): show FullName if it's not empty and DefaultShowFullName is set, otherwise show Name
444+
// * user.ShortName(): used a lot in templates, but it should be removed and let frontend use "ellipsis" styles
445+
// * activity action.ShortActUserName/GetActDisplayName/GetActDisplayNameTitle, etc: duplicate and messy
446+
447+
// DisplayName returns full name if it's not empty, returns username otherwise.
448+
func (u *User) DisplayName() string {
449+
fullName := strings.TrimSpace(u.FullName)
450+
if fullName != "" {
451+
return fullName
452+
}
453+
return u.Name
454+
}
455+
456+
// GetDisplayName returns full name if it's not empty and DEFAULT_SHOW_FULL_NAME is set, otherwise, username.
450457
func (u *User) GetDisplayName() string {
451458
if setting.UI.DefaultShowFullName {
452-
trimmed := strings.TrimSpace(u.FullName)
453-
if len(trimmed) > 0 {
454-
return trimmed
459+
fullName := strings.TrimSpace(u.FullName)
460+
if fullName != "" {
461+
return fullName
455462
}
456463
}
457464
return u.Name
458465
}
459466

460-
// GetCompleteName returns the full name and username in the form of
461-
// "Full Name (username)" if full name is not empty, otherwise it returns
462-
// "username".
463-
func (u *User) GetCompleteName() string {
464-
trimmedFullName := strings.TrimSpace(u.FullName)
465-
if len(trimmedFullName) > 0 {
466-
return fmt.Sprintf("%s (%s)", trimmedFullName, u.Name)
467+
// ShortName ellipses username to length (still used by many templates), it calls GetDisplayName and respects DEFAULT_SHOW_FULL_NAME
468+
func (u *User) ShortName(length int) string {
469+
return util.EllipsisDisplayString(u.GetDisplayName(), length)
470+
}
471+
472+
func (u *User) GetShortDisplayNameLinkHTML() template.HTML {
473+
fullName := strings.TrimSpace(u.FullName)
474+
displayName, displayTooltip := u.Name, fullName
475+
if setting.UI.DefaultShowFullName && fullName != "" {
476+
displayName, displayTooltip = fullName, u.Name
467477
}
468-
return u.Name
478+
return htmlutil.HTMLFormat(`<a class="muted" href="%s" data-tooltip-content="%s">%s</a>`, u.HomeLink(), displayTooltip, displayName)
469479
}
470480

471481
func gitSafeName(name string) string {
@@ -488,14 +498,6 @@ func (u *User) GitName() string {
488498
return fmt.Sprintf("user-%d", u.ID)
489499
}
490500

491-
// ShortName ellipses username to length
492-
func (u *User) ShortName(length int) string {
493-
if setting.UI.DefaultShowFullName && len(u.FullName) > 0 {
494-
return util.EllipsisDisplayString(u.FullName, length)
495-
}
496-
return util.EllipsisDisplayString(u.Name, length)
497-
}
498-
499501
// IsMailable checks if a user is eligible to receive emails.
500502
// System users like Ghost and Gitea Actions are excluded.
501503
func (u *User) IsMailable() bool {

modules/git/grep.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"slices"
1212
"strconv"
1313
"strings"
14+
"time"
1415

1516
"code.gitea.io/gitea/modules/git/gitcmd"
1617
"code.gitea.io/gitea/modules/util"
@@ -39,6 +40,10 @@ type GrepOptions struct {
3940
PathspecList []string
4041
}
4142

43+
// grepSearchTimeout is the timeout for git grep search, it should be long enough to get results
44+
// but not too long to cause performance issues
45+
const grepSearchTimeout = 30 * time.Second
46+
4247
func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepOptions) ([]*GrepResult, error) {
4348
/*
4449
The output is like this ( "^@" means \x00):
@@ -76,6 +81,7 @@ func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepO
7681
stdoutReader, stdoutReaderClose := cmd.MakeStdoutPipe()
7782
defer stdoutReaderClose()
7883
err := cmd.WithDir(repo.Path).
84+
WithTimeout(grepSearchTimeout).
7985
WithPipelineFunc(func(ctx gitcmd.Context) error {
8086
isInBlock := false
8187
rd := bufio.NewReaderSize(stdoutReader, util.IfZero(opts.MaxLineLength, 16*1024))

modules/httplib/url.go

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,14 @@ func IsRelativeURL(s string) bool {
4646

4747
func getRequestScheme(req *http.Request) string {
4848
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto
49-
if s := req.Header.Get("X-Forwarded-Proto"); s != "" {
50-
return s
49+
if proto, ok := parseForwardedProtoValue(req.Header.Get("X-Forwarded-Proto")); ok {
50+
return proto
5151
}
52-
if s := req.Header.Get("X-Forwarded-Protocol"); s != "" {
53-
return s
52+
if proto, ok := parseForwardedProtoValue(req.Header.Get("X-Forwarded-Protocol")); ok {
53+
return proto
5454
}
55-
if s := req.Header.Get("X-Url-Scheme"); s != "" {
56-
return s
55+
if proto, ok := parseForwardedProtoValue(req.Header.Get("X-Url-Scheme")); ok {
56+
return proto
5757
}
5858
if s := req.Header.Get("Front-End-Https"); s != "" {
5959
return util.Iif(s == "on", "https", "http")
@@ -64,6 +64,13 @@ func getRequestScheme(req *http.Request) string {
6464
return ""
6565
}
6666

67+
func parseForwardedProtoValue(val string) (string, bool) {
68+
if val == "http" || val == "https" {
69+
return val, true
70+
}
71+
return "", false
72+
}
73+
6774
// GuessCurrentAppURL tries to guess the current full public URL (with sub-path) by http headers. It always has a '/' suffix, exactly the same as setting.AppURL
6875
// TODO: should rename it to GuessCurrentPublicURL in the future
6976
func GuessCurrentAppURL(ctx context.Context) string {

modules/httplib/url_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ func TestGuessCurrentHostURL(t *testing.T) {
4747
defer test.MockVariableValue(&setting.AppURL, "http://cfg-host/sub/")()
4848
defer test.MockVariableValue(&setting.AppSubURL, "/sub")()
4949
headersWithProto := http.Header{"X-Forwarded-Proto": {"https"}}
50+
maliciousProtoHeaders := http.Header{"X-Forwarded-Proto": {"http://attacker.host/?trash="}}
5051

5152
t.Run("Legacy", func(t *testing.T) {
5253
defer test.MockVariableValue(&setting.PublicURLDetection, setting.PublicURLLegacy)()
@@ -60,6 +61,9 @@ func TestGuessCurrentHostURL(t *testing.T) {
6061
// if "X-Forwarded-Proto" exists, then use it and "Host" header
6162
ctx = context.WithValue(t.Context(), RequestContextKey, &http.Request{Host: "req-host:3000", Header: headersWithProto})
6263
assert.Equal(t, "https://req-host:3000", GuessCurrentHostURL(ctx))
64+
65+
ctx = context.WithValue(t.Context(), RequestContextKey, &http.Request{Host: "req-host:3000", Header: maliciousProtoHeaders})
66+
assert.Equal(t, "http://cfg-host", GuessCurrentHostURL(ctx))
6367
})
6468

6569
t.Run("Auto", func(t *testing.T) {
@@ -76,6 +80,9 @@ func TestGuessCurrentHostURL(t *testing.T) {
7680

7781
ctx = context.WithValue(t.Context(), RequestContextKey, &http.Request{Host: "req-host:3000", Header: headersWithProto})
7882
assert.Equal(t, "https://req-host:3000", GuessCurrentHostURL(ctx))
83+
84+
ctx = context.WithValue(t.Context(), RequestContextKey, &http.Request{Host: "req-host:3000", Header: maliciousProtoHeaders})
85+
assert.Equal(t, "http://req-host:3000", GuessCurrentHostURL(ctx))
7986
})
8087

8188
t.Run("Never", func(t *testing.T) {

modules/setting/ui.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ var UI = struct {
2525
ReactionMaxUserNum int
2626
MaxDisplayFileSize int64
2727
ShowUserEmail bool
28-
DefaultShowFullName bool
2928
DefaultTheme string
3029
Themes []string
3130
FileIconTheme string
@@ -43,6 +42,15 @@ var UI = struct {
4342

4443
AmbiguousUnicodeDetection bool
4544

45+
// TODO: DefaultShowFullName is introduced by https://github.com/go-gitea/gitea/pull/6710
46+
// But there are still many edge cases:
47+
// * Many places still use "username", not respecting this setting
48+
// * Many places use "Full Name" if it is not empty, cause inconsistent UI for users who have set their full name but some others don't
49+
// * Even if DefaultShowFullName=false, many places still need to show the full name
50+
// For most cases, either "username" or "username (Full Name)" should be used and are good enough.
51+
// Only in very few cases (e.g.: unimportant lists, narrow layout), "username" or "Full Name" can be used.
52+
DefaultShowFullName bool
53+
4654
Notification struct {
4755
MinTimeout time.Duration
4856
TimeoutStep time.Duration

0 commit comments

Comments
 (0)