Skip to content

Commit

Permalink
Reject star-related requests if stars are disabled (#33208)
Browse files Browse the repository at this point in the history
This PR fixes #33205.

If stars are disabled:
* The `.../repo/stars` page returns a 403 Forbidden error
* Star-related API endpoints return a 403 Forbidden error saying `Stars are disabled.`
* Same for action endpoints

---------

Co-authored-by: wxiaoguang <[email protected]>
  • Loading branch information
HeCorr and wxiaoguang authored Feb 4, 2025
1 parent a4676db commit d0f4e92
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 5 deletions.
16 changes: 13 additions & 3 deletions routers/api/v1/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,16 @@ func reqWebhooksEnabled() func(ctx *context.APIContext) {
}
}

// reqStarsEnabled requires Starring to be enabled in the config.
func reqStarsEnabled() func(ctx *context.APIContext) {
return func(ctx *context.APIContext) {
if setting.Repository.DisableStars {
ctx.Error(http.StatusForbidden, "", "stars disabled by administrator")
return
}
}
}

func orgAssignment(args ...bool) func(ctx *context.APIContext) {
var (
assignOrg bool
Expand Down Expand Up @@ -995,7 +1005,7 @@ func Routes() *web.Router {
m.Get("/{target}", user.CheckFollowing)
})

m.Get("/starred", user.GetStarredRepos)
m.Get("/starred", reqStarsEnabled(), user.GetStarredRepos)

m.Get("/subscriptions", user.GetWatchedRepos)
}, context.UserAssignmentAPI(), checkTokenPublicOnly())
Expand Down Expand Up @@ -1086,7 +1096,7 @@ func Routes() *web.Router {
m.Put("", user.Star)
m.Delete("", user.Unstar)
}, repoAssignment(), checkTokenPublicOnly())
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository))
}, reqStarsEnabled(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository))
m.Get("/times", repo.ListMyTrackedTimes)
m.Get("/stopwatches", repo.GetStopwatches)
m.Get("/subscriptions", user.GetMyWatchedRepos)
Expand Down Expand Up @@ -1248,7 +1258,7 @@ func Routes() *web.Router {
m.Post("/markup", reqToken(), bind(api.MarkupOption{}), misc.Markup)
m.Post("/markdown", reqToken(), bind(api.MarkdownOption{}), misc.Markdown)
m.Post("/markdown/raw", reqToken(), misc.MarkdownRaw)
m.Get("/stargazers", repo.ListStargazers)
m.Get("/stargazers", reqStarsEnabled(), repo.ListStargazers)
m.Get("/subscribers", repo.ListSubscribers)
m.Group("/subscription", func() {
m.Get("", user.IsWatching)
Expand Down
2 changes: 2 additions & 0 deletions routers/api/v1/repo/star.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ func ListStargazers(ctx *context.APIContext) {
// "$ref": "#/responses/UserList"
// "404":
// "$ref": "#/responses/notFound"
// "403":
// "$ref": "#/responses/forbidden"

stargazers, err := repo_model.GetStargazers(ctx, ctx.Repo.Repository, utils.GetListOptions(ctx))
if err != nil {
Expand Down
8 changes: 8 additions & 0 deletions routers/api/v1/user/star.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ func GetStarredRepos(ctx *context.APIContext) {
// "$ref": "#/responses/RepositoryList"
// "404":
// "$ref": "#/responses/notFound"
// "403":
// "$ref": "#/responses/forbidden"

private := ctx.ContextUser.ID == ctx.Doer.ID
repos, err := getStarredRepos(ctx, ctx.ContextUser, private)
Expand Down Expand Up @@ -97,6 +99,8 @@ func GetMyStarredRepos(ctx *context.APIContext) {
// responses:
// "200":
// "$ref": "#/responses/RepositoryList"
// "403":
// "$ref": "#/responses/forbidden"

repos, err := getStarredRepos(ctx, ctx.Doer, true)
if err != nil {
Expand Down Expand Up @@ -128,6 +132,8 @@ func IsStarring(ctx *context.APIContext) {
// "$ref": "#/responses/empty"
// "404":
// "$ref": "#/responses/notFound"
// "403":
// "$ref": "#/responses/forbidden"

if repo_model.IsStaring(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID) {
ctx.Status(http.StatusNoContent)
Expand Down Expand Up @@ -193,6 +199,8 @@ func Unstar(ctx *context.APIContext) {
// "$ref": "#/responses/empty"
// "404":
// "$ref": "#/responses/notFound"
// "403":
// "$ref": "#/responses/forbidden"

err := repo_model.StarRepo(ctx, ctx.Doer, ctx.Repo.Repository, false)
if err != nil {
Expand Down
13 changes: 11 additions & 2 deletions routers/web/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,13 @@ func registerRoutes(m *web.Router) {
}
}

starsEnabled := func(ctx *context.Context) {
if setting.Repository.DisableStars {
ctx.Error(http.StatusForbidden)
return
}
}

lfsServerEnabled := func(ctx *context.Context) {
if !setting.LFS.StartServer {
ctx.Error(http.StatusNotFound)
Expand Down Expand Up @@ -1593,10 +1600,12 @@ func registerRoutes(m *web.Router) {
// end "/{username}/{reponame}": repo code

m.Group("/{username}/{reponame}", func() {
m.Get("/stars", repo.Stars)
m.Get("/stars", starsEnabled, repo.Stars)
m.Get("/watchers", repo.Watchers)
m.Get("/search", reqUnitCodeReader, repo.Search)
m.Post("/action/{action}", reqSignIn, repo.Action)
m.Post("/action/{action:star|unstar}", reqSignIn, starsEnabled, repo.Action)
m.Post("/action/{action:watch|unwatch}", reqSignIn, repo.Action)
m.Post("/action/{action:accept_transfer|reject_transfer}", reqSignIn, repo.Action)
}, optSignIn, context.RepoAssignment)

common.AddOwnerRepoGitLFSRoutes(m, optSignInIgnoreCsrf, lfsServerEnabled) // "/{username}/{reponame}/{lfs-paths}": git-lfs support
Expand Down
15 changes: 15 additions & 0 deletions templates/swagger/v1_json.tmpl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

64 changes: 64 additions & 0 deletions tests/integration/api_user_star_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import (
auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/tests"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -91,3 +93,65 @@ func TestAPIStar(t *testing.T) {
MakeRequest(t, req, http.StatusNoContent)
})
}

func TestAPIStarDisabled(t *testing.T) {
defer tests.PrepareTestEnv(t)()

user := "user1"
repo := "user2/repo1"

session := loginUser(t, user)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadUser)
tokenWithUserScope := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteUser, auth_model.AccessTokenScopeWriteRepository)

defer test.MockVariableValue(&setting.Repository.DisableStars, true)()

t.Run("Star", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()

req := NewRequest(t, "PUT", fmt.Sprintf("/api/v1/user/starred/%s", repo)).
AddTokenAuth(tokenWithUserScope)
MakeRequest(t, req, http.StatusForbidden)

user34 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 34})
req = NewRequest(t, "PUT", fmt.Sprintf("/api/v1/user/starred/%s", repo)).
AddTokenAuth(getUserToken(t, user34.Name, auth_model.AccessTokenScopeWriteRepository))
MakeRequest(t, req, http.StatusForbidden)
})

t.Run("GetStarredRepos", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()

req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/users/%s/starred", user)).
AddTokenAuth(token)
MakeRequest(t, req, http.StatusForbidden)
})

t.Run("GetMyStarredRepos", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()

req := NewRequest(t, "GET", "/api/v1/user/starred").
AddTokenAuth(tokenWithUserScope)
MakeRequest(t, req, http.StatusForbidden)
})

t.Run("IsStarring", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()

req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/user/starred/%s", repo)).
AddTokenAuth(tokenWithUserScope)
MakeRequest(t, req, http.StatusForbidden)

req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/user/starred/%s", repo+"notexisting")).
AddTokenAuth(tokenWithUserScope)
MakeRequest(t, req, http.StatusForbidden)
})

t.Run("Unstar", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()

req := NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/user/starred/%s", repo)).
AddTokenAuth(tokenWithUserScope)
MakeRequest(t, req, http.StatusForbidden)
})
}

0 comments on commit d0f4e92

Please sign in to comment.