config.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
  2. // See LICENSE.txt for license information.
  3. package api4
  4. import (
  5. "net/http"
  6. "reflect"
  7. "github.com/mattermost/mattermost-server/v5/audit"
  8. "github.com/mattermost/mattermost-server/v5/config"
  9. "github.com/mattermost/mattermost-server/v5/model"
  10. "github.com/mattermost/mattermost-server/v5/utils"
  11. )
  12. func (api *API) InitConfig() {
  13. api.BaseRoutes.ApiRoot.Handle("/config", api.ApiSessionRequired(getConfig)).Methods("GET")
  14. api.BaseRoutes.ApiRoot.Handle("/config", api.ApiSessionRequired(updateConfig)).Methods("PUT")
  15. api.BaseRoutes.ApiRoot.Handle("/config/patch", api.ApiSessionRequired(patchConfig)).Methods("PUT")
  16. api.BaseRoutes.ApiRoot.Handle("/config/reload", api.ApiSessionRequired(configReload)).Methods("POST")
  17. api.BaseRoutes.ApiRoot.Handle("/config/client", api.ApiHandler(getClientConfig)).Methods("GET")
  18. api.BaseRoutes.ApiRoot.Handle("/config/environment", api.ApiSessionRequired(getEnvironmentConfig)).Methods("GET")
  19. }
  20. func getConfig(c *Context, w http.ResponseWriter, r *http.Request) {
  21. if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) {
  22. c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
  23. return
  24. }
  25. auditRec := c.MakeAuditRecord("getConfig", audit.Fail)
  26. defer c.LogAuditRec(auditRec)
  27. cfg := c.App.GetSanitizedConfig()
  28. auditRec.Success()
  29. w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
  30. w.Write([]byte(cfg.ToJson()))
  31. }
  32. func configReload(c *Context, w http.ResponseWriter, r *http.Request) {
  33. auditRec := c.MakeAuditRecord("configReload", audit.Fail)
  34. defer c.LogAuditRec(auditRec)
  35. if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) {
  36. c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
  37. return
  38. }
  39. if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin {
  40. c.Err = model.NewAppError("configReload", "api.restricted_system_admin", nil, "", http.StatusBadRequest)
  41. return
  42. }
  43. c.App.ReloadConfig()
  44. auditRec.Success()
  45. w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
  46. ReturnStatusOK(w)
  47. }
  48. func updateConfig(c *Context, w http.ResponseWriter, r *http.Request) {
  49. cfg := model.ConfigFromJson(r.Body)
  50. if cfg == nil {
  51. c.SetInvalidParam("config")
  52. return
  53. }
  54. auditRec := c.MakeAuditRecord("updateConfig", audit.Fail)
  55. defer c.LogAuditRec(auditRec)
  56. cfg.SetDefaults()
  57. if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) {
  58. c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
  59. return
  60. }
  61. appCfg := c.App.Config()
  62. if *appCfg.ServiceSettings.SiteURL != "" && *cfg.ServiceSettings.SiteURL == "" {
  63. c.Err = model.NewAppError("updateConfig", "api.config.update_config.clear_siteurl.app_error", nil, "", http.StatusBadRequest)
  64. return
  65. }
  66. if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin {
  67. // Start with the current configuration, and only merge values not marked as being
  68. // restricted.
  69. var err error
  70. cfg, err = config.Merge(appCfg, cfg, &utils.MergeConfig{
  71. StructFieldFilter: func(structField reflect.StructField, base, patch reflect.Value) bool {
  72. restricted := structField.Tag.Get("restricted") == "true"
  73. return !restricted
  74. },
  75. })
  76. if err != nil {
  77. c.Err = model.NewAppError("updateConfig", "api.config.update_config.restricted_merge.app_error", nil, err.Error(), http.StatusInternalServerError)
  78. }
  79. }
  80. // Do not allow plugin uploads to be toggled through the API
  81. cfg.PluginSettings.EnableUploads = appCfg.PluginSettings.EnableUploads
  82. // Do not allow certificates to be changed through the API
  83. cfg.PluginSettings.SignaturePublicKeyFiles = appCfg.PluginSettings.SignaturePublicKeyFiles
  84. c.App.HandleMessageExportConfig(cfg, appCfg)
  85. err := cfg.IsValid()
  86. if err != nil {
  87. c.Err = err
  88. return
  89. }
  90. err = c.App.SaveConfig(cfg, true)
  91. if err != nil {
  92. c.Err = err
  93. return
  94. }
  95. cfg = c.App.GetSanitizedConfig()
  96. auditRec.Success()
  97. c.LogAudit("updateConfig")
  98. w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
  99. w.Write([]byte(cfg.ToJson()))
  100. }
  101. func getClientConfig(c *Context, w http.ResponseWriter, r *http.Request) {
  102. format := r.URL.Query().Get("format")
  103. if format == "" {
  104. c.Err = model.NewAppError("getClientConfig", "api.config.client.old_format.app_error", nil, "", http.StatusNotImplemented)
  105. return
  106. }
  107. if format != "old" {
  108. c.SetInvalidParam("format")
  109. return
  110. }
  111. var config map[string]string
  112. if len(c.App.Session().UserId) == 0 {
  113. config = c.App.LimitedClientConfigWithComputed()
  114. } else {
  115. config = c.App.ClientConfigWithComputed()
  116. }
  117. w.Write([]byte(model.MapToJson(config)))
  118. }
  119. func getEnvironmentConfig(c *Context, w http.ResponseWriter, r *http.Request) {
  120. if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) {
  121. c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
  122. return
  123. }
  124. envConfig := c.App.GetEnvironmentConfig()
  125. w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
  126. w.Write([]byte(model.StringInterfaceToJson(envConfig)))
  127. }
  128. func patchConfig(c *Context, w http.ResponseWriter, r *http.Request) {
  129. cfg := model.ConfigFromJson(r.Body)
  130. if cfg == nil {
  131. c.SetInvalidParam("config")
  132. return
  133. }
  134. auditRec := c.MakeAuditRecord("patchConfig", audit.Fail)
  135. defer c.LogAuditRec(auditRec)
  136. if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) {
  137. c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
  138. return
  139. }
  140. appCfg := c.App.Config()
  141. if *appCfg.ServiceSettings.SiteURL != "" && *cfg.ServiceSettings.SiteURL == "" {
  142. c.Err = model.NewAppError("patchConfig", "api.config.update_config.clear_siteurl.app_error", nil, "", http.StatusBadRequest)
  143. return
  144. }
  145. var filterFn utils.StructFieldFilter
  146. if *appCfg.ExperimentalSettings.RestrictSystemAdmin {
  147. filterFn = func(structField reflect.StructField, base, patch reflect.Value) bool {
  148. return !(structField.Tag.Get("restricted") == "true")
  149. }
  150. } else {
  151. filterFn = func(structField reflect.StructField, base, patch reflect.Value) bool {
  152. return true
  153. }
  154. }
  155. // Do not allow plugin uploads to be toggled through the API
  156. cfg.PluginSettings.EnableUploads = appCfg.PluginSettings.EnableUploads
  157. if cfg.MessageExportSettings.EnableExport != nil {
  158. c.App.HandleMessageExportConfig(cfg, appCfg)
  159. }
  160. updatedCfg, mergeErr := config.Merge(appCfg, cfg, &utils.MergeConfig{
  161. StructFieldFilter: filterFn,
  162. })
  163. if mergeErr != nil {
  164. c.Err = model.NewAppError("patchConfig", "api.config.update_config.restricted_merge.app_error", nil, mergeErr.Error(), http.StatusInternalServerError)
  165. return
  166. }
  167. err := updatedCfg.IsValid()
  168. if err != nil {
  169. c.Err = err
  170. return
  171. }
  172. err = c.App.SaveConfig(updatedCfg, true)
  173. if err != nil {
  174. c.Err = err
  175. return
  176. }
  177. auditRec.Success()
  178. w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
  179. w.Write([]byte(c.App.GetSanitizedConfig().ToJson()))
  180. }