Skip to content

Commit 8deafa9

Browse files
committed
Only use supported sort order for "explore/users" page (go-gitea#29430)
Thanks to inferenceus : some sort orders on the "explore/users" page could list users by their lastlogintime/updatetime. It leaks user's activity unintentionally. This PR makes that page only use "supported" sort orders. Removing the "sort orders" could also be a good solution, while IMO at the moment keeping the "create time" and "name" orders is also fine, in case some users would like to find a target user in the search result, the "sort order" might help. ![image](https://github.com/go-gitea/gitea/assets/2114189/ce5c39c1-1e86-484a-80c3-33cac6419af8) # Conflicts: # routers/web/explore/org.go # routers/web/explore/user.go
1 parent 9456deb commit 8deafa9

File tree

5 files changed

+79
-6
lines changed

5 files changed

+79
-6
lines changed

models/user/search.go

+3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"strings"
1010

1111
"code.gitea.io/gitea/models/db"
12+
"code.gitea.io/gitea/modules/container"
1213
"code.gitea.io/gitea/modules/structs"
1314
"code.gitea.io/gitea/modules/util"
1415

@@ -30,6 +31,8 @@ type SearchUserOptions struct {
3031
Actor *User // The user doing the search
3132
SearchByEmail bool // Search by email as well as username/full name
3233

34+
SupportedSortOrders container.Set[string] // if not nil, only allow to use the sort orders in this set
35+
3336
IsActive util.OptionalBool
3437
IsAdmin util.OptionalBool
3538
IsRestricted util.OptionalBool

routers/web/explore/org.go

+13-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package explore
66
import (
77
"code.gitea.io/gitea/models/db"
88
user_model "code.gitea.io/gitea/models/user"
9+
"code.gitea.io/gitea/modules/container"
910
"code.gitea.io/gitea/modules/context"
1011
"code.gitea.io/gitea/modules/setting"
1112
"code.gitea.io/gitea/modules/structs"
@@ -24,14 +25,24 @@ func Organizations(ctx *context.Context) {
2425
visibleTypes = append(visibleTypes, structs.VisibleTypeLimited, structs.VisibleTypePrivate)
2526
}
2627

27-
if ctx.FormString("sort") == "" {
28-
ctx.SetFormString("sort", UserSearchDefaultSortType)
28+
supportedSortOrders := container.SetOf(
29+
"newest",
30+
"oldest",
31+
"alphabetically",
32+
"reversealphabetically",
33+
)
34+
sortOrder := ctx.FormString("sort")
35+
if sortOrder == "" {
36+
sortOrder = "newest"
37+
ctx.SetFormString("sort", sortOrder)
2938
}
3039

3140
RenderUserSearch(ctx, &user_model.SearchUserOptions{
3241
Actor: ctx.Doer,
3342
Type: user_model.UserTypeOrganization,
3443
ListOptions: db.ListOptions{PageSize: setting.UI.ExplorePagingNum},
3544
Visible: visibleTypes,
45+
46+
SupportedSortOrders: supportedSortOrders,
3647
}, tplExploreUsers)
3748
}

routers/web/explore/user.go

+19-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"code.gitea.io/gitea/models/db"
1111
user_model "code.gitea.io/gitea/models/user"
1212
"code.gitea.io/gitea/modules/base"
13+
"code.gitea.io/gitea/modules/container"
1314
"code.gitea.io/gitea/modules/context"
1415
"code.gitea.io/gitea/modules/log"
1516
"code.gitea.io/gitea/modules/setting"
@@ -80,10 +81,16 @@ func RenderUserSearch(ctx *context.Context, opts *user_model.SearchUserOptions,
8081
fallthrough
8182
default:
8283
// in case the sortType is not valid, we set it to recentupdate
84+
sortOrder = "recentupdate"
8385
ctx.Data["SortType"] = "recentupdate"
8486
orderBy = "`user`.updated_unix DESC"
8587
}
8688

89+
if opts.SupportedSortOrders != nil && !opts.SupportedSortOrders.Contains(sortOrder) {
90+
ctx.NotFound("unsupported sort order", nil)
91+
return
92+
}
93+
8794
opts.Keyword = ctx.FormTrim("q")
8895
opts.OrderBy = orderBy
8996
if len(opts.Keyword) == 0 || isKeywordValid(opts.Keyword) {
@@ -133,8 +140,16 @@ func Users(ctx *context.Context) {
133140
ctx.Data["PageIsExploreUsers"] = true
134141
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
135142

136-
if ctx.FormString("sort") == "" {
137-
ctx.SetFormString("sort", UserSearchDefaultSortType)
143+
supportedSortOrders := container.SetOf(
144+
"newest",
145+
"oldest",
146+
"alphabetically",
147+
"reversealphabetically",
148+
)
149+
sortOrder := ctx.FormString("sort")
150+
if sortOrder == "" {
151+
sortOrder = "newest"
152+
ctx.SetFormString("sort", sortOrder)
138153
}
139154

140155
RenderUserSearch(ctx, &user_model.SearchUserOptions{
@@ -143,5 +158,7 @@ func Users(ctx *context.Context) {
143158
ListOptions: db.ListOptions{PageSize: setting.UI.ExplorePagingNum},
144159
IsActive: util.OptionalBoolTrue,
145160
Visible: []structs.VisibleType{structs.VisibleTypePublic, structs.VisibleTypeLimited, structs.VisibleTypePrivate},
161+
162+
SupportedSortOrders: supportedSortOrders,
146163
}, tplExploreUsers)
147164
}

templates/explore/search.tmpl

-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616
<a class="{{if eq .SortType "oldest"}}active {{end}}item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.oldest"}}</a>
1717
<a class="{{if eq .SortType "alphabetically"}}active {{end}}item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
1818
<a class="{{if eq .SortType "reversealphabetically"}}active {{end}}item" href="{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
19-
<a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
20-
<a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
2119
</div>
2220
</div>
2321
</div>
+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright 2024 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package integration
5+
6+
import (
7+
"net/http"
8+
"testing"
9+
10+
"code.gitea.io/gitea/tests"
11+
12+
"github.com/stretchr/testify/assert"
13+
)
14+
15+
func TestExploreUser(t *testing.T) {
16+
defer tests.PrepareTestEnv(t)()
17+
18+
cases := []struct{ sortOrder, expected string }{
19+
{"", "/explore/users?sort=newest&q="},
20+
{"newest", "/explore/users?sort=newest&q="},
21+
{"oldest", "/explore/users?sort=oldest&q="},
22+
{"alphabetically", "/explore/users?sort=alphabetically&q="},
23+
{"reversealphabetically", "/explore/users?sort=reversealphabetically&q="},
24+
}
25+
for _, c := range cases {
26+
req := NewRequest(t, "GET", "/explore/users?sort="+c.sortOrder)
27+
resp := MakeRequest(t, req, http.StatusOK)
28+
h := NewHTMLParser(t, resp.Body)
29+
href, _ := h.Find(`.ui.dropdown .menu a.active.item[href^="/explore/users"]`).Attr("href")
30+
assert.Equal(t, c.expected, href)
31+
}
32+
33+
// these sort orders shouldn't be supported, to avoid leaking user activity
34+
cases404 := []string{
35+
"/explore/users?sort=lastlogin",
36+
"/explore/users?sort=reverselastlogin",
37+
"/explore/users?sort=leastupdate",
38+
"/explore/users?sort=reverseleastupdate",
39+
}
40+
for _, c := range cases404 {
41+
req := NewRequest(t, "GET", c).SetHeader("Accept", "text/html")
42+
MakeRequest(t, req, http.StatusNotFound)
43+
}
44+
}

0 commit comments

Comments
 (0)