github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/app/permissions_migrations.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package app 5 6 import ( 7 "errors" 8 "net/http" 9 "strings" 10 11 "github.com/mattermost/mattermost-server/v5/model" 12 "github.com/mattermost/mattermost-server/v5/store" 13 ) 14 15 type permissionTransformation struct { 16 On func(*model.Role, map[string]map[string]bool) bool 17 Add []string 18 Remove []string 19 } 20 type permissionsMap []permissionTransformation 21 22 const ( 23 PERMISSION_MANAGE_SYSTEM = "manage_system" 24 PERMISSION_MANAGE_EMOJIS = "manage_emojis" 25 PERMISSION_MANAGE_OTHERS_EMOJIS = "manage_others_emojis" 26 PERMISSION_CREATE_EMOJIS = "create_emojis" 27 PERMISSION_DELETE_EMOJIS = "delete_emojis" 28 PERMISSION_DELETE_OTHERS_EMOJIS = "delete_others_emojis" 29 PERMISSION_MANAGE_WEBHOOKS = "manage_webhooks" 30 PERMISSION_MANAGE_OTHERS_WEBHOOKS = "manage_others_webhooks" 31 PERMISSION_MANAGE_INCOMING_WEBHOOKS = "manage_incoming_webhooks" 32 PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS = "manage_others_incoming_webhooks" 33 PERMISSION_MANAGE_OUTGOING_WEBHOOKS = "manage_outgoing_webhooks" 34 PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS = "manage_others_outgoing_webhooks" 35 PERMISSION_LIST_PUBLIC_TEAMS = "list_public_teams" 36 PERMISSION_LIST_PRIVATE_TEAMS = "list_private_teams" 37 PERMISSION_JOIN_PUBLIC_TEAMS = "join_public_teams" 38 PERMISSION_JOIN_PRIVATE_TEAMS = "join_private_teams" 39 PERMISSION_PERMANENT_DELETE_USER = "permanent_delete_user" 40 PERMISSION_CREATE_BOT = "create_bot" 41 PERMISSION_READ_BOTS = "read_bots" 42 PERMISSION_READ_OTHERS_BOTS = "read_others_bots" 43 PERMISSION_MANAGE_BOTS = "manage_bots" 44 PERMISSION_MANAGE_OTHERS_BOTS = "manage_others_bots" 45 PERMISSION_DELETE_PUBLIC_CHANNEL = "delete_public_channel" 46 PERMISSION_DELETE_PRIVATE_CHANNEL = "delete_private_channel" 47 PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES = "manage_public_channel_properties" 48 PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES = "manage_private_channel_properties" 49 PERMISSION_VIEW_MEMBERS = "view_members" 50 PERMISSION_INVITE_USER = "invite_user" 51 PERMISSION_INVITE_GUEST = "invite_guest" 52 PERMISSION_PROMOTE_GUEST = "promote_guest" 53 PERMISSION_DEMOTE_TO_GUEST = "demote_to_guest" 54 PERMISSION_USE_CHANNEL_MENTIONS = "use_channel_mentions" 55 PERMISSION_CREATE_POST = "create_post" 56 PERMISSION_CREATE_POST_PUBLIC = "create_post_public" 57 PERMISSION_USE_GROUP_MENTIONS = "use_group_mentions" 58 PERMISSION_ADD_REACTION = "add_reaction" 59 PERMISSION_REMOVE_REACTION = "remove_reaction" 60 PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS = "manage_public_channel_members" 61 PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS = "manage_private_channel_members" 62 ) 63 64 func isRole(roleName string) func(*model.Role, map[string]map[string]bool) bool { 65 return func(role *model.Role, permissionsMap map[string]map[string]bool) bool { 66 return role.Name == roleName 67 } 68 } 69 70 func isNotRole(roleName string) func(*model.Role, map[string]map[string]bool) bool { 71 return func(role *model.Role, permissionsMap map[string]map[string]bool) bool { 72 return role.Name != roleName 73 } 74 } 75 76 func isNotSchemeRole(roleName string) func(*model.Role, map[string]map[string]bool) bool { 77 return func(role *model.Role, permissionsMap map[string]map[string]bool) bool { 78 return !strings.Contains(role.DisplayName, roleName) 79 } 80 } 81 82 func permissionExists(permission string) func(*model.Role, map[string]map[string]bool) bool { 83 return func(role *model.Role, permissionsMap map[string]map[string]bool) bool { 84 val, ok := permissionsMap[role.Name][permission] 85 return ok && val 86 } 87 } 88 89 func permissionNotExists(permission string) func(*model.Role, map[string]map[string]bool) bool { 90 return func(role *model.Role, permissionsMap map[string]map[string]bool) bool { 91 val, ok := permissionsMap[role.Name][permission] 92 return !(ok && val) 93 } 94 } 95 96 func onOtherRole(otherRole string, function func(*model.Role, map[string]map[string]bool) bool) func(*model.Role, map[string]map[string]bool) bool { 97 return func(role *model.Role, permissionsMap map[string]map[string]bool) bool { 98 return function(&model.Role{Name: otherRole}, permissionsMap) 99 } 100 } 101 102 func permissionOr(funcs ...func(*model.Role, map[string]map[string]bool) bool) func(*model.Role, map[string]map[string]bool) bool { 103 return func(role *model.Role, permissionsMap map[string]map[string]bool) bool { 104 for _, f := range funcs { 105 if f(role, permissionsMap) { 106 return true 107 } 108 } 109 return false 110 } 111 } 112 113 func permissionAnd(funcs ...func(*model.Role, map[string]map[string]bool) bool) func(*model.Role, map[string]map[string]bool) bool { 114 return func(role *model.Role, permissionsMap map[string]map[string]bool) bool { 115 for _, f := range funcs { 116 if !f(role, permissionsMap) { 117 return false 118 } 119 } 120 return true 121 } 122 } 123 124 func applyPermissionsMap(role *model.Role, roleMap map[string]map[string]bool, migrationMap permissionsMap) []string { 125 var result []string 126 127 roleName := role.Name 128 for _, transformation := range migrationMap { 129 if transformation.On(role, roleMap) { 130 for _, permission := range transformation.Add { 131 roleMap[roleName][permission] = true 132 } 133 for _, permission := range transformation.Remove { 134 roleMap[roleName][permission] = false 135 } 136 } 137 } 138 139 for key, active := range roleMap[roleName] { 140 if active { 141 result = append(result, key) 142 } 143 } 144 return result 145 } 146 147 func (a *App) doPermissionsMigration(key string, migrationMap permissionsMap) *model.AppError { 148 if _, err := a.Srv().Store.System().GetByName(key); err == nil { 149 return nil 150 } 151 152 roles, err := a.GetAllRoles() 153 if err != nil { 154 return err 155 } 156 157 roleMap := make(map[string]map[string]bool) 158 for _, role := range roles { 159 roleMap[role.Name] = make(map[string]bool) 160 for _, permission := range role.Permissions { 161 roleMap[role.Name][permission] = true 162 } 163 } 164 165 for _, role := range roles { 166 role.Permissions = applyPermissionsMap(role, roleMap, migrationMap) 167 if _, err := a.Srv().Store.Role().Save(role); err != nil { 168 var invErr *store.ErrInvalidInput 169 switch { 170 case errors.As(err, &invErr): 171 return model.NewAppError("doPermissionsMigration", "app.role.save.invalid_role.app_error", nil, invErr.Error(), http.StatusBadRequest) 172 default: 173 return model.NewAppError("doPermissionsMigration", "app.role.save.insert.app_error", nil, err.Error(), http.StatusInternalServerError) 174 } 175 } 176 } 177 178 if err := a.Srv().Store.System().Save(&model.System{Name: key, Value: "true"}); err != nil { 179 return err 180 } 181 return nil 182 } 183 184 func (a *App) getEmojisPermissionsSplitMigration() (permissionsMap, error) { 185 return permissionsMap{ 186 permissionTransformation{ 187 On: permissionExists(PERMISSION_MANAGE_EMOJIS), 188 Add: []string{PERMISSION_CREATE_EMOJIS, PERMISSION_DELETE_EMOJIS}, 189 Remove: []string{PERMISSION_MANAGE_EMOJIS}, 190 }, 191 permissionTransformation{ 192 On: permissionExists(PERMISSION_MANAGE_OTHERS_EMOJIS), 193 Add: []string{PERMISSION_DELETE_OTHERS_EMOJIS}, 194 Remove: []string{PERMISSION_MANAGE_OTHERS_EMOJIS}, 195 }, 196 }, nil 197 } 198 199 func (a *App) getWebhooksPermissionsSplitMigration() (permissionsMap, error) { 200 return permissionsMap{ 201 permissionTransformation{ 202 On: permissionExists(PERMISSION_MANAGE_WEBHOOKS), 203 Add: []string{PERMISSION_MANAGE_INCOMING_WEBHOOKS, PERMISSION_MANAGE_OUTGOING_WEBHOOKS}, 204 Remove: []string{PERMISSION_MANAGE_WEBHOOKS}, 205 }, 206 permissionTransformation{ 207 On: permissionExists(PERMISSION_MANAGE_OTHERS_WEBHOOKS), 208 Add: []string{PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS, PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS}, 209 Remove: []string{PERMISSION_MANAGE_OTHERS_WEBHOOKS}, 210 }, 211 }, nil 212 } 213 214 func (a *App) getListJoinPublicPrivateTeamsPermissionsMigration() (permissionsMap, error) { 215 return permissionsMap{ 216 permissionTransformation{ 217 On: isRole(model.SYSTEM_ADMIN_ROLE_ID), 218 Add: []string{PERMISSION_LIST_PRIVATE_TEAMS, PERMISSION_JOIN_PRIVATE_TEAMS}, 219 Remove: []string{}, 220 }, 221 permissionTransformation{ 222 On: isRole(model.SYSTEM_USER_ROLE_ID), 223 Add: []string{PERMISSION_LIST_PUBLIC_TEAMS, PERMISSION_JOIN_PUBLIC_TEAMS}, 224 Remove: []string{}, 225 }, 226 }, nil 227 } 228 229 func (a *App) removePermanentDeleteUserMigration() (permissionsMap, error) { 230 return permissionsMap{ 231 permissionTransformation{ 232 On: permissionExists(PERMISSION_PERMANENT_DELETE_USER), 233 Remove: []string{PERMISSION_PERMANENT_DELETE_USER}, 234 }, 235 }, nil 236 } 237 238 func (a *App) getAddBotPermissionsMigration() (permissionsMap, error) { 239 return permissionsMap{ 240 permissionTransformation{ 241 On: isRole(model.SYSTEM_ADMIN_ROLE_ID), 242 Add: []string{PERMISSION_CREATE_BOT, PERMISSION_READ_BOTS, PERMISSION_READ_OTHERS_BOTS, PERMISSION_MANAGE_BOTS, PERMISSION_MANAGE_OTHERS_BOTS}, 243 Remove: []string{}, 244 }, 245 }, nil 246 } 247 248 func (a *App) applyChannelManageDeleteToChannelUser() (permissionsMap, error) { 249 return permissionsMap{ 250 permissionTransformation{ 251 On: permissionAnd(isRole(model.CHANNEL_USER_ROLE_ID), onOtherRole(model.TEAM_USER_ROLE_ID, permissionExists(PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES))), 252 Add: []string{PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES}, 253 }, 254 permissionTransformation{ 255 On: permissionAnd(isRole(model.CHANNEL_USER_ROLE_ID), onOtherRole(model.TEAM_USER_ROLE_ID, permissionExists(PERMISSION_DELETE_PRIVATE_CHANNEL))), 256 Add: []string{PERMISSION_DELETE_PRIVATE_CHANNEL}, 257 }, 258 permissionTransformation{ 259 On: permissionAnd(isRole(model.CHANNEL_USER_ROLE_ID), onOtherRole(model.TEAM_USER_ROLE_ID, permissionExists(PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES))), 260 Add: []string{PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES}, 261 }, 262 permissionTransformation{ 263 On: permissionAnd(isRole(model.CHANNEL_USER_ROLE_ID), onOtherRole(model.TEAM_USER_ROLE_ID, permissionExists(PERMISSION_DELETE_PUBLIC_CHANNEL))), 264 Add: []string{PERMISSION_DELETE_PUBLIC_CHANNEL}, 265 }, 266 }, nil 267 } 268 269 func (a *App) removeChannelManageDeleteFromTeamUser() (permissionsMap, error) { 270 return permissionsMap{ 271 permissionTransformation{ 272 On: permissionAnd(isRole(model.TEAM_USER_ROLE_ID), permissionExists(PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES)), 273 Remove: []string{PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES}, 274 }, 275 permissionTransformation{ 276 On: permissionAnd(isRole(model.TEAM_USER_ROLE_ID), permissionExists(PERMISSION_DELETE_PRIVATE_CHANNEL)), 277 Remove: []string{model.PERMISSION_DELETE_PRIVATE_CHANNEL.Id}, 278 }, 279 permissionTransformation{ 280 On: permissionAnd(isRole(model.TEAM_USER_ROLE_ID), permissionExists(PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES)), 281 Remove: []string{PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES}, 282 }, 283 permissionTransformation{ 284 On: permissionAnd(isRole(model.TEAM_USER_ROLE_ID), permissionExists(PERMISSION_DELETE_PUBLIC_CHANNEL)), 285 Remove: []string{PERMISSION_DELETE_PUBLIC_CHANNEL}, 286 }, 287 }, nil 288 } 289 290 func (a *App) getViewMembersPermissionMigration() (permissionsMap, error) { 291 return permissionsMap{ 292 permissionTransformation{ 293 On: isRole(model.SYSTEM_USER_ROLE_ID), 294 Add: []string{PERMISSION_VIEW_MEMBERS}, 295 }, 296 permissionTransformation{ 297 On: isRole(model.SYSTEM_ADMIN_ROLE_ID), 298 Add: []string{PERMISSION_VIEW_MEMBERS}, 299 }, 300 }, nil 301 } 302 303 func (a *App) getAddManageGuestsPermissionsMigration() (permissionsMap, error) { 304 return permissionsMap{ 305 permissionTransformation{ 306 On: isRole(model.SYSTEM_ADMIN_ROLE_ID), 307 Add: []string{PERMISSION_PROMOTE_GUEST, PERMISSION_DEMOTE_TO_GUEST, PERMISSION_INVITE_GUEST}, 308 }, 309 }, nil 310 } 311 312 func (a *App) channelModerationPermissionsMigration() (permissionsMap, error) { 313 transformations := permissionsMap{} 314 315 var allTeamSchemes []*model.Scheme 316 next := a.SchemesIterator(model.SCHEME_SCOPE_TEAM, 100) 317 var schemeBatch []*model.Scheme 318 for schemeBatch = next(); len(schemeBatch) > 0; schemeBatch = next() { 319 allTeamSchemes = append(allTeamSchemes, schemeBatch...) 320 } 321 322 moderatedPermissionsMinusCreatePost := []string{ 323 PERMISSION_ADD_REACTION, 324 PERMISSION_REMOVE_REACTION, 325 PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS, 326 PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS, 327 PERMISSION_USE_CHANNEL_MENTIONS, 328 } 329 330 teamAndChannelAdminConditionalTransformations := func(teamAdminID, channelAdminID, channelUserID, channelGuestID string) []permissionTransformation { 331 transformations := []permissionTransformation{} 332 333 for _, perm := range moderatedPermissionsMinusCreatePost { 334 // add each moderated permission to the channel admin if channel user or guest has the permission 335 trans := permissionTransformation{ 336 On: permissionAnd( 337 isRole(channelAdminID), 338 permissionOr( 339 onOtherRole(channelUserID, permissionExists(perm)), 340 onOtherRole(channelGuestID, permissionExists(perm)), 341 ), 342 ), 343 Add: []string{perm}, 344 } 345 transformations = append(transformations, trans) 346 347 // add each moderated permission to the team admin if channel admin, user, or guest has the permission 348 trans = permissionTransformation{ 349 On: permissionAnd( 350 isRole(teamAdminID), 351 permissionOr( 352 onOtherRole(channelAdminID, permissionExists(perm)), 353 onOtherRole(channelUserID, permissionExists(perm)), 354 onOtherRole(channelGuestID, permissionExists(perm)), 355 ), 356 ), 357 Add: []string{perm}, 358 } 359 transformations = append(transformations, trans) 360 } 361 362 return transformations 363 } 364 365 for _, ts := range allTeamSchemes { 366 // ensure all team scheme channel admins have create_post because it's not exposed via the UI 367 trans := permissionTransformation{ 368 On: isRole(ts.DefaultChannelAdminRole), 369 Add: []string{PERMISSION_CREATE_POST}, 370 } 371 transformations = append(transformations, trans) 372 373 // ensure all team scheme team admins have create_post because it's not exposed via the UI 374 trans = permissionTransformation{ 375 On: isRole(ts.DefaultTeamAdminRole), 376 Add: []string{PERMISSION_CREATE_POST}, 377 } 378 transformations = append(transformations, trans) 379 380 // conditionally add all other moderated permissions to team and channel admins 381 transformations = append(transformations, teamAndChannelAdminConditionalTransformations( 382 ts.DefaultTeamAdminRole, 383 ts.DefaultChannelAdminRole, 384 ts.DefaultChannelUserRole, 385 ts.DefaultChannelGuestRole, 386 )...) 387 } 388 389 // ensure team admins have create_post 390 transformations = append(transformations, permissionTransformation{ 391 On: isRole(model.TEAM_ADMIN_ROLE_ID), 392 Add: []string{PERMISSION_CREATE_POST}, 393 }) 394 395 // ensure channel admins have create_post 396 transformations = append(transformations, permissionTransformation{ 397 On: isRole(model.CHANNEL_ADMIN_ROLE_ID), 398 Add: []string{PERMISSION_CREATE_POST}, 399 }) 400 401 // conditionally add all other moderated permissions to team and channel admins 402 transformations = append(transformations, teamAndChannelAdminConditionalTransformations( 403 model.TEAM_ADMIN_ROLE_ID, 404 model.CHANNEL_ADMIN_ROLE_ID, 405 model.CHANNEL_USER_ROLE_ID, 406 model.CHANNEL_GUEST_ROLE_ID, 407 )...) 408 409 // ensure system admin has all of the moderated permissions 410 transformations = append(transformations, permissionTransformation{ 411 On: isRole(model.SYSTEM_ADMIN_ROLE_ID), 412 Add: append(moderatedPermissionsMinusCreatePost, PERMISSION_CREATE_POST), 413 }) 414 415 // add the new use_channel_mentions permission to everyone who has create_post 416 transformations = append(transformations, permissionTransformation{ 417 On: permissionOr(permissionExists(PERMISSION_CREATE_POST), permissionExists(PERMISSION_CREATE_POST_PUBLIC)), 418 Add: []string{PERMISSION_USE_CHANNEL_MENTIONS}, 419 }) 420 421 return transformations, nil 422 } 423 424 func (a *App) getAddUseGroupMentionsPermissionMigration() (permissionsMap, error) { 425 return permissionsMap{ 426 permissionTransformation{ 427 On: permissionAnd( 428 isNotRole(model.CHANNEL_GUEST_ROLE_ID), 429 isNotSchemeRole("Channel Guest Role for Scheme"), 430 permissionOr(permissionExists(PERMISSION_CREATE_POST), permissionExists(PERMISSION_CREATE_POST_PUBLIC)), 431 ), 432 Add: []string{PERMISSION_USE_GROUP_MENTIONS}, 433 }, 434 }, nil 435 } 436 437 // DoPermissionsMigrations execute all the permissions migrations need by the current version. 438 func (a *App) DoPermissionsMigrations() error { 439 PermissionsMigrations := []struct { 440 Key string 441 Migration func() (permissionsMap, error) 442 }{ 443 {Key: model.MIGRATION_KEY_EMOJI_PERMISSIONS_SPLIT, Migration: a.getEmojisPermissionsSplitMigration}, 444 {Key: model.MIGRATION_KEY_WEBHOOK_PERMISSIONS_SPLIT, Migration: a.getWebhooksPermissionsSplitMigration}, 445 {Key: model.MIGRATION_KEY_LIST_JOIN_PUBLIC_PRIVATE_TEAMS, Migration: a.getListJoinPublicPrivateTeamsPermissionsMigration}, 446 {Key: model.MIGRATION_KEY_REMOVE_PERMANENT_DELETE_USER, Migration: a.removePermanentDeleteUserMigration}, 447 {Key: model.MIGRATION_KEY_ADD_BOT_PERMISSIONS, Migration: a.getAddBotPermissionsMigration}, 448 {Key: model.MIGRATION_KEY_APPLY_CHANNEL_MANAGE_DELETE_TO_CHANNEL_USER, Migration: a.applyChannelManageDeleteToChannelUser}, 449 {Key: model.MIGRATION_KEY_REMOVE_CHANNEL_MANAGE_DELETE_FROM_TEAM_USER, Migration: a.removeChannelManageDeleteFromTeamUser}, 450 {Key: model.MIGRATION_KEY_VIEW_MEMBERS_NEW_PERMISSION, Migration: a.getViewMembersPermissionMigration}, 451 {Key: model.MIGRATION_KEY_ADD_MANAGE_GUESTS_PERMISSIONS, Migration: a.getAddManageGuestsPermissionsMigration}, 452 {Key: model.MIGRATION_KEY_CHANNEL_MODERATIONS_PERMISSIONS, Migration: a.channelModerationPermissionsMigration}, 453 {Key: model.MIGRATION_KEY_ADD_USE_GROUP_MENTIONS_PERMISSION, Migration: a.getAddUseGroupMentionsPermissionMigration}, 454 } 455 456 for _, migration := range PermissionsMigrations { 457 migMap, err := migration.Migration() 458 if err != nil { 459 return err 460 } 461 if err := a.doPermissionsMigration(migration.Key, migMap); err != nil { 462 return err 463 } 464 } 465 return nil 466 }