]> source.dussan.org Git - gitea.git/commitdiff
Fix the permission check for user search API and limit the number of returned users...
authorZettat123 <zettat123@gmail.com>
Wed, 23 Oct 2024 04:56:13 +0000 (12:56 +0800)
committerGitHub <noreply@github.com>
Wed, 23 Oct 2024 04:56:13 +0000 (04:56 +0000)
Partially backport #32288

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
routers/api/v1/api.go
routers/web/user/search.go
routers/web/web.go
web_src/js/features/comp/SearchUserBox.js

index 19b643135665d28f584a69c7a11fc6604ab7f3d9..6e2d98c648ab4d43586f59930f75f0dc15070b86 100644 (file)
@@ -356,12 +356,20 @@ func reqToken() func(ctx *context.APIContext) {
 
 func reqExploreSignIn() func(ctx *context.APIContext) {
        return func(ctx *context.APIContext) {
-               if setting.Service.Explore.RequireSigninView && !ctx.IsSigned {
+               if (setting.Service.RequireSignInView || setting.Service.Explore.RequireSigninView) && !ctx.IsSigned {
                        ctx.Error(http.StatusUnauthorized, "reqExploreSignIn", "you must be signed in to search for users")
                }
        }
 }
 
+func reqUsersExploreEnabled() func(ctx *context.APIContext) {
+       return func(ctx *context.APIContext) {
+               if setting.Service.Explore.DisableUsersPage {
+                       ctx.NotFound()
+               }
+       }
+}
+
 func reqBasicOrRevProxyAuth() func(ctx *context.APIContext) {
        return func(ctx *context.APIContext) {
                if ctx.IsSigned && setting.Service.EnableReverseProxyAuthAPI && ctx.Data["AuthedMethod"].(string) == auth.ReverseProxyMethodName {
@@ -955,7 +963,7 @@ func Routes() *web.Route {
 
                // Users (requires user scope)
                m.Group("/users", func() {
-                       m.Get("/search", reqExploreSignIn(), user.Search)
+                       m.Get("/search", reqExploreSignIn(), reqUsersExploreEnabled(), user.Search)
 
                        m.Group("/{username}", func() {
                                m.Get("", reqExploreSignIn(), user.GetInfo)
index fb7729bbe141965c4236bd55abd2ff6944a418c5..be5eee90a971a03156f006172ff75b44ab449cfa 100644 (file)
@@ -8,37 +8,24 @@ import (
 
        "code.gitea.io/gitea/models/db"
        user_model "code.gitea.io/gitea/models/user"
+       "code.gitea.io/gitea/modules/optional"
+       "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/services/context"
        "code.gitea.io/gitea/services/convert"
 )
 
-// Search search users
-func Search(ctx *context.Context) {
-       listOptions := db.ListOptions{
-               Page:     ctx.FormInt("page"),
-               PageSize: convert.ToCorrectPageSize(ctx.FormInt("limit")),
-       }
-
-       users, maxResults, err := user_model.SearchUsers(ctx, &user_model.SearchUserOptions{
+// SearchCandidates searches candidate users for dropdown list
+func SearchCandidates(ctx *context.Context) {
+       users, _, err := user_model.SearchUsers(ctx, &user_model.SearchUserOptions{
                Actor:       ctx.Doer,
                Keyword:     ctx.FormTrim("q"),
-               UID:         ctx.FormInt64("uid"),
                Type:        user_model.UserTypeIndividual,
-               IsActive:    ctx.FormOptionalBool("active"),
-               ListOptions: listOptions,
+               IsActive:    optional.Some(true),
+               ListOptions: db.ListOptions{PageSize: setting.UI.MembersPagingNum},
        })
        if err != nil {
-               ctx.JSON(http.StatusInternalServerError, map[string]any{
-                       "ok":    false,
-                       "error": err.Error(),
-               })
+               ctx.ServerError("Unable to search users", err)
                return
        }
-
-       ctx.SetTotalCountHeader(maxResults)
-
-       ctx.JSON(http.StatusOK, map[string]any{
-               "ok":   true,
-               "data": convert.ToUsers(ctx, ctx.Doer, users),
-       })
+       ctx.JSON(http.StatusOK, map[string]any{"data": convert.ToUsers(ctx, ctx.Doer, users)})
 }
index 0391eb0d7fa3630c9ba29c6fc188545c95d4b892..787c5f51be77d5255d4f7354b71fefb334087a9c 100644 (file)
@@ -668,7 +668,7 @@ func registerRoutes(m *web.Route) {
                m.Post("/forgot_password", auth.ForgotPasswdPost)
                m.Post("/logout", auth.SignOut)
                m.Get("/stopwatches", reqSignIn, user.GetStopwatches)
-               m.Get("/search", ignExploreSignIn, user.Search)
+               m.Get("/search_candidates", ignExploreSignIn, user.SearchCandidates)
                m.Group("/oauth2", func() {
                        m.Get("/{provider}", auth.SignInOAuth)
                        m.Get("/{provider}/callback", auth.SignInOAuthCallback)
index 081c47425f8b84505a167b1638c7969b21962258..b03cbad16fe224d6d6eaffa1c951fc3ae3fb0395 100644 (file)
@@ -8,41 +8,38 @@ export function initCompSearchUserBox() {
   const searchUserBox = document.getElementById('search-user-box');
   if (!searchUserBox) return;
 
-  const $searchUserBox = $(searchUserBox);
   const allowEmailInput = searchUserBox.getAttribute('data-allow-email') === 'true';
   const allowEmailDescription = searchUserBox.getAttribute('data-allow-email-description') ?? undefined;
-  $searchUserBox.search({
+  $(searchUserBox).search({
     minCharacters: 2,
     apiSettings: {
-      url: `${appSubUrl}/user/search?active=1&q={query}`,
+      url: `${appSubUrl}/user/search_candidates?q={query}`,
       onResponse(response) {
-        const items = [];
-        const searchQuery = $searchUserBox.find('input').val();
+        const resultItems = [];
+        const searchQuery = searchUserBox.querySelector('input').value;
         const searchQueryUppercase = searchQuery.toUpperCase();
-        $.each(response.data, (_i, item) => {
+        for (const item of response.data) {
           const resultItem = {
             title: item.login,
             image: item.avatar_url,
+            description: htmlEscape(item.full_name),
           };
-          if (item.full_name) {
-            resultItem.description = htmlEscape(item.full_name);
-          }
           if (searchQueryUppercase === item.login.toUpperCase()) {
-            items.unshift(resultItem);
+            resultItems.unshift(resultItem); // add the exact match to the top
           } else {
-            items.push(resultItem);
+            resultItems.push(resultItem);
           }
-        });
+        }
 
-        if (allowEmailInput && !items.length && looksLikeEmailAddressCheck.test(searchQuery)) {
+        if (allowEmailInput && !resultItems.length && looksLikeEmailAddressCheck.test(searchQuery)) {
           const resultItem = {
             title: searchQuery,
             description: allowEmailDescription,
           };
-          items.push(resultItem);
+          resultItems.push(resultItem);
         }
 
-        return {results: items};
+        return {results: resultItems};
       },
     },
     searchFields: ['login', 'full_name'],