github.com/vnforks/kid/v5@v5.22.1-0.20200408055009-b89d99c65676/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/ecdsa"
     9  	"crypto/tls"
    10  	"fmt"
    11  	"net"
    12  	"net/http"
    13  	"net/url"
    14  	"os"
    15  	"strings"
    16  	"sync"
    17  	"sync/atomic"
    18  	"time"
    19  
    20  	"github.com/gorilla/mux"
    21  	"github.com/pkg/errors"
    22  	"github.com/rs/cors"
    23  	analytics "github.com/segmentio/analytics-go"
    24  	"github.com/throttled/throttled"
    25  	"golang.org/x/crypto/acme/autocert"
    26  
    27  	"github.com/vnforks/kid/v5/audit"
    28  	"github.com/vnforks/kid/v5/config"
    29  	"github.com/vnforks/kid/v5/einterfaces"
    30  	"github.com/vnforks/kid/v5/jobs"
    31  	"github.com/vnforks/kid/v5/mlog"
    32  	"github.com/vnforks/kid/v5/model"
    33  	"github.com/vnforks/kid/v5/services/cache"
    34  	"github.com/vnforks/kid/v5/services/cache/lru"
    35  	"github.com/vnforks/kid/v5/services/filesstore"
    36  	"github.com/vnforks/kid/v5/services/httpservice"
    37  	"github.com/vnforks/kid/v5/services/imageproxy"
    38  	"github.com/vnforks/kid/v5/services/searchengine"
    39  	"github.com/vnforks/kid/v5/services/timezones"
    40  	"github.com/vnforks/kid/v5/services/tracing"
    41  	"github.com/vnforks/kid/v5/store"
    42  	"github.com/vnforks/kid/v5/utils"
    43  )
    44  
    45  var MaxNotificationsPerClassDefault int64 = 1000000
    46  
    47  type Server struct {
    48  	Store           store.Store
    49  	WebSocketRouter *WebSocketRouter
    50  
    51  	// RootRouter is the starting point for all HTTP requests to the server.
    52  	RootRouter *mux.Router
    53  
    54  	// Router is the starting point for all web, api4 and ws requests to the server. It differs
    55  	// from RootRouter only if the SiteURL contains a /subpath.
    56  	Router *mux.Router
    57  
    58  	Server      *http.Server
    59  	ListenAddr  *net.TCPAddr
    60  	RateLimiter *RateLimiter
    61  	Busy        *Busy
    62  
    63  	didFinishListen chan struct{}
    64  
    65  	goroutineCount      int32
    66  	goroutineExitSignal chan struct{}
    67  
    68  	EmailBatching    *EmailBatchingJob
    69  	EmailRateLimiter *throttled.GCRARateLimiter
    70  
    71  	hubsLock                    sync.RWMutex
    72  	hubs                        []*Hub
    73  	HubsStopCheckingForDeadlock chan bool
    74  
    75  	PushNotificationsHub PushNotificationsHub
    76  
    77  	runjobs bool
    78  	Jobs    *jobs.JobServer
    79  
    80  	clusterLeaderListeners sync.Map
    81  
    82  	licenseValue       atomic.Value
    83  	clientLicenseValue atomic.Value
    84  	licenseListeners   map[string]func(*model.License, *model.License)
    85  
    86  	timezones *timezones.Timezones
    87  
    88  	newStore func() store.Store
    89  
    90  	htmlTemplateWatcher     *utils.HTMLTemplateWatcher
    91  	sessionCache            cache.Cache
    92  	seenPendingPostIdsCache cache.Cache
    93  	statusCache             cache.Cache
    94  	configListenerId        string
    95  	licenseListenerId       string
    96  	logListenerId           string
    97  	clusterLeaderListenerId string
    98  	searchConfigListenerId  string
    99  	searchLicenseListenerId string
   100  	configStore             config.Store
   101  	asymmetricSigningKey    *ecdsa.PrivateKey
   102  	postActionCookieSecret  []byte
   103  
   104  	clientConfig        map[string]string
   105  	clientConfigHash    string
   106  	limitedClientConfig map[string]string
   107  
   108  	diagnosticId     string
   109  	diagnosticClient analytics.Client
   110  
   111  	phase2PermissionsMigrationComplete bool
   112  
   113  	HTTPService            httpservice.HTTPService
   114  	pushNotificationClient *http.Client // TODO: move this to it's own package
   115  
   116  	ImageProxy *imageproxy.ImageProxy
   117  
   118  	Audit            *audit.Audit
   119  	Log              *mlog.Logger
   120  	NotificationsLog *mlog.Logger
   121  
   122  	joinCluster       bool
   123  	startMetrics      bool
   124  	startSearchEngine bool
   125  
   126  	SearchEngine *searchengine.Broker
   127  
   128  	AccountMigration einterfaces.AccountMigrationInterface
   129  	Cluster          einterfaces.ClusterInterface
   130  	Compliance       einterfaces.ComplianceInterface
   131  	DataRetention    einterfaces.DataRetentionInterface
   132  	Ldap             einterfaces.LdapInterface
   133  	MessageExport    einterfaces.MessageExportInterface
   134  	Metrics          einterfaces.MetricsInterface
   135  	Notification     einterfaces.NotificationInterface
   136  	Saml             einterfaces.SamlInterface
   137  
   138  	CacheProvider cache.Provider
   139  
   140  	tracer *tracing.Tracer
   141  }
   142  
   143  func NewServer(options ...Option) (*Server, error) {
   144  	rootRouter := mux.NewRouter()
   145  
   146  	s := &Server{
   147  		goroutineExitSignal: make(chan struct{}, 1),
   148  		RootRouter:          rootRouter,
   149  		licenseListeners:    map[string]func(*model.License, *model.License){},
   150  		clientConfig:        make(map[string]string),
   151  	}
   152  
   153  	for _, option := range options {
   154  		if err := option(s); err != nil {
   155  			return nil, errors.Wrap(err, "failed to apply option")
   156  		}
   157  	}
   158  
   159  	if s.configStore == nil {
   160  		configStore, err := config.NewFileStore("config.json", true)
   161  		if err != nil {
   162  			return nil, errors.Wrap(err, "failed to load config")
   163  		}
   164  
   165  		s.configStore = configStore
   166  	}
   167  
   168  	if s.Log == nil {
   169  		s.Log = mlog.NewLogger(utils.MloggerConfigFromLoggerConfig(&s.Config().LogSettings, utils.GetLogFileLocation))
   170  	}
   171  
   172  	if s.NotificationsLog == nil {
   173  		notificationLogSettings := utils.GetLogSettingsFromNotificationsLogSettings(&s.Config().NotificationLogSettings)
   174  		s.NotificationsLog = mlog.NewLogger(utils.MloggerConfigFromLoggerConfig(notificationLogSettings, utils.GetNotificationsLogFileLocation)).
   175  			WithCallerSkip(1).With(mlog.String("logSource", "notifications"))
   176  	}
   177  
   178  	// Redirect default golang logger to this logger
   179  	mlog.RedirectStdLog(s.Log)
   180  
   181  	// Use this app logger as the global logger (eventually remove all instances of global logging)
   182  	mlog.InitGlobalLogger(s.Log)
   183  
   184  	if *s.Config().ServiceSettings.EnableOpenTracing {
   185  		tracer, err := tracing.New()
   186  		if err != nil {
   187  			return nil, err
   188  		}
   189  		s.tracer = tracer
   190  	}
   191  
   192  	s.logListenerId = s.AddConfigListener(func(_, after *model.Config) {
   193  		s.Log.ChangeLevels(utils.MloggerConfigFromLoggerConfig(&after.LogSettings, utils.GetLogFileLocation))
   194  
   195  		notificationLogSettings := utils.GetLogSettingsFromNotificationsLogSettings(&after.NotificationLogSettings)
   196  		s.NotificationsLog.ChangeLevels(utils.MloggerConfigFromLoggerConfig(notificationLogSettings, utils.GetNotificationsLogFileLocation))
   197  	})
   198  
   199  	s.HTTPService = httpservice.MakeHTTPService(s)
   200  	s.pushNotificationClient = s.HTTPService.MakeClient(true)
   201  
   202  	s.ImageProxy = imageproxy.MakeImageProxy(s, s.HTTPService, s.Log)
   203  
   204  	if err := utils.TranslationsPreInit(); err != nil {
   205  		return nil, errors.Wrapf(err, "unable to load Mattermost translation files")
   206  	}
   207  
   208  	s.SearchEngine = searchengine.NewBroker(s.Config(), s.Jobs)
   209  
   210  	// at the moment we only have this implementation
   211  	// in the future the cache provider will be built based on the loaded config
   212  	s.CacheProvider = new(lru.CacheProvider)
   213  
   214  	s.CacheProvider.Connect()
   215  
   216  	s.sessionCache = s.CacheProvider.NewCache(model.SESSION_CACHE_SIZE)
   217  	s.seenPendingPostIdsCache = s.CacheProvider.NewCache(PENDING_POST_IDS_CACHE_SIZE)
   218  	s.statusCache = s.CacheProvider.NewCache(model.STATUS_CACHE_SIZE)
   219  
   220  	err := s.RunOldAppInitialization()
   221  	if err != nil {
   222  		return nil, err
   223  	}
   224  
   225  	model.AppErrorInit(utils.T)
   226  
   227  	s.timezones = timezones.New()
   228  	// Start email batching because it's not like the other jobs
   229  	s.InitEmailBatching()
   230  	s.AddConfigListener(func(_, _ *model.Config) {
   231  		s.InitEmailBatching()
   232  	})
   233  
   234  	logCurrentVersion := fmt.Sprintf("Current version is %v (%v/%v/%v/%v)", model.CurrentVersion, model.BuildNumber, model.BuildDate, model.BuildHash, model.BuildHashEnterprise)
   235  	mlog.Info(
   236  		logCurrentVersion,
   237  		mlog.String("current_version", model.CurrentVersion),
   238  		mlog.String("build_number", model.BuildNumber),
   239  		mlog.String("build_date", model.BuildDate),
   240  		mlog.String("build_hash", model.BuildHash),
   241  		mlog.String("build_hash_enterprise", model.BuildHashEnterprise),
   242  	)
   243  	if model.BuildEnterpriseReady == "true" {
   244  		mlog.Info("Enterprise Build", mlog.Bool("enterprise_build", true))
   245  	} else {
   246  		mlog.Info("Branch Edition Build", mlog.Bool("enterprise_build", false))
   247  	}
   248  
   249  	pwd, _ := os.Getwd()
   250  	mlog.Info("Printing current working", mlog.String("directory", pwd))
   251  	mlog.Info("Loaded config", mlog.String("source", s.configStore.String()))
   252  
   253  	s.checkPushNotificationServerUrl()
   254  
   255  	license := s.License()
   256  
   257  	if license == nil && len(s.Config().SqlSettings.DataSourceReplicas) > 1 {
   258  		mlog.Warn("More than 1 read replica functionality disabled by current license. Please contact your system administrator about upgrading your enterprise license.")
   259  		s.UpdateConfig(func(cfg *model.Config) {
   260  			cfg.SqlSettings.DataSourceReplicas = cfg.SqlSettings.DataSourceReplicas[:1]
   261  		})
   262  	}
   263  
   264  	if license == nil {
   265  		s.UpdateConfig(func(cfg *model.Config) {
   266  			cfg.BranchSettings.MaxNotificationsPerClass = &MaxNotificationsPerClassDefault
   267  		})
   268  	}
   269  
   270  	s.ReloadConfig()
   271  
   272  	if s.Audit == nil {
   273  		s.Audit = &audit.Audit{}
   274  		s.Audit.Init(audit.DefMaxQueueSize)
   275  		s.configureAudit(s.Audit)
   276  	}
   277  
   278  	// Enable developer settings if this is a "dev" build
   279  	if model.BuildNumber == "dev" {
   280  		s.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableDeveloper = true })
   281  	}
   282  
   283  	if err := s.Store.Status().ResetAll(); err != nil {
   284  		mlog.Error("Error to reset the server status.", mlog.Err(err))
   285  	}
   286  
   287  	if s.joinCluster && s.Cluster != nil {
   288  		s.FakeApp().registerAllClusterMessageHandlers()
   289  		s.Cluster.StartInterNodeCommunication()
   290  	}
   291  
   292  	if s.startMetrics && s.Metrics != nil {
   293  		s.Metrics.StartServer()
   294  	}
   295  
   296  	s.initJobs()
   297  
   298  	if s.runjobs {
   299  		s.Go(func() {
   300  			runSecurityJob(s)
   301  		})
   302  		s.Go(func() {
   303  			runDiagnosticsJob(s)
   304  		})
   305  		s.Go(func() {
   306  			runSessionCleanupJob(s)
   307  		})
   308  		s.Go(func() {
   309  			runTokenCleanupJob(s)
   310  		})
   311  		s.Go(func() {
   312  			runCommandWebhookCleanupJob(s)
   313  		})
   314  
   315  		if complianceI := s.Compliance; complianceI != nil {
   316  			complianceI.StartComplianceDailyJob()
   317  		}
   318  
   319  		if *s.Config().JobSettings.RunJobs && s.Jobs != nil {
   320  			s.Jobs.StartWorkers()
   321  		}
   322  		if *s.Config().JobSettings.RunScheduler && s.Jobs != nil {
   323  			s.Jobs.StartSchedulers()
   324  		}
   325  	}
   326  
   327  	s.SearchEngine.UpdateConfig(s.Config())
   328  	searchConfigListenerId, searchLicenseListenerId := s.StartSearchEngine()
   329  	s.searchConfigListenerId = searchConfigListenerId
   330  	s.searchLicenseListenerId = searchLicenseListenerId
   331  
   332  	return s, nil
   333  }
   334  
   335  // Global app options that should be applied to apps created by this server
   336  func (s *Server) AppOptions() []AppOption {
   337  	return []AppOption{
   338  		ServerConnector(s),
   339  	}
   340  }
   341  
   342  const TIME_TO_WAIT_FOR_CONNECTIONS_TO_CLOSE_ON_SERVER_SHUTDOWN = time.Second
   343  
   344  func (s *Server) StopHTTPServer() {
   345  	if s.Server != nil {
   346  		ctx, cancel := context.WithTimeout(context.Background(), TIME_TO_WAIT_FOR_CONNECTIONS_TO_CLOSE_ON_SERVER_SHUTDOWN)
   347  		defer cancel()
   348  		didShutdown := false
   349  		for s.didFinishListen != nil && !didShutdown {
   350  			if err := s.Server.Shutdown(ctx); err != nil {
   351  				mlog.Warn("Unable to shutdown server", mlog.Err(err))
   352  			}
   353  			timer := time.NewTimer(time.Millisecond * 50)
   354  			select {
   355  			case <-s.didFinishListen:
   356  				didShutdown = true
   357  			case <-timer.C:
   358  			}
   359  			timer.Stop()
   360  		}
   361  		s.Server.Close()
   362  		s.Server = nil
   363  	}
   364  }
   365  
   366  func (s *Server) Shutdown() error {
   367  	mlog.Info("Stopping Server...")
   368  
   369  	s.RunOldAppShutdown()
   370  
   371  	if s.tracer != nil {
   372  		if err := s.tracer.Close(); err != nil {
   373  			mlog.Error("Unable to cleanly shutdown opentracing client", mlog.Err(err))
   374  		}
   375  	}
   376  
   377  	err := s.shutdownDiagnostics()
   378  	if err != nil {
   379  		mlog.Error("Unable to cleanly shutdown diagnostic client", mlog.Err(err))
   380  	}
   381  
   382  	s.StopHTTPServer()
   383  	s.WaitForGoroutines()
   384  
   385  	if s.htmlTemplateWatcher != nil {
   386  		s.htmlTemplateWatcher.Close()
   387  	}
   388  
   389  	s.RemoveConfigListener(s.configListenerId)
   390  	s.RemoveConfigListener(s.logListenerId)
   391  	s.stopSearchEngine()
   392  
   393  	s.Audit.Shutdown()
   394  
   395  	s.configStore.Close()
   396  
   397  	if s.Cluster != nil {
   398  		s.Cluster.StopInterNodeCommunication()
   399  	}
   400  
   401  	if s.Metrics != nil {
   402  		s.Metrics.StopServer()
   403  	}
   404  
   405  	if s.Jobs != nil && s.runjobs {
   406  		s.Jobs.StopWorkers()
   407  		s.Jobs.StopSchedulers()
   408  	}
   409  
   410  	if s.Store != nil {
   411  		s.Store.Close()
   412  	}
   413  
   414  	if s.CacheProvider != nil {
   415  		s.CacheProvider.Close()
   416  	}
   417  
   418  	mlog.Info("Server stopped")
   419  	return nil
   420  }
   421  
   422  // Go creates a goroutine, but maintains a record of it to ensure that execution completes before
   423  // the server is shutdown.
   424  func (s *Server) Go(f func()) {
   425  	atomic.AddInt32(&s.goroutineCount, 1)
   426  
   427  	go func() {
   428  		f()
   429  
   430  		atomic.AddInt32(&s.goroutineCount, -1)
   431  		select {
   432  		case s.goroutineExitSignal <- struct{}{}:
   433  		default:
   434  		}
   435  	}()
   436  }
   437  
   438  // WaitForGoroutines blocks until all goroutines created by App.Go exit.
   439  func (s *Server) WaitForGoroutines() {
   440  	for atomic.LoadInt32(&s.goroutineCount) != 0 {
   441  		<-s.goroutineExitSignal
   442  	}
   443  }
   444  
   445  var corsAllowedMethods = []string{
   446  	"POST",
   447  	"GET",
   448  	"OPTIONS",
   449  	"PUT",
   450  	"PATCH",
   451  	"DELETE",
   452  }
   453  
   454  // golang.org/x/crypto/acme/autocert/autocert.go
   455  func handleHTTPRedirect(w http.ResponseWriter, r *http.Request) {
   456  	if r.Method != "GET" && r.Method != "HEAD" {
   457  		http.Error(w, "Use HTTPS", http.StatusBadRequest)
   458  		return
   459  	}
   460  	target := "https://" + stripPort(r.Host) + r.URL.RequestURI()
   461  	http.Redirect(w, r, target, http.StatusFound)
   462  }
   463  
   464  // golang.org/x/crypto/acme/autocert/autocert.go
   465  func stripPort(hostport string) string {
   466  	host, _, err := net.SplitHostPort(hostport)
   467  	if err != nil {
   468  		return hostport
   469  	}
   470  	return net.JoinHostPort(host, "443")
   471  }
   472  
   473  func (s *Server) Start() error {
   474  	mlog.Info("Starting Server...")
   475  
   476  	var handler http.Handler = s.RootRouter
   477  	if allowedOrigins := *s.Config().ServiceSettings.AllowCorsFrom; allowedOrigins != "" {
   478  		exposedCorsHeaders := *s.Config().ServiceSettings.CorsExposedHeaders
   479  		allowCredentials := *s.Config().ServiceSettings.CorsAllowCredentials
   480  		debug := *s.Config().ServiceSettings.CorsDebug
   481  		corsWrapper := cors.New(cors.Options{
   482  			AllowedOrigins:   strings.Fields(allowedOrigins),
   483  			AllowedMethods:   corsAllowedMethods,
   484  			AllowedHeaders:   []string{"*"},
   485  			ExposedHeaders:   strings.Fields(exposedCorsHeaders),
   486  			MaxAge:           86400,
   487  			AllowCredentials: allowCredentials,
   488  			Debug:            debug,
   489  		})
   490  
   491  		// If we have debugging of CORS turned on then forward messages to logs
   492  		if debug {
   493  			corsWrapper.Log = s.Log.StdLog(mlog.String("source", "cors"))
   494  		}
   495  
   496  		handler = corsWrapper.Handler(handler)
   497  	}
   498  
   499  	if *s.Config().RateLimitSettings.Enable {
   500  		mlog.Info("RateLimiter is enabled")
   501  
   502  		rateLimiter, err := NewRateLimiter(&s.Config().RateLimitSettings, s.Config().ServiceSettings.TrustedProxyIPHeader)
   503  		if err != nil {
   504  			return err
   505  		}
   506  
   507  		s.RateLimiter = rateLimiter
   508  		handler = rateLimiter.RateLimitHandler(handler)
   509  	}
   510  	s.Busy = NewBusy(s.Cluster)
   511  
   512  	// Creating a logger for logging errors from http.Server at error level
   513  	errStdLog, err := s.Log.StdLogAt(mlog.LevelError, mlog.String("source", "httpserver"))
   514  	if err != nil {
   515  		return err
   516  	}
   517  
   518  	s.Server = &http.Server{
   519  		Handler:      handler,
   520  		ReadTimeout:  time.Duration(*s.Config().ServiceSettings.ReadTimeout) * time.Second,
   521  		WriteTimeout: time.Duration(*s.Config().ServiceSettings.WriteTimeout) * time.Second,
   522  		IdleTimeout:  time.Duration(*s.Config().ServiceSettings.IdleTimeout) * time.Second,
   523  		ErrorLog:     errStdLog,
   524  	}
   525  
   526  	addr := *s.Config().ServiceSettings.ListenAddress
   527  	if addr == "" {
   528  		if *s.Config().ServiceSettings.ConnectionSecurity == model.CONN_SECURITY_TLS {
   529  			addr = ":https"
   530  		} else {
   531  			addr = ":http"
   532  		}
   533  	}
   534  
   535  	listener, err := net.Listen("tcp", addr)
   536  	if err != nil {
   537  		errors.Wrapf(err, utils.T("api.server.start_server.starting.critical"), err)
   538  		return err
   539  	}
   540  	s.ListenAddr = listener.Addr().(*net.TCPAddr)
   541  
   542  	logListeningPort := fmt.Sprintf("Server is listening on %v", listener.Addr().String())
   543  	mlog.Info(logListeningPort, mlog.String("address", listener.Addr().String()))
   544  
   545  	m := &autocert.Manager{
   546  		Cache:  autocert.DirCache(*s.Config().ServiceSettings.LetsEncryptCertificateCacheFile),
   547  		Prompt: autocert.AcceptTOS,
   548  	}
   549  
   550  	if *s.Config().ServiceSettings.Forward80To443 {
   551  		if host, port, err := net.SplitHostPort(addr); err != nil {
   552  			mlog.Error("Unable to setup forwarding", mlog.Err(err))
   553  		} else if port != "443" {
   554  			return fmt.Errorf(utils.T("api.server.start_server.forward80to443.enabled_but_listening_on_wrong_port"), port)
   555  		} else {
   556  			httpListenAddress := net.JoinHostPort(host, "http")
   557  
   558  			if *s.Config().ServiceSettings.UseLetsEncrypt {
   559  				server := &http.Server{
   560  					Addr:     httpListenAddress,
   561  					Handler:  m.HTTPHandler(nil),
   562  					ErrorLog: s.Log.StdLog(mlog.String("source", "le_forwarder_server")),
   563  				}
   564  				go server.ListenAndServe()
   565  			} else {
   566  				go func() {
   567  					redirectListener, err := net.Listen("tcp", httpListenAddress)
   568  					if err != nil {
   569  						mlog.Error("Unable to setup forwarding", mlog.Err(err))
   570  						return
   571  					}
   572  					defer redirectListener.Close()
   573  
   574  					server := &http.Server{
   575  						Handler:  http.HandlerFunc(handleHTTPRedirect),
   576  						ErrorLog: s.Log.StdLog(mlog.String("source", "forwarder_server")),
   577  					}
   578  					server.Serve(redirectListener)
   579  				}()
   580  			}
   581  		}
   582  	} else if *s.Config().ServiceSettings.UseLetsEncrypt {
   583  		return errors.New(utils.T("api.server.start_server.forward80to443.disabled_while_using_lets_encrypt"))
   584  	}
   585  
   586  	s.didFinishListen = make(chan struct{})
   587  	go func() {
   588  		var err error
   589  		if *s.Config().ServiceSettings.ConnectionSecurity == model.CONN_SECURITY_TLS {
   590  
   591  			tlsConfig := &tls.Config{
   592  				PreferServerCipherSuites: true,
   593  				CurvePreferences:         []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256},
   594  			}
   595  
   596  			switch *s.Config().ServiceSettings.TLSMinVer {
   597  			case "1.0":
   598  				tlsConfig.MinVersion = tls.VersionTLS10
   599  			case "1.1":
   600  				tlsConfig.MinVersion = tls.VersionTLS11
   601  			default:
   602  				tlsConfig.MinVersion = tls.VersionTLS12
   603  			}
   604  
   605  			defaultCiphers := []uint16{
   606  				tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
   607  				tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
   608  				tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
   609  				tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
   610  				tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
   611  				tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
   612  			}
   613  
   614  			if len(s.Config().ServiceSettings.TLSOverwriteCiphers) == 0 {
   615  				tlsConfig.CipherSuites = defaultCiphers
   616  			} else {
   617  				var cipherSuites []uint16
   618  				for _, cipher := range s.Config().ServiceSettings.TLSOverwriteCiphers {
   619  					value, ok := model.ServerTLSSupportedCiphers[cipher]
   620  
   621  					if !ok {
   622  						mlog.Warn("Unsupported cipher passed", mlog.String("cipher", cipher))
   623  						continue
   624  					}
   625  
   626  					cipherSuites = append(cipherSuites, value)
   627  				}
   628  
   629  				if len(cipherSuites) == 0 {
   630  					mlog.Warn("No supported ciphers passed, fallback to default cipher suite")
   631  					cipherSuites = defaultCiphers
   632  				}
   633  
   634  				tlsConfig.CipherSuites = cipherSuites
   635  			}
   636  
   637  			certFile := ""
   638  			keyFile := ""
   639  
   640  			if *s.Config().ServiceSettings.UseLetsEncrypt {
   641  				tlsConfig.GetCertificate = m.GetCertificate
   642  				tlsConfig.NextProtos = append(tlsConfig.NextProtos, "h2")
   643  			} else {
   644  				certFile = *s.Config().ServiceSettings.TLSCertFile
   645  				keyFile = *s.Config().ServiceSettings.TLSKeyFile
   646  			}
   647  
   648  			s.Server.TLSConfig = tlsConfig
   649  			err = s.Server.ServeTLS(listener, certFile, keyFile)
   650  		} else {
   651  			err = s.Server.Serve(listener)
   652  		}
   653  
   654  		if err != nil && err != http.ErrServerClosed {
   655  			mlog.Critical("Error starting server", mlog.Err(err))
   656  			time.Sleep(time.Second)
   657  		}
   658  
   659  		close(s.didFinishListen)
   660  	}()
   661  
   662  	return nil
   663  }
   664  
   665  func (a *App) OriginChecker() func(*http.Request) bool {
   666  	if allowed := *a.Config().ServiceSettings.AllowCorsFrom; allowed != "" {
   667  		if allowed != "*" {
   668  			siteURL, err := url.Parse(*a.Config().ServiceSettings.SiteURL)
   669  			if err == nil {
   670  				siteURL.Path = ""
   671  				allowed += " " + siteURL.String()
   672  			}
   673  		}
   674  
   675  		return utils.OriginChecker(allowed)
   676  	}
   677  	return nil
   678  }
   679  
   680  func (s *Server) checkPushNotificationServerUrl() {
   681  	notificationServer := *s.Config().EmailSettings.PushNotificationServer
   682  	if strings.HasPrefix(notificationServer, "http://") {
   683  		mlog.Warn("Your push notification server is configured with HTTP. For improved security, update to HTTPS in your configuration.")
   684  	}
   685  }
   686  
   687  func runSecurityJob(s *Server) {
   688  	doSecurity(s)
   689  	model.CreateRecurringTask("Security", func() {
   690  		doSecurity(s)
   691  	}, time.Hour*4)
   692  }
   693  
   694  func runDiagnosticsJob(s *Server) {
   695  	doDiagnostics(s)
   696  	model.CreateRecurringTask("Diagnostics", func() {
   697  		doDiagnostics(s)
   698  	}, time.Hour*24)
   699  }
   700  
   701  func runTokenCleanupJob(s *Server) {
   702  	doTokenCleanup(s)
   703  	model.CreateRecurringTask("Token Cleanup", func() {
   704  		doTokenCleanup(s)
   705  	}, time.Hour*1)
   706  }
   707  
   708  func runCommandWebhookCleanupJob(s *Server) {
   709  	doCommandWebhookCleanup(s)
   710  	model.CreateRecurringTask("Command Hook Cleanup", func() {
   711  		doCommandWebhookCleanup(s)
   712  	}, time.Hour*1)
   713  }
   714  
   715  func runSessionCleanupJob(s *Server) {
   716  	doSessionCleanup(s)
   717  	model.CreateRecurringTask("Session Cleanup", func() {
   718  		doSessionCleanup(s)
   719  	}, time.Hour*24)
   720  }
   721  
   722  func doSecurity(s *Server) {
   723  	s.DoSecurityUpdateCheck()
   724  }
   725  
   726  func doDiagnostics(s *Server) {
   727  	if *s.Config().LogSettings.EnableDiagnostics {
   728  		s.FakeApp().SendDailyDiagnostics()
   729  	}
   730  }
   731  
   732  func doTokenCleanup(s *Server) {
   733  	s.Store.Token().Cleanup()
   734  }
   735  
   736  func doCommandWebhookCleanup(s *Server) {
   737  	s.Store.CommandWebhook().Cleanup()
   738  }
   739  
   740  const (
   741  	SESSIONS_CLEANUP_BATCH_SIZE = 1000
   742  )
   743  
   744  func doSessionCleanup(s *Server) {
   745  	s.Store.Session().Cleanup(model.GetMillis(), SESSIONS_CLEANUP_BATCH_SIZE)
   746  }
   747  
   748  func (s *Server) StartSearchEngine() (string, string) {
   749  	if s.SearchEngine.ElasticsearchEngine != nil && s.SearchEngine.ElasticsearchEngine.IsActive() {
   750  		s.Go(func() {
   751  			if err := s.SearchEngine.ElasticsearchEngine.Start(); err != nil {
   752  				s.Log.Error(err.Error())
   753  			}
   754  		})
   755  	}
   756  
   757  	configListenerId := s.AddConfigListener(func(oldConfig *model.Config, newConfig *model.Config) {
   758  		if s.SearchEngine == nil {
   759  			return
   760  		}
   761  		s.SearchEngine.UpdateConfig(newConfig)
   762  
   763  		if s.SearchEngine.ElasticsearchEngine != nil && !*oldConfig.ElasticsearchSettings.EnableIndexing && *newConfig.ElasticsearchSettings.EnableIndexing {
   764  			s.Go(func() {
   765  				if err := s.SearchEngine.ElasticsearchEngine.Start(); err != nil {
   766  					mlog.Error(err.Error())
   767  				}
   768  			})
   769  		} else if s.SearchEngine.ElasticsearchEngine != nil && *oldConfig.ElasticsearchSettings.EnableIndexing && !*newConfig.ElasticsearchSettings.EnableIndexing {
   770  			s.Go(func() {
   771  				if err := s.SearchEngine.ElasticsearchEngine.Stop(); err != nil {
   772  					mlog.Error(err.Error())
   773  				}
   774  			})
   775  		} 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 {
   776  			s.Go(func() {
   777  				if *oldConfig.ElasticsearchSettings.EnableIndexing {
   778  					if err := s.SearchEngine.ElasticsearchEngine.Stop(); err != nil {
   779  						mlog.Error(err.Error())
   780  					}
   781  					if err := s.SearchEngine.ElasticsearchEngine.Start(); err != nil {
   782  						mlog.Error(err.Error())
   783  					}
   784  				}
   785  			})
   786  		}
   787  	})
   788  
   789  	licenseListenerId := s.AddLicenseListener(func(oldLicense, newLicense *model.License) {
   790  		if s.SearchEngine == nil {
   791  			return
   792  		}
   793  		if oldLicense == nil && newLicense != nil {
   794  			if s.SearchEngine.ElasticsearchEngine != nil && s.SearchEngine.ElasticsearchEngine.IsActive() {
   795  				s.Go(func() {
   796  					if err := s.SearchEngine.ElasticsearchEngine.Start(); err != nil {
   797  						mlog.Error(err.Error())
   798  					}
   799  				})
   800  			}
   801  		} else if oldLicense != nil && newLicense == nil {
   802  			if s.SearchEngine.ElasticsearchEngine != nil {
   803  				s.Go(func() {
   804  					if err := s.SearchEngine.ElasticsearchEngine.Stop(); err != nil {
   805  						mlog.Error(err.Error())
   806  					}
   807  				})
   808  			}
   809  		}
   810  	})
   811  
   812  	return configListenerId, licenseListenerId
   813  }
   814  
   815  func (s *Server) stopSearchEngine() {
   816  	s.RemoveConfigListener(s.searchConfigListenerId)
   817  	s.RemoveLicenseListener(s.searchLicenseListenerId)
   818  	if s.SearchEngine != nil && s.SearchEngine.ElasticsearchEngine != nil && s.SearchEngine.ElasticsearchEngine.IsActive() {
   819  		s.SearchEngine.ElasticsearchEngine.Stop()
   820  	}
   821  }
   822  
   823  func (s *Server) initDiagnostics(endpoint string) {
   824  	if s.diagnosticClient == nil {
   825  		config := analytics.Config{}
   826  		config.Logger = analytics.StdLogger(s.Log.StdLog(mlog.String("source", "segment")))
   827  		// For testing
   828  		if endpoint != "" {
   829  			config.Endpoint = endpoint
   830  			config.Verbose = true
   831  			config.BatchSize = 1
   832  		}
   833  		client, _ := analytics.NewWithConfig(SEGMENT_KEY, config)
   834  		client.Enqueue(analytics.Identify{
   835  			UserId: s.diagnosticId,
   836  		})
   837  
   838  		s.diagnosticClient = client
   839  	}
   840  }
   841  
   842  // shutdownDiagnostics closes the diagnostic client.
   843  func (s *Server) shutdownDiagnostics() error {
   844  	if s.diagnosticClient != nil {
   845  		return s.diagnosticClient.Close()
   846  	}
   847  
   848  	return nil
   849  }
   850  
   851  // GetHubs returns the list of hubs. This method is safe
   852  // for concurrent use by multiple goroutines.
   853  func (s *Server) GetHubs() []*Hub {
   854  	s.hubsLock.RLock()
   855  	defer s.hubsLock.RUnlock()
   856  	return s.hubs
   857  }
   858  
   859  // getHub gets the element at the given index in the hubs list. This method is safe
   860  // for concurrent use by multiple goroutines.
   861  func (s *Server) GetHub(index int) (*Hub, error) {
   862  	s.hubsLock.RLock()
   863  	defer s.hubsLock.RUnlock()
   864  	if index >= len(s.hubs) {
   865  		return nil, errors.New("Hub element doesn't exist")
   866  	}
   867  	return s.hubs[index], nil
   868  }
   869  
   870  // SetHubs sets a new list of hubs. This method is safe
   871  // for concurrent use by multiple goroutines.
   872  func (s *Server) SetHubs(hubs []*Hub) {
   873  	s.hubsLock.Lock()
   874  	defer s.hubsLock.Unlock()
   875  	s.hubs = hubs
   876  }
   877  
   878  // SetHub sets the element at the given index in the hubs list. This method is safe
   879  // for concurrent use by multiple goroutines.
   880  func (s *Server) SetHub(index int, hub *Hub) error {
   881  	s.hubsLock.Lock()
   882  	defer s.hubsLock.Unlock()
   883  	if index >= len(s.hubs) {
   884  		return errors.New("Index is greater than the size of the hubs list")
   885  	}
   886  	s.hubs[index] = hub
   887  	return nil
   888  }
   889  
   890  func (s *Server) FileBackend() (filesstore.FileBackend, *model.AppError) {
   891  	license := s.License()
   892  	return filesstore.NewFileBackend(&s.Config().FileSettings, license != nil && *license.Features.Compliance)
   893  }
   894  
   895  func (s *Server) TotalWebsocketConnections() int {
   896  	count := int64(0)
   897  	for _, hub := range s.GetHubs() {
   898  		count = count + atomic.LoadInt64(&hub.connectionCount)
   899  	}
   900  
   901  	return int(count)
   902  }
   903  
   904  func (s *Server) ensureDiagnosticId() {
   905  	if s.diagnosticId != "" {
   906  		return
   907  	}
   908  	props, err := s.Store.System().Get()
   909  	if err != nil {
   910  		return
   911  	}
   912  
   913  	id := props[model.SYSTEM_DIAGNOSTIC_ID]
   914  	if len(id) == 0 {
   915  		id = model.NewId()
   916  		systemID := &model.System{Name: model.SYSTEM_DIAGNOSTIC_ID, Value: id}
   917  		s.Store.System().Save(systemID)
   918  	}
   919  
   920  	s.diagnosticId = id
   921  }