github.com/keys-pub/mattermost-server@v4.10.10+incompatible/app/app.go (about)

     1  // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package app
     5  
     6  import (
     7  	"crypto/ecdsa"
     8  	"fmt"
     9  	"html/template"
    10  	"net"
    11  	"net/http"
    12  	"reflect"
    13  	"strings"
    14  	"sync"
    15  	"sync/atomic"
    16  
    17  	"github.com/gorilla/mux"
    18  	"github.com/pkg/errors"
    19  
    20  	"github.com/mattermost/mattermost-server/einterfaces"
    21  	ejobs "github.com/mattermost/mattermost-server/einterfaces/jobs"
    22  	"github.com/mattermost/mattermost-server/jobs"
    23  	"github.com/mattermost/mattermost-server/mlog"
    24  	"github.com/mattermost/mattermost-server/model"
    25  	"github.com/mattermost/mattermost-server/plugin/pluginenv"
    26  	"github.com/mattermost/mattermost-server/store"
    27  	"github.com/mattermost/mattermost-server/store/sqlstore"
    28  	"github.com/mattermost/mattermost-server/utils"
    29  )
    30  
    31  const ADVANCED_PERMISSIONS_MIGRATION_KEY = "AdvancedPermissionsMigrationComplete"
    32  
    33  type App struct {
    34  	goroutineCount      int32
    35  	goroutineExitSignal chan struct{}
    36  
    37  	Srv *Server
    38  
    39  	Log *mlog.Logger
    40  
    41  	PluginEnv              *pluginenv.Environment
    42  	PluginConfigListenerId string
    43  
    44  	EmailBatching *EmailBatchingJob
    45  
    46  	Hubs                        []*Hub
    47  	HubsStopCheckingForDeadlock chan bool
    48  
    49  	Jobs *jobs.JobServer
    50  
    51  	AccountMigration einterfaces.AccountMigrationInterface
    52  	Brand            einterfaces.BrandInterface
    53  	Cluster          einterfaces.ClusterInterface
    54  	Compliance       einterfaces.ComplianceInterface
    55  	DataRetention    einterfaces.DataRetentionInterface
    56  	Elasticsearch    einterfaces.ElasticsearchInterface
    57  	Emoji            einterfaces.EmojiInterface
    58  	Ldap             einterfaces.LdapInterface
    59  	MessageExport    einterfaces.MessageExportInterface
    60  	Metrics          einterfaces.MetricsInterface
    61  	Mfa              einterfaces.MfaInterface
    62  	Saml             einterfaces.SamlInterface
    63  
    64  	config          atomic.Value
    65  	envConfig       map[string]interface{}
    66  	configFile      string
    67  	configListeners map[string]func(*model.Config, *model.Config)
    68  
    69  	licenseValue       atomic.Value
    70  	clientLicenseValue atomic.Value
    71  	licenseListeners   map[string]func()
    72  
    73  	timezones atomic.Value
    74  
    75  	siteURL string
    76  
    77  	newStore func() store.Store
    78  
    79  	htmlTemplateWatcher  *utils.HTMLTemplateWatcher
    80  	sessionCache         *utils.Cache
    81  	configListenerId     string
    82  	licenseListenerId    string
    83  	logListenerId        string
    84  	disableConfigWatch   bool
    85  	configWatcher        *utils.ConfigWatcher
    86  	asymmetricSigningKey *ecdsa.PrivateKey
    87  
    88  	pluginCommands     []*PluginCommand
    89  	pluginCommandsLock sync.RWMutex
    90  
    91  	clientConfig     map[string]string
    92  	clientConfigHash string
    93  	diagnosticId     string
    94  }
    95  
    96  var appCount = 0
    97  
    98  // New creates a new App. You must call Shutdown when you're done with it.
    99  // XXX: For now, only one at a time is allowed as some resources are still shared.
   100  func New(options ...Option) (outApp *App, outErr error) {
   101  	appCount++
   102  	if appCount > 1 {
   103  		panic("Only one App should exist at a time. Did you forget to call Shutdown()?")
   104  	}
   105  
   106  	app := &App{
   107  		goroutineExitSignal: make(chan struct{}, 1),
   108  		Srv: &Server{
   109  			Router: mux.NewRouter(),
   110  		},
   111  		sessionCache:     utils.NewLru(model.SESSION_CACHE_SIZE),
   112  		configFile:       "config.json",
   113  		configListeners:  make(map[string]func(*model.Config, *model.Config)),
   114  		clientConfig:     make(map[string]string),
   115  		licenseListeners: map[string]func(){},
   116  	}
   117  	defer func() {
   118  		if outErr != nil {
   119  			app.Shutdown()
   120  		}
   121  	}()
   122  
   123  	for _, option := range options {
   124  		option(app)
   125  	}
   126  
   127  	if utils.T == nil {
   128  		if err := utils.TranslationsPreInit(); err != nil {
   129  			return nil, errors.Wrapf(err, "unable to load Mattermost translation files")
   130  		}
   131  	}
   132  	model.AppErrorInit(utils.T)
   133  
   134  	if err := app.LoadConfig(app.configFile); err != nil {
   135  		return nil, err
   136  	}
   137  
   138  	// Initalize logging
   139  	app.Log = mlog.NewLogger(utils.MloggerConfigFromLoggerConfig(&app.Config().LogSettings))
   140  
   141  	// Redirect default golang logger to this logger
   142  	mlog.RedirectStdLog(app.Log)
   143  
   144  	// Use this app logger as the global logger (eventually remove all instances of global logging)
   145  	mlog.InitGlobalLogger(app.Log)
   146  
   147  	app.logListenerId = app.AddConfigListener(func(_, after *model.Config) {
   148  		app.Log.ChangeLevels(utils.MloggerConfigFromLoggerConfig(&after.LogSettings))
   149  	})
   150  
   151  	app.EnableConfigWatch()
   152  
   153  	app.LoadTimezones()
   154  
   155  	if err := utils.InitTranslations(app.Config().LocalizationSettings); err != nil {
   156  		return nil, errors.Wrapf(err, "unable to load Mattermost translation files")
   157  	}
   158  
   159  	app.configListenerId = app.AddConfigListener(func(_, _ *model.Config) {
   160  		app.configOrLicenseListener()
   161  
   162  		message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_CONFIG_CHANGED, "", "", "", nil)
   163  
   164  		message.Add("config", app.ClientConfigWithComputed())
   165  		app.Go(func() {
   166  			app.Publish(message)
   167  		})
   168  	})
   169  	app.licenseListenerId = app.AddLicenseListener(func() {
   170  		app.configOrLicenseListener()
   171  
   172  		message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_LICENSE_CHANGED, "", "", "", nil)
   173  		message.Add("license", app.GetSanitizedClientLicense())
   174  		app.Go(func() {
   175  			app.Publish(message)
   176  		})
   177  
   178  	})
   179  	app.regenerateClientConfig()
   180  
   181  	mlog.Info("Server is initializing...")
   182  
   183  	app.initEnterprise()
   184  
   185  	if app.newStore == nil {
   186  		app.newStore = func() store.Store {
   187  			return store.NewLayeredStore(sqlstore.NewSqlSupplier(app.Config().SqlSettings, app.Metrics), app.Metrics, app.Cluster)
   188  		}
   189  	}
   190  
   191  	if htmlTemplateWatcher, err := utils.NewHTMLTemplateWatcher("templates"); err != nil {
   192  		mlog.Error(fmt.Sprintf("Failed to parse server templates %v", err))
   193  	} else {
   194  		app.htmlTemplateWatcher = htmlTemplateWatcher
   195  	}
   196  
   197  	app.Srv.Store = app.newStore()
   198  	if err := app.ensureAsymmetricSigningKey(); err != nil {
   199  		return nil, errors.Wrapf(err, "unable to ensure asymmetric signing key")
   200  	}
   201  
   202  	app.initJobs()
   203  
   204  	app.initBuiltInPlugins()
   205  	app.Srv.Router.HandleFunc("/plugins/{plugin_id:[A-Za-z0-9\\_\\-\\.]+}", app.ServePluginRequest)
   206  	app.Srv.Router.HandleFunc("/plugins/{plugin_id:[A-Za-z0-9\\_\\-\\.]+}/{anything:.*}", app.ServePluginRequest)
   207  
   208  	app.Srv.Router.NotFoundHandler = http.HandlerFunc(app.Handle404)
   209  
   210  	app.Srv.WebSocketRouter = &WebSocketRouter{
   211  		app:      app,
   212  		handlers: make(map[string]webSocketHandler),
   213  	}
   214  
   215  	return app, nil
   216  }
   217  
   218  func (a *App) configOrLicenseListener() {
   219  	a.regenerateClientConfig()
   220  }
   221  
   222  func (a *App) Shutdown() {
   223  	appCount--
   224  
   225  	mlog.Info("Stopping Server...")
   226  
   227  	a.StopServer()
   228  	a.HubStop()
   229  
   230  	a.ShutDownPlugins()
   231  	a.WaitForGoroutines()
   232  
   233  	if a.Srv.Store != nil {
   234  		a.Srv.Store.Close()
   235  	}
   236  	a.Srv = nil
   237  
   238  	if a.htmlTemplateWatcher != nil {
   239  		a.htmlTemplateWatcher.Close()
   240  	}
   241  
   242  	a.RemoveConfigListener(a.configListenerId)
   243  	a.RemoveLicenseListener(a.licenseListenerId)
   244  	a.RemoveConfigListener(a.logListenerId)
   245  	mlog.Info("Server stopped")
   246  
   247  	a.DisableConfigWatch()
   248  }
   249  
   250  var accountMigrationInterface func(*App) einterfaces.AccountMigrationInterface
   251  
   252  func RegisterAccountMigrationInterface(f func(*App) einterfaces.AccountMigrationInterface) {
   253  	accountMigrationInterface = f
   254  }
   255  
   256  var brandInterface func(*App) einterfaces.BrandInterface
   257  
   258  func RegisterBrandInterface(f func(*App) einterfaces.BrandInterface) {
   259  	brandInterface = f
   260  }
   261  
   262  var clusterInterface func(*App) einterfaces.ClusterInterface
   263  
   264  func RegisterClusterInterface(f func(*App) einterfaces.ClusterInterface) {
   265  	clusterInterface = f
   266  }
   267  
   268  var complianceInterface func(*App) einterfaces.ComplianceInterface
   269  
   270  func RegisterComplianceInterface(f func(*App) einterfaces.ComplianceInterface) {
   271  	complianceInterface = f
   272  }
   273  
   274  var dataRetentionInterface func(*App) einterfaces.DataRetentionInterface
   275  
   276  func RegisterDataRetentionInterface(f func(*App) einterfaces.DataRetentionInterface) {
   277  	dataRetentionInterface = f
   278  }
   279  
   280  var elasticsearchInterface func(*App) einterfaces.ElasticsearchInterface
   281  
   282  func RegisterElasticsearchInterface(f func(*App) einterfaces.ElasticsearchInterface) {
   283  	elasticsearchInterface = f
   284  }
   285  
   286  var emojiInterface func(*App) einterfaces.EmojiInterface
   287  
   288  func RegisterEmojiInterface(f func(*App) einterfaces.EmojiInterface) {
   289  	emojiInterface = f
   290  }
   291  
   292  var jobsDataRetentionJobInterface func(*App) ejobs.DataRetentionJobInterface
   293  
   294  func RegisterJobsDataRetentionJobInterface(f func(*App) ejobs.DataRetentionJobInterface) {
   295  	jobsDataRetentionJobInterface = f
   296  }
   297  
   298  var jobsMessageExportJobInterface func(*App) ejobs.MessageExportJobInterface
   299  
   300  func RegisterJobsMessageExportJobInterface(f func(*App) ejobs.MessageExportJobInterface) {
   301  	jobsMessageExportJobInterface = f
   302  }
   303  
   304  var jobsElasticsearchAggregatorInterface func(*App) ejobs.ElasticsearchAggregatorInterface
   305  
   306  func RegisterJobsElasticsearchAggregatorInterface(f func(*App) ejobs.ElasticsearchAggregatorInterface) {
   307  	jobsElasticsearchAggregatorInterface = f
   308  }
   309  
   310  var jobsElasticsearchIndexerInterface func(*App) ejobs.ElasticsearchIndexerInterface
   311  
   312  func RegisterJobsElasticsearchIndexerInterface(f func(*App) ejobs.ElasticsearchIndexerInterface) {
   313  	jobsElasticsearchIndexerInterface = f
   314  }
   315  
   316  var jobsLdapSyncInterface func(*App) ejobs.LdapSyncInterface
   317  
   318  func RegisterJobsLdapSyncInterface(f func(*App) ejobs.LdapSyncInterface) {
   319  	jobsLdapSyncInterface = f
   320  }
   321  
   322  var ldapInterface func(*App) einterfaces.LdapInterface
   323  
   324  func RegisterLdapInterface(f func(*App) einterfaces.LdapInterface) {
   325  	ldapInterface = f
   326  }
   327  
   328  var messageExportInterface func(*App) einterfaces.MessageExportInterface
   329  
   330  func RegisterMessageExportInterface(f func(*App) einterfaces.MessageExportInterface) {
   331  	messageExportInterface = f
   332  }
   333  
   334  var metricsInterface func(*App) einterfaces.MetricsInterface
   335  
   336  func RegisterMetricsInterface(f func(*App) einterfaces.MetricsInterface) {
   337  	metricsInterface = f
   338  }
   339  
   340  var mfaInterface func(*App) einterfaces.MfaInterface
   341  
   342  func RegisterMfaInterface(f func(*App) einterfaces.MfaInterface) {
   343  	mfaInterface = f
   344  }
   345  
   346  var samlInterface func(*App) einterfaces.SamlInterface
   347  
   348  func RegisterSamlInterface(f func(*App) einterfaces.SamlInterface) {
   349  	samlInterface = f
   350  }
   351  
   352  func (a *App) initEnterprise() {
   353  	if accountMigrationInterface != nil {
   354  		a.AccountMigration = accountMigrationInterface(a)
   355  	}
   356  	if brandInterface != nil {
   357  		a.Brand = brandInterface(a)
   358  	}
   359  	if clusterInterface != nil {
   360  		a.Cluster = clusterInterface(a)
   361  	}
   362  	if complianceInterface != nil {
   363  		a.Compliance = complianceInterface(a)
   364  	}
   365  	if elasticsearchInterface != nil {
   366  		a.Elasticsearch = elasticsearchInterface(a)
   367  	}
   368  	if emojiInterface != nil {
   369  		a.Emoji = emojiInterface(a)
   370  	}
   371  	if ldapInterface != nil {
   372  		a.Ldap = ldapInterface(a)
   373  		a.AddConfigListener(func(_, cfg *model.Config) {
   374  			if err := utils.ValidateLdapFilter(cfg, a.Ldap); err != nil {
   375  				panic(utils.T(err.Id))
   376  			}
   377  		})
   378  	}
   379  	if messageExportInterface != nil {
   380  		a.MessageExport = messageExportInterface(a)
   381  	}
   382  	if metricsInterface != nil {
   383  		a.Metrics = metricsInterface(a)
   384  	}
   385  	if mfaInterface != nil {
   386  		a.Mfa = mfaInterface(a)
   387  	}
   388  	if samlInterface != nil {
   389  		a.Saml = samlInterface(a)
   390  		a.AddConfigListener(func(_, cfg *model.Config) {
   391  			a.Saml.ConfigureSP()
   392  		})
   393  	}
   394  	if dataRetentionInterface != nil {
   395  		a.DataRetention = dataRetentionInterface(a)
   396  	}
   397  }
   398  
   399  func (a *App) initJobs() {
   400  	a.Jobs = jobs.NewJobServer(a, a.Srv.Store)
   401  	if jobsDataRetentionJobInterface != nil {
   402  		a.Jobs.DataRetentionJob = jobsDataRetentionJobInterface(a)
   403  	}
   404  	if jobsMessageExportJobInterface != nil {
   405  		a.Jobs.MessageExportJob = jobsMessageExportJobInterface(a)
   406  	}
   407  	if jobsElasticsearchAggregatorInterface != nil {
   408  		a.Jobs.ElasticsearchAggregator = jobsElasticsearchAggregatorInterface(a)
   409  	}
   410  	if jobsElasticsearchIndexerInterface != nil {
   411  		a.Jobs.ElasticsearchIndexer = jobsElasticsearchIndexerInterface(a)
   412  	}
   413  	if jobsLdapSyncInterface != nil {
   414  		a.Jobs.LdapSync = jobsLdapSyncInterface(a)
   415  	}
   416  }
   417  
   418  func (a *App) DiagnosticId() string {
   419  	return a.diagnosticId
   420  }
   421  
   422  func (a *App) SetDiagnosticId(id string) {
   423  	a.diagnosticId = id
   424  }
   425  
   426  func (a *App) EnsureDiagnosticId() {
   427  	if a.diagnosticId != "" {
   428  		return
   429  	}
   430  	if result := <-a.Srv.Store.System().Get(); result.Err == nil {
   431  		props := result.Data.(model.StringMap)
   432  
   433  		id := props[model.SYSTEM_DIAGNOSTIC_ID]
   434  		if len(id) == 0 {
   435  			id = model.NewId()
   436  			systemId := &model.System{Name: model.SYSTEM_DIAGNOSTIC_ID, Value: id}
   437  			<-a.Srv.Store.System().Save(systemId)
   438  		}
   439  
   440  		a.diagnosticId = id
   441  	}
   442  }
   443  
   444  // Go creates a goroutine, but maintains a record of it to ensure that execution completes before
   445  // the app is destroyed.
   446  func (a *App) Go(f func()) {
   447  	atomic.AddInt32(&a.goroutineCount, 1)
   448  
   449  	go func() {
   450  		f()
   451  
   452  		atomic.AddInt32(&a.goroutineCount, -1)
   453  		select {
   454  		case a.goroutineExitSignal <- struct{}{}:
   455  		default:
   456  		}
   457  	}()
   458  }
   459  
   460  // WaitForGoroutines blocks until all goroutines created by App.Go exit.
   461  func (a *App) WaitForGoroutines() {
   462  	for atomic.LoadInt32(&a.goroutineCount) != 0 {
   463  		<-a.goroutineExitSignal
   464  	}
   465  }
   466  
   467  func (a *App) HTMLTemplates() *template.Template {
   468  	if a.htmlTemplateWatcher != nil {
   469  		return a.htmlTemplateWatcher.Templates()
   470  	}
   471  
   472  	return nil
   473  }
   474  
   475  func (a *App) HTTPClient(trustURLs bool) *http.Client {
   476  	insecure := a.Config().ServiceSettings.EnableInsecureOutgoingConnections != nil && *a.Config().ServiceSettings.EnableInsecureOutgoingConnections
   477  
   478  	if trustURLs {
   479  		return utils.NewHTTPClient(insecure, nil, nil)
   480  	}
   481  
   482  	allowHost := func(host string) bool {
   483  		if a.Config().ServiceSettings.AllowedUntrustedInternalConnections == nil {
   484  			return false
   485  		}
   486  		for _, allowed := range strings.Fields(*a.Config().ServiceSettings.AllowedUntrustedInternalConnections) {
   487  			if host == allowed {
   488  				return true
   489  			}
   490  		}
   491  		return false
   492  	}
   493  
   494  	allowIP := func(ip net.IP) bool {
   495  		reservedIP := utils.IsReservedIP(ip)
   496  		ownIP, err := utils.IsOwnIP(ip)
   497  
   498  		// If there is an error getting the self-assigned IPs, default to the secure option
   499  		if err != nil {
   500  			return false
   501  		}
   502  
   503  		// If it's not a reserved IP and it's not self-assigned IP, accept the IP
   504  		if !reservedIP && !ownIP {
   505  			return true
   506  		}
   507  
   508  		if a.Config().ServiceSettings.AllowedUntrustedInternalConnections == nil {
   509  			return false
   510  		}
   511  
   512  		// In the case it's the self-assigned IP, enforce that it needs to be explicitly added to the AllowedUntrustedInternalConnections
   513  		for _, allowed := range strings.Fields(*a.Config().ServiceSettings.AllowedUntrustedInternalConnections) {
   514  			if _, ipRange, err := net.ParseCIDR(allowed); err == nil && ipRange.Contains(ip) {
   515  				return true
   516  			}
   517  		}
   518  		return false
   519  	}
   520  
   521  	return utils.NewHTTPClient(insecure, allowHost, allowIP)
   522  }
   523  
   524  func (a *App) Handle404(w http.ResponseWriter, r *http.Request) {
   525  	err := model.NewAppError("Handle404", "api.context.404.app_error", nil, "", http.StatusNotFound)
   526  
   527  	mlog.Debug(fmt.Sprintf("%v: code=404 ip=%v", r.URL.Path, utils.GetIpAddress(r)))
   528  
   529  	utils.RenderWebAppError(w, r, err, a.AsymmetricSigningKey())
   530  }
   531  
   532  // This function migrates the default built in roles from code/config to the database.
   533  func (a *App) DoAdvancedPermissionsMigration() {
   534  	// If the migration is already marked as completed, don't do it again.
   535  	if result := <-a.Srv.Store.System().GetByName(ADVANCED_PERMISSIONS_MIGRATION_KEY); result.Err == nil {
   536  		return
   537  	}
   538  
   539  	mlog.Info("Migrating roles to database.")
   540  	roles := model.MakeDefaultRoles()
   541  	roles = utils.SetRolePermissionsFromConfig(roles, a.Config(), a.License() != nil)
   542  
   543  	allSucceeded := true
   544  
   545  	for _, role := range roles {
   546  		if result := <-a.Srv.Store.Role().Save(role); result.Err != nil {
   547  			// If this failed for reasons other than the role already existing, don't mark the migration as done.
   548  			if result2 := <-a.Srv.Store.Role().GetByName(role.Name); result2.Err != nil {
   549  				mlog.Critical("Failed to migrate role to database.")
   550  				mlog.Critical(fmt.Sprint(result.Err))
   551  				allSucceeded = false
   552  			} else {
   553  				// If the role already existed, check it is the same and update if not.
   554  				fetchedRole := result.Data.(*model.Role)
   555  				if !reflect.DeepEqual(fetchedRole.Permissions, role.Permissions) ||
   556  					fetchedRole.DisplayName != role.DisplayName ||
   557  					fetchedRole.Description != role.Description ||
   558  					fetchedRole.SchemeManaged != role.SchemeManaged {
   559  					role.Id = fetchedRole.Id
   560  					if result := <-a.Srv.Store.Role().Save(role); result.Err != nil {
   561  						// Role is not the same, but failed to update.
   562  						mlog.Critical("Failed to migrate role to database.")
   563  						mlog.Critical(fmt.Sprint(result.Err))
   564  						allSucceeded = false
   565  					}
   566  				}
   567  			}
   568  		}
   569  	}
   570  
   571  	if !allSucceeded {
   572  		return
   573  	}
   574  
   575  	config := a.Config()
   576  	if *config.ServiceSettings.AllowEditPost == model.ALLOW_EDIT_POST_ALWAYS {
   577  		*config.ServiceSettings.PostEditTimeLimit = -1
   578  		if err := a.SaveConfig(config, true); err != nil {
   579  			mlog.Error("Failed to update config in Advanced Permissions Phase 1 Migration.", mlog.String("error", err.Error()))
   580  		}
   581  	}
   582  
   583  	system := model.System{
   584  		Name:  ADVANCED_PERMISSIONS_MIGRATION_KEY,
   585  		Value: "true",
   586  	}
   587  
   588  	if result := <-a.Srv.Store.System().Save(&system); result.Err != nil {
   589  		mlog.Critical("Failed to mark advanced permissions migration as completed.")
   590  		mlog.Critical(fmt.Sprint(result.Err))
   591  	}
   592  }