From 8354206e5c3cabfbb6f0eee9874fd5c4f74a295c Mon Sep 17 00:00:00 2001 From: Martin Kraft Date: Fri, 21 Aug 2020 16:49:31 -0400 Subject: [PATCH] MM-25543: New Admin Roles (#14960) * MM-23832: Initial set of changes * MM-23832: further iteration * MM-23832: further iteration * MM-23832: further iteration * MM-23832: Fixes merge. * create migration for new Roles * MM-23832: Renames some roles. * MM-23832: Adds ability to see logs. * MM-23832: Removes manage roles from restricted admin. * MM-23832: Make authentication section read-only for restricted admin. * MM-23832: Allow restricted admin to purge caches. * MM-23832: Adds ability to recycle DB connections. * MM-23832: Adds ability to purge indexes. * MM-23832: Adds ability to test email and S3 config. * MM-23832: Adds abilituy to read job status. * MM-23832: Adds ability to read plugin statuses. * MM-23832: Renames Restricted Admin to System Manager. * MM-23832: Adds manage team roles to system_user_manager. * MM-23832: Updates some permissions. * MM-23832: Allow get all channels and get moderations. * MM-23832: Adds some permissions to User Manager. * MM-23832: Remove write users from user manager. * MM-23832: Changes permissions for the usermanagement > users sysconsole section. * MM-23832: Removes read_settings and write_settings permissions. Ensures the usermanagement parent permissions encompass the sub-permissions. * MM-23832: Updates permissions. * MM-23832: Changes some permissions checks, adds new permissions to roles. * MM-23832: Adds ability to update a role. * MM-23832: Permissions updates. * MM-23832: Removes write access to plugins for system manager. * MM-23832: Removes read compliance from new roles. * MM-23832: Adds mock for new roles creation migration. * MM-23832: Changes to variadic param. * MM-23832: Removes some duplication in the permissions model. Renames some permissions constants. * MM-23832: Updates some migrations. * MM-23832: Removes some unnecessary constants. * MM-23832: Changes back to old app method name. * MM-23832: Fixes incorrect permission check. * MM-23832: Changes write to read permission check. * MM-23832: Removes the authentication permission from link/unlink group. * MM-23832: Enable testing LDAP with read permissions. * MM-23832: Make testing elasticsearch a read permission. * MM-23832: Warn metrics are associated to any system console read permissions. * MM-23832: Updates some permissions checks. * MM-23832: Removes non-systemconsole permissions from roles. * MM-23832: Update default permission assignment of sysadmin. * MM-23832: Fixes incorrect permission check. Removes some unused stuff. * MM-23832: Update permission to check. * MM-23832: Switches to struct tags. * MM-23832: Adds some docs for the permissions tag. * MM-23832: Removes whitespace. * MM-23832: Combines system admin restricted access with other acess-control tag. * MM-23832: Fixes some tests. * MM-23832: Clarifies docs, does not assume prior permission check in '-' access value case. * MM-23832: Updates to correct access tag value. * MM-23832: Adds test of the config settings tag access. * MM-23832: Undoes whitespace change. * MM-23832: Removes comment. * MM-23832: Adds the permissions to the new roles rather than using OR conditions on the permissions checks. * MM-23832: Removes or condition on permission check. * MM-23832: Updates mapping. * MM-23832: Typo fix. * MM-23832: Adds new 'read_jobs' permission. * MM-23832: Add read_jobs to all roles with manage_jobs. * MM-23832: Adds new permission read_other_users_teams. * MM-23832: Adds read filtering of config. * MM-23932: Change tag value. * MM-23832: Fixes some tests. Adds test for read config access tag. * MM-23832: Adds permissions to list teams. * MM-23832: Removes the '-' tag value. Adds a new permission read_channel_groups. Updates a permission check. * MM-23832: Removes unnecessary parent permission for user_management. Fixes permission check change error. * MM-23832: Removes unused parameter to filter/merge function. * MM-23832: Renames migration name. * MM-23832: Fix for godoc. * MM-23832: Fixes tests. * MM-23832: Only makes a map once rather than every function call. Doesn't require access tag on config field structs. Reverts one test update and fixes another. * MM-23832: Removes all of the unnecessary uses of (*App).SessionHasPermissionToAny since removing the user_management parent permission. * MM-23832: Updates constant type. * MM-23832: Removes unnecessary comment. * MM-23832: Renames permissions. * MM-23832: Fix for permission name changes. * MM-23832: Adds missing config access tags. Adds some requirec ancillary permissions for write_usermanagement_teams. * MM-23832: Adds local API endpoint for getting config. * MM-23832: If tag value is blank or restrict_sys_admin_write then don't do the permission check. * MM-23832: nil check for strings prior to dereferencing. * MM-23832: Fix for config display logic. * MM-23832: Updates godoc. * MM-23832: Delays the unrestricted check for parity with other permissions checks if the channel id does not exist. * MM-23832: Removes tautology. * MM-23832: Re-adds status code check. * MM-23832: Adds new permission to edit brand image. * MM-23832: Exports variable for use by mmctl. * MM-23832: Initialize exported map for use by mmctl. * MM-23832: Accept deprecated permissions as valid. * MM-23832: Adds missing permissions to archive a channel. * MM-23832: Adds missing permissions for managing team. * MM-23832: Properly filters config values in patch and update API responses. * MM-23832: Fixes license viewing and writing permissions. * MM-23832: Require license to assign 'new system roles'. * MM-23832: Adds translation keys. * MM-23832: Updates translation order. * MM-27529: Splits read_channel_groups into read_public_channel_groups and read_private_channel_groups. * MM-23832: Prevent read-only permissions from editing site url test parameter. * MM-23832: Prevent read permissions from sniffing ports and elastic password. * MM-23832: Adds missing permission required for write user management channels. * MM-23832: Allows new roles to search for channels. * MM-23832: Adds ability for system_manager to manage jobs. * MM-23832: Cluster status access by sysconsole permission, not manage_system. * MM-23832: Adds 'add_user_to_team' permission to sysconsole write usermanagement teams. * MM-23832: Fixes lint. * MM-23832: Test fix. * MM-23832: Test fix. Co-authored-by: Catalin Tomai Co-authored-by: Scott Bishel Co-authored-by: Mattermod --- api4/brand.go | 8 +- api4/channel.go | 24 +- api4/channel_test.go | 2 +- api4/cluster.go | 4 +- api4/compliance.go | 16 +- api4/config.go | 158 +++-- api4/config_local.go | 11 +- api4/config_test.go | 122 +++- api4/elasticsearch.go | 16 +- api4/group.go | 30 +- api4/job.go | 16 +- api4/ldap.go | 20 +- api4/license.go | 14 +- api4/plugin.go | 36 +- api4/role.go | 4 +- api4/scheme.go | 28 +- api4/system.go | 46 +- api4/team.go | 16 +- api4/user.go | 16 +- app/app_iface.go | 4 +- app/app_test.go | 216 +------ app/authorization.go | 37 +- app/channel.go | 2 +- app/channel_test.go | 8 +- app/import_validators.go | 2 +- app/migrations.go | 49 +- app/opentracing/opentracing_layer.go | 36 +- app/permissions_migrations.go | 56 ++ i18n/en.json | 12 + model/config.go | 881 ++++++++++++++------------- model/migration.go | 2 + model/permission.go | 602 +++++++++++++----- model/permission_test.go | 2 +- model/role.go | 231 +++++-- model/role_test.go | 22 +- store/sqlstore/scheme_store.go | 2 +- testlib/store.go | 2 + utils/policies-roles-mapping.json | 2 +- web/context.go | 4 +- 39 files changed, 1715 insertions(+), 1044 deletions(-) diff --git a/api4/brand.go b/api4/brand.go index 78b3fae3dd..137eb68c86 100644 --- a/api4/brand.go +++ b/api4/brand.go @@ -61,8 +61,8 @@ func uploadBrandImage(c *Context, w http.ResponseWriter, r *http.Request) { auditRec := c.MakeAuditRecord("uploadBrandImage", audit.Fail) defer c.LogAuditRec(auditRec) - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_EDIT_BRAND) { + c.SetPermissionError(model.PERMISSION_EDIT_BRAND) return } @@ -82,8 +82,8 @@ func deleteBrandImage(c *Context, w http.ResponseWriter, r *http.Request) { auditRec := c.MakeAuditRecord("deleteBrandImage", audit.Fail) defer c.LogAuditRec(auditRec) - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_EDIT_BRAND) { + c.SetPermissionError(model.PERMISSION_EDIT_BRAND) return } diff --git a/api4/channel.go b/api4/channel.go index a68040bbfa..41e6616b9a 100644 --- a/api4/channel.go +++ b/api4/channel.go @@ -690,8 +690,12 @@ func getPinnedPosts(c *Context, w http.ResponseWriter, r *http.Request) { } func getAllChannels(c *Context, w http.ResponseWriter, r *http.Request) { - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + permissions := []*model.Permission{ + model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS, + model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_CHANNELS, + } + if !c.App.SessionHasPermissionToAny(*c.App.Session(), permissions) { + c.SetPermissionError(permissions...) return } @@ -1004,8 +1008,8 @@ func searchAllChannels(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_CHANNELS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_CHANNELS) return } includeDeleted, _ := strconv.ParseBool(r.URL.Query().Get("include_deleted")) @@ -1673,8 +1677,8 @@ func channelMembersMinusGroupMembers(c *Context, w http.ResponseWriter, r *http. groupIDs = append(groupIDs, gid) } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_CHANNELS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_CHANNELS) return } @@ -1745,8 +1749,8 @@ func getChannelModerations(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_CHANNELS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_CHANNELS) return } @@ -1785,8 +1789,8 @@ func patchChannelModerations(c *Context, w http.ResponseWriter, r *http.Request) auditRec := c.MakeAuditRecord("patchChannelModerations", audit.Fail) defer c.LogAuditRec(auditRec) - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_CHANNELS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_CHANNELS) return } diff --git a/api4/channel_test.go b/api4/channel_test.go index 5bf9510345..4666c60ed1 100644 --- a/api4/channel_test.go +++ b/api4/channel_test.go @@ -3661,7 +3661,7 @@ func TestPatchChannelModerations(t *testing.T) { emptyPatch := []*model.ChannelModerationPatch{} - createPosts := model.CHANNEL_MODERATED_PERMISSIONS[0] + createPosts := model.ChannelModeratedPermissions[0] th.App.SetPhase2PermissionsMigrationStatus(true) diff --git a/api4/cluster.go b/api4/cluster.go index 53c19f5345..7e2b7f60f5 100644 --- a/api4/cluster.go +++ b/api4/cluster.go @@ -14,8 +14,8 @@ func (api *API) InitCluster() { } func getClusterStatus(c *Context, w http.ResponseWriter, r *http.Request) { - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_ENVIRONMENT) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_ENVIRONMENT) return } diff --git a/api4/compliance.go b/api4/compliance.go index d47e9481bc..b7c67e5884 100644 --- a/api4/compliance.go +++ b/api4/compliance.go @@ -29,8 +29,8 @@ func createComplianceReport(c *Context, w http.ResponseWriter, r *http.Request) auditRec := c.MakeAuditRecord("createComplianceReport", audit.Fail) defer c.LogAuditRec(auditRec) - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE) return } @@ -52,8 +52,8 @@ func createComplianceReport(c *Context, w http.ResponseWriter, r *http.Request) } func getComplianceReports(c *Context, w http.ResponseWriter, r *http.Request) { - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_COMPLIANCE) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_COMPLIANCE) return } @@ -79,8 +79,8 @@ func getComplianceReport(c *Context, w http.ResponseWriter, r *http.Request) { auditRec := c.MakeAuditRecord("getComplianceReport", audit.Fail) defer c.LogAuditRec(auditRec) - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_COMPLIANCE) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_COMPLIANCE) return } @@ -107,8 +107,8 @@ func downloadComplianceReport(c *Context, w http.ResponseWriter, r *http.Request defer c.LogAuditRec(auditRec) auditRec.AddMeta("compliance_id", c.Params.ReportId) - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_COMPLIANCE) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_COMPLIANCE) return } diff --git a/api4/config.go b/api4/config.go index c76c96e373..be6e24daf3 100644 --- a/api4/config.go +++ b/api4/config.go @@ -4,15 +4,27 @@ package api4 import ( + "fmt" "net/http" "reflect" + "strings" "github.com/mattermost/mattermost-server/v5/audit" "github.com/mattermost/mattermost-server/v5/config" + "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" "github.com/mattermost/mattermost-server/v5/utils" ) +var writeFilter func(c *Context, structField reflect.StructField) bool +var readFilter func(c *Context, structField reflect.StructField) bool +var permissionMap map[string]*model.Permission + +type filterType string + +const filterTypeWrite filterType = "write" +const filterTypeRead filterType = "read" + func (api *API) InitConfig() { api.BaseRoutes.ApiRoot.Handle("/config", api.ApiSessionRequired(getConfig)).Methods("GET") api.BaseRoutes.ApiRoot.Handle("/config", api.ApiSessionRequired(updateConfig)).Methods("PUT") @@ -23,16 +35,32 @@ func (api *API) InitConfig() { api.BaseRoutes.ApiRoot.Handle("/config/migrate", api.ApiSessionRequired(migrateConfig)).Methods("POST") } +func init() { + writeFilter = makeFilterConfigByPermission(filterTypeWrite) + readFilter = makeFilterConfigByPermission(filterTypeRead) + permissionMap = map[string]*model.Permission{} + for _, p := range model.AllPermissions { + permissionMap[p.Id] = p + } +} + func getConfig(c *Context, w http.ResponseWriter, r *http.Request) { - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionToAny(*c.App.Session(), model.SysconsoleReadPermissions) { + c.SetPermissionError(model.SysconsoleReadPermissions...) return } auditRec := c.MakeAuditRecord("getConfig", audit.Fail) defer c.LogAuditRec(auditRec) - cfg := c.App.GetSanitizedConfig() + cfg, err := config.Merge(&model.Config{}, c.App.GetSanitizedConfig(), &utils.MergeConfig{ + StructFieldFilter: func(structField reflect.StructField, base, patch reflect.Value) bool { + return readFilter(c, structField) + }, + }) + if err != nil { + c.Err = model.NewAppError("getConfig", "api.config.get_config.restricted_merge.app_error", nil, err.Error(), http.StatusInternalServerError) + } auditRec.Success() @@ -44,8 +72,8 @@ func configReload(c *Context, w http.ResponseWriter, r *http.Request) { auditRec := c.MakeAuditRecord("configReload", audit.Fail) defer c.LogAuditRec(auditRec) - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionToAny(*c.App.Session(), model.SysconsoleReadPermissions) { + c.SetPermissionError(model.SysconsoleReadPermissions...) return } @@ -74,8 +102,8 @@ func updateConfig(c *Context, w http.ResponseWriter, r *http.Request) { cfg.SetDefaults() - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionToAny(*c.App.Session(), model.SysconsoleWritePermissions) { + c.SetPermissionError(model.SysconsoleWritePermissions...) return } @@ -84,20 +112,15 @@ func updateConfig(c *Context, w http.ResponseWriter, r *http.Request) { c.Err = model.NewAppError("updateConfig", "api.config.update_config.clear_siteurl.app_error", nil, "", http.StatusBadRequest) return } - if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin { - // Start with the current configuration, and only merge values not marked as being - // restricted. - var err error - cfg, err = config.Merge(appCfg, cfg, &utils.MergeConfig{ - StructFieldFilter: func(structField reflect.StructField, base, patch reflect.Value) bool { - restricted := structField.Tag.Get("restricted") == "true" - return !restricted - }, - }) - if err != nil { - c.Err = model.NewAppError("updateConfig", "api.config.update_config.restricted_merge.app_error", nil, err.Error(), http.StatusInternalServerError) - } + var err1 error + cfg, err1 = config.Merge(appCfg, cfg, &utils.MergeConfig{ + StructFieldFilter: func(structField reflect.StructField, base, patch reflect.Value) bool { + return writeFilter(c, structField) + }, + }) + if err1 != nil { + c.Err = model.NewAppError("updateConfig", "api.config.update_config.restricted_merge.app_error", nil, err1.Error(), http.StatusInternalServerError) } // Do not allow plugin uploads to be toggled through the API @@ -120,7 +143,14 @@ func updateConfig(c *Context, w http.ResponseWriter, r *http.Request) { return } - cfg = c.App.GetSanitizedConfig() + cfg, mergeErr := config.Merge(&model.Config{}, c.App.GetSanitizedConfig(), &utils.MergeConfig{ + StructFieldFilter: func(structField reflect.StructField, base, patch reflect.Value) bool { + return readFilter(c, structField) + }, + }) + if mergeErr != nil { + c.Err = model.NewAppError("getConfig", "api.config.update_config.restricted_merge.app_error", nil, err.Error(), http.StatusInternalServerError) + } auditRec.Success() c.LogAudit("updateConfig") @@ -153,8 +183,8 @@ func getClientConfig(c *Context, w http.ResponseWriter, r *http.Request) { } func getEnvironmentConfig(c *Context, w http.ResponseWriter, r *http.Request) { - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_ENVIRONMENT) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_ENVIRONMENT) return } @@ -174,8 +204,8 @@ func patchConfig(c *Context, w http.ResponseWriter, r *http.Request) { auditRec := c.MakeAuditRecord("patchConfig", audit.Fail) defer c.LogAuditRec(auditRec) - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionToAny(*c.App.Session(), model.SysconsoleWritePermissions) { + c.SetPermissionError(model.SysconsoleWritePermissions...) return } @@ -184,15 +214,9 @@ func patchConfig(c *Context, w http.ResponseWriter, r *http.Request) { c.Err = model.NewAppError("patchConfig", "api.config.update_config.clear_siteurl.app_error", nil, "", http.StatusBadRequest) return } - var filterFn utils.StructFieldFilter - if *appCfg.ExperimentalSettings.RestrictSystemAdmin { - filterFn = func(structField reflect.StructField, base, patch reflect.Value) bool { - return !(structField.Tag.Get("restricted") == "true") - } - } else { - filterFn = func(structField reflect.StructField, base, patch reflect.Value) bool { - return true - } + + filterFn := func(structField reflect.StructField, base, patch reflect.Value) bool { + return writeFilter(c, structField) } // Do not allow plugin uploads to be toggled through the API @@ -225,8 +249,72 @@ func patchConfig(c *Context, w http.ResponseWriter, r *http.Request) { auditRec.Success() + cfg, mergeErr = config.Merge(&model.Config{}, c.App.GetSanitizedConfig(), &utils.MergeConfig{ + StructFieldFilter: func(structField reflect.StructField, base, patch reflect.Value) bool { + return readFilter(c, structField) + }, + }) + if mergeErr != nil { + c.Err = model.NewAppError("getConfig", "api.config.patch_config.restricted_merge.app_error", nil, err.Error(), http.StatusInternalServerError) + } + w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") - w.Write([]byte(c.App.GetSanitizedConfig().ToJson())) + w.Write([]byte(cfg.ToJson())) +} + +func makeFilterConfigByPermission(accessType filterType) func(c *Context, structField reflect.StructField) bool { + return func(c *Context, structField reflect.StructField) bool { + if structField.Type.Kind() == reflect.Struct { + return true + } + + tagPermissions := strings.Split(structField.Tag.Get("access"), ",") + + // If there are no access tag values and the role has manage_system, no need to continue + // checking permissions. + if len(tagPermissions) == 0 { + if c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { + return true + } + } + + // one iteration for write_restrictable value, it could be anywhere in the order of values + for _, val := range tagPermissions { + tagValue := strings.TrimSpace(val) + if tagValue == "" { + continue + } + // ConfigAccessTagWriteRestrictable trumps all other permissions + if tagValue == model.ConfigAccessTagWriteRestrictable { + if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin && accessType == filterTypeWrite { + return false + } + continue + } + } + + // another iteration for permissions checks of other tag values + for _, val := range tagPermissions { + tagValue := strings.TrimSpace(val) + if tagValue == "" { + continue + } + if tagValue == model.ConfigAccessTagWriteRestrictable { + continue + } + permissionID := fmt.Sprintf("sysconsole_%s_%s", accessType, tagValue) + if permission, ok := permissionMap[permissionID]; ok { + if c.App.SessionHasPermissionTo(*c.App.Session(), permission) { + return true + } + } else { + mlog.Warn("Unrecognized config permissions tag value.", mlog.String("tag_value", permissionID)) + } + } + + // with manage_system, default to allow, otherwise default not-allow + return c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) + } } func migrateConfig(c *Context, w http.ResponseWriter, r *http.Request) { diff --git a/api4/config_local.go b/api4/config_local.go index 275b693672..4f4d42b87d 100644 --- a/api4/config_local.go +++ b/api4/config_local.go @@ -14,12 +14,21 @@ import ( ) func (api *API) InitConfigLocal() { - api.BaseRoutes.ApiRoot.Handle("/config", api.ApiLocal(getConfig)).Methods("GET") + api.BaseRoutes.ApiRoot.Handle("/config", api.ApiLocal(localGetConfig)).Methods("GET") api.BaseRoutes.ApiRoot.Handle("/config", api.ApiLocal(localUpdateConfig)).Methods("PUT") api.BaseRoutes.ApiRoot.Handle("/config/patch", api.ApiLocal(localPatchConfig)).Methods("PUT") api.BaseRoutes.ApiRoot.Handle("/config/migrate", api.ApiLocal(migrateConfig)).Methods("POST") } +func localGetConfig(c *Context, w http.ResponseWriter, r *http.Request) { + auditRec := c.MakeAuditRecord("localGetConfig", audit.Fail) + defer c.LogAuditRec(auditRec) + cfg := c.App.GetSanitizedConfig() + auditRec.Success() + w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") + w.Write([]byte(cfg.ToJson())) +} + func localUpdateConfig(c *Context, w http.ResponseWriter, r *http.Request) { cfg := model.ConfigFromJson(r.Body) if cfg == nil { diff --git a/api4/config_test.go b/api4/config_test.go index 196df28295..cd999ec79c 100644 --- a/api4/config_test.go +++ b/api4/config_test.go @@ -4,6 +4,7 @@ package api4 import ( + "fmt" "net/http" "os" "strings" @@ -54,6 +55,43 @@ func TestGetConfig(t *testing.T) { }) } +func TestGetConfigWithAccessTag(t *testing.T) { + th := Setup(t) + defer th.TearDown() + + varyByHeader := *&th.App.Config().RateLimitSettings.VaryByHeader // environment perm. + supportEmail := *&th.App.Config().SupportSettings.SupportEmail // site perm. + defer th.App.UpdateConfig(func(cfg *model.Config) { + cfg.RateLimitSettings.VaryByHeader = varyByHeader + cfg.SupportSettings.SupportEmail = supportEmail + }) + + // set some values so that we know they're not blank + mockVaryByHeader := model.NewId() + mockSupportEmail := model.NewId() + "@mattermost.com" + th.App.UpdateConfig(func(cfg *model.Config) { + cfg.RateLimitSettings.VaryByHeader = mockVaryByHeader + cfg.SupportSettings.SupportEmail = &mockSupportEmail + }) + + th.Client.Login(th.BasicUser.Username, th.BasicUser.Password) + + // add read sysconsole environment config + th.AddPermissionToRole(model.PERMISSION_SYSCONSOLE_READ_ENVIRONMENT.Id, model.SYSTEM_USER_ROLE_ID) + defer th.RemovePermissionFromRole(model.PERMISSION_SYSCONSOLE_READ_ENVIRONMENT.Id, model.SYSTEM_USER_ROLE_ID) + + cfg, resp := th.Client.GetConfig() + CheckNoError(t, resp) + + t.Run("Cannot read value without permission", func(t *testing.T) { + assert.Nil(t, cfg.SupportSettings.SupportEmail) + }) + + t.Run("Can read value with permission", func(t *testing.T) { + assert.Equal(t, mockVaryByHeader, cfg.RateLimitSettings.VaryByHeader) + }) +} + func TestReloadConfig(t *testing.T) { th := Setup(t) defer th.TearDown() @@ -108,7 +146,7 @@ func TestUpdateConfig(t *testing.T) { require.Equal(t, SiteName, cfg.TeamSettings.SiteName, "It should update the SiteName") t.Run("Should set defaults for missing fields", func(t *testing.T) { - _, appErr := th.SystemAdminClient.DoApiPut(th.SystemAdminClient.GetConfigRoute(), `{"ServiceSettings":{}}`) + _, appErr := th.SystemAdminClient.DoApiPut(th.SystemAdminClient.GetConfigRoute(), fmt.Sprintf(`{"ServiceSettings":{"SiteURL":"%s"}}`, *cfg.ServiceSettings.SiteURL)) require.Nil(t, appErr) }) @@ -179,6 +217,88 @@ func TestUpdateConfig(t *testing.T) { }) } +func TestGetConfigWithoutManageSystemPermission(t *testing.T) { + th := Setup(t) + defer th.TearDown() + th.Client.Login(th.BasicUser.Username, th.BasicUser.Password) + + t.Run("any sysconsole read permission provides config read access", func(t *testing.T) { + // forbidden by default + _, resp := th.Client.GetConfig() + CheckForbiddenStatus(t, resp) + + // add any sysconsole read permission + th.AddPermissionToRole(model.SysconsoleReadPermissions[0].Id, model.SYSTEM_USER_ROLE_ID) + _, resp = th.Client.GetConfig() + + // should be readable now + CheckNoError(t, resp) + }) +} + +func TestUpdateConfigWithoutManageSystemPermission(t *testing.T) { + th := Setup(t) + defer th.TearDown() + th.Client.Login(th.BasicUser.Username, th.BasicUser.Password) + + // add read sysconsole integrations config + th.AddPermissionToRole(model.PERMISSION_SYSCONSOLE_READ_INTEGRATIONS.Id, model.SYSTEM_USER_ROLE_ID) + defer th.RemovePermissionFromRole(model.PERMISSION_SYSCONSOLE_READ_INTEGRATIONS.Id, model.SYSTEM_USER_ROLE_ID) + + t.Run("sysconsole read permission does not provides config write access", func(t *testing.T) { + // should be readable because has a sysconsole read permission + cfg, resp := th.Client.GetConfig() + CheckNoError(t, resp) + + _, resp = th.Client.UpdateConfig(cfg) + + CheckForbiddenStatus(t, resp) + }) + + t.Run("the wrong write permission does not grant access", func(t *testing.T) { + // should be readable because has a sysconsole read permission + cfg, resp := th.SystemAdminClient.GetConfig() + CheckNoError(t, resp) + + originalValue := *cfg.ServiceSettings.AllowCorsFrom + + // add the wrong write permission + th.AddPermissionToRole(model.PERMISSION_SYSCONSOLE_WRITE_ABOUT.Id, model.SYSTEM_USER_ROLE_ID) + defer th.RemovePermissionFromRole(model.PERMISSION_SYSCONSOLE_WRITE_ABOUT.Id, model.SYSTEM_USER_ROLE_ID) + + // try update a config value allowed by sysconsole WRITE integrations + mockVal := model.NewId() + cfg.ServiceSettings.AllowCorsFrom = &mockVal + _, resp = th.Client.UpdateConfig(cfg) + CheckNoError(t, resp) + + // ensure the config setting was not updated + cfg, resp = th.Client.GetConfig() + CheckNoError(t, resp) + assert.Equal(t, *cfg.ServiceSettings.AllowCorsFrom, originalValue) + }) + + t.Run("config value is writeable by specific system console permission", func(t *testing.T) { + // should be readable because has a sysconsole read permission + cfg, resp := th.SystemAdminClient.GetConfig() + CheckNoError(t, resp) + + th.AddPermissionToRole(model.PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS.Id, model.SYSTEM_USER_ROLE_ID) + defer th.RemovePermissionFromRole(model.PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS.Id, model.SYSTEM_USER_ROLE_ID) + + // try update a config value allowed by sysconsole WRITE integrations + mockVal := model.NewId() + cfg.ServiceSettings.AllowCorsFrom = &mockVal + _, resp = th.Client.UpdateConfig(cfg) + CheckNoError(t, resp) + + // ensure the config setting was updated + cfg, resp = th.Client.GetConfig() + CheckNoError(t, resp) + assert.Equal(t, *cfg.ServiceSettings.AllowCorsFrom, mockVal) + }) +} + func TestUpdateConfigMessageExportSpecialHandling(t *testing.T) { th := Setup(t) defer th.TearDown() diff --git a/api4/elasticsearch.go b/api4/elasticsearch.go index 1f2a159531..5fe590f36b 100644 --- a/api4/elasticsearch.go +++ b/api4/elasticsearch.go @@ -21,8 +21,8 @@ func testElasticsearch(c *Context, w http.ResponseWriter, r *http.Request) { cfg = c.App.Config() } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_ENVIRONMENT) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_ENVIRONMENT) return } @@ -31,6 +31,14 @@ func testElasticsearch(c *Context, w http.ResponseWriter, r *http.Request) { return } + // no sniffing for ports or passwords + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT) { + if (*cfg.ElasticsearchSettings.ConnectionUrl != *c.App.Config().ElasticsearchSettings.ConnectionUrl) || (*cfg.ElasticsearchSettings.Password != model.FAKE_SETTING) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT) + return + } + } + if err := c.App.TestElasticsearch(cfg); err != nil { c.Err = err return @@ -43,8 +51,8 @@ func purgeElasticsearchIndexes(c *Context, w http.ResponseWriter, r *http.Reques auditRec := c.MakeAuditRecord("purgeElasticsearchIndexes", audit.Fail) defer c.LogAuditRec(auditRec) - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT) return } diff --git a/api4/group.go b/api4/group.go index 396aa352cf..8134d67c97 100644 --- a/api4/group.go +++ b/api4/group.go @@ -88,8 +88,8 @@ func getGroup(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS) return } @@ -128,8 +128,8 @@ func patchGroup(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_GROUPS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_GROUPS) return } @@ -321,8 +321,8 @@ func getGroupSyncables(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS) return } @@ -474,7 +474,7 @@ func verifyLinkUnlinkPermission(c *Context, syncableType model.GroupSyncableType switch syncableType { case model.GroupSyncableTypeTeam: if !c.App.SessionHasPermissionToTeam(*c.App.Session(), syncableID, model.PERMISSION_MANAGE_TEAM) { - return c.App.MakePermissionError(model.PERMISSION_MANAGE_TEAM) + return c.App.MakePermissionError([]*model.Permission{model.PERMISSION_MANAGE_TEAM}) } case model.GroupSyncableTypeChannel: channel, err := c.App.GetChannel(syncableID) @@ -490,7 +490,7 @@ func verifyLinkUnlinkPermission(c *Context, syncableType model.GroupSyncableType } if !c.App.SessionHasPermissionToChannel(*c.App.Session(), syncableID, permission) { - return c.App.MakePermissionError(permission) + return c.App.MakePermissionError([]*model.Permission{permission}) } } @@ -508,8 +508,8 @@ func getGroupMembers(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS) return } @@ -545,8 +545,8 @@ func getGroupStats(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS) return } @@ -611,16 +611,16 @@ func getGroupsByChannel(c *Context, w http.ResponseWriter, r *http.Request) { return } - var permission *model.Permission channel, err := c.App.GetChannel(c.Params.ChannelId) if err != nil { c.Err = err return } + var permission *model.Permission if channel.Type == model.CHANNEL_PRIVATE { - permission = model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS + permission = model.PERMISSION_READ_PRIVATE_CHANNEL_GROUPS } else { - permission = model.PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS + permission = model.PERMISSION_READ_PUBLIC_CHANNEL_GROUPS } if !c.App.SessionHasPermissionToChannel(*c.App.Session(), c.Params.ChannelId, permission) { c.SetPermissionError(permission) diff --git a/api4/job.go b/api4/job.go index 34191febd8..bd28ea2c86 100644 --- a/api4/job.go +++ b/api4/job.go @@ -29,8 +29,8 @@ func getJob(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_JOBS) { - c.SetPermissionError(model.PERMISSION_MANAGE_JOBS) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_READ_JOBS) { + c.SetPermissionError(model.PERMISSION_READ_JOBS) return } @@ -67,8 +67,8 @@ func downloadJob(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_JOBS) { - c.SetPermissionError(model.PERMISSION_MANAGE_JOBS) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_READ_JOBS) { + c.SetPermissionError(model.PERMISSION_READ_JOBS) return } @@ -139,8 +139,8 @@ func getJobs(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_JOBS) { - c.SetPermissionError(model.PERMISSION_MANAGE_JOBS) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_READ_JOBS) { + c.SetPermissionError(model.PERMISSION_READ_JOBS) return } @@ -159,8 +159,8 @@ func getJobsByType(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_JOBS) { - c.SetPermissionError(model.PERMISSION_MANAGE_JOBS) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_READ_JOBS) { + c.SetPermissionError(model.PERMISSION_READ_JOBS) return } diff --git a/api4/ldap.go b/api4/ldap.go index fcf93806d8..41d649e975 100644 --- a/api4/ldap.go +++ b/api4/ldap.go @@ -43,8 +43,8 @@ func syncLdap(c *Context, w http.ResponseWriter, r *http.Request) { auditRec := c.MakeAuditRecord("syncLdap", audit.Fail) defer c.LogAuditRec(auditRec) - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION) return } @@ -60,8 +60,8 @@ func testLdap(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_AUTHENTICATION) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_AUTHENTICATION) return } @@ -74,8 +74,8 @@ func testLdap(c *Context, w http.ResponseWriter, r *http.Request) { } func getLdapGroups(c *Context, w http.ResponseWriter, r *http.Request) { - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS) return } @@ -131,8 +131,8 @@ func linkLdapGroup(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_GROUPS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_GROUPS) return } @@ -232,8 +232,8 @@ func unlinkLdapGroup(c *Context, w http.ResponseWriter, r *http.Request) { defer c.LogAuditRec(auditRec) auditRec.AddMeta("remote_id", c.Params.RemoteId) - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_GROUPS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_GROUPS) return } diff --git a/api4/license.go b/api4/license.go index 7708625cff..4b1202819c 100644 --- a/api4/license.go +++ b/api4/license.go @@ -36,7 +36,7 @@ func getClientLicense(c *Context, w http.ResponseWriter, r *http.Request) { var clientLicense map[string]string - if c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { + if c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_ABOUT) { clientLicense = c.App.Srv().ClientLicense() } else { clientLicense = c.App.Srv().GetSanitizedClientLicense() @@ -50,8 +50,8 @@ func addLicense(c *Context, w http.ResponseWriter, r *http.Request) { defer c.LogAuditRec(auditRec) c.LogAudit("attempt") - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_WRITE_ABOUT) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_WRITE_ABOUT) return } @@ -121,8 +121,8 @@ func removeLicense(c *Context, w http.ResponseWriter, r *http.Request) { defer c.LogAuditRec(auditRec) c.LogAudit("attempt") - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_WRITE_ABOUT) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_WRITE_ABOUT) return } @@ -147,8 +147,8 @@ func requestTrialLicense(c *Context, w http.ResponseWriter, r *http.Request) { defer c.LogAuditRec(auditRec) c.LogAudit("attempt") - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_WRITE_ABOUT) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_WRITE_ABOUT) return } diff --git a/api4/plugin.go b/api4/plugin.go index fb10d86afe..0ff1915606 100644 --- a/api4/plugin.go +++ b/api4/plugin.go @@ -50,8 +50,8 @@ func uploadPlugin(c *Context, w http.ResponseWriter, r *http.Request) { auditRec := c.MakeAuditRecord("uploadPlugin", audit.Fail) defer c.LogAuditRec(auditRec) - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_WRITE_PLUGINS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_WRITE_PLUGINS) return } @@ -101,8 +101,8 @@ func installPluginFromUrl(c *Context, w http.ResponseWriter, r *http.Request) { auditRec := c.MakeAuditRecord("installPluginFromUrl", audit.Fail) defer c.LogAuditRec(auditRec) - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_WRITE_PLUGINS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_WRITE_PLUGINS) return } @@ -134,8 +134,8 @@ func installMarketplacePlugin(c *Context, w http.ResponseWriter, r *http.Request auditRec := c.MakeAuditRecord("installMarketplacePlugin", audit.Fail) defer c.LogAuditRec(auditRec) - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_WRITE_PLUGINS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_WRITE_PLUGINS) return } @@ -166,8 +166,8 @@ func getPlugins(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_PLUGINS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_PLUGINS) return } @@ -186,8 +186,8 @@ func getPluginStatuses(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_PLUGINS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_PLUGINS) return } @@ -215,8 +215,8 @@ func removePlugin(c *Context, w http.ResponseWriter, r *http.Request) { defer c.LogAuditRec(auditRec) auditRec.AddMeta("plugin_id", c.Params.PluginId) - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_WRITE_PLUGINS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_WRITE_PLUGINS) return } @@ -267,8 +267,8 @@ func getMarketplacePlugins(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_PLUGINS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_PLUGINS) return } @@ -308,8 +308,8 @@ func enablePlugin(c *Context, w http.ResponseWriter, r *http.Request) { defer c.LogAuditRec(auditRec) auditRec.AddMeta("plugin_id", c.Params.PluginId) - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_WRITE_PLUGINS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_WRITE_PLUGINS) return } @@ -337,8 +337,8 @@ func disablePlugin(c *Context, w http.ResponseWriter, r *http.Request) { defer c.LogAuditRec(auditRec) auditRec.AddMeta("plugin_id", c.Params.PluginId) - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_WRITE_PLUGINS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_WRITE_PLUGINS) return } diff --git a/api4/role.go b/api4/role.go index 26ea67757b..842acae4c4 100644 --- a/api4/role.go +++ b/api4/role.go @@ -130,8 +130,8 @@ func patchRole(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_PERMISSIONS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_PERMISSIONS) return } diff --git a/api4/scheme.go b/api4/scheme.go index e65720af36..f764136107 100644 --- a/api4/scheme.go +++ b/api4/scheme.go @@ -36,8 +36,8 @@ func createScheme(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_PERMISSIONS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_PERMISSIONS) return } @@ -60,8 +60,8 @@ func getScheme(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_PERMISSIONS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_PERMISSIONS) return } @@ -75,8 +75,8 @@ func getScheme(c *Context, w http.ResponseWriter, r *http.Request) { } func getSchemes(c *Context, w http.ResponseWriter, r *http.Request) { - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_PERMISSIONS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_PERMISSIONS) return } @@ -101,8 +101,8 @@ func getTeamsForScheme(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_TEAMS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_TEAMS) return } @@ -132,8 +132,8 @@ func getChannelsForScheme(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_CHANNELS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_CHANNELS) return } @@ -184,8 +184,8 @@ func patchScheme(c *Context, w http.ResponseWriter, r *http.Request) { } auditRec.AddMeta("scheme", scheme) - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_PERMISSIONS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_PERMISSIONS) return } @@ -216,8 +216,8 @@ func deleteScheme(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_PERMISSIONS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_PERMISSIONS) return } diff --git a/api4/system.go b/api4/system.go index f58e7481b0..6586488692 100644 --- a/api4/system.go +++ b/api4/system.go @@ -147,8 +147,8 @@ func testEmail(c *Context, w http.ResponseWriter, r *http.Request) { cfg = c.App.Config() } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_ENVIRONMENT) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_ENVIRONMENT) return } @@ -167,8 +167,8 @@ func testEmail(c *Context, w http.ResponseWriter, r *http.Request) { } func testSiteURL(c *Context, w http.ResponseWriter, r *http.Request) { - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_ENVIRONMENT) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_ENVIRONMENT) return } @@ -183,6 +183,12 @@ func testSiteURL(c *Context, w http.ResponseWriter, r *http.Request) { c.SetInvalidParam("site_url") return } + + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT) && siteURL != *c.App.Config().ServiceSettings.SiteURL { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_ENVIRONMENT) + return + } + err := c.App.TestSiteURL(siteURL) if err != nil { c.Err = err @@ -196,8 +202,8 @@ func getAudits(c *Context, w http.ResponseWriter, r *http.Request) { auditRec := c.MakeAuditRecord("getAudits", audit.Fail) defer c.LogAuditRec(auditRec) - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_COMPLIANCE) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_COMPLIANCE) return } @@ -215,8 +221,8 @@ func getAudits(c *Context, w http.ResponseWriter, r *http.Request) { } func databaseRecycle(c *Context, w http.ResponseWriter, r *http.Request) { - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT) return } @@ -235,8 +241,8 @@ func databaseRecycle(c *Context, w http.ResponseWriter, r *http.Request) { } func invalidateCaches(c *Context, w http.ResponseWriter, r *http.Request) { - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT) return } @@ -264,8 +270,8 @@ func getLogs(c *Context, w http.ResponseWriter, r *http.Request) { auditRec := c.MakeAuditRecord("getLogs", audit.Fail) defer c.LogAuditRec(auditRec) - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_REPORTING) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_REPORTING) return } @@ -327,8 +333,12 @@ func getAnalytics(c *Context, w http.ResponseWriter, r *http.Request) { name = "standard" } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + permissions := []*model.Permission{ + model.PERMISSION_SYSCONSOLE_READ_REPORTING, + model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_USERS, + } + if !c.App.SessionHasPermissionToAny(*c.App.Session(), permissions) { + c.SetPermissionError(permissions...) return } @@ -367,8 +377,8 @@ func testS3(c *Context, w http.ResponseWriter, r *http.Request) { cfg = c.App.Config() } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_ENVIRONMENT) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_ENVIRONMENT) return } @@ -656,8 +666,8 @@ func restart(c *Context, w http.ResponseWriter, r *http.Request) { } func getWarnMetricsStatus(c *Context, w http.ResponseWriter, r *http.Request) { - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionToAny(*c.App.Session(), model.SysconsoleReadPermissions) { + c.SetPermissionError(model.SysconsoleReadPermissions...) return } diff --git a/api4/team.go b/api4/team.go index 449caf44ba..54b9ec298b 100644 --- a/api4/team.go +++ b/api4/team.go @@ -392,8 +392,8 @@ func getTeamsForUser(c *Context, w http.ResponseWriter, r *http.Request) { return } - if c.App.Session().UserId != c.Params.UserId && !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if c.App.Session().UserId != c.Params.UserId && !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_USERS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_USERS) return } @@ -503,8 +503,8 @@ func getTeamMembersForUser(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionToUser(*c.App.Session(), c.Params.UserId) { - c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS) + if !c.App.SessionHasPermissionToUser(*c.App.Session(), c.Params.UserId) && !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_READ_OTHER_USERS_TEAMS) { + c.SetPermissionError(model.PERMISSION_READ_OTHER_USERS_TEAMS) return } @@ -1477,8 +1477,8 @@ func updateTeamScheme(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionToTeam(*c.App.Session(), c.Params.TeamId, model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_PERMISSIONS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_PERMISSIONS) return } @@ -1537,8 +1537,8 @@ func teamMembersMinusGroupMembers(c *Context, w http.ResponseWriter, r *http.Req groupIDs = append(groupIDs, gid) } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS) return } diff --git a/api4/user.go b/api4/user.go index b2d14d1b67..43a4360a5f 100644 --- a/api4/user.go +++ b/api4/user.go @@ -756,8 +756,8 @@ func getUsers(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS) { + c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS) return } @@ -1225,6 +1225,18 @@ func updateUserRoles(c *Context, w http.ResponseWriter, r *http.Request) { return } + // require license feature to assign "new system roles" + for _, roleName := range strings.Fields(newRoles) { + for _, id := range model.NewSystemRoleIDs { + if roleName == id { + if license := c.App.Srv().License(); license == nil || !*license.Features.CustomPermissionsSchemes { + c.Err = model.NewAppError("updateUserRoles", "api.user.update_user_roles.license.app_error", nil, "", http.StatusBadRequest) + return + } + } + } + } + auditRec := c.MakeAuditRecord("updateUserRoles", audit.Fail) defer c.LogAuditRec(auditRec) auditRec.AddMeta("roles", newRoles) diff --git a/app/app_iface.go b/app/app_iface.go index 445b377415..41f84c204b 100644 --- a/app/app_iface.go +++ b/app/app_iface.go @@ -468,6 +468,7 @@ type AppIface interface { DoLogin(w http.ResponseWriter, r *http.Request, user *model.User, deviceId string, isMobile, isOAuthUser, isSaml bool) *model.AppError DoPostAction(postId, actionId, userId, selectedOption string) (string, *model.AppError) DoPostActionWithCookie(postId, actionId, userId, selectedOption string, cookie *model.PostActionCookie) (string, *model.AppError) + DoSystemConsoleRolesCreationMigration() DoUploadFile(now time.Time, rawTeamId string, rawChannelId string, rawUserId string, rawFilename string, data []byte) (*model.FileInfo, *model.AppError) DoUploadFileExpectModification(now time.Time, rawTeamId string, rawChannelId string, rawUserId string, rawFilename string, data []byte) (*model.FileInfo, []byte, *model.AppError) DownloadFromURL(downloadURL string) ([]byte, error) @@ -751,7 +752,7 @@ type AppIface interface { ListTeamCommands(teamId string) ([]*model.Command, *model.AppError) Log() *mlog.Logger LoginByOAuth(service string, userData io.Reader, teamId string) (*model.User, *model.AppError) - MakePermissionError(permission *model.Permission) *model.AppError + MakePermissionError(permissions []*model.Permission) *model.AppError MarkChannelsAsViewed(channelIds []string, userId string, currentSessionId string) (map[string]int64, *model.AppError) MaxPostSize() int MessageExport() einterfaces.MessageExportInterface @@ -872,6 +873,7 @@ type AppIface interface { Session() *model.Session SessionCacheLength() int SessionHasPermissionTo(session model.Session, permission *model.Permission) bool + SessionHasPermissionToAny(session model.Session, permissions []*model.Permission) bool SessionHasPermissionToCategory(session model.Session, userId, teamId, categoryId string) bool SessionHasPermissionToChannel(session model.Session, channelId string, permission *model.Permission) bool SessionHasPermissionToChannelByPost(session model.Session, postId string, permission *model.Permission) bool diff --git a/app/app_test.go b/app/app_test.go index 79f983e832..3b3819e03d 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -29,6 +29,14 @@ func TestAppRace(t *testing.T) { } */ +var allPermissionIDs []string + +func init() { + for _, perm := range model.AllPermissions { + allPermissionIDs = append(allPermissionIDs, perm.Id) + } +} + func TestUnitUpdateConfig(t *testing.T) { th := SetupWithStoreMock(t) defer th.TearDown() @@ -168,79 +176,14 @@ func TestDoAdvancedPermissionsMigration(t *testing.T) { model.PERMISSION_READ_USER_ACCESS_TOKEN.Id, model.PERMISSION_REVOKE_USER_ACCESS_TOKEN.Id, }, - "system_admin": { - model.PERMISSION_ASSIGN_SYSTEM_ADMIN_ROLE.Id, - model.PERMISSION_MANAGE_SYSTEM.Id, - model.PERMISSION_MANAGE_ROLES.Id, - model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, - model.PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id, - model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id, - model.PERMISSION_DELETE_PUBLIC_CHANNEL.Id, - model.PERMISSION_CREATE_PUBLIC_CHANNEL.Id, - model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, - model.PERMISSION_DELETE_PRIVATE_CHANNEL.Id, - model.PERMISSION_CREATE_PRIVATE_CHANNEL.Id, - model.PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH.Id, - model.PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS.Id, - model.PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS.Id, - model.PERMISSION_EDIT_OTHER_USERS.Id, - model.PERMISSION_EDIT_OTHERS_POSTS.Id, - model.PERMISSION_MANAGE_OAUTH.Id, - model.PERMISSION_INVITE_USER.Id, - model.PERMISSION_INVITE_GUEST.Id, - model.PERMISSION_PROMOTE_GUEST.Id, - model.PERMISSION_DEMOTE_TO_GUEST.Id, - model.PERMISSION_DELETE_POST.Id, - model.PERMISSION_DELETE_OTHERS_POSTS.Id, - model.PERMISSION_CREATE_TEAM.Id, - model.PERMISSION_ADD_USER_TO_TEAM.Id, - model.PERMISSION_LIST_USERS_WITHOUT_TEAM.Id, - model.PERMISSION_MANAGE_JOBS.Id, - model.PERMISSION_CREATE_POST_PUBLIC.Id, - model.PERMISSION_CREATE_POST_EPHEMERAL.Id, - model.PERMISSION_CREATE_USER_ACCESS_TOKEN.Id, - model.PERMISSION_READ_USER_ACCESS_TOKEN.Id, - model.PERMISSION_REVOKE_USER_ACCESS_TOKEN.Id, - model.PERMISSION_CREATE_BOT.Id, - model.PERMISSION_READ_BOTS.Id, - model.PERMISSION_READ_OTHERS_BOTS.Id, - model.PERMISSION_MANAGE_BOTS.Id, - model.PERMISSION_MANAGE_OTHERS_BOTS.Id, - model.PERMISSION_REMOVE_OTHERS_REACTIONS.Id, - model.PERMISSION_LIST_PRIVATE_TEAMS.Id, - model.PERMISSION_JOIN_PRIVATE_TEAMS.Id, - model.PERMISSION_VIEW_MEMBERS.Id, - model.PERMISSION_LIST_TEAM_CHANNELS.Id, - model.PERMISSION_JOIN_PUBLIC_CHANNELS.Id, - model.PERMISSION_READ_PUBLIC_CHANNEL.Id, - model.PERMISSION_VIEW_TEAM.Id, - model.PERMISSION_READ_CHANNEL.Id, - model.PERMISSION_ADD_REACTION.Id, - model.PERMISSION_REMOVE_REACTION.Id, - model.PERMISSION_UPLOAD_FILE.Id, - model.PERMISSION_GET_PUBLIC_LINK.Id, - model.PERMISSION_CREATE_POST.Id, - model.PERMISSION_USE_CHANNEL_MENTIONS.Id, - model.PERMISSION_USE_SLASH_COMMANDS.Id, - model.PERMISSION_REMOVE_USER_FROM_TEAM.Id, - model.PERMISSION_MANAGE_TEAM.Id, - model.PERMISSION_IMPORT_TEAM.Id, - model.PERMISSION_MANAGE_TEAM_ROLES.Id, - model.PERMISSION_MANAGE_CHANNEL_ROLES.Id, - model.PERMISSION_MANAGE_SLASH_COMMANDS.Id, - model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS.Id, - model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, - model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, - model.PERMISSION_USE_GROUP_MENTIONS.Id, - model.PERMISSION_EDIT_POST.Id, - }, + "system_admin": allPermissionIDs, } // Check the migration matches what's expected. for name, permissions := range expected1 { role, err := th.App.GetRoleByName(name) assert.Nil(t, err) - assert.Equal(t, role.Permissions, permissions) + assert.Equal(t, role.Permissions, permissions, fmt.Sprintf("role %q didn't match", name)) } // Add a license and change the policy config. restrictPublicChannel := *th.App.Config().TeamSettings.DEPRECATED_DO_NOT_USE_RestrictPublicChannelManagement @@ -360,72 +303,7 @@ func TestDoAdvancedPermissionsMigration(t *testing.T) { model.PERMISSION_READ_USER_ACCESS_TOKEN.Id, model.PERMISSION_REVOKE_USER_ACCESS_TOKEN.Id, }, - "system_admin": { - model.PERMISSION_ASSIGN_SYSTEM_ADMIN_ROLE.Id, - model.PERMISSION_MANAGE_SYSTEM.Id, - model.PERMISSION_MANAGE_ROLES.Id, - model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, - model.PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id, - model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id, - model.PERMISSION_DELETE_PUBLIC_CHANNEL.Id, - model.PERMISSION_CREATE_PUBLIC_CHANNEL.Id, - model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, - model.PERMISSION_DELETE_PRIVATE_CHANNEL.Id, - model.PERMISSION_CREATE_PRIVATE_CHANNEL.Id, - model.PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH.Id, - model.PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS.Id, - model.PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS.Id, - model.PERMISSION_EDIT_OTHER_USERS.Id, - model.PERMISSION_EDIT_OTHERS_POSTS.Id, - model.PERMISSION_MANAGE_OAUTH.Id, - model.PERMISSION_INVITE_USER.Id, - model.PERMISSION_INVITE_GUEST.Id, - model.PERMISSION_PROMOTE_GUEST.Id, - model.PERMISSION_DEMOTE_TO_GUEST.Id, - model.PERMISSION_DELETE_POST.Id, - model.PERMISSION_DELETE_OTHERS_POSTS.Id, - model.PERMISSION_CREATE_TEAM.Id, - model.PERMISSION_ADD_USER_TO_TEAM.Id, - model.PERMISSION_LIST_USERS_WITHOUT_TEAM.Id, - model.PERMISSION_MANAGE_JOBS.Id, - model.PERMISSION_CREATE_POST_PUBLIC.Id, - model.PERMISSION_CREATE_POST_EPHEMERAL.Id, - model.PERMISSION_CREATE_USER_ACCESS_TOKEN.Id, - model.PERMISSION_READ_USER_ACCESS_TOKEN.Id, - model.PERMISSION_REVOKE_USER_ACCESS_TOKEN.Id, - model.PERMISSION_CREATE_BOT.Id, - model.PERMISSION_READ_BOTS.Id, - model.PERMISSION_READ_OTHERS_BOTS.Id, - model.PERMISSION_MANAGE_BOTS.Id, - model.PERMISSION_MANAGE_OTHERS_BOTS.Id, - model.PERMISSION_REMOVE_OTHERS_REACTIONS.Id, - model.PERMISSION_LIST_PRIVATE_TEAMS.Id, - model.PERMISSION_JOIN_PRIVATE_TEAMS.Id, - model.PERMISSION_VIEW_MEMBERS.Id, - model.PERMISSION_LIST_TEAM_CHANNELS.Id, - model.PERMISSION_JOIN_PUBLIC_CHANNELS.Id, - model.PERMISSION_READ_PUBLIC_CHANNEL.Id, - model.PERMISSION_VIEW_TEAM.Id, - model.PERMISSION_READ_CHANNEL.Id, - model.PERMISSION_ADD_REACTION.Id, - model.PERMISSION_REMOVE_REACTION.Id, - model.PERMISSION_UPLOAD_FILE.Id, - model.PERMISSION_GET_PUBLIC_LINK.Id, - model.PERMISSION_CREATE_POST.Id, - model.PERMISSION_USE_CHANNEL_MENTIONS.Id, - model.PERMISSION_USE_SLASH_COMMANDS.Id, - model.PERMISSION_REMOVE_USER_FROM_TEAM.Id, - model.PERMISSION_MANAGE_TEAM.Id, - model.PERMISSION_IMPORT_TEAM.Id, - model.PERMISSION_MANAGE_TEAM_ROLES.Id, - model.PERMISSION_MANAGE_CHANNEL_ROLES.Id, - model.PERMISSION_MANAGE_SLASH_COMMANDS.Id, - model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS.Id, - model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, - model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, - model.PERMISSION_USE_GROUP_MENTIONS.Id, - model.PERMISSION_EDIT_POST.Id, - }, + "system_admin": allPermissionIDs, } roles3, err3 := th.App.GetRolesByNames(roleNames) @@ -509,75 +387,7 @@ func TestDoEmojisPermissionsMigration(t *testing.T) { th.ResetEmojisMigration() th.App.DoEmojisPermissionsMigration() - expectedSystemAdmin := []string{ - model.PERMISSION_ASSIGN_SYSTEM_ADMIN_ROLE.Id, - model.PERMISSION_MANAGE_SYSTEM.Id, - model.PERMISSION_MANAGE_ROLES.Id, - model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, - model.PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id, - model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id, - model.PERMISSION_DELETE_PUBLIC_CHANNEL.Id, - model.PERMISSION_CREATE_PUBLIC_CHANNEL.Id, - model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, - model.PERMISSION_DELETE_PRIVATE_CHANNEL.Id, - model.PERMISSION_CREATE_PRIVATE_CHANNEL.Id, - model.PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH.Id, - model.PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS.Id, - model.PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS.Id, - model.PERMISSION_EDIT_OTHER_USERS.Id, - model.PERMISSION_EDIT_OTHERS_POSTS.Id, - model.PERMISSION_MANAGE_OAUTH.Id, - model.PERMISSION_INVITE_USER.Id, - model.PERMISSION_INVITE_GUEST.Id, - model.PERMISSION_PROMOTE_GUEST.Id, - model.PERMISSION_DEMOTE_TO_GUEST.Id, - model.PERMISSION_DELETE_POST.Id, - model.PERMISSION_DELETE_OTHERS_POSTS.Id, - model.PERMISSION_CREATE_TEAM.Id, - model.PERMISSION_ADD_USER_TO_TEAM.Id, - model.PERMISSION_LIST_USERS_WITHOUT_TEAM.Id, - model.PERMISSION_MANAGE_JOBS.Id, - model.PERMISSION_CREATE_POST_PUBLIC.Id, - model.PERMISSION_CREATE_POST_EPHEMERAL.Id, - model.PERMISSION_CREATE_USER_ACCESS_TOKEN.Id, - model.PERMISSION_READ_USER_ACCESS_TOKEN.Id, - model.PERMISSION_REVOKE_USER_ACCESS_TOKEN.Id, - model.PERMISSION_CREATE_BOT.Id, - model.PERMISSION_READ_BOTS.Id, - model.PERMISSION_READ_OTHERS_BOTS.Id, - model.PERMISSION_MANAGE_BOTS.Id, - model.PERMISSION_MANAGE_OTHERS_BOTS.Id, - model.PERMISSION_REMOVE_OTHERS_REACTIONS.Id, - model.PERMISSION_LIST_PRIVATE_TEAMS.Id, - model.PERMISSION_JOIN_PRIVATE_TEAMS.Id, - model.PERMISSION_LIST_TEAM_CHANNELS.Id, - model.PERMISSION_JOIN_PUBLIC_CHANNELS.Id, - model.PERMISSION_READ_PUBLIC_CHANNEL.Id, - model.PERMISSION_VIEW_TEAM.Id, - model.PERMISSION_READ_CHANNEL.Id, - model.PERMISSION_ADD_REACTION.Id, - model.PERMISSION_REMOVE_REACTION.Id, - model.PERMISSION_UPLOAD_FILE.Id, - model.PERMISSION_GET_PUBLIC_LINK.Id, - model.PERMISSION_CREATE_POST.Id, - model.PERMISSION_USE_SLASH_COMMANDS.Id, - model.PERMISSION_REMOVE_USER_FROM_TEAM.Id, - model.PERMISSION_MANAGE_TEAM.Id, - model.PERMISSION_IMPORT_TEAM.Id, - model.PERMISSION_MANAGE_TEAM_ROLES.Id, - model.PERMISSION_MANAGE_CHANNEL_ROLES.Id, - model.PERMISSION_MANAGE_SLASH_COMMANDS.Id, - model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS.Id, - model.PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, - model.PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, - model.PERMISSION_EDIT_POST.Id, - model.PERMISSION_CREATE_EMOJIS.Id, - model.PERMISSION_DELETE_EMOJIS.Id, - model.PERMISSION_DELETE_OTHERS_EMOJIS.Id, - model.PERMISSION_VIEW_MEMBERS.Id, - model.PERMISSION_USE_CHANNEL_MENTIONS.Id, - model.PERMISSION_USE_GROUP_MENTIONS.Id, - } + expectedSystemAdmin := allPermissionIDs sort.Strings(expectedSystemAdmin) role1, err1 := th.App.GetRoleByName(model.SYSTEM_ADMIN_ROLE_ID) @@ -599,6 +409,8 @@ func TestDoEmojisPermissionsMigration(t *testing.T) { model.PERMISSION_MANAGE_TEAM.Id, model.PERMISSION_IMPORT_TEAM.Id, model.PERMISSION_MANAGE_TEAM_ROLES.Id, + model.PERMISSION_READ_PUBLIC_CHANNEL_GROUPS.Id, + model.PERMISSION_READ_PRIVATE_CHANNEL_GROUPS.Id, model.PERMISSION_MANAGE_CHANNEL_ROLES.Id, model.PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS.Id, model.PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS.Id, diff --git a/app/authorization.go b/app/authorization.go index ca24c977b2..7765e6242d 100644 --- a/app/authorization.go +++ b/app/authorization.go @@ -11,8 +11,13 @@ import ( "github.com/mattermost/mattermost-server/v5/model" ) -func (a *App) MakePermissionError(permission *model.Permission) *model.AppError { - return model.NewAppError("Permissions", "api.context.permissions.app_error", nil, "userId="+a.Session().UserId+", "+"permission="+permission.Id, http.StatusForbidden) +func (a *App) MakePermissionError(permissions []*model.Permission) *model.AppError { + permissionsStr := "permission=" + for _, permission := range permissions { + permissionsStr += permission.Id + permissionsStr += "," + } + return model.NewAppError("Permissions", "api.context.permissions.app_error", nil, "userId="+a.Session().UserId+", "+permissionsStr, http.StatusForbidden) } func (a *App) SessionHasPermissionTo(session model.Session, permission *model.Permission) bool { @@ -22,6 +27,15 @@ func (a *App) SessionHasPermissionTo(session model.Session, permission *model.Pe return a.RolesGrantPermission(session.GetUserRoles(), permission.Id) } +func (a *App) SessionHasPermissionToAny(session model.Session, permissions []*model.Permission) bool { + for _, perm := range permissions { + if a.SessionHasPermissionTo(session, perm) { + return true + } + } + return false +} + func (a *App) SessionHasPermissionToTeam(session model.Session, teamId string, permission *model.Permission) bool { if teamId == "" { return false @@ -44,9 +58,6 @@ func (a *App) SessionHasPermissionToChannel(session model.Session, channelId str if channelId == "" { return false } - if session.IsUnrestricted() { - return true - } ids, err := a.Srv().Store.Channel().GetAllChannelMembersForUser(session.UserId, true, true) @@ -61,14 +72,18 @@ func (a *App) SessionHasPermissionToChannel(session model.Session, channelId str } channel, err := a.GetChannel(channelId) - if err == nil && channel.TeamId != "" { - return a.SessionHasPermissionToTeam(session, channel.TeamId, permission) - } - if err != nil && err.StatusCode == http.StatusNotFound { return false } + if session.IsUnrestricted() { + return true + } + + if channel.TeamId != "" { + return a.SessionHasPermissionToTeam(session, channel.TeamId, permission) + } + return a.SessionHasPermissionTo(session, permission) } @@ -247,7 +262,7 @@ func (a *App) SessionHasPermissionToManageBot(session model.Session, botUserId s // the bot doesn't exist at all. return model.MakeBotNotFoundError(botUserId) } - return a.MakePermissionError(model.PERMISSION_MANAGE_BOTS) + return a.MakePermissionError([]*model.Permission{model.PERMISSION_MANAGE_BOTS}) } } else { if !a.SessionHasPermissionTo(session, model.PERMISSION_MANAGE_OTHERS_BOTS) { @@ -256,7 +271,7 @@ func (a *App) SessionHasPermissionToManageBot(session model.Session, botUserId s // pretend as if the bot doesn't exist at all. return model.MakeBotNotFoundError(botUserId) } - return a.MakePermissionError(model.PERMISSION_MANAGE_OTHERS_BOTS) + return a.MakePermissionError([]*model.Permission{model.PERMISSION_MANAGE_OTHERS_BOTS}) } } diff --git a/app/channel.go b/app/channel.go index ab42e23985..e7cbee9836 100644 --- a/app/channel.go +++ b/app/channel.go @@ -954,7 +954,7 @@ func buildChannelModerations(channelType string, memberRole *model.Role, guestRo } var channelModerations []*model.ChannelModeration - for _, permissionKey := range model.CHANNEL_MODERATED_PERMISSIONS { + for _, permissionKey := range model.ChannelModeratedPermissions { roles := &model.ChannelModeratedRoles{} roles.Members = &model.ChannelModeratedRole{ diff --git a/app/channel_test.go b/app/channel_test.go index c6774ed742..7a5b827b92 100644 --- a/app/channel_test.go +++ b/app/channel_test.go @@ -1465,10 +1465,10 @@ func TestPatchChannelModerationsForChannel(t *testing.T) { th.App.SetPhase2PermissionsMigrationStatus(true) channel := th.BasicChannel - createPosts := model.CHANNEL_MODERATED_PERMISSIONS[0] - createReactions := model.CHANNEL_MODERATED_PERMISSIONS[1] - manageMembers := model.CHANNEL_MODERATED_PERMISSIONS[2] - channelMentions := model.CHANNEL_MODERATED_PERMISSIONS[3] + createPosts := model.ChannelModeratedPermissions[0] + createReactions := model.ChannelModeratedPermissions[1] + manageMembers := model.ChannelModeratedPermissions[2] + channelMentions := model.ChannelModeratedPermissions[3] nonChannelModeratedPermission := model.PERMISSION_CREATE_BOT.Id diff --git a/app/import_validators.go b/app/import_validators.go index 31f429c3b3..fd6229b893 100644 --- a/app/import_validators.go +++ b/app/import_validators.go @@ -100,7 +100,7 @@ func validateRoleImportData(data *RoleImportData) *model.AppError { if data.Permissions != nil { for _, permission := range *data.Permissions { permissionValidated := false - for _, p := range model.ALL_PERMISSIONS { + for _, p := range append(model.AllPermissions, model.DeprecatedPermissions...) { if permission == p.Id { permissionValidated = true break diff --git a/app/migrations.go b/app/migrations.go index 501a0241ef..f8e7b12041 100644 --- a/app/migrations.go +++ b/app/migrations.go @@ -15,6 +15,7 @@ import ( const ADVANCED_PERMISSIONS_MIGRATION_KEY = "AdvancedPermissionsMigrationComplete" const EMOJIS_PERMISSIONS_MIGRATION_KEY = "EmojisPermissionsMigrationComplete" const GUEST_ROLES_CREATION_MIGRATION_KEY = "GuestRolesCreationMigrationComplete" +const SYSTEM_CONSOLE_ROLES_CREATION_MIGRATION_KEY = "SystemConsoleRolesCreationMigrationComplete" // This function migrates the default built in roles from code/config to the database. func (a *App) DoAdvancedPermissionsMigration() { @@ -241,11 +242,57 @@ func (a *App) DoGuestRolesCreationMigration() { } } +func (a *App) DoSystemConsoleRolesCreationMigration() { + // If the migration is already marked as completed, don't do it again. + if _, err := a.Srv().Store.System().GetByName(SYSTEM_CONSOLE_ROLES_CREATION_MIGRATION_KEY); err == nil { + return + } + + roles := model.MakeDefaultRoles() + + allSucceeded := true + if _, err := a.Srv().Store.Role().GetByName(model.SYSTEM_MANAGER_ROLE_ID); err != nil { + if _, err := a.Srv().Store.Role().Save(roles[model.SYSTEM_MANAGER_ROLE_ID]); err != nil { + mlog.Critical("Failed to create new role.", mlog.Err(err), mlog.String("role", model.SYSTEM_MANAGER_ROLE_ID)) + allSucceeded = false + } + } + if _, err := a.Srv().Store.Role().GetByName(model.SYSTEM_READ_ONLY_ADMIN_ROLE_ID); err != nil { + if _, err := a.Srv().Store.Role().Save(roles[model.SYSTEM_READ_ONLY_ADMIN_ROLE_ID]); err != nil { + mlog.Critical("Failed to create new role.", mlog.Err(err), mlog.String("role", model.SYSTEM_READ_ONLY_ADMIN_ROLE_ID)) + allSucceeded = false + } + } + if _, err := a.Srv().Store.Role().GetByName(model.SYSTEM_USER_MANAGER_ROLE_ID); err != nil { + if _, err := a.Srv().Store.Role().Save(roles[model.SYSTEM_USER_MANAGER_ROLE_ID]); err != nil { + mlog.Critical("Failed to create new role.", mlog.Err(err), mlog.String("role", model.SYSTEM_USER_MANAGER_ROLE_ID)) + allSucceeded = false + } + } + + if !allSucceeded { + return + } + + system := model.System{ + Name: SYSTEM_CONSOLE_ROLES_CREATION_MIGRATION_KEY, + Value: "true", + } + + if err := a.Srv().Store.System().Save(&system); err != nil { + mlog.Critical("Failed to mark system console roles creation migration as completed.", mlog.Err(err)) + } +} + func (a *App) DoAppMigrations() { a.DoAdvancedPermissionsMigration() a.DoEmojisPermissionsMigration() a.DoGuestRolesCreationMigration() + a.DoSystemConsoleRolesCreationMigration() // This migration always must be the last, because can be based on previous // migrations. For example, it needs the guest roles migration. - a.DoPermissionsMigrations() + err := a.DoPermissionsMigrations() + if err != nil { + mlog.Critical("(app.App).DoPermissionsMigrations failed", mlog.Err(err)) + } } diff --git a/app/opentracing/opentracing_layer.go b/app/opentracing/opentracing_layer.go index fce15f375a..5492af0143 100644 --- a/app/opentracing/opentracing_layer.go +++ b/app/opentracing/opentracing_layer.go @@ -3198,6 +3198,21 @@ func (a *OpenTracingAppLayer) DoPostActionWithCookie(postId string, actionId str return resultVar0, resultVar1 } +func (a *OpenTracingAppLayer) DoSystemConsoleRolesCreationMigration() { + origCtx := a.ctx + span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.DoSystemConsoleRolesCreationMigration") + + a.ctx = newCtx + a.app.Srv().Store.SetContext(newCtx) + defer func() { + a.app.Srv().Store.SetContext(origCtx) + a.ctx = origCtx + }() + + defer span.Finish() + a.app.DoSystemConsoleRolesCreationMigration() +} + func (a *OpenTracingAppLayer) DoUploadFile(now time.Time, rawTeamId string, rawChannelId string, rawUserId string, rawFilename string, data []byte) (*model.FileInfo, *model.AppError) { origCtx := a.ctx span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.DoUploadFile") @@ -10042,7 +10057,7 @@ func (a *OpenTracingAppLayer) MakeAuditRecord(event string, initialStatus string return resultVar0 } -func (a *OpenTracingAppLayer) MakePermissionError(permission *model.Permission) *model.AppError { +func (a *OpenTracingAppLayer) MakePermissionError(permissions []*model.Permission) *model.AppError { origCtx := a.ctx span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.MakePermissionError") @@ -10054,7 +10069,7 @@ func (a *OpenTracingAppLayer) MakePermissionError(permission *model.Permission) }() defer span.Finish() - resultVar0 := a.app.MakePermissionError(permission) + resultVar0 := a.app.MakePermissionError(permissions) if resultVar0 != nil { span.LogFields(spanlog.Error(resultVar0)) @@ -12793,6 +12808,23 @@ func (a *OpenTracingAppLayer) SessionHasPermissionTo(session model.Session, perm return resultVar0 } +func (a *OpenTracingAppLayer) SessionHasPermissionToAny(session model.Session, permissions []*model.Permission) bool { + origCtx := a.ctx + span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SessionHasPermissionToAny") + + a.ctx = newCtx + a.app.Srv().Store.SetContext(newCtx) + defer func() { + a.app.Srv().Store.SetContext(origCtx) + a.ctx = origCtx + }() + + defer span.Finish() + resultVar0 := a.app.SessionHasPermissionToAny(session, permissions) + + return resultVar0 +} + func (a *OpenTracingAppLayer) SessionHasPermissionToCategory(session model.Session, userId string, teamId string, categoryId string) bool { origCtx := a.ctx span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SessionHasPermissionToCategory") diff --git a/app/permissions_migrations.go b/app/permissions_migrations.go index 0062723c27..8291e84a5a 100644 --- a/app/permissions_migrations.go +++ b/app/permissions_migrations.go @@ -59,6 +59,13 @@ const ( PERMISSION_REMOVE_REACTION = "remove_reaction" PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS = "manage_public_channel_members" PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS = "manage_private_channel_members" + PERMISSION_READ_JOBS = "read_jobs" + PERMISSION_MANAGE_JOBS = "manage_jobs" + PERMISSION_READ_OTHER_USERS_TEAMS = "read_other_users_teams" + PERMISSION_EDIT_OTHER_USERS = "edit_other_users" + PERMISSION_READ_PUBLIC_CHANNEL_GROUPS = "read_public_channel_groups" + PERMISSION_READ_PRIVATE_CHANNEL_GROUPS = "read_private_channel_groups" + PERMISSION_EDIT_BRAND = "edit_brand" ) func isRole(roleName string) func(*model.Role, map[string]map[string]bool) bool { @@ -434,6 +441,54 @@ func (a *App) getAddUseGroupMentionsPermissionMigration() (permissionsMap, error }, nil } +func (a *App) getAddSystemConsolePermissionsMigration() (permissionsMap, error) { + transformations := []permissionTransformation{} + + permissionsToAdd := []string{} + for _, permission := range append(model.SysconsoleReadPermissions, model.SysconsoleWritePermissions...) { + permissionsToAdd = append(permissionsToAdd, permission.Id) + } + + // add the new permissions to system admin + transformations = append(transformations, + permissionTransformation{ + On: isRole(model.SYSTEM_ADMIN_ROLE_ID), + Add: permissionsToAdd, + }) + + // add read_jobs to all roles with manage_jobs + transformations = append(transformations, permissionTransformation{ + On: permissionExists(PERMISSION_MANAGE_JOBS), + Add: []string{PERMISSION_READ_JOBS}, + }) + + // add read_other_users_teams to all roles with edit_other_users + transformations = append(transformations, permissionTransformation{ + On: permissionExists(PERMISSION_EDIT_OTHER_USERS), + Add: []string{PERMISSION_READ_OTHER_USERS_TEAMS}, + }) + + // add read_public_channel_groups to all roles with manage_public_channel_members + transformations = append(transformations, permissionTransformation{ + On: permissionExists(PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS), + Add: []string{PERMISSION_READ_PUBLIC_CHANNEL_GROUPS}, + }) + + // add read_private_channel_groups to all roles with manage_private_channel_members + transformations = append(transformations, permissionTransformation{ + On: permissionExists(PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS), + Add: []string{PERMISSION_READ_PRIVATE_CHANNEL_GROUPS}, + }) + + // add edit_brand to all roles with manage_system + transformations = append(transformations, permissionTransformation{ + On: permissionExists(PERMISSION_MANAGE_SYSTEM), + Add: []string{PERMISSION_EDIT_BRAND}, + }) + + return transformations, nil +} + // DoPermissionsMigrations execute all the permissions migrations need by the current version. func (a *App) DoPermissionsMigrations() error { PermissionsMigrations := []struct { @@ -451,6 +506,7 @@ func (a *App) DoPermissionsMigrations() error { {Key: model.MIGRATION_KEY_ADD_MANAGE_GUESTS_PERMISSIONS, Migration: a.getAddManageGuestsPermissionsMigration}, {Key: model.MIGRATION_KEY_CHANNEL_MODERATIONS_PERMISSIONS, Migration: a.channelModerationPermissionsMigration}, {Key: model.MIGRATION_KEY_ADD_USE_GROUP_MENTIONS_PERMISSION, Migration: a.getAddUseGroupMentionsPermissionMigration}, + {Key: model.MIGRATION_KEY_ADD_SYSTEM_CONSOLE_PERMISSIONS, Migration: a.getAddSystemConsolePermissionsMigration}, } for _, migration := range PermissionsMigrations { diff --git a/i18n/en.json b/i18n/en.json index c6c9bc6f0c..a305e2d063 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -1110,10 +1110,18 @@ "id": "api.config.client.old_format.app_error", "translation": "New format for the client configuration is not supported yet. Please specify format=old in the query string." }, + { + "id": "api.config.get_config.restricted_merge.app_error", + "translation": "" + }, { "id": "api.config.migrate_config.app_error", "translation": "Failed to migrate config store." }, + { + "id": "api.config.patch_config.restricted_merge.app_error", + "translation": "" + }, { "id": "api.config.update_config.clear_siteurl.app_error", "translation": "Site URL cannot be cleared." @@ -3042,6 +3050,10 @@ "id": "api.user.update_user.accepted_guest_domain.app_error", "translation": "The email you provided does not belong to an accepted domain for guest accounts. Please contact your administrator or sign up with a different email." }, + { + "id": "api.user.update_user_roles.license.app_error", + "translation": "" + }, { "id": "api.user.upload_profile_user.array.app_error", "translation": "Empty array under 'image' in request." diff --git a/model/config.go b/model/config.go index f73c601959..1a2b698e5a 100644 --- a/model/config.go +++ b/model/config.go @@ -247,97 +247,97 @@ var ServerTLSSupportedCiphers = map[string]uint16{ } type ServiceSettings struct { - SiteURL *string `restricted:"true"` - WebsocketURL *string `restricted:"true"` - LicenseFileLocation *string `restricted:"true"` - ListenAddress *string `restricted:"true"` - ConnectionSecurity *string `restricted:"true"` - TLSCertFile *string `restricted:"true"` - TLSKeyFile *string `restricted:"true"` - TLSMinVer *string `restricted:"true"` - TLSStrictTransport *bool `restricted:"true"` - TLSStrictTransportMaxAge *int64 `restricted:"true"` - TLSOverwriteCiphers []string `restricted:"true"` - UseLetsEncrypt *bool `restricted:"true"` - LetsEncryptCertificateCacheFile *string `restricted:"true"` - Forward80To443 *bool `restricted:"true"` - TrustedProxyIPHeader []string `restricted:"true"` - ReadTimeout *int `restricted:"true"` - WriteTimeout *int `restricted:"true"` - IdleTimeout *int `restricted:"true"` - MaximumLoginAttempts *int `restricted:"true"` - GoroutineHealthThreshold *int `restricted:"true"` - GoogleDeveloperKey *string `restricted:"true"` - EnableOAuthServiceProvider *bool - EnableIncomingWebhooks *bool - EnableOutgoingWebhooks *bool - EnableCommands *bool - DEPRECATED_DO_NOT_USE_EnableOnlyAdminIntegrations *bool `json:"EnableOnlyAdminIntegrations" mapstructure:"EnableOnlyAdminIntegrations"` // This field is deprecated and must not be used. - EnablePostUsernameOverride *bool - EnablePostIconOverride *bool - EnableLinkPreviews *bool - EnableTesting *bool `restricted:"true"` - EnableDeveloper *bool `restricted:"true"` - EnableOpenTracing *bool `restricted:"true"` - EnableSecurityFixAlert *bool `restricted:"true"` - EnableInsecureOutgoingConnections *bool `restricted:"true"` - AllowedUntrustedInternalConnections *string `restricted:"true"` - EnableMultifactorAuthentication *bool - EnforceMultifactorAuthentication *bool - EnableUserAccessTokens *bool - AllowCorsFrom *string `restricted:"true"` - CorsExposedHeaders *string `restricted:"true"` - CorsAllowCredentials *bool `restricted:"true"` - CorsDebug *bool `restricted:"true"` - AllowCookiesForSubdomains *bool `restricted:"true"` - ExtendSessionLengthWithActivity *bool `restricted:"true"` - SessionLengthWebInDays *int `restricted:"true"` - SessionLengthMobileInDays *int `restricted:"true"` - SessionLengthSSOInDays *int `restricted:"true"` - SessionCacheInMinutes *int `restricted:"true"` - SessionIdleTimeoutInMinutes *int `restricted:"true"` - WebsocketSecurePort *int `restricted:"true"` - WebsocketPort *int `restricted:"true"` - WebserverMode *string `restricted:"true"` - EnableCustomEmoji *bool - EnableEmojiPicker *bool - EnableGifPicker *bool - GfycatApiKey *string - GfycatApiSecret *string - DEPRECATED_DO_NOT_USE_RestrictCustomEmojiCreation *string `json:"RestrictCustomEmojiCreation" mapstructure:"RestrictCustomEmojiCreation"` // This field is deprecated and must not be used. - DEPRECATED_DO_NOT_USE_RestrictPostDelete *string `json:"RestrictPostDelete" mapstructure:"RestrictPostDelete"` // This field is deprecated and must not be used. - DEPRECATED_DO_NOT_USE_AllowEditPost *string `json:"AllowEditPost" mapstructure:"AllowEditPost"` // This field is deprecated and must not be used. - PostEditTimeLimit *int - TimeBetweenUserTypingUpdatesMilliseconds *int64 `restricted:"true"` - EnablePostSearch *bool `restricted:"true"` - MinimumHashtagLength *int `restricted:"true"` - EnableUserTypingMessages *bool `restricted:"true"` - EnableChannelViewedMessages *bool `restricted:"true"` - EnableUserStatuses *bool `restricted:"true"` - ExperimentalEnableAuthenticationTransfer *bool `restricted:"true"` - ClusterLogTimeoutMilliseconds *int `restricted:"true"` - CloseUnusedDirectMessages *bool - EnablePreviewFeatures *bool - EnableTutorial *bool - ExperimentalEnableDefaultChannelLeaveJoinMessages *bool - ExperimentalGroupUnreadChannels *string - ExperimentalChannelOrganization *bool - ExperimentalChannelSidebarOrganization *string - ExperimentalDataPrefetch *bool - DEPRECATED_DO_NOT_USE_ImageProxyType *string `json:"ImageProxyType" mapstructure:"ImageProxyType"` // This field is deprecated and must not be used. - DEPRECATED_DO_NOT_USE_ImageProxyURL *string `json:"ImageProxyURL" mapstructure:"ImageProxyURL"` // This field is deprecated and must not be used. - DEPRECATED_DO_NOT_USE_ImageProxyOptions *string `json:"ImageProxyOptions" mapstructure:"ImageProxyOptions"` // This field is deprecated and must not be used. + SiteURL *string `access:"environment,authentication,write_restrictable"` + WebsocketURL *string `access:"write_restrictable"` + LicenseFileLocation *string `access:"write_restrictable"` + ListenAddress *string `access:"environment,write_restrictable"` + ConnectionSecurity *string `access:"environment,write_restrictable"` + TLSCertFile *string `access:"environment,write_restrictable"` + TLSKeyFile *string `access:"environment,write_restrictable"` + TLSMinVer *string `access:"write_restrictable"` + TLSStrictTransport *bool `access:"write_restrictable"` + TLSStrictTransportMaxAge *int64 `access:"write_restrictable"` + TLSOverwriteCiphers []string `access:"write_restrictable"` + UseLetsEncrypt *bool `access:"environment,write_restrictable"` + LetsEncryptCertificateCacheFile *string `access:"environment,write_restrictable"` + Forward80To443 *bool `access:"environment,write_restrictable"` + TrustedProxyIPHeader []string `access:"write_restrictable"` + ReadTimeout *int `access:"environment,write_restrictable"` + WriteTimeout *int `access:"environment,write_restrictable"` + IdleTimeout *int `access:"write_restrictable"` + MaximumLoginAttempts *int `access:"authentication,write_restrictable"` + GoroutineHealthThreshold *int `access:"write_restrictable"` + GoogleDeveloperKey *string `access:"site,write_restrictable"` + EnableOAuthServiceProvider *bool `access:"integrations"` + EnableIncomingWebhooks *bool `access:"integrations"` + EnableOutgoingWebhooks *bool `access:"integrations"` + EnableCommands *bool `access:"integrations"` + DEPRECATED_DO_NOT_USE_EnableOnlyAdminIntegrations *bool `json:"EnableOnlyAdminIntegrations" mapstructure:"EnableOnlyAdminIntegrations"` // This field is deprecated and must not be used. + EnablePostUsernameOverride *bool `access:"integrations"` + EnablePostIconOverride *bool `access:"integrations"` + EnableLinkPreviews *bool `access:"site"` + EnableTesting *bool `access:"environment,write_restrictable"` + EnableDeveloper *bool `access:"environment,write_restrictable"` + EnableOpenTracing *bool `access:"write_restrictable"` + EnableSecurityFixAlert *bool `access:"environment,write_restrictable"` + EnableInsecureOutgoingConnections *bool `access:"environment,write_restrictable"` + AllowedUntrustedInternalConnections *string `access:"environment,write_restrictable"` + EnableMultifactorAuthentication *bool `access:"authentication"` + EnforceMultifactorAuthentication *bool `access:"authentication"` + EnableUserAccessTokens *bool `access:"integrations"` + AllowCorsFrom *string `access:"integrations,write_restrictable"` + CorsExposedHeaders *string `access:"integrations,write_restrictable"` + CorsAllowCredentials *bool `access:"integrations,write_restrictable"` + CorsDebug *bool `access:"integrations,write_restrictable"` + AllowCookiesForSubdomains *bool `access:"write_restrictable"` + ExtendSessionLengthWithActivity *bool `access:"environment,write_restrictable"` + SessionLengthWebInDays *int `access:"environment,write_restrictable"` + SessionLengthMobileInDays *int `access:"environment,write_restrictable"` + SessionLengthSSOInDays *int `access:"environment,write_restrictable"` + SessionCacheInMinutes *int `access:"environment,write_restrictable"` + SessionIdleTimeoutInMinutes *int `access:"environment,write_restrictable"` + WebsocketSecurePort *int `access:"write_restrictable"` + WebsocketPort *int `access:"write_restrictable"` + WebserverMode *string `access:"environment,write_restrictable"` + EnableCustomEmoji *bool `access:"site"` + EnableEmojiPicker *bool `access:"site"` + EnableGifPicker *bool `access:"integrations"` + GfycatApiKey *string `access:"integrations"` + GfycatApiSecret *string `access:"integrations"` + DEPRECATED_DO_NOT_USE_RestrictCustomEmojiCreation *string `json:"RestrictCustomEmojiCreation" mapstructure:"RestrictCustomEmojiCreation"` // This field is deprecated and must not be used. + DEPRECATED_DO_NOT_USE_RestrictPostDelete *string `json:"RestrictPostDelete" mapstructure:"RestrictPostDelete"` // This field is deprecated and must not be used. + DEPRECATED_DO_NOT_USE_AllowEditPost *string `json:"AllowEditPost" mapstructure:"AllowEditPost"` // This field is deprecated and must not be used. + PostEditTimeLimit *int `access:"user_management_permissions"` + TimeBetweenUserTypingUpdatesMilliseconds *int64 `access:"experimental,write_restrictable"` + EnablePostSearch *bool `access:"write_restrictable"` + MinimumHashtagLength *int `access:"environment,write_restrictable"` + EnableUserTypingMessages *bool `access:"experimental,write_restrictable"` + EnableChannelViewedMessages *bool `access:"experimental,write_restrictable"` + EnableUserStatuses *bool `access:"write_restrictable"` + ExperimentalEnableAuthenticationTransfer *bool `access:"experimental,write_restrictable"` + ClusterLogTimeoutMilliseconds *int `access:"write_restrictable"` + CloseUnusedDirectMessages *bool `access:"experimental"` + EnablePreviewFeatures *bool `access:"experimental"` + EnableTutorial *bool `access:"experimental"` + ExperimentalEnableDefaultChannelLeaveJoinMessages *bool `access:"experimental"` + ExperimentalGroupUnreadChannels *string `access:"experimental"` + ExperimentalChannelOrganization *bool `access:"experimental"` + ExperimentalChannelSidebarOrganization *string `access:"experimental"` + ExperimentalDataPrefetch *bool `access:"experimental"` + DEPRECATED_DO_NOT_USE_ImageProxyType *string `json:"ImageProxyType" mapstructure:"ImageProxyType"` // This field is deprecated and must not be used. + DEPRECATED_DO_NOT_USE_ImageProxyURL *string `json:"ImageProxyURL" mapstructure:"ImageProxyURL"` // This field is deprecated and must not be used. + DEPRECATED_DO_NOT_USE_ImageProxyOptions *string `json:"ImageProxyOptions" mapstructure:"ImageProxyOptions"` // This field is deprecated and must not be used. EnableAPITeamDeletion *bool EnableAPIUserDeletion *bool + ExperimentalEnableHardenedMode *bool `access:"experimental"` + DisableLegacyMFA *bool `access:"write_restrictable"` + ExperimentalStrictCSRFEnforcement *bool `access:"experimental,write_restrictable"` + EnableEmailInvitations *bool `access:"authentication"` + DisableBotsWhenOwnerIsDeactivated *bool `access:"integrations,write_restrictable"` + EnableBotAccountCreation *bool `access:"integrations"` + EnableSVGs *bool `access:"site"` + EnableLatex *bool `access:"site"` EnableAPIChannelDeletion *bool - ExperimentalEnableHardenedMode *bool - DisableLegacyMFA *bool `restricted:"true"` - ExperimentalStrictCSRFEnforcement *bool `restricted:"true"` - EnableEmailInvitations *bool - DisableBotsWhenOwnerIsDeactivated *bool `restricted:"true"` - EnableBotAccountCreation *bool - EnableSVGs *bool - EnableLatex *bool EnableLocalMode *bool LocalModeSocketLocation *string } @@ -756,21 +756,21 @@ func (s *ServiceSettings) SetDefaults(isUpdate bool) { } type ClusterSettings struct { - Enable *bool `restricted:"true"` - ClusterName *string `restricted:"true"` - OverrideHostname *string `restricted:"true"` - NetworkInterface *string `restricted:"true"` - BindAddress *string `restricted:"true"` - AdvertiseAddress *string `restricted:"true"` - UseIpAddress *bool `restricted:"true"` - UseExperimentalGossip *bool `restricted:"true"` - EnableExperimentalGossipEncryption *bool `restricted:"true"` - ReadOnlyConfig *bool `restricted:"true"` - GossipPort *int `restricted:"true"` - StreamingPort *int `restricted:"true"` - MaxIdleConns *int `restricted:"true"` - MaxIdleConnsPerHost *int `restricted:"true"` - IdleConnTimeoutMilliseconds *int `restricted:"true"` + Enable *bool `access:"environment,write_restrictable"` + ClusterName *string `access:"environment,write_restrictable"` + OverrideHostname *string `access:"environment,write_restrictable"` + NetworkInterface *string `access:"environment,write_restrictable"` + BindAddress *string `access:"environment,write_restrictable"` + AdvertiseAddress *string `access:"environment,write_restrictable"` + UseIpAddress *bool `access:"environment,write_restrictable"` + UseExperimentalGossip *bool `access:"environment,write_restrictable"` + EnableExperimentalGossipEncryption *bool `access:"environment,write_restrictable"` + ReadOnlyConfig *bool `access:"environment,write_restrictable"` + GossipPort *int `access:"environment,write_restrictable"` + StreamingPort *int `access:"environment,write_restrictable"` + MaxIdleConns *int `access:"environment,write_restrictable"` + MaxIdleConnsPerHost *int `access:"environment,write_restrictable"` + IdleConnTimeoutMilliseconds *int `access:"environment,write_restrictable"` } func (s *ClusterSettings) SetDefaults() { @@ -836,9 +836,9 @@ func (s *ClusterSettings) SetDefaults() { } type MetricsSettings struct { - Enable *bool `restricted:"true"` - BlockProfileRate *int `restricted:"true"` - ListenAddress *string `restricted:"true"` + Enable *bool `access:"environment,write_restrictable"` + BlockProfileRate *int `access:"environment,write_restrictable"` + ListenAddress *string `access:"environment,write_restrictable"` } func (s *MetricsSettings) SetDefaults() { @@ -856,13 +856,13 @@ func (s *MetricsSettings) SetDefaults() { } type ExperimentalSettings struct { - ClientSideCertEnable *bool - ClientSideCertCheck *string - EnableClickToReply *bool `restricted:"true"` - LinkMetadataTimeoutMilliseconds *int64 `restricted:"true"` - RestrictSystemAdmin *bool `restricted:"true"` - CloudUserLimit *int64 `restricted:"true"` - UseNewSAMLLibrary *bool + ClientSideCertEnable *bool `access:"experimental"` + ClientSideCertCheck *string `access:"experimental"` + EnableClickToReply *bool `access:"experimental,write_restrictable"` + LinkMetadataTimeoutMilliseconds *int64 `access:"experimental,write_restrictable"` + RestrictSystemAdmin *bool `access:"experimental,write_restrictable"` + UseNewSAMLLibrary *bool `access:"experimental"` + CloudUserLimit *int64 `access:"experimental,write_restrictable"` } func (s *ExperimentalSettings) SetDefaults() { @@ -896,7 +896,7 @@ func (s *ExperimentalSettings) SetDefaults() { } type AnalyticsSettings struct { - MaxUsersForStatistics *int `restricted:"true"` + MaxUsersForStatistics *int `access:"write_restrictable"` } func (s *AnalyticsSettings) SetDefaults() { @@ -906,13 +906,13 @@ func (s *AnalyticsSettings) SetDefaults() { } type SSOSettings struct { - Enable *bool - Secret *string - Id *string - Scope *string - AuthEndpoint *string - TokenEndpoint *string - UserApiEndpoint *string + Enable *bool `access:"authentication"` + Secret *string `access:"authentication"` + Id *string `access:"authentication"` + Scope *string `access:"authentication"` + AuthEndpoint *string `access:"authentication"` + TokenEndpoint *string `access:"authentication"` + UserApiEndpoint *string `access:"authentication"` } func (s *SSOSettings) setDefaults(scope, authEndpoint, tokenEndpoint, userApiEndpoint string) { @@ -946,14 +946,14 @@ func (s *SSOSettings) setDefaults(scope, authEndpoint, tokenEndpoint, userApiEnd } type Office365Settings struct { - Enable *bool - Secret *string - Id *string - Scope *string - AuthEndpoint *string - TokenEndpoint *string - UserApiEndpoint *string - DirectoryId *string + Enable *bool `access:"authentication"` + Secret *string `access:"authentication"` + Id *string `access:"authentication"` + Scope *string `access:"authentication"` + AuthEndpoint *string `access:"authentication"` + TokenEndpoint *string `access:"authentication"` + UserApiEndpoint *string `access:"authentication"` + DirectoryId *string `access:"authentication"` } func (s *Office365Settings) setDefaults() { @@ -1003,17 +1003,17 @@ func (s *Office365Settings) SSOSettings() *SSOSettings { } type SqlSettings struct { - DriverName *string `restricted:"true"` - DataSource *string `restricted:"true"` - DataSourceReplicas []string `restricted:"true"` - DataSourceSearchReplicas []string `restricted:"true"` - MaxIdleConns *int `restricted:"true"` - ConnMaxLifetimeMilliseconds *int `restricted:"true"` - MaxOpenConns *int `restricted:"true"` - Trace *bool `restricted:"true"` - AtRestEncryptKey *string `restricted:"true"` - QueryTimeout *int `restricted:"true"` - DisableDatabaseSearch *bool `restricted:"true"` + DriverName *string `access:"environment,write_restrictable"` + DataSource *string `access:"environment,write_restrictable"` + DataSourceReplicas []string `access:"environment,write_restrictable"` + DataSourceSearchReplicas []string `access:"environment,write_restrictable"` + MaxIdleConns *int `access:"environment,write_restrictable"` + ConnMaxLifetimeMilliseconds *int `access:"environment,write_restrictable"` + MaxOpenConns *int `access:"environment,write_restrictable"` + Trace *bool `access:"environment,write_restrictable"` + AtRestEncryptKey *string `access:"environment,write_restrictable"` + QueryTimeout *int `access:"environment,write_restrictable"` + DisableDatabaseSearch *bool `access:"environment,write_restrictable"` } func (s *SqlSettings) SetDefaults(isUpdate bool) { @@ -1069,17 +1069,17 @@ func (s *SqlSettings) SetDefaults(isUpdate bool) { } type LogSettings struct { - EnableConsole *bool `restricted:"true"` - ConsoleLevel *string `restricted:"true"` - ConsoleJson *bool `restricted:"true"` - EnableFile *bool `restricted:"true"` - FileLevel *string `restricted:"true"` - FileJson *bool `restricted:"true"` - FileLocation *string `restricted:"true"` - EnableWebhookDebugging *bool `restricted:"true"` - EnableDiagnostics *bool `restricted:"true"` - EnableSentry *bool `restricted:"true"` - AdvancedLoggingConfig *string `restricted:"true"` + EnableConsole *bool `access:"environment,write_restrictable"` + ConsoleLevel *string `access:"environment,write_restrictable"` + ConsoleJson *bool `access:"environment,write_restrictable"` + EnableFile *bool `access:"environment,write_restrictable"` + FileLevel *string `access:"environment,write_restrictable"` + FileJson *bool `access:"environment,write_restrictable"` + FileLocation *string `access:"environment,write_restrictable"` + EnableWebhookDebugging *bool `access:"environment,write_restrictable"` + EnableDiagnostics *bool `access:"environment,write_restrictable"` + EnableSentry *bool `access:"environment,write_restrictable"` + AdvancedLoggingConfig *string `access:"environment,write_restrictable"` } func (s *LogSettings) SetDefaults() { @@ -1129,14 +1129,14 @@ func (s *LogSettings) SetDefaults() { } type ExperimentalAuditSettings struct { - FileEnabled *bool `restricted:"true"` - FileName *string `restricted:"true"` - FileMaxSizeMB *int `restricted:"true"` - FileMaxAgeDays *int `restricted:"true"` - FileMaxBackups *int `restricted:"true"` - FileCompress *bool `restricted:"true"` - FileMaxQueueSize *int `restricted:"true"` - AdvancedLoggingConfig *string `restricted:"true"` + FileEnabled *bool `access:"experimental,write_restrictable"` + FileName *string `access:"experimental,write_restrictable"` + FileMaxSizeMB *int `access:"experimental,write_restrictable"` + FileMaxAgeDays *int `access:"experimental,write_restrictable"` + FileMaxBackups *int `access:"experimental,write_restrictable"` + FileCompress *bool `access:"experimental,write_restrictable"` + FileMaxQueueSize *int `access:"experimental,write_restrictable"` + AdvancedLoggingConfig *string `access:"experimental,write_restrictable"` } func (s *ExperimentalAuditSettings) SetDefaults() { @@ -1174,14 +1174,14 @@ func (s *ExperimentalAuditSettings) SetDefaults() { } type NotificationLogSettings struct { - EnableConsole *bool `restricted:"true"` - ConsoleLevel *string `restricted:"true"` - ConsoleJson *bool `restricted:"true"` - EnableFile *bool `restricted:"true"` - FileLevel *string `restricted:"true"` - FileJson *bool `restricted:"true"` - FileLocation *string `restricted:"true"` - AdvancedLoggingConfig *string `restricted:"true"` + EnableConsole *bool `access:"write_restrictable"` + ConsoleLevel *string `access:"write_restrictable"` + ConsoleJson *bool `access:"write_restrictable"` + EnableFile *bool `access:"write_restrictable"` + FileLevel *string `access:"write_restrictable"` + FileJson *bool `access:"write_restrictable"` + FileLocation *string `access:"write_restrictable"` + AdvancedLoggingConfig *string `access:"write_restrictable"` } func (s *NotificationLogSettings) SetDefaults() { @@ -1219,11 +1219,11 @@ func (s *NotificationLogSettings) SetDefaults() { } type PasswordSettings struct { - MinimumLength *int - Lowercase *bool - Number *bool - Uppercase *bool - Symbol *bool + MinimumLength *int `access:"authentication"` + Lowercase *bool `access:"authentication"` + Number *bool `access:"authentication"` + Uppercase *bool `access:"authentication"` + Symbol *bool `access:"authentication"` } func (s *PasswordSettings) SetDefaults() { @@ -1249,25 +1249,25 @@ func (s *PasswordSettings) SetDefaults() { } type FileSettings struct { - EnableFileAttachments *bool - EnableMobileUpload *bool - EnableMobileDownload *bool - MaxFileSize *int64 - DriverName *string `restricted:"true"` - Directory *string `restricted:"true"` - EnablePublicLink *bool - PublicLinkSalt *string - InitialFont *string - AmazonS3AccessKeyId *string `restricted:"true"` - AmazonS3SecretAccessKey *string `restricted:"true"` - AmazonS3Bucket *string `restricted:"true"` - AmazonS3PathPrefix *string `restricted:"true"` - AmazonS3Region *string `restricted:"true"` - AmazonS3Endpoint *string `restricted:"true"` - AmazonS3SSL *bool `restricted:"true"` - AmazonS3SignV2 *bool `restricted:"true"` - AmazonS3SSE *bool `restricted:"true"` - AmazonS3Trace *bool `restricted:"true"` + EnableFileAttachments *bool `access:"site"` + EnableMobileUpload *bool `access:"site"` + EnableMobileDownload *bool `access:"site"` + MaxFileSize *int64 `access:"environment"` + DriverName *string `access:"environment,write_restrictable"` + Directory *string `access:"environment,write_restrictable"` + EnablePublicLink *bool `access:"site"` + PublicLinkSalt *string `access:"site"` + InitialFont *string `access:"environment"` + AmazonS3AccessKeyId *string `access:"environment,write_restrictable"` + AmazonS3SecretAccessKey *string `access:"environment,write_restrictable"` + AmazonS3Bucket *string `access:"environment,write_restrictable"` + AmazonS3PathPrefix *string `access:"environment,write_restrictable"` + AmazonS3Region *string `access:"environment,write_restrictable"` + AmazonS3Endpoint *string `access:"environment,write_restrictable"` + AmazonS3SSL *bool `access:"environment,write_restrictable"` + AmazonS3SignV2 *bool `access:"environment,write_restrictable"` + AmazonS3SSE *bool `access:"environment,write_restrictable"` + AmazonS3Trace *bool `access:"environment,write_restrictable"` } func (s *FileSettings) SetDefaults(isUpdate bool) { @@ -1358,36 +1358,36 @@ func (s *FileSettings) SetDefaults(isUpdate bool) { } type EmailSettings struct { - EnableSignUpWithEmail *bool - EnableSignInWithEmail *bool - EnableSignInWithUsername *bool - SendEmailNotifications *bool - UseChannelInEmailNotifications *bool - RequireEmailVerification *bool - FeedbackName *string - FeedbackEmail *string - ReplyToAddress *string - FeedbackOrganization *string - EnableSMTPAuth *bool `restricted:"true"` - SMTPUsername *string `restricted:"true"` - SMTPPassword *string `restricted:"true"` - SMTPServer *string `restricted:"true"` - SMTPPort *string `restricted:"true"` + EnableSignUpWithEmail *bool `access:"authentication"` + EnableSignInWithEmail *bool `access:"authentication"` + EnableSignInWithUsername *bool `access:"authentication"` + SendEmailNotifications *bool `access:"site"` + UseChannelInEmailNotifications *bool `access:"experimental"` + RequireEmailVerification *bool `access:"authentication"` + FeedbackName *string `access:"site"` + FeedbackEmail *string `access:"site"` + ReplyToAddress *string `access:"site"` + FeedbackOrganization *string `access:"site"` + EnableSMTPAuth *bool `access:"environment,write_restrictable"` + SMTPUsername *string `access:"environment,write_restrictable"` + SMTPPassword *string `access:"environment,write_restrictable"` + SMTPServer *string `access:"environment,write_restrictable"` + SMTPPort *string `access:"environment,write_restrictable"` SMTPServerTimeout *int - ConnectionSecurity *string `restricted:"true"` - SendPushNotifications *bool - PushNotificationServer *string - PushNotificationContents *string + ConnectionSecurity *string `access:"environment,write_restrictable"` + SendPushNotifications *bool `access:"environment"` + PushNotificationServer *string `access:"environment"` + PushNotificationContents *string `access:"site"` PushNotificationBuffer *int - EnableEmailBatching *bool - EmailBatchingBufferSize *int - EmailBatchingInterval *int - EnablePreviewModeBanner *bool - SkipServerCertificateVerification *bool `restricted:"true"` - EmailNotificationContentsType *string - LoginButtonColor *string - LoginButtonBorderColor *string - LoginButtonTextColor *string + EnableEmailBatching *bool `access:"site"` + EmailBatchingBufferSize *int `access:"experimental"` + EmailBatchingInterval *int `access:"experimental"` + EnablePreviewModeBanner *bool `access:"site"` + SkipServerCertificateVerification *bool `access:"environment,write_restrictable"` + EmailNotificationContentsType *string `access:"site"` + LoginButtonColor *string `access:"experimental"` + LoginButtonBorderColor *string `access:"experimental"` + LoginButtonTextColor *string `access:"experimental"` } func (s *EmailSettings) SetDefaults(isUpdate bool) { @@ -1533,13 +1533,13 @@ func (s *EmailSettings) SetDefaults(isUpdate bool) { } type RateLimitSettings struct { - Enable *bool `restricted:"true"` - PerSec *int `restricted:"true"` - MaxBurst *int `restricted:"true"` - MemoryStoreSize *int `restricted:"true"` - VaryByRemoteAddr *bool `restricted:"true"` - VaryByUser *bool `restricted:"true"` - VaryByHeader string `restricted:"true"` + Enable *bool `access:"environment,write_restrictable"` + PerSec *int `access:"environment,write_restrictable"` + MaxBurst *int `access:"environment,write_restrictable"` + MemoryStoreSize *int `access:"environment,write_restrictable"` + VaryByRemoteAddr *bool `access:"environment,write_restrictable"` + VaryByUser *bool `access:"environment,write_restrictable"` + VaryByHeader string `access:"environment,write_restrictable"` } func (s *RateLimitSettings) SetDefaults() { @@ -1569,8 +1569,8 @@ func (s *RateLimitSettings) SetDefaults() { } type PrivacySettings struct { - ShowEmailAddress *bool - ShowFullName *bool + ShowEmailAddress *bool `access:"site"` + ShowFullName *bool `access:"site"` } func (s *PrivacySettings) setDefaults() { @@ -1584,15 +1584,15 @@ func (s *PrivacySettings) setDefaults() { } type SupportSettings struct { - TermsOfServiceLink *string `restricted:"true"` - PrivacyPolicyLink *string `restricted:"true"` - AboutLink *string `restricted:"true"` - HelpLink *string `restricted:"true"` - ReportAProblemLink *string `restricted:"true"` - SupportEmail *string - CustomTermsOfServiceEnabled *bool - CustomTermsOfServiceReAcceptancePeriod *int - EnableAskCommunityLink *bool + TermsOfServiceLink *string `access:"site,write_restrictable"` + PrivacyPolicyLink *string `access:"site,write_restrictable"` + AboutLink *string `access:"site,write_restrictable"` + HelpLink *string `access:"site,write_restrictable"` + ReportAProblemLink *string `access:"site,write_restrictable"` + SupportEmail *string `access:"site"` + CustomTermsOfServiceEnabled *bool `access:"compliance"` + CustomTermsOfServiceReAcceptancePeriod *int `access:"compliance"` + EnableAskCommunityLink *bool `access:"site"` } func (s *SupportSettings) SetDefaults() { @@ -1654,11 +1654,11 @@ func (s *SupportSettings) SetDefaults() { } type AnnouncementSettings struct { - EnableBanner *bool - BannerText *string - BannerColor *string - BannerTextColor *string - AllowBannerDismissal *bool + EnableBanner *bool `access:"site"` + BannerText *string `access:"site"` + BannerColor *string `access:"site"` + BannerTextColor *string `access:"site"` + AllowBannerDismissal *bool `access:"site"` } func (s *AnnouncementSettings) SetDefaults() { @@ -1684,9 +1684,9 @@ func (s *AnnouncementSettings) SetDefaults() { } type ThemeSettings struct { - EnableThemeSelection *bool - DefaultTheme *string - AllowCustomThemes *bool + EnableThemeSelection *bool `access:"experimental"` + DefaultTheme *string `access:"experimental"` + AllowCustomThemes *bool `access:"experimental"` AllowedThemes []string } @@ -1709,38 +1709,38 @@ func (s *ThemeSettings) SetDefaults() { } type TeamSettings struct { - SiteName *string - MaxUsersPerTeam *int - DEPRECATED_DO_NOT_USE_EnableTeamCreation *bool `json:"EnableTeamCreation" mapstructure:"EnableTeamCreation"` // This field is deprecated and must not be used. - EnableUserCreation *bool - EnableOpenServer *bool - EnableUserDeactivation *bool - RestrictCreationToDomains *string - EnableCustomBrand *bool - CustomBrandText *string - CustomDescriptionText *string - RestrictDirectMessage *string - DEPRECATED_DO_NOT_USE_RestrictTeamInvite *string `json:"RestrictTeamInvite" mapstructure:"RestrictTeamInvite"` // This field is deprecated and must not be used. - DEPRECATED_DO_NOT_USE_RestrictPublicChannelManagement *string `json:"RestrictPublicChannelManagement" mapstructure:"RestrictPublicChannelManagement"` // This field is deprecated and must not be used. - DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManagement *string `json:"RestrictPrivateChannelManagement" mapstructure:"RestrictPrivateChannelManagement"` // This field is deprecated and must not be used. - DEPRECATED_DO_NOT_USE_RestrictPublicChannelCreation *string `json:"RestrictPublicChannelCreation" mapstructure:"RestrictPublicChannelCreation"` // This field is deprecated and must not be used. - DEPRECATED_DO_NOT_USE_RestrictPrivateChannelCreation *string `json:"RestrictPrivateChannelCreation" mapstructure:"RestrictPrivateChannelCreation"` // This field is deprecated and must not be used. - DEPRECATED_DO_NOT_USE_RestrictPublicChannelDeletion *string `json:"RestrictPublicChannelDeletion" mapstructure:"RestrictPublicChannelDeletion"` // This field is deprecated and must not be used. - DEPRECATED_DO_NOT_USE_RestrictPrivateChannelDeletion *string `json:"RestrictPrivateChannelDeletion" mapstructure:"RestrictPrivateChannelDeletion"` // This field is deprecated and must not be used. - DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManageMembers *string `json:"RestrictPrivateChannelManageMembers" mapstructure:"RestrictPrivateChannelManageMembers"` // This field is deprecated and must not be used. - EnableXToLeaveChannelsFromLHS *bool - UserStatusAwayTimeout *int64 - MaxChannelsPerTeam *int64 - MaxNotificationsPerChannel *int64 - EnableConfirmNotificationsToChannel *bool - TeammateNameDisplay *string - ExperimentalViewArchivedChannels *bool - ExperimentalEnableAutomaticReplies *bool - ExperimentalHideTownSquareinLHS *bool - ExperimentalTownSquareIsReadOnly *bool - LockTeammateNameDisplay *bool - ExperimentalPrimaryTeam *string - ExperimentalDefaultChannels []string + SiteName *string `access:"site"` + MaxUsersPerTeam *int `access:"site"` + DEPRECATED_DO_NOT_USE_EnableTeamCreation *bool `json:"EnableTeamCreation" mapstructure:"EnableTeamCreation"` // This field is deprecated and must not be used. + EnableUserCreation *bool `access:"authentication"` + EnableOpenServer *bool `access:"authentication"` + EnableUserDeactivation *bool `access:"experimental"` + RestrictCreationToDomains *string `access:"authentication"` + EnableCustomBrand *bool `access:"site"` + CustomBrandText *string `access:"site"` + CustomDescriptionText *string `access:"site"` + RestrictDirectMessage *string `access:"site"` + DEPRECATED_DO_NOT_USE_RestrictTeamInvite *string `json:"RestrictTeamInvite" mapstructure:"RestrictTeamInvite"` // This field is deprecated and must not be used. + DEPRECATED_DO_NOT_USE_RestrictPublicChannelManagement *string `json:"RestrictPublicChannelManagement" mapstructure:"RestrictPublicChannelManagement"` // This field is deprecated and must not be used. + DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManagement *string `json:"RestrictPrivateChannelManagement" mapstructure:"RestrictPrivateChannelManagement"` // This field is deprecated and must not be used. + DEPRECATED_DO_NOT_USE_RestrictPublicChannelCreation *string `json:"RestrictPublicChannelCreation" mapstructure:"RestrictPublicChannelCreation"` // This field is deprecated and must not be used. + DEPRECATED_DO_NOT_USE_RestrictPrivateChannelCreation *string `json:"RestrictPrivateChannelCreation" mapstructure:"RestrictPrivateChannelCreation"` // This field is deprecated and must not be used. + DEPRECATED_DO_NOT_USE_RestrictPublicChannelDeletion *string `json:"RestrictPublicChannelDeletion" mapstructure:"RestrictPublicChannelDeletion"` // This field is deprecated and must not be used. + DEPRECATED_DO_NOT_USE_RestrictPrivateChannelDeletion *string `json:"RestrictPrivateChannelDeletion" mapstructure:"RestrictPrivateChannelDeletion"` // This field is deprecated and must not be used. + DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManageMembers *string `json:"RestrictPrivateChannelManageMembers" mapstructure:"RestrictPrivateChannelManageMembers"` // This field is deprecated and must not be used. + EnableXToLeaveChannelsFromLHS *bool `access:"experimental"` + UserStatusAwayTimeout *int64 `access:"experimental"` + MaxChannelsPerTeam *int64 `access:"site"` + MaxNotificationsPerChannel *int64 `access:"environment"` + EnableConfirmNotificationsToChannel *bool `access:"site"` + TeammateNameDisplay *string `access:"site"` + ExperimentalViewArchivedChannels *bool `access:"experimental,site"` + ExperimentalEnableAutomaticReplies *bool `access:"experimental"` + ExperimentalHideTownSquareinLHS *bool `access:"experimental"` + ExperimentalTownSquareIsReadOnly *bool `access:"experimental"` + LockTeammateNameDisplay *bool `access:"site"` + ExperimentalPrimaryTeam *string `access:"experimental"` + ExperimentalDefaultChannels []string `access:"experimental"` } func (s *TeamSettings) SetDefaults() { @@ -1892,63 +1892,63 @@ func (s *TeamSettings) SetDefaults() { } type ClientRequirements struct { - AndroidLatestVersion string `restricted:"true"` - AndroidMinVersion string `restricted:"true"` - DesktopLatestVersion string `restricted:"true"` - DesktopMinVersion string `restricted:"true"` - IosLatestVersion string `restricted:"true"` - IosMinVersion string `restricted:"true"` + AndroidLatestVersion string `access:"write_restrictable"` + AndroidMinVersion string `access:"write_restrictable"` + DesktopLatestVersion string `access:"write_restrictable"` + DesktopMinVersion string `access:"write_restrictable"` + IosLatestVersion string `access:"write_restrictable"` + IosMinVersion string `access:"write_restrictable"` } type LdapSettings struct { // Basic - Enable *bool - EnableSync *bool - LdapServer *string - LdapPort *int - ConnectionSecurity *string - BaseDN *string - BindUsername *string - BindPassword *string + Enable *bool `access:"authentication"` + EnableSync *bool `access:"authentication"` + LdapServer *string `access:"authentication"` + LdapPort *int `access:"authentication"` + ConnectionSecurity *string `access:"authentication"` + BaseDN *string `access:"authentication"` + BindUsername *string `access:"authentication"` + BindPassword *string `access:"authentication"` // Filtering - UserFilter *string - GroupFilter *string - GuestFilter *string - EnableAdminFilter *bool - AdminFilter *string + UserFilter *string `access:"authentication"` + GroupFilter *string `access:"authentication"` + GuestFilter *string `access:"authentication"` + EnableAdminFilter *bool `access:"authentication"` + AdminFilter *string `access:"authentication"` // Group Mapping - GroupDisplayNameAttribute *string - GroupIdAttribute *string + GroupDisplayNameAttribute *string `access:"authentication"` + GroupIdAttribute *string `access:"authentication"` // User Mapping - FirstNameAttribute *string - LastNameAttribute *string - EmailAttribute *string - UsernameAttribute *string - NicknameAttribute *string - IdAttribute *string - PositionAttribute *string - LoginIdAttribute *string - PictureAttribute *string + FirstNameAttribute *string `access:"authentication"` + LastNameAttribute *string `access:"authentication"` + EmailAttribute *string `access:"authentication"` + UsernameAttribute *string `access:"authentication"` + NicknameAttribute *string `access:"authentication"` + IdAttribute *string `access:"authentication"` + PositionAttribute *string `access:"authentication"` + LoginIdAttribute *string `access:"authentication"` + PictureAttribute *string `access:"authentication"` // Synchronization - SyncIntervalMinutes *int + SyncIntervalMinutes *int `access:"authentication"` // Advanced - SkipCertificateVerification *bool - QueryTimeout *int - MaxPageSize *int + SkipCertificateVerification *bool `access:"authentication"` + QueryTimeout *int `access:"authentication"` + MaxPageSize *int `access:"authentication"` // Customization - LoginFieldName *string + LoginFieldName *string `access:"authentication"` - LoginButtonColor *string - LoginButtonBorderColor *string - LoginButtonTextColor *string + LoginButtonColor *string `access:"authentication"` + LoginButtonBorderColor *string `access:"authentication"` + LoginButtonTextColor *string `access:"authentication"` - Trace *bool + Trace *bool `access:"authentication"` } func (s *LdapSettings) SetDefaults() { @@ -2089,9 +2089,9 @@ func (s *LdapSettings) SetDefaults() { } type ComplianceSettings struct { - Enable *bool - Directory *string - EnableDaily *bool + Enable *bool `access:"compliance"` + Directory *string `access:"compliance"` + EnableDaily *bool `access:"compliance"` } func (s *ComplianceSettings) SetDefaults() { @@ -2109,9 +2109,9 @@ func (s *ComplianceSettings) SetDefaults() { } type LocalizationSettings struct { - DefaultServerLocale *string - DefaultClientLocale *string - AvailableLocales *string + DefaultServerLocale *string `access:"site"` + DefaultClientLocale *string `access:"site"` + AvailableLocales *string `access:"site"` } func (s *LocalizationSettings) SetDefaults() { @@ -2130,48 +2130,48 @@ func (s *LocalizationSettings) SetDefaults() { type SamlSettings struct { // Basic - Enable *bool - EnableSyncWithLdap *bool - EnableSyncWithLdapIncludeAuth *bool + Enable *bool `access:"authentication"` + EnableSyncWithLdap *bool `access:"authentication"` + EnableSyncWithLdapIncludeAuth *bool `access:"authentication"` - Verify *bool - Encrypt *bool - SignRequest *bool + Verify *bool `access:"authentication"` + Encrypt *bool `access:"authentication"` + SignRequest *bool `access:"authentication"` - IdpUrl *string - IdpDescriptorUrl *string - IdpMetadataUrl *string - ServiceProviderIdentifier *string - AssertionConsumerServiceURL *string + IdpUrl *string `access:"authentication"` + IdpDescriptorUrl *string `access:"authentication"` + IdpMetadataUrl *string `access:"authentication"` + ServiceProviderIdentifier *string `access:"authentication"` + AssertionConsumerServiceURL *string `access:"authentication"` - SignatureAlgorithm *string - CanonicalAlgorithm *string + SignatureAlgorithm *string `access:"authentication"` + CanonicalAlgorithm *string `access:"authentication"` - ScopingIDPProviderId *string - ScopingIDPName *string + ScopingIDPProviderId *string `access:"authentication"` + ScopingIDPName *string `access:"authentication"` - IdpCertificateFile *string - PublicCertificateFile *string - PrivateKeyFile *string + IdpCertificateFile *string `access:"authentication"` + PublicCertificateFile *string `access:"authentication"` + PrivateKeyFile *string `access:"authentication"` // User Mapping - IdAttribute *string - GuestAttribute *string - EnableAdminAttribute *bool - AdminAttribute *string - FirstNameAttribute *string - LastNameAttribute *string - EmailAttribute *string - UsernameAttribute *string - NicknameAttribute *string - LocaleAttribute *string - PositionAttribute *string + IdAttribute *string `access:"authentication"` + GuestAttribute *string `access:"authentication"` + EnableAdminAttribute *bool `access:"authentication"` + AdminAttribute *string `access:"authentication"` + FirstNameAttribute *string `access:"authentication"` + LastNameAttribute *string `access:"authentication"` + EmailAttribute *string `access:"authentication"` + UsernameAttribute *string `access:"authentication"` + NicknameAttribute *string `access:"authentication"` + LocaleAttribute *string `access:"authentication"` + PositionAttribute *string `access:"authentication"` - LoginButtonText *string + LoginButtonText *string `access:"authentication"` - LoginButtonColor *string - LoginButtonBorderColor *string - LoginButtonTextColor *string + LoginButtonColor *string `access:"authentication"` + LoginButtonBorderColor *string `access:"authentication"` + LoginButtonTextColor *string `access:"authentication"` } func (s *SamlSettings) SetDefaults() { @@ -2311,9 +2311,9 @@ func (s *SamlSettings) SetDefaults() { } type NativeAppSettings struct { - AppDownloadLink *string `restricted:"true"` - AndroidAppDownloadLink *string `restricted:"true"` - IosAppDownloadLink *string `restricted:"true"` + AppDownloadLink *string `access:"site,write_restrictable"` + AndroidAppDownloadLink *string `access:"site,write_restrictable"` + IosAppDownloadLink *string `access:"site,write_restrictable"` } func (s *NativeAppSettings) SetDefaults() { @@ -2331,27 +2331,27 @@ func (s *NativeAppSettings) SetDefaults() { } type ElasticsearchSettings struct { - ConnectionUrl *string `restricted:"true"` - Username *string `restricted:"true"` - Password *string `restricted:"true"` - EnableIndexing *bool `restricted:"true"` - EnableSearching *bool `restricted:"true"` - EnableAutocomplete *bool `restricted:"true"` - Sniff *bool `restricted:"true"` - PostIndexReplicas *int `restricted:"true"` - PostIndexShards *int `restricted:"true"` - ChannelIndexReplicas *int `restricted:"true"` - ChannelIndexShards *int `restricted:"true"` - UserIndexReplicas *int `restricted:"true"` - UserIndexShards *int `restricted:"true"` - AggregatePostsAfterDays *int `restricted:"true"` - PostsAggregatorJobStartTime *string `restricted:"true"` - IndexPrefix *string `restricted:"true"` - LiveIndexingBatchSize *int `restricted:"true"` - BulkIndexingTimeWindowSeconds *int `restricted:"true"` - RequestTimeoutSeconds *int `restricted:"true"` - SkipTLSVerification *bool `restricted:"true"` - Trace *string `restricted:"true"` + ConnectionUrl *string `access:"environment,write_restrictable"` + Username *string `access:"environment,write_restrictable"` + Password *string `access:"environment,write_restrictable"` + EnableIndexing *bool `access:"environment,write_restrictable"` + EnableSearching *bool `access:"environment,write_restrictable"` + EnableAutocomplete *bool `access:"environment,write_restrictable"` + Sniff *bool `access:"environment,write_restrictable"` + PostIndexReplicas *int `access:"environment,write_restrictable"` + PostIndexShards *int `access:"environment,write_restrictable"` + ChannelIndexReplicas *int `access:"environment,write_restrictable"` + ChannelIndexShards *int `access:"environment,write_restrictable"` + UserIndexReplicas *int `access:"environment,write_restrictable"` + UserIndexShards *int `access:"environment,write_restrictable"` + AggregatePostsAfterDays *int `access:"environment,write_restrictable"` + PostsAggregatorJobStartTime *string `access:"environment,write_restrictable"` + IndexPrefix *string `access:"environment,write_restrictable"` + LiveIndexingBatchSize *int `access:"environment,write_restrictable"` + BulkIndexingTimeWindowSeconds *int `access:"environment,write_restrictable"` + RequestTimeoutSeconds *int `access:"environment,write_restrictable"` + SkipTLSVerification *bool `access:"environment,write_restrictable"` + Trace *string `access:"environment,write_restrictable"` } func (s *ElasticsearchSettings) SetDefaults() { @@ -2441,11 +2441,11 @@ func (s *ElasticsearchSettings) SetDefaults() { } type BleveSettings struct { - IndexDir *string - EnableIndexing *bool - EnableSearching *bool - EnableAutocomplete *bool - BulkIndexingTimeWindowSeconds *int + IndexDir *string `access:"experimental"` + EnableIndexing *bool `access:"experimental"` + EnableSearching *bool `access:"experimental"` + EnableAutocomplete *bool `access:"experimental"` + BulkIndexingTimeWindowSeconds *int `access:"experimental"` } func (bs *BleveSettings) SetDefaults() { @@ -2471,11 +2471,11 @@ func (bs *BleveSettings) SetDefaults() { } type DataRetentionSettings struct { - EnableMessageDeletion *bool - EnableFileDeletion *bool - MessageRetentionDays *int - FileRetentionDays *int - DeletionJobStartTime *string + EnableMessageDeletion *bool `access:"compliance"` + EnableFileDeletion *bool `access:"compliance"` + MessageRetentionDays *int `access:"compliance"` + FileRetentionDays *int `access:"compliance"` + DeletionJobStartTime *string `access:"compliance"` } func (s *DataRetentionSettings) SetDefaults() { @@ -2501,8 +2501,8 @@ func (s *DataRetentionSettings) SetDefaults() { } type JobSettings struct { - RunJobs *bool `restricted:"true"` - RunScheduler *bool `restricted:"true"` + RunJobs *bool `access:"write_restrictable"` + RunScheduler *bool `access:"write_restrictable"` } func (s *JobSettings) SetDefaults() { @@ -2520,20 +2520,20 @@ type PluginState struct { } type PluginSettings struct { - Enable *bool - EnableUploads *bool `restricted:"true"` - AllowInsecureDownloadUrl *bool `restricted:"true"` - EnableHealthCheck *bool `restricted:"true"` - Directory *string `restricted:"true"` - ClientDirectory *string `restricted:"true"` - Plugins map[string]map[string]interface{} - PluginStates map[string]*PluginState - EnableMarketplace *bool - EnableRemoteMarketplace *bool - AutomaticPrepackagedPlugins *bool - RequirePluginSignature *bool - MarketplaceUrl *string - SignaturePublicKeyFiles []string + Enable *bool `access:"plugins"` + EnableUploads *bool `access:"plugins,write_restrictable"` + AllowInsecureDownloadUrl *bool `access:"plugins,write_restrictable"` + EnableHealthCheck *bool `access:"plugins,write_restrictable"` + Directory *string `access:"plugins,write_restrictable"` + ClientDirectory *string `access:"plugins,write_restrictable"` + Plugins map[string]map[string]interface{} `access:"plugins"` + PluginStates map[string]*PluginState `access:"plugins"` + EnableMarketplace *bool `access:"plugins"` + EnableRemoteMarketplace *bool `access:"plugins"` + AutomaticPrepackagedPlugins *bool `access:"plugins"` + RequirePluginSignature *bool `access:"plugins"` + MarketplaceUrl *string `access:"plugins"` + SignaturePublicKeyFiles []string `access:"plugins"` } func (s *PluginSettings) SetDefaults(ls LogSettings) { @@ -2600,11 +2600,11 @@ func (s *PluginSettings) SetDefaults(ls LogSettings) { } type GlobalRelayMessageExportSettings struct { - CustomerType *string // must be either A9 or A10, dictates SMTP server url - SmtpUsername *string - SmtpPassword *string - EmailAddress *string // the address to send messages to - SMTPServerTimeout *int + CustomerType *string `access:"compliance"` // must be either A9 or A10, dictates SMTP server url + SmtpUsername *string `access:"compliance"` + SmtpPassword *string `access:"compliance"` + EmailAddress *string `access:"compliance"` // the address to send messages to + SMTPServerTimeout *int `access:"compliance"` } func (s *GlobalRelayMessageExportSettings) SetDefaults() { @@ -2626,12 +2626,12 @@ func (s *GlobalRelayMessageExportSettings) SetDefaults() { } type MessageExportSettings struct { - EnableExport *bool - DownloadExportResults *bool - ExportFormat *string - DailyRunTime *string - ExportFromTimestamp *int64 - BatchSize *int + EnableExport *bool `access:"compliance"` + ExportFormat *string `access:"compliance"` + DailyRunTime *string `access:"compliance"` + ExportFromTimestamp *int64 `access:"compliance"` + BatchSize *int `access:"compliance"` + DownloadExportResults *bool `access:"compliance"` // formatter-specific settings - these are only expected to be non-nil if ExportFormat is set to the associated format GlobalRelaySettings *GlobalRelayMessageExportSettings @@ -2669,8 +2669,8 @@ func (s *MessageExportSettings) SetDefaults() { } type DisplaySettings struct { - CustomUrlSchemes []string - ExperimentalTimezone *bool + CustomUrlSchemes []string `access:"site"` + ExperimentalTimezone *bool `access:"experimental"` } func (s *DisplaySettings) SetDefaults() { @@ -2685,10 +2685,10 @@ func (s *DisplaySettings) SetDefaults() { } type GuestAccountsSettings struct { - Enable *bool - AllowEmailAccounts *bool - EnforceMultifactorAuthentication *bool - RestrictCreationToDomains *string + Enable *bool `access:"authentication"` + AllowEmailAccounts *bool `access:"authentication"` + EnforceMultifactorAuthentication *bool `access:"authentication"` + RestrictCreationToDomains *string `access:"authentication"` } func (s *GuestAccountsSettings) SetDefaults() { @@ -2710,10 +2710,10 @@ func (s *GuestAccountsSettings) SetDefaults() { } type ImageProxySettings struct { - Enable *bool - ImageProxyType *string - RemoteImageProxyURL *string - RemoteImageProxyOptions *string + Enable *bool `access:"environment"` + ImageProxyType *string `access:"environment"` + RemoteImageProxyURL *string `access:"environment"` + RemoteImageProxyOptions *string `access:"environment"` } func (s *ImageProxySettings) SetDefaults(ss ServiceSettings) { @@ -2752,6 +2752,35 @@ func (s *ImageProxySettings) SetDefaults(ss ServiceSettings) { type ConfigFunc func() *Config +const ConfigAccessTagWriteRestrictable = "write_restrictable" + +// Config fields support the 'access' tag with the following values corresponding to the suffix of the associated +// PERMISSION_SYSCONSOLE_*_* permission Id: 'about', 'reporting', 'user_management_users', +// 'user_management_groups', 'user_management_teams', 'user_management_channels', +// 'user_management_permissions', 'environment', 'site', 'authentication', 'plugins', +// 'integrations', 'compliance', 'plugins', and 'experimental'. They grant read and/or write access to the config field +// to roles without PERMISSION_MANAGE_SYSTEM. +// +// By default config values can be written with PERMISSION_MANAGE_SYSTEM, but if ExperimentalSettings.RestrictSystemAdmin is true +// and the access tag contains the value 'write_restrictable', then even PERMISSION_MANAGE_SYSTEM does not grant write access. +// +// PERMISSION_MANAGE_SYSTEM always grants read access. +// +// Example: +// type HairSettings struct { +// // Colour is writeable with either PERMISSION_SYSCONSOLE_WRITE_REPORTING or PERMISSION_SYSCONSOLE_WRITE_USER_MANAGEMENT_GROUPS. +// // It is readable by PERMISSION_SYSCONSOLE_READ_REPORTING and PERMISSION_SYSCONSOLE_READ_USER_MANAGEMENT_GROUPS permissions. +// // PERMISSION_MANAGE_SYSTEM grants read and write access. +// Colour string `access:"reporting,user_management_groups"` +// +// +// // Length is only readable and writable via PERMISSION_MANAGE_SYSTEM. +// Length string +// +// // Product is only writeable by PERMISSION_MANAGE_SYSTEM if ExperimentalSettings.RestrictSystemAdmin is false. +// // PERMISSION_MANAGE_SYSTEM can always read the value. +// Product bool `access:write_restrictable` +// } type Config struct { ServiceSettings ServiceSettings TeamSettings TeamSettings diff --git a/model/migration.go b/model/migration.go index 7dd08bef6e..f0e24659ad 100644 --- a/model/migration.go +++ b/model/migration.go @@ -17,4 +17,6 @@ const ( MIGRATION_KEY_ADD_MANAGE_GUESTS_PERMISSIONS = "add_manage_guests_permissions" MIGRATION_KEY_CHANNEL_MODERATIONS_PERMISSIONS = "channel_moderations_permissions" MIGRATION_KEY_ADD_USE_GROUP_MENTIONS_PERMISSION = "add_use_group_mentions_permission" + MIGRATION_KEY_ADD_SYSTEM_CONSOLE_PERMISSIONS = "add_system_console_permissions" + MIGRATION_KEY_SIDEBAR_CATEGORIES_PHASE_2 = "migration_sidebar_categories_phase_2" ) diff --git a/model/permission.go b/model/permission.go index cc3c5a7085..dca3c6eddb 100644 --- a/model/permission.go +++ b/model/permission.go @@ -4,9 +4,9 @@ package model const ( - PERMISSION_SCOPE_SYSTEM = "system_scope" - PERMISSION_SCOPE_TEAM = "team_scope" - PERMISSION_SCOPE_CHANNEL = "channel_scope" + PermissionScopeSystem = "system_scope" + PermissionScopeTeam = "team_scope" + PermissionScopeChannel = "channel_scope" ) type Permission struct { @@ -43,6 +43,8 @@ var PERMISSION_DELETE_PUBLIC_CHANNEL *Permission var PERMISSION_DELETE_PRIVATE_CHANNEL *Permission var PERMISSION_EDIT_OTHER_USERS *Permission var PERMISSION_READ_CHANNEL *Permission +var PERMISSION_READ_PUBLIC_CHANNEL_GROUPS *Permission +var PERMISSION_READ_PRIVATE_CHANNEL_GROUPS *Permission var PERMISSION_READ_PUBLIC_CHANNEL *Permission var PERMISSION_ADD_REACTION *Permission var PERMISSION_REMOVE_REACTION *Permission @@ -76,6 +78,7 @@ var PERMISSION_MANAGE_TEAM *Permission var PERMISSION_IMPORT_TEAM *Permission var PERMISSION_VIEW_TEAM *Permission var PERMISSION_LIST_USERS_WITHOUT_TEAM *Permission +var PERMISSION_READ_JOBS *Permission var PERMISSION_MANAGE_JOBS *Permission var PERMISSION_CREATE_USER_ACCESS_TOKEN *Permission var PERMISSION_READ_USER_ACCESS_TOKEN *Permission @@ -92,537 +95,853 @@ var PERMISSION_PROMOTE_GUEST *Permission var PERMISSION_DEMOTE_TO_GUEST *Permission var PERMISSION_USE_CHANNEL_MENTIONS *Permission var PERMISSION_USE_GROUP_MENTIONS *Permission +var PERMISSION_READ_OTHER_USERS_TEAMS *Permission +var PERMISSION_EDIT_BRAND *Permission + +var PERMISSION_SYSCONSOLE_READ_ABOUT *Permission +var PERMISSION_SYSCONSOLE_WRITE_ABOUT *Permission + +var PERMISSION_SYSCONSOLE_READ_REPORTING *Permission +var PERMISSION_SYSCONSOLE_WRITE_REPORTING *Permission + +var PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_USERS *Permission +var PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_USERS *Permission + +var PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS *Permission +var PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_GROUPS *Permission + +var PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_TEAMS *Permission +var PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_TEAMS *Permission + +var PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_CHANNELS *Permission +var PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_CHANNELS *Permission + +var PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_PERMISSIONS *Permission +var PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_PERMISSIONS *Permission + +var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT *Permission +var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT *Permission + +var PERMISSION_SYSCONSOLE_READ_SITE *Permission +var PERMISSION_SYSCONSOLE_WRITE_SITE *Permission + +var PERMISSION_SYSCONSOLE_READ_AUTHENTICATION *Permission +var PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION *Permission + +var PERMISSION_SYSCONSOLE_READ_PLUGINS *Permission +var PERMISSION_SYSCONSOLE_WRITE_PLUGINS *Permission + +var PERMISSION_SYSCONSOLE_READ_INTEGRATIONS *Permission +var PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS *Permission + +var PERMISSION_SYSCONSOLE_READ_COMPLIANCE *Permission +var PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE *Permission + +var PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL *Permission +var PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL *Permission // General permission that encompasses all system admin functions // in the future this could be broken up to allow access to some // admin functions but not others var PERMISSION_MANAGE_SYSTEM *Permission -var ALL_PERMISSIONS []*Permission +var AllPermissions []*Permission +var DeprecatedPermissions []*Permission -var CHANNEL_MODERATED_PERMISSIONS []string -var CHANNEL_MODERATED_PERMISSIONS_MAP map[string]string +var ChannelModeratedPermissions []string +var ChannelModeratedPermissionsMap map[string]string + +var SysconsoleReadPermissions []*Permission +var SysconsoleWritePermissions []*Permission func initializePermissions() { PERMISSION_INVITE_USER = &Permission{ "invite_user", "authentication.permissions.team_invite_user.name", "authentication.permissions.team_invite_user.description", - PERMISSION_SCOPE_TEAM, + PermissionScopeTeam, } PERMISSION_ADD_USER_TO_TEAM = &Permission{ "add_user_to_team", "authentication.permissions.add_user_to_team.name", "authentication.permissions.add_user_to_team.description", - PERMISSION_SCOPE_TEAM, + PermissionScopeTeam, } PERMISSION_USE_SLASH_COMMANDS = &Permission{ "use_slash_commands", "authentication.permissions.team_use_slash_commands.name", "authentication.permissions.team_use_slash_commands.description", - PERMISSION_SCOPE_CHANNEL, + PermissionScopeChannel, } PERMISSION_MANAGE_SLASH_COMMANDS = &Permission{ "manage_slash_commands", "authentication.permissions.manage_slash_commands.name", "authentication.permissions.manage_slash_commands.description", - PERMISSION_SCOPE_TEAM, + PermissionScopeTeam, } PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS = &Permission{ "manage_others_slash_commands", "authentication.permissions.manage_others_slash_commands.name", "authentication.permissions.manage_others_slash_commands.description", - PERMISSION_SCOPE_TEAM, + PermissionScopeTeam, } PERMISSION_CREATE_PUBLIC_CHANNEL = &Permission{ "create_public_channel", "authentication.permissions.create_public_channel.name", "authentication.permissions.create_public_channel.description", - PERMISSION_SCOPE_TEAM, + PermissionScopeTeam, } PERMISSION_CREATE_PRIVATE_CHANNEL = &Permission{ "create_private_channel", "authentication.permissions.create_private_channel.name", "authentication.permissions.create_private_channel.description", - PERMISSION_SCOPE_TEAM, + PermissionScopeTeam, } PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS = &Permission{ "manage_public_channel_members", "authentication.permissions.manage_public_channel_members.name", "authentication.permissions.manage_public_channel_members.description", - PERMISSION_SCOPE_CHANNEL, + PermissionScopeChannel, } PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS = &Permission{ "manage_private_channel_members", "authentication.permissions.manage_private_channel_members.name", "authentication.permissions.manage_private_channel_members.description", - PERMISSION_SCOPE_CHANNEL, + PermissionScopeChannel, } PERMISSION_ASSIGN_SYSTEM_ADMIN_ROLE = &Permission{ "assign_system_admin_role", "authentication.permissions.assign_system_admin_role.name", "authentication.permissions.assign_system_admin_role.description", - PERMISSION_SCOPE_SYSTEM, + PermissionScopeSystem, } PERMISSION_MANAGE_ROLES = &Permission{ "manage_roles", "authentication.permissions.manage_roles.name", "authentication.permissions.manage_roles.description", - PERMISSION_SCOPE_SYSTEM, + PermissionScopeSystem, } PERMISSION_MANAGE_TEAM_ROLES = &Permission{ "manage_team_roles", "authentication.permissions.manage_team_roles.name", "authentication.permissions.manage_team_roles.description", - PERMISSION_SCOPE_TEAM, + PermissionScopeTeam, } PERMISSION_MANAGE_CHANNEL_ROLES = &Permission{ "manage_channel_roles", "authentication.permissions.manage_channel_roles.name", "authentication.permissions.manage_channel_roles.description", - PERMISSION_SCOPE_CHANNEL, + PermissionScopeChannel, } PERMISSION_MANAGE_SYSTEM = &Permission{ "manage_system", "authentication.permissions.manage_system.name", "authentication.permissions.manage_system.description", - PERMISSION_SCOPE_SYSTEM, + PermissionScopeSystem, } PERMISSION_CREATE_DIRECT_CHANNEL = &Permission{ "create_direct_channel", "authentication.permissions.create_direct_channel.name", "authentication.permissions.create_direct_channel.description", - PERMISSION_SCOPE_SYSTEM, + PermissionScopeSystem, } PERMISSION_CREATE_GROUP_CHANNEL = &Permission{ "create_group_channel", "authentication.permissions.create_group_channel.name", "authentication.permissions.create_group_channel.description", - PERMISSION_SCOPE_SYSTEM, + PermissionScopeSystem, } PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES = &Permission{ "manage_public_channel_properties", "authentication.permissions.manage_public_channel_properties.name", "authentication.permissions.manage_public_channel_properties.description", - PERMISSION_SCOPE_CHANNEL, + PermissionScopeChannel, } PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES = &Permission{ "manage_private_channel_properties", "authentication.permissions.manage_private_channel_properties.name", "authentication.permissions.manage_private_channel_properties.description", - PERMISSION_SCOPE_CHANNEL, + PermissionScopeChannel, } PERMISSION_LIST_PUBLIC_TEAMS = &Permission{ "list_public_teams", "authentication.permissions.list_public_teams.name", "authentication.permissions.list_public_teams.description", - PERMISSION_SCOPE_SYSTEM, + PermissionScopeSystem, } PERMISSION_JOIN_PUBLIC_TEAMS = &Permission{ "join_public_teams", "authentication.permissions.join_public_teams.name", "authentication.permissions.join_public_teams.description", - PERMISSION_SCOPE_SYSTEM, + PermissionScopeSystem, } PERMISSION_LIST_PRIVATE_TEAMS = &Permission{ "list_private_teams", "authentication.permissions.list_private_teams.name", "authentication.permissions.list_private_teams.description", - PERMISSION_SCOPE_SYSTEM, + PermissionScopeSystem, } PERMISSION_JOIN_PRIVATE_TEAMS = &Permission{ "join_private_teams", "authentication.permissions.join_private_teams.name", "authentication.permissions.join_private_teams.description", - PERMISSION_SCOPE_SYSTEM, + PermissionScopeSystem, } PERMISSION_LIST_TEAM_CHANNELS = &Permission{ "list_team_channels", "authentication.permissions.list_team_channels.name", "authentication.permissions.list_team_channels.description", - PERMISSION_SCOPE_TEAM, + PermissionScopeTeam, } PERMISSION_JOIN_PUBLIC_CHANNELS = &Permission{ "join_public_channels", "authentication.permissions.join_public_channels.name", "authentication.permissions.join_public_channels.description", - PERMISSION_SCOPE_TEAM, + PermissionScopeTeam, } PERMISSION_DELETE_PUBLIC_CHANNEL = &Permission{ "delete_public_channel", "authentication.permissions.delete_public_channel.name", "authentication.permissions.delete_public_channel.description", - PERMISSION_SCOPE_CHANNEL, + PermissionScopeChannel, } PERMISSION_DELETE_PRIVATE_CHANNEL = &Permission{ "delete_private_channel", "authentication.permissions.delete_private_channel.name", "authentication.permissions.delete_private_channel.description", - PERMISSION_SCOPE_CHANNEL, + PermissionScopeChannel, } PERMISSION_EDIT_OTHER_USERS = &Permission{ "edit_other_users", "authentication.permissions.edit_other_users.name", "authentication.permissions.edit_other_users.description", - PERMISSION_SCOPE_SYSTEM, + PermissionScopeSystem, } PERMISSION_READ_CHANNEL = &Permission{ "read_channel", "authentication.permissions.read_channel.name", "authentication.permissions.read_channel.description", - PERMISSION_SCOPE_CHANNEL, + PermissionScopeChannel, + } + PERMISSION_READ_PUBLIC_CHANNEL_GROUPS = &Permission{ + "read_public_channel_groups", + "authentication.permissions.read_public_channel_groups.name", + "authentication.permissions.read_public_channel_groups.description", + PermissionScopeChannel, + } + PERMISSION_READ_PRIVATE_CHANNEL_GROUPS = &Permission{ + "read_private_channel_groups", + "authentication.permissions.read_private_channel_groups.name", + "authentication.permissions.read_private_channel_groups.description", + PermissionScopeChannel, } PERMISSION_READ_PUBLIC_CHANNEL = &Permission{ "read_public_channel", "authentication.permissions.read_public_channel.name", "authentication.permissions.read_public_channel.description", - PERMISSION_SCOPE_TEAM, + PermissionScopeTeam, } PERMISSION_ADD_REACTION = &Permission{ "add_reaction", "authentication.permissions.add_reaction.name", "authentication.permissions.add_reaction.description", - PERMISSION_SCOPE_CHANNEL, + PermissionScopeChannel, } PERMISSION_REMOVE_REACTION = &Permission{ "remove_reaction", "authentication.permissions.remove_reaction.name", "authentication.permissions.remove_reaction.description", - PERMISSION_SCOPE_CHANNEL, + PermissionScopeChannel, } PERMISSION_REMOVE_OTHERS_REACTIONS = &Permission{ "remove_others_reactions", "authentication.permissions.remove_others_reactions.name", "authentication.permissions.remove_others_reactions.description", - PERMISSION_SCOPE_CHANNEL, + PermissionScopeChannel, } // DEPRECATED PERMISSION_PERMANENT_DELETE_USER = &Permission{ "permanent_delete_user", "authentication.permissions.permanent_delete_user.name", "authentication.permissions.permanent_delete_user.description", - PERMISSION_SCOPE_SYSTEM, + PermissionScopeSystem, } PERMISSION_UPLOAD_FILE = &Permission{ "upload_file", "authentication.permissions.upload_file.name", "authentication.permissions.upload_file.description", - PERMISSION_SCOPE_CHANNEL, + PermissionScopeChannel, } PERMISSION_GET_PUBLIC_LINK = &Permission{ "get_public_link", "authentication.permissions.get_public_link.name", "authentication.permissions.get_public_link.description", - PERMISSION_SCOPE_SYSTEM, + PermissionScopeSystem, } // DEPRECATED PERMISSION_MANAGE_WEBHOOKS = &Permission{ "manage_webhooks", "authentication.permissions.manage_webhooks.name", "authentication.permissions.manage_webhooks.description", - PERMISSION_SCOPE_TEAM, + PermissionScopeTeam, } // DEPRECATED PERMISSION_MANAGE_OTHERS_WEBHOOKS = &Permission{ "manage_others_webhooks", "authentication.permissions.manage_others_webhooks.name", "authentication.permissions.manage_others_webhooks.description", - PERMISSION_SCOPE_TEAM, + PermissionScopeTeam, } PERMISSION_MANAGE_INCOMING_WEBHOOKS = &Permission{ "manage_incoming_webhooks", "authentication.permissions.manage_incoming_webhooks.name", "authentication.permissions.manage_incoming_webhooks.description", - PERMISSION_SCOPE_TEAM, + PermissionScopeTeam, } PERMISSION_MANAGE_OUTGOING_WEBHOOKS = &Permission{ "manage_outgoing_webhooks", "authentication.permissions.manage_outgoing_webhooks.name", "authentication.permissions.manage_outgoing_webhooks.description", - PERMISSION_SCOPE_TEAM, + PermissionScopeTeam, } PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS = &Permission{ "manage_others_incoming_webhooks", "authentication.permissions.manage_others_incoming_webhooks.name", "authentication.permissions.manage_others_incoming_webhooks.description", - PERMISSION_SCOPE_TEAM, + PermissionScopeTeam, } PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS = &Permission{ "manage_others_outgoing_webhooks", "authentication.permissions.manage_others_outgoing_webhooks.name", "authentication.permissions.manage_others_outgoing_webhooks.description", - PERMISSION_SCOPE_TEAM, + PermissionScopeTeam, } PERMISSION_MANAGE_OAUTH = &Permission{ "manage_oauth", "authentication.permissions.manage_oauth.name", "authentication.permissions.manage_oauth.description", - PERMISSION_SCOPE_SYSTEM, + PermissionScopeSystem, } PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH = &Permission{ "manage_system_wide_oauth", "authentication.permissions.manage_system_wide_oauth.name", "authentication.permissions.manage_system_wide_oauth.description", - PERMISSION_SCOPE_SYSTEM, + PermissionScopeSystem, } // DEPRECATED PERMISSION_MANAGE_EMOJIS = &Permission{ "manage_emojis", "authentication.permissions.manage_emojis.name", "authentication.permissions.manage_emojis.description", - PERMISSION_SCOPE_TEAM, + PermissionScopeTeam, } // DEPRECATED PERMISSION_MANAGE_OTHERS_EMOJIS = &Permission{ "manage_others_emojis", "authentication.permissions.manage_others_emojis.name", "authentication.permissions.manage_others_emojis.description", - PERMISSION_SCOPE_TEAM, + PermissionScopeTeam, } PERMISSION_CREATE_EMOJIS = &Permission{ "create_emojis", "authentication.permissions.create_emojis.name", "authentication.permissions.create_emojis.description", - PERMISSION_SCOPE_TEAM, + PermissionScopeTeam, } PERMISSION_DELETE_EMOJIS = &Permission{ "delete_emojis", "authentication.permissions.delete_emojis.name", "authentication.permissions.delete_emojis.description", - PERMISSION_SCOPE_TEAM, + PermissionScopeTeam, } PERMISSION_DELETE_OTHERS_EMOJIS = &Permission{ "delete_others_emojis", "authentication.permissions.delete_others_emojis.name", "authentication.permissions.delete_others_emojis.description", - PERMISSION_SCOPE_TEAM, + PermissionScopeTeam, } PERMISSION_CREATE_POST = &Permission{ "create_post", "authentication.permissions.create_post.name", "authentication.permissions.create_post.description", - PERMISSION_SCOPE_CHANNEL, + PermissionScopeChannel, } PERMISSION_CREATE_POST_PUBLIC = &Permission{ "create_post_public", "authentication.permissions.create_post_public.name", "authentication.permissions.create_post_public.description", - PERMISSION_SCOPE_CHANNEL, + PermissionScopeChannel, } PERMISSION_CREATE_POST_EPHEMERAL = &Permission{ "create_post_ephemeral", "authentication.permissions.create_post_ephemeral.name", "authentication.permissions.create_post_ephemeral.description", - PERMISSION_SCOPE_CHANNEL, + PermissionScopeChannel, } PERMISSION_EDIT_POST = &Permission{ "edit_post", "authentication.permissions.edit_post.name", "authentication.permissions.edit_post.description", - PERMISSION_SCOPE_CHANNEL, + PermissionScopeChannel, } PERMISSION_EDIT_OTHERS_POSTS = &Permission{ "edit_others_posts", "authentication.permissions.edit_others_posts.name", "authentication.permissions.edit_others_posts.description", - PERMISSION_SCOPE_CHANNEL, + PermissionScopeChannel, } PERMISSION_DELETE_POST = &Permission{ "delete_post", "authentication.permissions.delete_post.name", "authentication.permissions.delete_post.description", - PERMISSION_SCOPE_CHANNEL, + PermissionScopeChannel, } PERMISSION_DELETE_OTHERS_POSTS = &Permission{ "delete_others_posts", "authentication.permissions.delete_others_posts.name", "authentication.permissions.delete_others_posts.description", - PERMISSION_SCOPE_CHANNEL, + PermissionScopeChannel, } PERMISSION_REMOVE_USER_FROM_TEAM = &Permission{ "remove_user_from_team", "authentication.permissions.remove_user_from_team.name", "authentication.permissions.remove_user_from_team.description", - PERMISSION_SCOPE_TEAM, + PermissionScopeTeam, } PERMISSION_CREATE_TEAM = &Permission{ "create_team", "authentication.permissions.create_team.name", "authentication.permissions.create_team.description", - PERMISSION_SCOPE_SYSTEM, + PermissionScopeSystem, } PERMISSION_MANAGE_TEAM = &Permission{ "manage_team", "authentication.permissions.manage_team.name", "authentication.permissions.manage_team.description", - PERMISSION_SCOPE_TEAM, + PermissionScopeTeam, } PERMISSION_IMPORT_TEAM = &Permission{ "import_team", "authentication.permissions.import_team.name", "authentication.permissions.import_team.description", - PERMISSION_SCOPE_TEAM, + PermissionScopeTeam, } PERMISSION_VIEW_TEAM = &Permission{ "view_team", "authentication.permissions.view_team.name", "authentication.permissions.view_team.description", - PERMISSION_SCOPE_TEAM, + PermissionScopeTeam, } PERMISSION_LIST_USERS_WITHOUT_TEAM = &Permission{ "list_users_without_team", "authentication.permissions.list_users_without_team.name", "authentication.permissions.list_users_without_team.description", - PERMISSION_SCOPE_SYSTEM, + PermissionScopeSystem, } PERMISSION_CREATE_USER_ACCESS_TOKEN = &Permission{ "create_user_access_token", "authentication.permissions.create_user_access_token.name", "authentication.permissions.create_user_access_token.description", - PERMISSION_SCOPE_SYSTEM, + PermissionScopeSystem, } PERMISSION_READ_USER_ACCESS_TOKEN = &Permission{ "read_user_access_token", "authentication.permissions.read_user_access_token.name", "authentication.permissions.read_user_access_token.description", - PERMISSION_SCOPE_SYSTEM, + PermissionScopeSystem, } PERMISSION_REVOKE_USER_ACCESS_TOKEN = &Permission{ "revoke_user_access_token", "authentication.permissions.revoke_user_access_token.name", "authentication.permissions.revoke_user_access_token.description", - PERMISSION_SCOPE_SYSTEM, + PermissionScopeSystem, } PERMISSION_CREATE_BOT = &Permission{ "create_bot", "authentication.permissions.create_bot.name", "authentication.permissions.create_bot.description", - PERMISSION_SCOPE_SYSTEM, + PermissionScopeSystem, } PERMISSION_ASSIGN_BOT = &Permission{ "assign_bot", "authentication.permissions.assign_bot.name", "authentication.permissions.assign_bot.description", - PERMISSION_SCOPE_SYSTEM, + PermissionScopeSystem, } PERMISSION_READ_BOTS = &Permission{ "read_bots", "authentication.permissions.read_bots.name", "authentication.permissions.read_bots.description", - PERMISSION_SCOPE_SYSTEM, + PermissionScopeSystem, } PERMISSION_READ_OTHERS_BOTS = &Permission{ "read_others_bots", "authentication.permissions.read_others_bots.name", "authentication.permissions.read_others_bots.description", - PERMISSION_SCOPE_SYSTEM, + PermissionScopeSystem, } PERMISSION_MANAGE_BOTS = &Permission{ "manage_bots", "authentication.permissions.manage_bots.name", "authentication.permissions.manage_bots.description", - PERMISSION_SCOPE_SYSTEM, + PermissionScopeSystem, } PERMISSION_MANAGE_OTHERS_BOTS = &Permission{ "manage_others_bots", "authentication.permissions.manage_others_bots.name", "authentication.permissions.manage_others_bots.description", - PERMISSION_SCOPE_SYSTEM, + PermissionScopeSystem, + } + PERMISSION_READ_JOBS = &Permission{ + "read_jobs", + "authentication.permisssions.read_jobs.name", + "authentication.permisssions.read_jobs.description", + PermissionScopeSystem, } PERMISSION_MANAGE_JOBS = &Permission{ "manage_jobs", "authentication.permisssions.manage_jobs.name", "authentication.permisssions.manage_jobs.description", - PERMISSION_SCOPE_SYSTEM, + PermissionScopeSystem, } PERMISSION_VIEW_MEMBERS = &Permission{ "view_members", "authentication.permisssions.view_members.name", "authentication.permisssions.view_members.description", - PERMISSION_SCOPE_TEAM, + PermissionScopeTeam, } PERMISSION_INVITE_GUEST = &Permission{ "invite_guest", "authentication.permissions.invite_guest.name", "authentication.permissions.invite_guest.description", - PERMISSION_SCOPE_TEAM, + PermissionScopeTeam, } PERMISSION_PROMOTE_GUEST = &Permission{ "promote_guest", "authentication.permissions.promote_guest.name", "authentication.permissions.promote_guest.description", - PERMISSION_SCOPE_SYSTEM, + PermissionScopeSystem, } - PERMISSION_DEMOTE_TO_GUEST = &Permission{ "demote_to_guest", "authentication.permissions.demote_to_guest.name", "authentication.permissions.demote_to_guest.description", - PERMISSION_SCOPE_SYSTEM, + PermissionScopeSystem, } - PERMISSION_USE_CHANNEL_MENTIONS = &Permission{ "use_channel_mentions", "authentication.permissions.use_channel_mentions.name", "authentication.permissions.use_channel_mentions.description", - PERMISSION_SCOPE_CHANNEL, + PermissionScopeChannel, } - PERMISSION_USE_GROUP_MENTIONS = &Permission{ "use_group_mentions", "authentication.permissions.use_group_mentions.name", "authentication.permissions.use_group_mentions.description", - PERMISSION_SCOPE_CHANNEL, + PermissionScopeChannel, + } + PERMISSION_READ_OTHER_USERS_TEAMS = &Permission{ + "read_other_users_teams", + "authentication.permissions.read_other_users_teams.name", + "authentication.permissions.read_other_users_teams.description", + PermissionScopeSystem, + } + PERMISSION_EDIT_BRAND = &Permission{ + "edit_brand", + "authentication.permissions.edit_brand.name", + "authentication.permissions.edit_brand.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_ABOUT = &Permission{ + "sysconsole_read_about", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_ABOUT = &Permission{ + "sysconsole_write_about", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_REPORTING = &Permission{ + "sysconsole_read_reporting", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_REPORTING = &Permission{ + "sysconsole_write_reporting", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_USERS = &Permission{ + "sysconsole_read_user_management_users", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_USERS = &Permission{ + "sysconsole_write_user_management_users", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS = &Permission{ + "sysconsole_read_user_management_groups", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_GROUPS = &Permission{ + "sysconsole_write_user_management_groups", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_TEAMS = &Permission{ + "sysconsole_read_user_management_teams", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_TEAMS = &Permission{ + "sysconsole_write_user_management_teams", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_CHANNELS = &Permission{ + "sysconsole_read_user_management_channels", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_CHANNELS = &Permission{ + "sysconsole_write_user_management_channels", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_PERMISSIONS = &Permission{ + "sysconsole_read_user_management_permissions", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_PERMISSIONS = &Permission{ + "sysconsole_write_user_management_permissions", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT = &Permission{ + "sysconsole_read_environment", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT = &Permission{ + "sysconsole_write_environment", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_SITE = &Permission{ + "sysconsole_read_site", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_SITE = &Permission{ + "sysconsole_write_site", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION = &Permission{ + "sysconsole_read_authentication", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION = &Permission{ + "sysconsole_write_authentication", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_PLUGINS = &Permission{ + "sysconsole_read_plugins", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_PLUGINS = &Permission{ + "sysconsole_write_plugins", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_INTEGRATIONS = &Permission{ + "sysconsole_read_integrations", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS = &Permission{ + "sysconsole_write_integrations", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_COMPLIANCE = &Permission{ + "sysconsole_read_compliance", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE = &Permission{ + "sysconsole_write_compliance", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_PLUGINS = &Permission{ + "sysconsole_read_plugins", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_PLUGINS = &Permission{ + "sysconsole_write_plugins", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL = &Permission{ + "sysconsole_read_experimental", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL = &Permission{ + "sysconsole_write_experimental", + "authentication.permissions.use_group_mentions.name", + "authentication.permissions.use_group_mentions.description", + PermissionScopeSystem, } - ALL_PERMISSIONS = []*Permission{ - PERMISSION_INVITE_USER, - PERMISSION_ADD_USER_TO_TEAM, - PERMISSION_USE_SLASH_COMMANDS, - PERMISSION_MANAGE_SLASH_COMMANDS, - PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS, - PERMISSION_CREATE_PUBLIC_CHANNEL, - PERMISSION_CREATE_PRIVATE_CHANNEL, - PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS, - PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS, + SysconsoleReadPermissions = []*Permission{ + PERMISSION_SYSCONSOLE_READ_ABOUT, + PERMISSION_SYSCONSOLE_READ_REPORTING, + PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_USERS, + PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS, + PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_TEAMS, + PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_CHANNELS, + PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_PERMISSIONS, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT, + PERMISSION_SYSCONSOLE_READ_SITE, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION, + PERMISSION_SYSCONSOLE_READ_PLUGINS, + PERMISSION_SYSCONSOLE_READ_INTEGRATIONS, + PERMISSION_SYSCONSOLE_READ_COMPLIANCE, + PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL, + } + + SysconsoleWritePermissions = []*Permission{ + PERMISSION_SYSCONSOLE_WRITE_ABOUT, + PERMISSION_SYSCONSOLE_WRITE_REPORTING, + PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_USERS, + PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_GROUPS, + PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_TEAMS, + PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_CHANNELS, + PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_PERMISSIONS, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT, + PERMISSION_SYSCONSOLE_WRITE_SITE, + PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION, + PERMISSION_SYSCONSOLE_WRITE_PLUGINS, + PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS, + PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE, + PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL, + } + + SystemScopedPermissionsMinusSysconsole := []*Permission{ PERMISSION_ASSIGN_SYSTEM_ADMIN_ROLE, PERMISSION_MANAGE_ROLES, - PERMISSION_MANAGE_TEAM_ROLES, - PERMISSION_MANAGE_CHANNEL_ROLES, + PERMISSION_MANAGE_SYSTEM, PERMISSION_CREATE_DIRECT_CHANNEL, PERMISSION_CREATE_GROUP_CHANNEL, - PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES, - PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES, PERMISSION_LIST_PUBLIC_TEAMS, PERMISSION_JOIN_PUBLIC_TEAMS, PERMISSION_LIST_PRIVATE_TEAMS, PERMISSION_JOIN_PRIVATE_TEAMS, + PERMISSION_EDIT_OTHER_USERS, + PERMISSION_READ_OTHER_USERS_TEAMS, + PERMISSION_GET_PUBLIC_LINK, + PERMISSION_MANAGE_OAUTH, + PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH, + PERMISSION_CREATE_TEAM, + PERMISSION_LIST_USERS_WITHOUT_TEAM, + PERMISSION_CREATE_USER_ACCESS_TOKEN, + PERMISSION_READ_USER_ACCESS_TOKEN, + PERMISSION_REVOKE_USER_ACCESS_TOKEN, + PERMISSION_CREATE_BOT, + PERMISSION_ASSIGN_BOT, + PERMISSION_READ_BOTS, + PERMISSION_READ_OTHERS_BOTS, + PERMISSION_MANAGE_BOTS, + PERMISSION_MANAGE_OTHERS_BOTS, + PERMISSION_READ_JOBS, + PERMISSION_MANAGE_JOBS, + PERMISSION_PROMOTE_GUEST, + PERMISSION_DEMOTE_TO_GUEST, + PERMISSION_EDIT_BRAND, + } + + TeamScopedPermissions := []*Permission{ + PERMISSION_INVITE_USER, + PERMISSION_ADD_USER_TO_TEAM, + PERMISSION_MANAGE_SLASH_COMMANDS, + PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS, + PERMISSION_CREATE_PUBLIC_CHANNEL, + PERMISSION_CREATE_PRIVATE_CHANNEL, + PERMISSION_MANAGE_TEAM_ROLES, PERMISSION_LIST_TEAM_CHANNELS, PERMISSION_JOIN_PUBLIC_CHANNELS, - PERMISSION_DELETE_PUBLIC_CHANNEL, - PERMISSION_DELETE_PRIVATE_CHANNEL, - PERMISSION_EDIT_OTHER_USERS, - PERMISSION_READ_CHANNEL, PERMISSION_READ_PUBLIC_CHANNEL, - PERMISSION_ADD_REACTION, - PERMISSION_REMOVE_REACTION, - PERMISSION_REMOVE_OTHERS_REACTIONS, - PERMISSION_PERMANENT_DELETE_USER, - PERMISSION_UPLOAD_FILE, - PERMISSION_GET_PUBLIC_LINK, - PERMISSION_MANAGE_WEBHOOKS, - PERMISSION_MANAGE_OTHERS_WEBHOOKS, PERMISSION_MANAGE_INCOMING_WEBHOOKS, PERMISSION_MANAGE_OUTGOING_WEBHOOKS, PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS, PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS, - PERMISSION_MANAGE_OAUTH, - PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH, - PERMISSION_MANAGE_EMOJIS, - PERMISSION_MANAGE_OTHERS_EMOJIS, PERMISSION_CREATE_EMOJIS, PERMISSION_DELETE_EMOJIS, PERMISSION_DELETE_OTHERS_EMOJIS, + PERMISSION_REMOVE_USER_FROM_TEAM, + PERMISSION_MANAGE_TEAM, + PERMISSION_IMPORT_TEAM, + PERMISSION_VIEW_TEAM, + PERMISSION_VIEW_MEMBERS, + PERMISSION_INVITE_GUEST, + } + + ChannelScopedPermissions := []*Permission{ + PERMISSION_USE_SLASH_COMMANDS, + PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS, + PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS, + PERMISSION_MANAGE_CHANNEL_ROLES, + PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES, + PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES, + PERMISSION_DELETE_PUBLIC_CHANNEL, + PERMISSION_DELETE_PRIVATE_CHANNEL, + PERMISSION_READ_CHANNEL, + PERMISSION_READ_PUBLIC_CHANNEL_GROUPS, + PERMISSION_READ_PRIVATE_CHANNEL_GROUPS, + PERMISSION_ADD_REACTION, + PERMISSION_REMOVE_REACTION, + PERMISSION_REMOVE_OTHERS_REACTIONS, + PERMISSION_UPLOAD_FILE, PERMISSION_CREATE_POST, PERMISSION_CREATE_POST_PUBLIC, PERMISSION_CREATE_POST_EPHEMERAL, @@ -630,44 +949,39 @@ func initializePermissions() { PERMISSION_EDIT_OTHERS_POSTS, PERMISSION_DELETE_POST, PERMISSION_DELETE_OTHERS_POSTS, - PERMISSION_REMOVE_USER_FROM_TEAM, - PERMISSION_CREATE_TEAM, - PERMISSION_MANAGE_TEAM, - PERMISSION_IMPORT_TEAM, - PERMISSION_VIEW_TEAM, - PERMISSION_LIST_USERS_WITHOUT_TEAM, - PERMISSION_MANAGE_JOBS, - PERMISSION_CREATE_USER_ACCESS_TOKEN, - PERMISSION_READ_USER_ACCESS_TOKEN, - PERMISSION_REVOKE_USER_ACCESS_TOKEN, - PERMISSION_CREATE_BOT, - PERMISSION_READ_BOTS, - PERMISSION_READ_OTHERS_BOTS, - PERMISSION_MANAGE_BOTS, - PERMISSION_MANAGE_OTHERS_BOTS, - PERMISSION_MANAGE_SYSTEM, - PERMISSION_VIEW_MEMBERS, - PERMISSION_INVITE_GUEST, - PERMISSION_PROMOTE_GUEST, - PERMISSION_DEMOTE_TO_GUEST, PERMISSION_USE_CHANNEL_MENTIONS, PERMISSION_USE_GROUP_MENTIONS, } - CHANNEL_MODERATED_PERMISSIONS = []string{ + DeprecatedPermissions = []*Permission{ + PERMISSION_PERMANENT_DELETE_USER, + PERMISSION_MANAGE_WEBHOOKS, + PERMISSION_MANAGE_OTHERS_WEBHOOKS, + PERMISSION_MANAGE_EMOJIS, + PERMISSION_MANAGE_OTHERS_EMOJIS, + } + + AllPermissions = []*Permission{} + AllPermissions = append(AllPermissions, SystemScopedPermissionsMinusSysconsole...) + AllPermissions = append(AllPermissions, TeamScopedPermissions...) + AllPermissions = append(AllPermissions, ChannelScopedPermissions...) + AllPermissions = append(AllPermissions, SysconsoleReadPermissions...) + AllPermissions = append(AllPermissions, SysconsoleWritePermissions...) + + ChannelModeratedPermissions = []string{ PERMISSION_CREATE_POST.Id, "create_reactions", "manage_members", PERMISSION_USE_CHANNEL_MENTIONS.Id, } - CHANNEL_MODERATED_PERMISSIONS_MAP = map[string]string{ - PERMISSION_CREATE_POST.Id: CHANNEL_MODERATED_PERMISSIONS[0], - PERMISSION_ADD_REACTION.Id: CHANNEL_MODERATED_PERMISSIONS[1], - PERMISSION_REMOVE_REACTION.Id: CHANNEL_MODERATED_PERMISSIONS[1], - PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id: CHANNEL_MODERATED_PERMISSIONS[2], - PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id: CHANNEL_MODERATED_PERMISSIONS[2], - PERMISSION_USE_CHANNEL_MENTIONS.Id: CHANNEL_MODERATED_PERMISSIONS[3], + ChannelModeratedPermissionsMap = map[string]string{ + PERMISSION_CREATE_POST.Id: ChannelModeratedPermissions[0], + PERMISSION_ADD_REACTION.Id: ChannelModeratedPermissions[1], + PERMISSION_REMOVE_REACTION.Id: ChannelModeratedPermissions[1], + PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id: ChannelModeratedPermissions[2], + PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id: ChannelModeratedPermissions[2], + PERMISSION_USE_CHANNEL_MENTIONS.Id: ChannelModeratedPermissions[3], } } diff --git a/model/permission_test.go b/model/permission_test.go index 141d01bf21..5e803d5bea 100644 --- a/model/permission_test.go +++ b/model/permission_test.go @@ -13,7 +13,7 @@ import ( // in the database column for role permissions. func TestPermissionsLength(t *testing.T) { permissionsString := "" - for _, permission := range ALL_PERMISSIONS { + for _, permission := range AllPermissions { permissionsString += " " + permission.Id } diff --git a/model/role.go b/model/role.go index 837db366c8..c61936cc00 100644 --- a/model/role.go +++ b/model/role.go @@ -9,10 +9,21 @@ import ( "strings" ) +// SysconsoleAncillaryPermissions maps the non-sysconsole permissions required by each sysconsole view. +var SysconsoleAncillaryPermissions map[string][]*Permission + var BuiltInSchemeManagedRoleIDs []string +var NewSystemRoleIDs []string + func init() { - BuiltInSchemeManagedRoleIDs = []string{ + NewSystemRoleIDs = []string{ + SYSTEM_USER_MANAGER_ROLE_ID, + SYSTEM_READ_ONLY_ADMIN_ROLE_ID, + SYSTEM_MANAGER_ROLE_ID, + } + + BuiltInSchemeManagedRoleIDs = append([]string{ SYSTEM_GUEST_ROLE_ID, SYSTEM_USER_ROLE_ID, SYSTEM_ADMIN_ROLE_ID, @@ -29,6 +40,58 @@ func init() { CHANNEL_GUEST_ROLE_ID, CHANNEL_USER_ROLE_ID, CHANNEL_ADMIN_ROLE_ID, + }, NewSystemRoleIDs...) + + SysconsoleAncillaryPermissions = map[string][]*Permission{ + PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_CHANNELS.Id: { + PERMISSION_READ_PUBLIC_CHANNEL, + PERMISSION_READ_CHANNEL, + PERMISSION_READ_PUBLIC_CHANNEL_GROUPS, + PERMISSION_READ_PRIVATE_CHANNEL_GROUPS, + }, + PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_USERS.Id: { + PERMISSION_READ_OTHER_USERS_TEAMS, + }, + PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_TEAMS.Id: { + PERMISSION_LIST_PRIVATE_TEAMS, + PERMISSION_LIST_PUBLIC_TEAMS, + PERMISSION_VIEW_TEAM, + }, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT.Id: { + PERMISSION_READ_JOBS, + }, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION.Id: { + PERMISSION_READ_JOBS, + }, + PERMISSION_SYSCONSOLE_READ_REPORTING.Id: { + PERMISSION_VIEW_TEAM, + }, + PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_CHANNELS.Id: { + PERMISSION_MANAGE_TEAM, + PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES, + PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES, + PERMISSION_DELETE_PRIVATE_CHANNEL, + PERMISSION_DELETE_PUBLIC_CHANNEL, + PERMISSION_MANAGE_CHANNEL_ROLES, + }, + PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_TEAMS.Id: { + PERMISSION_MANAGE_TEAM_ROLES, + PERMISSION_REMOVE_USER_FROM_TEAM, + PERMISSION_JOIN_PRIVATE_TEAMS, + PERMISSION_JOIN_PUBLIC_TEAMS, + PERMISSION_ADD_USER_TO_TEAM, + }, + PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_GROUPS.Id: { + PERMISSION_MANAGE_TEAM, + PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS, + PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS, + }, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT.Id: { + PERMISSION_MANAGE_JOBS, + }, + PERMISSION_SYSCONSOLE_WRITE_SITE.Id: { + PERMISSION_EDIT_BRAND, + }, } } @@ -42,6 +105,9 @@ const ( SYSTEM_POST_ALL_ROLE_ID = "system_post_all" SYSTEM_POST_ALL_PUBLIC_ROLE_ID = "system_post_all_public" SYSTEM_USER_ACCESS_TOKEN_ROLE_ID = "system_user_access_token" + SYSTEM_USER_MANAGER_ROLE_ID = "system_user_manager" + SYSTEM_READ_ONLY_ADMIN_ROLE_ID = "system_read_only_admin" + SYSTEM_MANAGER_ROLE_ID = "system_manager" TEAM_GUEST_ROLE_ID = "team_guest" TEAM_USER_ROLE_ID = "team_user" @@ -135,8 +201,8 @@ func (r *Role) MergeChannelHigherScopedPermissions(higherScopedPermissions *Role higherScopedPermissionsMap := AsStringBoolMap(higherScopedPermissions.Permissions) rolePermissionsMap := AsStringBoolMap(r.Permissions) - for _, cp := range ALL_PERMISSIONS { - if cp.Scope != PERMISSION_SCOPE_CHANNEL { + for _, cp := range AllPermissions { + if cp.Scope != PermissionScopeChannel { continue } @@ -150,7 +216,7 @@ func (r *Role) MergeChannelHigherScopedPermissions(higherScopedPermissions *Role continue } - _, permissionIsModerated := CHANNEL_MODERATED_PERMISSIONS_MAP[cp.Id] + _, permissionIsModerated := ChannelModeratedPermissionsMap[cp.Id] if permissionIsModerated { _, presentOnRole := rolePermissionsMap[cp.Id] if presentOnRole && presentOnHigherScope { @@ -216,13 +282,13 @@ func ChannelModeratedPermissionsChangedByPatch(role *Role, patch *RolePatch) []s patchMap := make(map[string]bool) for _, permission := range role.Permissions { - if channelModeratedPermissionName, found := CHANNEL_MODERATED_PERMISSIONS_MAP[permission]; found { + if channelModeratedPermissionName, found := ChannelModeratedPermissionsMap[permission]; found { roleMap[channelModeratedPermissionName] = true } } for _, permission := range *patch.Permissions { - if channelModeratedPermissionName, found := CHANNEL_MODERATED_PERMISSIONS_MAP[permission]; found { + if channelModeratedPermissionName, found := ChannelModeratedPermissionsMap[permission]; found { patchMap[channelModeratedPermissionName] = true } } @@ -246,11 +312,11 @@ func ChannelModeratedPermissionsChangedByPatch(role *Role, patch *RolePatch) []s func (r *Role) GetChannelModeratedPermissions(channelType string) map[string]bool { moderatedPermissions := make(map[string]bool) for _, permission := range r.Permissions { - if _, found := CHANNEL_MODERATED_PERMISSIONS_MAP[permission]; !found { + if _, found := ChannelModeratedPermissionsMap[permission]; !found { continue } - for moderated, moderatedPermissionValue := range CHANNEL_MODERATED_PERMISSIONS_MAP { + for moderated, moderatedPermissionValue := range ChannelModeratedPermissionsMap { // the moderated permission has already been found to be true so skip this iteration if moderatedPermissions[moderatedPermissionValue] { continue @@ -279,14 +345,14 @@ func (r *Role) RolePatchFromChannelModerationsPatch(channelModerationsPatch []*C // Iterate through the list of existing permissions on the role and append permissions that we want to keep. for _, permission := range r.Permissions { // Permission is not moderated so dont add it to the patch and skip the channelModerationsPatch - if _, isModerated := CHANNEL_MODERATED_PERMISSIONS_MAP[permission]; !isModerated { + if _, isModerated := ChannelModeratedPermissionsMap[permission]; !isModerated { continue } permissionEnabled := true // Check if permission has a matching moderated permission name inside the channel moderation patch for _, channelModerationPatch := range channelModerationsPatch { - if *channelModerationPatch.Name == CHANNEL_MODERATED_PERMISSIONS_MAP[permission] { + if *channelModerationPatch.Name == ChannelModeratedPermissionsMap[permission] { // Permission key exists in patch with a value of false so skip over it if roleName == "members" { if channelModerationPatch.Roles.Members != nil && !*channelModerationPatch.Roles.Members { @@ -307,7 +373,7 @@ func (r *Role) RolePatchFromChannelModerationsPatch(channelModerationsPatch []*C // Iterate through the patch and add any permissions that dont already exist on the role for _, channelModerationPatch := range channelModerationsPatch { - for permission, moderatedPermissionName := range CHANNEL_MODERATED_PERMISSIONS_MAP { + for permission, moderatedPermissionName := range ChannelModeratedPermissionsMap { if roleName == "members" && channelModerationPatch.Roles.Members != nil && *channelModerationPatch.Roles.Members && *channelModerationPatch.Name == moderatedPermissionName { permissionsToAddToPatch[permission] = true } @@ -349,7 +415,7 @@ func (r *Role) IsValidWithoutId() bool { for _, permission := range r.Permissions { permissionValidated := false - for _, p := range ALL_PERMISSIONS { + for _, p := range append(AllPermissions, DeprecatedPermissions...) { if permission == p.Id { permissionValidated = true break @@ -579,6 +645,91 @@ func MakeDefaultRoles() map[string]*Role { BuiltIn: true, } + roles[SYSTEM_USER_MANAGER_ROLE_ID] = &Role{ + Name: "system_user_manager", + DisplayName: "authentication.roles.system_user_manager.name", + Description: "authentication.roles.system_user_manager.description", + Permissions: []string{ + PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS.Id, + PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_TEAMS.Id, + PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_CHANNELS.Id, + PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_PERMISSIONS.Id, + PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_GROUPS.Id, + PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_TEAMS.Id, + PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_CHANNELS.Id, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION.Id, + }, + SchemeManaged: false, + BuiltIn: true, + } + + roles[SYSTEM_READ_ONLY_ADMIN_ROLE_ID] = &Role{ + Name: "system_read_only_admin", + DisplayName: "authentication.roles.system_read_only_admin.name", + Description: "authentication.roles.system_read_only_admin.description", + Permissions: []string{ + PERMISSION_SYSCONSOLE_READ_ABOUT.Id, + PERMISSION_SYSCONSOLE_READ_REPORTING.Id, + PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_USERS.Id, + PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS.Id, + PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_TEAMS.Id, + PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_CHANNELS.Id, + PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_PERMISSIONS.Id, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT.Id, + PERMISSION_SYSCONSOLE_READ_SITE.Id, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION.Id, + PERMISSION_SYSCONSOLE_READ_PLUGINS.Id, + PERMISSION_SYSCONSOLE_READ_INTEGRATIONS.Id, + PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL.Id, + }, + SchemeManaged: false, + BuiltIn: true, + } + + roles[SYSTEM_MANAGER_ROLE_ID] = &Role{ + Name: "system_manager", + DisplayName: "authentication.roles.system_manager.name", + Description: "authentication.roles.system_manager.description", + Permissions: []string{ + PERMISSION_SYSCONSOLE_READ_ABOUT.Id, + PERMISSION_SYSCONSOLE_READ_REPORTING.Id, + PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS.Id, + PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_TEAMS.Id, + PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_CHANNELS.Id, + PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_PERMISSIONS.Id, + PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_GROUPS.Id, + PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_TEAMS.Id, + PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_CHANNELS.Id, + PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_PERMISSIONS.Id, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT.Id, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT.Id, + PERMISSION_SYSCONSOLE_READ_SITE.Id, + PERMISSION_SYSCONSOLE_WRITE_SITE.Id, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION.Id, + PERMISSION_SYSCONSOLE_READ_PLUGINS.Id, + PERMISSION_SYSCONSOLE_READ_INTEGRATIONS.Id, + PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS.Id, + }, + SchemeManaged: false, + BuiltIn: true, + } + + // Add the ancillary permissions to each new system role + for _, role := range []*Role{roles[SYSTEM_USER_MANAGER_ROLE_ID], roles[SYSTEM_READ_ONLY_ADMIN_ROLE_ID], roles[SYSTEM_MANAGER_ROLE_ID]} { + for _, rolePermission := range role.Permissions { + if ancillaryPermissions, ok := SysconsoleAncillaryPermissions[rolePermission]; ok { + for _, ancillaryPermission := range ancillaryPermissions { + role.Permissions = append(role.Permissions, ancillaryPermission.Id) + } + } + } + } + + allPermissionIDs := []string{} + for _, permission := range AllPermissions { + allPermissionIDs = append(allPermissionIDs, permission.Id) + } + roles[SYSTEM_ADMIN_ROLE_ID] = &Role{ Name: "system_admin", DisplayName: "authentication.roles.global_admin.name", @@ -586,61 +737,7 @@ func MakeDefaultRoles() map[string]*Role { // System admins can do anything channel and team admins can do // plus everything members of teams and channels can do to all teams // and channels on the system - Permissions: append( - append( - append( - append( - []string{ - PERMISSION_ASSIGN_SYSTEM_ADMIN_ROLE.Id, - PERMISSION_MANAGE_SYSTEM.Id, - PERMISSION_MANAGE_ROLES.Id, - PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, - PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id, - PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id, - PERMISSION_DELETE_PUBLIC_CHANNEL.Id, - PERMISSION_CREATE_PUBLIC_CHANNEL.Id, - PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, - PERMISSION_DELETE_PRIVATE_CHANNEL.Id, - PERMISSION_CREATE_PRIVATE_CHANNEL.Id, - PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH.Id, - PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS.Id, - PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS.Id, - PERMISSION_EDIT_OTHER_USERS.Id, - PERMISSION_EDIT_OTHERS_POSTS.Id, - PERMISSION_MANAGE_OAUTH.Id, - PERMISSION_INVITE_USER.Id, - PERMISSION_INVITE_GUEST.Id, - PERMISSION_PROMOTE_GUEST.Id, - PERMISSION_DEMOTE_TO_GUEST.Id, - PERMISSION_DELETE_POST.Id, - PERMISSION_DELETE_OTHERS_POSTS.Id, - PERMISSION_CREATE_TEAM.Id, - PERMISSION_ADD_USER_TO_TEAM.Id, - PERMISSION_LIST_USERS_WITHOUT_TEAM.Id, - PERMISSION_MANAGE_JOBS.Id, - PERMISSION_CREATE_POST_PUBLIC.Id, - PERMISSION_CREATE_POST_EPHEMERAL.Id, - PERMISSION_CREATE_USER_ACCESS_TOKEN.Id, - PERMISSION_READ_USER_ACCESS_TOKEN.Id, - PERMISSION_REVOKE_USER_ACCESS_TOKEN.Id, - PERMISSION_CREATE_BOT.Id, - PERMISSION_READ_BOTS.Id, - PERMISSION_READ_OTHERS_BOTS.Id, - PERMISSION_MANAGE_BOTS.Id, - PERMISSION_MANAGE_OTHERS_BOTS.Id, - PERMISSION_REMOVE_OTHERS_REACTIONS.Id, - PERMISSION_LIST_PRIVATE_TEAMS.Id, - PERMISSION_JOIN_PRIVATE_TEAMS.Id, - PERMISSION_VIEW_MEMBERS.Id, - }, - roles[TEAM_USER_ROLE_ID].Permissions..., - ), - roles[CHANNEL_USER_ROLE_ID].Permissions..., - ), - roles[TEAM_ADMIN_ROLE_ID].Permissions..., - ), - roles[CHANNEL_ADMIN_ROLE_ID].Permissions..., - ), + Permissions: allPermissionIDs, SchemeManaged: true, BuiltIn: true, } diff --git a/model/role_test.go b/model/role_test.go index a3bd9efae4..081707e1b4 100644 --- a/model/role_test.go +++ b/model/role_test.go @@ -26,13 +26,13 @@ func TestChannelModeratedPermissionsChangedByPatch(t *testing.T) { "Adds permissions to empty initial permissions list", []string{}, []string{PERMISSION_CREATE_POST.Id, PERMISSION_ADD_REACTION.Id}, - []string{CHANNEL_MODERATED_PERMISSIONS[0], CHANNEL_MODERATED_PERMISSIONS[1]}, + []string{ChannelModeratedPermissions[0], ChannelModeratedPermissions[1]}, }, { "Ignores non moderated permissions in initial permissions list", []string{PERMISSION_ASSIGN_BOT.Id}, []string{PERMISSION_CREATE_POST.Id, PERMISSION_REMOVE_REACTION.Id}, - []string{CHANNEL_MODERATED_PERMISSIONS[0], CHANNEL_MODERATED_PERMISSIONS[1]}, + []string{ChannelModeratedPermissions[0], ChannelModeratedPermissions[1]}, }, { "Adds removed moderated permissions from initial permissions list", @@ -58,10 +58,10 @@ func TestChannelModeratedPermissionsChangedByPatch(t *testing.T) { } func TestRolePatchFromChannelModerationsPatch(t *testing.T) { - createPosts := CHANNEL_MODERATED_PERMISSIONS[0] - createReactions := CHANNEL_MODERATED_PERMISSIONS[1] - manageMembers := CHANNEL_MODERATED_PERMISSIONS[2] - channelMentions := CHANNEL_MODERATED_PERMISSIONS[3] + createPosts := ChannelModeratedPermissions[0] + createReactions := ChannelModeratedPermissions[1] + manageMembers := ChannelModeratedPermissions[2] + channelMentions := ChannelModeratedPermissions[3] basePermissions := []string{ PERMISSION_ADD_REACTION.Id, @@ -245,10 +245,10 @@ func TestGetChannelModeratedPermissions(t *testing.T) { []string{PERMISSION_CREATE_POST.Id, PERMISSION_ADD_REACTION.Id, PERMISSION_REMOVE_REACTION.Id, PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id, PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id, PERMISSION_USE_CHANNEL_MENTIONS.Id}, CHANNEL_OPEN, map[string]bool{ - CHANNEL_MODERATED_PERMISSIONS[0]: true, - CHANNEL_MODERATED_PERMISSIONS[1]: true, - CHANNEL_MODERATED_PERMISSIONS[2]: true, - CHANNEL_MODERATED_PERMISSIONS[3]: true, + ChannelModeratedPermissions[0]: true, + ChannelModeratedPermissions[1]: true, + ChannelModeratedPermissions[2]: true, + ChannelModeratedPermissions[3]: true, }, }, { @@ -256,7 +256,7 @@ func TestGetChannelModeratedPermissions(t *testing.T) { []string{PERMISSION_CREATE_POST.Id, PERMISSION_CREATE_DIRECT_CHANNEL.Id}, CHANNEL_OPEN, map[string]bool{ - CHANNEL_MODERATED_PERMISSIONS[0]: true, + ChannelModeratedPermissions[0]: true, }, }, { diff --git a/store/sqlstore/scheme_store.go b/store/sqlstore/scheme_store.go index 3f7e4756e9..9aa240f02b 100644 --- a/store/sqlstore/scheme_store.go +++ b/store/sqlstore/scheme_store.go @@ -234,7 +234,7 @@ func (s *SqlSchemeStore) createScheme(scheme *model.Scheme, transaction *gorp.Tr func filterModerated(permissions []string) []string { filteredPermissions := []string{} for _, perm := range permissions { - if _, ok := model.CHANNEL_MODERATED_PERMISSIONS_MAP[perm]; ok { + if _, ok := model.ChannelModeratedPermissionsMap[perm]; ok { filteredPermissions = append(filteredPermissions, perm) } } diff --git a/testlib/store.go b/testlib/store.go index 468fbf9345..12685256cd 100644 --- a/testlib/store.go +++ b/testlib/store.go @@ -32,6 +32,7 @@ func GetMockStoreForSetupFunctions() *mocks.Store { systemStore.On("GetByName", "AdvancedPermissionsMigrationComplete").Return(&model.System{Name: "AdvancedPermissionsMigrationComplete", Value: "true"}, nil) systemStore.On("GetByName", "EmojisPermissionsMigrationComplete").Return(&model.System{Name: "EmojisPermissionsMigrationComplete", Value: "true"}, nil) systemStore.On("GetByName", "GuestRolesCreationMigrationComplete").Return(&model.System{Name: "GuestRolesCreationMigrationComplete", Value: "true"}, nil) + systemStore.On("GetByName", "SystemConsoleRolesCreationMigrationComplete").Return(&model.System{Name: "SystemConsoleRolesCreationMigrationComplete", Value: "true"}, nil) systemStore.On("GetByName", model.MIGRATION_KEY_EMOJI_PERMISSIONS_SPLIT).Return(&model.System{Name: model.MIGRATION_KEY_EMOJI_PERMISSIONS_SPLIT, Value: "true"}, nil) systemStore.On("GetByName", model.MIGRATION_KEY_WEBHOOK_PERMISSIONS_SPLIT).Return(&model.System{Name: model.MIGRATION_KEY_WEBHOOK_PERMISSIONS_SPLIT, Value: "true"}, nil) systemStore.On("GetByName", model.MIGRATION_KEY_LIST_JOIN_PUBLIC_PRIVATE_TEAMS).Return(&model.System{Name: model.MIGRATION_KEY_LIST_JOIN_PUBLIC_PRIVATE_TEAMS, Value: "true"}, nil) @@ -43,6 +44,7 @@ func GetMockStoreForSetupFunctions() *mocks.Store { systemStore.On("GetByName", model.MIGRATION_KEY_ADD_MANAGE_GUESTS_PERMISSIONS).Return(&model.System{Name: model.MIGRATION_KEY_ADD_MANAGE_GUESTS_PERMISSIONS, Value: "true"}, nil) systemStore.On("GetByName", model.MIGRATION_KEY_CHANNEL_MODERATIONS_PERMISSIONS).Return(&model.System{Name: model.MIGRATION_KEY_CHANNEL_MODERATIONS_PERMISSIONS, Value: "true"}, nil) systemStore.On("GetByName", model.MIGRATION_KEY_ADD_USE_GROUP_MENTIONS_PERMISSION).Return(&model.System{Name: model.MIGRATION_KEY_ADD_USE_GROUP_MENTIONS_PERMISSION, Value: "true"}, nil) + systemStore.On("GetByName", model.MIGRATION_KEY_ADD_SYSTEM_CONSOLE_PERMISSIONS).Return(&model.System{Name: model.MIGRATION_KEY_ADD_SYSTEM_CONSOLE_PERMISSIONS, Value: "true"}, nil) systemStore.On("Get").Return(make(model.StringMap), nil) systemStore.On("Save", mock.AnythingOfType("*model.System")).Return(nil) diff --git a/utils/policies-roles-mapping.json b/utils/policies-roles-mapping.json index 414ab62f16..24929152c4 100644 --- a/utils/policies-roles-mapping.json +++ b/utils/policies-roles-mapping.json @@ -420,7 +420,7 @@ { "roleName": "system_admin", "permission": "edit_post", - "shouldHave": false + "shouldHave": true } ] }, diff --git a/web/context.go b/web/context.go index 32e1eed644..16abc870f4 100644 --- a/web/context.go +++ b/web/context.go @@ -258,8 +258,8 @@ func NewServerBusyError() *model.AppError { return err } -func (c *Context) SetPermissionError(permission *model.Permission) { - c.Err = c.App.MakePermissionError(permission) +func (c *Context) SetPermissionError(permissions ...*model.Permission) { + c.Err = c.App.MakePermissionError(permissions) } func (c *Context) SetSiteURLHeader(url string) {