Files
team/server/channels/app/permissions_migrations.go
Felipe MartinandGitHub d7f9e52f82 MM-68830: Preserve unknown permissions during migrations on downgrade (#36888)
* MM-68830: Preserve unknown permissions during migrations on downgrade

A server that was upgraded to a newer release (which introduced new
permissions and wrote them into roles) and then downgraded fails fatally
at startup: the permissions migration re-saves every role, and
Role.Save() rejects any permission the older binary does not recognize,
making the downgrade unrecoverable.

Add RoleStore.SavePreservingUnknownPermissions, used only by
doPermissionsMigration, which tolerates and preserves permissions this
build does not recognize (logging a warning) instead of rejecting the
role. The regular Save() — and therefore the role API path — stays
strict, so unknown permissions cannot be introduced through user input.

Unrecognized permissions are kept on disk so they are not lost on a
later re-upgrade.

* MM-68830: assert save forwarding in role cache tests

Address review feedback: assert the underlying store's Save and
SavePreservingUnknownPermissions are actually invoked (the cache
invalidation defer fires regardless of forwarding), and check the
returned errors.

* MM-68830: address review feedback

- Shorten log message in validateForSave
- Rename validationRole -> roleCopy for clarity
- Trim doc comments to describe behavior only
- List all unknown permissions in IsValidWithoutId error
- Assert specific error type in storetest

* MM-68830: add Role.Clone and use it in validateForSave

* MM-68830: add tests for Role.Clone

* MM-68830: fix scheme id deep copy assertion in Role.Clone test
2026-06-09 11:18:19 +02:00

1430 lines
59 KiB
Go

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package app
import (
"errors"
"net/http"
"strings"
"github.com/mattermost/mattermost/server/public/model"
"github.com/mattermost/mattermost/server/public/shared/mlog"
"github.com/mattermost/mattermost/server/v8/channels/store"
"github.com/mattermost/mattermost/server/v8/channels/store/sqlstore"
)
type permissionTransformation struct {
On func(*model.Role, map[string]map[string]bool) bool
Add []string
Remove []string
}
type permissionsMap []permissionTransformation
const (
PermissionManageSystem = "manage_system"
PermissionManageTeam = "manage_team"
PermissionManageEmojis = "manage_emojis"
PermissionManageOthersEmojis = "manage_others_emojis"
PermissionCreateEmojis = "create_emojis"
PermissionDeleteEmojis = "delete_emojis"
PermissionDeleteOthersEmojis = "delete_others_emojis"
PermissionManageWebhooks = "manage_webhooks"
PermissionManageOthersWebhooks = "manage_others_webhooks"
PermissionManageIncomingWebhooks = "manage_incoming_webhooks"
PermissionManageOwnIncomingWebhooks = "manage_own_incoming_webhooks"
PermissionManageOthersIncomingWebhooks = "manage_others_incoming_webhooks"
PermissionManageOutgoingWebhooks = "manage_outgoing_webhooks"
PermissionManageOwnOutgoingWebhooks = "manage_own_outgoing_webhooks"
PermissionManageOthersOutgoingWebhooks = "manage_others_outgoing_webhooks"
PermissionBypassIncomingWebhookChannelLock = "bypass_incoming_webhook_channel_lock"
PermissionListPublicTeams = "list_public_teams"
PermissionListPrivateTeams = "list_private_teams"
PermissionJoinPublicTeams = "join_public_teams"
PermissionJoinPrivateTeams = "join_private_teams"
PermissionPermanentDeleteUser = "permanent_delete_user"
PermissionCreateBot = "create_bot"
PermissionReadBots = "read_bots"
PermissionReadOthersBots = "read_others_bots"
PermissionManageBots = "manage_bots"
PermissionManageOthersBots = "manage_others_bots"
PermissionManageSlashCommands = "manage_slash_commands"
PermissionManageOwnSlashCommands = "manage_own_slash_commands"
PermissionDeletePublicChannel = "delete_public_channel"
PermissionDeletePrivateChannel = "delete_private_channel"
PermissionManagePublicChannelProperties = "manage_public_channel_properties"
PermissionManagePrivateChannelProperties = "manage_private_channel_properties"
PermissionManagePublicChannelAutoTranslation = "manage_public_channel_auto_translation"
PermissionManagePrivateChannelAutoTranslation = "manage_private_channel_auto_translation"
PermissionConvertPublicChannelToPrivate = "convert_public_channel_to_private"
PermissionConvertPrivateChannelToPublic = "convert_private_channel_to_public"
PermissionViewMembers = "view_members"
PermissionInviteUser = "invite_user"
PermissionInviteGuest = "invite_guest"
PermissionPromoteGuest = "promote_guest"
PermissionDemoteToGuest = "demote_to_guest"
PermissionUseChannelMentions = "use_channel_mentions"
PermissionCreatePost = "create_post"
PermissionCreatePost_PUBLIC = "create_post_public"
PermissionUseGroupMentions = "use_group_mentions"
PermissionAddReaction = "add_reaction"
PermissionRemoveReaction = "remove_reaction"
PermissionManagePublicChannelMembers = "manage_public_channel_members"
PermissionManagePrivateChannelMembers = "manage_private_channel_members"
PermissionReadJobs = "read_jobs"
PermissionManageJobs = "manage_jobs"
PermissionReadOtherUsersTeams = "read_other_users_teams"
PermissionEditOtherUsers = "edit_other_users"
PermissionReadPublicChannelGroups = "read_public_channel_groups"
PermissionReadPrivateChannelGroups = "read_private_channel_groups"
PermissionEditBrand = "edit_brand"
PermissionManageSharedChannels = "manage_shared_channels"
PermissionManageSecureConnections = "manage_secure_connections"
PermissionManageOAuth = "manage_oauth"
PermissionManageRemoteClusters = "manage_remote_clusters" // deprecated; use `manage_secure_connections`
)
// Deprecated: This function should only be used if a case arises where team and/or channel scheme roles do not need to be migrated.
// Otherwise, use isRole.
func isExactRole(roleName string) func(*model.Role, map[string]map[string]bool) bool {
return func(role *model.Role, permissionsMap map[string]map[string]bool) bool {
return role.Name == roleName
}
}
// isRole returns true if roleName matches a role's name field or if the team
// or channel scheme role matches a "common name". A common name is one of the following role
// that is common among the system scheme and the team and/or channel schemes:
//
// TeamAdmin,
// TeamUser,
// TeamGuest,
// ChannelAdmin,
// ChannelUser,
// ChannelGuest,
// PlaybookAdmin,
// PlaybookMember,
// RunAdmin,
// RunMember
func isRole(roleName string) func(*model.Role, map[string]map[string]bool) bool {
return func(role *model.Role, permissionsMap map[string]map[string]bool) bool {
if role.Name == roleName {
return true
}
return isSchemeRoleAssociatedToCommonName(roleName, role)
}
}
// Deprecated: use isNotRole instead.
func isNotExactRole(roleName string) func(*model.Role, map[string]map[string]bool) bool {
return func(role *model.Role, permissionsMap map[string]map[string]bool) bool {
return role.Name != roleName
}
}
func isNotRole(roleName string) func(*model.Role, map[string]map[string]bool) bool {
return func(role *model.Role, permissionsMap map[string]map[string]bool) bool {
return role.Name != roleName && !isSchemeRoleAssociatedToCommonName(roleName, role)
}
}
func isSchemeRoleAssociatedToCommonName(roleName string, role *model.Role) bool {
roleIDToSchemeRoleDisplayName := map[string]string{
model.TeamAdminRoleId: sqlstore.SchemeRoleDisplayNameTeamAdmin,
model.TeamUserRoleId: sqlstore.SchemeRoleDisplayNameTeamUser,
model.TeamGuestRoleId: sqlstore.SchemeRoleDisplayNameTeamGuest,
model.ChannelAdminRoleId: sqlstore.SchemeRoleDisplayNameChannelAdmin,
model.ChannelUserRoleId: sqlstore.SchemeRoleDisplayNameChannelUser,
model.ChannelGuestRoleId: sqlstore.SchemeRoleDisplayNameChannelGuest,
model.PlaybookAdminRoleId: sqlstore.SchemeRoleDisplayNamePlaybookAdmin,
model.PlaybookMemberRoleId: sqlstore.SchemeRoleDisplayNamePlaybookMember,
model.RunAdminRoleId: sqlstore.SchemeRoleDisplayNameRunAdmin,
model.RunMemberRoleId: sqlstore.SchemeRoleDisplayNameRunMember,
}
displayName, ok := roleIDToSchemeRoleDisplayName[roleName]
if !ok {
return false
}
return strings.HasPrefix(role.DisplayName, displayName)
}
func isNotSchemeRole(roleName string) func(*model.Role, map[string]map[string]bool) bool {
return func(role *model.Role, permissionsMap map[string]map[string]bool) bool {
return !strings.Contains(role.DisplayName, roleName)
}
}
func permissionExists(permission string) func(*model.Role, map[string]map[string]bool) bool {
return func(role *model.Role, permissionsMap map[string]map[string]bool) bool {
val, ok := permissionsMap[role.Name][permission]
return ok && val
}
}
func permissionNotExists(permission string) func(*model.Role, map[string]map[string]bool) bool {
return func(role *model.Role, permissionsMap map[string]map[string]bool) bool {
val, ok := permissionsMap[role.Name][permission]
return !(ok && val)
}
}
func onOtherRole(otherRole string, function func(*model.Role, map[string]map[string]bool) bool) func(*model.Role, map[string]map[string]bool) bool {
return func(role *model.Role, permissionsMap map[string]map[string]bool) bool {
return function(&model.Role{Name: otherRole}, permissionsMap)
}
}
func permissionOr(funcs ...func(*model.Role, map[string]map[string]bool) bool) func(*model.Role, map[string]map[string]bool) bool {
return func(role *model.Role, permissionsMap map[string]map[string]bool) bool {
for _, f := range funcs {
if f(role, permissionsMap) {
return true
}
}
return false
}
}
func permissionAnd(funcs ...func(*model.Role, map[string]map[string]bool) bool) func(*model.Role, map[string]map[string]bool) bool {
return func(role *model.Role, permissionsMap map[string]map[string]bool) bool {
for _, f := range funcs {
if !f(role, permissionsMap) {
return false
}
}
return true
}
}
func applyPermissionsMap(role *model.Role, roleMap map[string]map[string]bool, migrationMap permissionsMap) []string {
var result []string
roleName := role.Name
for _, transformation := range migrationMap {
if transformation.On(role, roleMap) {
for _, permission := range transformation.Add {
roleMap[roleName][permission] = true
}
for _, permission := range transformation.Remove {
roleMap[roleName][permission] = false
}
}
}
for key, active := range roleMap[roleName] {
if active {
result = append(result, key)
}
}
return result
}
func (s *Server) doPermissionsMigration(key string, migrationMap permissionsMap, roles []*model.Role) *model.AppError {
if _, err := s.Store().System().GetByName(key); err == nil {
return nil
}
roleMap := make(map[string]map[string]bool)
for _, role := range roles {
roleMap[role.Name] = make(map[string]bool)
for _, permission := range role.Permissions {
roleMap[role.Name][permission] = true
}
}
for _, role := range roles {
role.Permissions = applyPermissionsMap(role, roleMap, migrationMap)
// Use SavePreservingUnknownPermissions so a server that was downgraded from a
// newer release (which wrote permissions this binary doesn't recognize) does
// not fail fatally here. Unknown permissions are logged and preserved (MM-68830).
if _, err := s.Store().Role().SavePreservingUnknownPermissions(role); err != nil {
var invErr *store.ErrInvalidInput
switch {
case errors.As(err, &invErr):
return model.NewAppError("doPermissionsMigration", "app.role.save.invalid_role.app_error", nil, "", http.StatusBadRequest).Wrap(err)
default:
return model.NewAppError("doPermissionsMigration", "app.role.save.insert.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
}
}
}
if err := s.Store().System().SaveOrUpdate(&model.System{Name: key, Value: "true"}); err != nil {
return model.NewAppError("doPermissionsMigration", "app.system.save.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
}
return nil
}
func (a *App) getEmojisPermissionsSplitMigration() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: permissionExists(PermissionManageEmojis),
Add: []string{PermissionCreateEmojis, PermissionDeleteEmojis},
Remove: []string{PermissionManageEmojis},
},
permissionTransformation{
On: permissionExists(PermissionManageOthersEmojis),
Add: []string{PermissionDeleteOthersEmojis},
Remove: []string{PermissionManageOthersEmojis},
},
}, nil
}
func (a *App) getWebhooksPermissionsSplitMigration() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: permissionExists(PermissionManageWebhooks),
Add: []string{PermissionManageIncomingWebhooks, PermissionManageOutgoingWebhooks},
Remove: []string{PermissionManageWebhooks},
},
permissionTransformation{
On: permissionExists(PermissionManageOthersWebhooks),
Add: []string{PermissionManageOthersIncomingWebhooks, PermissionManageOthersOutgoingWebhooks},
Remove: []string{PermissionManageOthersWebhooks},
},
}, nil
}
func (a *App) getIntegrationsOwnPermissionsMigration() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: permissionExists(PermissionManageIncomingWebhooks),
Add: []string{PermissionManageOwnIncomingWebhooks, PermissionBypassIncomingWebhookChannelLock},
Remove: []string{PermissionManageIncomingWebhooks},
},
permissionTransformation{
On: permissionExists(PermissionManageOutgoingWebhooks),
Add: []string{PermissionManageOwnOutgoingWebhooks},
Remove: []string{PermissionManageOutgoingWebhooks},
},
permissionTransformation{
On: permissionExists(PermissionManageSlashCommands),
Add: []string{PermissionManageOwnSlashCommands},
Remove: []string{PermissionManageSlashCommands},
},
// Ensure system admin has the new "manage others" permissions
permissionTransformation{
On: isExactRole(model.SystemAdminRoleId),
Add: []string{model.PermissionManageOthersIncomingWebhooks.Id, model.PermissionManageOthersOutgoingWebhooks.Id, model.PermissionManageOthersSlashCommands.Id},
},
// Ensure team admin (including scheme team admins) have the new "manage others" permissions
permissionTransformation{
On: isRole(model.TeamAdminRoleId),
Add: []string{model.PermissionManageOthersIncomingWebhooks.Id, model.PermissionManageOthersOutgoingWebhooks.Id, model.PermissionManageOthersSlashCommands.Id},
},
}, nil
}
func (a *App) getListJoinPublicPrivateTeamsPermissionsMigration() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: isExactRole(model.SystemAdminRoleId),
Add: []string{PermissionListPrivateTeams, PermissionJoinPrivateTeams},
Remove: []string{},
},
permissionTransformation{
On: isExactRole(model.SystemUserRoleId),
Add: []string{PermissionListPublicTeams, PermissionJoinPublicTeams},
Remove: []string{},
},
}, nil
}
func (a *App) removePermanentDeleteUserMigration() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: permissionExists(PermissionPermanentDeleteUser),
Remove: []string{PermissionPermanentDeleteUser},
},
}, nil
}
func (a *App) getAddBotPermissionsMigration() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: isExactRole(model.SystemAdminRoleId),
Add: []string{PermissionCreateBot, PermissionReadBots, PermissionReadOthersBots, PermissionManageBots, PermissionManageOthersBots},
Remove: []string{},
},
}, nil
}
func (a *App) applyChannelManageDeleteToChannelUser() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: permissionAnd(isExactRole(model.ChannelUserRoleId), onOtherRole(model.TeamUserRoleId, permissionExists(PermissionManagePrivateChannelProperties))),
Add: []string{PermissionManagePrivateChannelProperties},
},
permissionTransformation{
On: permissionAnd(isExactRole(model.ChannelUserRoleId), onOtherRole(model.TeamUserRoleId, permissionExists(PermissionDeletePrivateChannel))),
Add: []string{PermissionDeletePrivateChannel},
},
permissionTransformation{
On: permissionAnd(isExactRole(model.ChannelUserRoleId), onOtherRole(model.TeamUserRoleId, permissionExists(PermissionManagePublicChannelProperties))),
Add: []string{PermissionManagePublicChannelProperties},
},
permissionTransformation{
On: permissionAnd(isExactRole(model.ChannelUserRoleId), onOtherRole(model.TeamUserRoleId, permissionExists(PermissionDeletePublicChannel))),
Add: []string{PermissionDeletePublicChannel},
},
}, nil
}
func (a *App) removeChannelManageDeleteFromTeamUser() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: permissionAnd(isExactRole(model.TeamUserRoleId), permissionExists(PermissionManagePrivateChannelProperties)),
Remove: []string{PermissionManagePrivateChannelProperties},
},
permissionTransformation{
On: permissionAnd(isExactRole(model.TeamUserRoleId), permissionExists(PermissionDeletePrivateChannel)),
Remove: []string{model.PermissionDeletePrivateChannel.Id},
},
permissionTransformation{
On: permissionAnd(isExactRole(model.TeamUserRoleId), permissionExists(PermissionManagePublicChannelProperties)),
Remove: []string{PermissionManagePublicChannelProperties},
},
permissionTransformation{
On: permissionAnd(isExactRole(model.TeamUserRoleId), permissionExists(PermissionDeletePublicChannel)),
Remove: []string{PermissionDeletePublicChannel},
},
}, nil
}
func (a *App) getViewMembersPermissionMigration() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: isExactRole(model.SystemUserRoleId),
Add: []string{PermissionViewMembers},
},
permissionTransformation{
On: isExactRole(model.SystemAdminRoleId),
Add: []string{PermissionViewMembers},
},
}, nil
}
func (a *App) getAddManageGuestsPermissionsMigration() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: isExactRole(model.SystemAdminRoleId),
Add: []string{PermissionPromoteGuest, PermissionDemoteToGuest, PermissionInviteGuest},
},
}, nil
}
func (a *App) channelModerationPermissionsMigration() (permissionsMap, error) {
transformations := permissionsMap{}
var allTeamSchemes []*model.Scheme
next := a.SchemesIterator(model.SchemeScopeTeam, 100)
var schemeBatch []*model.Scheme
for schemeBatch = next(); len(schemeBatch) > 0; schemeBatch = next() {
allTeamSchemes = append(allTeamSchemes, schemeBatch...)
}
moderatedPermissionsMinusCreatePost := []string{
PermissionAddReaction,
PermissionRemoveReaction,
PermissionManagePublicChannelMembers,
PermissionManagePrivateChannelMembers,
PermissionUseChannelMentions,
}
teamAndChannelAdminConditionalTransformations := func(teamAdminID, channelAdminID, channelUserID, channelGuestID string) []permissionTransformation {
transformations := []permissionTransformation{}
for _, perm := range moderatedPermissionsMinusCreatePost {
// add each moderated permission to the channel admin if channel user or guest has the permission
trans := permissionTransformation{
On: permissionAnd(
isExactRole(channelAdminID),
permissionOr(
onOtherRole(channelUserID, permissionExists(perm)),
onOtherRole(channelGuestID, permissionExists(perm)),
),
),
Add: []string{perm},
}
transformations = append(transformations, trans)
// add each moderated permission to the team admin if channel admin, user, or guest has the permission
trans = permissionTransformation{
On: permissionAnd(
isExactRole(teamAdminID),
permissionOr(
onOtherRole(channelAdminID, permissionExists(perm)),
onOtherRole(channelUserID, permissionExists(perm)),
onOtherRole(channelGuestID, permissionExists(perm)),
),
),
Add: []string{perm},
}
transformations = append(transformations, trans)
}
return transformations
}
for _, ts := range allTeamSchemes {
// ensure all team scheme channel admins have create_post because it's not exposed via the UI
trans := permissionTransformation{
On: isExactRole(ts.DefaultChannelAdminRole),
Add: []string{PermissionCreatePost},
}
transformations = append(transformations, trans)
// ensure all team scheme team admins have create_post because it's not exposed via the UI
trans = permissionTransformation{
On: isExactRole(ts.DefaultTeamAdminRole),
Add: []string{PermissionCreatePost},
}
transformations = append(transformations, trans)
// conditionally add all other moderated permissions to team and channel admins
transformations = append(transformations, teamAndChannelAdminConditionalTransformations(
ts.DefaultTeamAdminRole,
ts.DefaultChannelAdminRole,
ts.DefaultChannelUserRole,
ts.DefaultChannelGuestRole,
)...)
}
// ensure team admins have create_post
transformations = append(transformations, permissionTransformation{
On: isExactRole(model.TeamAdminRoleId),
Add: []string{PermissionCreatePost},
})
// ensure channel admins have create_post
transformations = append(transformations, permissionTransformation{
On: isExactRole(model.ChannelAdminRoleId),
Add: []string{PermissionCreatePost},
})
// conditionally add all other moderated permissions to team and channel admins
transformations = append(transformations, teamAndChannelAdminConditionalTransformations(
model.TeamAdminRoleId,
model.ChannelAdminRoleId,
model.ChannelUserRoleId,
model.ChannelGuestRoleId,
)...)
// ensure system admin has all the moderated permissions
transformations = append(transformations, permissionTransformation{
On: isExactRole(model.SystemAdminRoleId),
Add: append(moderatedPermissionsMinusCreatePost, PermissionCreatePost),
})
// add the new use_channel_mentions permission to everyone who has create_post
transformations = append(transformations, permissionTransformation{
On: permissionOr(permissionExists(PermissionCreatePost), permissionExists(PermissionCreatePost_PUBLIC)),
Add: []string{PermissionUseChannelMentions},
})
return transformations, nil
}
func (a *App) getAddUseGroupMentionsPermissionMigration() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: permissionAnd(
isNotExactRole(model.ChannelGuestRoleId),
isNotSchemeRole(sqlstore.SchemeRoleDisplayNameChannelGuest),
permissionOr(permissionExists(PermissionCreatePost), permissionExists(PermissionCreatePost_PUBLIC)),
),
Add: []string{PermissionUseGroupMentions},
},
}, nil
}
func (a *App) getAddSystemConsolePermissionsMigration() (permissionsMap, error) {
permissionsToAdd := []string{}
for _, permission := range append(model.SysconsoleReadPermissions, model.SysconsoleWritePermissions...) {
permissionsToAdd = append(permissionsToAdd, permission.Id)
}
return permissionsMap{
// add the new permissions to system admin
permissionTransformation{
On: isExactRole(model.SystemAdminRoleId),
Add: permissionsToAdd,
},
// add read_jobs to all roles with manage_jobs
permissionTransformation{
On: permissionExists(PermissionManageJobs),
Add: []string{PermissionReadJobs},
},
// add read_other_users_teams to all roles with edit_other_users
permissionTransformation{
On: permissionExists(PermissionEditOtherUsers),
Add: []string{PermissionReadOtherUsersTeams},
},
// add read_public_channel_groups to all roles with manage_public_channel_members
permissionTransformation{
On: permissionExists(PermissionManagePublicChannelMembers),
Add: []string{PermissionReadPublicChannelGroups},
},
// add read_private_channel_groups to all roles with manage_private_channel_members
permissionTransformation{
On: permissionExists(PermissionManagePrivateChannelMembers),
Add: []string{PermissionReadPrivateChannelGroups},
},
// add edit_brand to all roles with manage_system
permissionTransformation{
On: permissionExists(PermissionManageSystem),
Add: []string{PermissionEditBrand},
},
}, nil
}
func (a *App) getAddConvertChannelPermissionsMigration() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: permissionExists(PermissionManageTeam),
Add: []string{PermissionConvertPublicChannelToPrivate, PermissionConvertPrivateChannelToPublic},
},
}, nil
}
func (a *App) getSystemRolesPermissionsMigration() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: isExactRole(model.SystemAdminRoleId),
Add: []string{model.PermissionSysconsoleReadUserManagementSystemRoles.Id, model.PermissionSysconsoleWriteUserManagementSystemRoles.Id},
},
}, nil
}
func (a *App) getAddManageSharedChannelsPermissionsMigration() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: isExactRole(model.SystemAdminRoleId),
Add: []string{PermissionManageSharedChannels},
},
}, nil
}
func (a *App) getBillingPermissionsMigration() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: isExactRole(model.SystemAdminRoleId),
Add: []string{model.PermissionSysconsoleReadBilling.Id, model.PermissionSysconsoleWriteBilling.Id},
},
}, nil
}
func (a *App) getAddManageSecureConnectionsPermissionsMigration() (permissionsMap, error) {
return permissionsMap{
// add the new permission to system admin
permissionTransformation{
On: isExactRole(model.SystemAdminRoleId),
Add: []string{PermissionManageSecureConnections},
},
// remove the deprecated permission from system admin
permissionTransformation{
On: isExactRole(model.SystemAdminRoleId),
Remove: []string{PermissionManageRemoteClusters},
},
}, nil
}
func (a *App) getAddDownloadComplianceExportResult() (permissionsMap, error) {
return permissionsMap{
// add the new permissions to system admin
permissionTransformation{
On: isExactRole(model.SystemAdminRoleId),
Add: []string{model.PermissionDownloadComplianceExportResult.Id},
},
// add Download Compliance Export Result and Read Jobs to all roles with sysconsole_read_compliance
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleReadCompliance.Id),
Add: []string{model.PermissionDownloadComplianceExportResult.Id, model.PermissionReadDataRetentionJob.Id},
},
// add manage_jobs to all roles with sysconsole_write_compliance
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleWriteCompliance.Id),
Add: []string{model.PermissionManageJobs.Id},
},
}, nil
}
func (a *App) getAddExperimentalSubsectionPermissions() (permissionsMap, error) {
return permissionsMap{
// Give the new subsection READ permissions to any user with READ_EXPERIMENTAL
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleReadExperimental.Id),
Add: []string{model.PermissionSysconsoleReadExperimentalFeatures.Id, model.PermissionSysconsoleReadExperimentalFeatureFlags.Id},
},
// Give the new subsection WRITE permissions to any user with WRITE_EXPERIMENTAL
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleWriteExperimental.Id),
Add: []string{model.PermissionSysconsoleWriteExperimentalFeatures.Id, model.PermissionSysconsoleWriteExperimentalFeatureFlags.Id},
},
}, nil
}
func (a *App) getAddIntegrationsSubsectionPermissions() (permissionsMap, error) {
permissionsIntegrationsRead := []string{model.PermissionSysconsoleReadIntegrationsIntegrationManagement.Id, model.PermissionSysconsoleReadIntegrationsBotAccounts.Id, model.PermissionSysconsoleReadIntegrationsGif.Id, model.PermissionSysconsoleReadIntegrationsCors.Id}
permissionsIntegrationsWrite := []string{model.PermissionSysconsoleWriteIntegrationsIntegrationManagement.Id, model.PermissionSysconsoleWriteIntegrationsBotAccounts.Id, model.PermissionSysconsoleWriteIntegrationsGif.Id, model.PermissionSysconsoleWriteIntegrationsCors.Id}
return permissionsMap{
// Give the new subsection READ permissions to any user with READ_INTEGRATIONS
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleReadIntegrations.Id),
Add: permissionsIntegrationsRead,
},
// Give the new subsection WRITE permissions to any user with WRITE_EXPERIMENTAL
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleWriteIntegrations.Id),
Add: permissionsIntegrationsWrite,
},
}, nil
}
func (a *App) getAddSiteSubsectionPermissions() (permissionsMap, error) {
permissionsSiteRead := []string{model.PermissionSysconsoleReadSiteCustomization.Id, model.PermissionSysconsoleReadSiteLocalization.Id, model.PermissionSysconsoleReadSiteUsersAndTeams.Id, model.PermissionSysconsoleReadSiteNotifications.Id, model.PermissionSysconsoleReadSiteAnnouncementBanner.Id, model.PermissionSysconsoleReadSiteEmoji.Id, model.PermissionSysconsoleReadSitePosts.Id, model.PermissionSysconsoleReadSiteFileSharingAndDownloads.Id, model.PermissionSysconsoleReadSitePublicLinks.Id, model.PermissionSysconsoleReadSiteNotices.Id}
permissionsSiteWrite := []string{model.PermissionSysconsoleWriteSiteCustomization.Id, model.PermissionSysconsoleWriteSiteLocalization.Id, model.PermissionSysconsoleWriteSiteUsersAndTeams.Id, model.PermissionSysconsoleWriteSiteNotifications.Id, model.PermissionSysconsoleWriteSiteAnnouncementBanner.Id, model.PermissionSysconsoleWriteSiteEmoji.Id, model.PermissionSysconsoleWriteSitePosts.Id, model.PermissionSysconsoleWriteSiteFileSharingAndDownloads.Id, model.PermissionSysconsoleWriteSitePublicLinks.Id, model.PermissionSysconsoleWriteSiteNotices.Id}
return permissionsMap{
// Give the new subsection READ permissions to any user with READ_SITE
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleReadSite.Id),
Add: permissionsSiteRead,
},
// Give the new subsection WRITE permissions to any user with WRITE_SITE
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleWriteSite.Id),
Add: permissionsSiteWrite,
},
// Give the ancillary permissions EDIT_BRAND to anyone with WRITE_SITE_CUSTOMIZATION
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleWriteSiteCustomization.Id),
Add: []string{model.PermissionEditBrand.Id},
},
}, nil
}
func (a *App) getAddComplianceSubsectionPermissions() (permissionsMap, error) {
permissionsComplianceRead := []string{model.PermissionSysconsoleReadComplianceDataRetentionPolicy.Id, model.PermissionSysconsoleReadComplianceComplianceExport.Id, model.PermissionSysconsoleReadComplianceComplianceMonitoring.Id, model.PermissionSysconsoleReadComplianceCustomTermsOfService.Id}
permissionsComplianceWrite := []string{model.PermissionSysconsoleWriteComplianceDataRetentionPolicy.Id, model.PermissionSysconsoleWriteComplianceComplianceExport.Id, model.PermissionSysconsoleWriteComplianceComplianceMonitoring.Id, model.PermissionSysconsoleWriteComplianceCustomTermsOfService.Id}
return permissionsMap{
// Give the new subsection READ permissions to any user with READ_COMPLIANCE
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleReadCompliance.Id),
Add: permissionsComplianceRead,
},
// Give the new subsection WRITE permissions to any user with WRITE_COMPLIANCE
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleWriteCompliance.Id),
Add: permissionsComplianceWrite,
},
// Ancillary permissions
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleWriteComplianceDataRetentionPolicy.Id),
Add: []string{model.PermissionCreateDataRetentionJob.Id},
},
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleReadComplianceDataRetentionPolicy.Id),
Add: []string{model.PermissionReadDataRetentionJob.Id},
},
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleWriteComplianceComplianceExport.Id),
Add: []string{model.PermissionCreateComplianceExportJob.Id, model.PermissionDownloadComplianceExportResult.Id},
},
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleReadComplianceComplianceExport.Id),
Add: []string{model.PermissionReadComplianceExportJob.Id, model.PermissionDownloadComplianceExportResult.Id},
},
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleReadComplianceCustomTermsOfService.Id),
Add: []string{model.PermissionReadAudits.Id},
},
}, nil
}
func (a *App) getAddEnvironmentSubsectionPermissions() (permissionsMap, error) {
permissionsEnvironmentRead := []string{
model.PermissionSysconsoleReadEnvironmentWebServer.Id,
model.PermissionSysconsoleReadEnvironmentDatabase.Id,
model.PermissionSysconsoleReadEnvironmentElasticsearch.Id,
model.PermissionSysconsoleReadEnvironmentFileStorage.Id,
model.PermissionSysconsoleReadEnvironmentImageProxy.Id,
model.PermissionSysconsoleReadEnvironmentSMTP.Id,
model.PermissionSysconsoleReadEnvironmentPushNotificationServer.Id,
model.PermissionSysconsoleReadEnvironmentHighAvailability.Id,
model.PermissionSysconsoleReadEnvironmentRateLimiting.Id,
model.PermissionSysconsoleReadEnvironmentLogging.Id,
model.PermissionSysconsoleReadEnvironmentSessionLengths.Id,
model.PermissionSysconsoleReadEnvironmentPerformanceMonitoring.Id,
model.PermissionSysconsoleReadEnvironmentDeveloper.Id,
}
permissionsEnvironmentWrite := []string{
model.PermissionSysconsoleWriteEnvironmentWebServer.Id,
model.PermissionSysconsoleWriteEnvironmentDatabase.Id,
model.PermissionSysconsoleWriteEnvironmentElasticsearch.Id,
model.PermissionSysconsoleWriteEnvironmentFileStorage.Id,
model.PermissionSysconsoleWriteEnvironmentImageProxy.Id,
model.PermissionSysconsoleWriteEnvironmentSMTP.Id,
model.PermissionSysconsoleWriteEnvironmentPushNotificationServer.Id,
model.PermissionSysconsoleWriteEnvironmentHighAvailability.Id,
model.PermissionSysconsoleWriteEnvironmentRateLimiting.Id,
model.PermissionSysconsoleWriteEnvironmentLogging.Id,
model.PermissionSysconsoleWriteEnvironmentSessionLengths.Id,
model.PermissionSysconsoleWriteEnvironmentPerformanceMonitoring.Id,
model.PermissionSysconsoleWriteEnvironmentDeveloper.Id,
}
permissionsElasticsearchRead := []string{
model.PermissionReadElasticsearchPostIndexingJob.Id,
model.PermissionReadElasticsearchPostAggregationJob.Id,
}
permissionsElasticsearchWrite := []string{
model.PermissionTestElasticsearch.Id,
model.PermissionCreateElasticsearchPostIndexingJob.Id,
model.PermissionCreateElasticsearchPostAggregationJob.Id,
model.PermissionPurgeElasticsearchIndexes.Id,
}
permissionsWebServerWrite := []string{
model.PermissionTestSiteURL.Id,
model.PermissionReloadConfig.Id,
model.PermissionInvalidateCaches.Id,
}
return permissionsMap{
// Give the new subsection READ permissions to any user with READ_ENVIRONMENT
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleReadEnvironment.Id),
Add: permissionsEnvironmentRead,
},
// Give the new subsection WRITE permissions to any user with WRITE_ENVIRONMENT
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleWriteEnvironment.Id),
Add: permissionsEnvironmentWrite,
},
// Give these ancillary permissions to anyone with READ_ENVIRONMENT_ELASTICSEARCH
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleReadEnvironmentElasticsearch.Id),
Add: permissionsElasticsearchRead,
},
// Give these ancillary permissions to anyone with WRITE_ENVIRONMENT_WEB_SERVER
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleWriteEnvironmentWebServer.Id),
Add: permissionsWebServerWrite,
},
// Give these ancillary permissions to anyone with WRITE_ENVIRONMENT_DATABASE
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleWriteEnvironmentDatabase.Id),
Add: []string{model.PermissionRecycleDatabaseConnections.Id},
},
// Give these ancillary permissions to anyone with WRITE_ENVIRONMENT_ELASTICSEARCH
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleWriteEnvironmentElasticsearch.Id),
Add: permissionsElasticsearchWrite,
},
// Give these ancillary permissions to anyone with WRITE_ENVIRONMENT_FILE_STORAGE
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleWriteEnvironmentFileStorage.Id),
Add: []string{model.PermissionTestS3.Id},
},
}, nil
}
func (a *App) getAddAboutSubsectionPermissions() (permissionsMap, error) {
permissionsAboutRead := []string{model.PermissionSysconsoleReadAboutEditionAndLicense.Id}
permissionsAboutWrite := []string{model.PermissionSysconsoleWriteAboutEditionAndLicense.Id}
return permissionsMap{
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleReadAbout.Id),
Add: permissionsAboutRead,
},
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleWriteAbout.Id),
Add: permissionsAboutWrite,
},
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleReadAboutEditionAndLicense.Id),
Add: []string{model.PermissionReadLicenseInformation.Id},
},
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleWriteAboutEditionAndLicense.Id),
Add: []string{model.PermissionManageLicenseInformation.Id},
},
}, nil
}
func (a *App) getAddReportingSubsectionPermissions() (permissionsMap, error) {
permissionsReportingRead := []string{
model.PermissionSysconsoleReadReportingSiteStatistics.Id,
model.PermissionSysconsoleReadReportingTeamStatistics.Id,
model.PermissionSysconsoleReadReportingServerLogs.Id,
}
permissionsReportingWrite := []string{
model.PermissionSysconsoleWriteReportingSiteStatistics.Id,
model.PermissionSysconsoleWriteReportingTeamStatistics.Id,
model.PermissionSysconsoleWriteReportingServerLogs.Id,
}
return permissionsMap{
// Give the new subsection READ permissions to any user with READ_REPORTING
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleReadReporting.Id),
Add: permissionsReportingRead,
},
// Give the new subsection WRITE permissions to any user with WRITE_REPORTING
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleWriteReporting.Id),
Add: permissionsReportingWrite,
},
// Give the ancillary permissions PERMISSION_GET_ANALYTICS to anyone with PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_USERS or PERMISSION_SYSCONSOLE_READ_REPORTING_SITE_STATISTICS
permissionTransformation{
On: permissionOr(permissionExists(model.PermissionSysconsoleReadUserManagementUsers.Id), permissionExists(model.PermissionSysconsoleReadReportingSiteStatistics.Id)),
Add: []string{model.PermissionGetAnalytics.Id},
},
// Give the ancillary permissions PERMISSION_GET_LOGS to anyone with PERMISSION_SYSCONSOLE_READ_REPORTING_SERVER_LOGS
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleReadReportingServerLogs.Id),
Add: []string{model.PermissionGetLogs.Id},
},
}, nil
}
func (a *App) getAddAuthenticationSubsectionPermissions() (permissionsMap, error) {
permissionsAuthenticationRead := []string{model.PermissionSysconsoleReadAuthenticationSignup.Id, model.PermissionSysconsoleReadAuthenticationEmail.Id, model.PermissionSysconsoleReadAuthenticationPassword.Id, model.PermissionSysconsoleReadAuthenticationMfa.Id, model.PermissionSysconsoleReadAuthenticationLdap.Id, model.PermissionSysconsoleReadAuthenticationSaml.Id, model.PermissionSysconsoleReadAuthenticationOpenid.Id, model.PermissionSysconsoleReadAuthenticationGuestAccess.Id}
permissionsAuthenticationWrite := []string{model.PermissionSysconsoleWriteAuthenticationSignup.Id, model.PermissionSysconsoleWriteAuthenticationEmail.Id, model.PermissionSysconsoleWriteAuthenticationPassword.Id, model.PermissionSysconsoleWriteAuthenticationMfa.Id, model.PermissionSysconsoleWriteAuthenticationLdap.Id, model.PermissionSysconsoleWriteAuthenticationSaml.Id, model.PermissionSysconsoleWriteAuthenticationOpenid.Id, model.PermissionSysconsoleWriteAuthenticationGuestAccess.Id}
return permissionsMap{
// Give the new subsection READ permissions to any user with READ_AUTHENTICATION
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleReadAuthentication.Id),
Add: permissionsAuthenticationRead,
},
// Give the new subsection WRITE permissions to any user with WRITE_AUTHENTICATION
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleWriteAuthentication.Id),
Add: permissionsAuthenticationWrite,
},
// Give the ancillary permissions for LDAP to anyone with WRITE_AUTHENTICATION_LDAP
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleWriteAuthenticationLdap.Id),
Add: []string{model.PermissionCreateLdapSyncJob.Id, model.PermissionTestLdap.Id, model.PermissionAddLdapPublicCert.Id, model.PermissionAddLdapPrivateCert.Id, model.PermissionRemoveLdapPublicCert.Id, model.PermissionRemoveLdapPrivateCert.Id},
},
// Give the ancillary permissions PERMISSION_TEST_LDAP to anyone with READ_AUTHENTICATION_LDAP
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleReadAuthenticationLdap.Id),
Add: []string{model.PermissionReadLdapSyncJob.Id},
},
// Give the ancillary permissions PERMISSION_INVALIDATE_EMAIL_INVITE to anyone with WRITE_AUTHENTICATION_EMAIL
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleWriteAuthenticationEmail.Id),
Add: []string{model.PermissionInvalidateEmailInvite.Id},
},
// Give the ancillary permissions for SAML to anyone with WRITE_AUTHENTICATION_SAML
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleWriteAuthenticationSaml.Id),
Add: []string{model.PermissionGetSamlMetadataFromIdp.Id, model.PermissionAddSamlPublicCert.Id, model.PermissionAddSamlPrivateCert.Id, model.PermissionAddSamlIdpCert.Id, model.PermissionRemoveSamlPublicCert.Id, model.PermissionRemoveSamlPrivateCert.Id, model.PermissionRemoveSamlIdpCert.Id, model.PermissionGetSamlCertStatus.Id},
},
}, nil
}
// This migration fixes https://github.com/mattermost/mattermost-server/issues/17642 where this particular ancillary permission was forgotten during the initial migrations
func (a *App) getAddTestEmailAncillaryPermission() (permissionsMap, error) {
return permissionsMap{
// Give these ancillary permissions to anyone with WRITE_ENVIRONMENT_SMTP
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleWriteEnvironmentSMTP.Id),
Add: []string{model.PermissionTestEmail.Id},
},
}, nil
}
func (a *App) getAddCustomUserGroupsPermissions() (permissionsMap, error) {
customGroupPermissions := []string{
model.PermissionCreateCustomGroup.Id,
model.PermissionManageCustomGroupMembers.Id,
model.PermissionEditCustomGroup.Id,
model.PermissionDeleteCustomGroup.Id,
}
return permissionsMap{
permissionTransformation{
On: isExactRole(model.SystemUserRoleId),
Add: customGroupPermissions,
},
permissionTransformation{
On: isExactRole(model.SystemAdminRoleId),
Add: customGroupPermissions,
},
}, nil
}
func (a *App) getAddCustomUserGroupsPermissionRestore() (permissionsMap, error) {
customGroupPermissions := []string{
model.PermissionRestoreCustomGroup.Id,
}
return permissionsMap{
permissionTransformation{
On: isExactRole(model.SystemUserRoleId),
Add: customGroupPermissions,
},
permissionTransformation{
On: isExactRole(model.SystemAdminRoleId),
Add: customGroupPermissions,
},
permissionTransformation{
On: isExactRole(model.SystemCustomGroupAdminRoleId),
Add: customGroupPermissions,
},
}, nil
}
func (a *App) getAddPlaybooksPermissions() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: permissionOr(
permissionExists(model.PermissionCreatePublicChannel.Id),
permissionExists(model.PermissionCreatePrivateChannel.Id),
),
Add: []string{
model.PermissionPublicPlaybookCreate.Id,
model.PermissionPrivatePlaybookCreate.Id,
},
},
permissionTransformation{
On: isExactRole(model.SystemAdminRoleId),
Add: []string{
model.PermissionPublicPlaybookManageProperties.Id,
model.PermissionPublicPlaybookManageMembers.Id,
model.PermissionPublicPlaybookView.Id,
model.PermissionPublicPlaybookMakePrivate.Id,
model.PermissionPrivatePlaybookManageProperties.Id,
model.PermissionPrivatePlaybookManageMembers.Id,
model.PermissionPrivatePlaybookView.Id,
model.PermissionPrivatePlaybookMakePublic.Id,
model.PermissionRunCreate.Id,
model.PermissionRunManageProperties.Id,
model.PermissionRunManageMembers.Id,
model.PermissionRunView.Id,
},
},
}, nil
}
func (a *App) getPlaybooksPermissionsAddManageRoles() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: permissionOr(
isExactRole(model.PlaybookAdminRoleId),
isExactRole(model.TeamAdminRoleId),
isExactRole(model.SystemAdminRoleId),
),
Add: []string{
model.PermissionPublicPlaybookManageRoles.Id,
model.PermissionPrivatePlaybookManageRoles.Id,
},
},
}, nil
}
func (a *App) getProductsBoardsPermissions() (permissionsMap, error) {
return permissionsMap{
// Give the new subsection READ permissions to any user with SYSTEM_MANAGER
permissionTransformation{
On: permissionOr(isExactRole(model.SystemManagerRoleId)),
Add: []string{model.PermissionSysconsoleReadProductsBoards.Id},
},
// Give the new subsection WRITE permissions to any user with SYSTEM_ADMIN
permissionTransformation{
On: permissionOr(isExactRole(model.SystemAdminRoleId)),
Add: []string{model.PermissionSysconsoleWriteProductsBoards.Id},
},
}, nil
}
func (a *App) getAddChannelReadContentPermissions() (permissionsMap, error) {
return permissionsMap{
// Migrate all roles including custom roles that have the read_channel permission
// but exclude system console roles system_read_only_admin system_user_manager & system_manager
// as this system roles are for the admin console use only
permissionTransformation{
On: permissionAnd(
permissionAnd(
isNotRole(model.SystemUserManagerRoleId),
isNotRole(model.SystemReadOnlyAdminRoleId),
isNotRole(model.SystemManagerRoleId),
),
permissionExists(model.PermissionReadChannel.Id),
),
Add: []string{
model.PermissionReadChannelContent.Id,
},
},
}, nil
}
func (a *App) getAddIPFilterPermissionsMigration() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: permissionOr(isExactRole(model.SystemAdminRoleId)),
Add: []string{
model.PermissionSysconsoleReadIPFilters.Id,
},
},
permissionTransformation{
On: permissionOr(isExactRole(model.SystemAdminRoleId)),
Add: []string{
model.PermissionSysconsoleWriteIPFilters.Id,
},
},
}, nil
}
func (a *App) getAddOutgoingOAuthConnectionsPermissions() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: permissionOr(isExactRole(model.SystemAdminRoleId)),
Add: []string{
model.PermissionManageOutgoingOAuthConnections.Id,
},
},
}, nil
}
func (a *App) getAddChannelBookmarksPermissionsMigration() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: permissionOr(
isRole(model.ChannelUserRoleId),
isRole(model.ChannelAdminRoleId),
isRole(model.TeamAdminRoleId),
isRole(model.SystemAdminRoleId),
),
Add: []string{
model.PermissionAddBookmarkPublicChannel.Id,
model.PermissionEditBookmarkPublicChannel.Id,
model.PermissionDeleteBookmarkPublicChannel.Id,
model.PermissionOrderBookmarkPublicChannel.Id,
model.PermissionAddBookmarkPrivateChannel.Id,
model.PermissionEditBookmarkPrivateChannel.Id,
model.PermissionDeleteBookmarkPrivateChannel.Id,
model.PermissionOrderBookmarkPrivateChannel.Id,
},
},
}, nil
}
func (a *App) getAddManageJobAncillaryPermissionsMigration() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleWriteAuthenticationLdap.Id),
Add: []string{model.PermissionManageLdapSyncJob.Id},
},
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleWriteComplianceDataRetentionPolicy.Id),
Add: []string{model.PermissionManageDataRetentionJob.Id},
},
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleWriteComplianceComplianceExport.Id),
Add: []string{model.PermissionManageComplianceExportJob.Id},
},
permissionTransformation{
On: permissionExists(model.PermissionSysconsoleWriteEnvironmentElasticsearch.Id),
Add: []string{
model.PermissionManageElasticsearchPostIndexingJob.Id,
model.PermissionManageElasticsearchPostAggregationJob.Id,
},
},
}, nil
}
func (a *App) getAddUploadFilePermissionMigration() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: permissionExists(model.PermissionCreatePost.Id),
Add: []string{model.PermissionUploadFile.Id},
},
}, nil
}
func (a *App) getFixReadAuditsPermissionMigration() (permissionsMap, error) {
transformations := []permissionTransformation{}
transformations = append(transformations, permissionTransformation{
On: permissionExists(model.PermissionSysconsoleReadComplianceCustomTermsOfService.Id),
Remove: []string{model.PermissionReadAudits.Id},
})
transformations = append(transformations, permissionTransformation{
On: permissionExists(model.PermissionSysconsoleReadComplianceComplianceMonitoring.Id),
Add: []string{model.PermissionReadAudits.Id},
})
return transformations, nil
}
func (a *App) removeGetAnalyticsPermissionMigration() (permissionsMap, error) {
transformations := []permissionTransformation{}
transformations = append(transformations, permissionTransformation{
On: permissionExists(model.PermissionSysconsoleReadUserManagementUsers.Id),
Remove: []string{model.PermissionGetAnalytics.Id},
})
transformations = append(transformations, permissionTransformation{
On: permissionExists(model.PermissionSysconsoleReadReportingTeamStatistics.Id),
Add: []string{model.PermissionGetAnalytics.Id},
})
return transformations, nil
}
func (a *App) addSysConsoleMobileSecurityPermission() (permissionsMap, error) {
transformations := []permissionTransformation{}
transformations = append(transformations, permissionTransformation{
On: isExactRole(model.SystemAdminRoleId),
Add: []string{model.PermissionSysconsoleWriteEnvironmentMobileSecurity.Id},
})
transformations = append(transformations, permissionTransformation{
On: permissionOr(
isExactRole(model.SystemAdminRoleId),
isExactRole(model.SystemReadOnlyAdminRoleId),
),
Add: []string{model.PermissionSysconsoleReadEnvironmentMobileSecurity.Id},
})
return transformations, nil
}
func (a *App) getAddChannelBannerPermissionMigration() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: permissionOr(
isRole(model.ChannelAdminRoleId),
isRole(model.TeamAdminRoleId),
isRole(model.SystemAdminRoleId),
),
Add: []string{
model.PermissionManagePublicChannelBanner.Id,
model.PermissionManagePrivateChannelBanner.Id,
},
},
}, nil
}
func (a *App) getAddChannelAccessRulesPermissionMigration() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: permissionOr(
isRole(model.ChannelAdminRoleId),
isRole(model.TeamAdminRoleId),
isRole(model.SystemAdminRoleId),
),
Add: []string{
model.PermissionManageChannelAccessRules.Id,
},
},
}, nil
}
func (a *App) getAddTeamAccessRulesPermissionMigration() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: permissionOr(
isRole(model.TeamAdminRoleId),
isRole(model.SystemAdminRoleId),
),
Add: []string{
model.PermissionManageTeamAccessRules.Id,
},
},
}, nil
}
func (a *App) getAddChannelAutoTranslationPermissionMigration() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: permissionOr(
isRole(model.ChannelAdminRoleId),
isRole(model.TeamAdminRoleId),
isRole(model.SystemAdminRoleId),
),
Add: []string{
model.PermissionManagePublicChannelAutoTranslation.Id,
model.PermissionManagePrivateChannelAutoTranslation.Id,
},
},
}, nil
}
// Only sysadmins, team admins, and users with channels and groups managements have access to "convert channel to public"
func (a *App) getRestrictAcessToChannelConversionToPublic() (permissionsMap, error) {
return []permissionTransformation{
{
On: permissionAnd(
isNotRole(model.SystemAdminRoleId),
isNotRole(model.TeamAdminRoleId),
permissionOr(
permissionNotExists(model.PermissionSysconsoleWriteUserManagementChannels.Id),
permissionNotExists(model.PermissionSysconsoleWriteUserManagementGroups.Id),
),
),
Remove: []string{PermissionConvertPrivateChannelToPublic},
},
}, nil
}
func (a *App) getAddSharedChannelManagerPermissionsMigration() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: isExactRole(model.SharedChannelManagerRoleId),
Add: []string{PermissionManageSharedChannels},
},
}, nil
}
func (a *App) getRestoreManageOAuthPermissionMigration() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: isExactRole(model.SystemAdminRoleId),
Add: []string{model.PermissionManageOAuth.Id},
},
}, nil
}
func (a *App) getAddManageAgentPermissionsMigration() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: isExactRole(model.SystemAdminRoleId),
Add: []string{
model.PermissionManageOwnAgent.Id,
model.PermissionManageOthersAgent.Id,
},
},
permissionTransformation{
On: isExactRole(model.SystemUserRoleId),
Add: []string{
model.PermissionManageOwnAgent.Id,
},
},
}, nil
}
func (a *App) getAddEditFileAttachmentPermissionMigration() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: permissionExists(model.PermissionEditPost.Id),
Add: []string{model.PermissionEditFileAttachment.Id},
},
}, nil
}
func (a *App) getAddDiscoverableChannelPermissionsMigration() (permissionsMap, error) {
return permissionsMap{
permissionTransformation{
On: permissionOr(
isRole(model.ChannelAdminRoleId),
isRole(model.TeamAdminRoleId),
isRole(model.SystemAdminRoleId),
),
Add: []string{
model.PermissionManagePrivateChannelDiscoverability.Id,
model.PermissionManageChannelJoinRequests.Id,
},
},
}, nil
}
// DoPermissionsMigrations execute all the permissions migrations need by the current version.
func (a *App) DoPermissionsMigrations() error {
return a.Srv().doPermissionsMigrations()
}
func (s *Server) doPermissionsMigrations() error {
a := New(ServerConnector(s.Channels()))
PermissionsMigrations := []struct {
Key string
Migration func() (permissionsMap, error)
}{
{Key: model.MigrationKeyEmojiPermissionsSplit, Migration: a.getEmojisPermissionsSplitMigration},
{Key: model.MigrationKeyWebhookPermissionsSplit, Migration: a.getWebhooksPermissionsSplitMigration},
{Key: model.MigrationKeyIntegrationsOwnPermissions, Migration: a.getIntegrationsOwnPermissionsMigration},
{Key: model.MigrationKeyListJoinPublicPrivateTeams, Migration: a.getListJoinPublicPrivateTeamsPermissionsMigration},
{Key: model.MigrationKeyRemovePermanentDeleteUser, Migration: a.removePermanentDeleteUserMigration},
{Key: model.MigrationKeyAddBotPermissions, Migration: a.getAddBotPermissionsMigration},
{Key: model.MigrationKeyApplyChannelManageDeleteToChannelUser, Migration: a.applyChannelManageDeleteToChannelUser},
{Key: model.MigrationKeyRemoveChannelManageDeleteFromTeamUser, Migration: a.removeChannelManageDeleteFromTeamUser},
{Key: model.MigrationKeyViewMembersNewPermission, Migration: a.getViewMembersPermissionMigration},
{Key: model.MigrationKeyAddManageGuestsPermissions, Migration: a.getAddManageGuestsPermissionsMigration},
{Key: model.MigrationKeyChannelModerationsPermissions, Migration: a.channelModerationPermissionsMigration},
{Key: model.MigrationKeyAddUseGroupMentionsPermission, Migration: a.getAddUseGroupMentionsPermissionMigration},
{Key: model.MigrationKeyAddSystemConsolePermissions, Migration: a.getAddSystemConsolePermissionsMigration},
{Key: model.MigrationKeyAddConvertChannelPermissions, Migration: a.getAddConvertChannelPermissionsMigration},
{Key: model.MigrationKeyAddManageSharedChannelPermissions, Migration: a.getAddManageSharedChannelsPermissionsMigration},
{Key: model.MigrationKeyAddManageSecureConnectionsPermissions, Migration: a.getAddManageSecureConnectionsPermissionsMigration},
{Key: model.MigrationKeyAddSystemRolesPermissions, Migration: a.getSystemRolesPermissionsMigration},
{Key: model.MigrationKeyAddBillingPermissions, Migration: a.getBillingPermissionsMigration},
{Key: model.MigrationKeyAddDownloadComplianceExportResults, Migration: a.getAddDownloadComplianceExportResult},
{Key: model.MigrationKeyAddExperimentalSubsectionPermissions, Migration: a.getAddExperimentalSubsectionPermissions},
{Key: model.MigrationKeyAddAuthenticationSubsectionPermissions, Migration: a.getAddAuthenticationSubsectionPermissions},
{Key: model.MigrationKeyAddIntegrationsSubsectionPermissions, Migration: a.getAddIntegrationsSubsectionPermissions},
{Key: model.MigrationKeyAddSiteSubsectionPermissions, Migration: a.getAddSiteSubsectionPermissions},
{Key: model.MigrationKeyAddComplianceSubsectionPermissions, Migration: a.getAddComplianceSubsectionPermissions},
{Key: model.MigrationKeyAddEnvironmentSubsectionPermissions, Migration: a.getAddEnvironmentSubsectionPermissions},
{Key: model.MigrationKeyAddAboutSubsectionPermissions, Migration: a.getAddAboutSubsectionPermissions},
{Key: model.MigrationKeyAddReportingSubsectionPermissions, Migration: a.getAddReportingSubsectionPermissions},
{Key: model.MigrationKeyAddTestEmailAncillaryPermission, Migration: a.getAddTestEmailAncillaryPermission},
{Key: model.MigrationKeyAddPlaybooksPermissions, Migration: a.getAddPlaybooksPermissions},
{Key: model.MigrationKeyAddCustomUserGroupsPermissions, Migration: a.getAddCustomUserGroupsPermissions},
{Key: model.MigrationKeyAddPlayboosksManageRolesPermissions, Migration: a.getPlaybooksPermissionsAddManageRoles},
{Key: model.MigrationKeyAddProductsBoardsPermissions, Migration: a.getProductsBoardsPermissions},
{Key: model.MigrationKeyAddCustomUserGroupsPermissionRestore, Migration: a.getAddCustomUserGroupsPermissionRestore},
{Key: model.MigrationKeyAddReadChannelContentPermissions, Migration: a.getAddChannelReadContentPermissions},
{Key: model.MigrationKeyAddIPFilteringPermissions, Migration: a.getAddIPFilterPermissionsMigration},
{Key: model.MigrationKeyAddOutgoingOAuthConnectionsPermissions, Migration: a.getAddOutgoingOAuthConnectionsPermissions},
{Key: model.MigrationKeyAddChannelBookmarksPermissions, Migration: a.getAddChannelBookmarksPermissionsMigration},
{Key: model.MigrationKeyAddManageJobAncillaryPermissions, Migration: a.getAddManageJobAncillaryPermissionsMigration},
{Key: model.MigrationKeyAddUploadFilePermission, Migration: a.getAddUploadFilePermissionMigration},
{Key: model.RestrictAccessToChannelConversionToPublic, Migration: a.getRestrictAcessToChannelConversionToPublic},
{Key: model.MigrationKeyFixReadAuditsPermission, Migration: a.getFixReadAuditsPermissionMigration},
{Key: model.MigrationRemoveGetAnalyticsPermission, Migration: a.removeGetAnalyticsPermissionMigration},
{Key: model.MigrationAddSysconsoleMobileSecurityPermission, Migration: a.addSysConsoleMobileSecurityPermission},
{Key: model.MigrationKeyAddChannelBannerPermissions, Migration: a.getAddChannelBannerPermissionMigration},
{Key: model.MigrationKeyAddChannelAccessRulesPermission, Migration: a.getAddChannelAccessRulesPermissionMigration},
{Key: model.MigrationKeyAddTeamAccessRulesPermission, Migration: a.getAddTeamAccessRulesPermissionMigration},
{Key: model.MigrationKeyAddChannelAutoTranslationPermissions, Migration: a.getAddChannelAutoTranslationPermissionMigration},
{Key: model.MigrationKeyAddSharedChannelManagerPermissions, Migration: a.getAddSharedChannelManagerPermissionsMigration},
{Key: model.MigrationKeyRestoreManageOAuthPermission, Migration: a.getRestoreManageOAuthPermissionMigration},
{Key: model.MigrationKeyAddManageAgentPermissions, Migration: a.getAddManageAgentPermissionsMigration},
{Key: model.MigrationKeyAddEditFileAttachmentPermission, Migration: a.getAddEditFileAttachmentPermissionMigration},
{Key: model.MigrationKeyAddDiscoverableChannelPermissions, Migration: a.getAddDiscoverableChannelPermissionsMigration},
}
roles, err := s.Store().Role().GetAll()
if err != nil {
return err
}
for _, migration := range PermissionsMigrations {
migMap, err := migration.Migration()
if err != nil {
return err
}
if err := s.doPermissionsMigration(migration.Key, migMap, roles); err != nil {
mlog.Error("Failed to run permissions migration", mlog.String("key", migration.Key), mlog.Err(err))
return err
}
}
return nil
}