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  }