MM-45535: Batch optimize auth checks in GraphQL (#20634)

We create two new auth checks which take multiple channels
and teams. They can be used to check whenever a user needs
access to multiple entities.

These are then access in dataloaders to ease the load in the
database.

```release-note
NONE
```
Этот коммит содержится в:
Agniva De Sarker
2022-07-12 23:26:48 +05:30
коммит произвёл GitHub
родитель 72346eccb8
Коммит 049e67b863
6 изменённых файлов: 171 добавлений и 28 удалений

Просмотреть файл

@@ -26,11 +26,6 @@ func (cm *channelMember) User(ctx context.Context) (*user, error) {
// match with api4.Channel
func (cm *channelMember) Channel(ctx context.Context) (*channel, error) {
c, err := getCtx(ctx)
if err != nil {
return nil, err
}
loader, err := getChannelsLoader(ctx)
if err != nil {
return nil, err
@@ -43,19 +38,6 @@ func (cm *channelMember) Channel(ctx context.Context) (*channel, error) {
}
channel := result.(*channel)
if channel.Type == model.ChannelTypeOpen {
if !c.App.SessionHasPermissionToTeam(*c.AppContext.Session(), channel.TeamId, model.PermissionReadPublicChannel) &&
!c.App.SessionHasPermissionToChannel(*c.AppContext.Session(), cm.ChannelId, model.PermissionReadChannel) {
c.SetPermissionError(model.PermissionReadPublicChannel)
return nil, c.Err
}
} else {
if !c.App.SessionHasPermissionToChannel(*c.AppContext.Session(), cm.ChannelId, model.PermissionReadChannel) {
c.SetPermissionError(model.PermissionReadChannel)
return nil, c.Err
}
}
return channel, nil
}
@@ -95,6 +77,32 @@ func getGraphQLChannels(c *web.Context, channelIDs []string) ([]*channel, error)
return nil, fmt.Errorf("all channels were not found. Requested %d; Found %d", len(channelIDs), len(channels))
}
var openChannels, nonOpenChannels, teamsForOpenChannels []string
uniqueTeams := make(map[string]bool)
for _, ch := range channels {
if ch.Type == model.ChannelTypeOpen {
openChannels = append(openChannels, ch.Id)
uniqueTeams[ch.TeamId] = true
} else {
nonOpenChannels = append(nonOpenChannels, ch.Id)
}
}
for teamID := range uniqueTeams {
teamsForOpenChannels = append(teamsForOpenChannels, teamID)
}
if len(openChannels) > 0 && !c.App.SessionHasPermissionToChannels(*c.AppContext.Session(), openChannels, model.PermissionReadChannel) &&
!c.App.SessionHasPermissionToTeams(*c.AppContext.Session(), teamsForOpenChannels, model.PermissionReadPublicChannel) {
c.SetPermissionError(model.PermissionReadPublicChannel)
return nil, c.Err
}
if len(nonOpenChannels) > 0 && !c.App.SessionHasPermissionToChannels(*c.AppContext.Session(), nonOpenChannels, model.PermissionReadChannel) {
c.SetPermissionError(model.PermissionReadChannel)
return nil, c.Err
}
appErr = c.App.FillInChannelsProps(model.ChannelList(channels))
if appErr != nil {
return nil, appErr

Просмотреть файл

@@ -64,15 +64,19 @@ func getGraphQLTeams(c *web.Context, teamIDs []string) ([]*model.Team, error) {
return nil, fmt.Errorf("all teams were not found. Requested %d; Found %d", len(teamIDs), len(teams))
}
// We pre-calculate this so that it's not computed in separate goroutines outside
// the dataloader.
for i, team := range teams {
if (!team.AllowOpenInvite || team.Type != model.TeamOpen) &&
!c.App.SessionHasPermissionToTeam(*c.AppContext.Session(), team.Id, model.PermissionViewTeam) {
c.SetPermissionError(model.PermissionViewTeam)
return nil, c.Err
var teamsToCheck []string
for _, team := range teams {
if !team.AllowOpenInvite || team.Type != model.TeamOpen {
teamsToCheck = append(teamsToCheck, team.Id)
}
}
if !c.App.SessionHasPermissionToTeams(*c.AppContext.Session(), teamsToCheck, model.PermissionViewMembers) {
c.SetPermissionError(model.PermissionViewTeam)
return nil, c.Err
}
for i, team := range teams {
teams[i] = c.App.SanitizeTeam(*c.AppContext.Session(), team)
}