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 }