backport #37118 This PR closes remaining `public-only` token gaps in the API by making the restriction apply consistently across repository, organization, activity, notification, and authenticated `/api/v1/user/...` routes. Previously, `public-only` tokens were still able to: - receive private results from some list/search/self endpoints, - access repository data through ID-based lookups, - and reach several authenticated self routes that should remain unavailable for public-only access. This change treats `public-only` as a cross-cutting visibility boundary: - list/search endpoints now filter private resources consistently, - repository lookups enforce the same restriction even when addressed indirectly, - and self routes that inherently expose or mutate private account state now reject `public-only` tokens. --- Generated by a coding agent with Codex 5.2 Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com> Co-authored-by: Nicolas <bircni@icloud.com>
This commit is contained in:
@@ -19,12 +19,15 @@ import (
|
||||
func listUserRepos(ctx *context.APIContext, u *user_model.User, private bool) {
|
||||
opts := utils.GetListOptions(ctx)
|
||||
|
||||
repos, count, err := repo_model.GetUserRepositories(ctx, repo_model.SearchRepoOptions{
|
||||
searchOpts := repo_model.SearchRepoOptions{
|
||||
Actor: u,
|
||||
Private: private,
|
||||
ListOptions: opts,
|
||||
OrderBy: "id ASC",
|
||||
})
|
||||
}
|
||||
searchOpts.ApplyPublicOnly(ctx.PublicOnly)
|
||||
|
||||
repos, count, err := repo_model.GetUserRepositories(ctx, searchOpts)
|
||||
if err != nil {
|
||||
ctx.APIErrorInternal(err)
|
||||
return
|
||||
@@ -79,8 +82,7 @@ func ListUserRepos(ctx *context.APIContext) {
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
|
||||
private := ctx.IsSigned
|
||||
listUserRepos(ctx, ctx.ContextUser, private)
|
||||
listUserRepos(ctx, ctx.ContextUser, ctx.IsSigned)
|
||||
}
|
||||
|
||||
// ListMyRepos - list the repositories you own or have access to.
|
||||
@@ -110,6 +112,7 @@ func ListMyRepos(ctx *context.APIContext) {
|
||||
Private: ctx.IsSigned,
|
||||
IncludeDescription: true,
|
||||
}
|
||||
opts.ApplyPublicOnly(ctx.PublicOnly)
|
||||
|
||||
repos, count, err := repo_model.SearchRepository(ctx, opts)
|
||||
if err != nil {
|
||||
|
||||
@@ -20,11 +20,14 @@ import (
|
||||
// getStarredRepos returns the repos that the user with the specified userID has
|
||||
// starred
|
||||
func getStarredRepos(ctx *context.APIContext, user *user_model.User, private bool) ([]*api.Repository, error) {
|
||||
starredRepos, err := repo_model.GetStarredRepos(ctx, &repo_model.StarredReposOptions{
|
||||
opts := &repo_model.StarredReposOptions{
|
||||
ListOptions: utils.GetListOptions(ctx),
|
||||
StarrerID: user.ID,
|
||||
IncludePrivate: private,
|
||||
})
|
||||
}
|
||||
opts.ApplyPublicOnly(ctx.PublicOnly)
|
||||
|
||||
starredRepos, err := repo_model.GetStarredRepos(ctx, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
|
||||
activities_model "code.gitea.io/gitea/models/activities"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/routers/api/v1/utils"
|
||||
"code.gitea.io/gitea/services/context"
|
||||
"code.gitea.io/gitea/services/convert"
|
||||
@@ -69,19 +68,16 @@ func Search(ctx *context.APIContext) {
|
||||
maxResults = 1
|
||||
users = []*user_model.User{user_model.NewActionsUser()}
|
||||
default:
|
||||
var visible []structs.VisibleType
|
||||
if ctx.PublicOnly {
|
||||
visible = []structs.VisibleType{structs.VisibleTypePublic}
|
||||
}
|
||||
users, maxResults, err = user_model.SearchUsers(ctx, user_model.SearchUserOptions{
|
||||
opts := user_model.SearchUserOptions{
|
||||
Actor: ctx.Doer,
|
||||
Keyword: ctx.FormTrim("q"),
|
||||
UID: uid,
|
||||
Types: []user_model.UserType{user_model.UserTypeIndividual},
|
||||
SearchByEmail: true,
|
||||
Visible: visible,
|
||||
ListOptions: listOptions,
|
||||
})
|
||||
}
|
||||
opts.ApplyPublicOnly(ctx.PublicOnly)
|
||||
users, maxResults, err = user_model.SearchUsers(ctx, opts)
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, map[string]any{
|
||||
"ok": false,
|
||||
@@ -214,6 +210,7 @@ func ListUserActivityFeeds(ctx *context.APIContext) {
|
||||
Date: ctx.FormString("date"),
|
||||
ListOptions: listOptions,
|
||||
}
|
||||
opts.ApplyPublicOnly(ctx.PublicOnly)
|
||||
|
||||
feeds, count, err := feed_service.GetFeeds(ctx, opts)
|
||||
if err != nil {
|
||||
|
||||
@@ -18,11 +18,14 @@ import (
|
||||
|
||||
// getWatchedRepos returns the repos that the user with the specified userID is watching
|
||||
func getWatchedRepos(ctx *context.APIContext, user *user_model.User, private bool) ([]*api.Repository, int64, error) {
|
||||
watchedRepos, total, err := repo_model.GetWatchedRepos(ctx, &repo_model.WatchedReposOptions{
|
||||
opts := &repo_model.WatchedReposOptions{
|
||||
ListOptions: utils.GetListOptions(ctx),
|
||||
WatcherID: user.ID,
|
||||
IncludePrivate: private,
|
||||
})
|
||||
}
|
||||
opts.ApplyPublicOnly(ctx.PublicOnly)
|
||||
|
||||
watchedRepos, total, err := repo_model.GetWatchedRepos(ctx, opts)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user