github.com/vnforks/kid/v5@v5.22.1-0.20200408055009-b89d99c65676/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 "strings" 8 9 "github.com/vnforks/kid/v5/model" 10 ) 11 12 type permissionTransformation struct { 13 On func(*model.Role, map[string]map[string]bool) bool 14 Add []string 15 Remove []string 16 } 17 type permissionsMap []permissionTransformation 18 19 const ( 20 PERMISSION_MANAGE_SYSTEM = "manage_system" 21 PERMISSION_MANAGE_EMOJIS = "manage_emojis" 22 PERMISSION_MANAGE_OTHERS_EMOJIS = "manage_others_emojis" 23 PERMISSION_CREATE_EMOJIS = "create_emojis" 24 PERMISSION_DELETE_EMOJIS = "delete_emojis" 25 PERMISSION_DELETE_OTHERS_EMOJIS = "delete_others_emojis" 26 PERMISSION_MANAGE_WEBHOOKS = "manage_webhooks" 27 PERMISSION_MANAGE_OTHERS_WEBHOOKS = "manage_others_webhooks" 28 PERMISSION_MANAGE_INCOMING_WEBHOOKS = "manage_incoming_webhooks" 29 PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS = "manage_others_incoming_webhooks" 30 PERMISSION_MANAGE_OUTGOING_WEBHOOKS = "manage_outgoing_webhooks" 31 PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS = "manage_others_outgoing_webhooks" 32 PERMISSION_LIST_BRANCHES = "list_branches" 33 PERMISSION_PERMANENT_DELETE_USER = "permanent_delete_user" 34 PERMISSION_DELETE_CLASS = "delete_class" 35 PERMISSION_MANAGE_CLASS = "manage_class" 36 PERMISSION_VIEW_MEMBERS = "view_members" 37 PERMISSION_USE_CLASS_MENTIONS = "use_class_mentions" 38 PERMISSION_CREATE_POST = "create_post" 39 PERMISSION_ADD_REACTION = "add_reaction" 40 PERMISSION_REMOVE_REACTION = "remove_reaction" 41 PERMISSION_MANAGE_CLASS_MEMBERS = "manage_class_members" 42 ) 43 44 func isRole(roleName string) func(*model.Role, map[string]map[string]bool) bool { 45 return func(role *model.Role, permissionsMap map[string]map[string]bool) bool { 46 return role.Name == roleName 47 } 48 } 49 50 func isNotRole(roleName string) func(*model.Role, map[string]map[string]bool) bool { 51 return func(role *model.Role, permissionsMap map[string]map[string]bool) bool { 52 return role.Name != roleName 53 } 54 } 55 56 func isNotSchemeRole(roleName string) func(*model.Role, map[string]map[string]bool) bool { 57 return func(role *model.Role, permissionsMap map[string]map[string]bool) bool { 58 return !strings.Contains(role.DisplayName, roleName) 59 } 60 } 61 62 func permissionExists(permission string) func(*model.Role, map[string]map[string]bool) bool { 63 return func(role *model.Role, permissionsMap map[string]map[string]bool) bool { 64 val, ok := permissionsMap[role.Name][permission] 65 return ok && val 66 } 67 } 68 69 func permissionNotExists(permission string) func(*model.Role, map[string]map[string]bool) bool { 70 return func(role *model.Role, permissionsMap map[string]map[string]bool) bool { 71 val, ok := permissionsMap[role.Name][permission] 72 return !(ok && val) 73 } 74 } 75 76 func onOtherRole(otherRole string, function func(*model.Role, map[string]map[string]bool) bool) func(*model.Role, map[string]map[string]bool) bool { 77 return func(role *model.Role, permissionsMap map[string]map[string]bool) bool { 78 return function(&model.Role{Name: otherRole}, permissionsMap) 79 } 80 } 81 82 func permissionOr(funcs ...func(*model.Role, map[string]map[string]bool) bool) func(*model.Role, map[string]map[string]bool) bool { 83 return func(role *model.Role, permissionsMap map[string]map[string]bool) bool { 84 for _, f := range funcs { 85 if f(role, permissionsMap) { 86 return true 87 } 88 } 89 return false 90 } 91 } 92 93 func permissionAnd(funcs ...func(*model.Role, map[string]map[string]bool) bool) func(*model.Role, map[string]map[string]bool) bool { 94 return func(role *model.Role, permissionsMap map[string]map[string]bool) bool { 95 for _, f := range funcs { 96 if !f(role, permissionsMap) { 97 return false 98 } 99 } 100 return true 101 } 102 } 103 104 func applyPermissionsMap(role *model.Role, roleMap map[string]map[string]bool, migrationMap permissionsMap) []string { 105 var result []string 106 107 roleName := role.Name 108 for _, transformation := range migrationMap { 109 if transformation.On(role, roleMap) { 110 for _, permission := range transformation.Add { 111 roleMap[roleName][permission] = true 112 } 113 for _, permission := range transformation.Remove { 114 roleMap[roleName][permission] = false 115 } 116 } 117 } 118 119 for key, active := range roleMap[roleName] { 120 if active { 121 result = append(result, key) 122 } 123 } 124 return result 125 } 126 127 func (a *App) doPermissionsMigration(key string, migrationMap permissionsMap) *model.AppError { 128 if _, err := a.Srv().Store.System().GetByName(key); err == nil { 129 return nil 130 } 131 132 roles, err := a.GetAllRoles() 133 if err != nil { 134 return err 135 } 136 137 roleMap := make(map[string]map[string]bool) 138 for _, role := range roles { 139 roleMap[role.Name] = make(map[string]bool) 140 for _, permission := range role.Permissions { 141 roleMap[role.Name][permission] = true 142 } 143 } 144 145 for _, role := range roles { 146 role.Permissions = applyPermissionsMap(role, roleMap, migrationMap) 147 if _, err := a.Srv().Store.Role().Save(role); err != nil { 148 return err 149 } 150 } 151 152 if err := a.Srv().Store.System().Save(&model.System{Name: key, Value: "true"}); err != nil { 153 return err 154 } 155 return nil 156 } 157 158 func (a *App) getEmojisPermissionsSplitMigration() (permissionsMap, error) { 159 return permissionsMap{ 160 permissionTransformation{ 161 On: permissionExists(PERMISSION_MANAGE_EMOJIS), 162 Add: []string{PERMISSION_CREATE_EMOJIS, PERMISSION_DELETE_EMOJIS}, 163 Remove: []string{PERMISSION_MANAGE_EMOJIS}, 164 }, 165 permissionTransformation{ 166 On: permissionExists(PERMISSION_MANAGE_OTHERS_EMOJIS), 167 Add: []string{PERMISSION_DELETE_OTHERS_EMOJIS}, 168 Remove: []string{PERMISSION_MANAGE_OTHERS_EMOJIS}, 169 }, 170 }, nil 171 } 172 173 func (a *App) getWebhooksPermissionsSplitMigration() (permissionsMap, error) { 174 return permissionsMap{ 175 permissionTransformation{ 176 On: permissionExists(PERMISSION_MANAGE_WEBHOOKS), 177 Add: []string{PERMISSION_MANAGE_INCOMING_WEBHOOKS, PERMISSION_MANAGE_OUTGOING_WEBHOOKS}, 178 Remove: []string{PERMISSION_MANAGE_WEBHOOKS}, 179 }, 180 permissionTransformation{ 181 On: permissionExists(PERMISSION_MANAGE_OTHERS_WEBHOOKS), 182 Add: []string{PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS, PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS}, 183 Remove: []string{PERMISSION_MANAGE_OTHERS_WEBHOOKS}, 184 }, 185 }, nil 186 } 187 188 func (a *App) removePermanentDeleteUserMigration() (permissionsMap, error) { 189 return permissionsMap{ 190 permissionTransformation{ 191 On: permissionExists(PERMISSION_PERMANENT_DELETE_USER), 192 Remove: []string{PERMISSION_PERMANENT_DELETE_USER}, 193 }, 194 }, nil 195 } 196 197 func (a *App) applyClassManageDeleteToClassUser() (permissionsMap, error) { 198 return permissionsMap{ 199 permissionTransformation{ 200 On: permissionAnd(isRole(model.CLASS_USER_ROLE_ID), onOtherRole(model.BRANCH_USER_ROLE_ID, permissionExists(PERMISSION_DELETE_CLASS))), 201 Add: []string{PERMISSION_DELETE_CLASS}, 202 }, 203 permissionTransformation{ 204 On: permissionAnd(isRole(model.CLASS_USER_ROLE_ID), onOtherRole(model.BRANCH_USER_ROLE_ID, permissionExists(PERMISSION_MANAGE_CLASS))), 205 Add: []string{PERMISSION_MANAGE_CLASS}, 206 }, 207 }, nil 208 } 209 210 func (a *App) removeClassManageDeleteFromBranchUser() (permissionsMap, error) { 211 return permissionsMap{ 212 permissionTransformation{ 213 On: permissionAnd(isRole(model.BRANCH_USER_ROLE_ID), permissionExists(PERMISSION_MANAGE_CLASS)), 214 Remove: []string{PERMISSION_MANAGE_CLASS}, 215 }, 216 permissionTransformation{ 217 On: permissionAnd(isRole(model.BRANCH_USER_ROLE_ID), permissionExists(PERMISSION_DELETE_CLASS)), 218 Remove: []string{model.PERMISSION_DELETE_CLASS.Id}, 219 }, 220 }, nil 221 } 222 223 func (a *App) getViewMembersPermissionMigration() (permissionsMap, error) { 224 return permissionsMap{ 225 permissionTransformation{ 226 On: isRole(model.SYSTEM_USER_ROLE_ID), 227 Add: []string{PERMISSION_VIEW_MEMBERS}, 228 }, 229 permissionTransformation{ 230 On: isRole(model.SYSTEM_ADMIN_ROLE_ID), 231 Add: []string{PERMISSION_VIEW_MEMBERS}, 232 }, 233 }, nil 234 } 235 236 func (a *App) classModerationPermissionsMigration() (permissionsMap, error) { 237 transformations := permissionsMap{} 238 239 var allBranchSchemes []*model.Scheme 240 next := a.SchemesIterator(model.SCHEME_SCOPE_BRANCH, 100) 241 var schemeBatch []*model.Scheme 242 for schemeBatch = next(); len(schemeBatch) > 0; schemeBatch = next() { 243 allBranchSchemes = append(allBranchSchemes, schemeBatch...) 244 } 245 246 moderatedPermissionsMinusCreatePost := []string{ 247 PERMISSION_ADD_REACTION, 248 PERMISSION_REMOVE_REACTION, 249 PERMISSION_MANAGE_CLASS_MEMBERS, 250 PERMISSION_USE_CLASS_MENTIONS, 251 } 252 253 branchAndClassAdminConditionalTransformations := func(branchAdminID, classAdminID, classUserID string) []permissionTransformation { 254 transformations := []permissionTransformation{} 255 256 for _, perm := range moderatedPermissionsMinusCreatePost { 257 // add each moderated permission to the class admin if class user or guest has the permission 258 trans := permissionTransformation{ 259 On: permissionAnd( 260 isRole(classAdminID), 261 permissionOr( 262 onOtherRole(classUserID, permissionExists(perm)), 263 ), 264 ), 265 Add: []string{perm}, 266 } 267 transformations = append(transformations, trans) 268 269 // add each moderated permission to the branch admin if class admin, user, or guest has the permission 270 trans = permissionTransformation{ 271 On: permissionAnd( 272 isRole(branchAdminID), 273 permissionOr( 274 onOtherRole(classAdminID, permissionExists(perm)), 275 onOtherRole(classUserID, permissionExists(perm)), 276 ), 277 ), 278 Add: []string{perm}, 279 } 280 transformations = append(transformations, trans) 281 } 282 283 return transformations 284 } 285 286 for _, ts := range allBranchSchemes { 287 // ensure all branch scheme class admins have create_post because it's not exposed via the UI 288 trans := permissionTransformation{ 289 On: isRole(ts.DefaultClassAdminRole), 290 Add: []string{PERMISSION_CREATE_POST}, 291 } 292 transformations = append(transformations, trans) 293 294 // ensure all branch scheme branch admins have create_post because it's not exposed via the UI 295 trans = permissionTransformation{ 296 On: isRole(ts.DefaultBranchAdminRole), 297 Add: []string{PERMISSION_CREATE_POST}, 298 } 299 transformations = append(transformations, trans) 300 301 // conditionally add all other moderated permissions to branch and class admins 302 transformations = append(transformations, branchAndClassAdminConditionalTransformations( 303 ts.DefaultBranchAdminRole, 304 ts.DefaultClassAdminRole, 305 ts.DefaultClassUserRole, 306 )...) 307 } 308 309 // ensure branch admins have create_post 310 transformations = append(transformations, permissionTransformation{ 311 On: isRole(model.BRANCH_ADMIN_ROLE_ID), 312 Add: []string{PERMISSION_CREATE_POST}, 313 }) 314 315 // ensure class admins have create_post 316 transformations = append(transformations, permissionTransformation{ 317 On: isRole(model.CLASS_ADMIN_ROLE_ID), 318 Add: []string{PERMISSION_CREATE_POST}, 319 }) 320 321 // conditionally add all other moderated permissions to branch and class admins 322 transformations = append(transformations, branchAndClassAdminConditionalTransformations( 323 model.BRANCH_ADMIN_ROLE_ID, 324 model.CLASS_ADMIN_ROLE_ID, 325 model.CLASS_USER_ROLE_ID, 326 )...) 327 328 // ensure system admin has all of the moderated permissions 329 transformations = append(transformations, permissionTransformation{ 330 On: isRole(model.SYSTEM_ADMIN_ROLE_ID), 331 Add: append(moderatedPermissionsMinusCreatePost, PERMISSION_CREATE_POST), 332 }) 333 334 // add the new use_class_mentions permission to everyone who has create_post 335 transformations = append(transformations, permissionTransformation{ 336 On: permissionOr(permissionExists(PERMISSION_CREATE_POST)), 337 Add: []string{PERMISSION_USE_CLASS_MENTIONS}, 338 }) 339 340 return transformations, nil 341 } 342 343 // DoPermissionsMigrations execute all the permissions migrations need by the current version. 344 func (a *App) DoPermissionsMigrations() error { 345 PermissionsMigrations := []struct { 346 Key string 347 Migration func() (permissionsMap, error) 348 }{ 349 {Key: model.MIGRATION_KEY_EMOJI_PERMISSIONS_SPLIT, Migration: a.getEmojisPermissionsSplitMigration}, 350 {Key: model.MIGRATION_KEY_WEBHOOK_PERMISSIONS_SPLIT, Migration: a.getWebhooksPermissionsSplitMigration}, 351 {Key: model.MIGRATION_KEY_REMOVE_PERMANENT_DELETE_USER, Migration: a.removePermanentDeleteUserMigration}, 352 {Key: model.MIGRATION_KEY_APPLY_CLASS_MANAGE_DELETE_TO_CLASS_USER, Migration: a.applyClassManageDeleteToClassUser}, 353 {Key: model.MIGRATION_KEY_REMOVE_CLASS_MANAGE_DELETE_FROM_BRANCH_USER, Migration: a.removeClassManageDeleteFromBranchUser}, 354 {Key: model.MIGRATION_KEY_VIEW_MEMBERS_NEW_PERMISSION, Migration: a.getViewMembersPermissionMigration}, 355 {Key: model.MIGRATION_KEY_CLASS_MODERATIONS_PERMISSIONS, Migration: a.classModerationPermissionsMigration}, 356 } 357 358 for _, migration := range PermissionsMigrations { 359 migMap, err := migration.Migration() 360 if err != nil { 361 return err 362 } 363 if err := a.doPermissionsMigration(migration.Key, migMap); err != nil { 364 return err 365 } 366 } 367 return nil 368 }