1// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
2// See LICENSE.txt for license information.
3
4package app
5
6import (
7	"context"
8	"net/http"
9	"strings"
10
11	"github.com/mattermost/mattermost-server/v6/model"
12	"github.com/mattermost/mattermost-server/v6/shared/mlog"
13)
14
15func (a *App) MakePermissionError(s *model.Session, permissions []*model.Permission) *model.AppError {
16	permissionsStr := "permission="
17	for _, permission := range permissions {
18		permissionsStr += permission.Id
19		permissionsStr += ","
20	}
21	return model.NewAppError("Permissions", "api.context.permissions.app_error", nil, "userId="+s.UserId+", "+permissionsStr, http.StatusForbidden)
22}
23
24func (a *App) SessionHasPermissionTo(session model.Session, permission *model.Permission) bool {
25	if session.IsUnrestricted() {
26		return true
27	}
28	return a.RolesGrantPermission(session.GetUserRoles(), permission.Id)
29}
30
31func (a *App) SessionHasPermissionToAny(session model.Session, permissions []*model.Permission) bool {
32	for _, perm := range permissions {
33		if a.SessionHasPermissionTo(session, perm) {
34			return true
35		}
36	}
37	return false
38}
39
40func (a *App) SessionHasPermissionToTeam(session model.Session, teamID string, permission *model.Permission) bool {
41	if teamID == "" {
42		return false
43	}
44	if session.IsUnrestricted() {
45		return true
46	}
47
48	teamMember := session.GetTeamByTeamId(teamID)
49	if teamMember != nil {
50		if a.RolesGrantPermission(teamMember.GetRoles(), permission.Id) {
51			return true
52		}
53	}
54
55	return a.RolesGrantPermission(session.GetUserRoles(), permission.Id)
56}
57
58func (a *App) SessionHasPermissionToChannel(session model.Session, channelID string, permission *model.Permission) bool {
59	if channelID == "" {
60		return false
61	}
62
63	ids, err := a.Srv().Store.Channel().GetAllChannelMembersForUser(session.UserId, true, true)
64
65	var channelRoles []string
66	if err == nil {
67		if roles, ok := ids[channelID]; ok {
68			channelRoles = strings.Fields(roles)
69			if a.RolesGrantPermission(channelRoles, permission.Id) {
70				return true
71			}
72		}
73	}
74
75	channel, appErr := a.GetChannel(channelID)
76	if appErr != nil && appErr.StatusCode == http.StatusNotFound {
77		return false
78	}
79
80	if session.IsUnrestricted() {
81		return true
82	}
83
84	if appErr == nil && channel.TeamId != "" {
85		return a.SessionHasPermissionToTeam(session, channel.TeamId, permission)
86	}
87
88	return a.SessionHasPermissionTo(session, permission)
89}
90
91func (a *App) SessionHasPermissionToChannelByPost(session model.Session, postID string, permission *model.Permission) bool {
92	if channelMember, err := a.Srv().Store.Channel().GetMemberForPost(postID, session.UserId); err == nil {
93
94		if a.RolesGrantPermission(channelMember.GetRoles(), permission.Id) {
95			return true
96		}
97	}
98
99	if channel, err := a.Srv().Store.Channel().GetForPost(postID); err == nil {
100		if channel.TeamId != "" {
101			return a.SessionHasPermissionToTeam(session, channel.TeamId, permission)
102		}
103	}
104
105	return a.SessionHasPermissionTo(session, permission)
106}
107
108func (a *App) SessionHasPermissionToCategory(session model.Session, userID, teamID, categoryId string) bool {
109	if a.SessionHasPermissionTo(session, model.PermissionEditOtherUsers) {
110		return true
111	}
112	category, err := a.GetSidebarCategory(categoryId)
113	return err == nil && category != nil && category.UserId == session.UserId && category.UserId == userID && category.TeamId == teamID
114}
115
116func (a *App) SessionHasPermissionToUser(session model.Session, userID string) bool {
117	if userID == "" {
118		return false
119	}
120	if session.IsUnrestricted() {
121		return true
122	}
123
124	if session.UserId == userID {
125		return true
126	}
127
128	if a.SessionHasPermissionTo(session, model.PermissionEditOtherUsers) {
129		return true
130	}
131
132	return false
133}
134
135func (a *App) SessionHasPermissionToUserOrBot(session model.Session, userID string) bool {
136	if session.IsUnrestricted() {
137		return true
138	}
139	if a.SessionHasPermissionToUser(session, userID) {
140		return true
141	}
142
143	if err := a.SessionHasPermissionToManageBot(session, userID); err == nil {
144		return true
145	}
146
147	return false
148}
149
150func (a *App) HasPermissionTo(askingUserId string, permission *model.Permission) bool {
151	user, err := a.GetUser(askingUserId)
152	if err != nil {
153		return false
154	}
155
156	roles := user.GetRoles()
157
158	return a.RolesGrantPermission(roles, permission.Id)
159}
160
161func (a *App) HasPermissionToTeam(askingUserId string, teamID string, permission *model.Permission) bool {
162	if teamID == "" || askingUserId == "" {
163		return false
164	}
165	teamMember, _ := a.GetTeamMember(teamID, askingUserId)
166	if teamMember != nil && teamMember.DeleteAt == 0 {
167		if a.RolesGrantPermission(teamMember.GetRoles(), permission.Id) {
168			return true
169		}
170	}
171	return a.HasPermissionTo(askingUserId, permission)
172}
173
174func (a *App) HasPermissionToChannel(askingUserId string, channelID string, permission *model.Permission) bool {
175	if channelID == "" || askingUserId == "" {
176		return false
177	}
178
179	channelMember, err := a.GetChannelMember(context.Background(), channelID, askingUserId)
180	if err == nil {
181		roles := channelMember.GetRoles()
182		if a.RolesGrantPermission(roles, permission.Id) {
183			return true
184		}
185	}
186
187	var channel *model.Channel
188	channel, err = a.GetChannel(channelID)
189	if err == nil {
190		return a.HasPermissionToTeam(askingUserId, channel.TeamId, permission)
191	}
192
193	return a.HasPermissionTo(askingUserId, permission)
194}
195
196func (a *App) HasPermissionToChannelByPost(askingUserId string, postID string, permission *model.Permission) bool {
197	if channelMember, err := a.Srv().Store.Channel().GetMemberForPost(postID, askingUserId); err == nil {
198		if a.RolesGrantPermission(channelMember.GetRoles(), permission.Id) {
199			return true
200		}
201	}
202
203	if channel, err := a.Srv().Store.Channel().GetForPost(postID); err == nil {
204		return a.HasPermissionToTeam(askingUserId, channel.TeamId, permission)
205	}
206
207	return a.HasPermissionTo(askingUserId, permission)
208}
209
210func (a *App) HasPermissionToUser(askingUserId string, userID string) bool {
211	if askingUserId == userID {
212		return true
213	}
214
215	if a.HasPermissionTo(askingUserId, model.PermissionEditOtherUsers) {
216		return true
217	}
218
219	return false
220}
221
222func (a *App) RolesGrantPermission(roleNames []string, permissionId string) bool {
223	roles, err := a.GetRolesByNames(roleNames)
224	if err != nil {
225		// This should only happen if something is very broken. We can't realistically
226		// recover the situation, so deny permission and log an error.
227		mlog.Error("Failed to get roles from database with role names: "+strings.Join(roleNames, ",")+" ", mlog.Err(err))
228		return false
229	}
230
231	for _, role := range roles {
232		if role.DeleteAt != 0 {
233			continue
234		}
235
236		permissions := role.Permissions
237		for _, permission := range permissions {
238			if permission == permissionId {
239				return true
240			}
241		}
242	}
243
244	return false
245}
246
247// SessionHasPermissionToManageBot returns nil if the session has access to manage the given bot.
248// This function deviates from other authorization checks in returning an error instead of just
249// a boolean, allowing the permission failure to be exposed with more granularity.
250func (a *App) SessionHasPermissionToManageBot(session model.Session, botUserId string) *model.AppError {
251	existingBot, err := a.GetBot(botUserId, true)
252	if err != nil {
253		return err
254	}
255	if session.IsUnrestricted() {
256		return nil
257	}
258
259	if existingBot.OwnerId == session.UserId {
260		if !a.SessionHasPermissionTo(session, model.PermissionManageBots) {
261			if !a.SessionHasPermissionTo(session, model.PermissionReadBots) {
262				// If the user doesn't have permission to read bots, pretend as if
263				// the bot doesn't exist at all.
264				return model.MakeBotNotFoundError(botUserId)
265			}
266			return a.MakePermissionError(&session, []*model.Permission{model.PermissionManageBots})
267		}
268	} else {
269		if !a.SessionHasPermissionTo(session, model.PermissionManageOthersBots) {
270			if !a.SessionHasPermissionTo(session, model.PermissionReadOthersBots) {
271				// If the user doesn't have permission to read others' bots,
272				// pretend as if the bot doesn't exist at all.
273				return model.MakeBotNotFoundError(botUserId)
274			}
275			return a.MakePermissionError(&session, []*model.Permission{model.PermissionManageOthersBots})
276		}
277	}
278
279	return nil
280}
281
282func (a *App) HasPermissionToReadChannel(userID string, channel *model.Channel) bool {
283	return a.HasPermissionToChannel(userID, channel.Id, model.PermissionReadChannel) || (channel.Type == model.ChannelTypeOpen && a.HasPermissionToTeam(userID, channel.TeamId, model.PermissionReadPublicChannel))
284}
285