Reject star-related requests if stars are disabled (#33208)
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 <wxiaoguang@gmail.com>
This commit is contained in:
parent
a4676db7dd
commit
d0f4e92563
6 changed files with 113 additions and 5 deletions
|
@ -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) {
|
func orgAssignment(args ...bool) func(ctx *context.APIContext) {
|
||||||
var (
|
var (
|
||||||
assignOrg bool
|
assignOrg bool
|
||||||
|
@ -995,7 +1005,7 @@ func Routes() *web.Router {
|
||||||
m.Get("/{target}", user.CheckFollowing)
|
m.Get("/{target}", user.CheckFollowing)
|
||||||
})
|
})
|
||||||
|
|
||||||
m.Get("/starred", user.GetStarredRepos)
|
m.Get("/starred", reqStarsEnabled(), user.GetStarredRepos)
|
||||||
|
|
||||||
m.Get("/subscriptions", user.GetWatchedRepos)
|
m.Get("/subscriptions", user.GetWatchedRepos)
|
||||||
}, context.UserAssignmentAPI(), checkTokenPublicOnly())
|
}, context.UserAssignmentAPI(), checkTokenPublicOnly())
|
||||||
|
@ -1086,7 +1096,7 @@ func Routes() *web.Router {
|
||||||
m.Put("", user.Star)
|
m.Put("", user.Star)
|
||||||
m.Delete("", user.Unstar)
|
m.Delete("", user.Unstar)
|
||||||
}, repoAssignment(), checkTokenPublicOnly())
|
}, repoAssignment(), checkTokenPublicOnly())
|
||||||
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository))
|
}, reqStarsEnabled(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository))
|
||||||
m.Get("/times", repo.ListMyTrackedTimes)
|
m.Get("/times", repo.ListMyTrackedTimes)
|
||||||
m.Get("/stopwatches", repo.GetStopwatches)
|
m.Get("/stopwatches", repo.GetStopwatches)
|
||||||
m.Get("/subscriptions", user.GetMyWatchedRepos)
|
m.Get("/subscriptions", user.GetMyWatchedRepos)
|
||||||
|
@ -1248,7 +1258,7 @@ func Routes() *web.Router {
|
||||||
m.Post("/markup", reqToken(), bind(api.MarkupOption{}), misc.Markup)
|
m.Post("/markup", reqToken(), bind(api.MarkupOption{}), misc.Markup)
|
||||||
m.Post("/markdown", reqToken(), bind(api.MarkdownOption{}), misc.Markdown)
|
m.Post("/markdown", reqToken(), bind(api.MarkdownOption{}), misc.Markdown)
|
||||||
m.Post("/markdown/raw", reqToken(), misc.MarkdownRaw)
|
m.Post("/markdown/raw", reqToken(), misc.MarkdownRaw)
|
||||||
m.Get("/stargazers", repo.ListStargazers)
|
m.Get("/stargazers", reqStarsEnabled(), repo.ListStargazers)
|
||||||
m.Get("/subscribers", repo.ListSubscribers)
|
m.Get("/subscribers", repo.ListSubscribers)
|
||||||
m.Group("/subscription", func() {
|
m.Group("/subscription", func() {
|
||||||
m.Get("", user.IsWatching)
|
m.Get("", user.IsWatching)
|
||||||
|
|
|
@ -44,6 +44,8 @@ func ListStargazers(ctx *context.APIContext) {
|
||||||
// "$ref": "#/responses/UserList"
|
// "$ref": "#/responses/UserList"
|
||||||
// "404":
|
// "404":
|
||||||
// "$ref": "#/responses/notFound"
|
// "$ref": "#/responses/notFound"
|
||||||
|
// "403":
|
||||||
|
// "$ref": "#/responses/forbidden"
|
||||||
|
|
||||||
stargazers, err := repo_model.GetStargazers(ctx, ctx.Repo.Repository, utils.GetListOptions(ctx))
|
stargazers, err := repo_model.GetStargazers(ctx, ctx.Repo.Repository, utils.GetListOptions(ctx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -66,6 +66,8 @@ func GetStarredRepos(ctx *context.APIContext) {
|
||||||
// "$ref": "#/responses/RepositoryList"
|
// "$ref": "#/responses/RepositoryList"
|
||||||
// "404":
|
// "404":
|
||||||
// "$ref": "#/responses/notFound"
|
// "$ref": "#/responses/notFound"
|
||||||
|
// "403":
|
||||||
|
// "$ref": "#/responses/forbidden"
|
||||||
|
|
||||||
private := ctx.ContextUser.ID == ctx.Doer.ID
|
private := ctx.ContextUser.ID == ctx.Doer.ID
|
||||||
repos, err := getStarredRepos(ctx, ctx.ContextUser, private)
|
repos, err := getStarredRepos(ctx, ctx.ContextUser, private)
|
||||||
|
@ -97,6 +99,8 @@ func GetMyStarredRepos(ctx *context.APIContext) {
|
||||||
// responses:
|
// responses:
|
||||||
// "200":
|
// "200":
|
||||||
// "$ref": "#/responses/RepositoryList"
|
// "$ref": "#/responses/RepositoryList"
|
||||||
|
// "403":
|
||||||
|
// "$ref": "#/responses/forbidden"
|
||||||
|
|
||||||
repos, err := getStarredRepos(ctx, ctx.Doer, true)
|
repos, err := getStarredRepos(ctx, ctx.Doer, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -128,6 +132,8 @@ func IsStarring(ctx *context.APIContext) {
|
||||||
// "$ref": "#/responses/empty"
|
// "$ref": "#/responses/empty"
|
||||||
// "404":
|
// "404":
|
||||||
// "$ref": "#/responses/notFound"
|
// "$ref": "#/responses/notFound"
|
||||||
|
// "403":
|
||||||
|
// "$ref": "#/responses/forbidden"
|
||||||
|
|
||||||
if repo_model.IsStaring(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID) {
|
if repo_model.IsStaring(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID) {
|
||||||
ctx.Status(http.StatusNoContent)
|
ctx.Status(http.StatusNoContent)
|
||||||
|
@ -193,6 +199,8 @@ func Unstar(ctx *context.APIContext) {
|
||||||
// "$ref": "#/responses/empty"
|
// "$ref": "#/responses/empty"
|
||||||
// "404":
|
// "404":
|
||||||
// "$ref": "#/responses/notFound"
|
// "$ref": "#/responses/notFound"
|
||||||
|
// "403":
|
||||||
|
// "$ref": "#/responses/forbidden"
|
||||||
|
|
||||||
err := repo_model.StarRepo(ctx, ctx.Doer, ctx.Repo.Repository, false)
|
err := repo_model.StarRepo(ctx, ctx.Doer, ctx.Repo.Repository, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -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) {
|
lfsServerEnabled := func(ctx *context.Context) {
|
||||||
if !setting.LFS.StartServer {
|
if !setting.LFS.StartServer {
|
||||||
ctx.Error(http.StatusNotFound)
|
ctx.Error(http.StatusNotFound)
|
||||||
|
@ -1593,10 +1600,12 @@ func registerRoutes(m *web.Router) {
|
||||||
// end "/{username}/{reponame}": repo code
|
// end "/{username}/{reponame}": repo code
|
||||||
|
|
||||||
m.Group("/{username}/{reponame}", func() {
|
m.Group("/{username}/{reponame}", func() {
|
||||||
m.Get("/stars", repo.Stars)
|
m.Get("/stars", starsEnabled, repo.Stars)
|
||||||
m.Get("/watchers", repo.Watchers)
|
m.Get("/watchers", repo.Watchers)
|
||||||
m.Get("/search", reqUnitCodeReader, repo.Search)
|
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)
|
}, optSignIn, context.RepoAssignment)
|
||||||
|
|
||||||
common.AddOwnerRepoGitLFSRoutes(m, optSignInIgnoreCsrf, lfsServerEnabled) // "/{username}/{reponame}/{lfs-paths}": git-lfs support
|
common.AddOwnerRepoGitLFSRoutes(m, optSignInIgnoreCsrf, lfsServerEnabled) // "/{username}/{reponame}/{lfs-paths}": git-lfs support
|
||||||
|
|
15
templates/swagger/v1_json.tmpl
generated
15
templates/swagger/v1_json.tmpl
generated
|
@ -13808,6 +13808,9 @@
|
||||||
"200": {
|
"200": {
|
||||||
"$ref": "#/responses/UserList"
|
"$ref": "#/responses/UserList"
|
||||||
},
|
},
|
||||||
|
"403": {
|
||||||
|
"$ref": "#/responses/forbidden"
|
||||||
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"$ref": "#/responses/notFound"
|
"$ref": "#/responses/notFound"
|
||||||
}
|
}
|
||||||
|
@ -17546,6 +17549,9 @@
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"$ref": "#/responses/RepositoryList"
|
"$ref": "#/responses/RepositoryList"
|
||||||
|
},
|
||||||
|
"403": {
|
||||||
|
"$ref": "#/responses/forbidden"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17577,6 +17583,9 @@
|
||||||
"204": {
|
"204": {
|
||||||
"$ref": "#/responses/empty"
|
"$ref": "#/responses/empty"
|
||||||
},
|
},
|
||||||
|
"403": {
|
||||||
|
"$ref": "#/responses/forbidden"
|
||||||
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"$ref": "#/responses/notFound"
|
"$ref": "#/responses/notFound"
|
||||||
}
|
}
|
||||||
|
@ -17642,6 +17651,9 @@
|
||||||
"204": {
|
"204": {
|
||||||
"$ref": "#/responses/empty"
|
"$ref": "#/responses/empty"
|
||||||
},
|
},
|
||||||
|
"403": {
|
||||||
|
"$ref": "#/responses/forbidden"
|
||||||
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"$ref": "#/responses/notFound"
|
"$ref": "#/responses/notFound"
|
||||||
}
|
}
|
||||||
|
@ -18318,6 +18330,9 @@
|
||||||
"200": {
|
"200": {
|
||||||
"$ref": "#/responses/RepositoryList"
|
"$ref": "#/responses/RepositoryList"
|
||||||
},
|
},
|
||||||
|
"403": {
|
||||||
|
"$ref": "#/responses/forbidden"
|
||||||
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"$ref": "#/responses/notFound"
|
"$ref": "#/responses/notFound"
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,9 @@ import (
|
||||||
auth_model "code.gitea.io/gitea/models/auth"
|
auth_model "code.gitea.io/gitea/models/auth"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
"code.gitea.io/gitea/modules/test"
|
||||||
"code.gitea.io/gitea/tests"
|
"code.gitea.io/gitea/tests"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -91,3 +93,65 @@ func TestAPIStar(t *testing.T) {
|
||||||
MakeRequest(t, req, http.StatusNoContent)
|
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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue