github.com/gigforks/mattermost-server@v4.9.1-0.20180619094218-800d97fa55d0+incompatible/api4/system.go (about) 1 // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package api4 5 6 import ( 7 "bytes" 8 "fmt" 9 "io" 10 "net/http" 11 "runtime" 12 13 "github.com/mattermost/mattermost-server/mlog" 14 "github.com/mattermost/mattermost-server/model" 15 "github.com/mattermost/mattermost-server/utils" 16 ) 17 18 func (api *API) InitSystem() { 19 api.BaseRoutes.System.Handle("/ping", api.ApiHandler(getSystemPing)).Methods("GET") 20 21 api.BaseRoutes.System.Handle("/timezones", api.ApiSessionRequired(getSupportedTimezones)).Methods("GET") 22 23 api.BaseRoutes.ApiRoot.Handle("/config", api.ApiSessionRequired(getConfig)).Methods("GET") 24 api.BaseRoutes.ApiRoot.Handle("/config", api.ApiSessionRequired(updateConfig)).Methods("PUT") 25 api.BaseRoutes.ApiRoot.Handle("/config/reload", api.ApiSessionRequired(configReload)).Methods("POST") 26 api.BaseRoutes.ApiRoot.Handle("/config/client", api.ApiHandler(getClientConfig)).Methods("GET") 27 api.BaseRoutes.ApiRoot.Handle("/config/environment", api.ApiSessionRequired(getEnvironmentConfig)).Methods("GET") 28 29 api.BaseRoutes.ApiRoot.Handle("/license", api.ApiSessionRequired(addLicense)).Methods("POST") 30 api.BaseRoutes.ApiRoot.Handle("/license", api.ApiSessionRequired(removeLicense)).Methods("DELETE") 31 api.BaseRoutes.ApiRoot.Handle("/license/client", api.ApiHandler(getClientLicense)).Methods("GET") 32 33 api.BaseRoutes.ApiRoot.Handle("/audits", api.ApiSessionRequired(getAudits)).Methods("GET") 34 api.BaseRoutes.ApiRoot.Handle("/email/test", api.ApiSessionRequired(testEmail)).Methods("POST") 35 api.BaseRoutes.ApiRoot.Handle("/file/s3_test", api.ApiSessionRequired(testS3)).Methods("POST") 36 api.BaseRoutes.ApiRoot.Handle("/database/recycle", api.ApiSessionRequired(databaseRecycle)).Methods("POST") 37 api.BaseRoutes.ApiRoot.Handle("/caches/invalidate", api.ApiSessionRequired(invalidateCaches)).Methods("POST") 38 39 api.BaseRoutes.ApiRoot.Handle("/logs", api.ApiSessionRequired(getLogs)).Methods("GET") 40 api.BaseRoutes.ApiRoot.Handle("/logs", api.ApiHandler(postLog)).Methods("POST") 41 42 api.BaseRoutes.ApiRoot.Handle("/analytics/old", api.ApiSessionRequired(getAnalytics)).Methods("GET") 43 } 44 45 func getSystemPing(c *Context, w http.ResponseWriter, r *http.Request) { 46 47 actualGoroutines := runtime.NumGoroutine() 48 if *c.App.Config().ServiceSettings.GoroutineHealthThreshold <= 0 || actualGoroutines <= *c.App.Config().ServiceSettings.GoroutineHealthThreshold { 49 m := make(map[string]string) 50 m[model.STATUS] = model.STATUS_OK 51 52 reqs := c.App.Config().ClientRequirements 53 m["AndroidLatestVersion"] = reqs.AndroidLatestVersion 54 m["AndroidMinVersion"] = reqs.AndroidMinVersion 55 m["DesktopLatestVersion"] = reqs.DesktopLatestVersion 56 m["DesktopMinVersion"] = reqs.DesktopMinVersion 57 m["IosLatestVersion"] = reqs.IosLatestVersion 58 m["IosMinVersion"] = reqs.IosMinVersion 59 60 w.Write([]byte(model.MapToJson(m))) 61 } else { 62 rdata := map[string]string{} 63 rdata["status"] = "unhealthy" 64 65 mlog.Warn(fmt.Sprintf("The number of running goroutines is over the health threshold %v of %v", actualGoroutines, *c.App.Config().ServiceSettings.GoroutineHealthThreshold)) 66 67 w.WriteHeader(http.StatusInternalServerError) 68 w.Write([]byte(model.MapToJson(rdata))) 69 } 70 } 71 72 func testEmail(c *Context, w http.ResponseWriter, r *http.Request) { 73 cfg := model.ConfigFromJson(r.Body) 74 if cfg == nil { 75 cfg = c.App.Config() 76 } 77 78 if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) { 79 c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) 80 return 81 } 82 83 err := c.App.TestEmail(c.Session.UserId, cfg) 84 if err != nil { 85 c.Err = err 86 return 87 } 88 89 ReturnStatusOK(w) 90 } 91 92 func getConfig(c *Context, w http.ResponseWriter, r *http.Request) { 93 if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) { 94 c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) 95 return 96 } 97 98 cfg := c.App.GetConfig() 99 100 w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") 101 w.Write([]byte(cfg.ToJson())) 102 } 103 104 func configReload(c *Context, w http.ResponseWriter, r *http.Request) { 105 if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) { 106 c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) 107 return 108 } 109 110 c.App.ReloadConfig() 111 112 w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") 113 ReturnStatusOK(w) 114 } 115 116 func updateConfig(c *Context, w http.ResponseWriter, r *http.Request) { 117 cfg := model.ConfigFromJson(r.Body) 118 if cfg == nil { 119 c.SetInvalidParam("config") 120 return 121 } 122 123 if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) { 124 c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) 125 return 126 } 127 128 // Do not allow plugin uploads to be toggled through the API 129 cfg.PluginSettings.EnableUploads = c.App.GetConfig().PluginSettings.EnableUploads 130 131 err := c.App.SaveConfig(cfg, true) 132 if err != nil { 133 c.Err = err 134 return 135 } 136 137 c.LogAudit("updateConfig") 138 139 cfg = c.App.GetConfig() 140 141 w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") 142 w.Write([]byte(cfg.ToJson())) 143 } 144 145 func getAudits(c *Context, w http.ResponseWriter, r *http.Request) { 146 if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) { 147 c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) 148 return 149 } 150 151 audits, err := c.App.GetAuditsPage("", c.Params.Page, c.Params.PerPage) 152 153 if err != nil { 154 c.Err = err 155 return 156 } 157 158 w.Write([]byte(audits.ToJson())) 159 } 160 161 func databaseRecycle(c *Context, w http.ResponseWriter, r *http.Request) { 162 163 if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) { 164 c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) 165 return 166 } 167 168 c.App.RecycleDatabaseConnection() 169 170 ReturnStatusOK(w) 171 } 172 173 func invalidateCaches(c *Context, w http.ResponseWriter, r *http.Request) { 174 if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) { 175 c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) 176 return 177 } 178 179 err := c.App.InvalidateAllCaches() 180 if err != nil { 181 c.Err = err 182 return 183 } 184 185 w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") 186 ReturnStatusOK(w) 187 } 188 189 func getLogs(c *Context, w http.ResponseWriter, r *http.Request) { 190 if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) { 191 c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) 192 return 193 } 194 195 lines, err := c.App.GetLogs(c.Params.Page, c.Params.LogsPerPage) 196 if err != nil { 197 c.Err = err 198 return 199 } 200 201 w.Write([]byte(model.ArrayToJson(lines))) 202 } 203 204 func postLog(c *Context, w http.ResponseWriter, r *http.Request) { 205 forceToDebug := false 206 207 if !*c.App.Config().ServiceSettings.EnableDeveloper { 208 if c.Session.UserId == "" { 209 c.Err = model.NewAppError("postLog", "api.context.permissions.app_error", nil, "", http.StatusForbidden) 210 return 211 } 212 213 if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) { 214 forceToDebug = true 215 } 216 } 217 218 m := model.MapFromJson(r.Body) 219 lvl := m["level"] 220 msg := m["message"] 221 222 if len(msg) > 400 { 223 msg = msg[0:399] 224 } 225 226 if !forceToDebug && lvl == "ERROR" { 227 err := &model.AppError{} 228 err.Message = msg 229 err.Id = msg 230 err.Where = "client" 231 c.LogError(err) 232 } else { 233 mlog.Debug(fmt.Sprint(msg)) 234 } 235 236 m["message"] = msg 237 w.Write([]byte(model.MapToJson(m))) 238 } 239 240 func getClientConfig(c *Context, w http.ResponseWriter, r *http.Request) { 241 format := r.URL.Query().Get("format") 242 243 if format == "" { 244 c.Err = model.NewAppError("getClientConfig", "api.config.client.old_format.app_error", nil, "", http.StatusNotImplemented) 245 return 246 } 247 248 if format != "old" { 249 c.SetInvalidParam("format") 250 return 251 } 252 253 w.Write([]byte(model.MapToJson(c.App.ClientConfigWithComputed()))) 254 } 255 256 func getEnvironmentConfig(c *Context, w http.ResponseWriter, r *http.Request) { 257 if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) { 258 c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) 259 return 260 } 261 262 envConfig := c.App.GetEnvironmentConfig() 263 264 w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") 265 w.Write([]byte(model.StringInterfaceToJson(envConfig))) 266 } 267 268 func getClientLicense(c *Context, w http.ResponseWriter, r *http.Request) { 269 format := r.URL.Query().Get("format") 270 271 if format == "" { 272 c.Err = model.NewAppError("getClientLicense", "api.license.client.old_format.app_error", nil, "", http.StatusNotImplemented) 273 return 274 } 275 276 if format != "old" { 277 c.SetInvalidParam("format") 278 return 279 } 280 281 etag := c.App.GetClientLicenseEtag(true) 282 if c.HandleEtag(etag, "Get Client License", w, r) { 283 return 284 } 285 286 var clientLicense map[string]string 287 288 if c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) { 289 clientLicense = c.App.ClientLicense() 290 } else { 291 clientLicense = c.App.GetSanitizedClientLicense() 292 } 293 294 w.Header().Set(model.HEADER_ETAG_SERVER, etag) 295 w.Write([]byte(model.MapToJson(clientLicense))) 296 } 297 298 func addLicense(c *Context, w http.ResponseWriter, r *http.Request) { 299 c.LogAudit("attempt") 300 301 if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) { 302 c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) 303 return 304 } 305 306 err := r.ParseMultipartForm(*c.App.Config().FileSettings.MaxFileSize) 307 if err != nil { 308 http.Error(w, err.Error(), http.StatusBadRequest) 309 return 310 } 311 312 m := r.MultipartForm 313 314 fileArray, ok := m.File["license"] 315 if !ok { 316 c.Err = model.NewAppError("addLicense", "api.license.add_license.no_file.app_error", nil, "", http.StatusBadRequest) 317 return 318 } 319 320 if len(fileArray) <= 0 { 321 c.Err = model.NewAppError("addLicense", "api.license.add_license.array.app_error", nil, "", http.StatusBadRequest) 322 return 323 } 324 325 fileData := fileArray[0] 326 327 file, err := fileData.Open() 328 if err != nil { 329 c.Err = model.NewAppError("addLicense", "api.license.add_license.open.app_error", nil, err.Error(), http.StatusBadRequest) 330 return 331 } 332 defer file.Close() 333 334 buf := bytes.NewBuffer(nil) 335 io.Copy(buf, file) 336 337 if license, err := c.App.SaveLicense(buf.Bytes()); err != nil { 338 if err.Id == model.EXPIRED_LICENSE_ERROR { 339 c.LogAudit("failed - expired or non-started license") 340 } else if err.Id == model.INVALID_LICENSE_ERROR { 341 c.LogAudit("failed - invalid license") 342 } else { 343 c.LogAudit("failed - unable to save license") 344 } 345 c.Err = err 346 return 347 } else { 348 c.LogAudit("success") 349 w.Write([]byte(license.ToJson())) 350 } 351 } 352 353 func removeLicense(c *Context, w http.ResponseWriter, r *http.Request) { 354 c.LogAudit("attempt") 355 356 if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) { 357 c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) 358 return 359 } 360 361 if err := c.App.RemoveLicense(); err != nil { 362 c.Err = err 363 return 364 } 365 366 c.LogAudit("success") 367 ReturnStatusOK(w) 368 } 369 370 func getAnalytics(c *Context, w http.ResponseWriter, r *http.Request) { 371 name := r.URL.Query().Get("name") 372 teamId := r.URL.Query().Get("team_id") 373 374 if name == "" { 375 name = "standard" 376 } 377 378 if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) { 379 c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) 380 return 381 } 382 383 rows, err := c.App.GetAnalytics(name, teamId) 384 if err != nil { 385 c.Err = err 386 return 387 } 388 389 if rows == nil { 390 c.SetInvalidParam("name") 391 return 392 } 393 394 w.Write([]byte(rows.ToJson())) 395 } 396 397 func getSupportedTimezones(c *Context, w http.ResponseWriter, r *http.Request) { 398 supportedTimezones := c.App.Timezones() 399 400 if supportedTimezones != nil { 401 w.Write([]byte(model.TimezonesToJson(supportedTimezones))) 402 return 403 } 404 405 emptyTimezones := make([]string, 0) 406 w.Write([]byte(model.TimezonesToJson(emptyTimezones))) 407 } 408 409 func testS3(c *Context, w http.ResponseWriter, r *http.Request) { 410 cfg := model.ConfigFromJson(r.Body) 411 if cfg == nil { 412 cfg = c.App.Config() 413 } 414 415 if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) { 416 c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) 417 return 418 } 419 420 err := utils.CheckMandatoryS3Fields(&cfg.FileSettings) 421 if err != nil { 422 c.Err = err 423 return 424 } 425 426 if cfg.FileSettings.AmazonS3SecretAccessKey == model.FAKE_SETTING { 427 cfg.FileSettings.AmazonS3SecretAccessKey = c.App.Config().FileSettings.AmazonS3SecretAccessKey 428 } 429 430 license := c.App.License() 431 backend, appErr := utils.NewFileBackend(&cfg.FileSettings, license != nil && *license.Features.Compliance) 432 if appErr == nil { 433 appErr = backend.TestConnection() 434 } 435 if appErr != nil { 436 c.Err = appErr 437 return 438 } 439 440 ReturnStatusOK(w) 441 }