Only show Followers that current user can access (#20220)

Users who are following or being followed by a user should only be
displayed if the viewing user can see them.

Signed-off-by: Andrew Thornton <art27@cantab.net>
This commit is contained in:
zeripath 2022-07-05 16:47:45 +01:00 committed by GitHub
parent ed13d7aadf
commit 45f17528a8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 58 additions and 17 deletions

View file

@ -316,37 +316,45 @@ func (u *User) GenerateEmailActivateCode(email string) string {
} }
// GetUserFollowers returns range of user's followers. // GetUserFollowers returns range of user's followers.
func GetUserFollowers(u *User, listOptions db.ListOptions) ([]*User, error) { func GetUserFollowers(ctx context.Context, u, viewer *User, listOptions db.ListOptions) ([]*User, int64, error) {
sess := db.GetEngine(db.DefaultContext). sess := db.GetEngine(ctx).
Select("`user`.*").
Join("LEFT", "follow", "`user`.id=follow.user_id").
Where("follow.follow_id=?", u.ID). Where("follow.follow_id=?", u.ID).
Join("LEFT", "follow", "`user`.id=follow.user_id") And(isUserVisibleToViewerCond(viewer))
if listOptions.Page != 0 { if listOptions.Page != 0 {
sess = db.SetSessionPagination(sess, &listOptions) sess = db.SetSessionPagination(sess, &listOptions)
users := make([]*User, 0, listOptions.PageSize) users := make([]*User, 0, listOptions.PageSize)
return users, sess.Find(&users) count, err := sess.FindAndCount(&users)
return users, count, err
} }
users := make([]*User, 0, 8) users := make([]*User, 0, 8)
return users, sess.Find(&users) count, err := sess.FindAndCount(&users)
return users, count, err
} }
// GetUserFollowing returns range of user's following. // GetUserFollowing returns range of user's following.
func GetUserFollowing(u *User, listOptions db.ListOptions) ([]*User, error) { func GetUserFollowing(ctx context.Context, u, viewer *User, listOptions db.ListOptions) ([]*User, int64, error) {
sess := db.GetEngine(db.DefaultContext). sess := db.GetEngine(db.DefaultContext).
Select("`user`.*").
Join("LEFT", "follow", "`user`.id=follow.follow_id").
Where("follow.user_id=?", u.ID). Where("follow.user_id=?", u.ID).
Join("LEFT", "follow", "`user`.id=follow.follow_id") And(isUserVisibleToViewerCond(viewer))
if listOptions.Page != 0 { if listOptions.Page != 0 {
sess = db.SetSessionPagination(sess, &listOptions) sess = db.SetSessionPagination(sess, &listOptions)
users := make([]*User, 0, listOptions.PageSize) users := make([]*User, 0, listOptions.PageSize)
return users, sess.Find(&users) count, err := sess.FindAndCount(&users)
return users, count, err
} }
users := make([]*User, 0, 8) users := make([]*User, 0, 8)
return users, sess.Find(&users) count, err := sess.FindAndCount(&users)
return users, count, err
} }
// NewGitSig generates and returns the signature of given user. // NewGitSig generates and returns the signature of given user.
@ -1222,6 +1230,39 @@ func GetAdminUser() (*User, error) {
return &admin, nil return &admin, nil
} }
func isUserVisibleToViewerCond(viewer *User) builder.Cond {
if viewer != nil && viewer.IsAdmin {
return builder.NewCond()
}
if viewer == nil || viewer.IsRestricted {
return builder.Eq{
"`user`.visibility": structs.VisibleTypePublic,
}
}
return builder.Neq{
"`user`.visibility": structs.VisibleTypePrivate,
}.Or(
builder.In("`user`.id",
builder.
Select("`follow`.user_id").
From("follow").
Where(builder.Eq{"`follow`.follow_id": viewer.ID})),
builder.In("`user`.id",
builder.
Select("`team_user`.uid").
From("team_user").
Join("INNER", "`team_user` AS t2", "`team_user`.id = `t2`.id").
Where(builder.Eq{"`t2`.uid": viewer.ID})),
builder.In("`user`.id",
builder.
Select("`team_user`.uid").
From("team_user").
Join("INNER", "`team_user` AS t2", "`team_user`.org_id = `t2`.org_id").
Where(builder.Eq{"`t2`.uid": viewer.ID})))
}
// IsUserVisibleToViewer check if viewer is able to see user profile // IsUserVisibleToViewer check if viewer is able to see user profile
func IsUserVisibleToViewer(ctx context.Context, u, viewer *User) bool { func IsUserVisibleToViewer(ctx context.Context, u, viewer *User) bool {
if viewer != nil && viewer.IsAdmin { if viewer != nil && viewer.IsAdmin {

View file

@ -24,13 +24,13 @@ func responseAPIUsers(ctx *context.APIContext, users []*user_model.User) {
} }
func listUserFollowers(ctx *context.APIContext, u *user_model.User) { func listUserFollowers(ctx *context.APIContext, u *user_model.User) {
users, err := user_model.GetUserFollowers(u, utils.GetListOptions(ctx)) users, count, err := user_model.GetUserFollowers(ctx, u, ctx.Doer, utils.GetListOptions(ctx))
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "GetUserFollowers", err) ctx.Error(http.StatusInternalServerError, "GetUserFollowers", err)
return return
} }
ctx.SetTotalCountHeader(int64(u.NumFollowers)) ctx.SetTotalCountHeader(count)
responseAPIUsers(ctx, users) responseAPIUsers(ctx, users)
} }
@ -86,13 +86,13 @@ func ListFollowers(ctx *context.APIContext) {
} }
func listUserFollowing(ctx *context.APIContext, u *user_model.User) { func listUserFollowing(ctx *context.APIContext, u *user_model.User) {
users, err := user_model.GetUserFollowing(u, utils.GetListOptions(ctx)) users, count, err := user_model.GetUserFollowing(ctx, u, ctx.Doer, utils.GetListOptions(ctx))
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "GetUserFollowing", err) ctx.Error(http.StatusInternalServerError, "GetUserFollowing", err)
return return
} }
ctx.SetTotalCountHeader(int64(u.NumFollowing)) ctx.SetTotalCountHeader(count)
responseAPIUsers(ctx, users) responseAPIUsers(ctx, users)
} }

View file

@ -157,7 +157,7 @@ func Profile(ctx *context.Context) {
switch tab { switch tab {
case "followers": case "followers":
items, err := user_model.GetUserFollowers(ctx.ContextUser, db.ListOptions{ items, count, err := user_model.GetUserFollowers(ctx, ctx.ContextUser, ctx.Doer, db.ListOptions{
PageSize: setting.UI.User.RepoPagingNum, PageSize: setting.UI.User.RepoPagingNum,
Page: page, Page: page,
}) })
@ -167,9 +167,9 @@ func Profile(ctx *context.Context) {
} }
ctx.Data["Cards"] = items ctx.Data["Cards"] = items
total = ctx.ContextUser.NumFollowers total = int(count)
case "following": case "following":
items, err := user_model.GetUserFollowing(ctx.ContextUser, db.ListOptions{ items, count, err := user_model.GetUserFollowing(ctx, ctx.ContextUser, ctx.Doer, db.ListOptions{
PageSize: setting.UI.User.RepoPagingNum, PageSize: setting.UI.User.RepoPagingNum,
Page: page, Page: page,
}) })
@ -179,7 +179,7 @@ func Profile(ctx *context.Context) {
} }
ctx.Data["Cards"] = items ctx.Data["Cards"] = items
total = ctx.ContextUser.NumFollowing total = int(count)
case "activity": case "activity":
ctx.Data["Feeds"], err = models.GetFeeds(ctx, models.GetFeedsOptions{ ctx.Data["Feeds"], err = models.GetFeeds(ctx, models.GetFeedsOptions{
RequestedUser: ctx.ContextUser, RequestedUser: ctx.ContextUser,