mirror of
https://github.com/go-gitea/gitea.git
synced 2026-08-23 06:00:36 +00:00
Backport #39004 by @bircni Use the canonical profile-visibility check for user API content and prevent restricted users from enumerating public repositories owned by limited users. This keeps feeds, heatmaps, keys, and issue search consistent with profile visibility. Co-authored-by: bircni <bircni@icloud.com> Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
auth_model "gitea.dev/models/auth"
|
||||
"gitea.dev/models/unittest"
|
||||
user_model "gitea.dev/models/user"
|
||||
api "gitea.dev/modules/structs"
|
||||
"gitea.dev/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestAPIRestrictedUserLimitedOwner(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user2"})
|
||||
owner.Visibility = api.VisibleTypeLimited
|
||||
require.NoError(t, user_model.UpdateUserCols(t.Context(), owner, "visibility"))
|
||||
|
||||
restrictedToken := getUserToken(t, "user29", auth_model.AccessTokenScopeReadUser, auth_model.AccessTokenScopeReadIssue, auth_model.AccessTokenScopeReadOrganization)
|
||||
for _, path := range []string{
|
||||
"/api/v1/users/user2/activities/feeds",
|
||||
"/api/v1/users/user2/heatmap",
|
||||
"/api/v1/users/user2/keys",
|
||||
"/api/v1/users/user2/gpg_keys",
|
||||
"/api/v1/users/user2/orgs",
|
||||
} {
|
||||
req := NewRequest(t, "GET", path).AddTokenAuth(restrictedToken)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
}
|
||||
|
||||
issueSearch := url.URL{Path: "/api/v1/repos/issues/search"}
|
||||
issueSearch.RawQuery = url.Values{"owner": {"user2"}}.Encode()
|
||||
req := NewRequest(t, "GET", issueSearch.String()).AddTokenAuth(restrictedToken)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
assert.Empty(t, DecodeJSON(t, resp, []*api.Issue{}))
|
||||
|
||||
issueSearch.RawQuery = url.Values{"limit": {"100"}, "type": {"issues"}}.Encode()
|
||||
req = NewRequest(t, "GET", issueSearch.String()).AddTokenAuth(restrictedToken)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
issues := DecodeJSON(t, resp, []*api.Issue{})
|
||||
require.NotEmpty(t, issues)
|
||||
for _, issue := range issues {
|
||||
assert.NotEqual(t, owner.Name, issue.Repo.Owner)
|
||||
}
|
||||
|
||||
restrictedSession := loginUser(t, "user29")
|
||||
req = NewRequest(t, "GET", "/issues/search?owner=user2")
|
||||
resp = restrictedSession.MakeRequest(t, req, http.StatusOK)
|
||||
assert.Empty(t, DecodeJSON(t, resp, []*api.Issue{}))
|
||||
|
||||
viewerToken := getUserToken(t, "user4", auth_model.AccessTokenScopeReadUser, auth_model.AccessTokenScopeReadIssue, auth_model.AccessTokenScopeReadOrganization)
|
||||
for _, path := range []string{
|
||||
"/api/v1/users/user2/activities/feeds",
|
||||
"/api/v1/users/user2/heatmap",
|
||||
"/api/v1/users/user2/keys",
|
||||
"/api/v1/users/user2/gpg_keys",
|
||||
"/api/v1/users/user2/orgs",
|
||||
} {
|
||||
req := NewRequest(t, "GET", path).AddTokenAuth(viewerToken)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
}
|
||||
|
||||
issueSearch.RawQuery = url.Values{"owner": {"user2"}}.Encode()
|
||||
req = NewRequest(t, "GET", issueSearch.String()).AddTokenAuth(viewerToken)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
assert.NotEmpty(t, DecodeJSON(t, resp, []*api.Issue{}))
|
||||
}
|
||||
Reference in New Issue
Block a user