Skip to content

Commit 89255e9

Browse files
Fix visibility check for api get user info:
- check for teams intersection - fix context output - right fake 404 if not visible
1 parent f24d3bc commit 89255e9

File tree

3 files changed

+67
-7
lines changed

3 files changed

+67
-7
lines changed

models/user.go

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,11 @@ func (u *User) IsPasswordSet() bool {
434434

435435
// IsVisibleToUser check if viewer is able to see user profile
436436
func (u *User) IsVisibleToUser(viewer *User) bool {
437+
438+
if viewer != nil && viewer.IsAdmin {
439+
return true
440+
}
441+
437442
switch u.Visibility {
438443
case structs.VisibleTypePublic:
439444
return true
@@ -446,8 +451,61 @@ func (u *User) IsVisibleToUser(viewer *User) bool {
446451
if viewer == nil || viewer.IsRestricted {
447452
return false
448453
}
449-
// if private user if follow the viewer he know each other ...
450-
return IsFollowing(u.ID, viewer.ID) || viewer.IsAdmin
454+
455+
// If they follow - they see each over
456+
follower := IsFollowing(u.ID, viewer.ID)
457+
if follower {
458+
return true
459+
}
460+
461+
// Now we need to check if they in some team together
462+
463+
var orgIds1 []int64
464+
var orgIds2 []int64
465+
466+
// First user all teams organization
467+
if err := x.Table("team_user").
468+
Cols("team_user.org_id").
469+
Where("team_user.uid = ?", u.ID).
470+
Find(&orgIds1); err != nil {
471+
return false
472+
}
473+
if len(orgIds1) == 0 {
474+
// No teams 1
475+
return false
476+
}
477+
478+
// Second user all teams organization
479+
if err := x.Table("team_user").
480+
Cols("team_user.org_id").
481+
Where("team_user.uid = ?", viewer.ID).
482+
Find(&orgIds2); err != nil {
483+
return false
484+
}
485+
if len(orgIds2) == 0 {
486+
// No teams 2
487+
return false
488+
}
489+
490+
// Intersect they organizations
491+
var cond builder.Cond = builder.
492+
In("id", orgIds1).
493+
And(builder.In("id", orgIds2)).
494+
And(builder.Eq{"type": UserTypeOrganization})
495+
count, err := x.Table("user").
496+
Cols("id").
497+
Where(cond).
498+
Count(1)
499+
if err != nil {
500+
return false
501+
}
502+
if count == 0 {
503+
// they teams from different orgs?
504+
return false
505+
}
506+
507+
// they in some organizations together
508+
return true
451509
}
452510
return false
453511
}

routers/api/v1/user/helper.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ func GetUserByParamsName(ctx *context.APIContext, name string) *models.User {
1717
user, err := models.GetUserByName(username)
1818
if err != nil {
1919
if models.IsErrUserNotExist(err) {
20-
if redirectUserID, err := models.LookupUserRedirect(username); err == nil {
20+
if redirectUserID, err2 := models.LookupUserRedirect(username); err2 == nil {
2121
context.RedirectToUser(ctx.Context, username, redirectUserID)
2222
} else {
2323
ctx.NotFound("GetUserByName", err)

routers/api/v1/user/user.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,16 @@ func GetInfo(ctx *context.APIContext) {
103103
// "$ref": "#/responses/notFound"
104104

105105
u := GetUserByParams(ctx)
106-
if !u.IsVisibleToUser(ctx.User) {
107-
ctx.JSON(http.StatusNotFound, nil)
108-
return
109-
}
106+
110107
if ctx.Written() {
111108
return
112109
}
113110

111+
if !u.IsVisibleToUser(ctx.User) {
112+
// fake ErrUserNotExist error message to not leak information about existence
113+
ctx.NotFound("GetUserByName", models.ErrUserNotExist{Name: ctx.Params(":username")})
114+
return
115+
}
114116
ctx.JSON(http.StatusOK, convert.ToUser(u, ctx.User))
115117
}
116118

0 commit comments

Comments
 (0)