* add request context

* move initialialization to server

* use app interface instead of global app functions

* remove app context from webconn

* cleanup

* remove duplicated services

* move context to separate package

* remove finalize init method and move content to NewServer function

* restart workers and schedulers after adding license for tests

* reflect review comments

Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
Ibrahim Serdar Acikgoz
2021-05-11 13:00:44 +03:00
коммит произвёл GitHub
родитель c09369f14a
Коммит 5ea06e51d0
235 изменённых файлов: 4048 добавлений и 3819 удалений

Просмотреть файл

@@ -10,6 +10,7 @@ import (
"strings"
"github.com/mattermost/mattermost-server/v5/app"
"github.com/mattermost/mattermost-server/v5/app/request"
"github.com/mattermost/mattermost-server/v5/audit"
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/shared/i18n"
@@ -19,6 +20,7 @@ import (
type Context struct {
App app.AppIface
AppContext *request.Context
Logger *mlog.Logger
Params *Params
Err *model.AppError
@@ -51,13 +53,13 @@ func (c *Context) LogAuditRecWithLevel(rec *audit.Record, level mlog.LogLevel) {
// MakeAuditRecord creates a audit record pre-populated with data from this context.
func (c *Context) MakeAuditRecord(event string, initialStatus string) *audit.Record {
rec := &audit.Record{
APIPath: c.App.Path(),
APIPath: c.AppContext.Path(),
Event: event,
Status: initialStatus,
UserID: c.App.Session().UserId,
SessionID: c.App.Session().Id,
Client: c.App.UserAgent(),
IPAddress: c.App.IpAddress(),
UserID: c.AppContext.Session().UserId,
SessionID: c.AppContext.Session().Id,
Client: c.AppContext.UserAgent(),
IPAddress: c.AppContext.IpAddress(),
Meta: audit.Meta{audit.KeyClusterID: c.App.GetClusterId()},
}
rec.AddMetaTypeConverter(model.AuditModelTypeConv)
@@ -66,7 +68,7 @@ func (c *Context) MakeAuditRecord(event string, initialStatus string) *audit.Rec
}
func (c *Context) LogAudit(extraInfo string) {
audit := &model.Audit{UserId: c.App.Session().UserId, IpAddress: c.App.IpAddress(), Action: c.App.Path(), ExtraInfo: extraInfo, SessionId: c.App.Session().Id}
audit := &model.Audit{UserId: c.AppContext.Session().UserId, IpAddress: c.AppContext.IpAddress(), Action: c.AppContext.Path(), ExtraInfo: extraInfo, SessionId: c.AppContext.Session().Id}
if err := c.App.Srv().Store.Audit().Save(audit); err != nil {
appErr := model.NewAppError("LogAudit", "app.audit.save.saving.app_error", nil, err.Error(), http.StatusInternalServerError)
c.LogErrorByCode(appErr)
@@ -75,11 +77,11 @@ func (c *Context) LogAudit(extraInfo string) {
func (c *Context) LogAuditWithUserId(userId, extraInfo string) {
if c.App.Session().UserId != "" {
extraInfo = strings.TrimSpace(extraInfo + " session_user=" + c.App.Session().UserId)
if c.AppContext.Session().UserId != "" {
extraInfo = strings.TrimSpace(extraInfo + " session_user=" + c.AppContext.Session().UserId)
}
audit := &model.Audit{UserId: userId, IpAddress: c.App.IpAddress(), Action: c.App.Path(), ExtraInfo: extraInfo, SessionId: c.App.Session().Id}
audit := &model.Audit{UserId: userId, IpAddress: c.AppContext.IpAddress(), Action: c.AppContext.Path(), ExtraInfo: extraInfo, SessionId: c.AppContext.Session().Id}
if err := c.App.Srv().Store.Audit().Save(audit); err != nil {
appErr := model.NewAppError("LogAuditWithUserId", "app.audit.save.saving.app_error", nil, err.Error(), http.StatusInternalServerError)
c.LogErrorByCode(appErr)
@@ -106,33 +108,33 @@ func (c *Context) LogErrorByCode(err *model.AppError) {
}
func (c *Context) IsSystemAdmin() bool {
return c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM)
return c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_MANAGE_SYSTEM)
}
func (c *Context) SessionRequired() {
if !*c.App.Config().ServiceSettings.EnableUserAccessTokens &&
c.App.Session().Props[model.SESSION_PROP_TYPE] == model.SESSION_TYPE_USER_ACCESS_TOKEN &&
c.App.Session().Props[model.SESSION_PROP_IS_BOT] != model.SESSION_PROP_IS_BOT_VALUE {
c.AppContext.Session().Props[model.SESSION_PROP_TYPE] == model.SESSION_TYPE_USER_ACCESS_TOKEN &&
c.AppContext.Session().Props[model.SESSION_PROP_IS_BOT] != model.SESSION_PROP_IS_BOT_VALUE {
c.Err = model.NewAppError("", "api.context.session_expired.app_error", nil, "UserAccessToken", http.StatusUnauthorized)
return
}
if c.App.Session().UserId == "" {
if c.AppContext.Session().UserId == "" {
c.Err = model.NewAppError("", "api.context.session_expired.app_error", nil, "UserRequired", http.StatusUnauthorized)
return
}
}
func (c *Context) CloudKeyRequired() {
if license := c.App.Srv().License(); license == nil || !*license.Features.Cloud || c.App.Session().Props[model.SESSION_PROP_TYPE] != model.SESSION_TYPE_CLOUD_KEY {
if license := c.App.Srv().License(); license == nil || !*license.Features.Cloud || c.AppContext.Session().Props[model.SESSION_PROP_TYPE] != model.SESSION_TYPE_CLOUD_KEY {
c.Err = model.NewAppError("", "api.context.session_expired.app_error", nil, "TokenRequired", http.StatusUnauthorized)
return
}
}
func (c *Context) RemoteClusterTokenRequired() {
if license := c.App.Srv().License(); license == nil || !*license.Features.RemoteClusterService || c.App.Session().Props[model.SESSION_PROP_TYPE] != model.SESSION_TYPE_REMOTECLUSTER_TOKEN {
if license := c.App.Srv().License(); license == nil || !*license.Features.RemoteClusterService || c.AppContext.Session().Props[model.SESSION_PROP_TYPE] != model.SESSION_TYPE_REMOTECLUSTER_TOKEN {
c.Err = model.NewAppError("", "api.context.session_expired.app_error", nil, "TokenRequired", http.StatusUnauthorized)
return
}
@@ -145,11 +147,11 @@ func (c *Context) MfaRequired() {
}
// OAuth integrations are excepted
if c.App.Session().IsOAuth {
if c.AppContext.Session().IsOAuth {
return
}
user, err := c.App.GetUser(c.App.Session().UserId)
user, err := c.App.GetUser(c.AppContext.Session().UserId)
if err != nil {
c.Err = model.NewAppError("MfaRequired", "api.context.get_user.app_error", nil, err.Error(), http.StatusUnauthorized)
return
@@ -167,7 +169,7 @@ func (c *Context) MfaRequired() {
// Special case to let user get themself
subpath, _ := utils.GetSubpathFromConfig(c.App.Config())
if c.App.Path() == path.Join(subpath, "/api/v4/users/me") {
if c.AppContext.Path() == path.Join(subpath, "/api/v4/users/me") {
return
}
@@ -185,8 +187,8 @@ func (c *Context) MfaRequired() {
// ExtendSessionExpiryIfNeeded will update Session.ExpiresAt based on session lengths in config.
// Session cookies will be resent to the client with updated max age.
func (c *Context) ExtendSessionExpiryIfNeeded(w http.ResponseWriter, r *http.Request) {
if ok := c.App.ExtendSessionExpiryIfNeeded(c.App.Session()); ok {
c.App.AttachSessionCookies(w, r)
if ok := c.App.ExtendSessionExpiryIfNeeded(c.AppContext.Session()); ok {
c.App.AttachSessionCookies(c.AppContext, w, r)
}
}
@@ -281,7 +283,7 @@ func NewJSONEncodingError() *model.AppError {
}
func (c *Context) SetPermissionError(permissions ...*model.Permission) {
c.Err = c.App.MakePermissionError(permissions)
c.Err = c.App.MakePermissionError(c.AppContext.Session(), permissions)
}
func (c *Context) SetSiteURLHeader(url string) {
@@ -298,7 +300,7 @@ func (c *Context) RequireUserId() *Context {
}
if c.Params.UserId == model.ME {
c.Params.UserId = c.App.Session().UserId
c.Params.UserId = c.AppContext.Session().UserId
}
if !model.IsValidId(c.Params.UserId) {

Просмотреть файл

@@ -11,6 +11,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/mattermost/mattermost-server/v5/app/request"
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/plugin/plugintest/mock"
"github.com/mattermost/mattermost-server/v5/store/storetest/mocks"
@@ -41,7 +42,8 @@ func TestCloudKeyRequired(t *testing.T) {
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
c := &Context{
App: th.App,
App: th.App,
AppContext: &request.Context{},
}
c.CloudKeyRequired()
@@ -69,7 +71,7 @@ func TestMfaRequired(t *testing.T) {
th.App.Srv().SetLicense(model.NewTestLicense("mfa"))
th.App.SetSession(&model.Session{Id: "abc", UserId: "userid"})
th.Context.SetSession(&model.Session{Id: "abc", UserId: "userid"})
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.AnnouncementSettings.UserNoticesEnabled = false
@@ -79,7 +81,8 @@ func TestMfaRequired(t *testing.T) {
})
c := &Context{
App: th.App,
App: th.App,
AppContext: th.Context,
}
c.MfaRequired()

Просмотреть файл

@@ -21,6 +21,7 @@ import (
"github.com/mattermost/mattermost-server/v5/app"
app_opentracing "github.com/mattermost/mattermost-server/v5/app/opentracing"
"github.com/mattermost/mattermost-server/v5/app/request"
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/services/tracing"
"github.com/mattermost/mattermost-server/v5/shared/i18n"
@@ -40,37 +41,37 @@ func GetHandlerName(h func(*Context, http.ResponseWriter, *http.Request)) string
func (w *Web) NewHandler(h func(*Context, http.ResponseWriter, *http.Request)) http.Handler {
return &Handler{
GetGlobalAppOptions: w.GetGlobalAppOptions,
HandleFunc: h,
HandlerName: GetHandlerName(h),
RequireSession: false,
TrustRequester: false,
RequireMfa: false,
IsStatic: false,
IsLocal: false,
App: w.app,
HandleFunc: h,
HandlerName: GetHandlerName(h),
RequireSession: false,
TrustRequester: false,
RequireMfa: false,
IsStatic: false,
IsLocal: false,
}
}
func (w *Web) NewStaticHandler(h func(*Context, http.ResponseWriter, *http.Request)) http.Handler {
// Determine the CSP SHA directive needed for subpath support, if any. This value is fixed
// on server start and intentionally requires a restart to take effect.
subpath, _ := utils.GetSubpathFromConfig(w.ConfigService.Config())
subpath, _ := utils.GetSubpathFromConfig(w.app.Config())
return &Handler{
GetGlobalAppOptions: w.GetGlobalAppOptions,
HandleFunc: h,
HandlerName: GetHandlerName(h),
RequireSession: false,
TrustRequester: false,
RequireMfa: false,
IsStatic: true,
App: w.app,
HandleFunc: h,
HandlerName: GetHandlerName(h),
RequireSession: false,
TrustRequester: false,
RequireMfa: false,
IsStatic: true,
cspShaDirective: utils.GetSubpathScriptHash(subpath),
}
}
type Handler struct {
GetGlobalAppOptions app.AppOptionCreator
App app.AppIface
HandleFunc func(*Context, http.ResponseWriter, *http.Request)
HandlerName string
RequireSession bool
@@ -104,19 +105,18 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
mlog.Debug("Received HTTP request", responseLogFields...)
}()
c := &Context{}
c.App = app.New(
h.GetGlobalAppOptions()...,
)
c.App.InitServer()
c := &Context{
AppContext: &request.Context{},
App: h.App,
}
t, _ := i18n.GetTranslationsAndLocaleFromRequest(r)
c.App.SetT(t)
c.App.SetRequestId(requestID)
c.App.SetIpAddress(utils.GetIPAddress(r, c.App.Config().ServiceSettings.TrustedProxyIPHeader))
c.App.SetUserAgent(r.UserAgent())
c.App.SetAcceptLanguage(r.Header.Get("Accept-Language"))
c.App.SetPath(r.URL.Path)
c.AppContext.SetT(t)
c.AppContext.SetRequestId(requestID)
c.AppContext.SetIpAddress(utils.GetIPAddress(r, c.App.Config().ServiceSettings.TrustedProxyIPHeader))
c.AppContext.SetUserAgent(r.UserAgent())
c.AppContext.SetAcceptLanguage(r.Header.Get("Accept-Language"))
c.AppContext.SetPath(r.URL.Path)
c.Params = ParamsFromRequest(r)
c.Logger = c.App.Log()
@@ -125,10 +125,10 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
carrier := opentracing.HTTPHeadersCarrier(r.Header)
_ = opentracing.GlobalTracer().Inject(span.Context(), opentracing.HTTPHeaders, carrier)
ext.HTTPMethod.Set(span, r.Method)
ext.HTTPUrl.Set(span, c.App.Path())
ext.PeerAddress.Set(span, c.App.IpAddress())
span.SetTag("request_id", c.App.RequestId())
span.SetTag("user_agent", c.App.UserAgent())
ext.HTTPUrl.Set(span, c.AppContext.Path())
ext.PeerAddress.Set(span, c.AppContext.IpAddress())
span.SetTag("request_id", c.AppContext.RequestId())
span.SetTag("user_agent", c.AppContext.UserAgent())
defer func() {
if c.Err != nil {
@@ -138,7 +138,7 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
span.Finish()
}()
c.App.SetContext(ctx)
c.AppContext.SetContext(ctx)
tmpSrv := *c.App.Srv()
tmpSrv.Store = opentracinglayer.New(c.App.Srv().Store, ctx)
@@ -158,7 +158,7 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
siteURLHeader := app.GetProtocol(r) + "://" + r.Host + subpath
c.SetSiteURLHeader(siteURLHeader)
w.Header().Set(model.HEADER_REQUEST_ID, c.App.RequestId())
w.Header().Set(model.HEADER_REQUEST_ID, c.AppContext.RequestId())
w.Header().Set(model.HEADER_VERSION_ID, fmt.Sprintf("%v.%v.%v.%v", model.CurrentVersion, model.BuildNumber, c.App.ClientConfigHash(), c.App.Srv().License() != nil))
if *c.App.Config().ServiceSettings.TLSStrictTransport {
@@ -219,11 +219,11 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
} else if !session.IsOAuth && tokenLocation == app.TokenLocationQueryString {
c.Err = model.NewAppError("ServeHTTP", "api.context.token_provided.app_error", nil, "token="+token, http.StatusUnauthorized)
} else {
c.App.SetSession(session)
c.AppContext.SetSession(session)
}
// Rate limit by UserID
if c.App.Srv().RateLimiter != nil && c.App.Srv().RateLimiter.UserIdRateLimit(c.App.Session().UserId, w) {
if c.App.Srv().RateLimiter != nil && c.App.Srv().RateLimiter.UserIdRateLimit(c.AppContext.Session().UserId, w) {
return
}
@@ -235,7 +235,7 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
c.Logger.Warn("Invalid CWS token", mlog.Err(err))
c.Err = err
} else {
c.App.SetSession(session)
c.AppContext.SetSession(session)
}
} else if token != "" && c.App.Srv().License() != nil && *c.App.Srv().License().Features.RemoteClusterService && tokenLocation == app.TokenLocationRemoteClusterHeader {
// Get the remote cluster
@@ -249,16 +249,16 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
c.Logger.Warn("Invalid remote cluster token", mlog.Err(err))
c.Err = err
} else {
c.App.SetSession(session)
c.AppContext.SetSession(session)
}
}
}
c.Logger = c.App.Log().With(
mlog.String("path", c.App.Path()),
mlog.String("request_id", c.App.RequestId()),
mlog.String("ip_addr", c.App.IpAddress()),
mlog.String("user_id", c.App.Session().UserId),
mlog.String("path", c.AppContext.Path()),
mlog.String("request_id", c.AppContext.RequestId()),
mlog.String("ip_addr", c.AppContext.IpAddress()),
mlog.String("user_id", c.AppContext.Session().UserId),
mlog.String("method", r.Method),
)
@@ -287,7 +287,7 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// shape IP:PORT (it will be "@" in Linux, for example)
isLocalOrigin := !strings.Contains(r.RemoteAddr, ":")
if *c.App.Config().ServiceSettings.EnableLocalMode && isLocalOrigin {
c.App.SetSession(&model.Session{Local: true})
c.AppContext.SetSession(&model.Session{Local: true})
} else if !isLocalOrigin {
c.Err = model.NewAppError("", "api.context.local_origin_required.app_error", nil, "LocalOriginRequired", http.StatusUnauthorized)
}
@@ -299,8 +299,8 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Handle errors that have occurred
if c.Err != nil {
c.Err.Translate(c.App.T)
c.Err.RequestId = c.App.RequestId()
c.Err.Translate(c.AppContext.T)
c.Err.RequestId = c.AppContext.RequestId()
c.LogErrorByCode(c.Err)
c.Err.Where = r.URL.Path
@@ -382,7 +382,7 @@ func (h *Handler) checkCSRFToken(c *Context, r *http.Request, token string, toke
}
if !csrfCheckPassed {
c.App.SetSession(&model.Session{})
c.AppContext.SetSession(&model.Session{})
c.Err = model.NewAppError("ServeHTTP", "api.context.session_expired.app_error", nil, "token="+token+" Appears to be a CSRF attempt", http.StatusUnauthorized)
}
}
@@ -394,16 +394,16 @@ func (h *Handler) checkCSRFToken(c *Context, r *http.Request, token string, toke
// granted.
func (w *Web) ApiHandler(h func(*Context, http.ResponseWriter, *http.Request)) http.Handler {
handler := &Handler{
GetGlobalAppOptions: w.GetGlobalAppOptions,
HandleFunc: h,
HandlerName: GetHandlerName(h),
RequireSession: false,
TrustRequester: false,
RequireMfa: false,
IsStatic: false,
IsLocal: false,
App: w.app,
HandleFunc: h,
HandlerName: GetHandlerName(h),
RequireSession: false,
TrustRequester: false,
RequireMfa: false,
IsStatic: false,
IsLocal: false,
}
if *w.ConfigService.Config().ServiceSettings.WebserverMode == "gzip" {
if *w.app.Config().ServiceSettings.WebserverMode == "gzip" {
return gziphandler.GzipHandler(handler)
}
return handler
@@ -414,16 +414,16 @@ func (w *Web) ApiHandler(h func(*Context, http.ResponseWriter, *http.Request)) h
// websocket.
func (w *Web) ApiHandlerTrustRequester(h func(*Context, http.ResponseWriter, *http.Request)) http.Handler {
handler := &Handler{
GetGlobalAppOptions: w.GetGlobalAppOptions,
HandleFunc: h,
HandlerName: GetHandlerName(h),
RequireSession: false,
TrustRequester: true,
RequireMfa: false,
IsStatic: false,
IsLocal: false,
App: w.app,
HandleFunc: h,
HandlerName: GetHandlerName(h),
RequireSession: false,
TrustRequester: true,
RequireMfa: false,
IsStatic: false,
IsLocal: false,
}
if *w.ConfigService.Config().ServiceSettings.WebserverMode == "gzip" {
if *w.app.Config().ServiceSettings.WebserverMode == "gzip" {
return gziphandler.GzipHandler(handler)
}
return handler
@@ -433,16 +433,16 @@ func (w *Web) ApiHandlerTrustRequester(h func(*Context, http.ResponseWriter, *ht
// be granted.
func (w *Web) ApiSessionRequired(h func(*Context, http.ResponseWriter, *http.Request)) http.Handler {
handler := &Handler{
GetGlobalAppOptions: w.GetGlobalAppOptions,
HandleFunc: h,
HandlerName: GetHandlerName(h),
RequireSession: true,
TrustRequester: false,
RequireMfa: true,
IsStatic: false,
IsLocal: false,
App: w.app,
HandleFunc: h,
HandlerName: GetHandlerName(h),
RequireSession: true,
TrustRequester: false,
RequireMfa: true,
IsStatic: false,
IsLocal: false,
}
if *w.ConfigService.Config().ServiceSettings.WebserverMode == "gzip" {
if *w.app.Config().ServiceSettings.WebserverMode == "gzip" {
return gziphandler.GzipHandler(handler)
}
return handler

Просмотреть файл

@@ -25,7 +25,7 @@ func TestHandlerServeHTTPErrors(t *testing.T) {
th := SetupWithStoreMock(t)
defer th.TearDown()
web := New(th.Server, th.Server.AppOptions, th.Server.Router)
web := New(th.App, th.Server.Router)
handler := web.NewHandler(handlerForHTTPErrors)
var flagtests = []struct {
@@ -84,7 +84,7 @@ func TestHandlerServeHTTPSecureTransport(t *testing.T) {
*config.ServiceSettings.TLSStrictTransportMaxAge = 6000
})
web := New(th.Server, th.Server.AppOptions, th.Server.Router)
web := New(th.App, th.Server.Router)
handler := web.NewHandler(handlerForHTTPSecureTransport)
request := httptest.NewRequest("GET", "/api/v4/test", nil)
@@ -136,15 +136,15 @@ func TestHandlerServeCSRFToken(t *testing.T) {
t.Errorf("Expected nil, got %s", err)
}
web := New(th.Server, th.Server.AppOptions, th.Server.Router)
web := New(th.App, th.Server.Router)
handler := Handler{
GetGlobalAppOptions: web.GetGlobalAppOptions,
HandleFunc: handlerForCSRFToken,
RequireSession: true,
TrustRequester: false,
RequireMfa: false,
IsStatic: false,
App: web.app,
HandleFunc: handlerForCSRFToken,
RequireSession: true,
TrustRequester: false,
RequireMfa: false,
IsStatic: false,
}
cookie := &http.Cookie{
@@ -219,12 +219,12 @@ func TestHandlerServeCSRFToken(t *testing.T) {
// Handler with RequireSession set to false
handlerNoSession := Handler{
GetGlobalAppOptions: web.GetGlobalAppOptions,
HandleFunc: handlerForCSRFToken,
RequireSession: false,
TrustRequester: false,
RequireMfa: false,
IsStatic: false,
App: th.App,
HandleFunc: handlerForCSRFToken,
RequireSession: false,
TrustRequester: false,
RequireMfa: false,
IsStatic: false,
}
// CSRF Token Used - Success Expected
@@ -263,15 +263,15 @@ func TestHandlerServeCSPHeader(t *testing.T) {
th := SetupWithStoreMock(t)
defer th.TearDown()
web := New(th.Server, th.Server.AppOptions, th.Server.Router)
web := New(th.App, th.Server.Router)
handler := Handler{
GetGlobalAppOptions: web.GetGlobalAppOptions,
HandleFunc: handlerForCSPHeader,
RequireSession: false,
TrustRequester: false,
RequireMfa: false,
IsStatic: false,
App: web.app,
HandleFunc: handlerForCSPHeader,
RequireSession: false,
TrustRequester: false,
RequireMfa: false,
IsStatic: false,
}
request := httptest.NewRequest("POST", "/api/v4/test", nil)
@@ -285,15 +285,15 @@ func TestHandlerServeCSPHeader(t *testing.T) {
th := SetupWithStoreMock(t)
defer th.TearDown()
web := New(th.Server, th.Server.AppOptions, th.Server.Router)
web := New(th.App, th.Server.Router)
handler := Handler{
GetGlobalAppOptions: web.GetGlobalAppOptions,
HandleFunc: handlerForCSPHeader,
RequireSession: false,
TrustRequester: false,
RequireMfa: false,
IsStatic: true,
App: web.app,
HandleFunc: handlerForCSPHeader,
RequireSession: false,
TrustRequester: false,
RequireMfa: false,
IsStatic: true,
}
request := httptest.NewRequest("POST", "/", nil)
@@ -325,15 +325,15 @@ func TestHandlerServeCSPHeader(t *testing.T) {
*cfg.ServiceSettings.SiteURL = *cfg.ServiceSettings.SiteURL + "/subpath"
})
web := New(th.Server, th.Server.AppOptions, th.Server.Router)
web := New(th.App, th.Server.Router)
handler := Handler{
GetGlobalAppOptions: web.GetGlobalAppOptions,
HandleFunc: handlerForCSPHeader,
RequireSession: false,
TrustRequester: false,
RequireMfa: false,
IsStatic: true,
App: web.app,
HandleFunc: handlerForCSPHeader,
RequireSession: false,
TrustRequester: false,
RequireMfa: false,
IsStatic: true,
}
request := httptest.NewRequest("POST", "/", nil)
@@ -380,15 +380,15 @@ func TestHandlerServeInvalidToken(t *testing.T) {
*cfg.ServiceSettings.SiteURL = tc.SiteURL
})
web := New(th.Server, th.Server.AppOptions, th.Server.Router)
web := New(th.App, th.Server.Router)
handler := Handler{
GetGlobalAppOptions: web.GetGlobalAppOptions,
HandleFunc: handlerForCSRFToken,
RequireSession: true,
TrustRequester: false,
RequireMfa: false,
IsStatic: false,
App: web.app,
HandleFunc: handlerForCSRFToken,
RequireSession: true,
TrustRequester: false,
RequireMfa: false,
IsStatic: false,
}
cookie := &http.Cookie{
@@ -422,7 +422,8 @@ func TestCheckCSRFToken(t *testing.T) {
tokenLocation := app.TokenLocationCookie
c := &Context{
App: th.App,
App: th.App,
AppContext: th.Context,
}
r, _ := http.NewRequest(http.MethodPost, "", nil)
r.Header.Set(model.HEADER_CSRF_TOKEN, token)
@@ -452,8 +453,9 @@ func TestCheckCSRFToken(t *testing.T) {
tokenLocation := app.TokenLocationCookie
c := &Context{
App: th.App,
Logger: th.App.Log(),
App: th.App,
Logger: th.App.Log(),
AppContext: th.Context,
}
r, _ := http.NewRequest(http.MethodPost, "", nil)
r.Header.Set(model.HEADER_REQUESTED_WITH, model.HEADER_REQUESTED_WITH_XML)
@@ -501,8 +503,9 @@ func TestCheckCSRFToken(t *testing.T) {
tokenLocation := app.TokenLocationCookie
c := &Context{
App: th.App,
Logger: th.App.Log(),
App: th.App,
Logger: th.App.Log(),
AppContext: th.Context,
}
r, _ := http.NewRequest(http.MethodPost, "", nil)
r.Header.Set(model.HEADER_REQUESTED_WITH, model.HEADER_REQUESTED_WITH_XML)
@@ -532,7 +535,8 @@ func TestCheckCSRFToken(t *testing.T) {
tokenLocation := app.TokenLocationCookie
c := &Context{
App: th.App,
App: th.App,
AppContext: th.Context,
}
r, _ := http.NewRequest(http.MethodPost, "", nil)
session := &model.Session{
@@ -561,7 +565,8 @@ func TestCheckCSRFToken(t *testing.T) {
tokenLocation := app.TokenLocationCookie
c := &Context{
App: th.App,
App: th.App,
AppContext: th.Context,
}
r, _ := http.NewRequest(http.MethodGet, "", nil)
session := &model.Session{
@@ -590,7 +595,8 @@ func TestCheckCSRFToken(t *testing.T) {
tokenLocation := app.TokenLocationHeader
c := &Context{
App: th.App,
App: th.App,
AppContext: th.Context,
}
r, _ := http.NewRequest(http.MethodPost, "", nil)
session := &model.Session{
@@ -619,7 +625,8 @@ func TestCheckCSRFToken(t *testing.T) {
tokenLocation := app.TokenLocationCookie
c := &Context{
App: th.App,
App: th.App,
AppContext: th.Context,
}
r, _ := http.NewRequest(http.MethodPost, "", nil)
r.Header.Set(model.HEADER_CSRF_TOKEN, token)
@@ -644,7 +651,8 @@ func TestCheckCSRFToken(t *testing.T) {
tokenLocation := app.TokenLocationCookie
c := &Context{
App: th.App,
App: th.App,
AppContext: th.Context,
}
r, _ := http.NewRequest(http.MethodPost, "", nil)
r.Header.Set(model.HEADER_CSRF_TOKEN, token)

Просмотреть файл

@@ -54,7 +54,7 @@ func authorizeOAuthApp(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
if c.App.Session().IsOAuth {
if c.AppContext.Session().IsOAuth {
c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
c.Err.DetailedError += ", attempted access by oauth app"
return
@@ -64,7 +64,7 @@ func authorizeOAuthApp(c *Context, w http.ResponseWriter, r *http.Request) {
defer c.LogAuditRec(auditRec)
c.LogAudit("attempt")
redirectUrl, err := c.App.AllowOAuthAppAccessToUser(c.App.Session().UserId, authRequest)
redirectUrl, err := c.App.AllowOAuthAppAccessToUser(c.AppContext.Session().UserId, authRequest)
if err != nil {
c.Err = err
@@ -89,7 +89,7 @@ func deauthorizeOAuthApp(c *Context, w http.ResponseWriter, r *http.Request) {
auditRec := c.MakeAuditRecord("deauthorizeOAuthApp", audit.Fail)
defer c.LogAuditRec(auditRec)
err := c.App.DeauthorizeOAuthAppForUser(c.App.Session().UserId, clientId)
err := c.App.DeauthorizeOAuthAppForUser(c.AppContext.Session().UserId, clientId)
if err != nil {
c.Err = err
return
@@ -134,7 +134,7 @@ func authorizeOAuthPage(c *Context, w http.ResponseWriter, r *http.Request) {
}
// here we should check if the user is logged in
if c.App.Session().UserId == "" {
if c.AppContext.Session().UserId == "" {
if loginHint == model.USER_AUTH_SERVICE_SAML {
http.Redirect(w, r, c.GetSiteURLHeader()+"/login/sso/saml?redirect_to="+url.QueryEscape(r.RequestURI), http.StatusFound)
} else {
@@ -155,14 +155,14 @@ func authorizeOAuthPage(c *Context, w http.ResponseWriter, r *http.Request) {
isAuthorized := false
if _, err := c.App.GetPreferenceByCategoryAndNameForUser(c.App.Session().UserId, model.PREFERENCE_CATEGORY_AUTHORIZED_OAUTH_APP, authRequest.ClientId); err == nil {
if _, err := c.App.GetPreferenceByCategoryAndNameForUser(c.AppContext.Session().UserId, model.PREFERENCE_CATEGORY_AUTHORIZED_OAUTH_APP, authRequest.ClientId); err == nil {
// when we support scopes we should check if the scopes match
isAuthorized = true
}
// Automatically allow if the app is trusted
if oauthApp.IsTrusted || isAuthorized {
redirectUrl, err := c.App.AllowOAuthAppAccessToUser(c.App.Session().UserId, authRequest)
redirectUrl, err := c.App.AllowOAuthAppAccessToUser(c.AppContext.Session().UserId, authRequest)
if err != nil {
utils.RenderWebAppError(c.App.Config(), w, r, err, c.App.AsymmetricSigningKey())
@@ -295,15 +295,15 @@ func completeOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
}
if err != nil {
err.Translate(c.App.T)
err.Translate(c.AppContext.T)
c.LogErrorByCode(err)
renderError(err)
return
}
user, err := c.App.CompleteOAuth(service, body, teamId, props, tokenUser)
user, err := c.App.CompleteOAuth(c.AppContext, service, body, teamId, props, tokenUser)
if err != nil {
err.Translate(c.App.T)
err.Translate(c.AppContext.T)
c.LogErrorByCode(err)
renderError(err)
return
@@ -314,9 +314,9 @@ func completeOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
} else if action == model.OAUTH_ACTION_SSO_TO_EMAIL {
redirectURL = app.GetProtocol(r) + "://" + r.Host + "/claim?email=" + url.QueryEscape(props["email"])
} else {
err = c.App.DoLogin(w, r, user, "", isMobile, false, false)
err = c.App.DoLogin(c.AppContext, w, r, user, "", isMobile, false, false)
if err != nil {
err.Translate(c.App.T)
err.Translate(c.AppContext.T)
mlog.Error(err.Error())
renderError(err)
return
@@ -324,19 +324,19 @@ func completeOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
// Old mobile version
if isMobile && !hasRedirectURL {
c.App.AttachSessionCookies(w, r)
c.App.AttachSessionCookies(c.AppContext, w, r)
return
} else
// New mobile version
if isMobile && hasRedirectURL {
redirectURL = utils.AppendQueryParamsToURL(redirectURL, map[string]string{
model.SESSION_COOKIE_TOKEN: c.App.Session().Token,
model.SESSION_COOKIE_CSRF: c.App.Session().GetCSRF(),
model.SESSION_COOKIE_TOKEN: c.AppContext.Session().Token,
model.SESSION_COOKIE_CSRF: c.AppContext.Session().GetCSRF(),
})
utils.RenderMobileAuthComplete(w, redirectURL)
return
} else { // For web
c.App.AttachSessionCookies(w, r)
c.App.AttachSessionCookies(c.AppContext, w, r)
// If no redirect url is passed, get the default one
if !hasRedirectURL {

Просмотреть файл

@@ -18,6 +18,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/mattermost/mattermost-server/v5/app/request"
"github.com/mattermost/mattermost-server/v5/einterfaces"
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/shared/i18n"
@@ -530,14 +531,15 @@ func TestOAuthComplete_ErrorMessages(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
c := &Context{
App: th.App,
App: th.App,
AppContext: &request.Context{},
Params: &Params{
Service: "gitlab",
},
}
translationFunc := i18n.GetUserTranslations("en")
c.App.SetT(translationFunc)
c.AppContext.SetT(translationFunc)
buffer := &bytes.Buffer{}
c.Logger = mlog.NewTestingLogger(t, buffer)
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GitLabSettings.Enable = true })

Просмотреть файл

@@ -112,7 +112,7 @@ func completeSaml(c *Context, w http.ResponseWriter, r *http.Request) {
handleError := func(err *model.AppError) {
if isMobile && hasRedirectURL {
err.Translate(c.App.T)
err.Translate(c.AppContext.T)
utils.RenderMobileError(c.App.Config(), w, err, redirectURL)
} else {
c.Err = err
@@ -120,7 +120,7 @@ func completeSaml(c *Context, w http.ResponseWriter, r *http.Request) {
}
}
user, err := samlInterface.DoLogin(encodedXML, relayProps)
user, err := samlInterface.DoLogin(c.AppContext, encodedXML, relayProps)
if err != nil {
c.LogAudit("fail")
mlog.Error(err.Error())
@@ -137,7 +137,7 @@ func completeSaml(c *Context, w http.ResponseWriter, r *http.Request) {
switch action {
case model.OAUTH_ACTION_SIGNUP:
if teamId := relayProps["team_id"]; teamId != "" {
if err = c.App.AddUserToTeamByTeamId(teamId, user); err != nil {
if err = c.App.AddUserToTeamByTeamId(c.AppContext, teamId, user); err != nil {
c.LogErrorByCode(err)
break
}
@@ -162,7 +162,7 @@ func completeSaml(c *Context, w http.ResponseWriter, r *http.Request) {
auditRec.AddMeta("obtained_user_id", user.Id)
c.LogAuditWithUserId(user.Id, "obtained user")
err = c.App.DoLogin(w, r, user, "", isMobile, false, true)
err = c.App.DoLogin(c.AppContext, w, r, user, "", isMobile, false, true)
if err != nil {
mlog.Error(err.Error())
handleError(err)
@@ -172,14 +172,14 @@ func completeSaml(c *Context, w http.ResponseWriter, r *http.Request) {
auditRec.Success()
c.LogAuditWithUserId(user.Id, "success")
c.App.AttachSessionCookies(w, r)
c.App.AttachSessionCookies(c.AppContext, w, r)
if hasRedirectURL {
if isMobile {
// Mobile clients with redirect url support
redirectURL = utils.AppendQueryParamsToURL(redirectURL, map[string]string{
model.SESSION_COOKIE_TOKEN: c.App.Session().Token,
model.SESSION_COOKIE_CSRF: c.App.Session().GetCSRF(),
model.SESSION_COOKIE_TOKEN: c.AppContext.Session().Token,
model.SESSION_COOKIE_CSRF: c.AppContext.Session().GetCSRF(),
})
utils.RenderMobileAuthComplete(w, redirectURL)
} else {

Просмотреть файл

@@ -21,20 +21,20 @@ import (
var robotsTxt = []byte("User-agent: *\nDisallow: /\n")
func (w *Web) InitStatic() {
if *w.ConfigService.Config().ServiceSettings.WebserverMode != "disabled" {
if err := utils.UpdateAssetsSubpathFromConfig(w.ConfigService.Config()); err != nil {
if *w.app.Config().ServiceSettings.WebserverMode != "disabled" {
if err := utils.UpdateAssetsSubpathFromConfig(w.app.Config()); err != nil {
mlog.Error("Failed to update assets subpath from config", mlog.Err(err))
}
staticDir, _ := fileutils.FindDir(model.CLIENT_DIR)
mlog.Debug("Using client directory", mlog.String("clientDir", staticDir))
subpath, _ := utils.GetSubpathFromConfig(w.ConfigService.Config())
subpath, _ := utils.GetSubpathFromConfig(w.app.Config())
staticHandler := staticFilesHandler(http.StripPrefix(path.Join(subpath, "static"), http.FileServer(http.Dir(staticDir))))
pluginHandler := staticFilesHandler(http.StripPrefix(path.Join(subpath, "static", "plugins"), http.FileServer(http.Dir(*w.ConfigService.Config().PluginSettings.ClientDirectory))))
pluginHandler := staticFilesHandler(http.StripPrefix(path.Join(subpath, "static", "plugins"), http.FileServer(http.Dir(*w.app.Config().PluginSettings.ClientDirectory))))
if *w.ConfigService.Config().ServiceSettings.WebserverMode == "gzip" {
if *w.app.Config().ServiceSettings.WebserverMode == "gzip" {
staticHandler = gziphandler.GzipHandler(staticHandler)
pluginHandler = gziphandler.GzipHandler(pluginHandler)
}
@@ -58,7 +58,10 @@ func (w *Web) InitStatic() {
func root(c *Context, w http.ResponseWriter, r *http.Request) {
if !CheckClientCompatibility(r.UserAgent()) {
renderUnsupportedBrowser(c.App, w, r)
w.Header().Set("Cache-Control", "no-store")
data := renderUnsupportedBrowser(c.AppContext, r)
c.App.Srv().TemplatesContainer().Render(w, "unsupported_browser", data)
return
}

Просмотреть файл

@@ -8,7 +8,7 @@ import (
"github.com/avct/uasurfer"
"github.com/mattermost/mattermost-server/v5/app"
"github.com/mattermost/mattermost-server/v5/app/request"
"github.com/mattermost/mattermost-server/v5/shared/templates"
)
@@ -44,13 +44,12 @@ type SystemBrowser struct {
MakeDefaultString string
}
func renderUnsupportedBrowser(app app.AppIface, w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "no-store")
func renderUnsupportedBrowser(ctx *request.Context, r *http.Request) templates.Data {
data := templates.Data{
Props: map[string]interface{}{
"DownloadAppOrUpgradeBrowserString": app.T("web.error.unsupported_browser.download_app_or_upgrade_browser"),
"LearnMoreString": app.T("web.error.unsupported_browser.learn_more"),
"DownloadAppOrUpgradeBrowserString": ctx.T("web.error.unsupported_browser.download_app_or_upgrade_browser"),
"LearnMoreString": ctx.T("web.error.unsupported_browser.learn_more"),
},
}
@@ -63,98 +62,99 @@ func renderUnsupportedBrowser(app app.AppIface, w http.ResponseWriter, r *http.R
// Basic heading translations
if isSafari {
data.Props["NoLongerSupportString"] = app.T("web.error.unsupported_browser.no_longer_support_version")
data.Props["NoLongerSupportString"] = ctx.T("web.error.unsupported_browser.no_longer_support_version")
} else {
data.Props["NoLongerSupportString"] = app.T("web.error.unsupported_browser.no_longer_support")
data.Props["NoLongerSupportString"] = ctx.T("web.error.unsupported_browser.no_longer_support")
}
// Mattermost app version
if isWindows {
data.Props["App"] = renderMattermostAppWindows(app)
data.Props["App"] = renderMattermostAppWindows(ctx)
} else if isMacOSX {
data.Props["App"] = renderMattermostAppMac(app)
data.Props["App"] = renderMattermostAppMac(ctx)
}
// Browsers to download
// Show a link to Safari if you're using safari and it's outdated
// Can't show on Mac all the time because there's no way to open it via URI
browsers := []Browser{renderBrowserChrome(app), renderBrowserFirefox(app)}
browsers := []Browser{renderBrowserChrome(ctx), renderBrowserFirefox(ctx)}
if isSafari {
browsers = append(browsers, renderBrowserSafari(app))
browsers = append(browsers, renderBrowserSafari(ctx))
}
data.Props["Browsers"] = browsers
// If on Windows 10, show link to Edge
if isWindows10 {
data.Props["SystemBrowser"] = renderSystemBrowserEdge(app, r)
data.Props["SystemBrowser"] = renderSystemBrowserEdge(ctx, r)
}
app.Srv().TemplatesContainer().Render(w, "unsupported_browser", data)
return data
}
func renderMattermostAppMac(app app.AppIface) MattermostApp {
func renderMattermostAppMac(ctx *request.Context) MattermostApp {
return MattermostApp{
"/static/images/browser-icons/mac.png",
app.T("web.error.unsupported_browser.download_the_app"),
app.T("web.error.unsupported_browser.min_os_version.mac"),
app.T("web.error.unsupported_browser.download"),
ctx.T("web.error.unsupported_browser.download_the_app"),
ctx.T("web.error.unsupported_browser.min_os_version.mac"),
ctx.T("web.error.unsupported_browser.download"),
"https://mattermost.com/download/#mattermostApps",
app.T("web.error.unsupported_browser.install_guide.mac"),
ctx.T("web.error.unsupported_browser.install_guide.mac"),
"https://docs.mattermost.com/install/desktop.html#mac-os-x-10-9",
}
}
func renderMattermostAppWindows(app app.AppIface) MattermostApp {
func renderMattermostAppWindows(ctx *request.Context) MattermostApp {
return MattermostApp{
"/static/images/browser-icons/windows.svg",
app.T("web.error.unsupported_browser.download_the_app"),
app.T("web.error.unsupported_browser.min_os_version.windows"),
app.T("web.error.unsupported_browser.download"),
ctx.T("web.error.unsupported_browser.download_the_app"),
ctx.T("web.error.unsupported_browser.min_os_version.windows"),
ctx.T("web.error.unsupported_browser.download"),
"https://mattermost.com/download/#mattermostApps",
app.T("web.error.unsupported_browser.install_guide.windows"),
ctx.T("web.error.unsupported_browser.install_guide.windows"),
"https://docs.mattermost.com/install/desktop.html#windows-10-windows-8-1-windows-7",
}
}
func renderBrowserChrome(app app.AppIface) Browser {
func renderBrowserChrome(ctx *request.Context) Browser {
return Browser{
"/static/images/browser-icons/chrome.svg",
app.T("web.error.unsupported_browser.browser_title.chrome"),
app.T("web.error.unsupported_browser.min_browser_version.chrome"),
ctx.T("web.error.unsupported_browser.browser_title.chrome"),
ctx.T("web.error.unsupported_browser.min_browser_version.chrome"),
"http://www.google.com/chrome",
app.T("web.error.unsupported_browser.browser_get_latest.chrome"),
ctx.T("web.error.unsupported_browser.browser_get_latest.chrome"),
}
}
func renderBrowserFirefox(app app.AppIface) Browser {
func renderBrowserFirefox(ctx *request.Context) Browser {
return Browser{
"/static/images/browser-icons/firefox.svg",
app.T("web.error.unsupported_browser.browser_title.firefox"),
app.T("web.error.unsupported_browser.min_browser_version.firefox"),
ctx.T("web.error.unsupported_browser.browser_title.firefox"),
ctx.T("web.error.unsupported_browser.min_browser_version.firefox"),
"https://www.mozilla.org/firefox/new/",
app.T("web.error.unsupported_browser.browser_get_latest.firefox"),
ctx.T("web.error.unsupported_browser.browser_get_latest.firefox"),
}
}
func renderBrowserSafari(app app.AppIface) Browser {
func renderBrowserSafari(ctx *request.Context) Browser {
return Browser{
"/static/images/browser-icons/safari.svg",
app.T("web.error.unsupported_browser.browser_title.safari"),
app.T("web.error.unsupported_browser.min_browser_version.safari"),
ctx.T("web.error.unsupported_browser.browser_title.safari"),
ctx.T("web.error.unsupported_browser.min_browser_version.safari"),
"macappstore://showUpdatesPage",
app.T("web.error.unsupported_browser.browser_get_latest.safari"),
ctx.T("web.error.unsupported_browser.browser_get_latest.safari"),
}
}
func renderSystemBrowserEdge(app app.AppIface, r *http.Request) SystemBrowser {
func renderSystemBrowserEdge(ctx *request.Context, r *http.Request) SystemBrowser {
return SystemBrowser{
"/static/images/browser-icons/edge.svg",
app.T("web.error.unsupported_browser.browser_title.edge"),
app.T("web.error.unsupported_browser.min_browser_version.edge"),
app.T("web.error.unsupported_browser.open_system_browser.edge"),
ctx.T("web.error.unsupported_browser.browser_title.edge"),
ctx.T("web.error.unsupported_browser.min_browser_version.edge"),
ctx.T("web.error.unsupported_browser.open_system_browser.edge"),
"microsoft-edge:http://" + r.Host + r.RequestURI, //TODO: Can we get HTTP or HTTPS? If someone's server doesn't have a redirect this won't work
"ms-settings:defaultapps",
app.T("web.error.unsupported_browser.system_browser_or"),
app.T("web.error.unsupported_browser.system_browser_make_default"),
ctx.T("web.error.unsupported_browser.system_browser_or"),
ctx.T("web.error.unsupported_browser.system_browser_make_default"),
}
}

Просмотреть файл

@@ -13,24 +13,21 @@ import (
"github.com/mattermost/mattermost-server/v5/app"
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/services/configservice"
"github.com/mattermost/mattermost-server/v5/shared/mlog"
"github.com/mattermost/mattermost-server/v5/utils"
)
type Web struct {
GetGlobalAppOptions app.AppOptionCreator
ConfigService configservice.ConfigService
MainRouter *mux.Router
app app.AppIface
MainRouter *mux.Router
}
func New(config configservice.ConfigService, globalOptions app.AppOptionCreator, root *mux.Router) *Web {
func New(a app.AppIface, root *mux.Router) *Web {
mlog.Debug("Initializing web routes")
web := &Web{
GetGlobalAppOptions: globalOptions,
ConfigService: config,
MainRouter: root,
app: a,
MainRouter: root,
}
web.InitOAuth()
@@ -60,24 +57,24 @@ func CheckClientCompatibility(agentString string) bool {
return true
}
func Handle404(config configservice.ConfigService, w http.ResponseWriter, r *http.Request) {
func Handle404(a app.AppIface, w http.ResponseWriter, r *http.Request) {
err := model.NewAppError("Handle404", "api.context.404.app_error", nil, "", http.StatusNotFound)
ipAddress := utils.GetIPAddress(r, config.Config().ServiceSettings.TrustedProxyIPHeader)
ipAddress := utils.GetIPAddress(r, a.Config().ServiceSettings.TrustedProxyIPHeader)
mlog.Debug("not found handler triggered", mlog.String("path", r.URL.Path), mlog.Int("code", 404), mlog.String("ip", ipAddress))
if IsApiCall(config, r) {
if IsApiCall(a, r) {
w.WriteHeader(err.StatusCode)
err.DetailedError = "There doesn't appear to be an api call for the url='" + r.URL.Path + "'. Typo? are you missing a team_id or user_id as part of the url?"
w.Write([]byte(err.ToJson()))
} else if *config.Config().ServiceSettings.WebserverMode == "disabled" {
} else if *a.Config().ServiceSettings.WebserverMode == "disabled" {
http.NotFound(w, r)
} else {
utils.RenderWebAppError(config.Config(), w, r, err, config.AsymmetricSigningKey())
utils.RenderWebAppError(a.Config(), w, r, err, a.AsymmetricSigningKey())
}
}
func IsApiCall(config configservice.ConfigService, r *http.Request) bool {
subpath, _ := utils.GetSubpathFromConfig(config.Config())
func IsApiCall(a app.AppIface, r *http.Request) bool {
subpath, _ := utils.GetSubpathFromConfig(a.Config())
return strings.HasPrefix(r.URL.Path, path.Join(subpath, "api")+"/")
}
@@ -88,8 +85,8 @@ func IsWebhookCall(a app.AppIface, r *http.Request) bool {
return strings.HasPrefix(r.URL.Path, path.Join(subpath, "hooks")+"/")
}
func IsOAuthApiCall(config configservice.ConfigService, r *http.Request) bool {
subpath, _ := utils.GetSubpathFromConfig(config.Config())
func IsOAuthApiCall(a app.AppIface, r *http.Request) bool {
subpath, _ := utils.GetSubpathFromConfig(a.Config())
if r.Method == "POST" && r.URL.Path == path.Join(subpath, "oauth", "authorize") {
return true

Просмотреть файл

@@ -17,6 +17,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/mattermost/mattermost-server/v5/app"
"github.com/mattermost/mattermost-server/v5/app/request"
"github.com/mattermost/mattermost-server/v5/config"
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/plugin"
@@ -30,9 +31,10 @@ var ApiClient *model.Client4
var URL string
type TestHelper struct {
App app.AppIface
Server *app.Server
Web *Web
App app.AppIface
Context *request.Context
Server *app.Server
Web *Web
BasicUser *model.User
BasicChannel *model.Channel
@@ -108,10 +110,10 @@ func setupTestHelper(includeCacheLayer bool) *TestHelper {
*cfg.PasswordSettings.Number = false
})
ctx := &request.Context{}
a := app.New(app.ServerConnector(s))
a.InitServer()
web := New(s, s.AppOptions, s.Router)
web := New(a, s.Router)
URL = fmt.Sprintf("http://localhost:%v", s.ListenAddr.Port)
ApiClient = model.NewAPIv4Client(URL)
@@ -123,6 +125,7 @@ func setupTestHelper(includeCacheLayer bool) *TestHelper {
th := &TestHelper{
App: a,
Context: ctx,
Server: s,
Web: web,
IncludeCacheLayer: includeCacheLayer,
@@ -135,21 +138,25 @@ func (th *TestHelper) InitPlugins() *TestHelper {
pluginDir := filepath.Join(th.tempWorkspace, "plugins")
webappDir := filepath.Join(th.tempWorkspace, "webapp")
th.App.InitPlugins(pluginDir, webappDir)
th.App.InitPlugins(th.Context, pluginDir, webappDir)
return th
}
func (th *TestHelper) NewPluginAPI(manifest *model.Manifest) plugin.API {
return th.App.NewPluginAPI(th.Context, manifest)
}
func (th *TestHelper) InitBasic() *TestHelper {
th.SystemAdminUser, _ = th.App.CreateUser(&model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1", EmailVerified: true, Roles: model.SYSTEM_ADMIN_ROLE_ID})
th.SystemAdminUser, _ = th.App.CreateUser(th.Context, &model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1", EmailVerified: true, Roles: model.SYSTEM_ADMIN_ROLE_ID})
user, _ := th.App.CreateUser(&model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1", EmailVerified: true, Roles: model.SYSTEM_USER_ROLE_ID})
user, _ := th.App.CreateUser(th.Context, &model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1", EmailVerified: true, Roles: model.SYSTEM_USER_ROLE_ID})
team, _ := th.App.CreateTeam(&model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: user.Email, Type: model.TEAM_OPEN})
team, _ := th.App.CreateTeam(th.Context, &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: user.Email, Type: model.TEAM_OPEN})
th.App.JoinUserToTeam(team, user, "")
th.App.JoinUserToTeam(th.Context, team, user, "")
channel, _ := th.App.CreateChannel(&model.Channel{DisplayName: "Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id, CreatorId: user.Id}, true)
channel, _ := th.App.CreateChannel(th.Context, &model.Channel{DisplayName: "Test API Name", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id, CreatorId: user.Id}, true)
th.BasicUser = user
th.BasicChannel = channel
@@ -263,7 +270,7 @@ func TestPublicFilesRequest(t *testing.T) {
defer os.RemoveAll(pluginDir)
defer os.RemoveAll(webappPluginDir)
env, err := plugin.NewEnvironment(th.App.NewPluginAPI, pluginDir, webappPluginDir, th.App.Log(), nil)
env, err := plugin.NewEnvironment(th.NewPluginAPI, pluginDir, webappPluginDir, th.App.Log(), nil)
require.NoError(t, err)
pluginID := "com.mattermost.sample"

Просмотреть файл

@@ -49,7 +49,7 @@ func incomingWebhook(c *Context, w http.ResponseWriter, r *http.Request) {
defer func() {
if *c.App.Config().LogSettings.EnableWebhookDebugging {
if c.Err != nil {
mlog.Debug("Incoming webhook received", mlog.String("webhook_id", id), mlog.String("request_id", c.App.RequestId()), mlog.String("payload", incomingWebhookPayload.ToJson()))
mlog.Debug("Incoming webhook received", mlog.String("webhook_id", id), mlog.String("request_id", c.AppContext.RequestId()), mlog.String("payload", incomingWebhookPayload.ToJson()))
}
}
}()
@@ -85,7 +85,7 @@ func incomingWebhook(c *Context, w http.ResponseWriter, r *http.Request) {
}
}
err = c.App.HandleIncomingWebhook(id, incomingWebhookPayload)
err = c.App.HandleIncomingWebhook(c.AppContext, id, incomingWebhookPayload)
if err != nil {
c.Err = err
return
@@ -105,7 +105,7 @@ func commandWebhook(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
appErr := c.App.HandleCommandWebhook(id, response)
appErr := c.App.HandleCommandWebhook(c.AppContext, id, response)
if appErr != nil {
c.Err = appErr
return

Просмотреть файл

@@ -232,7 +232,7 @@ func TestIncomingWebhook(t *testing.T) {
})
t.Run("ChannelLockedWebhook", func(t *testing.T) {
channel, err := th.App.CreateChannel(&model.Channel{TeamId: th.BasicTeam.Id, Name: model.NewId(), DisplayName: model.NewId(), Type: model.CHANNEL_OPEN, CreatorId: th.BasicUser.Id}, true)
channel, err := th.App.CreateChannel(th.Context, &model.Channel{TeamId: th.BasicTeam.Id, Name: model.NewId(), DisplayName: model.NewId(), Type: model.CHANNEL_OPEN, CreatorId: th.BasicUser.Id}, true)
require.Nil(t, err)
hook, err := th.App.CreateIncomingWebhookForChannel(th.BasicUser.Id, th.BasicChannel, &model.IncomingWebhook{ChannelId: th.BasicChannel.Id, ChannelLocked: true})