github.com/mattermost/mattermost-server/v5@v5.39.3/api4/system.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package api4 5 6 import ( 7 "bytes" 8 "encoding/json" 9 "fmt" 10 "io" 11 "io/ioutil" 12 "net/http" 13 "path" 14 "runtime" 15 "strconv" 16 "time" 17 18 "github.com/pkg/errors" 19 20 "github.com/mattermost/mattermost-server/v5/audit" 21 "github.com/mattermost/mattermost-server/v5/model" 22 "github.com/mattermost/mattermost-server/v5/services/cache" 23 "github.com/mattermost/mattermost-server/v5/services/upgrader" 24 "github.com/mattermost/mattermost-server/v5/shared/mlog" 25 ) 26 27 const ( 28 RedirectLocationCacheSize = 10000 29 DefaultServerBusySeconds = 3600 30 MaxServerBusySeconds = 86400 31 ) 32 33 var redirectLocationDataCache = cache.NewLRU(cache.LRUOptions{ 34 Size: RedirectLocationCacheSize, 35 }) 36 37 func (api *API) InitSystem() { 38 api.BaseRoutes.System.Handle("/ping", api.ApiHandler(getSystemPing)).Methods("GET") 39 40 api.BaseRoutes.System.Handle("/timezones", api.ApiSessionRequired(getSupportedTimezones)).Methods("GET") 41 42 api.BaseRoutes.ApiRoot.Handle("/audits", api.ApiSessionRequired(getAudits)).Methods("GET") 43 api.BaseRoutes.ApiRoot.Handle("/email/test", api.ApiSessionRequired(testEmail)).Methods("POST") 44 api.BaseRoutes.ApiRoot.Handle("/site_url/test", api.ApiSessionRequired(testSiteURL)).Methods("POST") 45 api.BaseRoutes.ApiRoot.Handle("/file/s3_test", api.ApiSessionRequired(testS3)).Methods("POST") 46 api.BaseRoutes.ApiRoot.Handle("/database/recycle", api.ApiSessionRequired(databaseRecycle)).Methods("POST") 47 api.BaseRoutes.ApiRoot.Handle("/caches/invalidate", api.ApiSessionRequired(invalidateCaches)).Methods("POST") 48 49 api.BaseRoutes.ApiRoot.Handle("/logs", api.ApiSessionRequired(getLogs)).Methods("GET") 50 api.BaseRoutes.ApiRoot.Handle("/logs", api.ApiHandler(postLog)).Methods("POST") 51 52 api.BaseRoutes.ApiRoot.Handle("/analytics/old", api.ApiSessionRequired(getAnalytics)).Methods("GET") 53 54 api.BaseRoutes.ApiRoot.Handle("/redirect_location", api.ApiSessionRequiredTrustRequester(getRedirectLocation)).Methods("GET") 55 56 api.BaseRoutes.ApiRoot.Handle("/notifications/ack", api.ApiSessionRequired(pushNotificationAck)).Methods("POST") 57 58 api.BaseRoutes.ApiRoot.Handle("/server_busy", api.ApiSessionRequired(setServerBusy)).Methods("POST") 59 api.BaseRoutes.ApiRoot.Handle("/server_busy", api.ApiSessionRequired(getServerBusyExpires)).Methods("GET") 60 api.BaseRoutes.ApiRoot.Handle("/server_busy", api.ApiSessionRequired(clearServerBusy)).Methods("DELETE") 61 api.BaseRoutes.ApiRoot.Handle("/upgrade_to_enterprise", api.ApiSessionRequired(upgradeToEnterprise)).Methods("POST") 62 api.BaseRoutes.ApiRoot.Handle("/upgrade_to_enterprise/status", api.ApiSessionRequired(upgradeToEnterpriseStatus)).Methods("GET") 63 api.BaseRoutes.ApiRoot.Handle("/restart", api.ApiSessionRequired(restart)).Methods("POST") 64 api.BaseRoutes.ApiRoot.Handle("/warn_metrics/status", api.ApiSessionRequired(getWarnMetricsStatus)).Methods("GET") 65 api.BaseRoutes.ApiRoot.Handle("/warn_metrics/ack/{warn_metric_id:[A-Za-z0-9-_]+}", api.ApiHandler(sendWarnMetricAckEmail)).Methods("POST") 66 api.BaseRoutes.ApiRoot.Handle("/warn_metrics/trial-license-ack/{warn_metric_id:[A-Za-z0-9-_]+}", api.ApiHandler(requestTrialLicenseAndAckWarnMetric)).Methods("POST") 67 api.BaseRoutes.System.Handle("/notices/{team_id:[A-Za-z0-9]+}", api.ApiSessionRequired(getProductNotices)).Methods("GET") 68 api.BaseRoutes.System.Handle("/notices/view", api.ApiSessionRequired(updateViewedProductNotices)).Methods("PUT") 69 70 api.BaseRoutes.System.Handle("/support_packet", api.ApiSessionRequired(generateSupportPacket)).Methods("GET") 71 } 72 73 func generateSupportPacket(c *Context, w http.ResponseWriter, r *http.Request) { 74 const FileMime = "application/zip" 75 const OutputDirectory = "support_packet" 76 77 // Checking to see if the user is a admin of any sort or not 78 // If they are a admin, they should theoritcally have access to one or more of the system console read permissions 79 if !c.App.SessionHasPermissionToAny(*c.AppContext.Session(), model.SysconsoleReadPermissions) { 80 c.SetPermissionError(model.SysconsoleReadPermissions...) 81 return 82 } 83 84 // Checking to see if the server has a e10 or e20 license (this feature is only permitted for servers with licenses) 85 if c.App.Srv().License() == nil { 86 c.Err = model.NewAppError("Api4.generateSupportPacket", "api.no_license", nil, "", http.StatusForbidden) 87 return 88 } 89 90 fileDatas := c.App.GenerateSupportPacket() 91 92 // Constructing the ZIP file name as per spec (mattermost_support_packet_YYYY-MM-DD-HH-MM.zip) 93 now := time.Now() 94 outputZipFilename := fmt.Sprintf("mattermost_support_packet_%s.zip", now.Format("2006-01-02-03-04")) 95 96 fileStorageBackend, fileBackendErr := c.App.FileBackend() 97 if fileBackendErr != nil { 98 c.Err = fileBackendErr 99 return 100 } 101 102 // We do this incase we get concurrent requests, we will always have a unique directory. 103 // This is to avoid the situation where we try to write to the same directory while we are trying to delete it (further down) 104 outputDirectoryToUse := OutputDirectory + "_" + model.NewId() 105 err := c.App.CreateZipFileAndAddFiles(fileStorageBackend, fileDatas, outputZipFilename, outputDirectoryToUse) 106 if err != nil { 107 c.Err = model.NewAppError("Api4.generateSupportPacket", "api.unable_to_create_zip_file", nil, err.Error(), http.StatusForbidden) 108 return 109 } 110 111 fileBytes, err := fileStorageBackend.ReadFile(path.Join(outputDirectoryToUse, outputZipFilename)) 112 defer fileStorageBackend.RemoveDirectory(outputDirectoryToUse) 113 if err != nil { 114 c.Err = model.NewAppError("Api4.generateSupportPacket", "api.unable_to_read_file_from_backend", nil, err.Error(), http.StatusForbidden) 115 return 116 } 117 fileBytesReader := bytes.NewReader(fileBytes) 118 119 // Send the zip file back to client 120 // We are able to pass 0 for content size due to the fact that Golang's serveContent (https://golang.org/src/net/http/fs.go) 121 // already sets that for us 122 writeFileResponse(outputZipFilename, FileMime, 0, now, *c.App.Config().ServiceSettings.WebserverMode, fileBytesReader, true, w, r) 123 } 124 125 func getSystemPing(c *Context, w http.ResponseWriter, r *http.Request) { 126 reqs := c.App.Config().ClientRequirements 127 128 s := make(map[string]string) 129 s[model.STATUS] = model.STATUS_OK 130 s["AndroidLatestVersion"] = reqs.AndroidLatestVersion 131 s["AndroidMinVersion"] = reqs.AndroidMinVersion 132 s["DesktopLatestVersion"] = reqs.DesktopLatestVersion 133 s["DesktopMinVersion"] = reqs.DesktopMinVersion 134 s["IosLatestVersion"] = reqs.IosLatestVersion 135 s["IosMinVersion"] = reqs.IosMinVersion 136 137 testflag := c.App.Config().FeatureFlags.TestFeature 138 if testflag != "off" { 139 s["TestFeatureFlag"] = testflag 140 } 141 142 actualGoroutines := runtime.NumGoroutine() 143 if *c.App.Config().ServiceSettings.GoroutineHealthThreshold > 0 && actualGoroutines >= *c.App.Config().ServiceSettings.GoroutineHealthThreshold { 144 mlog.Warn("The number of running goroutines is over the health threshold", mlog.Int("goroutines", actualGoroutines), mlog.Int("health_threshold", *c.App.Config().ServiceSettings.GoroutineHealthThreshold)) 145 s[model.STATUS] = model.STATUS_UNHEALTHY 146 } 147 148 // Enhanced ping health check: 149 // If an extra form value is provided then perform extra health checks for 150 // database and file storage backends. 151 if r.FormValue("get_server_status") != "" { 152 dbStatusKey := "database_status" 153 s[dbStatusKey] = model.STATUS_OK 154 155 writeErr := c.App.DBHealthCheckWrite() 156 if writeErr != nil { 157 mlog.Warn("Unable to write to database.", mlog.Err(writeErr)) 158 s[dbStatusKey] = model.STATUS_UNHEALTHY 159 s[model.STATUS] = model.STATUS_UNHEALTHY 160 } 161 162 writeErr = c.App.DBHealthCheckDelete() 163 if writeErr != nil { 164 mlog.Warn("Unable to remove ping health check value from database.", mlog.Err(writeErr)) 165 s[dbStatusKey] = model.STATUS_UNHEALTHY 166 s[model.STATUS] = model.STATUS_UNHEALTHY 167 } 168 169 if s[dbStatusKey] == model.STATUS_OK { 170 mlog.Debug("Able to write to database.") 171 } 172 173 filestoreStatusKey := "filestore_status" 174 s[filestoreStatusKey] = model.STATUS_OK 175 appErr := c.App.TestFileStoreConnection() 176 if appErr != nil { 177 s[filestoreStatusKey] = model.STATUS_UNHEALTHY 178 s[model.STATUS] = model.STATUS_UNHEALTHY 179 } 180 181 w.Header().Set(model.STATUS, s[model.STATUS]) 182 w.Header().Set(dbStatusKey, s[dbStatusKey]) 183 w.Header().Set(filestoreStatusKey, s[filestoreStatusKey]) 184 } 185 186 if s[model.STATUS] != model.STATUS_OK { 187 w.WriteHeader(http.StatusInternalServerError) 188 } 189 w.Write([]byte(model.MapToJson(s))) 190 } 191 192 func testEmail(c *Context, w http.ResponseWriter, r *http.Request) { 193 cfg := model.ConfigFromJson(r.Body) 194 if cfg == nil { 195 cfg = c.App.Config() 196 } 197 198 if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_TEST_EMAIL) { 199 c.SetPermissionError(model.PERMISSION_TEST_EMAIL) 200 return 201 } 202 203 if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin { 204 c.Err = model.NewAppError("testEmail", "api.restricted_system_admin", nil, "", http.StatusForbidden) 205 return 206 } 207 208 err := c.App.TestEmail(c.AppContext.Session().UserId, cfg) 209 if err != nil { 210 c.Err = err 211 return 212 } 213 214 ReturnStatusOK(w) 215 } 216 217 func testSiteURL(c *Context, w http.ResponseWriter, r *http.Request) { 218 if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_TEST_SITE_URL) { 219 c.SetPermissionError(model.PERMISSION_TEST_SITE_URL) 220 return 221 } 222 223 if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin { 224 c.Err = model.NewAppError("testSiteURL", "api.restricted_system_admin", nil, "", http.StatusForbidden) 225 return 226 } 227 228 props := model.MapFromJson(r.Body) 229 siteURL := props["site_url"] 230 if siteURL == "" { 231 c.SetInvalidParam("site_url") 232 return 233 } 234 235 err := c.App.TestSiteURL(siteURL) 236 if err != nil { 237 c.Err = err 238 return 239 } 240 241 ReturnStatusOK(w) 242 } 243 244 func getAudits(c *Context, w http.ResponseWriter, r *http.Request) { 245 auditRec := c.MakeAuditRecord("getAudits", audit.Fail) 246 defer c.LogAuditRec(auditRec) 247 248 if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_READ_AUDITS) { 249 c.SetPermissionError(model.PERMISSION_READ_AUDITS) 250 return 251 } 252 253 audits, err := c.App.GetAuditsPage("", c.Params.Page, c.Params.PerPage) 254 if err != nil { 255 c.Err = err 256 return 257 } 258 259 auditRec.Success() 260 auditRec.AddMeta("page", c.Params.Page) 261 auditRec.AddMeta("audits_per_page", c.Params.LogsPerPage) 262 263 w.Write([]byte(audits.ToJson())) 264 } 265 266 func databaseRecycle(c *Context, w http.ResponseWriter, r *http.Request) { 267 if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_RECYCLE_DATABASE_CONNECTIONS) { 268 c.SetPermissionError(model.PERMISSION_RECYCLE_DATABASE_CONNECTIONS) 269 return 270 } 271 272 auditRec := c.MakeAuditRecord("databaseRecycle", audit.Fail) 273 defer c.LogAuditRec(auditRec) 274 275 if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin { 276 c.Err = model.NewAppError("databaseRecycle", "api.restricted_system_admin", nil, "", http.StatusForbidden) 277 return 278 } 279 280 c.App.RecycleDatabaseConnection() 281 282 auditRec.Success() 283 ReturnStatusOK(w) 284 } 285 286 func invalidateCaches(c *Context, w http.ResponseWriter, r *http.Request) { 287 if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_INVALIDATE_CACHES) { 288 c.SetPermissionError(model.PERMISSION_INVALIDATE_CACHES) 289 return 290 } 291 292 auditRec := c.MakeAuditRecord("invalidateCaches", audit.Fail) 293 defer c.LogAuditRec(auditRec) 294 295 if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin { 296 c.Err = model.NewAppError("invalidateCaches", "api.restricted_system_admin", nil, "", http.StatusForbidden) 297 return 298 } 299 300 err := c.App.Srv().InvalidateAllCaches() 301 if err != nil { 302 c.Err = err 303 return 304 } 305 306 auditRec.Success() 307 308 w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") 309 ReturnStatusOK(w) 310 } 311 312 func getLogs(c *Context, w http.ResponseWriter, r *http.Request) { 313 auditRec := c.MakeAuditRecord("getLogs", audit.Fail) 314 defer c.LogAuditRec(auditRec) 315 316 if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin { 317 c.Err = model.NewAppError("getLogs", "api.restricted_system_admin", nil, "", http.StatusForbidden) 318 return 319 } 320 321 if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_GET_LOGS) { 322 c.SetPermissionError(model.PERMISSION_GET_LOGS) 323 return 324 } 325 326 lines, err := c.App.GetLogs(c.Params.Page, c.Params.LogsPerPage) 327 if err != nil { 328 c.Err = err 329 return 330 } 331 332 auditRec.AddMeta("page", c.Params.Page) 333 auditRec.AddMeta("logs_per_page", c.Params.LogsPerPage) 334 335 w.Write([]byte(model.ArrayToJson(lines))) 336 } 337 338 func postLog(c *Context, w http.ResponseWriter, r *http.Request) { 339 forceToDebug := false 340 341 if !*c.App.Config().ServiceSettings.EnableDeveloper { 342 if c.AppContext.Session().UserId == "" { 343 c.Err = model.NewAppError("postLog", "api.context.permissions.app_error", nil, "", http.StatusForbidden) 344 return 345 } 346 347 if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_MANAGE_SYSTEM) { 348 forceToDebug = true 349 } 350 } 351 352 m := model.MapFromJson(r.Body) 353 lvl := m["level"] 354 msg := m["message"] 355 356 if len(msg) > 400 { 357 msg = msg[0:399] 358 } 359 360 msg = "Client Logs API Endpoint Message: " + msg 361 fields := []mlog.Field{ 362 mlog.String("type", "client_message"), 363 mlog.String("user_agent", c.AppContext.UserAgent()), 364 } 365 366 if !forceToDebug && lvl == "ERROR" { 367 mlog.Error(msg, fields...) 368 } else { 369 mlog.Debug(msg, fields...) 370 } 371 372 m["message"] = msg 373 w.Write([]byte(model.MapToJson(m))) 374 } 375 376 func getAnalytics(c *Context, w http.ResponseWriter, r *http.Request) { 377 name := r.URL.Query().Get("name") 378 teamId := r.URL.Query().Get("team_id") 379 380 if name == "" { 381 name = "standard" 382 } 383 384 if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_GET_ANALYTICS) { 385 c.SetPermissionError(model.PERMISSION_GET_ANALYTICS) 386 return 387 } 388 389 rows, err := c.App.GetAnalytics(name, teamId) 390 if err != nil { 391 c.Err = err 392 return 393 } 394 395 if rows == nil { 396 c.SetInvalidParam("name") 397 return 398 } 399 400 w.Write([]byte(rows.ToJson())) 401 } 402 403 func getSupportedTimezones(c *Context, w http.ResponseWriter, r *http.Request) { 404 supportedTimezones := c.App.Timezones().GetSupported() 405 if supportedTimezones == nil { 406 supportedTimezones = make([]string, 0) 407 } 408 409 b, err := json.Marshal(supportedTimezones) 410 if err != nil { 411 c.Logger.Warn("Unable to marshal JSON in timezones.", mlog.Err(err)) 412 w.WriteHeader(http.StatusInternalServerError) 413 } 414 415 w.Write(b) 416 } 417 418 func testS3(c *Context, w http.ResponseWriter, r *http.Request) { 419 cfg := model.ConfigFromJson(r.Body) 420 if cfg == nil { 421 cfg = c.App.Config() 422 } 423 424 if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_TEST_S3) { 425 c.SetPermissionError(model.PERMISSION_TEST_S3) 426 return 427 } 428 429 if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin { 430 c.Err = model.NewAppError("testS3", "api.restricted_system_admin", nil, "", http.StatusForbidden) 431 return 432 } 433 434 err := c.App.CheckMandatoryS3Fields(&cfg.FileSettings) 435 if err != nil { 436 c.Err = err 437 return 438 } 439 440 if *cfg.FileSettings.AmazonS3SecretAccessKey == model.FAKE_SETTING { 441 cfg.FileSettings.AmazonS3SecretAccessKey = c.App.Config().FileSettings.AmazonS3SecretAccessKey 442 } 443 444 appErr := c.App.TestFileStoreConnectionWithConfig(&cfg.FileSettings) 445 if appErr != nil { 446 c.Err = appErr 447 return 448 } 449 450 ReturnStatusOK(w) 451 } 452 453 func getRedirectLocation(c *Context, w http.ResponseWriter, r *http.Request) { 454 m := make(map[string]string) 455 m["location"] = "" 456 457 if !*c.App.Config().ServiceSettings.EnableLinkPreviews { 458 w.Write([]byte(model.MapToJson(m))) 459 return 460 } 461 462 url := r.URL.Query().Get("url") 463 if url == "" { 464 c.SetInvalidParam("url") 465 return 466 } 467 468 var location string 469 if err := redirectLocationDataCache.Get(url, &location); err == nil { 470 m["location"] = location 471 w.Write([]byte(model.MapToJson(m))) 472 return 473 } 474 475 client := c.App.HTTPService().MakeClient(false) 476 client.CheckRedirect = func(req *http.Request, via []*http.Request) error { 477 return http.ErrUseLastResponse 478 } 479 480 res, err := client.Head(url) 481 if err != nil { 482 // Cache failures to prevent retries. 483 redirectLocationDataCache.SetWithExpiry(url, "", 1*time.Hour) 484 // Always return a success status and a JSON string to limit information returned to client. 485 w.Write([]byte(model.MapToJson(m))) 486 return 487 } 488 defer func() { 489 io.Copy(ioutil.Discard, res.Body) 490 res.Body.Close() 491 }() 492 493 location = res.Header.Get("Location") 494 redirectLocationDataCache.SetWithExpiry(url, location, 1*time.Hour) 495 m["location"] = location 496 497 w.Write([]byte(model.MapToJson(m))) 498 } 499 500 func pushNotificationAck(c *Context, w http.ResponseWriter, r *http.Request) { 501 ack, err := model.PushNotificationAckFromJson(r.Body) 502 if err != nil { 503 c.Err = model.NewAppError("pushNotificationAck", 504 "api.push_notifications_ack.message.parse.app_error", 505 nil, 506 err.Error(), 507 http.StatusBadRequest, 508 ) 509 return 510 } 511 512 if _, appErr := c.App.GetPostIfAuthorized(ack.PostId, c.AppContext.Session()); appErr != nil { 513 c.Err = appErr 514 return 515 } 516 517 if !*c.App.Config().EmailSettings.SendPushNotifications { 518 c.Err = model.NewAppError("pushNotificationAck", "api.push_notification.disabled.app_error", nil, "", http.StatusNotImplemented) 519 return 520 } 521 522 err = c.App.SendAckToPushProxy(ack) 523 if ack.IsIdLoaded { 524 if err != nil { 525 // Log the error only, then continue to fetch notification message 526 c.App.NotificationsLog().Error("Notification ack not sent to push proxy", 527 mlog.String("ackId", ack.Id), 528 mlog.String("type", ack.NotificationType), 529 mlog.String("postId", ack.PostId), 530 mlog.String("status", err.Error()), 531 ) 532 } 533 534 notificationInterface := c.App.Notification() 535 536 if notificationInterface == nil { 537 c.Err = model.NewAppError("pushNotificationAck", "api.system.id_loaded.not_available.app_error", nil, "", http.StatusFound) 538 return 539 } 540 541 msg, appError := notificationInterface.GetNotificationMessage(ack, c.AppContext.Session().UserId) 542 if appError != nil { 543 c.Err = model.NewAppError("pushNotificationAck", "api.push_notification.id_loaded.fetch.app_error", nil, appError.Error(), http.StatusInternalServerError) 544 return 545 } 546 547 w.Write([]byte(msg.ToJson())) 548 549 return 550 } else if err != nil { 551 c.Err = model.NewAppError("pushNotificationAck", "api.push_notifications_ack.forward.app_error", nil, err.Error(), http.StatusInternalServerError) 552 return 553 } 554 555 ReturnStatusOK(w) 556 } 557 558 func setServerBusy(c *Context, w http.ResponseWriter, r *http.Request) { 559 if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_MANAGE_SYSTEM) { 560 c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) 561 return 562 } 563 564 // number of seconds to keep server marked busy 565 secs := r.URL.Query().Get("seconds") 566 if secs == "" { 567 secs = strconv.FormatInt(DefaultServerBusySeconds, 10) 568 } 569 570 i, err := strconv.ParseInt(secs, 10, 64) 571 if err != nil || i <= 0 || i > MaxServerBusySeconds { 572 c.SetInvalidUrlParam(fmt.Sprintf("seconds must be 1 - %d", MaxServerBusySeconds)) 573 return 574 } 575 576 auditRec := c.MakeAuditRecord("setServerBusy", audit.Fail) 577 defer c.LogAuditRec(auditRec) 578 auditRec.AddMeta("seconds", i) 579 580 c.App.Srv().Busy.Set(time.Second * time.Duration(i)) 581 mlog.Warn("server busy state activated - non-critical services disabled", mlog.Int64("seconds", i)) 582 583 auditRec.Success() 584 ReturnStatusOK(w) 585 } 586 587 func clearServerBusy(c *Context, w http.ResponseWriter, r *http.Request) { 588 if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_MANAGE_SYSTEM) { 589 c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) 590 return 591 } 592 593 auditRec := c.MakeAuditRecord("clearServerBusy", audit.Fail) 594 defer c.LogAuditRec(auditRec) 595 596 c.App.Srv().Busy.Clear() 597 mlog.Info("server busy state cleared - non-critical services enabled") 598 599 auditRec.Success() 600 ReturnStatusOK(w) 601 } 602 603 func getServerBusyExpires(c *Context, w http.ResponseWriter, r *http.Request) { 604 if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_MANAGE_SYSTEM) { 605 c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) 606 return 607 } 608 w.Write([]byte(c.App.Srv().Busy.ToJson())) 609 } 610 611 func upgradeToEnterprise(c *Context, w http.ResponseWriter, r *http.Request) { 612 auditRec := c.MakeAuditRecord("upgradeToEnterprise", audit.Fail) 613 defer c.LogAuditRec(auditRec) 614 615 if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_MANAGE_SYSTEM) { 616 c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) 617 return 618 } 619 620 if model.BuildEnterpriseReady == "true" { 621 c.Err = model.NewAppError("upgradeToEnterprise", "api.upgrade_to_enterprise.already-enterprise.app_error", nil, "", http.StatusTooManyRequests) 622 return 623 } 624 625 percentage, _ := c.App.Srv().UpgradeToE0Status() 626 627 if percentage > 0 { 628 c.Err = model.NewAppError("upgradeToEnterprise", "api.upgrade_to_enterprise.app_error", nil, "", http.StatusTooManyRequests) 629 return 630 } 631 if percentage == 100 { 632 c.Err = model.NewAppError("upgradeToEnterprise", "api.upgrade_to_enterprise.already-done.app_error", nil, "", http.StatusTooManyRequests) 633 return 634 } 635 636 if err := c.App.Srv().CanIUpgradeToE0(); err != nil { 637 var ipErr *upgrader.InvalidPermissions 638 var iaErr *upgrader.InvalidArch 639 switch { 640 case errors.As(err, &ipErr): 641 params := map[string]interface{}{ 642 "MattermostUsername": ipErr.MattermostUsername, 643 "FileUsername": ipErr.FileUsername, 644 "Path": ipErr.Path, 645 } 646 if ipErr.ErrType == "invalid-user-and-permission" { 647 c.Err = model.NewAppError("upgradeToEnterprise", "api.upgrade_to_enterprise.invalid-user-and-permission.app_error", params, err.Error(), http.StatusForbidden) 648 } else if ipErr.ErrType == "invalid-user" { 649 c.Err = model.NewAppError("upgradeToEnterprise", "api.upgrade_to_enterprise.invalid-user.app_error", params, err.Error(), http.StatusForbidden) 650 } else if ipErr.ErrType == "invalid-permission" { 651 c.Err = model.NewAppError("upgradeToEnterprise", "api.upgrade_to_enterprise.invalid-permission.app_error", params, err.Error(), http.StatusForbidden) 652 } 653 case errors.As(err, &iaErr): 654 c.Err = model.NewAppError("upgradeToEnterprise", "api.upgrade_to_enterprise.system_not_supported.app_error", nil, err.Error(), http.StatusForbidden) 655 default: 656 c.Err = model.NewAppError("upgradeToEnterprise", "api.upgrade_to_enterprise.generic_error.app_error", nil, err.Error(), http.StatusForbidden) 657 } 658 return 659 } 660 661 c.App.Srv().Go(func() { 662 c.App.Srv().UpgradeToE0() 663 }) 664 665 auditRec.Success() 666 w.WriteHeader(http.StatusAccepted) 667 ReturnStatusOK(w) 668 } 669 670 func upgradeToEnterpriseStatus(c *Context, w http.ResponseWriter, r *http.Request) { 671 if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_MANAGE_SYSTEM) { 672 c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) 673 return 674 } 675 676 percentage, err := c.App.Srv().UpgradeToE0Status() 677 var s map[string]interface{} 678 if err != nil { 679 var isErr *upgrader.InvalidSignature 680 switch { 681 case errors.As(err, &isErr): 682 appErr := model.NewAppError("upgradeToEnterpriseStatus", "api.upgrade_to_enterprise_status.app_error", nil, err.Error(), http.StatusBadRequest) 683 s = map[string]interface{}{"percentage": 0, "error": appErr.Message} 684 default: 685 appErr := model.NewAppError("upgradeToEnterpriseStatus", "api.upgrade_to_enterprise_status.signature.app_error", nil, err.Error(), http.StatusBadRequest) 686 s = map[string]interface{}{"percentage": 0, "error": appErr.Message} 687 } 688 } else { 689 s = map[string]interface{}{"percentage": percentage, "error": nil} 690 } 691 692 w.Write([]byte(model.StringInterfaceToJson(s))) 693 } 694 695 func restart(c *Context, w http.ResponseWriter, r *http.Request) { 696 auditRec := c.MakeAuditRecord("restartServer", audit.Fail) 697 defer c.LogAuditRec(auditRec) 698 699 if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_MANAGE_SYSTEM) { 700 c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) 701 return 702 } 703 704 auditRec.Success() 705 ReturnStatusOK(w) 706 time.Sleep(1 * time.Second) 707 708 go func() { 709 c.App.Srv().Restart() 710 }() 711 } 712 713 func getWarnMetricsStatus(c *Context, w http.ResponseWriter, r *http.Request) { 714 if !c.App.SessionHasPermissionToAny(*c.AppContext.Session(), model.SysconsoleReadPermissions) { 715 c.SetPermissionError(model.SysconsoleReadPermissions...) 716 return 717 } 718 719 license := c.App.Srv().License() 720 if license != nil { 721 mlog.Debug("License is present, skip.") 722 return 723 } 724 725 status, err := c.App.GetWarnMetricsStatus() 726 if err != nil { 727 c.Err = err 728 return 729 } 730 731 w.Write([]byte(model.MapWarnMetricStatusToJson(status))) 732 } 733 734 func sendWarnMetricAckEmail(c *Context, w http.ResponseWriter, r *http.Request) { 735 auditRec := c.MakeAuditRecord("sendWarnMetricAckEmail", audit.Fail) 736 defer c.LogAuditRec(auditRec) 737 c.LogAudit("attempt") 738 739 if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_MANAGE_SYSTEM) { 740 c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) 741 return 742 } 743 744 license := c.App.Srv().License() 745 if license != nil { 746 mlog.Debug("License is present, skip.") 747 return 748 } 749 750 user, appErr := c.App.GetUser(c.AppContext.Session().UserId) 751 if appErr != nil { 752 c.Err = appErr 753 return 754 } 755 756 ack := model.SendWarnMetricAckFromJson(r.Body) 757 if ack == nil { 758 c.SetInvalidParam("ack") 759 return 760 } 761 762 appErr = c.App.NotifyAndSetWarnMetricAck(c.Params.WarnMetricId, user, ack.ForceAck, false) 763 if appErr != nil { 764 c.Err = appErr 765 } 766 767 auditRec.Success() 768 ReturnStatusOK(w) 769 } 770 771 func requestTrialLicenseAndAckWarnMetric(c *Context, w http.ResponseWriter, r *http.Request) { 772 auditRec := c.MakeAuditRecord("requestTrialLicenseAndAckWarnMetric", audit.Fail) 773 defer c.LogAuditRec(auditRec) 774 c.LogAudit("attempt") 775 776 if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_MANAGE_SYSTEM) { 777 c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) 778 return 779 } 780 781 if model.BuildEnterpriseReady != "true" { 782 mlog.Debug("Not Enterprise Edition, skip.") 783 return 784 } 785 786 license := c.App.Srv().License() 787 if license != nil { 788 mlog.Debug("License is present, skip.") 789 return 790 } 791 792 if err := c.App.RequestLicenseAndAckWarnMetric(c.AppContext, c.Params.WarnMetricId, false); err != nil { 793 c.Err = err 794 return 795 } 796 797 auditRec.Success() 798 ReturnStatusOK(w) 799 } 800 801 func getProductNotices(c *Context, w http.ResponseWriter, r *http.Request) { 802 c.RequireTeamId() 803 if c.Err != nil { 804 return 805 } 806 807 client, parseError := model.NoticeClientTypeFromString(r.URL.Query().Get("client")) 808 if parseError != nil { 809 c.SetInvalidParam("client") 810 return 811 } 812 clientVersion := r.URL.Query().Get("clientVersion") 813 locale := r.URL.Query().Get("locale") 814 815 notices, err := c.App.GetProductNotices(c.AppContext, c.AppContext.Session().UserId, c.Params.TeamId, client, clientVersion, locale) 816 817 if err != nil { 818 c.Err = err 819 return 820 } 821 result, _ := notices.Marshal() 822 _, _ = w.Write(result) 823 } 824 825 func updateViewedProductNotices(c *Context, w http.ResponseWriter, r *http.Request) { 826 auditRec := c.MakeAuditRecord("updateViewedProductNotices", audit.Fail) 827 defer c.LogAuditRec(auditRec) 828 c.LogAudit("attempt") 829 830 ids := model.ArrayFromJson(r.Body) 831 err := c.App.UpdateViewedProductNotices(c.AppContext.Session().UserId, ids) 832 if err != nil { 833 c.Err = err 834 return 835 } 836 837 auditRec.Success() 838 ReturnStatusOK(w) 839 }