2018-12-17 08:51:46 -08:00
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
2019-11-29 12:59:40 +01:00
// See LICENSE.txt for license information.
2018-12-17 08:51:46 -08:00
package app
import (
"net/http"
"net/url"
"path"
2019-11-28 14:39:38 +01:00
"github.com/mattermost/mattermost-server/v5/mlog"
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/services/mailservice"
"github.com/mattermost/mattermost-server/v5/store"
"github.com/mattermost/mattermost-server/v5/store/localcachelayer"
"github.com/mattermost/mattermost-server/v5/store/sqlstore"
"github.com/mattermost/mattermost-server/v5/utils"
2018-12-17 08:51:46 -08:00
"github.com/pkg/errors"
)
2019-11-12 19:33:05 +08:00
// This is a bridge between the old and new initialization for the context refactor.
// It calls app layer initialization code that then turns around and acts on the server.
// Don't add anything new here, new initialization should be done in the server and
2018-12-17 08:51:46 -08:00
// performed in the NewServer function.
2019-11-12 19:33:05 +08:00
func ( s * Server ) RunOldAppInitialization ( ) error {
2019-02-08 18:13:52 -08:00
s . FakeApp ( ) . CreatePushNotificationsHub ( )
s . FakeApp ( ) . StartPushNotificationsHubWorkers ( )
2018-12-17 08:51:46 -08:00
2019-02-08 18:13:52 -08:00
if err := utils . InitTranslations ( s . FakeApp ( ) . Config ( ) . LocalizationSettings ) ; err != nil {
2018-12-17 08:51:46 -08:00
return errors . Wrapf ( err , "unable to load Mattermost translation files" )
}
2019-02-08 18:13:52 -08:00
s . FakeApp ( ) . Srv . configListenerId = s . FakeApp ( ) . AddConfigListener ( func ( _ , _ * model . Config ) {
s . FakeApp ( ) . configOrLicenseListener ( )
2018-12-17 08:51:46 -08:00
message := model . NewWebSocketEvent ( model . WEBSOCKET_EVENT_CONFIG_CHANGED , "" , "" , "" , nil )
2019-02-08 18:13:52 -08:00
message . Add ( "config" , s . FakeApp ( ) . ClientConfigWithComputed ( ) )
s . Go ( func ( ) {
s . FakeApp ( ) . Publish ( message )
2018-12-17 08:51:46 -08:00
} )
} )
2019-02-08 18:13:52 -08:00
s . FakeApp ( ) . Srv . licenseListenerId = s . FakeApp ( ) . AddLicenseListener ( func ( ) {
s . FakeApp ( ) . configOrLicenseListener ( )
2018-12-17 08:51:46 -08:00
message := model . NewWebSocketEvent ( model . WEBSOCKET_EVENT_LICENSE_CHANGED , "" , "" , "" , nil )
2019-02-08 18:13:52 -08:00
message . Add ( "license" , s . FakeApp ( ) . GetSanitizedClientLicense ( ) )
s . Go ( func ( ) {
s . FakeApp ( ) . Publish ( message )
2018-12-17 08:51:46 -08:00
} )
} )
2019-02-08 18:13:52 -08:00
if err := s . FakeApp ( ) . SetupInviteEmailRateLimiting ( ) ; err != nil {
2018-12-17 08:51:46 -08:00
return err
}
mlog . Info ( "Server is initializing..." )
s . initEnterprise ( )
2019-02-08 18:13:52 -08:00
if s . FakeApp ( ) . Srv . newStore == nil {
s . FakeApp ( ) . Srv . newStore = func ( ) store . Store {
2019-12-30 22:52:31 +05:30
return store . NewTimerLayer (
localcachelayer . NewLocalCacheLayer (
sqlstore . NewSqlSupplier ( s . FakeApp ( ) . Config ( ) . SqlSettings , s . Metrics ) ,
2020-01-09 09:57:28 +01:00
s . Metrics , s . Cluster , s . CacheProvider ) ,
2019-12-30 22:52:31 +05:30
s . Metrics )
2018-12-17 08:51:46 -08:00
}
}
if htmlTemplateWatcher , err := utils . NewHTMLTemplateWatcher ( "templates" ) ; err != nil {
2019-10-11 15:24:54 +01:00
mlog . Error ( "Failed to parse server templates" , mlog . Err ( err ) )
2018-12-17 08:51:46 -08:00
} else {
2019-02-08 18:13:52 -08:00
s . FakeApp ( ) . Srv . htmlTemplateWatcher = htmlTemplateWatcher
2018-12-17 08:51:46 -08:00
}
2019-02-08 18:13:52 -08:00
s . FakeApp ( ) . Srv . Store = s . FakeApp ( ) . Srv . newStore ( )
2018-12-17 08:51:46 -08:00
2019-02-08 18:13:52 -08:00
if err := s . FakeApp ( ) . ensureAsymmetricSigningKey ( ) ; err != nil {
2018-12-17 08:51:46 -08:00
return errors . Wrapf ( err , "unable to ensure asymmetric signing key" )
}
MM-10516: Added support for PostActions in ephemeral posts (#10258)
* Added support for PostActions in ephemeral posts
The general approach is that we take all the metadata that DoPostAction
needs to process client DoPostActionRequests, and store it in a
serialized, encrypted Cookie field, in the PostAction struct.
The client then must send it back, and it is then used to process
PostActions as a fallback top the metadata in the database.
This PR adds a new config setting, `ServiceSettings.ActionCookieSecret`.
In a cluster environment it must be the same for all instances.
- Added type PostActionCookie, and a Cookie string to PostAction.
- Added App.AddActionCookiesToPost.
- Use App.AddActionCookiesToPost in api4.createEphemeralPost,
App.SendEphemeralPost, App.UpdateEphemeralPost.
- Added App.DoPostActionWithCookie to process incoming requests with
cookies. For backward compatibility, it prefers the metadata in the
database; falls back to cookie.
- Added plugin.API.UpdateEphemeralPost and plugin.API.DeleteEphemeralPost.
- Added App.encryptActionCookie/App.decryptActionCookie.
* Style
* Fixed an unfortunate typo, tested with matterpoll
* minor PR feedback
* Fixed uninitialized Context
* Fixed another test failure
* Fixed permission check
* Added api test for DoPostActionWithCookie
* Replaced config.ActionCookieSecret with Server.PostActionCookieSecret
Modeled after AsymetricSigningKey
* style
* Set DeleteAt in DeleteEphemeralPost
* PR feedback
* Removed deadwood comment
* Added EXPERIMENTAL comment to the 2 APIs in question
2019-03-01 10:15:31 -08:00
if err := s . FakeApp ( ) . ensurePostActionCookieSecret ( ) ; err != nil {
return errors . Wrapf ( err , "unable to ensure PostAction cookie secret" )
}
2019-02-08 18:13:52 -08:00
if err := s . FakeApp ( ) . ensureInstallationDate ( ) ; err != nil {
2018-12-17 08:51:46 -08:00
return errors . Wrapf ( err , "unable to ensure installation date" )
}
2019-02-08 18:13:52 -08:00
s . FakeApp ( ) . EnsureDiagnosticId ( )
s . FakeApp ( ) . regenerateClientConfig ( )
2018-12-17 08:51:46 -08:00
2019-02-08 18:13:52 -08:00
s . FakeApp ( ) . Srv . clusterLeaderListenerId = s . FakeApp ( ) . Srv . AddClusterLeaderChangedListener ( func ( ) {
mlog . Info ( "Cluster leader changed. Determining if job schedulers should be running:" , mlog . Bool ( "isLeader" , s . FakeApp ( ) . IsLeader ( ) ) )
if s . FakeApp ( ) . Srv . Jobs != nil {
s . FakeApp ( ) . Srv . Jobs . Schedulers . HandleClusterLeaderChange ( s . FakeApp ( ) . IsLeader ( ) )
2018-12-17 08:51:46 -08:00
}
} )
2019-02-08 18:13:52 -08:00
subpath , err := utils . GetSubpathFromConfig ( s . FakeApp ( ) . Config ( ) )
2018-12-17 08:51:46 -08:00
if err != nil {
return errors . Wrap ( err , "failed to parse SiteURL subpath" )
}
2019-02-08 18:13:52 -08:00
s . FakeApp ( ) . Srv . Router = s . FakeApp ( ) . Srv . RootRouter . PathPrefix ( subpath ) . Subrouter ( )
2019-04-05 07:35:51 -07:00
pluginsRoute := s . FakeApp ( ) . Srv . Router . PathPrefix ( "/plugins/{plugin_id:[A-Za-z0-9\\_\\-\\.]+}" ) . Subrouter ( )
pluginsRoute . HandleFunc ( "" , s . FakeApp ( ) . ServePluginRequest )
pluginsRoute . HandleFunc ( "/public/{public_file:.*}" , s . FakeApp ( ) . ServePluginPublicRequest )
pluginsRoute . HandleFunc ( "/{anything:.*}" , s . FakeApp ( ) . ServePluginRequest )
2018-12-17 08:51:46 -08:00
// If configured with a subpath, redirect 404s at the root back into the subpath.
if subpath != "/" {
2019-02-08 18:13:52 -08:00
s . FakeApp ( ) . Srv . RootRouter . NotFoundHandler = http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
2018-12-17 08:51:46 -08:00
r . URL . Path = path . Join ( subpath , r . URL . Path )
http . Redirect ( w , r , r . URL . String ( ) , http . StatusFound )
} )
}
2019-02-08 18:13:52 -08:00
s . FakeApp ( ) . Srv . Router . NotFoundHandler = http . HandlerFunc ( s . FakeApp ( ) . Handle404 )
2018-12-17 08:51:46 -08:00
2019-02-08 18:13:52 -08:00
s . FakeApp ( ) . Srv . WebSocketRouter = & WebSocketRouter {
app : s . FakeApp ( ) ,
2018-12-17 08:51:46 -08:00
handlers : make ( map [ string ] webSocketHandler ) ,
}
2019-02-08 18:13:52 -08:00
mailservice . TestConnection ( s . FakeApp ( ) . Config ( ) )
2018-12-17 08:51:46 -08:00
2019-02-08 18:13:52 -08:00
if _ , err := url . ParseRequestURI ( * s . FakeApp ( ) . Config ( ) . ServiceSettings . SiteURL ) ; err != nil {
2018-12-17 08:51:46 -08:00
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" )
}
2019-02-08 18:13:52 -08:00
backend , appErr := s . FakeApp ( ) . FileBackend ( )
2018-12-17 08:51:46 -08:00
if appErr == nil {
appErr = backend . TestConnection ( )
}
if appErr != nil {
2019-10-11 15:24:54 +01:00
mlog . Error ( "Problem with file storage settings" , mlog . Err ( appErr ) )
2018-12-17 08:51:46 -08:00
}
if model . BuildEnterpriseReady == "true" {
2019-02-08 18:13:52 -08:00
s . FakeApp ( ) . LoadLicense ( )
2018-12-17 08:51:46 -08:00
}
2019-04-30 20:36:21 +02:00
s . FakeApp ( ) . DoAppMigrations ( )
2018-12-17 08:51:46 -08:00
2019-02-08 18:13:52 -08:00
s . FakeApp ( ) . InitPostMetadata ( )
2018-12-17 08:51:46 -08:00
2019-02-08 18:13:52 -08:00
s . FakeApp ( ) . InitPlugins ( * s . Config ( ) . PluginSettings . Directory , * s . Config ( ) . PluginSettings . ClientDirectory )
s . FakeApp ( ) . AddConfigListener ( func ( prevCfg , cfg * model . Config ) {
2018-12-17 08:51:46 -08:00
if * cfg . PluginSettings . Enable {
2019-02-08 18:13:52 -08:00
s . FakeApp ( ) . InitPlugins ( * cfg . PluginSettings . Directory , * s . Config ( ) . PluginSettings . ClientDirectory )
2018-12-17 08:51:46 -08:00
} else {
2019-02-08 18:13:52 -08:00
s . FakeApp ( ) . ShutDownPlugins ( )
2018-12-17 08:51:46 -08:00
}
} )
return nil
}
func ( s * Server ) RunOldAppShutdown ( ) {
2019-02-08 18:13:52 -08:00
s . FakeApp ( ) . HubStop ( )
s . FakeApp ( ) . StopPushNotificationsHubWorkers ( )
s . FakeApp ( ) . ShutDownPlugins ( )
s . FakeApp ( ) . RemoveLicenseListener ( s . licenseListenerId )
2019-01-15 09:09:25 -08:00
s . RemoveClusterLeaderChangedListener ( s . clusterLeaderListenerId )
2018-12-17 08:51:46 -08:00
}
// A temporary bridge to deal with cases where the code is so tighly coupled that
// this is easier as a temporary solution
func ( s * Server ) FakeApp ( ) * App {
a := New (
ServerConnector ( s ) ,
)
return a
}