github.com/haalcala/mattermost-server-change-repo/v5@v5.33.2/app/server.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package app
     5  
     6  import (
     7  	"context"
     8  	"crypto/tls"
     9  	"encoding/json"
    10  	"fmt"
    11  	"hash/maphash"
    12  	"io/ioutil"
    13  	"net"
    14  	"net/http"
    15  	"net/url"
    16  	"os"
    17  	"os/exec"
    18  	"path"
    19  	"path/filepath"
    20  	"runtime"
    21  	"strconv"
    22  	"strings"
    23  	"sync"
    24  	"sync/atomic"
    25  	"syscall"
    26  	"time"
    27  
    28  	"gopkg.in/yaml.v2"
    29  
    30  	"github.com/getsentry/sentry-go"
    31  	sentryhttp "github.com/getsentry/sentry-go/http"
    32  	"github.com/gorilla/mux"
    33  	"github.com/pkg/errors"
    34  	"github.com/rs/cors"
    35  	"golang.org/x/crypto/acme/autocert"
    36  
    37  	"github.com/mattermost/mattermost-server/v5/audit"
    38  	"github.com/mattermost/mattermost-server/v5/config"
    39  	"github.com/mattermost/mattermost-server/v5/einterfaces"
    40  	"github.com/mattermost/mattermost-server/v5/jobs"
    41  	"github.com/mattermost/mattermost-server/v5/mlog"
    42  	"github.com/mattermost/mattermost-server/v5/model"
    43  	"github.com/mattermost/mattermost-server/v5/plugin"
    44  	"github.com/mattermost/mattermost-server/v5/services/awsmeter"
    45  	"github.com/mattermost/mattermost-server/v5/services/cache"
    46  	"github.com/mattermost/mattermost-server/v5/services/filesstore"
    47  	"github.com/mattermost/mattermost-server/v5/services/httpservice"
    48  	"github.com/mattermost/mattermost-server/v5/services/imageproxy"
    49  	"github.com/mattermost/mattermost-server/v5/services/mailservice"
    50  	"github.com/mattermost/mattermost-server/v5/services/searchengine"
    51  	"github.com/mattermost/mattermost-server/v5/services/searchengine/bleveengine"
    52  	"github.com/mattermost/mattermost-server/v5/services/telemetry"
    53  	"github.com/mattermost/mattermost-server/v5/services/timezones"
    54  	"github.com/mattermost/mattermost-server/v5/services/tracing"
    55  	"github.com/mattermost/mattermost-server/v5/services/upgrader"
    56  	"github.com/mattermost/mattermost-server/v5/store"
    57  	"github.com/mattermost/mattermost-server/v5/store/localcachelayer"
    58  	"github.com/mattermost/mattermost-server/v5/store/retrylayer"
    59  	"github.com/mattermost/mattermost-server/v5/store/searchlayer"
    60  	"github.com/mattermost/mattermost-server/v5/store/sqlstore"
    61  	"github.com/mattermost/mattermost-server/v5/store/timerlayer"
    62  	"github.com/mattermost/mattermost-server/v5/utils"
    63  )
    64  
    65  var MaxNotificationsPerChannelDefault int64 = 1000000
    66  
    67  // declaring this as var to allow overriding in tests
    68  var SentryDSN = "placeholder_sentry_dsn"
    69  
    70  type Server struct {
    71  	sqlStore           *sqlstore.SqlStore
    72  	Store              store.Store
    73  	WebSocketRouter    *WebSocketRouter
    74  	AppInitializedOnce sync.Once
    75  
    76  	// RootRouter is the starting point for all HTTP requests to the server.
    77  	RootRouter *mux.Router
    78  
    79  	// LocalRouter is the starting point for all the local UNIX socket
    80  	// requests to the server
    81  	LocalRouter *mux.Router
    82  
    83  	// Router is the starting point for all web, api4 and ws requests to the server. It differs
    84  	// from RootRouter only if the SiteURL contains a /subpath.
    85  	Router *mux.Router
    86  
    87  	Server      *http.Server
    88  	ListenAddr  *net.TCPAddr
    89  	RateLimiter *RateLimiter
    90  	Busy        *Busy
    91  
    92  	localModeServer *http.Server
    93  
    94  	didFinishListen chan struct{}
    95  
    96  	goroutineCount      int32
    97  	goroutineExitSignal chan struct{}
    98  
    99  	PluginsEnvironment     *plugin.Environment
   100  	PluginConfigListenerId string
   101  	PluginsLock            sync.RWMutex
   102  
   103  	EmailService *EmailService
   104  
   105  	hubs     []*Hub
   106  	hashSeed maphash.Seed
   107  
   108  	PushNotificationsHub   PushNotificationsHub
   109  	pushNotificationClient *http.Client // TODO: move this to it's own package
   110  
   111  	runjobs bool
   112  	Jobs    *jobs.JobServer
   113  
   114  	clusterLeaderListeners sync.Map
   115  
   116  	licenseValue       atomic.Value
   117  	clientLicenseValue atomic.Value
   118  	licenseListeners   map[string]func(*model.License, *model.License)
   119  
   120  	timezones *timezones.Timezones
   121  
   122  	newStore func() (store.Store, error)
   123  
   124  	htmlTemplateWatcher     *utils.HTMLTemplateWatcher
   125  	sessionCache            cache.Cache
   126  	seenPendingPostIdsCache cache.Cache
   127  	statusCache             cache.Cache
   128  	configListenerId        string
   129  	licenseListenerId       string
   130  	logListenerId           string
   131  	clusterLeaderListenerId string
   132  	searchConfigListenerId  string
   133  	searchLicenseListenerId string
   134  	loggerLicenseListenerId string
   135  	configStore             *config.Store
   136  	postActionCookieSecret  []byte
   137  
   138  	advancedLogListenerCleanup func()
   139  
   140  	pluginCommands     []*PluginCommand
   141  	pluginCommandsLock sync.RWMutex
   142  
   143  	asymmetricSigningKey atomic.Value
   144  	clientConfig         atomic.Value
   145  	clientConfigHash     atomic.Value
   146  	limitedClientConfig  atomic.Value
   147  
   148  	telemetryService *telemetry.TelemetryService
   149  
   150  	phase2PermissionsMigrationComplete bool
   151  
   152  	HTTPService httpservice.HTTPService
   153  
   154  	ImageProxy *imageproxy.ImageProxy
   155  
   156  	Audit            *audit.Audit
   157  	Log              *mlog.Logger
   158  	NotificationsLog *mlog.Logger
   159  
   160  	joinCluster       bool
   161  	startMetrics      bool
   162  	startSearchEngine bool
   163  
   164  	SearchEngine *searchengine.Broker
   165  
   166  	AccountMigration einterfaces.AccountMigrationInterface
   167  	Cluster          einterfaces.ClusterInterface
   168  	Compliance       einterfaces.ComplianceInterface
   169  	DataRetention    einterfaces.DataRetentionInterface
   170  	Ldap             einterfaces.LdapInterface
   171  	MessageExport    einterfaces.MessageExportInterface
   172  	Cloud            einterfaces.CloudInterface
   173  	Metrics          einterfaces.MetricsInterface
   174  	Notification     einterfaces.NotificationInterface
   175  	Saml             einterfaces.SamlInterface
   176  
   177  	CacheProvider cache.Provider
   178  
   179  	tracer *tracing.Tracer
   180  
   181  	// These are used to prevent concurrent upload requests
   182  	// for a given upload session which could cause inconsistencies
   183  	// and data corruption.
   184  	uploadLockMapMut sync.Mutex
   185  	uploadLockMap    map[string]bool
   186  
   187  	featureFlagSynchronizer      *config.FeatureFlagSynchronizer
   188  	featureFlagStop              chan struct{}
   189  	featureFlagStopped           chan struct{}
   190  	featureFlagSynchronizerMutex sync.Mutex
   191  }
   192  
   193  func NewServer(options ...Option) (*Server, error) {
   194  	rootRouter := mux.NewRouter()
   195  	localRouter := mux.NewRouter()
   196  
   197  	s := &Server{
   198  		goroutineExitSignal: make(chan struct{}, 1),
   199  		RootRouter:          rootRouter,
   200  		LocalRouter:         localRouter,
   201  		licenseListeners:    map[string]func(*model.License, *model.License){},
   202  		hashSeed:            maphash.MakeSeed(),
   203  		uploadLockMap:       map[string]bool{},
   204  	}
   205  
   206  	for _, option := range options {
   207  		if err := option(s); err != nil {
   208  			return nil, errors.Wrap(err, "failed to apply option")
   209  		}
   210  	}
   211  
   212  	if s.configStore == nil {
   213  		innerStore, err := config.NewFileStore("config.json", true)
   214  		if err != nil {
   215  			return nil, errors.Wrap(err, "failed to load config")
   216  		}
   217  		configStore, err := config.NewStoreFromBacking(innerStore, nil, false)
   218  		if err != nil {
   219  			return nil, errors.Wrap(err, "failed to load config")
   220  		}
   221  
   222  		s.configStore = configStore
   223  	}
   224  
   225  	if err := s.initLogging(); err != nil {
   226  		mlog.Error("Could not initiate logging", mlog.Err(err))
   227  	}
   228  
   229  	// This is called after initLogging() to avoid a race condition.
   230  	mlog.Info("Server is initializing...", mlog.String("go_version", runtime.Version()))
   231  
   232  	// It is important to initialize the hub only after the global logger is set
   233  	// to avoid race conditions while logging from inside the hub.
   234  	fakeApp := New(ServerConnector(s))
   235  	fakeApp.HubStart()
   236  
   237  	if *s.Config().LogSettings.EnableDiagnostics && *s.Config().LogSettings.EnableSentry {
   238  		if strings.Contains(SentryDSN, "placeholder") {
   239  			mlog.Warn("Sentry reporting is enabled, but SENTRY_DSN is not set. Disabling reporting.")
   240  		} else {
   241  			if err := sentry.Init(sentry.ClientOptions{
   242  				Dsn:              SentryDSN,
   243  				Release:          model.BuildHash,
   244  				AttachStacktrace: true,
   245  				BeforeSend: func(event *sentry.Event, hint *sentry.EventHint) *sentry.Event {
   246  					// sanitize data sent to sentry to reduce exposure of PII
   247  					if event.Request != nil {
   248  						event.Request.Cookies = ""
   249  						event.Request.QueryString = ""
   250  						event.Request.Headers = nil
   251  						event.Request.Data = ""
   252  					}
   253  					return event
   254  				},
   255  			}); err != nil {
   256  				mlog.Warn("Sentry could not be initiated, probably bad DSN?", mlog.Err(err))
   257  			}
   258  		}
   259  	}
   260  
   261  	if *s.Config().ServiceSettings.EnableOpenTracing {
   262  		tracer, err := tracing.New()
   263  		if err != nil {
   264  			return nil, err
   265  		}
   266  		s.tracer = tracer
   267  	}
   268  
   269  	s.HTTPService = httpservice.MakeHTTPService(s)
   270  	s.pushNotificationClient = s.HTTPService.MakeClient(true)
   271  
   272  	s.ImageProxy = imageproxy.MakeImageProxy(s, s.HTTPService, s.Log)
   273  
   274  	if err := utils.TranslationsPreInit(); err != nil {
   275  		return nil, errors.Wrapf(err, "unable to load Mattermost translation files")
   276  	}
   277  	model.AppErrorInit(utils.T)
   278  
   279  	searchEngine := searchengine.NewBroker(s.Config(), s.Jobs)
   280  	bleveEngine := bleveengine.NewBleveEngine(s.Config(), s.Jobs)
   281  	if err := bleveEngine.Start(); err != nil {
   282  		return nil, err
   283  	}
   284  	searchEngine.RegisterBleveEngine(bleveEngine)
   285  	s.SearchEngine = searchEngine
   286  
   287  	// at the moment we only have this implementation
   288  	// in the future the cache provider will be built based on the loaded config
   289  	s.CacheProvider = cache.NewProvider()
   290  	if err := s.CacheProvider.Connect(); err != nil {
   291  		return nil, errors.Wrapf(err, "Unable to connect to cache provider")
   292  	}
   293  
   294  	var err error
   295  	if s.sessionCache, err = s.CacheProvider.NewCache(&cache.CacheOptions{
   296  		Size:           model.SESSION_CACHE_SIZE,
   297  		Striped:        true,
   298  		StripedBuckets: maxInt(runtime.NumCPU()-1, 1),
   299  	}); err != nil {
   300  		return nil, errors.Wrap(err, "Unable to create session cache")
   301  	}
   302  	if s.seenPendingPostIdsCache, err = s.CacheProvider.NewCache(&cache.CacheOptions{
   303  		Size: PendingPostIDsCacheSize,
   304  	}); err != nil {
   305  		return nil, errors.Wrap(err, "Unable to create pending post ids cache")
   306  	}
   307  	if s.statusCache, err = s.CacheProvider.NewCache(&cache.CacheOptions{
   308  		Size:           model.STATUS_CACHE_SIZE,
   309  		Striped:        true,
   310  		StripedBuckets: maxInt(runtime.NumCPU()-1, 1),
   311  	}); err != nil {
   312  		return nil, errors.Wrap(err, "Unable to create status cache")
   313  	}
   314  
   315  	s.createPushNotificationsHub()
   316  
   317  	if err2 := utils.InitTranslations(s.Config().LocalizationSettings); err2 != nil {
   318  		return nil, errors.Wrapf(err2, "unable to load Mattermost translation files")
   319  	}
   320  
   321  	s.initEnterprise()
   322  
   323  	if s.newStore == nil {
   324  		s.newStore = func() (store.Store, error) {
   325  			s.sqlStore = sqlstore.New(s.Config().SqlSettings, s.Metrics)
   326  			if s.sqlStore.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   327  				ver, err2 := s.sqlStore.GetDbVersion(true)
   328  				if err2 != nil {
   329  					return nil, errors.Wrap(err2, "cannot get DB version")
   330  				}
   331  				intVer, err2 := strconv.Atoi(ver)
   332  				if err2 != nil {
   333  					return nil, errors.Wrap(err2, "cannot parse DB version")
   334  				}
   335  				if intVer < sqlstore.MinimumRequiredPostgresVersion {
   336  					return nil, fmt.Errorf("minimum required postgres version is %s; found %s", sqlstore.VersionString(sqlstore.MinimumRequiredPostgresVersion), sqlstore.VersionString(intVer))
   337  				}
   338  			}
   339  
   340  			lcl, err2 := localcachelayer.NewLocalCacheLayer(
   341  				retrylayer.New(s.sqlStore),
   342  				s.Metrics,
   343  				s.Cluster,
   344  				s.CacheProvider,
   345  			)
   346  			if err2 != nil {
   347  				return nil, errors.Wrap(err2, "cannot create local cache layer")
   348  			}
   349  
   350  			searchStore := searchlayer.NewSearchLayer(
   351  				lcl,
   352  				s.SearchEngine,
   353  				s.Config(),
   354  			)
   355  
   356  			s.AddConfigListener(func(prevCfg, cfg *model.Config) {
   357  				searchStore.UpdateConfig(cfg)
   358  			})
   359  
   360  			s.sqlStore.UpdateLicense(s.License())
   361  			s.AddLicenseListener(func(oldLicense, newLicense *model.License) {
   362  				s.sqlStore.UpdateLicense(newLicense)
   363  			})
   364  
   365  			return timerlayer.New(
   366  				searchStore,
   367  				s.Metrics,
   368  			), nil
   369  		}
   370  	}
   371  
   372  	if htmlTemplateWatcher, err2 := utils.NewHTMLTemplateWatcher("templates"); err2 != nil {
   373  		mlog.Error("Failed to parse server templates", mlog.Err(err2))
   374  	} else {
   375  		s.htmlTemplateWatcher = htmlTemplateWatcher
   376  	}
   377  
   378  	s.Store, err = s.newStore()
   379  	if err != nil {
   380  		return nil, errors.Wrap(err, "cannot create store")
   381  	}
   382  
   383  	s.configListenerId = s.AddConfigListener(func(_, _ *model.Config) {
   384  		s.configOrLicenseListener()
   385  
   386  		message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_CONFIG_CHANGED, "", "", "", nil)
   387  
   388  		message.Add("config", s.ClientConfigWithComputed())
   389  		s.Go(func() {
   390  			s.Publish(message)
   391  		})
   392  	})
   393  	s.licenseListenerId = s.AddLicenseListener(func(oldLicense, newLicense *model.License) {
   394  		s.configOrLicenseListener()
   395  
   396  		message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_LICENSE_CHANGED, "", "", "", nil)
   397  		message.Add("license", s.GetSanitizedClientLicense())
   398  		s.Go(func() {
   399  			s.Publish(message)
   400  		})
   401  
   402  	})
   403  
   404  	s.telemetryService = telemetry.New(s, s.Store, s.SearchEngine, s.Log)
   405  
   406  	emailService, err := NewEmailService(s)
   407  	if err != nil {
   408  		return nil, errors.Wrapf(err, "unable to initialize email service")
   409  	}
   410  	s.EmailService = emailService
   411  
   412  	if model.BuildEnterpriseReady == "true" {
   413  		s.LoadLicense()
   414  	}
   415  
   416  	s.setupFeatureFlags()
   417  
   418  	s.initJobs()
   419  
   420  	s.clusterLeaderListenerId = s.AddClusterLeaderChangedListener(func() {
   421  		mlog.Info("Cluster leader changed. Determining if job schedulers should be running:", mlog.Bool("isLeader", s.IsLeader()))
   422  		if s.Jobs != nil && s.Jobs.Schedulers != nil {
   423  			s.Jobs.Schedulers.HandleClusterLeaderChange(s.IsLeader())
   424  		}
   425  		s.setupFeatureFlags()
   426  	})
   427  
   428  	if s.joinCluster && s.Cluster != nil {
   429  		s.Cluster.StartInterNodeCommunication()
   430  	}
   431  
   432  	if err = s.ensureAsymmetricSigningKey(); err != nil {
   433  		return nil, errors.Wrapf(err, "unable to ensure asymmetric signing key")
   434  	}
   435  
   436  	if err = s.ensurePostActionCookieSecret(); err != nil {
   437  		return nil, errors.Wrapf(err, "unable to ensure PostAction cookie secret")
   438  	}
   439  
   440  	if err = s.ensureInstallationDate(); err != nil {
   441  		return nil, errors.Wrapf(err, "unable to ensure installation date")
   442  	}
   443  
   444  	if err = s.ensureFirstServerRunTimestamp(); err != nil {
   445  		return nil, errors.Wrapf(err, "unable to ensure first run timestamp")
   446  	}
   447  
   448  	s.regenerateClientConfig()
   449  
   450  	subpath, err := utils.GetSubpathFromConfig(s.Config())
   451  	if err != nil {
   452  		return nil, errors.Wrap(err, "failed to parse SiteURL subpath")
   453  	}
   454  	s.Router = s.RootRouter.PathPrefix(subpath).Subrouter()
   455  
   456  	// FakeApp: remove this when we have the ServePluginRequest and ServePluginPublicRequest migrated in the server
   457  	pluginsRoute := s.Router.PathPrefix("/plugins/{plugin_id:[A-Za-z0-9\\_\\-\\.]+}").Subrouter()
   458  	pluginsRoute.HandleFunc("", fakeApp.ServePluginRequest)
   459  	pluginsRoute.HandleFunc("/public/{public_file:.*}", fakeApp.ServePluginPublicRequest)
   460  	pluginsRoute.HandleFunc("/{anything:.*}", fakeApp.ServePluginRequest)
   461  
   462  	// If configured with a subpath, redirect 404s at the root back into the subpath.
   463  	if subpath != "/" {
   464  		s.RootRouter.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   465  			r.URL.Path = path.Join(subpath, r.URL.Path)
   466  			http.Redirect(w, r, r.URL.String(), http.StatusFound)
   467  		})
   468  	}
   469  
   470  	s.WebSocketRouter = &WebSocketRouter{
   471  		server:   s,
   472  		handlers: make(map[string]webSocketHandler),
   473  	}
   474  	s.WebSocketRouter.app = fakeApp
   475  
   476  	mailConfig := s.MailServiceConfig()
   477  
   478  	if nErr := mailservice.TestConnection(mailConfig); nErr != nil {
   479  		mlog.Error("Mail server connection test is failed", mlog.Err(nErr))
   480  	}
   481  
   482  	if _, err = url.ParseRequestURI(*s.Config().ServiceSettings.SiteURL); err != nil {
   483  		mlog.Error("SiteURL must be set. Some features will operate incorrectly if the SiteURL is not set. See documentation for details: http://about.mattermost.com/default-site-url")
   484  	}
   485  
   486  	backend, appErr := s.FileBackend()
   487  	if appErr != nil {
   488  		mlog.Error("Problem with file storage settings", mlog.Err(appErr))
   489  	} else {
   490  		if nErr := backend.TestConnection(); nErr != nil {
   491  			mlog.Error("Problem with file storage settings", mlog.Err(nErr))
   492  		}
   493  	}
   494  
   495  	s.timezones = timezones.New()
   496  	// Start email batching because it's not like the other jobs
   497  	s.AddConfigListener(func(_, _ *model.Config) {
   498  		s.EmailService.InitEmailBatching()
   499  	})
   500  
   501  	// Start plugin health check job
   502  	pluginsEnvironment := s.PluginsEnvironment
   503  	if pluginsEnvironment != nil {
   504  		pluginsEnvironment.InitPluginHealthCheckJob(*s.Config().PluginSettings.Enable && *s.Config().PluginSettings.EnableHealthCheck)
   505  	}
   506  	s.AddConfigListener(func(_, c *model.Config) {
   507  		s.PluginsLock.RLock()
   508  		pluginsEnvironment := s.PluginsEnvironment
   509  		s.PluginsLock.RUnlock()
   510  		if pluginsEnvironment != nil {
   511  			pluginsEnvironment.InitPluginHealthCheckJob(*s.Config().PluginSettings.Enable && *c.PluginSettings.EnableHealthCheck)
   512  		}
   513  	})
   514  
   515  	logCurrentVersion := fmt.Sprintf("Current version is %v (%v/%v/%v/%v)", model.CurrentVersion, model.BuildNumber, model.BuildDate, model.BuildHash, model.BuildHashEnterprise)
   516  	mlog.Info(
   517  		logCurrentVersion,
   518  		mlog.String("current_version", model.CurrentVersion),
   519  		mlog.String("build_number", model.BuildNumber),
   520  		mlog.String("build_date", model.BuildDate),
   521  		mlog.String("build_hash", model.BuildHash),
   522  		mlog.String("build_hash_enterprise", model.BuildHashEnterprise),
   523  	)
   524  	if model.BuildEnterpriseReady == "true" {
   525  		mlog.Info("Enterprise Build", mlog.Bool("enterprise_build", true))
   526  	} else {
   527  		mlog.Info("Team Edition Build", mlog.Bool("enterprise_build", false))
   528  	}
   529  
   530  	pwd, _ := os.Getwd()
   531  	mlog.Info("Printing current working", mlog.String("directory", pwd))
   532  	mlog.Info("Loaded config", mlog.String("source", s.configStore.String()))
   533  
   534  	s.checkPushNotificationServerUrl()
   535  
   536  	license := s.License()
   537  	if license == nil {
   538  		s.UpdateConfig(func(cfg *model.Config) {
   539  			cfg.TeamSettings.MaxNotificationsPerChannel = &MaxNotificationsPerChannelDefault
   540  		})
   541  	}
   542  
   543  	s.ReloadConfig()
   544  
   545  	allowAdvancedLogging := license != nil && *license.Features.AdvancedLogging
   546  
   547  	if s.Audit == nil {
   548  		s.Audit = &audit.Audit{}
   549  		s.Audit.Init(audit.DefMaxQueueSize)
   550  		if err = s.configureAudit(s.Audit, allowAdvancedLogging); err != nil {
   551  			mlog.Error("Error configuring audit", mlog.Err(err))
   552  		}
   553  	}
   554  
   555  	s.removeUnlicensedLogTargets(license)
   556  	s.enableLoggingMetrics()
   557  
   558  	s.loggerLicenseListenerId = s.AddLicenseListener(func(oldLicense, newLicense *model.License) {
   559  		s.removeUnlicensedLogTargets(newLicense)
   560  		s.enableLoggingMetrics()
   561  	})
   562  
   563  	// Enable developer settings if this is a "dev" build
   564  	if model.BuildNumber == "dev" {
   565  		s.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableDeveloper = true })
   566  	}
   567  
   568  	if err = s.Store.Status().ResetAll(); err != nil {
   569  		mlog.Error("Error to reset the server status.", mlog.Err(err))
   570  	}
   571  
   572  	if s.startMetrics && s.Metrics != nil {
   573  		s.Metrics.StartServer()
   574  	}
   575  
   576  	s.SearchEngine.UpdateConfig(s.Config())
   577  	searchConfigListenerId, searchLicenseListenerId := s.StartSearchEngine()
   578  	s.searchConfigListenerId = searchConfigListenerId
   579  	s.searchLicenseListenerId = searchLicenseListenerId
   580  
   581  	// if enabled - perform initial product notices fetch
   582  	if *s.Config().AnnouncementSettings.AdminNoticesEnabled || *s.Config().AnnouncementSettings.UserNoticesEnabled {
   583  		go fakeApp.UpdateProductNotices()
   584  	}
   585  
   586  	return s, nil
   587  }
   588  
   589  func maxInt(a, b int) int {
   590  	if a > b {
   591  		return a
   592  	}
   593  	return b
   594  }
   595  
   596  func (s *Server) RunJobs() {
   597  	if s.runjobs {
   598  		s.Go(func() {
   599  			runSecurityJob(s)
   600  		})
   601  		s.Go(func() {
   602  			firstRun, err := s.getFirstServerRunTimestamp()
   603  			if err != nil {
   604  				mlog.Warn("Fetching time of first server run failed. Setting to 'now'.")
   605  				s.ensureFirstServerRunTimestamp()
   606  				firstRun = utils.MillisFromTime(time.Now())
   607  			}
   608  			s.telemetryService.RunTelemetryJob(firstRun)
   609  		})
   610  		s.Go(func() {
   611  			runSessionCleanupJob(s)
   612  		})
   613  		s.Go(func() {
   614  			runTokenCleanupJob(s)
   615  		})
   616  		s.Go(func() {
   617  			runCommandWebhookCleanupJob(s)
   618  		})
   619  
   620  		if complianceI := s.Compliance; complianceI != nil {
   621  			complianceI.StartComplianceDailyJob()
   622  		}
   623  
   624  		if *s.Config().JobSettings.RunJobs && s.Jobs != nil {
   625  			s.Jobs.StartWorkers()
   626  		}
   627  		if *s.Config().JobSettings.RunScheduler && s.Jobs != nil {
   628  			s.Jobs.StartSchedulers()
   629  		}
   630  
   631  		if *s.Config().ServiceSettings.EnableAWSMetering {
   632  			runReportToAWSMeterJob(s)
   633  		}
   634  	}
   635  }
   636  
   637  // Global app options that should be applied to apps created by this server
   638  func (s *Server) AppOptions() []AppOption {
   639  	return []AppOption{
   640  		ServerConnector(s),
   641  	}
   642  }
   643  
   644  // Return Database type (postgres or mysql) and current version of Mattermost
   645  func (s *Server) DatabaseTypeAndMattermostVersion() (string, string) {
   646  	mattermostVersion, _ := s.Store.System().GetByName("Version")
   647  	return *s.Config().SqlSettings.DriverName, mattermostVersion.Value
   648  }
   649  
   650  // initLogging initializes and configures the logger. This may be called more than once.
   651  func (s *Server) initLogging() error {
   652  	if s.Log == nil {
   653  		s.Log = mlog.NewLogger(utils.MloggerConfigFromLoggerConfig(&s.Config().LogSettings, utils.GetLogFileLocation))
   654  	}
   655  
   656  	// Use this app logger as the global logger (eventually remove all instances of global logging).
   657  	// This is deferred because a copy is made of the logger and it must be fully configured before
   658  	// the copy is made.
   659  	defer mlog.InitGlobalLogger(s.Log)
   660  
   661  	// Redirect default Go logger to this logger.
   662  	defer mlog.RedirectStdLog(s.Log)
   663  
   664  	if s.NotificationsLog == nil {
   665  		notificationLogSettings := utils.GetLogSettingsFromNotificationsLogSettings(&s.Config().NotificationLogSettings)
   666  		s.NotificationsLog = mlog.NewLogger(utils.MloggerConfigFromLoggerConfig(notificationLogSettings, utils.GetNotificationsLogFileLocation)).
   667  			WithCallerSkip(1).With(mlog.String("logSource", "notifications"))
   668  	}
   669  
   670  	if s.logListenerId != "" {
   671  		s.RemoveConfigListener(s.logListenerId)
   672  	}
   673  	s.logListenerId = s.AddConfigListener(func(_, after *model.Config) {
   674  		s.Log.ChangeLevels(utils.MloggerConfigFromLoggerConfig(&after.LogSettings, utils.GetLogFileLocation))
   675  
   676  		notificationLogSettings := utils.GetLogSettingsFromNotificationsLogSettings(&after.NotificationLogSettings)
   677  		s.NotificationsLog.ChangeLevels(utils.MloggerConfigFromLoggerConfig(notificationLogSettings, utils.GetNotificationsLogFileLocation))
   678  	})
   679  
   680  	// Configure advanced logging.
   681  	// Advanced logging is E20 only, however logging must be initialized before the license
   682  	// file is loaded.  If no valid E20 license exists then advanced logging will be
   683  	// shutdown once license is loaded/checked.
   684  	if *s.Config().LogSettings.AdvancedLoggingConfig != "" {
   685  		dsn := *s.Config().LogSettings.AdvancedLoggingConfig
   686  		isJson := config.IsJsonMap(dsn)
   687  
   688  		// If this is a file based config we need the full path so it can be watched.
   689  		if !isJson && strings.HasPrefix(s.configStore.String(), "file://") && !filepath.IsAbs(dsn) {
   690  			configPath := strings.TrimPrefix(s.configStore.String(), "file://")
   691  			dsn = filepath.Join(filepath.Dir(configPath), dsn)
   692  		}
   693  
   694  		cfg, err := config.NewLogConfigSrc(dsn, isJson, s.configStore)
   695  		if err != nil {
   696  			return fmt.Errorf("invalid advanced logging config, %w", err)
   697  		}
   698  
   699  		if err := s.Log.ConfigAdvancedLogging(cfg.Get()); err != nil {
   700  			return fmt.Errorf("error configuring advanced logging, %w", err)
   701  		}
   702  
   703  		if !isJson {
   704  			mlog.Info("Loaded advanced logging config", mlog.String("source", dsn))
   705  		}
   706  
   707  		listenerId := cfg.AddListener(func(_, newCfg mlog.LogTargetCfg) {
   708  			if err := s.Log.ConfigAdvancedLogging(newCfg); err != nil {
   709  				mlog.Error("Error re-configuring advanced logging", mlog.Err(err))
   710  			} else {
   711  				mlog.Info("Re-configured advanced logging")
   712  			}
   713  		})
   714  
   715  		// In case initLogging is called more than once.
   716  		if s.advancedLogListenerCleanup != nil {
   717  			s.advancedLogListenerCleanup()
   718  		}
   719  
   720  		s.advancedLogListenerCleanup = func() {
   721  			cfg.RemoveListener(listenerId)
   722  		}
   723  	}
   724  	return nil
   725  }
   726  
   727  func (s *Server) removeUnlicensedLogTargets(license *model.License) {
   728  	if license != nil && *license.Features.AdvancedLogging {
   729  		// advanced logging enabled via license; no need to remove any targets
   730  		return
   731  	}
   732  
   733  	timeoutCtx, cancelCtx := context.WithTimeout(context.Background(), time.Second*10)
   734  	defer cancelCtx()
   735  
   736  	mlog.RemoveTargets(timeoutCtx, func(ti mlog.TargetInfo) bool {
   737  		return ti.Type != "*target.Writer" && ti.Type != "*target.File"
   738  	})
   739  }
   740  
   741  func (s *Server) enableLoggingMetrics() {
   742  	if s.Metrics == nil {
   743  		return
   744  	}
   745  
   746  	if err := mlog.EnableMetrics(s.Metrics.GetLoggerMetricsCollector()); err != nil {
   747  		mlog.Error("Failed to enable advanced logging metrics", mlog.Err(err))
   748  	} else {
   749  		mlog.Debug("Advanced logging metrics enabled")
   750  	}
   751  }
   752  
   753  const TimeToWaitForConnectionsToCloseOnServerShutdown = time.Second
   754  
   755  func (s *Server) StopHTTPServer() {
   756  	if s.Server != nil {
   757  		ctx, cancel := context.WithTimeout(context.Background(), TimeToWaitForConnectionsToCloseOnServerShutdown)
   758  		defer cancel()
   759  		didShutdown := false
   760  		for s.didFinishListen != nil && !didShutdown {
   761  			if err := s.Server.Shutdown(ctx); err != nil {
   762  				mlog.Warn("Unable to shutdown server", mlog.Err(err))
   763  			}
   764  			timer := time.NewTimer(time.Millisecond * 50)
   765  			select {
   766  			case <-s.didFinishListen:
   767  				didShutdown = true
   768  			case <-timer.C:
   769  			}
   770  			timer.Stop()
   771  		}
   772  		s.Server.Close()
   773  		s.Server = nil
   774  	}
   775  }
   776  
   777  func (s *Server) Shutdown() {
   778  	mlog.Info("Stopping Server...")
   779  
   780  	defer sentry.Flush(2 * time.Second)
   781  
   782  	s.HubStop()
   783  	s.ShutDownPlugins()
   784  	s.RemoveLicenseListener(s.licenseListenerId)
   785  	s.RemoveLicenseListener(s.loggerLicenseListenerId)
   786  	s.RemoveClusterLeaderChangedListener(s.clusterLeaderListenerId)
   787  
   788  	if s.tracer != nil {
   789  		if err := s.tracer.Close(); err != nil {
   790  			mlog.Warn("Unable to cleanly shutdown opentracing client", mlog.Err(err))
   791  		}
   792  	}
   793  
   794  	err := s.telemetryService.Shutdown()
   795  	if err != nil {
   796  		mlog.Warn("Unable to cleanly shutdown telemetry client", mlog.Err(err))
   797  	}
   798  
   799  	s.StopHTTPServer()
   800  	s.stopLocalModeServer()
   801  	// Push notification hub needs to be shutdown after HTTP server
   802  	// to prevent stray requests from generating a push notification after it's shut down.
   803  	s.StopPushNotificationsHubWorkers()
   804  
   805  	s.WaitForGoroutines()
   806  
   807  	if s.htmlTemplateWatcher != nil {
   808  		s.htmlTemplateWatcher.Close()
   809  	}
   810  
   811  	if s.advancedLogListenerCleanup != nil {
   812  		s.advancedLogListenerCleanup()
   813  		s.advancedLogListenerCleanup = nil
   814  	}
   815  
   816  	s.RemoveConfigListener(s.configListenerId)
   817  	s.RemoveConfigListener(s.logListenerId)
   818  	s.stopSearchEngine()
   819  
   820  	s.Audit.Shutdown()
   821  
   822  	s.stopFeatureFlagUpdateJob()
   823  
   824  	s.configStore.Close()
   825  
   826  	if s.Cluster != nil {
   827  		s.Cluster.StopInterNodeCommunication()
   828  	}
   829  
   830  	if s.Metrics != nil {
   831  		s.Metrics.StopServer()
   832  	}
   833  
   834  	// This must be done after the cluster is stopped.
   835  	if s.Jobs != nil && s.runjobs {
   836  		s.Jobs.StopWorkers()
   837  		s.Jobs.StopSchedulers()
   838  	}
   839  
   840  	if s.Store != nil {
   841  		s.Store.Close()
   842  	}
   843  
   844  	if s.CacheProvider != nil {
   845  		if err = s.CacheProvider.Close(); err != nil {
   846  			mlog.Warn("Unable to cleanly shutdown cache", mlog.Err(err))
   847  		}
   848  	}
   849  
   850  	timeoutCtx, timeoutCancel := context.WithTimeout(context.Background(), time.Second*15)
   851  	defer timeoutCancel()
   852  	if err := mlog.Flush(timeoutCtx); err != nil {
   853  		mlog.Warn("Error flushing logs", mlog.Err(err))
   854  	}
   855  
   856  	mlog.Info("Server stopped")
   857  
   858  	// this should just write the "server stopped" record, the rest are already flushed.
   859  	timeoutCtx2, timeoutCancel2 := context.WithTimeout(context.Background(), time.Second*5)
   860  	defer timeoutCancel2()
   861  	_ = mlog.ShutdownAdvancedLogging(timeoutCtx2)
   862  }
   863  
   864  func (s *Server) Restart() error {
   865  	percentage, err := s.UpgradeToE0Status()
   866  	if err != nil || percentage != 100 {
   867  		return errors.Wrap(err, "unable to restart because the system has not been upgraded")
   868  	}
   869  	s.Shutdown()
   870  
   871  	argv0, err := exec.LookPath(os.Args[0])
   872  	if err != nil {
   873  		return err
   874  	}
   875  
   876  	if _, err = os.Stat(argv0); err != nil {
   877  		return err
   878  	}
   879  
   880  	mlog.Info("Restarting server")
   881  	return syscall.Exec(argv0, os.Args, os.Environ())
   882  }
   883  
   884  func (s *Server) isUpgradedFromTE() bool {
   885  	val, err := s.Store.System().GetByName(model.SYSTEM_UPGRADED_FROM_TE_ID)
   886  	if err != nil {
   887  		return false
   888  	}
   889  	return val.Value == "true"
   890  }
   891  
   892  func (s *Server) CanIUpgradeToE0() error {
   893  	return upgrader.CanIUpgradeToE0()
   894  }
   895  
   896  func (s *Server) UpgradeToE0() error {
   897  	if err := upgrader.UpgradeToE0(); err != nil {
   898  		return err
   899  	}
   900  	upgradedFromTE := &model.System{Name: model.SYSTEM_UPGRADED_FROM_TE_ID, Value: "true"}
   901  	s.Store.System().Save(upgradedFromTE)
   902  	return nil
   903  }
   904  
   905  func (s *Server) UpgradeToE0Status() (int64, error) {
   906  	return upgrader.UpgradeToE0Status()
   907  }
   908  
   909  // Go creates a goroutine, but maintains a record of it to ensure that execution completes before
   910  // the server is shutdown.
   911  func (s *Server) Go(f func()) {
   912  	atomic.AddInt32(&s.goroutineCount, 1)
   913  
   914  	go func() {
   915  		f()
   916  
   917  		atomic.AddInt32(&s.goroutineCount, -1)
   918  		select {
   919  		case s.goroutineExitSignal <- struct{}{}:
   920  		default:
   921  		}
   922  	}()
   923  }
   924  
   925  // WaitForGoroutines blocks until all goroutines created by App.Go exit.
   926  func (s *Server) WaitForGoroutines() {
   927  	for atomic.LoadInt32(&s.goroutineCount) != 0 {
   928  		<-s.goroutineExitSignal
   929  	}
   930  }
   931  
   932  var corsAllowedMethods = []string{
   933  	"POST",
   934  	"GET",
   935  	"OPTIONS",
   936  	"PUT",
   937  	"PATCH",
   938  	"DELETE",
   939  }
   940  
   941  // golang.org/x/crypto/acme/autocert/autocert.go
   942  func handleHTTPRedirect(w http.ResponseWriter, r *http.Request) {
   943  	if r.Method != "GET" && r.Method != "HEAD" {
   944  		http.Error(w, "Use HTTPS", http.StatusBadRequest)
   945  		return
   946  	}
   947  	target := "https://" + stripPort(r.Host) + r.URL.RequestURI()
   948  	http.Redirect(w, r, target, http.StatusFound)
   949  }
   950  
   951  // golang.org/x/crypto/acme/autocert/autocert.go
   952  func stripPort(hostport string) string {
   953  	host, _, err := net.SplitHostPort(hostport)
   954  	if err != nil {
   955  		return hostport
   956  	}
   957  	return net.JoinHostPort(host, "443")
   958  }
   959  
   960  func (s *Server) Start() error {
   961  	mlog.Info("Starting Server...")
   962  
   963  	var handler http.Handler = s.RootRouter
   964  
   965  	if *s.Config().LogSettings.EnableDiagnostics && *s.Config().LogSettings.EnableSentry && !strings.Contains(SentryDSN, "placeholder") {
   966  		sentryHandler := sentryhttp.New(sentryhttp.Options{
   967  			Repanic: true,
   968  		})
   969  		handler = sentryHandler.Handle(handler)
   970  	}
   971  
   972  	if allowedOrigins := *s.Config().ServiceSettings.AllowCorsFrom; allowedOrigins != "" {
   973  		exposedCorsHeaders := *s.Config().ServiceSettings.CorsExposedHeaders
   974  		allowCredentials := *s.Config().ServiceSettings.CorsAllowCredentials
   975  		debug := *s.Config().ServiceSettings.CorsDebug
   976  		corsWrapper := cors.New(cors.Options{
   977  			AllowedOrigins:   strings.Fields(allowedOrigins),
   978  			AllowedMethods:   corsAllowedMethods,
   979  			AllowedHeaders:   []string{"*"},
   980  			ExposedHeaders:   strings.Fields(exposedCorsHeaders),
   981  			MaxAge:           86400,
   982  			AllowCredentials: allowCredentials,
   983  			Debug:            debug,
   984  		})
   985  
   986  		// If we have debugging of CORS turned on then forward messages to logs
   987  		if debug {
   988  			corsWrapper.Log = s.Log.StdLog(mlog.String("source", "cors"))
   989  		}
   990  
   991  		handler = corsWrapper.Handler(handler)
   992  	}
   993  
   994  	if *s.Config().RateLimitSettings.Enable {
   995  		mlog.Info("RateLimiter is enabled")
   996  
   997  		rateLimiter, err := NewRateLimiter(&s.Config().RateLimitSettings, s.Config().ServiceSettings.TrustedProxyIPHeader)
   998  		if err != nil {
   999  			return err
  1000  		}
  1001  
  1002  		s.RateLimiter = rateLimiter
  1003  		handler = rateLimiter.RateLimitHandler(handler)
  1004  	}
  1005  	s.Busy = NewBusy(s.Cluster)
  1006  
  1007  	// Creating a logger for logging errors from http.Server at error level
  1008  	errStdLog, err := s.Log.StdLogAt(mlog.LevelError, mlog.String("source", "httpserver"))
  1009  	if err != nil {
  1010  		return err
  1011  	}
  1012  
  1013  	s.Server = &http.Server{
  1014  		Handler:      handler,
  1015  		ReadTimeout:  time.Duration(*s.Config().ServiceSettings.ReadTimeout) * time.Second,
  1016  		WriteTimeout: time.Duration(*s.Config().ServiceSettings.WriteTimeout) * time.Second,
  1017  		IdleTimeout:  time.Duration(*s.Config().ServiceSettings.IdleTimeout) * time.Second,
  1018  		ErrorLog:     errStdLog,
  1019  	}
  1020  
  1021  	addr := *s.Config().ServiceSettings.ListenAddress
  1022  	if addr == "" {
  1023  		if *s.Config().ServiceSettings.ConnectionSecurity == model.CONN_SECURITY_TLS {
  1024  			addr = ":https"
  1025  		} else {
  1026  			addr = ":http"
  1027  		}
  1028  	}
  1029  
  1030  	listener, err := net.Listen("tcp", addr)
  1031  	if err != nil {
  1032  		return errors.Wrapf(err, utils.T("api.server.start_server.starting.critical"), err)
  1033  	}
  1034  	s.ListenAddr = listener.Addr().(*net.TCPAddr)
  1035  
  1036  	logListeningPort := fmt.Sprintf("Server is listening on %v", listener.Addr().String())
  1037  	mlog.Info(logListeningPort, mlog.String("address", listener.Addr().String()))
  1038  
  1039  	m := &autocert.Manager{
  1040  		Cache:  autocert.DirCache(*s.Config().ServiceSettings.LetsEncryptCertificateCacheFile),
  1041  		Prompt: autocert.AcceptTOS,
  1042  	}
  1043  
  1044  	if *s.Config().ServiceSettings.Forward80To443 {
  1045  		if host, port, err := net.SplitHostPort(addr); err != nil {
  1046  			mlog.Error("Unable to setup forwarding", mlog.Err(err))
  1047  		} else if port != "443" {
  1048  			return fmt.Errorf(utils.T("api.server.start_server.forward80to443.enabled_but_listening_on_wrong_port"), port)
  1049  		} else {
  1050  			httpListenAddress := net.JoinHostPort(host, "http")
  1051  
  1052  			if *s.Config().ServiceSettings.UseLetsEncrypt {
  1053  				server := &http.Server{
  1054  					Addr:     httpListenAddress,
  1055  					Handler:  m.HTTPHandler(nil),
  1056  					ErrorLog: s.Log.StdLog(mlog.String("source", "le_forwarder_server")),
  1057  				}
  1058  				go server.ListenAndServe()
  1059  			} else {
  1060  				go func() {
  1061  					redirectListener, err := net.Listen("tcp", httpListenAddress)
  1062  					if err != nil {
  1063  						mlog.Error("Unable to setup forwarding", mlog.Err(err))
  1064  						return
  1065  					}
  1066  					defer redirectListener.Close()
  1067  
  1068  					server := &http.Server{
  1069  						Handler:  http.HandlerFunc(handleHTTPRedirect),
  1070  						ErrorLog: s.Log.StdLog(mlog.String("source", "forwarder_server")),
  1071  					}
  1072  					server.Serve(redirectListener)
  1073  				}()
  1074  			}
  1075  		}
  1076  	} else if *s.Config().ServiceSettings.UseLetsEncrypt {
  1077  		return errors.New(utils.T("api.server.start_server.forward80to443.disabled_while_using_lets_encrypt"))
  1078  	}
  1079  
  1080  	s.didFinishListen = make(chan struct{})
  1081  	go func() {
  1082  		var err error
  1083  		if *s.Config().ServiceSettings.ConnectionSecurity == model.CONN_SECURITY_TLS {
  1084  
  1085  			tlsConfig := &tls.Config{
  1086  				PreferServerCipherSuites: true,
  1087  				CurvePreferences:         []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256},
  1088  			}
  1089  
  1090  			switch *s.Config().ServiceSettings.TLSMinVer {
  1091  			case "1.0":
  1092  				tlsConfig.MinVersion = tls.VersionTLS10
  1093  			case "1.1":
  1094  				tlsConfig.MinVersion = tls.VersionTLS11
  1095  			default:
  1096  				tlsConfig.MinVersion = tls.VersionTLS12
  1097  			}
  1098  
  1099  			defaultCiphers := []uint16{
  1100  				tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
  1101  				tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
  1102  				tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
  1103  				tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
  1104  				tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
  1105  				tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
  1106  			}
  1107  
  1108  			if len(s.Config().ServiceSettings.TLSOverwriteCiphers) == 0 {
  1109  				tlsConfig.CipherSuites = defaultCiphers
  1110  			} else {
  1111  				var cipherSuites []uint16
  1112  				for _, cipher := range s.Config().ServiceSettings.TLSOverwriteCiphers {
  1113  					value, ok := model.ServerTLSSupportedCiphers[cipher]
  1114  
  1115  					if !ok {
  1116  						mlog.Warn("Unsupported cipher passed", mlog.String("cipher", cipher))
  1117  						continue
  1118  					}
  1119  
  1120  					cipherSuites = append(cipherSuites, value)
  1121  				}
  1122  
  1123  				if len(cipherSuites) == 0 {
  1124  					mlog.Warn("No supported ciphers passed, fallback to default cipher suite")
  1125  					cipherSuites = defaultCiphers
  1126  				}
  1127  
  1128  				tlsConfig.CipherSuites = cipherSuites
  1129  			}
  1130  
  1131  			certFile := ""
  1132  			keyFile := ""
  1133  
  1134  			if *s.Config().ServiceSettings.UseLetsEncrypt {
  1135  				tlsConfig.GetCertificate = m.GetCertificate
  1136  				tlsConfig.NextProtos = append(tlsConfig.NextProtos, "h2")
  1137  			} else {
  1138  				certFile = *s.Config().ServiceSettings.TLSCertFile
  1139  				keyFile = *s.Config().ServiceSettings.TLSKeyFile
  1140  			}
  1141  
  1142  			s.Server.TLSConfig = tlsConfig
  1143  			err = s.Server.ServeTLS(listener, certFile, keyFile)
  1144  		} else {
  1145  			err = s.Server.Serve(listener)
  1146  		}
  1147  
  1148  		if err != nil && err != http.ErrServerClosed {
  1149  			mlog.Critical("Error starting server", mlog.Err(err))
  1150  			time.Sleep(time.Second)
  1151  		}
  1152  
  1153  		close(s.didFinishListen)
  1154  	}()
  1155  
  1156  	if *s.Config().ServiceSettings.EnableLocalMode {
  1157  		if err := s.startLocalModeServer(); err != nil {
  1158  			mlog.Critical(err.Error())
  1159  		}
  1160  	}
  1161  
  1162  	return nil
  1163  }
  1164  
  1165  func (s *Server) startLocalModeServer() error {
  1166  	s.localModeServer = &http.Server{
  1167  		Handler: s.LocalRouter,
  1168  	}
  1169  
  1170  	socket := *s.configStore.Get().ServiceSettings.LocalModeSocketLocation
  1171  	unixListener, err := net.Listen("unix", socket)
  1172  	if err != nil {
  1173  		return errors.Wrapf(err, utils.T("api.server.start_server.starting.critical"), err)
  1174  	}
  1175  	if err = os.Chmod(socket, 0600); err != nil {
  1176  		return errors.Wrapf(err, utils.T("api.server.start_server.starting.critical"), err)
  1177  	}
  1178  
  1179  	go func() {
  1180  		err = s.localModeServer.Serve(unixListener)
  1181  		if err != nil && err != http.ErrServerClosed {
  1182  			mlog.Critical("Error starting unix socket server", mlog.Err(err))
  1183  		}
  1184  	}()
  1185  	return nil
  1186  }
  1187  
  1188  func (s *Server) stopLocalModeServer() {
  1189  	if s.localModeServer != nil {
  1190  		s.localModeServer.Close()
  1191  	}
  1192  }
  1193  
  1194  func (a *App) OriginChecker() func(*http.Request) bool {
  1195  	if allowed := *a.Config().ServiceSettings.AllowCorsFrom; allowed != "" {
  1196  		if allowed != "*" {
  1197  			siteURL, err := url.Parse(*a.Config().ServiceSettings.SiteURL)
  1198  			if err == nil {
  1199  				siteURL.Path = ""
  1200  				allowed += " " + siteURL.String()
  1201  			}
  1202  		}
  1203  
  1204  		return utils.OriginChecker(allowed)
  1205  	}
  1206  	return nil
  1207  }
  1208  
  1209  func (s *Server) checkPushNotificationServerUrl() {
  1210  	notificationServer := *s.Config().EmailSettings.PushNotificationServer
  1211  	if strings.HasPrefix(notificationServer, "http://") {
  1212  		mlog.Warn("Your push notification server is configured with HTTP. For improved security, update to HTTPS in your configuration.")
  1213  	}
  1214  }
  1215  
  1216  func runSecurityJob(s *Server) {
  1217  	doSecurity(s)
  1218  	model.CreateRecurringTask("Security", func() {
  1219  		doSecurity(s)
  1220  	}, time.Hour*4)
  1221  }
  1222  
  1223  func runTokenCleanupJob(s *Server) {
  1224  	doTokenCleanup(s)
  1225  	model.CreateRecurringTask("Token Cleanup", func() {
  1226  		doTokenCleanup(s)
  1227  	}, time.Hour*1)
  1228  }
  1229  
  1230  func runCommandWebhookCleanupJob(s *Server) {
  1231  	doCommandWebhookCleanup(s)
  1232  	model.CreateRecurringTask("Command Hook Cleanup", func() {
  1233  		doCommandWebhookCleanup(s)
  1234  	}, time.Hour*1)
  1235  }
  1236  
  1237  func runSessionCleanupJob(s *Server) {
  1238  	doSessionCleanup(s)
  1239  	model.CreateRecurringTask("Session Cleanup", func() {
  1240  		doSessionCleanup(s)
  1241  	}, time.Hour*24)
  1242  }
  1243  
  1244  func runLicenseExpirationCheckJob(a *App) {
  1245  	doLicenseExpirationCheck(a)
  1246  	model.CreateRecurringTask("License Expiration Check", func() {
  1247  		doLicenseExpirationCheck(a)
  1248  	}, time.Hour*24)
  1249  }
  1250  
  1251  func runReportToAWSMeterJob(s *Server) {
  1252  	model.CreateRecurringTask("Collect and send usage report to AWS Metering Service", func() {
  1253  		doReportUsageToAWSMeteringService(s)
  1254  	}, time.Hour*model.AWS_METERING_REPORT_INTERVAL)
  1255  }
  1256  
  1257  func doReportUsageToAWSMeteringService(s *Server) {
  1258  	awsMeter := awsmeter.New(s.Store, s.Config())
  1259  	if awsMeter == nil {
  1260  		mlog.Error("Cannot obtain instance of AWS Metering Service.")
  1261  		return
  1262  	}
  1263  
  1264  	dimensions := []string{model.AWS_METERING_DIMENSION_USAGE_HRS}
  1265  	reports := awsMeter.GetUserCategoryUsage(dimensions, time.Now().UTC(), time.Now().Add(-model.AWS_METERING_REPORT_INTERVAL*time.Hour).UTC())
  1266  	awsMeter.ReportUserCategoryUsage(reports)
  1267  }
  1268  
  1269  func runCheckWarnMetricStatusJob(a *App) {
  1270  	doCheckWarnMetricStatus(a)
  1271  	model.CreateRecurringTask("Check Warn Metric Status Job", func() {
  1272  		doCheckWarnMetricStatus(a)
  1273  	}, time.Hour*model.WARN_METRIC_JOB_INTERVAL)
  1274  }
  1275  
  1276  func doSecurity(s *Server) {
  1277  	s.DoSecurityUpdateCheck()
  1278  }
  1279  
  1280  func doTokenCleanup(s *Server) {
  1281  	s.Store.Token().Cleanup()
  1282  }
  1283  
  1284  func doCommandWebhookCleanup(s *Server) {
  1285  	s.Store.CommandWebhook().Cleanup()
  1286  }
  1287  
  1288  const (
  1289  	SessionsCleanupBatchSize = 1000
  1290  )
  1291  
  1292  func doSessionCleanup(s *Server) {
  1293  	s.Store.Session().Cleanup(model.GetMillis(), SessionsCleanupBatchSize)
  1294  }
  1295  
  1296  func doCheckWarnMetricStatus(a *App) {
  1297  	license := a.Srv().License()
  1298  	if license != nil {
  1299  		mlog.Debug("License is present, skip")
  1300  		return
  1301  	}
  1302  
  1303  	// Get the system fields values from store
  1304  	systemDataList, nErr := a.Srv().Store.System().Get()
  1305  	if nErr != nil {
  1306  		mlog.Error("No system properties obtained", mlog.Err(nErr))
  1307  		return
  1308  	}
  1309  
  1310  	warnMetricStatusFromStore := make(map[string]string)
  1311  
  1312  	for key, value := range systemDataList {
  1313  		if strings.HasPrefix(key, model.WARN_METRIC_STATUS_STORE_PREFIX) {
  1314  			if _, ok := model.WarnMetricsTable[key]; ok {
  1315  				warnMetricStatusFromStore[key] = value
  1316  				if value == model.WARN_METRIC_STATUS_ACK {
  1317  					// If any warn metric has already been acked, we return
  1318  					mlog.Debug("Warn metrics have been acked, skip")
  1319  					return
  1320  				}
  1321  			}
  1322  		}
  1323  	}
  1324  
  1325  	lastWarnMetricRunTimestamp, err := a.Srv().getLastWarnMetricTimestamp()
  1326  	if err != nil {
  1327  		mlog.Debug("Cannot obtain last advisory run timestamp", mlog.Err(err))
  1328  	} else {
  1329  		currentTime := utils.MillisFromTime(time.Now())
  1330  		// If the admin advisory has already been shown in the last 7 days
  1331  		if (currentTime-lastWarnMetricRunTimestamp)/(model.WARN_METRIC_JOB_WAIT_TIME) < 1 {
  1332  			mlog.Debug("No advisories should be shown during the wait interval time")
  1333  			return
  1334  		}
  1335  	}
  1336  
  1337  	numberOfActiveUsers, err0 := a.Srv().Store.User().Count(model.UserCountOptions{})
  1338  	if err0 != nil {
  1339  		mlog.Debug("Error attempting to get active registered users.", mlog.Err(err0))
  1340  	}
  1341  
  1342  	teamCount, err1 := a.Srv().Store.Team().AnalyticsTeamCount(false)
  1343  	if err1 != nil {
  1344  		mlog.Debug("Error attempting to get number of teams.", mlog.Err(err1))
  1345  	}
  1346  
  1347  	openChannelCount, err2 := a.Srv().Store.Channel().AnalyticsTypeCount("", model.CHANNEL_OPEN)
  1348  	if err2 != nil {
  1349  		mlog.Debug("Error attempting to get number of public channels.", mlog.Err(err2))
  1350  	}
  1351  
  1352  	// If an account is created with a different email domain
  1353  	// Search for an entry that has an email account different from the current domain
  1354  	// Get domain account from site url
  1355  	localDomainAccount := utils.GetHostnameFromSiteURL(*a.Srv().Config().ServiceSettings.SiteURL)
  1356  	isDiffEmailAccount, err3 := a.Srv().Store.User().AnalyticsGetExternalUsers(localDomainAccount)
  1357  	if err3 != nil {
  1358  		mlog.Debug("Error attempting to get number of private channels.", mlog.Err(err3))
  1359  	}
  1360  
  1361  	warnMetrics := []model.WarnMetric{}
  1362  
  1363  	if numberOfActiveUsers < model.WARN_METRIC_NUMBER_OF_ACTIVE_USERS_25 {
  1364  		return
  1365  	} else if teamCount >= model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_TEAMS_5].Limit && warnMetricStatusFromStore[model.SYSTEM_WARN_METRIC_NUMBER_OF_TEAMS_5] != model.WARN_METRIC_STATUS_RUNONCE {
  1366  		warnMetrics = append(warnMetrics, model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_TEAMS_5])
  1367  	} else if *a.Config().ServiceSettings.EnableMultifactorAuthentication && warnMetricStatusFromStore[model.SYSTEM_WARN_METRIC_MFA] != model.WARN_METRIC_STATUS_RUNONCE {
  1368  		warnMetrics = append(warnMetrics, model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_MFA])
  1369  	} else if isDiffEmailAccount && warnMetricStatusFromStore[model.SYSTEM_WARN_METRIC_EMAIL_DOMAIN] != model.WARN_METRIC_STATUS_RUNONCE {
  1370  		warnMetrics = append(warnMetrics, model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_EMAIL_DOMAIN])
  1371  	} else if openChannelCount >= model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_CHANNELS_50].Limit && warnMetricStatusFromStore[model.SYSTEM_WARN_METRIC_NUMBER_OF_CHANNELS_50] != model.WARN_METRIC_STATUS_RUNONCE {
  1372  		warnMetrics = append(warnMetrics, model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_CHANNELS_50])
  1373  	}
  1374  
  1375  	// If the system did not cross any of the thresholds for the Contextual Advisories
  1376  	if len(warnMetrics) == 0 {
  1377  		if numberOfActiveUsers >= model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_100].Limit && numberOfActiveUsers < model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_200].Limit && warnMetricStatusFromStore[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_100] != model.WARN_METRIC_STATUS_RUNONCE {
  1378  			warnMetrics = append(warnMetrics, model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_100])
  1379  		} else if numberOfActiveUsers >= model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_200].Limit && numberOfActiveUsers < model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_300].Limit && warnMetricStatusFromStore[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_200] != model.WARN_METRIC_STATUS_RUNONCE {
  1380  			warnMetrics = append(warnMetrics, model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_200])
  1381  		} else if numberOfActiveUsers >= model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_300].Limit && numberOfActiveUsers < model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_500].Limit && warnMetricStatusFromStore[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_300] != model.WARN_METRIC_STATUS_RUNONCE {
  1382  			warnMetrics = append(warnMetrics, model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_300])
  1383  		} else if numberOfActiveUsers >= model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_500].Limit {
  1384  			var tWarnMetric model.WarnMetric
  1385  
  1386  			if warnMetricStatusFromStore[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_500] != model.WARN_METRIC_STATUS_RUNONCE {
  1387  				tWarnMetric = model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_500]
  1388  			}
  1389  
  1390  			postsCount, err4 := a.Srv().Store.Post().AnalyticsPostCount("", false, false)
  1391  			if err4 != nil {
  1392  				mlog.Debug("Error attempting to get number of posts.", mlog.Err(err4))
  1393  			}
  1394  
  1395  			if postsCount > model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_POSTS_2M].Limit && warnMetricStatusFromStore[model.SYSTEM_WARN_METRIC_NUMBER_OF_POSTS_2M] != model.WARN_METRIC_STATUS_RUNONCE {
  1396  				tWarnMetric = model.WarnMetricsTable[model.SYSTEM_WARN_METRIC_NUMBER_OF_POSTS_2M]
  1397  			}
  1398  
  1399  			if tWarnMetric != (model.WarnMetric{}) {
  1400  				warnMetrics = append(warnMetrics, tWarnMetric)
  1401  			}
  1402  		}
  1403  	}
  1404  
  1405  	isE0Edition := model.BuildEnterpriseReady == "true" // license == nil was already validated upstream
  1406  
  1407  	for _, warnMetric := range warnMetrics {
  1408  		data, nErr := a.Srv().Store.System().GetByName(warnMetric.Id)
  1409  		if nErr == nil && data != nil && warnMetric.IsBotOnly && data.Value == model.WARN_METRIC_STATUS_RUNONCE {
  1410  			mlog.Debug("This metric warning is bot only and ran once")
  1411  			continue
  1412  		}
  1413  
  1414  		warnMetricStatus, _ := a.getWarnMetricStatusAndDisplayTextsForId(warnMetric.Id, nil, isE0Edition)
  1415  		if !warnMetric.IsBotOnly {
  1416  			// Banner and bot metric types - send websocket event every interval
  1417  			message := model.NewWebSocketEvent(model.WEBSOCKET_WARN_METRIC_STATUS_RECEIVED, "", "", "", nil)
  1418  			message.Add("warnMetricStatus", warnMetricStatus.ToJson())
  1419  			a.Publish(message)
  1420  
  1421  			// Banner and bot metric types, send the bot message only once
  1422  			if data != nil && data.Value == model.WARN_METRIC_STATUS_RUNONCE {
  1423  				continue
  1424  			}
  1425  		}
  1426  
  1427  		if nerr := a.notifyAdminsOfWarnMetricStatus(warnMetric.Id, isE0Edition); nerr != nil {
  1428  			mlog.Error("Failed to send notifications to admin users.", mlog.Err(nerr))
  1429  		}
  1430  
  1431  		if warnMetric.IsRunOnce {
  1432  			a.setWarnMetricsStatusForId(warnMetric.Id, model.WARN_METRIC_STATUS_RUNONCE)
  1433  		} else {
  1434  			a.setWarnMetricsStatusForId(warnMetric.Id, model.WARN_METRIC_STATUS_LIMIT_REACHED)
  1435  		}
  1436  	}
  1437  }
  1438  
  1439  func doLicenseExpirationCheck(a *App) {
  1440  	a.Srv().LoadLicense()
  1441  	license := a.Srv().License()
  1442  
  1443  	if license == nil {
  1444  		mlog.Debug("License cannot be found.")
  1445  		return
  1446  	}
  1447  
  1448  	if !license.IsPastGracePeriod() {
  1449  		mlog.Debug("License is not past the grace period.")
  1450  		return
  1451  	}
  1452  
  1453  	users, err := a.Srv().Store.User().GetSystemAdminProfiles()
  1454  	if err != nil {
  1455  		mlog.Error("Failed to get system admins for license expired message from Mattermost.")
  1456  		return
  1457  	}
  1458  
  1459  	//send email to admin(s)
  1460  	for _, user := range users {
  1461  		user := user
  1462  		if user.Email == "" {
  1463  			mlog.Error("Invalid system admin email.", mlog.String("user_email", user.Email))
  1464  			continue
  1465  		}
  1466  
  1467  		mlog.Debug("Sending license expired email.", mlog.String("user_email", user.Email))
  1468  		a.Srv().Go(func() {
  1469  			if err := a.Srv().EmailService.SendRemoveExpiredLicenseEmail(user.Email, user.Locale, *a.Config().ServiceSettings.SiteURL); err != nil {
  1470  				mlog.Error("Error while sending the license expired email.", mlog.String("user_email", user.Email), mlog.Err(err))
  1471  			}
  1472  		})
  1473  	}
  1474  
  1475  	//remove the license
  1476  	a.Srv().RemoveLicense()
  1477  }
  1478  
  1479  func (s *Server) StartSearchEngine() (string, string) {
  1480  	if s.SearchEngine.ElasticsearchEngine != nil && s.SearchEngine.ElasticsearchEngine.IsActive() {
  1481  		s.Go(func() {
  1482  			if err := s.SearchEngine.ElasticsearchEngine.Start(); err != nil {
  1483  				s.Log.Error(err.Error())
  1484  			}
  1485  		})
  1486  	}
  1487  
  1488  	configListenerId := s.AddConfigListener(func(oldConfig *model.Config, newConfig *model.Config) {
  1489  		if s.SearchEngine == nil {
  1490  			return
  1491  		}
  1492  		s.SearchEngine.UpdateConfig(newConfig)
  1493  
  1494  		if s.SearchEngine.ElasticsearchEngine != nil && !*oldConfig.ElasticsearchSettings.EnableIndexing && *newConfig.ElasticsearchSettings.EnableIndexing {
  1495  			s.Go(func() {
  1496  				if err := s.SearchEngine.ElasticsearchEngine.Start(); err != nil {
  1497  					mlog.Error(err.Error())
  1498  				}
  1499  			})
  1500  		} else if s.SearchEngine.ElasticsearchEngine != nil && *oldConfig.ElasticsearchSettings.EnableIndexing && !*newConfig.ElasticsearchSettings.EnableIndexing {
  1501  			s.Go(func() {
  1502  				if err := s.SearchEngine.ElasticsearchEngine.Stop(); err != nil {
  1503  					mlog.Error(err.Error())
  1504  				}
  1505  			})
  1506  		} else if s.SearchEngine.ElasticsearchEngine != nil && *oldConfig.ElasticsearchSettings.Password != *newConfig.ElasticsearchSettings.Password || *oldConfig.ElasticsearchSettings.Username != *newConfig.ElasticsearchSettings.Username || *oldConfig.ElasticsearchSettings.ConnectionUrl != *newConfig.ElasticsearchSettings.ConnectionUrl || *oldConfig.ElasticsearchSettings.Sniff != *newConfig.ElasticsearchSettings.Sniff {
  1507  			s.Go(func() {
  1508  				if *oldConfig.ElasticsearchSettings.EnableIndexing {
  1509  					if err := s.SearchEngine.ElasticsearchEngine.Stop(); err != nil {
  1510  						mlog.Error(err.Error())
  1511  					}
  1512  					if err := s.SearchEngine.ElasticsearchEngine.Start(); err != nil {
  1513  						mlog.Error(err.Error())
  1514  					}
  1515  				}
  1516  			})
  1517  		}
  1518  	})
  1519  
  1520  	licenseListenerId := s.AddLicenseListener(func(oldLicense, newLicense *model.License) {
  1521  		if s.SearchEngine == nil {
  1522  			return
  1523  		}
  1524  		if oldLicense == nil && newLicense != nil {
  1525  			if s.SearchEngine.ElasticsearchEngine != nil && s.SearchEngine.ElasticsearchEngine.IsActive() {
  1526  				s.Go(func() {
  1527  					if err := s.SearchEngine.ElasticsearchEngine.Start(); err != nil {
  1528  						mlog.Error(err.Error())
  1529  					}
  1530  				})
  1531  			}
  1532  		} else if oldLicense != nil && newLicense == nil {
  1533  			if s.SearchEngine.ElasticsearchEngine != nil {
  1534  				s.Go(func() {
  1535  					if err := s.SearchEngine.ElasticsearchEngine.Stop(); err != nil {
  1536  						mlog.Error(err.Error())
  1537  					}
  1538  				})
  1539  			}
  1540  		}
  1541  	})
  1542  
  1543  	return configListenerId, licenseListenerId
  1544  }
  1545  
  1546  func (s *Server) stopSearchEngine() {
  1547  	s.RemoveConfigListener(s.searchConfigListenerId)
  1548  	s.RemoveLicenseListener(s.searchLicenseListenerId)
  1549  	if s.SearchEngine != nil && s.SearchEngine.ElasticsearchEngine != nil && s.SearchEngine.ElasticsearchEngine.IsActive() {
  1550  		s.SearchEngine.ElasticsearchEngine.Stop()
  1551  	}
  1552  	if s.SearchEngine != nil && s.SearchEngine.BleveEngine != nil && s.SearchEngine.BleveEngine.IsActive() {
  1553  		s.SearchEngine.BleveEngine.Stop()
  1554  	}
  1555  }
  1556  
  1557  func (s *Server) FileBackend() (filesstore.FileBackend, *model.AppError) {
  1558  	license := s.License()
  1559  	backend, err := filesstore.NewFileBackend(s.Config().FileSettings.ToFileBackendSettings(license != nil && *license.Features.Compliance))
  1560  	if err != nil {
  1561  		return nil, model.NewAppError("FileBackend", "api.file.no_driver.app_error", nil, err.Error(), http.StatusInternalServerError)
  1562  	}
  1563  	return backend, nil
  1564  }
  1565  
  1566  func (s *Server) TotalWebsocketConnections() int {
  1567  	// This method is only called after the hub is initialized.
  1568  	// Therefore, no mutex is needed to protect s.hubs.
  1569  	count := int64(0)
  1570  	for _, hub := range s.hubs {
  1571  		count = count + atomic.LoadInt64(&hub.connectionCount)
  1572  	}
  1573  
  1574  	return int(count)
  1575  }
  1576  
  1577  func (s *Server) ClusterHealthScore() int {
  1578  	return s.Cluster.HealthScore()
  1579  }
  1580  
  1581  func (s *Server) configOrLicenseListener() {
  1582  	s.regenerateClientConfig()
  1583  }
  1584  
  1585  func (s *Server) ClientConfigHash() string {
  1586  	return s.clientConfigHash.Load().(string)
  1587  }
  1588  
  1589  func (s *Server) initJobs() {
  1590  	s.Jobs = jobs.NewJobServer(s, s.Store, s.Metrics)
  1591  	if jobsDataRetentionJobInterface != nil {
  1592  		s.Jobs.DataRetentionJob = jobsDataRetentionJobInterface(s)
  1593  	}
  1594  	if jobsMessageExportJobInterface != nil {
  1595  		s.Jobs.MessageExportJob = jobsMessageExportJobInterface(s)
  1596  	}
  1597  	if jobsElasticsearchAggregatorInterface != nil {
  1598  		s.Jobs.ElasticsearchAggregator = jobsElasticsearchAggregatorInterface(s)
  1599  	}
  1600  	if jobsElasticsearchIndexerInterface != nil {
  1601  		s.Jobs.ElasticsearchIndexer = jobsElasticsearchIndexerInterface(s)
  1602  	}
  1603  	if jobsBleveIndexerInterface != nil {
  1604  		s.Jobs.BleveIndexer = jobsBleveIndexerInterface(s)
  1605  	}
  1606  	if jobsMigrationsInterface != nil {
  1607  		s.Jobs.Migrations = jobsMigrationsInterface(s)
  1608  	}
  1609  }
  1610  
  1611  func (s *Server) TelemetryId() string {
  1612  	if s.telemetryService == nil {
  1613  		return ""
  1614  	}
  1615  	return s.telemetryService.TelemetryID
  1616  }
  1617  
  1618  func (s *Server) HttpService() httpservice.HTTPService {
  1619  	return s.HTTPService
  1620  }
  1621  
  1622  func (s *Server) SetLog(l *mlog.Logger) {
  1623  	s.Log = l
  1624  }
  1625  
  1626  func (a *App) GenerateSupportPacket() []model.FileData {
  1627  	// If any errors we come across within this function, we will log it in a warning.txt file so that we know why certain files did not get produced if any
  1628  	var warnings []string
  1629  
  1630  	// Creating an array of files that we are going to be adding to our zip file
  1631  	fileDatas := []model.FileData{}
  1632  
  1633  	// A array of the functions that we can iterate through since they all have the same return value
  1634  	functions := []func() (*model.FileData, string){
  1635  		a.generateSupportPacketYaml,
  1636  		a.createPluginsFile,
  1637  		a.createSanitizedConfigFile,
  1638  		a.getMattermostLog,
  1639  		a.getNotificationsLog,
  1640  	}
  1641  
  1642  	for _, fn := range functions {
  1643  		fileData, warning := fn()
  1644  
  1645  		if fileData != nil {
  1646  			fileDatas = append(fileDatas, *fileData)
  1647  		} else {
  1648  			warnings = append(warnings, warning)
  1649  		}
  1650  	}
  1651  
  1652  	// Adding a warning.txt file to the fileDatas if any warning
  1653  	if len(warnings) > 0 {
  1654  		finalWarning := strings.Join(warnings, "\n")
  1655  		fileDatas = append(fileDatas, model.FileData{
  1656  			Filename: "warning.txt",
  1657  			Body:     []byte(finalWarning),
  1658  		})
  1659  	}
  1660  
  1661  	return fileDatas
  1662  }
  1663  
  1664  func (a *App) getNotificationsLog() (*model.FileData, string) {
  1665  	var warning string
  1666  
  1667  	// Getting notifications.log
  1668  	if *a.Srv().Config().NotificationLogSettings.EnableFile {
  1669  		// notifications.log
  1670  		notificationsLog := utils.GetNotificationsLogFileLocation(*a.Srv().Config().LogSettings.FileLocation)
  1671  
  1672  		notificationsLogFileData, notificationsLogFileDataErr := ioutil.ReadFile(notificationsLog)
  1673  
  1674  		if notificationsLogFileDataErr == nil {
  1675  			fileData := model.FileData{
  1676  				Filename: "notifications.log",
  1677  				Body:     notificationsLogFileData,
  1678  			}
  1679  			return &fileData, ""
  1680  		}
  1681  
  1682  		warning = fmt.Sprintf("ioutil.ReadFile(notificationsLog) Error: %s", notificationsLogFileDataErr.Error())
  1683  
  1684  	} else {
  1685  		warning = "Unable to retrieve notifications.log because LogSettings: EnableFile is false in config.json"
  1686  	}
  1687  
  1688  	return nil, warning
  1689  }
  1690  
  1691  func (a *App) getMattermostLog() (*model.FileData, string) {
  1692  	var warning string
  1693  
  1694  	// Getting mattermost.log
  1695  	if *a.Srv().Config().LogSettings.EnableFile {
  1696  		// mattermost.log
  1697  		mattermostLog := utils.GetLogFileLocation(*a.Srv().Config().LogSettings.FileLocation)
  1698  
  1699  		mattermostLogFileData, mattermostLogFileDataErr := ioutil.ReadFile(mattermostLog)
  1700  
  1701  		if mattermostLogFileDataErr == nil {
  1702  			fileData := model.FileData{
  1703  				Filename: "mattermost.log",
  1704  				Body:     mattermostLogFileData,
  1705  			}
  1706  			return &fileData, ""
  1707  		}
  1708  		warning = fmt.Sprintf("ioutil.ReadFile(mattermostLog) Error: %s", mattermostLogFileDataErr.Error())
  1709  
  1710  	} else {
  1711  		warning = "Unable to retrieve mattermost.log because LogSettings: EnableFile is false in config.json"
  1712  	}
  1713  
  1714  	return nil, warning
  1715  }
  1716  
  1717  func (a *App) createSanitizedConfigFile() (*model.FileData, string) {
  1718  	// Getting sanitized config, prettifying it, and then adding it to our file data array
  1719  	sanitizedConfigPrettyJSON, err := json.MarshalIndent(a.GetSanitizedConfig(), "", "    ")
  1720  	if err == nil {
  1721  		fileData := model.FileData{
  1722  			Filename: "sanitized_config.json",
  1723  			Body:     sanitizedConfigPrettyJSON,
  1724  		}
  1725  		return &fileData, ""
  1726  	}
  1727  
  1728  	warning := fmt.Sprintf("json.MarshalIndent(c.App.GetSanitizedConfig()) Error: %s", err.Error())
  1729  	return nil, warning
  1730  }
  1731  
  1732  func (a *App) createPluginsFile() (*model.FileData, string) {
  1733  	var warning string
  1734  
  1735  	// Getting the plugins installed on the server, prettify it, and then add them to the file data array
  1736  	pluginsResponse, appErr := a.GetPlugins()
  1737  	if appErr == nil {
  1738  		pluginsPrettyJSON, err := json.MarshalIndent(pluginsResponse, "", "    ")
  1739  		if err == nil {
  1740  			fileData := model.FileData{
  1741  				Filename: "plugins.json",
  1742  				Body:     pluginsPrettyJSON,
  1743  			}
  1744  
  1745  			return &fileData, ""
  1746  		}
  1747  
  1748  		warning = fmt.Sprintf("json.MarshalIndent(pluginsResponse) Error: %s", err.Error())
  1749  	} else {
  1750  		warning = fmt.Sprintf("c.App.GetPlugins() Error: %s", appErr.Error())
  1751  	}
  1752  
  1753  	return nil, warning
  1754  }
  1755  
  1756  func (a *App) generateSupportPacketYaml() (*model.FileData, string) {
  1757  	// Here we are getting information regarding Elastic Search
  1758  	var elasticServerVersion string
  1759  	var elasticServerPlugins []string
  1760  	if a.Srv().SearchEngine.ElasticsearchEngine != nil {
  1761  		elasticServerVersion = a.Srv().SearchEngine.ElasticsearchEngine.GetFullVersion()
  1762  		elasticServerPlugins = a.Srv().SearchEngine.ElasticsearchEngine.GetPlugins()
  1763  	}
  1764  
  1765  	// Here we are getting information regarding LDAP
  1766  	ldapInterface := a.Srv().Ldap
  1767  	var vendorName, vendorVersion string
  1768  	if ldapInterface != nil {
  1769  		vendorName, vendorVersion = ldapInterface.GetVendorNameAndVendorVersion()
  1770  	}
  1771  
  1772  	// Here we are getting information regarding the database (mysql/postgres + current Mattermost version)
  1773  	databaseType, databaseVersion := a.Srv().DatabaseTypeAndMattermostVersion()
  1774  
  1775  	// Creating the struct for support packet yaml file
  1776  	supportPacket := model.SupportPacket{
  1777  		ServerOS:             runtime.GOOS,
  1778  		ServerArchitecture:   runtime.GOARCH,
  1779  		DatabaseType:         databaseType,
  1780  		DatabaseVersion:      databaseVersion,
  1781  		LdapVendorName:       vendorName,
  1782  		LdapVendorVersion:    vendorVersion,
  1783  		ElasticServerVersion: elasticServerVersion,
  1784  		ElasticServerPlugins: elasticServerPlugins,
  1785  	}
  1786  
  1787  	// Marshal to a Yaml File
  1788  	supportPacketYaml, err := yaml.Marshal(&supportPacket)
  1789  	if err == nil {
  1790  		fileData := model.FileData{
  1791  			Filename: "support_packet.yaml",
  1792  			Body:     supportPacketYaml,
  1793  		}
  1794  		return &fileData, ""
  1795  	}
  1796  
  1797  	warning := fmt.Sprintf("yaml.Marshal(&supportPacket) Error: %s", err.Error())
  1798  	return nil, warning
  1799  }