github.com/jfrerich/mattermost-server@v5.8.0-rc2+incompatible/web/context.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package web
     5  
     6  import (
     7  	"net/http"
     8  	"path"
     9  	"regexp"
    10  	"strings"
    11  
    12  	"github.com/mattermost/mattermost-server/app"
    13  	"github.com/mattermost/mattermost-server/mlog"
    14  	"github.com/mattermost/mattermost-server/model"
    15  	"github.com/mattermost/mattermost-server/utils"
    16  )
    17  
    18  type Context struct {
    19  	App           *app.App
    20  	Log           *mlog.Logger
    21  	Params        *Params
    22  	Err           *model.AppError
    23  	siteURLHeader string
    24  }
    25  
    26  func (c *Context) LogAudit(extraInfo string) {
    27  	audit := &model.Audit{UserId: c.App.Session.UserId, IpAddress: c.App.IpAddress, Action: c.App.Path, ExtraInfo: extraInfo, SessionId: c.App.Session.Id}
    28  	if r := <-c.App.Srv.Store.Audit().Save(audit); r.Err != nil {
    29  		c.LogError(r.Err)
    30  	}
    31  }
    32  
    33  func (c *Context) LogAuditWithUserId(userId, extraInfo string) {
    34  
    35  	if len(c.App.Session.UserId) > 0 {
    36  		extraInfo = strings.TrimSpace(extraInfo + " session_user=" + c.App.Session.UserId)
    37  	}
    38  
    39  	audit := &model.Audit{UserId: userId, IpAddress: c.App.IpAddress, Action: c.App.Path, ExtraInfo: extraInfo, SessionId: c.App.Session.Id}
    40  	if r := <-c.App.Srv.Store.Audit().Save(audit); r.Err != nil {
    41  		c.LogError(r.Err)
    42  	}
    43  }
    44  
    45  func (c *Context) LogError(err *model.AppError) {
    46  	// Filter out 404s, endless reconnects and browser compatibility errors
    47  	if err.StatusCode == http.StatusNotFound ||
    48  		(c.App.Path == "/api/v3/users/websocket" && err.StatusCode == http.StatusUnauthorized) ||
    49  		err.Id == "web.check_browser_compatibility.app_error" {
    50  		c.LogDebug(err)
    51  	} else {
    52  		c.Log.Error(
    53  			err.SystemMessage(utils.TDefault),
    54  			mlog.String("err_where", err.Where),
    55  			mlog.Int("http_code", err.StatusCode),
    56  			mlog.String("err_details", err.DetailedError),
    57  		)
    58  	}
    59  }
    60  
    61  func (c *Context) LogInfo(err *model.AppError) {
    62  	// Filter out 401s
    63  	if err.StatusCode == http.StatusUnauthorized {
    64  		c.LogDebug(err)
    65  	} else {
    66  		c.Log.Info(
    67  			err.SystemMessage(utils.TDefault),
    68  			mlog.String("err_where", err.Where),
    69  			mlog.Int("http_code", err.StatusCode),
    70  			mlog.String("err_details", err.DetailedError),
    71  		)
    72  	}
    73  }
    74  
    75  func (c *Context) LogDebug(err *model.AppError) {
    76  	c.Log.Debug(
    77  		err.SystemMessage(utils.TDefault),
    78  		mlog.String("err_where", err.Where),
    79  		mlog.Int("http_code", err.StatusCode),
    80  		mlog.String("err_details", err.DetailedError),
    81  	)
    82  }
    83  
    84  func (c *Context) IsSystemAdmin() bool {
    85  	return c.App.SessionHasPermissionTo(c.App.Session, model.PERMISSION_MANAGE_SYSTEM)
    86  }
    87  
    88  func (c *Context) SessionRequired() {
    89  	if !*c.App.Config().ServiceSettings.EnableUserAccessTokens && c.App.Session.Props[model.SESSION_PROP_TYPE] == model.SESSION_TYPE_USER_ACCESS_TOKEN {
    90  		c.Err = model.NewAppError("", "api.context.session_expired.app_error", nil, "UserAccessToken", http.StatusUnauthorized)
    91  		return
    92  	}
    93  
    94  	if len(c.App.Session.UserId) == 0 {
    95  		c.Err = model.NewAppError("", "api.context.session_expired.app_error", nil, "UserRequired", http.StatusUnauthorized)
    96  		return
    97  	}
    98  }
    99  
   100  func (c *Context) MfaRequired() {
   101  	// Must be licensed for MFA and have it configured for enforcement
   102  	if license := c.App.License(); license == nil || !*license.Features.MFA || !*c.App.Config().ServiceSettings.EnableMultifactorAuthentication || !*c.App.Config().ServiceSettings.EnforceMultifactorAuthentication {
   103  		return
   104  	}
   105  
   106  	// OAuth integrations are excepted
   107  	if c.App.Session.IsOAuth {
   108  		return
   109  	}
   110  
   111  	if user, err := c.App.GetUser(c.App.Session.UserId); err != nil {
   112  		c.Err = model.NewAppError("", "api.context.session_expired.app_error", nil, "MfaRequired", http.StatusUnauthorized)
   113  		return
   114  	} else {
   115  		// Only required for email and ldap accounts
   116  		if user.AuthService != "" &&
   117  			user.AuthService != model.USER_AUTH_SERVICE_EMAIL &&
   118  			user.AuthService != model.USER_AUTH_SERVICE_LDAP {
   119  			return
   120  		}
   121  
   122  		// Special case to let user get themself
   123  		subpath, _ := utils.GetSubpathFromConfig(c.App.Config())
   124  		if c.App.Path == path.Join(subpath, "/api/v4/users/me") {
   125  			return
   126  		}
   127  
   128  		if !user.MfaActive {
   129  			c.Err = model.NewAppError("", "api.context.mfa_required.app_error", nil, "MfaRequired", http.StatusForbidden)
   130  			return
   131  		}
   132  	}
   133  }
   134  
   135  func (c *Context) RemoveSessionCookie(w http.ResponseWriter, r *http.Request) {
   136  	cookie := &http.Cookie{
   137  		Name:     model.SESSION_COOKIE_TOKEN,
   138  		Value:    "",
   139  		Path:     "/",
   140  		MaxAge:   -1,
   141  		HttpOnly: true,
   142  	}
   143  
   144  	http.SetCookie(w, cookie)
   145  }
   146  
   147  func (c *Context) SetInvalidParam(parameter string) {
   148  	c.Err = NewInvalidParamError(parameter)
   149  }
   150  
   151  func (c *Context) SetInvalidUrlParam(parameter string) {
   152  	c.Err = NewInvalidUrlParamError(parameter)
   153  }
   154  
   155  func (c *Context) HandleEtag(etag string, routeName string, w http.ResponseWriter, r *http.Request) bool {
   156  	metrics := c.App.Metrics
   157  	if et := r.Header.Get(model.HEADER_ETAG_CLIENT); len(etag) > 0 {
   158  		if et == etag {
   159  			w.Header().Set(model.HEADER_ETAG_SERVER, etag)
   160  			w.WriteHeader(http.StatusNotModified)
   161  			if metrics != nil {
   162  				metrics.IncrementEtagHitCounter(routeName)
   163  			}
   164  			return true
   165  		}
   166  	}
   167  
   168  	if metrics != nil {
   169  		metrics.IncrementEtagMissCounter(routeName)
   170  	}
   171  
   172  	return false
   173  }
   174  
   175  func NewInvalidParamError(parameter string) *model.AppError {
   176  	err := model.NewAppError("Context", "api.context.invalid_body_param.app_error", map[string]interface{}{"Name": parameter}, "", http.StatusBadRequest)
   177  	return err
   178  }
   179  func NewInvalidUrlParamError(parameter string) *model.AppError {
   180  	err := model.NewAppError("Context", "api.context.invalid_url_param.app_error", map[string]interface{}{"Name": parameter}, "", http.StatusBadRequest)
   181  	return err
   182  }
   183  
   184  func (c *Context) SetPermissionError(permission *model.Permission) {
   185  	c.Err = model.NewAppError("Permissions", "api.context.permissions.app_error", nil, "userId="+c.App.Session.UserId+", "+"permission="+permission.Id, http.StatusForbidden)
   186  }
   187  
   188  func (c *Context) SetSiteURLHeader(url string) {
   189  	c.siteURLHeader = strings.TrimRight(url, "/")
   190  }
   191  
   192  func (c *Context) GetSiteURLHeader() string {
   193  	return c.siteURLHeader
   194  }
   195  
   196  func (c *Context) RequireUserId() *Context {
   197  	if c.Err != nil {
   198  		return c
   199  	}
   200  
   201  	if c.Params.UserId == model.ME {
   202  		c.Params.UserId = c.App.Session.UserId
   203  	}
   204  
   205  	if len(c.Params.UserId) != 26 {
   206  		c.SetInvalidUrlParam("user_id")
   207  	}
   208  	return c
   209  }
   210  
   211  func (c *Context) RequireTeamId() *Context {
   212  	if c.Err != nil {
   213  		return c
   214  	}
   215  
   216  	if len(c.Params.TeamId) != 26 {
   217  		c.SetInvalidUrlParam("team_id")
   218  	}
   219  	return c
   220  }
   221  
   222  func (c *Context) RequireInviteId() *Context {
   223  	if c.Err != nil {
   224  		return c
   225  	}
   226  
   227  	if len(c.Params.InviteId) == 0 {
   228  		c.SetInvalidUrlParam("invite_id")
   229  	}
   230  	return c
   231  }
   232  
   233  func (c *Context) RequireTokenId() *Context {
   234  	if c.Err != nil {
   235  		return c
   236  	}
   237  
   238  	if len(c.Params.TokenId) != 26 {
   239  		c.SetInvalidUrlParam("token_id")
   240  	}
   241  	return c
   242  }
   243  
   244  func (c *Context) RequireChannelId() *Context {
   245  	if c.Err != nil {
   246  		return c
   247  	}
   248  
   249  	if len(c.Params.ChannelId) != 26 {
   250  		c.SetInvalidUrlParam("channel_id")
   251  	}
   252  	return c
   253  }
   254  
   255  func (c *Context) RequireUsername() *Context {
   256  	if c.Err != nil {
   257  		return c
   258  	}
   259  
   260  	if !model.IsValidUsername(c.Params.Username) {
   261  		c.SetInvalidParam("username")
   262  	}
   263  
   264  	return c
   265  }
   266  
   267  func (c *Context) RequirePostId() *Context {
   268  	if c.Err != nil {
   269  		return c
   270  	}
   271  
   272  	if len(c.Params.PostId) != 26 {
   273  		c.SetInvalidUrlParam("post_id")
   274  	}
   275  	return c
   276  }
   277  
   278  func (c *Context) RequireAppId() *Context {
   279  	if c.Err != nil {
   280  		return c
   281  	}
   282  
   283  	if len(c.Params.AppId) != 26 {
   284  		c.SetInvalidUrlParam("app_id")
   285  	}
   286  	return c
   287  }
   288  
   289  func (c *Context) RequireFileId() *Context {
   290  	if c.Err != nil {
   291  		return c
   292  	}
   293  
   294  	if len(c.Params.FileId) != 26 {
   295  		c.SetInvalidUrlParam("file_id")
   296  	}
   297  
   298  	return c
   299  }
   300  
   301  func (c *Context) RequireFilename() *Context {
   302  	if c.Err != nil {
   303  		return c
   304  	}
   305  
   306  	if len(c.Params.Filename) == 0 {
   307  		c.SetInvalidUrlParam("filename")
   308  	}
   309  
   310  	return c
   311  }
   312  
   313  func (c *Context) RequirePluginId() *Context {
   314  	if c.Err != nil {
   315  		return c
   316  	}
   317  
   318  	if len(c.Params.PluginId) == 0 {
   319  		c.SetInvalidUrlParam("plugin_id")
   320  	}
   321  
   322  	return c
   323  }
   324  
   325  func (c *Context) RequireReportId() *Context {
   326  	if c.Err != nil {
   327  		return c
   328  	}
   329  
   330  	if len(c.Params.ReportId) != 26 {
   331  		c.SetInvalidUrlParam("report_id")
   332  	}
   333  	return c
   334  }
   335  
   336  func (c *Context) RequireEmojiId() *Context {
   337  	if c.Err != nil {
   338  		return c
   339  	}
   340  
   341  	if len(c.Params.EmojiId) != 26 {
   342  		c.SetInvalidUrlParam("emoji_id")
   343  	}
   344  	return c
   345  }
   346  
   347  func (c *Context) RequireTeamName() *Context {
   348  	if c.Err != nil {
   349  		return c
   350  	}
   351  
   352  	if !model.IsValidTeamName(c.Params.TeamName) {
   353  		c.SetInvalidUrlParam("team_name")
   354  	}
   355  
   356  	return c
   357  }
   358  
   359  func (c *Context) RequireChannelName() *Context {
   360  	if c.Err != nil {
   361  		return c
   362  	}
   363  
   364  	if !model.IsValidChannelIdentifier(c.Params.ChannelName) {
   365  		c.SetInvalidUrlParam("channel_name")
   366  	}
   367  
   368  	return c
   369  }
   370  
   371  func (c *Context) RequireEmail() *Context {
   372  	if c.Err != nil {
   373  		return c
   374  	}
   375  
   376  	if !model.IsValidEmail(c.Params.Email) {
   377  		c.SetInvalidUrlParam("email")
   378  	}
   379  
   380  	return c
   381  }
   382  
   383  func (c *Context) RequireCategory() *Context {
   384  	if c.Err != nil {
   385  		return c
   386  	}
   387  
   388  	if !model.IsValidAlphaNumHyphenUnderscore(c.Params.Category, true) {
   389  		c.SetInvalidUrlParam("category")
   390  	}
   391  
   392  	return c
   393  }
   394  
   395  func (c *Context) RequireService() *Context {
   396  	if c.Err != nil {
   397  		return c
   398  	}
   399  
   400  	if len(c.Params.Service) == 0 {
   401  		c.SetInvalidUrlParam("service")
   402  	}
   403  
   404  	return c
   405  }
   406  
   407  func (c *Context) RequirePreferenceName() *Context {
   408  	if c.Err != nil {
   409  		return c
   410  	}
   411  
   412  	if !model.IsValidAlphaNumHyphenUnderscore(c.Params.PreferenceName, true) {
   413  		c.SetInvalidUrlParam("preference_name")
   414  	}
   415  
   416  	return c
   417  }
   418  
   419  func (c *Context) RequireEmojiName() *Context {
   420  	if c.Err != nil {
   421  		return c
   422  	}
   423  
   424  	validName := regexp.MustCompile(`^[a-zA-Z0-9\-\+_]+$`)
   425  
   426  	if len(c.Params.EmojiName) == 0 || len(c.Params.EmojiName) > model.EMOJI_NAME_MAX_LENGTH || !validName.MatchString(c.Params.EmojiName) {
   427  		c.SetInvalidUrlParam("emoji_name")
   428  	}
   429  
   430  	return c
   431  }
   432  
   433  func (c *Context) RequireHookId() *Context {
   434  	if c.Err != nil {
   435  		return c
   436  	}
   437  
   438  	if len(c.Params.HookId) != 26 {
   439  		c.SetInvalidUrlParam("hook_id")
   440  	}
   441  
   442  	return c
   443  }
   444  
   445  func (c *Context) RequireCommandId() *Context {
   446  	if c.Err != nil {
   447  		return c
   448  	}
   449  
   450  	if len(c.Params.CommandId) != 26 {
   451  		c.SetInvalidUrlParam("command_id")
   452  	}
   453  	return c
   454  }
   455  
   456  func (c *Context) RequireJobId() *Context {
   457  	if c.Err != nil {
   458  		return c
   459  	}
   460  
   461  	if len(c.Params.JobId) != 26 {
   462  		c.SetInvalidUrlParam("job_id")
   463  	}
   464  	return c
   465  }
   466  
   467  func (c *Context) RequireJobType() *Context {
   468  	if c.Err != nil {
   469  		return c
   470  	}
   471  
   472  	if len(c.Params.JobType) == 0 || len(c.Params.JobType) > 32 {
   473  		c.SetInvalidUrlParam("job_type")
   474  	}
   475  	return c
   476  }
   477  
   478  func (c *Context) RequireActionId() *Context {
   479  	if c.Err != nil {
   480  		return c
   481  	}
   482  
   483  	if len(c.Params.ActionId) != 26 {
   484  		c.SetInvalidUrlParam("action_id")
   485  	}
   486  	return c
   487  }
   488  
   489  func (c *Context) RequireRoleId() *Context {
   490  	if c.Err != nil {
   491  		return c
   492  	}
   493  
   494  	if len(c.Params.RoleId) != 26 {
   495  		c.SetInvalidUrlParam("role_id")
   496  	}
   497  	return c
   498  }
   499  
   500  func (c *Context) RequireSchemeId() *Context {
   501  	if c.Err != nil {
   502  		return c
   503  	}
   504  
   505  	if len(c.Params.SchemeId) != 26 {
   506  		c.SetInvalidUrlParam("scheme_id")
   507  	}
   508  	return c
   509  }
   510  
   511  func (c *Context) RequireRoleName() *Context {
   512  	if c.Err != nil {
   513  		return c
   514  	}
   515  
   516  	if !model.IsValidRoleName(c.Params.RoleName) {
   517  		c.SetInvalidUrlParam("role_name")
   518  	}
   519  
   520  	return c
   521  }
   522  
   523  func (c *Context) RequireGroupId() *Context {
   524  	if c.Err != nil {
   525  		return c
   526  	}
   527  
   528  	if len(c.Params.GroupId) != 26 {
   529  		c.SetInvalidUrlParam("group_id")
   530  	}
   531  	return c
   532  }
   533  
   534  func (c *Context) RequireRemoteId() *Context {
   535  	if c.Err != nil {
   536  		return c
   537  	}
   538  
   539  	if len(c.Params.RemoteId) == 0 {
   540  		c.SetInvalidUrlParam("remote_id")
   541  	}
   542  	return c
   543  }
   544  
   545  func (c *Context) RequireSyncableId() *Context {
   546  	if c.Err != nil {
   547  		return c
   548  	}
   549  
   550  	if len(c.Params.SyncableId) != 26 {
   551  		c.SetInvalidUrlParam("syncable_id")
   552  	}
   553  	return c
   554  }
   555  
   556  func (c *Context) RequireSyncableType() *Context {
   557  	if c.Err != nil {
   558  		return c
   559  	}
   560  
   561  	if c.Params.SyncableType != model.GroupSyncableTypeTeam && c.Params.SyncableType != model.GroupSyncableTypeChannel {
   562  		c.SetInvalidUrlParam("syncable_type")
   563  	}
   564  	return c
   565  }